Browse Source

módulo que en devolución agrega código de barra

SEBAS 1 year ago
commit
79940e9faa

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+*.pyc

+ 2 - 0
__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+import model

+ 25 - 0
__openerp__.py

@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+{
+    'name': 'Eiru Stock Picking Sale and Purchase',
+    'version': '1.0.2',
+    'description': '''
+    ## Devolución de producto de Venta/Compra.\n
+        * Facilita las devoluciones de productos.\n
+        * Mejora la creación de factura a crédito.
+    ''',
+    'author': 'Adrielso Kunert',
+    'category': 'stock',
+    'depends': ['sale', 'purchase', 'base'],
+    'data': [
+        'views/templates.xml',
+        'views/eiru_stock_picking.xml',
+        'views/eiru_stock_picking_purchase.xml',
+    ],
+    'qweb': [
+        'static/src/xml/*.xml',
+        'static/src/xml/modal/*.xml',
+    ],
+
+    'installable': True,
+    'auto_install': False,
+ }

+ 2 - 0
model/__init__.py

@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+import stock_return_picking

+ 264 - 0
model/stock_return_picking.py

@@ -0,0 +1,264 @@
+# -*- coding: utf-8 -*-
+from openerp import api, fields, models
+from openerp.tools.translate import _
+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
+from pytz import timezone
+from datetime import datetime,timedelta
+import logging
+_logger = logging.getLogger(__name__)
+
+class EiruStockReturnPicking(models.TransientModel):
+    _inherit = 'stock.return.picking'
+
+    ''' Timezone '''
+    def get_timezone(self):
+        return timezone(self._context.get('tz') or self.env.user.tz)
+
+    ''' Datetime '''
+    def get_datetime(self):
+        return datetime.now(self.get_timezone()).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+
+    ''' Date '''
+    def get_date(self):
+        return datetime.now(self.get_timezone()).strftime(DEFAULT_SERVER_DATE_FORMAT)
+
+    '''
+           ____ _____ _____   ____ ___ ____ _  _____ _   _  ____
+          / ___| ____|_   _| |  _ \_ _/ ___| |/ /_ _| \ | |/ ___|
+         | |  _|  _|   | |   | |_) | | |   | ' / | ||  \| | |  _
+         | |_| | |___  | |   |  __/| | |___| . \ | || |\  | |_| |
+          \____|_____| |_|   |_|  |___\____|_|\_\___|_| \_|\____|
+    '''
+    ''' GET Stock picking '''
+    @api.model
+    def eiru_get_stock_picking_order(self, idOrder, model):
+        pickingLine = []
+        pickingReturn = []
+        ''' decimal.precision '''
+        decimalPrecision = self.env['decimal.precision'].precision_get('Product UoS')
+
+        ''' sale.order '''
+        order =self.env[model].browse(idOrder)
+        if (not order):
+            return {
+                'state': False,
+                'message': "No fue posible obtener la orden."
+            }
+
+        procurement = self.env['procurement.group'].search([('name', '=', order.name)])
+        if (not procurement):
+            return {
+                'state': False,
+                'message': "No fue posible localizar la petición de abastecimiento."
+            }
+        ''' Get stock.picking '''
+        pickingSale = self.env['stock.picking'].search([('group_id.id', '=', procurement.id),('origin', '=', order.name)],order='id')
+        if (not pickingSale):
+            return {
+                'state': False,
+                'message': "Ya existe mas de un movimiento de stock de este pedido."
+            }
+
+        moveIds = map(lambda x: x.id, pickingSale.move_lines)
+        for line in self.env['stock.move'].search([('id', 'in', moveIds)]):
+            productProduct = self.env['product.product'].browse(line.product_id.id)
+            if (not productProduct):
+                continue
+
+
+            default_code = str(productProduct.ean13) if productProduct.ean13 else ""
+            name = str(productProduct.name) if productProduct.name else ""
+            productName = default_code + " " + name
+
+            pickingLine.append({
+                'moveId': line.id,
+                'qty_order': round((line.product_uom_qty) ,decimalPrecision),
+                'qty_return': 0,
+                'qty': round((line.product_uom_qty) ,decimalPrecision),
+                'productId' : productProduct.id,
+                'productName': productName,
+            })
+
+        if (not pickingLine):
+            return {
+                'state': False,
+                'message': "Ya existe mas de un movimiento de stock de este pedido."
+            }
+
+        stockPicking = self.env['stock.picking'].search([('group_id.id', '=', procurement.id), ('origin', '=', pickingSale.name)],order='id')
+
+        for picking in stockPicking:
+            moveIds = map(lambda x: x.id, picking.move_lines)
+            for line in self.env['stock.move'].search([('id', 'in', moveIds)]):
+                productProduct = self.env['product.product'].browse(line.product_id.id)
+                if (not productProduct):
+                    continue
+
+                moveIds = map(lambda x: x['moveId'], pickingLine)
+                if (line.origin_returned_move_id.id in moveIds):
+                    for stock in pickingLine:
+                        if (stock['moveId'] == line.origin_returned_move_id.id):
+                            stock['qty_return'] += line.product_uom_qty
+
+        if (not pickingLine):
+            return {
+                'state': False,
+                'message': "Ya existe mas de un movimiento de stock de este pedido."
+            }
+
+        for stock in pickingLine:
+            stock['qty'] = round((stock['qty'] - (stock['qty_return'])) ,decimalPrecision),
+            stock['qty_order'] = round((stock['qty_order']) ,decimalPrecision),
+            stock['qty_return'] = round((stock['qty_return']) ,decimalPrecision),
+
+        pickingReturn.append({
+            'order': [{
+                'id':order.id,
+                'name':order.name,
+                'dateOrder': order.date_order,
+            }],
+            'picking': [{
+                'id': pickingSale.id,
+                'name': pickingSale.name,
+                'state': pickingSale.state,
+                'locationOrigen': pickingSale.location_id.id,
+                'locationDest': pickingSale.location_dest_id.id,
+                'productFormat': {
+                    'thousandsSeparator': '.',
+                    'decimalSeparator': ',',
+                    'decimalPlaces': decimalPrecision
+                },
+                'lines': pickingLine
+            }],
+        })
+
+        return {
+            'state': True,
+            'pickingOrder': pickingReturn
+        }
+
+    '''
+          ____  _____ _____ _   _ ____  _   _   ____ ___ ____ _  _____ _   _  ____
+         |  _ \| ____|_   _| | | |  _ \| \ | | |  _ \_ _/ ___| |/ /_ _| \ | |/ ___|
+         | |_) |  _|   | | | | | | |_) |  \| | | |_) | | |   | ' / | ||  \| | |  _
+         |  _ <| |___  | | | |_| |  _ <| |\  | |  __/| | |___| . \ | || |\  | |_| |
+         |_| \_\_____| |_|  \___/|_| \_\_| \_| |_|  |___\____|_|\_\___|_| \_|\____|
+    '''
+    ''' create_stock_return '''
+    # @api.multi
+    def create_stock_return(self, vals):
+        return super(EiruStockReturnPicking, self).create(vals)
+
+    ''' eiru_create_stock_return_picking '''
+    @api.model
+    def eiru_create_stock_return_picking(self, values):
+        _logger.info('Stock Picking')
+        fields = ['product_return_moves', 'move_dest_exists', 'invoice_state']
+        res = super(EiruStockReturnPicking, self).default_get(fields)
+
+        stockMove = []
+        for line in values['move']:
+            stockMove.append([0, False,{
+                'product_id': line['productId'],
+                'move_id': line['moveID'],
+                'quantity':  line['qty']
+            }])
+
+        if 'product_return_moves' in fields:
+            res.update({'product_return_moves': stockMove})
+
+        if 'move_dest_exists' in fields:
+            res.update({'move_dest_exists': False})
+
+        if 'invoice_state' in fields:
+            res.update({'invoice_state': '2binvoiced'})
+
+        ''' stock.return.picking '''
+        pickingReturn = self.env['stock.return.picking'].create_stock_return(res)
+        new_picking_id, pick_type_id = pickingReturn.with_context(active_id=values['pickingId'],active_model='stock.picking')._create_returns()
+
+        ''' Get Picking '''
+        stockPicking = self.env['stock.picking'].browse(new_picking_id)
+        if(not stockPicking):
+            return {
+                'state': True,
+                'message': 'No fue posible localizar la devolución'
+            }
+
+        if (values['model'] == 'purchase.order'):
+            for moveline in stockPicking.move_lines:
+                moveOriginal = self.env['stock.move'].browse(moveline.origin_returned_move_id.id)
+                if (not moveOriginal):
+                    return False
+
+                orederLine = self.env['purchase.order.line'].browse(moveOriginal.purchase_line_id.id)
+                if (not orederLine):
+                    return False
+
+                moveline.write({
+                    'purchase_line_id': orederLine.id
+                })
+
+        ''' Transferir producto '''
+        stockPicking.force_assign()
+        stockPicking.action_done()
+
+        if (values['invoiced']):
+            ''' Crear Factura de la devolucion '''
+            stockInvoice = self.env['stock.invoice.onshipping'].with_context(active_ids=[stockPicking.id]).eiru_create_stock_invoice_onshipping(self.get_date())
+            if (not stockInvoice):
+                return {
+                    'state': True,
+                    'message': 'No es posible crear la factura'
+                }
+
+            if (values['model'] == 'purchase.order'):
+                purchase = self.env[values['model']].browse(values['orderID'])
+                if (not purchase):
+                    return {
+                        'state': True,
+                        'message': 'No es posible localizar la compra.'
+                    }
+
+                invoicesIds = map(lambda x: x.id, purchase.invoice_ids)
+                invoicesIds.append(stockInvoice[0])
+                invoice = self.env['account.invoice'].search([('id', 'in', stockInvoice)])
+                purchase.write({'invoice_ids': [(4, invoice.id, False)]})
+
+        return {
+            'state': True,
+            'message': 'Devolución realizada con suceso'
+        }
+
+''' stock.invoice.onshipping '''
+class EiruStockInvoiceOnshipping(models.TransientModel):
+    _inherit = 'stock.invoice.onshipping'
+
+    ''' Open Invoice '''
+    @api.multi
+    def create_invoice(self):
+        res = super(EiruStockInvoiceOnshipping, self).create_invoice()
+        invoice = self.env['account.invoice'].search([('id', 'in', res)])
+        if (invoice):
+            invoice.signal_workflow('invoice_open')
+        return res
+
+    ''' create Invoices stock returned '''
+    def eiru_create_stock_invoice_onshipping(self, dateServer):
+        ''' Get Journal Type '''
+        journalType = self._get_journal_type()
+        ''' Get Journal '''
+        journal = self._get_journal()
+
+        ''' Create stock.invoice.onshipping '''
+        res = {
+            'journal_id': journal,
+            'journal_type': journalType,
+            'invoice_date': dateServer,
+        }
+        newStockInvoice = self.create(res)
+
+        ''' Create Invoice '''
+        res = newStockInvoice.create_invoice()
+
+        return res

