Ver Fonte

commit inicial

Rodney Elpidio Enciso Arias há 6 anos atrás
commit
053a48ac95

+ 61 - 0
README.rst

@@ -0,0 +1,61 @@
+.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
+   :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+   :alt: License: AGPL-3
+
+==================
+Sale Order Barcode
+==================
+
+This module provides a wizard to add product 
+with the help of a barcode reader on sale order
+
+Installation
+============
+
+To install this module, you need to:
+
+1.  Clone the branch 8.0 of the repository https://github.com/open-synergy/opnsynid-sale-workflow
+2.  Add the path to this repository in your configuration (addons-path)
+3.  Update the module list
+4.  Go to menu *Setting -> Modules -> Local Modules*
+5.  Search For *Sale Order Barcode*
+6.  Install the module
+
+Configuration
+=============
+
+
+Usage
+=====
+
+
+
+Known issues / Roadmap
+======================
+
+
+Bug Tracker
+===========
+
+Bugs are tracked on `GitHub Issues
+<https://github.com/open-synergy/opnsynid-sale-workflow/issues>`_.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed
+and welcomed feedback.
+
+Credits
+=======
+
+Contributors
+------------
+
+* Michael Viriyananda <viriyananda.michael@gmail.com>
+
+Maintainer
+----------
+
+.. image:: https://opensynergy-indonesia.com/logo.png
+   :alt: OpenSynergy Indonesia
+   :target: https://opensynergy-indonesia.com
+
+This module is maintained by the OpenSynergy Indonesia.

+ 5 - 0
__init__.py

@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from . import wizards

BIN
__init__.pyc


+ 19 - 0
__openerp__.py

@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+{
+    "name": "Sale Order Barcode",
+    "version": "8.0.2.0.0",
+    "category": "Sale",
+    "website": "https://opensynergy-indonesia.com",
+    "author": "OpenSynergy Indonesia",
+    "license": "AGPL-3",
+    "installable": True,
+    "depends": [
+        "sale",
+    ],
+    "data": [
+        "wizards/sale_order_barcode_view.xml",
+        "views/sale_order_view.xml"
+    ],
+}

BIN
static/description/icon.png


+ 5 - 0
tests/__init__.py

@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import test_onchange_product_barcode

+ 305 - 0
tests/test_onchange_product_barcode.py

