Sebas 5 роки тому
коміт
d267ca94be

+ 19 - 0
README.rst

@@ -0,0 +1,19 @@
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+:alt: License: AGPL-3
+
+Stock Warehouse Transfer
+========================
+Create an transfer of products between 2 warehouses. This will be done with the
+use of a transit location so an incoming and outgoing picking will be created.
+
+Bug Tracker
+===========
+Bugs are tracked on `GitHub Issues <https://github.com/ICTSTUDIO/8.0-extra-addons/issues>`_.
+
+Maintainer
+==========
+.. image:: https://www.ictstudio.eu/github_logo.png
+:alt: ICTSTUDIO
+   :target: https://www.ictstudio.eu
+
+This module is maintained by the ICTSTUDIO.

+ 21 - 0
__init__.py

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


+ 37 - 0
__openerp__.py

@@ -0,0 +1,37 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    Copyright (C) 2015 ICTSTUDIO (<http://www.ictstudio.eu>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+    'name': 'Stock Warehouse Transfer Custom',
+    'version': '8.0.0.0.1',
+    'license': 'AGPL-3',
+    'author': 'ICTSTUDIO/ADHOC/Rodney Enciso Arias/Adrielso Kunert',
+    'website': 'http://www.ictstudio.eu',
+    'category': 'Purchase',
+    'complexity': 'normal',
+    'summary': 'Create a transfer of products between 2 warehouses',
+    'depends': [
+        'stock','product_barcode_athletic',
+    ],
+    'data': [
+        'views/stock_warehouse_transfer.xml',
+        'data/ir_sequence.xml'
+    ],
+}

+ 18 - 0
data/ir_sequence.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+        <record id="stock_warehouse_transfer_ir_seq_type" model="ir.sequence.type">
+            <field name="name">Stock Warehouse Transfer</field>
+            <field name="code">stock.warehouse.transfer</field>
+        </record>
+
+        <record id="stock_warehouse_transfer_ir_sequence" model="ir.sequence">
+            <field name="name">Stock Warehouse Transfer</field>
+            <field name="code">stock.warehouse.transfer</field>
+            <field name="prefix">SWT</field>
+            <field name="padding">5</field>
+            <field name="company_id" eval="False"/>
+        </record>
+        
+    </data>
+</openerp>

+ 24 - 0
models/__init__.py

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

BIN
models/__init__.pyc


+ 63 - 0
models/search_barcode_picking.py

@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+
+from openerp import models, fields, api, _
+from openerp.exceptions import Warning as UserError
+
+class Search_Barcode_Picking(models.TransientModel):
+    _name = 'search.barcode.picking'
+    _description = 'Buscar Producto por Codigo de Barra en Compras'
+
+    quantity = fields.Float('Quantity', default='1.0')
+    products_ids = fields.Many2many( 'product.product',
+                                      string='Products',
+                                      domain=[('sale_ok', '=', True)], )
+    # product_code = fields.Char( string='Codigo de Barra EAN13 ',
+    #                             help="Este campo está diseñado para ser llenado con un lector de código de barras")
+
+    # @api.onchange('product_code')
+    # def product_code_change(self):
+    #     if self.product_code:
+    #         products = self.env['product.product'].search([
+    #                             '|', ('ean13', '=', self.product_code), ('default_code', '=ilike', self.product_code)])
+    #
+    #         if len(products) == 1:
+    #             self.products_ids += products[0]
+    #             self.product_code =None
+    #
+    #         elif len(products) > 1:
+    #             self.product_code =None
+    #             return {'warning': {
+    #                 'title': _('Error'),
+    #                 'message': _(
+    #                     'Varios productos se han encontrado con el código (EAN 13) ingresado,'
+    #                     '\nDebe seleccionar el producto manualmente.')}}
+    #         else:
+    #             self.product_code =None
+    #             return {'warning': {
+    #                 'title': _('Error'),
+    #                 'message': _(
+    #                     'Ningún producto encontrado con el  código (EAN 13) ingresado, Debe seleccionar el producto manualmente')}}
+
+    @api.one
+    def add_multiple(self):
+        active_id = self._context['active_id']
+        stock_transfer = self.env['stock.warehouse.transfer'].browse(active_id)
+
+        for product_id in self.products_ids:
+            xxproducts = self.env['product.product'].search([('id', '=', product_id.id)])
+            orde_line_datos = self.env['stock.warehouse.transfer.line'].search([('transfer', '=', stock_transfer.id), ('product_id', "=", xxproducts.id)])
+
+            product = self.env['stock.warehouse.transfer.line'].product_id_change(
+                product_id.id,
+                qty=self.quantity)
+
+            if orde_line_datos:
+                orde_line_datos.write({ 'product_qty' : (orde_line_datos.product_qty + 1)})
+            else:
+                val = {
+                    'product_id': product_id.id or False,
+                    'product_qty': self.quantity,
+                    'product_uom_id': product_id.uom_po_id.id,
+                    'transfer': active_id,
+                }
+                self.env['stock.warehouse.transfer.line'].create(val)