BIN
static/description/icon.png


+ 184 - 0
static/src/css/style.css

@@ -0,0 +1,184 @@
+.eiru-stock-picking-return {
+    width: auto !important;
+    float: left;
+}
+.stock-picking-return-label {
+    width: 150px;
+    height: 30px;
+    font-size: 14px;
+    padding-top: 5px;
+    padding-left: 5px;
+}
+.stock-picking-return-group {
+    width: calc(100% - 150px);
+    height: 30px;
+    padding-left: 5px;
+    padding-right: 5px;
+    float: right;
+}
+.stock-picking-quantity {
+    width: 100%;
+    text-align: right;
+    padding-right: 10px !important;
+    font-size: 10pt;
+    border: 1px solid #e3e3e3 !important;
+    background: #ececec !important;
+    text-align: center !important;
+
+}
+.picking-qty {
+    background: white !important;
+}
+.picking-invoice-label {
+    width: 280px;
+}
+.picking-invoice-group {
+    width: calc(100% - 280px);
+}
+.picking-invoice-checkbox{
+    margin-top: 8px !important;
+}
+.picking-invoice-button {
+    font-size: 12pt !important;
+    width: 130px;
+    height: 35px;
+}
+.widget-content.widget-loading-picking-invoice {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    color : #000;
+    display: none;
+    z-index: 1100;
+    background: #8080806b;
+    align-items: center;
+    justify-content: center;
+}
+/*
+      _____  _    ____  _     _____
+     |_   _|/ \  | __ )| |   | ____|
+       | | / _ \ |  _ \| |   |  _|
+       | |/ ___ \| |_) | |___| |___
+       |_/_/   \_\____/|_____|_____|
+ */
+.select-stock-picking-retuned {
+    height: 20px !important;
+    margin: 0px;
+}
+.stock-picking-table {
+    margin-top: 0px !important;
+}
+.expired-account-modal .selected-product {
+     background: #d4e2f3  !important;
+}
+.expired-account-modal  .modal-head-wrapper-stock-picking {
+    width: 100%;
+}
+.expired-account-modal .modal-item-stock-picking {
+    width: 100%;
+    height: 254px;
+    overflow-y: auto;
+}
+.expired-account-modal .stock-picking-table table tbody tr {
+    height: 35px;
+}
+.expired-account-modal .stock-picking-table table thead tr {
+    height: 40px !important;
+}
+/******************************************************************************/
+/* move_id */
+.expired-account-modal .stock-picking-table table tbody tr td:nth-child(1){
+    display: none;
+}
+/* move_id */
+.expired-account-modal table thead tr th:nth-child(1){
+    display: none;
+}
+/******************************************************************************/
+/* product_id */
+.expired-account-modal .stock-picking-table table tbody tr td:nth-child(2){
+    display: none;
+}
+/* product_id */
+.expired-account-modal table thead tr th:nth-child(2){
+    display: none;
+}
+/******************************************************************************/
+/* selected */
+.expired-account-modal .stock-picking-table table tbody tr td:nth-child(3){
+    width: 33px;
+}
+/* selected */
+.expired-account-modal .stock-picking-table table thead tr th:nth-child(3){
+    width: 33px;
+}
+/******************************************************************************/
+/* Product Name  */
+.expired-account-modal .stock-picking-table table tbody tr td:nth-child(4){
+    width: 324px;
+    font-size: 10pt;
+    padding-left: 10px;
+    padding-top: 8px;
+}
+/* Product Name  */
+.expired-account-modal .stock-picking-table table thead tr th:nth-child(4){
+    width: 405px;
+    padding-left: 10px;
+    font-size: 11pt;
+    font-weight: bold;
+}
+/******************************************************************************/
+/* Quantity */
+.expired-account-modal .stock-picking-table table tbody tr td:nth-child(5){
+    width: 95px;
+    text-align: center;
+    font-size: 10pt;
+    padding-top: 8px;
+}
+/* Quantity */
+.expired-account-modal .stock-picking-table table thead tr th:nth-child(5){
+    width: 95px;
+    font-size: 11pt;
+    font-weight: bold;
+}
+/******************************************************************************/
+/* Quantity */
+.expired-account-modal .stock-picking-table table tbody tr td:nth-child(6){
+    width: 95px;
+    text-align: center;
+    font-size: 10pt;
+    padding-top: 8px;
+}
+/* Quantity */
+.expired-account-modal .stock-picking-table table thead tr th:nth-child(6){
+    width: 95px;
+    font-size: 11pt;
+    font-weight: bold;
+}
+/******************************************************************************/
+/* Quantity */
+.expired-account-modal .stock-picking-table table tbody tr td:nth-child(7){
+    width: 95px;
+    text-align: center;
+    font-size: 10pt;
+    padding-top: 8px;
+}
+/* Quantity */
+.expired-account-modal .stock-picking-table table thead tr th:nth-child(7){
+    width: 95px;
+    font-size: 11pt;
+    font-weight: bold;
+}
+/******************************************************************************/
+/* Quantity */
+.expired-account-modal .stock-picking-table table tbody tr td:nth-child(8){
+    text-align: center;
+    font-size: 10pt;
+    padding-top: 8px;
+}
+/* Quantity */
+.expired-account-modal .stock-picking-table table thead tr th:nth-child(8){
+    width: 115px;
+    font-size: 11pt;
+    font-weight: bold;
+}