@@ -0,0 +1,305 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from openerp.tests.common import TransactionCase
+from openerp.exceptions import Warning as UserError
+
+
+class TestOnchangeProductBarcode(TransactionCase):
+    def setUp(self, *args, **kwargs):
+        super(TestOnchangeProductBarcode, self).setUp(*args, **kwargs)
+        # Objects
+        self.wiz = self.env['sale.order.barcode']
+        self.obj_sale_order_line =\
+            self.env['sale.order.line']
+
+        # Data
+        self.data_so = self.env['sale.order'].create({
+            'partner_id': self.env.ref('base.res_partner_1').id,
+        })
+        self.product_1 =\
+            self.env.ref('product.product_product_25')
+        self.product_2 =\
+            self.env.ref('product.product_product_30')
+        self.product_3 =\
+            self.env.ref('product.product_product_3')
+        self.uom_unit =\
+            self.env.ref('product.product_uom_unit')
+        self.uom_dozen =\
+            self.env.ref('product.product_uom_dozen')
+
+    def test_error_product_no_ean_13(self):
+        new = self.wiz.with_context(
+            active_model="sale.order",
+            active_id=self.data_so.id
+        ).new()
+
+        new.product_barcode = 0000000000000
+        res = new.product_barcode_onchange()
+        self.assertEquals(
+            'No product found with this code as '
+            'EAN13 or product is not for sale. You should select '
+            'the right product manually.',
+            res['warning']['message']
+        )
+
+    def test_error_product_duplicate_ean(self):
+        new = self.wiz.with_context(
+            active_model="sale.order",
+            active_id=self.data_so.id
+        ).new()
+
+        self.product_1.ean13 = 8998989300155
+        self.product_2.ean13 = 8998989300155
+
+        new.product_barcode = 8998989300155
+        res = new.product_barcode_onchange()
+        self.assertIsNotNone(
+            res['warning']['message']
+        )
+
+    def test_error_more_than_1_line(self):
+        order_line = [
+            (0, 0, {
+                'product_id': self.product_1.id,
+                'product_uom_qty': 5,
+                }),
+            (0, 0, {
+                'product_id': self.product_1.id,
+                'product_uom_qty': 1,
+                }),
+        ]
+
+        self.data_so.update({
+            'order_line': order_line
+        })
+
+        new = self.wiz.with_context(
+            active_model="sale.order",
+            active_id=self.data_so.id
+        ).new()
+
+        self.product_1.ean13 = 8998989300155
+
+        new.product_barcode = 8998989300155
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 20.0
+
+        msg = ("More than 1 line found")
+
+        with self.assertRaises(UserError) as error:
+            new.save()
+
+        self.assertEqual(error.exception.message, msg)
+
+    def test_product_barcode_condition_1(self):
+        # CONDITION
+        # 1. type = INSERT
+        # 2. Uom Lines = Uom Wizard
+        # 3. Using single product
+
+        self.product_1.ean13 = 8998989300155
+
+        new = self.wiz.with_context(
+            active_model="sale.order",
+            active_id=self.data_so.id
+        ).new()
+
+        new.type = 'insert'
+        new.product_barcode = 8998989300155
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 5.0
+        new.save()
+
+        new.type = 'insert'
+        new.product_barcode = 8998989300155
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 9.0
+        new.save()
+
+        line_1 = self.obj_sale_order_line.search([
+            ('order_id', '=', self.data_so.id),
+            ('product_id', '=', self.product_1.id)
+        ])
+        self.assertEqual(line_1.product_uom_qty, 14.0)
+
+    def test_product_barcode_condition_2(self):
+        # CONDITION
+        # 1. type = INSERT
+        # 2. Uom Lines != Uom Wizard
+        # 3. Using single product
+
+        self.product_2.ean13 = 8996001600382
+
+        new = self.wiz.with_context(
+            active_model="sale.order",
+            active_id=self.data_so.id
+        ).new()
+
+        new.type = 'insert'
+        new.product_barcode = 8996001600382
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 1.0
+        new.save()
+
+        new.type = 'insert'
+        new.product_barcode = 8996001600382
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 2.0
+        new.product_uom_id = self.uom_dozen.id
+        new.save()
+
+        line_1 = self.obj_sale_order_line.search([
+            ('order_id', '=', self.data_so.id),
+            ('product_id', '=', self.product_2.id)
+        ])
+        self.assertEqual(line_1.product_uom_qty, 25.0)
+
+    def test_product_barcode_condition_3(self):
+        # CONDITION
+        # 1. type = UPDATE
+        # 2. Uom Lines = Uom Wizard
+        # 3. Using single product
+
+        self.product_1.ean13 = 8998989300155
+
+        new = self.wiz.with_context(
+            active_model="sale.order",
+            active_id=self.data_so.id
+        ).new()
+
+        new.type = 'insert'
+        new.product_barcode = 8998989300155
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 1.0
+        new.save()
+
+        new.type = 'update'
+        new.product_barcode = 8998989300155
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 2.0
+        new.save()
+
+        line_1 = self.obj_sale_order_line.search([
+            ('order_id', '=', self.data_so.id),
+            ('product_id', '=', self.product_1.id)
+        ])
+        self.assertEqual(line_1.product_uom_qty, 2.0)
+
+    def test_product_barcode_condition_4(self):
+        # CONDITION
+        # 1. type = UPDATE
+        # 2. Uom Lines != Uom Wizard
+        # 3. Using single product
+
+        self.product_3.ean13 = 8998666000903
+
+        new = self.wiz.with_context(
+            active_model="sale.order",
+            active_id=self.data_so.id
+        ).new()
+
+        new.type = 'insert'
+        new.product_barcode = 8998666000903
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 4.0
+        new.save()
+
+        new.type = 'update'
+        new.product_barcode = 8998666000903
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 1.0
+        new.product_uom_id = self.uom_dozen.id
+        new.save()
+
+        line_1 = self.obj_sale_order_line.search([
+            ('order_id', '=', self.data_so.id),
+            ('product_id', '=', self.product_3.id)
+        ])
+        self.assertEqual(line_1.product_uom_qty, 12.0)
+
+    def test_product_barcode_condition_5(self):
+        # CONDITION
+        # 1. type = UPDATE & INSERT
+        # 2. Uom Lines != Uom Wizard & Uom Lines = Uom Wizard
+        # 3. Using multiple product
+
+        self.product_1.ean13 = 8998989300155
+        self.product_2.ean13 = 8996001600382
+        self.product_3.ean13 = 8998666000903
+
+        new = self.wiz.with_context(
+            active_model="sale.order",
+            active_id=self.data_so.id
+        ).new()
+
+        new.type = 'insert'
+        new.product_barcode = 8998989300155
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 3.0
+        new.save()
+
+        new.type = 'insert'
+        new.product_barcode = 8996001600382
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 10.0
+        new.save()
+
+        new.type = 'insert'
+        new.product_barcode = 8998666000903
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 8.0
+        new.save()
+
+        new.type = 'update'
+        new.product_barcode = 8998989300155
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 13.0
+        new.save()
+
+        new.type = 'insert'
+        new.product_barcode = 8996001600382
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 10.0
+        new.save()
+
+        new.type = 'update'
+        new.product_barcode = 8998666000903
+        new.product_barcode_onchange()
+        new.product_id_onchange()
+        new.product_qty = 10.0
+        new.product_uom_id = self.uom_dozen.id
+        new.save()
+
+        line_1 = self.obj_sale_order_line.search([
+            ('order_id', '=', self.data_so.id),
+            ('product_id', '=', self.product_1.id)
+        ])
+        self.assertEqual(line_1.product_uom_qty, 13.0)
+
+        line_2 = self.obj_sale_order_line.search([
+            ('order_id', '=', self.data_so.id),
+            ('product_id', '=', self.product_2.id)
+        ])
+        self.assertEqual(line_2.product_uom_qty, 20.0)
+
+        line_3 = self.obj_sale_order_line.search([
+            ('order_id', '=', self.data_so.id),
+            ('product_id', '=', self.product_3.id)
+        ])
+        self.assertEqual(line_3.product_uom_qty, 120.0)