BIN
models/search_barcode_picking.pyc


+ 32 - 0
models/stock_picking.py

@@ -0,0 +1,32 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    Copyright (C) 2015 ICTSTUDIO (<http://www.ictstudio.eu>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp import models, fields, api, _
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class StockPicking(models.Model):
+    _inherit = 'stock.picking'
+
+    transfer = fields.Many2one(
+            comodel_name='stock.warehouse.transfer',
+            string='Transfer')

BIN
models/stock_picking.pyc


+ 157 - 0
models/stock_warehouse_transfer.py

@@ -0,0 +1,157 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    Copyright (C) 2015 ICTSTUDIO (<http://www.ictstudio.eu>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp import models, fields, api, _
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class StockWarehouseTransfer(models.Model):
+    _name = 'stock.warehouse.transfer'
+    _description = 'Stock Warehouse Transfer'
+    _inherit = ['mail.thread', 'ir.needaction_mixin']
+
+    @api.model
+    def _get_default_name(self):
+        return self.env['ir.sequence'].get('stock.warehouse.transfer')
+
+    @api.model
+    def _get_default_date(self):
+        return fields.Date.context_today(self)
+
+    @api.model
+    def _get_default_state(self):
+        return 'draft'
+
+    @api.multi
+    @api.depends('pickings.state')
+    def _calc_transfer_state(self):
+        for rec in self:
+            if rec.pickings:
+                picking_states = [p.state for p in rec.pickings]
+                if 'done' in picking_states:
+                    rec.state = 'done'
+                else:
+                    rec.state = 'picking'
+
+            else:
+                rec.state = 'draft'
+
+    name = fields.Char(
+            string='Referencia',
+            default=_get_default_name)
+    date = fields.Date(
+            string='Fecha',
+            default=_get_default_date)
+    source_warehouse = fields.Many2one(
+            comodel_name='stock.warehouse',
+            string='Sucursal de Origen')
+    dest_warehouse = fields.Many2one(
+            comodel_name='stock.warehouse',
+            string='Sucursal de Destino')
+    state = fields.Selection(
+            selection=[
+                ('draft', 'Borrador'),
+                ('picking', 'Picking'),
+                ('done', 'Realizado')],
+            string='Status',
+            default=_get_default_state,
+            store=True,
+            compute=_calc_transfer_state)
+    lines = fields.One2many(
+            comodel_name='stock.warehouse.transfer.line',
+            inverse_name='transfer',
+            string='Lineas de Transferencia')
+    pickings = fields.One2many(
+            comodel_name='stock.picking',
+            inverse_name='transfer',
+            string='Transferencia Relacionada')
+    company_id = fields.Many2one(
+            comodel_name='res.company', string='Compania', required=True,
+            default=lambda self: self.env['res.company']._company_default_get(
+                    'stock.warehouse.transfer'))
+
+
+    def get_transfer_picking_type(self):
+        self.ensure_one()
+
+        picking_types = self.env['stock.picking.type'].search(
+                [
+                    ('default_location_src_id', '=', self.source_warehouse.lot_stock_id.id),
+                    ('code', '=', 'outgoing')
+                ]
+        )
+        if not picking_types:
+            _logger.error("No picking tye found")
+            #TODO: Exception Raise
+
+        return picking_types and picking_types[0]
+
+    @api.multi
+    def get_picking_vals(self):
+        self.ensure_one()
+        picking_type = self.get_transfer_picking_type()
+        picking_vals = {
+            'picking_type_id' : picking_type.id,
+            'transfer' : self.id,
+            'origin': self.name
+        }
+
+        return picking_vals
+
+    @api.multi
+    def action_create_picking(self):
+        for rec in self:
+            picking_vals = rec.get_picking_vals()
+            _logger.debug("Picking Vals: %s", picking_vals)
+            picking = rec.pickings.create(picking_vals)
+            if not picking:
+                _logger.error("Error Creating Picking")
+                #TODO: Add  Exception
+
+            pc_group = rec._get_procurement_group()
+
+            for line in rec.lines:
+                move_vals = line.get_move_vals(picking, pc_group)
+                if move_vals:
+                    _logger.debug("Move Vals: %s", move_vals)
+                    self.env['stock.move'].create(move_vals)
+
+            picking.action_confirm()
+            picking.action_assign()
+
+    @api.model
+    def _prepare_procurement_group(self):
+        return {'name': self.name}
+
+    @api.model
+    def _get_procurement_group(self):
+        pc_groups = self.env['procurement.group'].search(
+                [
+                    ('name', '=', self.name)
+                ]
+        )
+        if pc_groups:
+            pc_group = pc_groups[0]
+        else:
+            pc_vals = self._prepare_procurement_group()
+            pc_group = self.env['procurement.group'].create(pc_vals)
+        return pc_group or False

BIN
models/stock_warehouse_transfer.pyc


+ 107 - 0
models/stock_warehouse_transfer_line.py

@@ -0,0 +1,107 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    Copyright (C) 2015 ICTSTUDIO (<http://www.ictstudio.eu>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp import models, fields, api, _
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
+class StockWarehouseTransferLine(models.Model):
+    _name = 'stock.warehouse.transfer.line'
+    _rec_name = 'product_id'
+
+
+    @api.model
+    def _get_default_product_qty(self):
+        return 1.0
+
+
+    product_id = fields.Many2one(
+            comodel_name='product.product',
+            string='Producto')
+    product_qty = fields.Float(
+            string='Cantidad',
+            default=_get_default_product_qty)
+    product_uom_id = fields.Many2one(
+            comodel_name='product.uom',
+            string='Unidad de Medida')
+    transfer = fields.Many2one(
+            comodel_name='stock.warehouse.transfer',
+            string='Transfer')
+    note = fields.Text(string='Note')
+    source_location = fields.Many2one(
+            comodel_name='stock.location',
+            string='Source Location',
+            compute='_get_transfer_locations',
+            store=True)
+    dest_location = fields.Many2one(
+            comodel_name='stock.location',
+            string='Destination Location',
+            compute='_get_transfer_locations',
+            store=True)
+
+
+    @api.one
+    @api.onchange('product_id')
+    def product_id_change(self):
+        self.product_uom_id = self.product_id.uom_id and self.product_id.uom_id.id or False
+
+    @api.multi
+    @api.depends('transfer.source_warehouse', 'transfer.dest_warehouse')
+    def _get_transfer_locations(self):
+        for rec in self:
+            rec.source_location = rec.transfer.source_warehouse.lot_stock_id.id
+            dest_location = False
+            transit_locations = self.env['stock.location'].search(
+                    [
+                        ('usage', '=', 'inventory')
+                    ]
+            )
+            for location in transit_locations:
+                if location.get_warehouse(location) == rec.transfer.dest_warehouse.id:
+                    dest_location = location.id
+
+            if not dest_location:
+                rec.dest_location = rec.transfer.dest_warehouse.lot_stock_id.id
+            else:
+                rec.dest_location = dest_location
+
+    @api.multi
+    def get_move_vals(self, picking, group):
+        """
+        Get the correct move values
+        :param picking:
+        :param group:
+        :return: dict
+        """
+
+        self.ensure_one()
+        return {
+            'name' : 'Warehouse Transfer',
+            'product_id' : self.product_id.id,
+            'product_uom' : self.product_uom_id.id,
+            'product_uom_qty' : self.product_qty,
+            'location_id' : self.source_location.id,
+            'location_dest_id' : self.dest_location.id,
+            'picking_id' : picking.id,
+            'group_id': group.id,
+            'note': self.note
+        }

BIN
models/stock_warehouse_transfer_line.pyc


BIN
static/description/icon.png


BIN
static/description/icon_image


+ 17 - 0
views/picking_product_view.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!-- <openerp>
+    <data>
+        <record id="view_warehouse_form" model="ir.ui.view">
+            <field name="name">warehouse.form</field>
+            <field name="model">stock.warehouse.transfer</field>
+            <field name="inherit_id" ref="stock_warehouse_transfer.stock_warehouse_transfer_view_form"/>
+            <field name="arch" type="xml">
+                <field name="lines" position="before">
+                    <button name="%(action_purchase_add_multiple)d"
+                            type="action" string="Activar Lector"
+                            attrs="{'invisible':[('state','not in',['draft','sent'])]}"/>
+                </field>
+            </field>
+        </record>
+    </data>
+</openerp> -->

+ 77 - 0
views/stock_warehouse_transfer.xml

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <record id="stock_warehouse_transfer_view_tree" model="ir.ui.view">
+            <field name="name">stock.warehouse.transfer.view.tree</field>
+            <field name="model">stock.warehouse.transfer</field>
+            <field name="arch" type="xml">
+                <tree string="Transfers">
+                    <field name="name"/>
+                    <field name="date"/>
+                    <field name="source_warehouse"/>
+                    <field name="dest_warehouse"/>
+                    <field name="pickings"/>
+                    <field name="state"/>
+                </tree>
+            </field>
+        </record>
+
+        <record id="stock_warehouse_transfer_view_form" model="ir.ui.view">
+            <field name="name">stock.warehouse.transfer.view.form</field>
+            <field name="model">stock.warehouse.transfer</field>
+            <field name="arch" type="xml">
+                <form string="Transfer">
+                    <header>
+                        <button name="action_create_picking" type="object" states="draft" class="oe_highlight" string="Crear Transferencia"/>
+                        <field name="state" widget="statusbar" translate="1"/>
+                    </header>
+
+                    <sheet>
+                        <h1>
+                            <field name="name" required="1" placeholder="Reference" attrs="{'readonly':[('state','!=','draft')]}"/>
+                        </h1>
+
+                        <group>
+                            <field name="date" required="1" attrs="{'readonly':[('state','!=','draft')]}"/>
+                        </group>
+
+                        <group col="4">
+                            <field name="source_warehouse" required="1" attrs="{'readonly':[('state','!=','draft')]}"/>
+                            <field name="dest_warehouse" required="1" attrs="{'readonly':[('state','!=','draft')]}"/>
+                        </group>
+
+                        <separator colspan="4" string="Transferencia" attrs="{'invisible':[('state','in','draft')]}"/>
+                        <field colspan="4" name="pickings" readonly="1" nolabel="1" attrs="{'readonly':[('state','!=','draft')],'invisible':[('state','=','draft')]}"/>
+
+                        <separator colspan="4" string="Productos"/>
+                        <field colspan="4" name="lines" nolabel="1" attrs="{'readonly':[('state','!=','draft')]}">
+                            <tree editable="bottom">
+                                <field name="product_id" domain="[('type','!=','service')]" required="1" options="{'no_create':True,'no_open':True}"/>
+                                <field name="product_qty" required="1" sum="qty"/>
+                                <field name="product_uom_id" required="1" invisible="1"/>
+                                <field name="source_location" invisible="1"/>
+                                <field name="dest_location" invisible="1"/>
+                                <field name="note" invisible="1"/>
+                            </tree>
+                        </field>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+
+        <record id="stock_warehouse_transfer_action" model="ir.actions.act_window">
+            <field name="name">Transferir Productos</field>
+            <field name="res_model">stock.warehouse.transfer</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+        </record>
+
+        <menuitem action="stock_warehouse_transfer_action"
+          id="stock_warehouse_transfer_menu"
+          parent="stock.menu_stock_warehouse_mgmt"
+          sequence="50"/>
+
+      </data>
+  </openerp>

+ 39 - 0
wizard/picking_add_multiple.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!-- <openerp>
+    <data>
+        <record model="ir.ui.view" id="search_barcode_picking_view">
+            <field name="name">search.barcode.picking.form</field>
+            <field name="model">search.barcode.picking</field>
+            <field name="arch" type="xml">
+                <form string="Add Multiple">
+
+                    <group>
+                        <field name='product_code' />
+                    </group>
+                    <group>
+                        <field name="products_ids" nolabel='1'>
+                          <tree string="Product Variants">
+                            <field name="factory_reference"/>
+                            <field name="factory_barcode"/>
+                            <field name="product_tmpl_id"/>
+                            <field name="attribute_value_ids" widget="many2many_tags"/>
+                          </tree>
+                        </field>
+                    </group>
+                <footer>
+                    <button name="add_multiple" type="object" class="oe_highlight" string="Aceptar"/>
+                </footer>
+                </form>
+            </field>
+        </record>
+
+        <record model="ir.actions.act_window" id="action_purchase_add_multiple">
+            <field name="name">Adicionar multiples productos</field>
+            <field name="res_model">search.barcode.picking</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="view_id" ref="search_barcode_picking_view"/>
+            <field name="target">new</field>
+        </record>
+    </data>
+</openerp> -->