+ 345 - 0
static/src/js/eiru_stock_picking.js

@@ -0,0 +1,345 @@
+(function() {
+    // EiruStockPicking
+    openerp.widgetInstanceEiruStockPicking = null;
+    openerp.parentInstanceEiruStockPicking = {};
+    var QWeb = openerp.web.qweb;
+    var instanceWeb = openerp.web;
+
+    openerp.EiruStockPicking = openerp.Widget.extend({
+        template: 'EiruStockPicking.Returned',
+        id: undefined,
+        model: undefined,
+        buttons: undefined,
+        stockPicking: [],
+
+        /* init */
+        init: function(parent) {
+            this._super(parent);
+            this.buttons = parent.$buttons;
+        },
+
+        /* start */
+        start: function () {
+            var self = this;
+            this.$el.click(function(){
+                self.fetchInitial();
+            });
+        },
+
+        /* Check state*/
+        updateId: function(id, model) {
+            var self = this;
+            self.id = id;
+            self.model = model;
+            self.$el.css('display','flex');
+            if (!self.id)
+                self.$el.css('display','none');
+        },
+
+        /* Reload Page*/
+        reloadPage: function() {
+            openerp.parentInstanceEiruStockPicking.reload();
+        },
+
+        /* Description: Función para remover el modal */
+        removeModal: function() {
+            $('.expired-account-modal').remove();
+            $('.modal-backdrop').remove();
+        },
+
+        /* Método inicial  */
+        fetchInitial: function() {
+            var self = this;
+            self.fetchStockPickingOrder(self.id, self.model).then(function(stockPicking) {
+                return stockPicking;
+            }).then(function(stockPicking) {
+                if (!stockPicking.state) {
+                    instanceWeb.notification.do_warn("Atencion", stockPicking.message);
+                    return false;
+                }
+
+                self.stockPicking = stockPicking.pickingOrder;
+                return self.showModalReturned();
+            });
+        },
+
+        /* Get account.interest */
+        fetchStockPickingOrder: function(id, model) {
+            var pickingOrder = new instanceWeb.Model('stock.return.picking');
+            return pickingOrder.call('eiru_get_stock_picking_order', [id, model], {
+                context: new instanceWeb.CompoundContext()
+            });
+        },
+        /* Format Quantity */
+        pickingFormatline: function(line, format){
+            var self = this;
+            _.each(line, function(item) {
+                item.qty_order_format = self.formatQty(item.qty_order, format)
+                item.qty_return_format = self.formatQty(item.qty_return, format)
+                item.qty_format = self.formatQty(item.qty, format)
+            })
+            return line;
+        },
+        /* Modal */
+        showModalReturned: function() {
+            var self = this;
+            var results = true;
+            var defer =$.Deferred();
+            var stockPicking = self.stockPicking[0];
+            var order = stockPicking.order[0];
+            var picking = stockPicking.picking[0];
+            var productoFormat = picking.productFormat;
+            var lines = self.pickingFormatline(picking.lines,productoFormat);
+            var productSelect = [];
+            /*Modal Init */
+            var modal = QWeb.render('EiruStockPicking.ModalReturned',{
+                'line': lines
+            });
+            $('.openerp_webclient_container').after(modal);
+            $('.expired-account-modal').modal();
+
+            /* Variable  */
+            var selectPickingAll = $('.expired-account-modal').find('.select-stock-picking-all');
+            var tableRow = $('.expired-account-modal').find('.table-tbody').find('tr');
+            var lableOrde = $('.expired-account-modal').find('.sale-lable-table');
+            /* Facturar */
+            var stockInvoiced = $('.expired-account-modal').find('.stock-return-invoiced')
+            /* button Crear Factura */
+            var buttonAccept = $('.expired-account-modal').find('.button-accept');
+
+            lableOrde.text(self.model === 'sale.order' ? 'Entregado' : 'Recibido')
+
+            /* Verify Qty */
+            _.each(tableRow, function(tr) {
+                if (self.unformatQty($($(tr).children()[6]).find('.picking-sale').val()) === 0) {
+                    ($($(tr).children()[2]).find('.select-stock-picking-retuned'))[0].checked = false;
+                    ($($(tr).children()[2]).find('.select-stock-picking-retuned')).attr("disabled", true);
+                    $(tr).css('color','red');
+                }
+            })
+
+            /* click  Select all */
+            selectPickingAll.click(function(e) {
+                var check = e.target.checked;
+                productSelect = [];
+
+                _.each(tableRow, function(tr) {
+                    if (parseInt($($(tr).children()[6]).find('.picking-sale').val()) === 0)
+                        return false;
+
+                    ($($(tr).children()[2]).find('.select-stock-picking-retuned'))[0].checked = check;
+                    $(tr).removeClass('selected-product');
+
+                    var productQty = ($($(tr).children()[7]).find('.picking-return'));
+                    productQty.removeClass('picking-qty');
+                    productQty.attr("disabled", true);
+
+                    if (check) {
+                        moveId = parseInt(($(tr).children()[0].textContent).trim());
+                        productId = parseInt(($(tr).children()[1].textContent).trim());
+
+                        productQty.addClass('picking-qty')
+                        productQty.removeAttr("disabled");
+                        $(tr).addClass('selected-product');
+
+                            productSelect.push({
+                                'productId': productId,
+                                'moveID': moveId,
+                                'qty': self.unformatQty(productQty.val())
+                            });
+                    }
+                });
+            });
+
+            /* Select Prodcut  */
+            tableRow.click(function(e) {
+                if (($(e.target).index() !== 0) ||(($(e.target).index() === 0) && ($(e.target)[0].className !== 'select-stock-picking-retuned')))
+                    return false;
+
+                /* Desmarcar todo*/
+                selectPickingAll[0].checked = false;
+                idRow = parseInt(($(e.target).closest('tr').children()[0].textContent).trim());
+                var productId =  parseInt(($(e.target).closest('tr').children()[1].textContent).trim());
+                var productQty = ($($(e.target).closest('tr').children()[7]).find('.picking-return'));
+                var pickingSale = $($(e.target).closest('tr').children()[6]).find('.picking-sale');
+
+                if (e.target.checked === true) {
+                    $(e.target).closest('tr').addClass('selected-product');
+                    productQty.addClass('picking-qty')
+                    productQty.removeAttr("disabled");
+                    productSelect.push({
+                        'productId': productId,
+                        'moveID': idRow,
+                        'qty': self.unformatQty(productQty.val())
+                    });
+                } else {
+                    $(e.target).closest('tr').removeClass('selected-product');
+                    productQty.removeClass('picking-qty')
+                    productQty.attr("disabled", true);
+                    var indexSplice = undefined;
+
+                    _.each(productSelect, function(item, index){
+                        if (item.moveID === idRow) {
+                            indexSplice = index
+                        }
+                    })
+
+                    if (indexSplice !== undefined)
+                        productSelect.splice(indexSplice,1);
+
+                    productQty.val(parseInt(pickingSale.val()))
+                }
+            });
+
+            tableRow.keyup(function(e) {
+                if (($(e.target).index() !== 0) ||(($(e.target).index() === 0) && (!_.contains(($(e.target)[0].className).split(' '), 'picking-return')) ))
+                    return false;
+
+                var productQty = ($($(e.target).closest('tr').children()[7]).find('.picking-return'));
+                if (e.key === productoFormat.decimalSeparator && productoFormat.decimalPlaces > 0)
+                    return false ;
+
+                value = self.unformatQty(productQty.val());
+                productQty.val(self.formatQty(value, productoFormat, true));
+
+            });
+
+            /*Validate focus */
+            tableRow.focusout(function(e) {
+                if (($(e.target).index() !== 0) ||(($(e.target).index() === 0) && ($(e.target)[0].className === 'picking-return')))
+                    return false;
+
+                var moveId = parseInt(($(e.target).closest('tr').children()[0].textContent).trim());
+                var pickingSale = $($(e.target).closest('tr').children()[6]).find('.picking-sale');
+                var pickingReturn = $($(e.target).closest('tr').children()[7]).find('.picking-return');
+
+                var qtySale = self.unformatQty(pickingSale.val());
+                var qtyReturn = self.unformatQty(pickingReturn.val())
+
+                if (qtyReturn > qtySale ) {
+                    instanceWeb.notification.do_warn("Atencion", "La cantidad del movimiento supera la cantidad disponible.");
+                    buttonAccept.attr("disabled", true);
+                    pickingReturn.focus();
+                    return false;
+                }
+
+                if (qtyReturn <= 0) {
+                    instanceWeb.notification.do_warn("Atencion", "La cantidad del movimiento debe ser mayor que 0");
+                    buttonAccept.attr("disabled", true);
+                    pickingReturn.focus();
+                    return false;
+                }
+
+                value = self.unformatQty(pickingReturn.val());
+                pickingReturn.val(self.formatQty(value,productoFormat, false));
+
+                _.each(productSelect, function(item, index) {
+                    if (item.moveID === moveId) {
+                        item.qty = qtyReturn
+                    }
+                })
+                buttonAccept.removeAttr("disabled");
+
+            });
+
+            /* Accept*/
+            buttonAccept.click(function(e) {
+                if (!productSelect.length) {
+                    instanceWeb.notification.do_warn("Atencion", "Debes seleccionar al menos un producto para generar la transferencia.");
+                    return false;
+                }
+                if (!!_.contains(_.map(productSelect,function(item){return item.qty}), 0)) {
+                    instanceWeb.notification.do_warn("Atencion", "Existe producto seleccionado con cantidad  0");
+                    return false;
+                }
+
+                var newPicking = {
+                    'orderID': order.id,
+                    'model': self.model,
+                    'pickingId': picking.id,
+                    'invoiced': stockInvoiced[0].checked,
+                    'move': productSelect
+                }
+
+                $('.expired-account-modal').find('.widget-content.widget-loading-picking-invoice').css('display','flex');
+                self.createReturnPicking(newPicking).then(function(resultsInvoice) {
+                    return resultsInvoice;
+                }).then(function(resultsInvoice) {
+                    $('.expired-account-modal').find('.widget-content.widget-loading-picking-invoice').css('display','none');
+                    instanceWeb.notification.do_warn("Atencion", resultsInvoice.message);
+                    self.reloadPage();
+                    self.removeModal(e);
+                });
+
+                defer.resolve(results);
+            });
+
+            /* Cerrar */
+            $('.expired-account-modal').on('hidden.bs.modal', function(e) {
+                results = false;
+                defer.resolve(results);
+                self.removeModal(e);
+            });
+            return defer;
+        },
+        /* Unformat Quantity */
+        unformatQty: function(value){
+            value = value.replace(/[\.|,](\d{0,3}$)/, '?$1').split(/\?/);
+            value[0] = value[0].replace(/[^0-9]/g, '');
+            value = Number.parseFloat(value.join('.')) || 0;
+            return value;
+        },
+        /* Format Quantity */
+        formatQty: function(value, productoFormat, edit) {
+            value = value.toString();
+            value = value.split('.');
+
+            value[0] = value[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, `$1${productoFormat.thousandsSeparator}`);
+            if (!!value[1]) {
+                var decimalPlaces = value[1].length < productoFormat.decimalPlaces && edit ?value[1].length :productoFormat.decimalPlaces;
+                value[1] = Number.parseFloat(`1.${value[1]}e${decimalPlaces}`);
+                value[1] = Math.round(value[1]).toString().replace(/^1/, '');
+            }
+
+            value = productoFormat.decimalPlaces === 0 ?value[0]  :value.join(productoFormat.decimalSeparator);
+            return  value;
+        },
+        /*createI Invoice */
+        createReturnPicking: function(newPicking){
+            var self = this;
+            var stockReturn = new instanceWeb.Model('stock.return.picking');
+            return stockReturn.call('eiru_create_stock_return_picking',[newPicking],{
+                context: new instanceWeb.CompoundContext()
+            });
+        },
+
+    });
+
+    if (openerp.web && openerp.web.FormView) {
+        openerp.web.FormView.include({
+            load_record: function(record) {
+                this._super.apply(this, arguments);
+
+                if (this.model !== 'sale.order' && this.model !== 'purchase.order')
+                    return;
+
+                openerp.parentInstanceEiruStockPicking = this;
+
+                if (openerp.widgetInstanceEiruStockPicking) {
+                    openerp.widgetInstanceEiruStockPicking.updateId(record.id, this.model);
+                    if (this.$el.find('.button-stock-picking-returned').length !== 0)
+                        return;
+                }
+
+                if (this.$el.find('.button-stock-picking-returned').length !== 0)
+                    return;
+
+                openerp.widgetInstanceEiruStockPicking = new openerp.EiruStockPicking(this);
+                var element =this.$el.find('.oe_form').find('.eiru-stock-picking-return');
+
+                openerp.widgetInstanceEiruStockPicking.appendTo(element[0]);
+                openerp.widgetInstanceEiruStockPicking.updateId(record.id, this.model);
+            }
+        });
+    }
+})();