+ 18 - 0
views/sale_order_view.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <record id="sale_order_view_form" model="ir.ui.view">
+            <field name="name">Sale Order Barcode Inherit Form</field>
+            <field name="model">sale.order</field>
+            <field name="inherit_id" ref="sale.view_order_form"/>
+            <field name="arch" type="xml">
+                <xpath expr="//field[@name='order_line']" position="before">
+                    <button name="%(sale_order_barcode_action)d" type="action"
+                        string="Lector" states="draft"/>
+                </xpath>
+            </field>
+        </record>
+
+    </data>
+</openerp>

+ 5 - 0
wizards/__init__.py

@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from . import sale_order_barcode

BIN
wizards/__init__.pyc


+ 154 - 0
wizards/sale_order_barcode.py

@@ -0,0 +1,154 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 OpenSynergy Indonesia
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from openerp import models, fields, api, _
+import openerp.addons.decimal_precision as dp
+from openerp.exceptions import Warning as UserError
+
+
+class SaleOrderBarcode(models.TransientModel):
+    _name = 'sale.order.barcode'
+    _description = 'Sale Order Barcode Wizard'
+
+    product_barcode = fields.Char(
+        string='Product Barcode (EAN13)',
+        help="This field is designed to be filled with a barcode reader")
+    product_id = fields.Many2one(
+        comodel_name='product.product',
+        string='Product',
+        required=True)
+    product_qty = fields.Float(
+        string='Quantity',
+        digits=dp.get_precision('Product Unit of Measure'),
+        default=1.0)
+    product_uom_id = fields.Many2one(
+        comodel_name='product.uom',
+        string='Unit of Measure',
+        required=True)
+    type = fields.Selection(
+        [
+            ('insert', 'Insert'),
+            ('update', 'Update'),
+        ],
+        string='Type',
+        required=True,
+        default=lambda self: self._context.get('type', 'insert')
+    )
+
+    @api.multi
+    def _prepare_domain(self):
+        self.ensure_one()
+        domain = [
+            ('ean13', '=', self.product_barcode),
+            ('sale_ok', '=', True)
+        ]
+        return domain
+
+    @api.multi
+    def _check_uom(self, lines):
+        self.ensure_one()
+        new_uom = self.product_uom_id.id
+        old_uom = lines.product_uom.id
+
+        if new_uom != old_uom:
+            return False
+        else:
+            return True
+
+    @api.multi
+    def _convert_uom(self, lines, product_qty):
+        self.ensure_one()
+        obj_product = self.env['product.uom']
+        from_uom = self.product_uom_id.id
+        to_uom = lines.product_uom.id
+
+        return obj_product._compute_qty(
+            from_uom_id=from_uom,
+            qty=product_qty,
+            to_uom_id=to_uom)
+
+    @api.onchange('product_barcode')
+    def product_barcode_onchange(self):
+        obj_product = self.env['product.product']
+        if self.product_barcode:
+            domain = self._prepare_domain()
+            products = obj_product.search(domain)
+            if len(products) == 1:
+                self.product_id = products[0]
+            elif len(products) > 1:
+                return {'warning': {
+                    'title': _('Error'),
+                    'message': _(
+                        'Several products have been found '
+                        'with this code as EAN13 or Internal Reference:\n %s'
+                        '\nYou should select the right product manually.'
+                        ) % '\n'.join([
+                            product.name_get()[0][1] for product in products
+                        ])}}
+            else:
+                return {'warning': {
+                    'title': _('Error'),
+                    'message': _(
+                        'No product found with this code as '
+                        'EAN13 or product is not for sale. You should select '
+                        'the right product manually.')}}
+
+    @api.onchange('product_id')
+    def product_id_onchange(self):
+        if self.product_id:
+            self.product_uom_id = self.product_id.uom_id.id
+
+    @api.multi
+    def create_sale_order_line(self):
+        self.ensure_one()
+        obj_sale_order_line = self.env['sale.order.line']
+        active_id = self._context['active_id']
+
+        lines = obj_sale_order_line.search([
+            ('order_id', '=', active_id),
+            ('product_id', '=', self.product_id.id),
+        ])
+
+        if len(lines) == 1:
+            check_uom = self._check_uom(lines)
+            if check_uom is True:
+                product_qty = self.product_qty
+            else:
+                product_qty = self._convert_uom(
+                    lines,
+                    self.product_qty
+                )
+            if self.type == 'insert':
+                lines.write({
+                    'product_uom_qty': lines.product_uom_qty + product_qty
+                })
+            elif self.type == 'update':
+                lines.write({
+                    'product_uom_qty': product_qty
+                })
+        elif len(lines) > 1:
+            raise UserError(_("More than 1 line found"))
+
+        elif len(lines) == 0:
+            obj_sale_order_line.create({
+                'order_id': active_id,
+                'product_id': self.product_id.id,
+                'product_uom': self.product_uom_id.id,
+                'product_uom_qty': self.product_qty
+            })
+
+    @api.multi
+    def save(self):
+        self.ensure_one()
+        self.create_sale_order_line()
+        action = {
+            'name': _('Sale Order Barcode Interface'),
+            'type': 'ir.actions.act_window',
+            'res_model': 'sale.order.barcode',
+            'view_mode': 'form',
+            'nodestroy': True,
+            'target': 'new',
+            'context': self._context,
+            }
+        return action

BIN
wizards/sale_order_barcode.pyc


+ 38 - 0
wizards/sale_order_barcode_view.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <record id="sale_order_barcode_view_form" model="ir.ui.view">
+            <field name="name">Sale Order Barcode Form</field>
+            <field name="model">sale.order.barcode</field>
+            <field name="arch"  type="xml">
+                <form string="Sale Order Barcode Wizard">
+                    <group name="product">
+                        <field name="product_barcode" string="Codigo de barras"/>
+                        <field name="product_id" options='{"no_open": True}' string="Producto"/>
+                        <label for="product_qty" string="Cantidad"/>
+                        <div>
+                            <field name="product_qty" class="oe_inline"/>
+                            <field name="product_uom_id" options='{"no_open": True}' class="oe_inline"/>
+                        </div>
+                        <field name="type" invisible="1"/>
+                    </group>
+                    <footer>
+                        <button name="save" type="object"
+                            class="oe_highlight" string="Guardar y Nuevo"/>
+                            or
+                        <button special="cancel" string="Cancel" class="oe_link"/>
+                    </footer>
+                </form>
+            </field>
+        </record>
+
+        <record id="sale_order_barcode_action" model="ir.actions.act_window">
+            <field name="name">Interfaz de Búsqueda</field>
+            <field name="res_model">sale.order.barcode</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+        </record>
+
+    </data>
+</openerp>