+ 8 - 0
static/src/xml/eiru_stock_picking.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates xml:space="preserve">
+    <t t-name="EiruStockPicking.Returned">
+        <button class="button-stock-picking-returned oe_button oe_form_button_save oe_highlight">
+            <div>Generar Devolución</div>
+        </button>
+  </t>
+</templates>

+ 90 - 0
static/src/xml/modal/modal_eiru_stock_picking.xml

@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="EiruStockPicking.ModalReturned">
+        <div class="modal in expired-account-modal" tabindex="-1" role="dialog">
+            <div class="modal-dialog modal-lg" role="document">
+                <div class="modal-content openerp">
+                    <div class="widget-content widget-loading-picking-invoice">
+                        <i class='fa fa-cog fa-spin fa-3x fa-fw'></i>
+                    </div>
+                    <!-- title  -->
+                    <div class="modal-header">
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close" aria-hidden="true">×</button>
+                        <h3 class="modal-title">Devolución de productos</h3>
+                    </div>
+                    <!-- Body -->
+                    <div class="modal-body">
+                        <!-- Table -->
+
+                        <div class=" oe_view_manager_body stock-picking-table">
+                            <div class="modal-head-wrapper-stock-picking">
+                                <table class="oe_list_content">
+                                    <thead >
+                                        <tr class="oe_list_header_columns"  >
+                                            <th class="oe_list_header_char oe_sortable"></th> <!-- move_id -->
+                                            <th class="oe_list_header_char oe_sortable"></th> <!-- product_id -->
+                                            <th class="oe_list_header_char oe_sortable"><input type="checkbox" class="select-stock-picking-all"></input></th>
+                                            <th class="oe_list_header_char oe_sortable">Producto</th>
+                                            <th class="oe_list_header_char oe_sortable sale-lable-table"></th>
+                                            <th class="oe_list_header_char oe_sortable">Devueltos</th>
+                                            <th class="oe_list_header_char oe_sortable">Disponible</th>
+                                            <th class="oe_list_header_char oe_sortable">A Devolver</th>
+                                        </tr>
+                                    </thead>
+                                </table>
+                            </div>
+                            <div class="modal-item-stock-picking">
+                                <table class="oe_list_content">
+                                    <tbody class="table-tbody">
+                                        <tr t-foreach="line" t-as="line">
+                                            <td>
+                                                <t t-esc="line_value.moveId"/>
+                                            </td>
+                                            <td>
+                                                <t t-esc="line_value.productId"/>
+                                            </td>
+                                            <td>
+                                                <input type="checkbox" class="select-stock-picking-retuned"></input>
+                                            </td>
+                                            <td>
+                                                <t t-esc="line_value.productName"/>
+                                            </td>
+                                            <td>
+                                                <input type="text" class="stock-picking-quantity" disabled="disabled" t-attf-value="{{ line_value.qty_order_format }}"></input>
+                                            </td>
+                                            <td>
+                                                <input type="text" class="stock-picking-quantity" disabled="disabled" t-attf-value="{{ line_value.qty_return_format }}"></input>
+                                            </td>
+                                            <td>
+                                                <input type="text" class="stock-picking-quantity picking-sale" disabled="disabled" t-attf-value="{{ line_value.qty_format }}"></input>
+                                            </td>
+                                            <td>
+                                                <input type="text" class="stock-picking-quantity picking-return" disabled="disabled" t-attf-value="{{ line_value.qty_format }}"></input>
+                                            </td>
+                                        </tr>
+                                    </tbody>
+                                </table>
+                            </div>
+                        </div>
+
+                        <!-- Crear Factura -->
+                        <div class="row ">
+                            <div class="col-xs-6">
+                                <label class="stock-picking-return-label picking-invoice-label">Crear factura por el movimiento de stock</label>
+                                <div class="stock-picking-return-group picking-invoice-group">
+                                    <input type="checkbox" class="picking-invoice-checkbox stock-return-invoiced" checked='checked'></input>
+                                </div>
+                            </div>
+                        </div>
+
+                    </div>
+                    <!-- Pie de Pagina -->
+                    <div class="modal-footer paymnets-invoice-footer">
+                        <button type="button" class="oe_button oe_form_button oe_highlight picking-invoice-button button-accept">Devolver</button>
+                        <button type="button" class="oe_button oe_form_button oe_link dismmis-modal picking-invoice-button" data-dismiss="modal">Salir</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </t>
+</template>

+ 15 - 0
views/eiru_stock_picking.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+	<data>
+        <record id="eiru_stock_picking_from" model="ir.ui.view">
+            <field name="name">eiru.stock.picking.from</field>
+            <field name="model">sale.order</field>
+            <field name="inherit_id" ref="sale.view_order_form"/>
+            <field name="arch" type="xml">
+                <field name="state" position="before">
+                    <div class="eiru-stock-picking-return" attrs="{'invisible': [('state','not in',['done','progress'])]}"></div>
+                </field>
+            </field>
+        </record>
+	</data>
+</openerp>

+ 15 - 0
views/eiru_stock_picking_purchase.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+	<data>
+        <record id="eiru_stock_picking_purchase_from" model="ir.ui.view">
+            <field name="name">eiru.stock.picking.purchase.from</field>
+            <field name="model">purchase.order</field>
+            <field name="inherit_id" ref="purchase.purchase_order_form"/>
+            <field name="arch" type="xml">
+                <field name="state" position="before">
+                    <div class="eiru-stock-picking-return" attrs="{'invisible': [('state','not in',['done','approved'])]}" ></div>
+                </field>
+            </field>
+        </record>
+	</data>
+</openerp>

+ 10 - 0
views/templates.xml

@@ -0,0 +1,10 @@
+<openerp>
+    <data>
+        <template id="eiru_stock_picking.eiru_assets" name="eiru_stock_picking_eiru_assets" inherit_id="eiru_assets.assets">
+            <xpath expr="." position="inside">
+                <link rel="stylesheet" href="/eiru_stock_picking/static/src/css/style.css"/>
+                <script type="text/javascript" src="/eiru_stock_picking/static/src/js/eiru_stock_picking.js"/>
+            </xpath>
+        </template>
+    </data>
+</openerp>