Selaa lähdekoodia

commit inicial

Rodney Elpidio Enciso Arias 6 vuotta sitten
commit
c18df533c9

+ 1 - 0
.gitignore

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

+ 2 - 0
__init__.py

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

BIN
__init__.pyc


+ 26 - 0
__openerp__.py

@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+{
+    'name': "Eiru Reports - Gastos",
+    'author': "Eiru",
+    'category': 'report',
+    'version': '1.1',
+    'depends': [
+        'base',
+        'product',
+        'account',
+        'stock',
+        'eiru_assets',
+        'account_journal_active',
+        'multi_store',
+        'multi_store_stock',
+    ],
+    'qweb': [
+        'static/src/xml/*.xml',
+        'static/src/reports/*.xml'
+    ],
+    'data': [
+        'templates.xml',
+        'views/actions.xml',
+        'views/menus.xml',
+    ],
+}

+ 1 - 0
controller/__init__.py

@@ -0,0 +1 @@
+import main

BIN
controller/__init__.pyc


+ 6 - 0
controller/helpers/__init__.py

@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+# ACCOUNT INVOICE
+from account_invoice import get_account_invoice_expense
+from account_invoice_line import get_account_invoice_line_expense
+# ACCOUNT VOUCHER
+from account_voucher import get_account_voucher_supplier

BIN
controller/helpers/__init__.pyc


+ 84 - 0
controller/helpers/account_invoice.py

@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_account_invoice_expense():
+    company_currency_rate = r.env.user.company_id.currency_id.rate
+    origin = '%PO%'
+    query = '''
+        SELECT
+        	invoice.id,
+        	rate.currency_id,
+        	invoice.date_invoice,
+        	invoice.type,
+        	invoice.origin,
+        	invoice.partner_id,
+        	invoice.user_id,
+        	invoice.amount_total * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]),
+            invoice.number,
+            partner.name,
+            customer.name,
+            invoice.amount_tax * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]),
+            invoice.state,
+            journal.store_id,
+            invoice.journal_id,
+            invoice.state,
+            invoice.company_id
+        FROM account_invoice AS invoice
+        LEFT JOIN res_store_journal_rel AS journal
+        ON journal.journal_id = invoice.journal_id
+        LEFT JOIN res_currency_rate AS rate
+        ON rate.currency_id = invoice.currency_id
+        LEFT JOIN res_company AS company
+        ON company.id = invoice.company_id
+        LEFT JOIN res_users AS users
+        ON users.id = invoice.user_id
+        LEFT JOIN res_partner AS partner
+        ON partner.id = users.partner_id
+        LEFT JOIN res_partner AS customer
+        ON customer.id = invoice.partner_id
+        WHERE invoice.state NOT IN ('draft', 'cancel')
+        AND invoice.type IN ('in_invoice')
+        AND (invoice.origin NOT LIKE %s OR invoice.origin IS NULL)
+        GROUP BY
+        	invoice.id,
+        	rate.currency_id,
+        	invoice.date_invoice,
+        	invoice.type,
+        	invoice.origin,
+        	invoice.amount_total,
+        	invoice.partner_id,
+        	invoice.user_id,
+            invoice.amount_total,
+            partner.name,
+            customer.name,
+            invoice.amount_tax,
+            invoice.state,
+            journal.store_id,
+            invoice.journal_id,
+            invoice.state,
+            invoice.company_id
+    '''
+
+    r.cr.execute(query,(tuple([company_currency_rate,company_currency_rate,origin])))
+
+    return [
+        {
+            'invoice_id': j[0],
+            'currency_id': j[1],
+            'date': j[2],
+            'type': j[3],
+            'origin': j[4],
+            'customer_id':j[5],
+            'user_id':j[6],
+            'amount':j[7],
+            'number':j[8],
+            'user_name':j[9],
+            'customer_name':j[10],
+            'amount_tax':j[11],
+            'state':j[12],
+            'store_id':j[13],
+            'journal_id':j[14],
+            'state':j[15],
+            'company_id':j[16]
+        } for j in r.cr.fetchall()
+    ]

BIN
controller/helpers/account_invoice.pyc


+ 230 - 0
controller/helpers/account_invoice_line.py

@@ -0,0 +1,230 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_account_invoice_line_expense():
+    user_store = r.env.user.store_id.id
+    company_currency_rate = r.env.user.company_id.currency_id.rate
+    origin = '%PO%'
+
+    validate_brand = '''
+        SELECT EXISTS(
+            SELECT table_name
+            FROM information_schema.columns
+            WHERE table_schema='public'
+                AND table_name='product_brand')
+    '''
+
+    query_with_brand = '''
+        SELECT
+        	invoice.id AS invoice_id,
+        	line.id AS invoice_line_id,
+        	invoice.number,
+        	invoice.origin,
+        	invoice.date_invoice,
+        	invoice.type,
+            CASE
+        		WHEN product.default_code IS NOT NULL
+        		THEN ('[' || product.default_code || '] ' || product.name_template)
+        		ELSE product.name_template
+        		END AS display_name,
+        	line.price_unit * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]) as price_unit,
+        	line.quantity AS cant,
+        	line.price_subtotal * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]) AS subtotal,
+        	(line.quantity * (line.price_unit * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]))) - (((line.quantity * (line.price_unit * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]) * line.discount)/100))) - (line.price_subtotal * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1])) AS impuestos,
+        	(array_agg(history.cost ORDER BY history.id DESC))[1] AS cost,
+            --line.name
+            journal.store_id,
+            template.categ_id,
+            partner.name,
+            product.id,
+            invoice.company_id,
+            invoice.journal_id,
+            (array_agg(attr_rel.att_id)) AS attr_rel,
+            (array_agg(attr_value.name)) AS attr_value,
+            (array_agg(attr.id)) AS attr,
+            template.product_brand_id,
+            brand.name,
+            line.discount
+            FROM account_invoice AS invoice
+            LEFT JOIN account_invoice_line AS line
+            ON line.invoice_id = invoice.id
+            --Product
+            LEFT JOIN product_product AS product
+            ON line.product_id = product.id
+            LEFT JOIN product_template AS template
+            ON template.id = product.product_tmpl_id
+            LEFT JOIN product_attribute_value_product_product_rel AS attr_rel
+        	ON attr_rel.prod_id = product.id
+        	LEFT JOIN product_attribute_value AS attr_value
+        	ON attr_value.id = attr_rel.att_id
+        	LEFT JOIN product_attribute AS attr
+        	ON attr.id = attr_value.attribute_id
+            LEFT JOIN res_store_journal_rel AS journal
+            ON journal.journal_id = invoice.journal_id
+            LEFT JOIN product_price_history AS history
+            ON history.product_template_id = product.product_tmpl_id
+            LEFT JOIN res_currency_rate AS rate
+            ON rate.currency_id = invoice.currency_id
+            LEFT JOIN res_partner AS partner
+            ON partner.id = invoice.partner_id
+            LEFT JOIN product_brand AS brand
+            ON brand.id = template.product_brand_id
+            WHERE invoice.state NOT IN ('draft', 'cancel')
+            AND invoice.type = 'in_invoice'
+            AND (invoice.origin NOT LIKE %s OR invoice.origin IS NULL)
+        GROUP BY
+        	invoice.id,
+        	line.id,
+        	invoice.number,
+        	invoice.origin,
+        	invoice.date_invoice,
+        	product.name_template,
+        	line.price_unit,
+        	line.quantity,
+        	line.price_subtotal,
+            journal.store_id,
+            template.categ_id,
+            product.default_code,
+            partner.name,
+            product.id,
+            invoice.company_id,
+            invoice.journal_id,
+            template.product_brand_id,
+            brand.name
+    '''
+
+    query_without_brand = '''
+        SELECT
+        	invoice.id AS invoice_id,
+        	line.id AS invoice_line_id,
+        	invoice.number,
+        	invoice.origin,
+        	invoice.date_invoice,
+        	invoice.type,
+            CASE
+        		WHEN product.default_code IS NOT NULL
+        		THEN ('[' || product.default_code || '] ' || product.name_template)
+        		ELSE product.name_template
+        		END AS display_name,
+        	line.price_unit * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]) as price_unit,
+        	line.quantity AS cant,
+        	line.price_subtotal * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]) AS subtotal,
+        	(line.quantity * (line.price_unit * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]))) - (((line.quantity * (line.price_unit * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1]) * line.discount)/100))) - (line.price_subtotal * (%s / (array_agg(rate.rate ORDER BY rate.id DESC))[1])) AS impuestos,
+        	(array_agg(history.cost ORDER BY history.id DESC))[1] AS cost,
+            --line.name
+            journal.store_id,
+            template.categ_id,
+            partner.name,
+            product.id,
+            invoice.company_id,
+            invoice.journal_id,
+            (array_agg(attr_rel.att_id)) AS attr_rel,
+            (array_agg(attr_value.name)) AS attr_value,
+            (array_agg(attr.id)) AS attr,
+            line.discount
+            FROM account_invoice AS invoice
+            LEFT JOIN account_invoice_line AS line
+            ON line.invoice_id = invoice.id
+            --Product
+            LEFT JOIN product_product AS product
+            ON line.product_id = product.id
+            LEFT JOIN product_template AS template
+            ON template.id = product.product_tmpl_id
+            LEFT JOIN product_attribute_value_product_product_rel AS attr_rel
+        	ON attr_rel.prod_id = product.id
+        	LEFT JOIN product_attribute_value AS attr_value
+        	ON attr_value.id = attr_rel.att_id
+        	LEFT JOIN product_attribute AS attr
+        	ON attr.id = attr_value.attribute_id
+            LEFT JOIN res_store_journal_rel AS journal
+            ON journal.journal_id = invoice.journal_id
+            LEFT JOIN product_price_history AS history
+            ON history.product_template_id = product.product_tmpl_id
+            LEFT JOIN res_currency_rate AS rate
+            ON rate.currency_id = invoice.currency_id
+            LEFT JOIN res_partner AS partner
+            ON partner.id = invoice.partner_id
+            WHERE invoice.state NOT IN ('draft', 'cancel')
+            AND invoice.type = 'in_invoice'
+            AND (invoice.origin NOT LIKE %s OR invoice.origin IS NULL)
+        GROUP BY
+        	invoice.id,
+        	line.id,
+        	invoice.number,
+        	invoice.origin,
+        	invoice.date_invoice,
+        	product.name_template,
+        	line.price_unit,
+        	line.quantity,
+        	line.price_subtotal,
+            journal.store_id,
+            template.categ_id,
+            product.default_code,
+            partner.name,
+            product.id,
+            invoice.company_id,
+            invoice.journal_id
+    '''
+
+    r.cr.execute(validate_brand)
+    for j in r.cr.fetchall():
+        brand = j[0]
+
+    if brand == True:
+        r.cr.execute(query_with_brand,(tuple([company_currency_rate,company_currency_rate,company_currency_rate,company_currency_rate,company_currency_rate,origin])))
+        return [
+            {
+                'invoice_id': j[0],
+                'invoice_line_id': j[1],
+                'number': j[2],
+                'origin': j[3],
+                'date': j[4],
+                'type': j[5],
+                'product_name':j[6],
+                'price_unit':j[7],
+                'quantity':j[8],
+                'subtotal':j[9],
+                'tax': j[10],
+                'cost': j[11],
+                'store_id': j[12],
+                'categ_id': j[13],
+                'partner_name': j[14],
+                'product_id': j[15],
+                'company_id': j[16],
+                'journal_id': j[17],
+                'attribute_value_ids': j[18],
+                'attribute_values': j[19],
+                'attribute_ids': j[20],
+                'product_brand_id': j[21],
+                'brand_name': j[22],
+                'discount': j[23],
+            } for j in r.cr.fetchall()
+        ]
+    else:
+        r.cr.execute(query_without_brand,(tuple([company_currency_rate,company_currency_rate,company_currency_rate,company_currency_rate,company_currency_rate,origin])))
+        return [
+            {
+                'invoice_id': j[0],
+                'invoice_line_id': j[1],
+                'number': j[2],
+                'origin': j[3],
+                'date': j[4],
+                'type': j[5],
+                'product_name':j[6],
+                'price_unit':j[7],
+                'quantity':j[8],
+                'subtotal':j[9],
+                'tax': j[10],
+                'cost': j[11],
+                'store_id': j[12],
+                'categ_id': j[13],
+                'partner_name': j[14],
+                'product_id': j[15],
+                'company_id': j[16],
+                'journal_id': j[17],
+                'attribute_value_ids': j[18],
+                'attribute_values': j[19],
+                'attribute_ids': j[20],
+                'discount': j[21],
+            } for j in r.cr.fetchall()
+        ]

BIN
controller/helpers/account_invoice_line.pyc


+ 53 - 0
controller/helpers/account_voucher.py

@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_account_voucher_supplier():
+    company_currency_rate = r.env.user.company_id.currency_id.rate
+    query = '''
+    SELECT  voucher.id,
+        	voucher.number,
+        	voucher.type,
+        	voucher.date,
+        	journal.currency,
+            voucher.amount,
+        	CASE
+        		WHEN journal.currency IS NULL
+        		THEN voucher.amount
+        		ELSE voucher.amount * (%s / (array_agg(rate.rate ORDER BY rate.name DESC))[1])
+        		END AS amount_currency,
+            voucher.journal_id,
+            voucher.reference
+        FROM account_voucher AS voucher
+        LEFT JOIN res_store_journal_rel AS journal_rel
+        ON voucher.journal_id = journal_rel.journal_id
+        LEFT JOIN account_journal AS journal
+        ON journal.id = voucher.journal_id
+        LEFT JOIN res_currency_rate AS rate
+        ON rate.currency_id = journal.currency
+        WHERE voucher.state = 'posted'
+        AND voucher.type = 'payment'
+        GROUP BY
+        	voucher.id,
+        	voucher.number,
+        	voucher.type,
+        	voucher.date,
+        	voucher.amount,
+        	journal.name,
+        	journal.currency
+    '''
+
+    r.cr.execute(query,(tuple([company_currency_rate])))
+
+    return [
+        {
+            'id': j[0],
+            'number': j[1],
+            'type': j[2],
+            'date': j[3],
+            'currency_id': j[4],
+            'amount': j[5],
+            'amount_currency': j[6],
+            'journal_id': j[7],
+            'reference': j[8],
+        } for j in r.cr.fetchall()
+    ]

BIN
controller/helpers/account_voucher.pyc


+ 45 - 0
controller/main.py

@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+from openerp import http
+from werkzeug.wrappers import Response
+from werkzeug.datastructures import Headers
+from gzip import GzipFile
+from StringIO import StringIO as IO
+import simplejson as json
+import helpers as hp
+import logging
+
+LOGGER = logging.getLogger(__name__)
+GZIP_COMPRESSION_LEVEL = 9
+
+def make_gzip_response(data=None, status=200):
+    gzip_buffer = IO()
+
+    with GzipFile(mode='wb', compresslevel=GZIP_COMPRESSION_LEVEL, fileobj=gzip_buffer) as gzip_file:
+        gzip_file.write(json.dumps(data))
+
+    value = gzip_buffer.getvalue()
+    gzip_buffer.close()
+
+    headers = Headers()
+    headers.add('Content-Encoding', 'gzip')
+    headers.add('Vary', 'Accept-Encoding')
+    headers.add('Content-Length', len(value))
+
+    return Response(value, status=status, headers=headers, content_type='application/json')
+
+class ReportController(http.Controller):
+
+    # HISTORICO DE GASTOS
+    @http.route('/report-expense-history', auth='user', methods=['GET', 'POST'])
+    def getExpenseHistory(self, **kw):
+        return make_gzip_response({
+            'invoices': hp.get_account_invoice_expense(),
+            'vouchers': hp.get_account_voucher_supplier(),
+        })
+
+    # ANALISIS DE GASTOS
+    @http.route('/report-expense-analytic', auth='user', methods=['GET', 'POST'])
+    def getExpenseAnalytic(self, **kw):
+        return make_gzip_response({
+            'invoice_lines': hp.get_account_invoice_line_expense(),
+        })

BIN
controller/main.pyc


BIN
static/description/icon.png


+ 300 - 0
static/src/js/chart.js

@@ -0,0 +1,300 @@
+function chart(reporting) {
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportSaleChartWidget = reporting.Base.extend({
+
+        BuildLineChart: function (label,data,CurrencyBase) {
+            var self = this;
+            Chart.scaleService.updateScaleDefaults('linear', {
+                ticks: {
+                    callback: function(tick) {
+                        return tick.toLocaleString('de-DE');
+                    }
+                }
+            });
+            Chart.defaults.global.tooltips.callbacks.label = function(tooltipItem, data) {
+                var dataset = data.datasets[tooltipItem.datasetIndex];
+                var datasetLabel = dataset.label || '';
+                return datasetLabel +  dataset.data[tooltipItem.index].toLocaleString('de-DE');
+            };
+            var chart = new Chart($(".reporting-chart"), {
+                type: 'line',
+                data: {
+                    labels: label,
+                    datasets: [
+                        {
+                            label: false,
+                            data: data,
+                            backgroundColor: '#bbdefb',
+                            borderColor: '#0288d1',
+                            borderWidth: 1,
+                            fill: true,
+                        }
+                    ]
+                },
+                options: {
+                    responsive: true,
+                    responsiveAnimationDuration:10,
+                    maintainAspectRatio:false,
+                    title: {
+                        display: false,
+                    },
+                    hover: {
+                        mode: 'nearest',
+                        intersect: true
+                    },
+                    legend: {
+                       display: false,
+                    },
+                    layout: {
+                        padding: {
+                            top: 0,
+                            bottom: 0,
+                            left : 0,
+                            rigth: 0,
+                        }
+                    },
+                    events: ['click'],
+                    tooltips: {
+                        callbacks: {
+                            label: function(tooltipItem, data) {
+                                var label = data.datasets[tooltipItem.datasetIndex].label || '';
+
+                                if (label) {
+                                    label += ': ';
+                                }
+                                label += accounting.formatMoney(tooltipItem.yLabel, CurrencyBase.symbol, CurrencyBase.decimal_places, CurrencyBase.thousands_separator, CurrencyBase.decimal_separator);
+                                return label;
+                            }
+                        }
+                    }
+                }
+            });
+        },
+
+        BuildBarChart: function (data,CurrencyBase,label,body) {
+            var self = this;
+            Chart.scaleService.updateScaleDefaults('linear', {
+              ticks: {
+                callback: function(tick) {
+                    return tick.toLocaleString('de-DE');
+                }
+              }
+            });
+            Chart.defaults.global.tooltips.callbacks.label = function(tooltipItem, data) {
+                var dataset = data.datasets[tooltipItem.datasetIndex];
+                var datasetLabel = dataset.label || '';
+                return datasetLabel +  dataset.data[tooltipItem.index].toLocaleString('de-DE');
+            };
+
+            var color = [];
+            color.push('#BCCEF4');
+            color.push('#A9E5E3');
+            color.push('#A0D995');
+            color.push('#C5D084');
+            color.push('#FAE187');
+            color.push('#FFBD82');
+            color.push('#FFA8B8');
+            color.push('#E5BEDD');
+            color.push('#C4ABFE');
+            color.push('#D8D8D8');
+
+            var chart = new Chart($(".reporting-chart"), {
+                type: 'horizontalBar',
+                data: {
+                    labels: label,
+                    datasets: [
+                        {
+                            label: false,
+                            data: body,
+                            backgroundColor: color,
+                            fill: true,
+                        }
+                    ]
+                },
+                options: {
+                    responsive: true,
+                    responsiveAnimationDuration:10,
+                    maintainAspectRatio:false,
+                    title: {
+                        display: false,
+                    },
+                    hover: {
+                        mode: 'nearest',
+                        intersect: true
+                    },
+                    legend: {
+                       display: false,
+                    },
+                    layout: {
+                        padding: {
+                            top: 0,
+                            bottom: 0,
+                            left : 0,
+                            rigth: 0,
+                        }
+                    },
+                    tooltips: {
+                        callbacks: {
+                            label: function(tooltipItem, data) {
+                                var label = data.datasets[tooltipItem.datasetIndex].label || '';
+
+                                if (label) {
+                                    label += ': ';
+                                }
+                                label += accounting.formatMoney(tooltipItem.xLabel, CurrencyBase.symbol, CurrencyBase.decimal_places, CurrencyBase.thousands_separator, CurrencyBase.decimal_separator);
+                                return label;
+                            }
+                        }
+                    },
+                    events: ['click'],
+                }
+            });
+        },
+
+        BuildPieChart: function (data,CurrencyBase,label,body) {
+            var self = this;
+
+            var color = [];
+            color.push('#BCCEF4');
+            color.push('#A9E5E3');
+            color.push('#A0D995');
+            color.push('#C5D084');
+            color.push('#FAE187');
+            color.push('#FFBD82');
+            color.push('#FFA8B8');
+            color.push('#E5BEDD');
+            color.push('#C4ABFE');
+            color.push('#D8D8D8');
+            color.push('#f3e5f5');
+
+            var chart = new Chart($(".reporting-pie-chart"), {
+                type: 'pie',
+                data: {
+                    labels: label,
+                    datasets: [
+                        {
+                            label: false,
+                            data: body,
+                            backgroundColor: color,
+                            fill: true,
+                        }
+                    ]
+                },
+
+                options: {
+                    responsive: true,
+                    responsiveAnimationDuration:10,
+                    maintainAspectRatio:false,
+                    hover: {
+                        mode: 'nearest',
+                        intersect: true
+                    },
+                    legend: {
+                        position: 'right',
+                    },
+                    layout: {
+                        padding: {
+                            top: 0,
+                            bottom: 0,
+                            left : 0,
+                            rigth: 0,
+                        }
+                    },
+                    tooltips: {
+                        callbacks: {
+                            label: function(tooltipItem, data) {
+                                var label = data.labels[tooltipItem.index] || '';
+                                if (label) {
+                                    label += ': ';
+                                }
+                                label += accounting.formatMoney(data.datasets[0].data[tooltipItem.index],{
+                                    symbol: "%",
+                                    format: "%v%s",
+                                    precision: 2,
+                                    thousand: ".",
+                                    decimal: ","
+                                });
+                                return label;
+                            }
+                        }
+                    },
+                    events: ['click'],
+                }
+            });
+        },
+
+        BuildDoughnutChart: function (data,CurrencyBase,label,body) {
+            var self = this;
+
+            var color = [];
+            color.push('#BCCEF4');
+            color.push('#A9E5E3');
+            color.push('#A0D995');
+            color.push('#C5D084');
+            color.push('#FAE187');
+            color.push('#FFBD82');
+            color.push('#FFA8B8');
+            color.push('#E5BEDD');
+            color.push('#C4ABFE');
+            color.push('#D8D8D8');
+
+            var chart = new Chart($(".reporting-doughnut-chart"), {
+                type: 'doughnut',
+                data: {
+                    labels: label,
+                    datasets: [
+                        {
+                            label: false,
+                            data: body,
+                            backgroundColor: color,
+                            fill: true,
+                        }
+                    ]
+                },
+
+                options: {
+                    responsive: true,
+                    responsiveAnimationDuration:10,
+                    maintainAspectRatio:false,
+                    hover: {
+                        mode: 'nearest',
+                        intersect: true
+                    },
+                    legend: {
+                        position: 'left',
+                    },
+                    layout: {
+                        padding: {
+                            top: 0,
+                            bottom: 0,
+                            left : 0,
+                            rigth: 0,
+                        }
+                    },
+                    tooltips: {
+                        callbacks: {
+                            label: function(tooltipItem, data) {
+                                var label = data.labels[tooltipItem.index] || '';
+                                if (label) {
+                                    label += ': ';
+                                }
+                                label += accounting.formatMoney(data.datasets[0].data[tooltipItem.index],{
+                                    symbol: "%",
+                                    format: "%v%s",
+                                    precision: 2,
+                                    thousand: ".",
+                                    decimal: ","
+                                });
+                                return label;
+                            }
+                        }
+                    },
+                    events: ['click'],
+                }
+            });
+        },
+    });
+}

+ 40 - 0
static/src/js/datepicker.js

@@ -0,0 +1,40 @@
+function datepicker(reporting) {
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportDatePickerWidget = reporting.Base.extend({
+        fecthFecha: function() {
+            var to;
+            var dateFormat1 = "mm/dd/yy",
+            from = $( "#from" )
+            .datepicker({
+                dateFormat: "dd/mm/yy",
+                changeMonth: true,
+                numberOfMonths: 1,
+            })
+            .on( "change", function() {
+                to.datepicker( "option", "minDate", getDate(this), "dd/mm/yyyy");
+            });
+            to = $( "#to" ).datepicker({
+                dateFormat: "dd/mm/yy",
+                defaultDate: "+7d",
+                changeMonth: true,
+                numberOfMonths: 1,
+            })
+            .on( "change", function() {
+                from.datepicker( "option", "maxDate", getDate(this));
+            });
+            function getDate( element ) {
+                var fechaSel =element.value.split('/');
+                var date;
+                try {
+                    date = $.datepicker.parseDate( dateFormat1, (fechaSel[1]+"/"+fechaSel[0]+"/"+fechaSel[2]));
+                } catch( error ) {
+                    date = null;
+                }
+                return date;
+            }
+        },
+    });
+}

+ 46 - 0
static/src/js/main.js

@@ -0,0 +1,46 @@
+openerp.eiru_reports_expenses = function (instance) {
+    "use strict";
+
+    var reporting = instance.eiru_reports_expenses;
+
+    reporting_base(instance,reporting);
+
+    try {
+        /*
+        ================================
+            BASE
+        ================================
+        */
+        pdf(reporting);
+        chart(reporting);
+        datepicker(reporting);
+        /*
+        ================================
+            VENTAS
+        ================================
+        */
+        report_expense(reporting);
+        report_expense_analytic(reporting);
+    } catch (e) {
+        // ignorar error
+    }
+
+    /*
+    ================================================================================
+        HISTORICO DE GASTOS
+    ================================================================================
+    */
+    instance.web.client_actions.add(
+        'eiru_reports_expenses.expense_action',
+        'instance.eiru_reports_expenses.ReportExpenseWidget'
+    );
+    /*
+    ================================================================================
+        ANALISIS DE GASTOS
+    ================================================================================
+     */
+    instance.web.client_actions.add(
+        'eiru_reports_expenses.expense_analytic_action',
+        'instance.eiru_reports_expenses.ReportExpenseAnalyticWidget'
+    );
+};

+ 137 - 0
static/src/js/pdf.js

@@ -0,0 +1,137 @@
+function pdf(reporting) {
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportSalePdfWidget = reporting.Base.extend({
+        drawPDF: function (getColumns,row,ResCompany,pdf_title,pdf_type,pdf_name,pdf_columnStyles,filter) {
+            var self = this;
+            var base64Img = 'data:image/png;base64,' + ResCompany.logo;
+            var hoy = moment().format('DD/MM/YYYY');
+            var totalPagesExp = "{total_pages_count_string}";
+            var pdfDoc = new jsPDF(pdf_type);
+            var y_position = 27;
+            var y_position2 = 27;
+            //LOGO
+            pdfDoc.addImage(base64Img, 'png', 7, 2, 0, 15);
+            //FECHA
+            pdfDoc.setFontSize(13);
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 35, 12,hoy);
+            //TITULO
+            pdfDoc.setFontSize(15);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor('#0288d1');
+            pdfDoc.autoTableText(pdf_title, pdfDoc.internal.pageSize.getWidth() - 12, 18, {
+                halign: 'right',
+                valign: 'middle'
+            });
+            pdfDoc.setLineWidth(0.5);
+            pdfDoc.setDrawColor('#424242');
+            pdfDoc.line(10, 22, pdfDoc.internal.pageSize.getWidth() - 10 , 22);
+            var i = 0;
+            var col1_title;
+            var col1_value;
+            var col2_title;
+            var col2_value;
+            if(pdf_type == 'l'){
+                col1_title = 15;
+                col1_value = 55;
+                col2_title = 150;
+                col2_value = 190;
+            }
+            else{
+                col1_title = 10;
+                col1_value = 50;
+                col2_title = 110;
+                col2_value = 150;
+            }
+            if(filter.length >0){
+                _.each(filter,function(item){
+                    if(i<4){
+                        self.addFilter(pdfDoc,item.title,item.value,col1_title,col1_value,y_position);
+                        y_position = y_position + 5;
+                    }else{
+                        self.addFilter(pdfDoc,item.title,item.value,col2_title,col2_value,y_position2);
+                        y_position2 = y_position2 + 5;
+                    }
+                    i++;
+                });
+                pdfDoc.setLineWidth(0.5);
+                pdfDoc.setDrawColor('#424242');
+                if(y_position >= y_position2){
+                    y_position = y_position;
+                    pdfDoc.line(10, y_position, pdfDoc.internal.pageSize.getWidth() - 10 , y_position);
+                }else{
+                    y_position = y_position2;
+                    pdfDoc.line(10, y_position2, pdfDoc.internal.pageSize.getWidth() - 10 , y_position2);
+                }
+            }
+            pdfDoc.autoTable(getColumns, row, {
+                startY: y_position + 5,
+                theme: 'grid',
+                styles: {
+                    overflow: 'linebreak',
+                    columnWidth: 'auto',
+                    fontSize: 7,
+                },
+                headerStyles: {
+                    fillColor: [76, 133, 248],
+                    fontSize: 9
+                },
+                columnStyles: pdf_columnStyles,
+                margin: { horizontal: 7},
+                drawCell: function(cell, opts) {
+                    var rows = opts.table.rows;
+                    if (opts.row.index == rows.length - 1) {
+                      pdfDoc.setFontStyle('bold');
+                    }
+                },
+                addPageContent: function (data) {
+
+                //FOOTER
+                    var str = "Página " + data.pageCount;
+                    if (typeof pdfDoc.putTotalPages === 'function') {
+                        str = str + " de " + totalPagesExp;
+                    }
+                    pdfDoc.setFontSize(9);
+                    pdfDoc.setFontStyle('bold');
+                    pdfDoc.setTextColor(40);
+                    var pageHeight = pdfDoc.internal.pageSize.height || pdfDoc.internal.pageSize.getHeight();
+                    pdfDoc.autoTableText(str, pdfDoc.internal.pageSize.getWidth() - 35, pageHeight - 5, {
+                      halign: 'rigth',
+                      valign: 'middle'
+                    });
+                }
+            });
+            if (typeof pdfDoc.putTotalPages === 'function') {
+                pdfDoc.putTotalPages(totalPagesExp);
+            }
+            row.pop();
+            if(model.printer_bridge){
+                var data = pdfDoc.output('datauristring');
+                model.printer_bridge.print(data);
+                return;
+            }
+            pdfDoc.save(pdf_name + hoy + '.pdf');
+        },
+
+        addFilter: function(pdfDoc,title,value,x_position_title,x_position_value,y_position){
+            pdfDoc.setFontSize(10);
+            pdfDoc.setTextColor('#424242');
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.autoTableText(title+':', x_position_title, y_position, {
+                halign: 'left',
+                valign: 'middle'
+            });
+            pdfDoc.setFontSize(10);
+            pdfDoc.setTextColor('#424242');
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.autoTableText(value, x_position_value, y_position, {
+                halign: 'left',
+                valign: 'middle'
+            });
+        },
+    });
+}

+ 22 - 0
static/src/js/reporting_base.js

@@ -0,0 +1,22 @@
+function reporting_base (instance, widget) {
+    "use strict";
+
+    widget.Base = instance.Widget.extend({
+
+        position: 0,
+
+        init: function (parent, position) {
+            this._super(parent);
+            this.position = position || this.position;
+        },
+        start: function () {
+            
+        },
+        getPosition: function () {
+            return this.position;
+        },
+        setPosition: function (position) {
+            this.position = position;
+        }
+    });
+}

+ 555 - 0
static/src/js/reports/report_expense.js

@@ -0,0 +1,555 @@
+function report_expense(reporting){
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportExpenseWidget = reporting.Base.extend({
+        template: 'ReportExpense',
+        rowsData :[],
+        content :[],
+        modules: [],
+
+        events:{
+            'click #generate' : 'fetchGenerate',
+            'change #current-company' : 'updateSelections',
+            'change #current-store' : 'updateJournalSelections',
+            'change #current-date' : 'ShowDateRange',
+            'click .print-report':'clickOnAction',
+        },
+
+        init : function(parent){
+            this._super(parent);
+        },
+
+        start: function () {
+            var table = this.$el.find('#table');
+            table.bootstrapTable({data : self.rowsData});
+            var date = new reporting.ReportDatePickerWidget(self);
+            date.fecthFecha();
+            this.fetchInitial();
+        },
+
+        valorNull:function(dato){
+            var valor = "";
+            if (dato){
+                valor = dato;
+            }
+            return valor;
+        },
+
+        ShowDateRange : function(){
+            var self = this;
+            var date = self.$el.find('#current-date').val();
+            if(date == 'range'){
+                self.$el.find('.datepicker').css('display','block');
+            }
+            if(date != 'range'){
+                self.$el.find('.datepicker').css('display','none');
+            }
+        },
+
+        fetchInitial: function () {
+            var self = this;
+            self.fetchIntialSQL().then(function (IntialSQL) {
+                return IntialSQL;
+            }).then(function(IntialSQL) {
+                /*
+                =================================
+                    RES COMPANY
+                =================================
+                */
+                self.ResCompany = IntialSQL.companies;
+                self.CompanyLogo = IntialSQL.logo;
+                if(self.ResCompany.length > 1){
+                    self.$el.find('#current-company').append('<option value="9999999">Todas las empresas</option>');
+                    _.each(self.ResCompany,function(item){
+                        self.$el.find('#current-company').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.company').css('display','none');
+                }
+                /*
+                =================================
+                    RES STORE
+                =================================
+                */
+                self.ResStore = IntialSQL.stores;
+                if(self.ResStore.length > 1){
+                    self.$el.find('#current-store').append('<option value="9999999">Todas las sucursales</option>');
+                    _.each(self.ResStore,function(item){
+                        self.$el.find('#current-store').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.store').css('display','none');
+                }
+                /*
+                =================================
+                    ACCOUNT JOURNAL
+                =================================
+                */
+                self.AccountJournal = IntialSQL.journals;
+                var journal = _.flatten(_.filter(self.AccountJournal,function (item) {
+                    return item.type == 'purchase';
+                }));
+                if(journal.length > 1){
+                    self.$el.find('#current-journal').append('<option value="9999999">Todas las facturas</option>');
+                    _.each(self.AccountJournal,function(item){
+                        if(item.type == 'purchase'){
+                            self.$el.find('#current-journal').append('<option value="' + item.id + '">' + item.name + '</option>');
+                        }
+                    });
+                }else{
+                    self.$el.find('.journal').css('display','none');
+                }
+                /*
+                =================================
+                    RES USERS
+                =================================
+                */
+                self.ResUsers = IntialSQL.users;
+                var store_ids = _.flatten(_.map(self.ResStore, function (item) {
+                    return item.id;
+                }));
+                var ResUsers = _.flatten(_.filter(self.ResUsers,function (item) {
+                    return _.contains(store_ids, item.store_id);
+                }));
+                if(ResUsers.length > 1){
+                    self.$el.find('#current-user').append('<option value="9999999">Todos los responsables</option>');
+                    _.each(ResUsers,function(item){
+                        self.$el.find('#current-user').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.users').css('display','none');
+                }
+            });
+            self.$el.find('#generate').css('display','inline');
+            return;
+        },
+
+        fetchGenerate: function () {
+            var self = this;
+            self.$el.find('.search-form').block({
+                message: null,
+                overlayCSS: {
+                    backgroundColor: '#FAFAFA'
+                }
+            });
+            self.$el.find('.report-form').block({
+                message: null,
+                overlayCSS: {
+                    backgroundColor: '#FAFAFA'
+                }
+            });
+            this.fetchDataSQL().then(function(DataSQL) {
+                return DataSQL;
+            }).then(function (DataSQL) {
+                self.AccountInvoice = DataSQL.invoices;
+                self.PosOrder = DataSQL.orders;
+                self.AccountVoucher = DataSQL.vouchers;
+                return self.BuildTable();
+            });
+        },
+
+        fetchIntialSQL: function() {
+            var self = this;
+            var data = $.get('/report-filter-data');
+            return data;
+        },
+
+        fetchDataSQL: function() {
+            var self = this;
+            var data = $.get('/report-expense-history');
+            return data;
+        },
+
+        /*====================================================================
+            UPDATE SELECTIONS
+        ====================================================================*/
+        updateSelections: function () {
+            var self = this;
+            var store;
+            var company = self.$el.find('#current-company').val();
+            if(company != 9999999){
+                store = self.$el.find('#current-store').empty();
+                self.$el.find('#current-store').append('<option value="9999999">Todas las sucursales</option>');
+                _.each(self.ResStore,function(item){
+                    if(parseFloat(company) == item.company_id[0]){
+                        self.$el.find('#current-store').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    }
+                });
+            }else{
+                store = self.$el.find('#current-store').empty();
+                self.$el.find('#current-store').append('<option value="9999999">Todas las sucursales</option>');
+                _.each(self.ResStore,function(item){
+                    self.$el.find('#current-store').append('<option value="' + item.id + '">' + item.name + '</option>');
+                });
+            }
+        },
+
+        updateJournalSelections: function () {
+            var self = this;
+            var journal;
+            var store = self.$el.find('#current-store').val();
+            if(store != 9999999){
+                self.$el.find('#current-journal').empty();
+                self.$el.find('#current-journal').append('<option value="9999999">Todas las facturas</option>');
+                _.each(self.AccountJournal,function(item){
+                    if(parseFloat(store) == item.store_id && item.type == 'sale'){
+                        self.$el.find('#current-journal').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    }
+                });
+                self.$el.find('#current-user').empty();
+                self.$el.find('#current-user').append('<option value="9999999">Todos los responsables</option>');
+                _.each(self.ResUsers,function(item){
+                    if(parseFloat(store) == item.store_id){
+                        self.$el.find('#current-user').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    }
+                });
+            }else{
+                journal = self.$el.find('#current-journal').empty();
+                self.$el.find('#current-journal').append('<option value="9999999">Todas las facturas</option>');
+                _.each(self.AccountJournal,function(item){
+                    if(item.type == 'purchase'){
+                        self.$el.find('#current-journal').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    }
+                });
+                _.each(self.ResUsers,function(item){
+                        self.$el.find('#current-user').append('<option value="' + item.id + '">' + item.name + '</option>');
+                });
+            }
+        },
+
+        getAccountInvoice:function() {
+            var self = this;
+            var content = self.AccountInvoice;
+            var company = self.$el.find('#current-company').val();
+            var store = self.$el.find('#current-store').val();
+            var state = self.$el.find('#current-state').val();
+            var journal = self.$el.find('#current-journal').val();
+            var user = self.$el.find('#current-user').val();
+            var date = self.$el.find('#current-date').val();
+            var desde = self.$el.find('#from').val();
+            var hasta = self.$el.find('#to').val();
+
+            if((store && store == 9999999)||(company && company == 9999999)){
+                var store_ids = _.flatten(_.map(self.ResStore, function (item) {
+                    return item.id;
+                }));
+                var company_ids = _.flatten(_.map(self.ResCompany, function (item) {
+                    return item.id;
+                }));
+                content = _.flatten(_.filter(content,function (item) {
+                    return _.contains(store_ids, item.store_id) && _.contains(company_ids, item.company_id);
+                }));
+            }
+
+            if(company && company != 9999999){
+                content = _.flatten(_.filter(content,function (item) {
+                    return item.company_id == company;
+                }));
+            }
+            if(store && store != 9999999){
+                content = _.flatten(_.filter(content,function (item) {
+                    return item.store_id == store;
+                }));
+            }
+            if(state && state != 9999999){
+                content = _.flatten(_.filter(content,function (item) {
+                    return item.state == state;
+                }));
+            }
+            if(journal && journal != 9999999){
+                content = _.flatten(_.filter(content,function (item) {
+                    return item.journal_id == journal;
+                }));
+            }
+            if(user && user != 9999999){
+                content = _.flatten(_.filter(content,function (item) {
+                    return item.user_id == user;
+                }));
+            }
+            if(date && date != 9999999){
+                if(date == 'range'){
+                    if(desde){
+                        date = desde.split('/');
+                        date = (date[2]+"-"+date[1]+"-"+date[0]);
+                        content = _.flatten(_.filter(content,function (inv) {
+                            return moment(inv.date).format('YYYY-MM-DD') >= date;
+                        }));
+                    }
+                    if(hasta){
+                        date = hasta.split('/');
+                        date = (date[2]+"-"+date[1]+"-"+date[0]);
+                        content = _.flatten(_.filter(content,function (inv) {
+                            return moment(inv.date).format('YYYY-MM-DD') <= date;
+                        }));
+                    }
+                }
+                if(date == 'today'){
+                    var today = moment().format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        return moment(inv.date).format('YYYY-MM-DD') === today;
+                    }));
+                }
+                if(date == 'yesterday'){
+                    var yesterday = moment().add(-1,'days').format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        return moment(inv.date).format('YYYY-MM-DD') === yesterday;
+                    }));
+                }
+                if(date == 'currentMonth'){
+                    var currentMonth = moment().format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        return moment(inv.date).format('YYYY-MM') === currentMonth;
+                    }));
+                }
+                if(date == 'lastMonth'){
+                    var lastMonth = moment().add(-1,'months').format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        return moment(inv.date).format('YYYY-MM') === lastMonth;
+                    }));
+                }
+            }
+            return content;
+        },
+
+        getAccountVoucher: function (number) {
+            var self = this;
+            return _.filter(self.AccountVoucher,function (item) {
+                return item.reference == number;
+            });
+        },
+
+        BuildTable: function(){
+            var self = this;
+            var data = [];
+            var residual = 0;
+            var CurrencyBase = self.ResCompany[0].currency_id;
+            var discount_amount;
+            var AccountInvoice = self.getAccountInvoice();
+            _.each(AccountInvoice, function(item){
+                residual = 0;
+                if(item.state == 'open'){
+                    residual = self.getAccountVoucher(item.number);
+                    residual =  _.reduce(_.map(residual,function(item){
+                        return item.amount_currency;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    residual = item.amount - residual;
+                }
+                data.push({
+                    id:item.id,
+                    origin:item.origin,
+                    number:item.number,
+                    date:moment(item.date).format('DD/MM/YYYY'),
+                    user_name:item.user_name,
+                    user_id:item.user_id,
+                    customer_name:self.valorNull(item.customer_name),
+                    residual:accounting.formatMoney(residual,'',CurrencyBase.decimal_places,CurrencyBase.thousands_separator,CurrencyBase.decimal_separator),
+                    untaxed:accounting.formatMoney(item.amount - item.amount_tax,'',CurrencyBase.decimal_places,CurrencyBase.thousands_separator,CurrencyBase.decimal_separator),
+                    tax:accounting.formatMoney(item.amount_tax,'',CurrencyBase.decimal_places,CurrencyBase.thousands_separator,CurrencyBase.decimal_separator),
+                    total:accounting.formatMoney(item.amount,'',CurrencyBase.decimal_places,CurrencyBase.thousands_separator,CurrencyBase.decimal_separator),
+                    /*
+                    =======================
+                        NO FORMAT
+                    =======================
+                    */
+                    date_no_format: moment(item.date).format('YYYY-MM-DD'),
+                    residual_no_format:residual,
+                    untaxed_no_format:item.amount - item.amount_tax,
+                    tax_no_format:item.amount_tax,
+                    total_no_format:item.amount,
+                    /*
+                    =======================
+                        FOOTER
+                    =======================
+                    */
+                    decimal_places:CurrencyBase.decimal_places,
+                    thousands_separator:CurrencyBase.thousands_separator,
+                    decimal_separator:CurrencyBase.decimal_separator,
+                });
+            });
+            data.sort(function (a, b) {
+                if (a.date_no_format > b.date_no_format) {
+                    return -1;
+                }
+                if (a.date_no_format < b.date_no_format) {
+                    return 1;
+                }
+                return 0;
+            });
+            self.content = data;
+            self.loadTable(data);
+            self.$el.find('.report-form').css('display','block');
+            self.$el.find('.search-form').unblock();
+            self.$el.find('.report-form').unblock();
+        },
+
+        loadTable:function(rowsTable){
+            var self = this;
+            self.rowsData = rowsTable;
+            var table = this.$el.find('#table');
+            table.bootstrapTable('load', rowsTable);
+        },
+
+        clickOnAction: function (e) {
+            var self = this;
+            var ResCompany;
+            var CurrencyBase;
+            var action = this.$el.find(e.target).val();
+            var company = $('#current-company').val();
+            if(company && company != 9999999){
+                ResCompany = _.flatten(_.filter(self.ResCompany,function (inv) {
+                    return inv.id == company;
+                }));
+                ResCompany = ResCompany[0];
+                CurrencyBase = ResCompany[0].currency_id;
+            }else{
+                ResCompany = self.ResCompany[0];
+                CurrencyBase = self.ResCompany[0].currency_id;
+            }
+            var getColumns=[];
+            var rows=[];
+            var table = this.$el.find("#table");
+            var column = table.bootstrapTable('getVisibleColumns');
+            var row = table.bootstrapTable('getData');
+            var residual = ResidualFooter(row);
+            var untaxed = UntaxedFooter(row);
+            var tax = TaxFooter(row);
+            var total = TotalFooter(row);
+            row.push({
+                number:'Totales',
+                residual:residual,
+                untaxed:untaxed,
+                tax:tax,
+                total:total,
+            });
+
+            if (action === 'pdf') {
+                var data = _.map(column, function (val){
+                    return val.field;
+                });
+                _.each(_.map(column,function(val){
+                    return val;
+                }), function(item){
+                    getColumns.push([{
+                        title: item.title,
+                        dataKey: item.field
+                    }]);
+                });
+                /*
+                ============================================================
+                    CONFIGURACION DEL PDF
+                ============================================================
+                */
+                var pdf_title = 'Facturas de Compra.';
+                var pdf_type = '';
+                var pdf_name = 'facturas_de_compra_';
+                var pdf_columnStyles = {
+                    number:{columnWidth: 30,halign:'left'},
+                    origin:{columnWidth: 15, halign:'center'},
+                    date:{halign:'center'},
+                    user_name:{ halign:'left'},
+                    customer_name:{columnWidth: 30, halign:'left'},
+                    residual:{columnWidth: 20, halign:'right'},
+                    untaxed:{columnWidth: 20, halign:'right'},
+                    tax:{columnWidth: 20, halign:'right'},
+                    total:{columnWidth: 20, halign:'right'},
+                };
+                /*
+                ============================================================
+                    LLAMAR FUNCION DE IMPRESION
+                ============================================================
+                */
+                var filter = self.getFilter();
+                var pdf = new reporting.ReportSalePdfWidget(self);
+                pdf.drawPDF(
+                    _.flatten(getColumns),
+                    row,
+                    ResCompany,
+                    pdf_title,
+                    pdf_type,
+                    pdf_name,
+                    pdf_columnStyles,
+                    filter
+                );
+            }
+        },
+        getFilter: function(){
+            var self = this;
+            var company = self.$el.find('#current-company').val();
+            var store = self.$el.find('#current-store').val();
+            var state = self.$el.find('#current-state').val();
+            var journal = self.$el.find('#current-journal').val();
+            var date = self.$el.find('#current-date').val();
+            var desde = self.$el.find('#from').val();
+            var hasta = self.$el.find('#to').val();
+            var filter = [];
+            if(company && company != 9999999){
+                var ResCompany = _.filter(self.ResCompany, function(item){
+                    return item.id == company;
+                });
+                filter.push({
+                    title:'Empresa',
+                    value: ResCompany[0].name,
+                });
+            }
+            if(store && store != 9999999){
+                var ResStore =  _.filter(self.ResStore,function (item) {
+                        return item.id == store;
+                });
+                filter.push({
+                    title: 'Sucursal',
+                    value:  ResStore[0].name,
+                });
+            }
+            if(state && state != 9999999){
+                filter.push({
+                    title: 'Estado',
+                    value: $('#current-state option:selected').text(),
+                });
+            }
+            if(journal && journal != 9999999){
+                var AccountJournal =  _.filter(self.AccountJournal,function (item) {
+                    return item.id == journal;
+                });
+                filter.push({
+                   title: 'Factura',
+                   value: AccountJournal[0].name,
+                });
+            }
+            if(date && date != 9999999){
+                moment.locale('es', {
+                    months: 'Enero_Febrero_Marzo_Abril_Mayo_Junio_Julio_Agosto_Septiembre_Octubre_Noviembre_Diciembre'.split('_'),
+                });
+
+                if(date == 'range'){
+                    filter.push({
+                        title: 'Fecha',
+                        value:  desde +' al '+hasta,
+                    });
+                }else {
+                    var fecha;
+                    if(date == 'today'){
+                        fecha = moment().format('DD/MM/YYYY');
+                    }
+                    if(date == 'yesterday'){
+                        fecha = moment().add(-1,'days').format('DD/MM/YYYY');
+                    }
+                    if(date == 'currentMonth'){
+                        fecha = moment().format('MMMM/YYYY');
+                    }
+                    if(date == 'lastMonth'){
+                        fecha = moment().add(-1,'months').format('MMMM/YYYY');
+                    }
+                    filter.push({
+                        title: 'Fecha',
+                        value:  fecha,
+                    });
+                }
+            }
+            return filter;
+        },
+    });
+}

+ 710 - 0
static/src/js/reports/report_expense_analytic.js

@@ -0,0 +1,710 @@
+function report_expense_analytic(reporting){
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportExpenseAnalyticWidget = reporting.Base.extend({
+        template: 'ReportExpenseAnalytic',
+        rowsData :[],
+        content :[],
+        modules: ['product_brand'],
+
+        events:{
+            'click .print-report' : 'clickOnAction',
+            'click #generate' : 'fetchGenerate',
+            'change #current-company' : 'updateSelections',
+            'change #current-attribute' : 'updateAttributeSelections',
+            'change #current-store' : 'updateJournalSelections',
+            'change #current-date' : 'ShowDateRange',
+        },
+
+        init : function(parent){
+            this._super(parent);
+        },
+
+        start: function () {
+            var table = this.$el.find('#table');
+            table.bootstrapTable({data : self.rowsData});
+            var date = new reporting.ReportDatePickerWidget(self);
+            date.fecthFecha();
+            this.fetchInitial();
+        },
+
+        checkModule : function(model){
+            var self = this;
+            return _.filter(self.IrModuleModule,function(item){
+                return item.name === model;
+            });
+        },
+
+        valorNull:function(dato){
+            var valor = "";
+            if (dato){
+                valor = dato;
+            }
+            return valor;
+        },
+
+        ShowDateRange : function(){
+            var self = this;
+            var date = self.$el.find('#current-date').val();
+            if(date == 'range'){
+                self.$el.find('.datepicker').css('display','block');
+            }
+            if(date != 'range'){
+                self.$el.find('.datepicker').css('display','none');
+            }
+        },
+
+        fetchInitial: function () {
+            var self = this;
+            self.fetchIntialSQL().then(function (IntialSQL) {
+                return IntialSQL;
+            }).then(function(IntialSQL) {
+                /*
+                =================================
+                    RES COMPANY
+                =================================
+                */
+                self.ResCompany = IntialSQL.companies;
+                self.CompanyLogo = IntialSQL.logo;
+                if(self.ResCompany.length > 1){
+                    self.$el.find('#current-company').append('<option value="9999999">Todas las empresas</option>');
+                    _.each(self.ResCompany,function(item){
+                        self.$el.find('#current-company').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.company').css('display','none');
+                }
+                /*
+                =================================
+                    RES STORE
+                =================================
+                */
+                self.ResStore = IntialSQL.stores;
+                if(self.ResStore.length > 1){
+                    self.$el.find('#current-store').append('<option value="9999999">Todas las sucursales</option>');
+                    _.each(self.ResStore,function(item){
+                        self.$el.find('#current-store').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.store').css('display','none');
+                }
+                /*
+                =================================
+                    ACCOUNT JOURNAL
+                =================================
+                */
+                self.AccountJournal = IntialSQL.journals;
+                var journal = _.flatten(_.filter(self.AccountJournal,function (item) {
+                    return item.type == 'sale';
+                }));
+                if(journal.length > 1){
+                    self.$el.find('#current-journal').append('<option value="9999999">Todas las facturas</option>');
+                    _.each(self.AccountJournal,function(item){
+                        if(item.type == 'sale'){
+                            self.$el.find('#current-journal').append('<option value="' + item.id + '">' + item.name + '</option>');
+                        }
+                    });
+                }else{
+                    self.$el.find('.journal').css('display','none');
+                }
+                /*
+                =================================
+                    PRODUCT CATEGORY
+                =================================
+                */
+                self.ProductCategory = IntialSQL.categories;
+                if(self.ProductCategory.length > 1){
+                    self.$el.find('#current-category').append('<option value="9999999">Todas las Categorias</option>');
+                    _.each(self.ProductCategory,function(item){
+                        self.$el.find('#current-category').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }
+                /*
+                =================================
+                    PRODUCT BRAND
+                =================================
+                */
+                self.ProductBrand = IntialSQL.brands;
+                if(self.ProductBrand.length > 1){
+                    self.$el.find('#current-brand').append('<option value="9999999">Todas las Marcas</option>');
+                    _.each(self.ProductBrand,function(item){
+                        self.$el.find('#current-brand').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.brand').css('display','none');
+                }
+                self.ProductAttribute = IntialSQL.attributes;
+                if(self.ProductAttribute.length > 1){
+                    self.$el.find('#current-attribute').append('<option value="9999999">Todos los atributos</option>');
+                    _.each(self.ProductAttribute,function(item){
+                        self.$el.find('#current-attribute').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.attribute').css('display','none');
+                }
+                self.ProductAttributeValue = IntialSQL.attribute_values;
+                if(self.ProductAttributeValue.length > 1){
+                    self.$el.find('#current-attribute-value').append('<option value="9999999">Todos los valores de atributos</option>');
+                    _.each(self.ProductAttributeValue,function(item){
+                        self.$el.find('#current-attribute-value').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.attribute-value').css('display','none');
+                }
+                return self.fetchIrModuleModule();
+            }).then(function(IrModuleModule) {
+                self.IrModuleModule = IrModuleModule;
+                return self.fetchCheckType();
+            });
+            self.$el.find('#generate').css('display','inline');
+            return;
+        },
+
+        fetchGenerate: function () {
+            var self = this;
+            self.$el.find('.search-form').block({
+                message: null,
+                overlayCSS: {
+                    backgroundColor: '#FAFAFA'
+                }
+            });
+            self.$el.find('.report-form').block({
+                message: null,
+                overlayCSS: {
+                    backgroundColor: '#FAFAFA'
+                }
+            });
+            this.fetchDataSQL().then(function(DataSQL) {
+                return DataSQL;
+            }).then(function (DataSQL) {
+                self.AccountInvoiceLine = DataSQL.invoice_lines;
+                self.PosOrderLine = DataSQL.order_lines;
+                return self.BuildTable();
+            });
+        },
+
+        fetchIntialSQL: function() {
+            var self = this;
+            var data = $.get('/report-filter-data');
+            return data;
+        },
+
+        fetchDataSQL: function() {
+            var self = this;
+            var data = $.get('/report-expense-analytic');
+            return data;
+        },
+
+        fetchIrModuleModule: function(){
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['name','id'];
+            var domain=[['state','=','installed'],['name','in',self.modules]];
+            var IrModuleModule = new model.web.Model('ir.module.module');
+            IrModuleModule.query(fields).filter(domain).all().then(function(results){
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        fetchCheckType: function(){
+            var self = this;
+            var modules = self.checkModule('point_of_sale');
+            if(modules.length == 0){
+                self.$el.find('.type').css('display','none');
+            }
+        },
+
+        /*====================================================================
+            UPDATE SELECTIONS
+        ====================================================================*/
+        updateSelections: function () {
+            var self = this;
+            var store;
+            var company = self.$el.find('#current-company').val();
+            if(company != 9999999){
+                store = self.$el.find('#current-store').empty();
+                self.$el.find('#current-store').append('<option value="9999999">Todas las sucursales</option>');
+                _.each(self.ResStore,function(item){
+                    if(parseFloat(company) == item.company_id){
+                        self.$el.find('#current-store').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    }
+                });
+            }else{
+                store = self.$el.find('#current-store').empty();
+                self.$el.find('#current-store').append('<option value="9999999">Todas las sucursales</option>');
+                _.each(self.ResStore,function(item){
+                    self.$el.find('#current-store').append('<option value="' + item.id + '">' + item.name + '</option>');
+                });
+            }
+        },
+
+        updateAttributeSelections: function () {
+            var self = this;
+            var attribute_value;
+            var attribute = self.$el.find('#current-attribute').val();
+            if(attribute != 9999999){
+                attribute_value = self.$el.find('#current-attribute-value').empty();
+                self.$el.find('#current-attribute-value').append('<option value="9999999">Todos los valores de atributos</option>');
+                _.each(self.ProductAttributeValue,function(item){
+                    if(parseFloat(attribute) == item.attribute_id){
+                        self.$el.find('#current-attribute-value').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    }
+                });
+            }else{
+                attribute_value = self.$el.find('#current-attribute-value').empty();
+                self.$el.find('#current-attribute-value').append('<option value="9999999">Todos los valores de atributos</option>');
+                _.each(self.ProductAttributeValue,function(item){
+                    self.$el.find('#current-attribute-value').append('<option value="' + item.id + '">' + item.name + '</option>');
+                });
+            }
+        },
+
+        updateJournalSelections: function () {
+            var self = this;
+            var journal;
+            var store = self.$el.find('#current-store').val();
+            if(store != 9999999){
+                journal = self.$el.find('#current-journal').empty();
+                self.$el.find('#current-journal').append('<option value="9999999">Todas las facturas</option>');
+                _.each(self.AccountJournal,function(item){
+                    if(parseFloat(store) == item.store_id){
+                        self.$el.find('#current-journal').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    }
+                });
+            }else{
+                journal = self.$el.find('#current-journal').empty();
+                self.$el.find('#current-journal').append('<option value="9999999">Todas las facturas</option>');
+                _.each(self.AccountJournal,function(item){
+                    self.$el.find('#current-journal').append('<option value="' + item.id + '">' + item.name + '</option>');
+                });
+            }
+        },
+
+        getProductCategory: function (id) {
+            var self = this;
+            var category;
+            category =  _.filter(self.ProductCategory,function (item) {
+                return item.id == id;
+            });
+            if(category.length > 0)
+                return category[0].name;
+        },
+
+        getAccountInvoiceLine:function() {
+            var self = this;
+            var content = self.AccountInvoiceLine;
+            var company = self.$el.find('#current-company').val();
+            var store = self.$el.find('#current-store').val();
+            var type = self.$el.find('#current-type').val();
+            var journal = self.$el.find('#current-journal').val();
+            var category = self.$el.find('#current-category').val();
+            var brand = self.$el.find('#current-brand').val();
+            var attribute = self.$el.find('#current-attribute').val();
+            var attribute_value = self.$el.find('#current-attribute-value').val();
+            var date = self.$el.find('#current-date').val();
+            var desde = self.$el.find('#from').val();
+            var hasta = self.$el.find('#to').val();
+
+            if((store && store == 9999999)||(company && company == 9999999)){
+                var store_ids = _.flatten(_.map(self.ResStore, function (item) {
+                    return item.id;
+                }));
+                var company_ids = _.flatten(_.map(self.ResCompany, function (item) {
+                    return item.id;
+                }));
+                content = _.flatten(_.filter(content,function (item) {
+                    return _.contains(store_ids, item.store_id) && _.contains(company_ids, item.company_id);
+                }));
+            }
+
+            if(company && company != 9999999){
+                content = _.flatten(_.filter(content,function (item) {
+                    return item.company_id == company;
+                }));
+            }
+            if(store && store != 9999999){
+                content = _.flatten(_.filter(content,function (item) {
+                    return item.store_id == store;
+                }));
+            }
+            if(type && type != 9999999){
+                if(type == 'tpv'){
+                    content = [];
+                }
+            }
+            if(journal && journal != 9999999){
+                content = _.flatten(_.filter(content,function (item) {
+                    return item.journal_id == journal;
+                }));
+            }
+            if(date && date != 9999999){
+                if(date == 'range'){
+                    if(desde){
+                        date = desde.split('/');
+                        date = (date[2]+"-"+date[1]+"-"+date[0]);
+                        content = _.flatten(_.filter(content,function (inv) {
+                            return moment(inv.date).format('YYYY-MM-DD') >= date;
+                        }));
+                    }
+                    if(hasta){
+                        date = hasta.split('/');
+                        date = (date[2]+"-"+date[1]+"-"+date[0]);
+                        content = _.flatten(_.filter(content,function (inv) {
+                            return moment(inv.date).format('YYYY-MM-DD') <= date;
+                        }));
+                    }
+                }
+                if(date == 'today'){
+                    var today = moment().format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        return moment(inv.date).format('YYYY-MM-DD') === today;
+                    }));
+                }
+                if(date == 'yesterday'){
+                    var yesterday = moment().add(-1,'days').format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        return moment(inv.date).format('YYYY-MM-DD') === yesterday;
+                    }));
+                }
+                if(date == 'currentMonth'){
+                    var currentMonth = moment().format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        return moment(inv.date).format('YYYY-MM') === currentMonth;
+                    }));
+                }
+                if(date == 'lastMonth'){
+                    var lastMonth = moment().add(-1,'months').format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        return moment(inv.date).format('YYYY-MM') === lastMonth;
+                    }));
+                }
+            }
+            if(category && category != 9999999){
+                var category_ids = _.map(_.filter(self.ProductCategory,function (item) {
+                    return item.id == category || item.parent_id == category;
+                }), function(map){
+                    return map.id;
+                });
+                var category_children_ids = _.map(_.filter(self.ProductCategory,function (item) {
+                    return _.contains(category_ids, item.parent_id) || item.id == category;
+                }), function(map){
+                    return map.id;
+                });
+                var category_grandchildren_ids = _.map(_.filter(self.ProductCategory,function (item) {
+                    return _.contains(category_children_ids, item.parent_id) || item.id == category;
+                }), function(map){
+                    return map.id;
+                });
+                var categ_ids =  _.map(_.filter(self.ProductCategory,function (item) {
+                    return _.contains(category_grandchildren_ids, item.parent_id) || item.id == category;
+                }), function(map){
+                    return map.id;
+                });
+                content = _.flatten(_.filter(content,function (inv) {
+                    return _.contains(categ_ids, inv.categ_id);
+                }));
+            }
+            if(brand && brand != 9999999){
+                content = _.filter(content,function (item) {
+                    return item.product_brand_id == parseInt(brand);
+                });
+            }
+            if(attribute && attribute != 9999999){
+                content = _.filter(content,function (item) {
+                    return _.contains(item.attribute_ids, parseInt(attribute));
+                });
+            }
+            if(attribute_value && attribute_value != 9999999){
+                content = _.filter(content,function (item) {
+                    return _.contains(item.attribute_value_ids, parseInt(attribute_value));
+                });
+            }
+            return content;
+        },
+
+        BuildTable: function(){
+            var self = this;
+            var data = [];
+            var CurrencyBase = self.ResCompany[0].currency_id;
+            var display_name;
+            var discount_amount;
+            var modules = self.checkModule('product_brand');
+            var AccountInvoiceLine = self.getAccountInvoiceLine();
+            _.each(AccountInvoiceLine,function(item) {
+                var category = self.getProductCategory(item.categ_id);
+                if(item.attribute_values[0] == null){
+                    display_name = item.product_name;
+                }else{
+                    display_name = item.product_name + ' (' + _.uniq(item.attribute_values) + ')';
+                }
+                if(modules.length > 0){
+                    if(item.product_brand_id != null){
+                        display_name = display_name + ' ( ' + item.brand_name + ')';
+                    }
+                }
+                discount_amount = 0;
+                if(item.discount > 0){
+                    discount_amount = ((item.quantity * item.price_unit) * item.discount)/100;
+                }
+                data.push({
+                    id : item.invoice_line_id,
+                    number:item.number,
+                    date:moment(item.date).format('DD/MM/YYYY'),
+                    customer_name:self.valorNull(item.partner_name),
+                    product_name:display_name,
+                    product_category:category,
+                    discount:accounting.formatNumber(item.discount,2,'.',',') + '%',
+                    discount_amount:accounting.formatMoney(discount_amount, '', CurrencyBase.decimal_places, CurrencyBase.thousands_separator, CurrencyBase.decimal_separator),
+                    price_unit:accounting.formatMoney(item.price_unit, '', CurrencyBase.decimal_places, CurrencyBase.thousands_separator, CurrencyBase.decimal_separator),
+                    quantity:accounting.formatNumber(item.quantity,2,'.',','),
+                    untaxed:accounting.formatMoney(item.subtotal, '', CurrencyBase.decimal_places, CurrencyBase.thousands_separator, CurrencyBase.decimal_separator),
+                    tax:accounting.formatMoney(item.tax, '', CurrencyBase.decimal_places, CurrencyBase.thousands_separator, CurrencyBase.decimal_separator),
+                    total:accounting.formatMoney(item.subtotal + item.tax, '', CurrencyBase.decimal_places, CurrencyBase.thousands_separator, CurrencyBase.decimal_separator),
+                    /*
+                    =============================
+                        NO FORMAT
+                    =============================
+                    */
+                    date_no_format:item.date,
+                    price_unit_no_format:item.price_unit,
+                    quantity_no_format:item.quantity,
+                    discount_amount_no_format: discount_amount,
+                    untaxed_no_format:item.subtotal,
+                    tax_no_format:item.tax,
+                    total_no_format:item.subtotal + item.tax,
+                    /*
+                    ==============================
+                        FOOTER
+                    ==============================
+                    */
+                    decimal_places:CurrencyBase.decimal_places,
+                    thousands_separator:CurrencyBase.thousands_separator,
+                    decimal_separator:CurrencyBase.decimal_separator,
+                });
+            });
+            data.sort(function (a, b) {
+                if (a.date_no_format > b.date_no_format) {
+                    return -1;
+                }
+                if (a.date_no_format < b.date_no_format) {
+                    return 1;
+                }
+                return 0;
+            });
+            self.content = data;
+            self.loadTable(data);
+            self.$el.find('.report-form').css('display','block');
+            self.$el.find('.search-form').unblock();
+            self.$el.find('.report-form').unblock();
+        },
+
+        loadTable:function(rowsTable){
+            var self = this;
+            self.rowsData = rowsTable;
+            var table = this.$el.find('#table');
+            table.bootstrapTable('load', rowsTable);
+        },
+
+        /*====================================================================
+            PRINT PDF
+        ====================================================================*/
+        clickOnAction: function (e) {
+            var self = this;
+            var ResCompany;
+            var CurrencyBase;
+            var action = this.$el.find(e.target).val();
+            var company = $('#current-company').val();
+            if(company && company != 9999999){
+                ResCompany = _.flatten(_.filter(self.CompanyLogo,function (inv) {
+                    return inv.id == company;
+                }));
+                ResCompany = ResCompany[0];
+                CurrencyBase = ResCompany[0].currency_id;
+            }else{
+                ResCompany = self.ResCompany[0];
+                CurrencyBase = self.ResCompany[0].currency_id;
+            }
+            var getColumns = [];
+            var rows = [];
+            var table = this.$el.find("#table");
+            var column = table.bootstrapTable('getVisibleColumns');
+            var row = table.bootstrapTable('getData');
+
+            var price_unit = PriceUnitFooter(row);
+            var quantity = QuantityFooter(row);
+            var tax = TaxFooter(row);
+            var untaxed = UntaxedFooter(row);
+            var total = TotalFooter(row);
+
+            row.push({
+                number : 'Totales',
+                price_unit : price_unit,
+                quantity : quantity,
+                tax : tax,
+                untaxed : untaxed,
+                total : total,
+            });
+
+            if (action === 'pdf') {
+                var data = _.map(column, function (val){
+                    return val.field;
+                });
+                _.each(_.map(column,function(val){
+                    return val;
+                }), function(item){
+                    getColumns.push([{
+                        title: item.title,
+                        dataKey: item.field
+                    }]);
+                });
+                /*
+                ============================================================
+                    CONFIGURACION DEL PDF
+                ============================================================
+                */
+                var pdf_title = 'Analisis de Compra.';
+                var pdf_type = 'l';
+                var pdf_name = 'analisis_de_compra_';
+                var pdf_columnStyles = {
+                    number:{columnWidth: 30, halign:'center'},
+                    date:{columnWidth: 20, halign:'center'},
+                    customer_name:{halign:'center'},
+                    product_name:{columnWidth: 'auto', halign:'left'},
+                    product_category:{columnWidth: 40, halign:'left'},
+                    price_unit:{columnWidth: 20, halign:'right'},
+                    quantity:{columnWidth: 20, halign:'right'},
+                    untaxed:{columnWidth: 20, halign:'right'},
+                    tax:{columnWidth: 20, halign:'right'},
+                    total:{columnWidth: 20, halign:'right'},
+                };
+                /*
+                ============================================================
+                    LLAMAR FUNCION DE IMPRESION
+                ============================================================
+                */
+                var filter = self.getFilter();
+                var pdf = new reporting.ReportSalePdfWidget(self);
+                pdf.drawPDF(
+                    _.flatten(getColumns),
+                    row,
+                    ResCompany,
+                    pdf_title,
+                    pdf_type,
+                    pdf_name,
+                    pdf_columnStyles,
+                    filter
+               );
+            }
+        },
+        getFilter: function(){
+            var self = this;
+            var company = self.$el.find('#current-company').val();
+            var store = self.$el.find('#current-store').val();
+            var journal = self.$el.find('#current-journal').val();
+            var category = self.$el.find('#current-category').val();
+            var brand = self.$el.find('#current-brand').val();
+            var attribute = self.$el.find('#current-attribute').val();
+            var attribute_value = self.$el.find('#current-attribute-value').val();
+            var date = self.$el.find('#current-date').val();
+            var desde = self.$el.find('#from').val();
+            var hasta = self.$el.find('#to').val();
+            var filter = [];
+            if(company && company != 9999999){
+                var ResCompany = _.filter(self.ResCompany, function(item){
+                    return item.id == company;
+                });
+                filter.push({
+                    title:'Empresa',
+                    value: ResCompany[0].name,
+                });
+            }
+            if(store && store != 9999999){
+                var ResStore =  _.filter(self.ResStore,function (item) {
+                    return item.id == store;
+                });
+                filter.push({
+                    title: 'Sucursal',
+                    value:  ResStore[0].name,
+                });
+            }
+            if(journal && journal != 9999999){
+                var AccountJournal = _.filter(self.AccountJournal, function(item){
+                  return item.id == journal;
+                });
+                filter.push({
+                  title: 'Factura',
+                  value: AccountJournal[0].name,
+                });
+            }
+            if(category && category != 9999999){
+                var categ =  _.filter(self.ProductCategory,function (item) {
+                    return item.id == category;
+                });
+                filter.push({
+                    title: 'Categoría',
+                    value: categ[0].name,
+               });
+            }
+            if(brand && brand != 9999999){
+                var ProductBrand =  _.filter(self.ProductBrand,function (item) {
+                    return item.id == brand;
+                });
+                filter.push({
+                    title: 'Marca',
+                    value: ProductBrand[0].name,
+                });
+            }
+            if(attribute && attribute != 9999999){
+                var attr =  _.filter(self.ProductAttribute,function (item) {
+                    return item.id == attribute;
+                });
+                filter.push({
+                    title: 'Atributo',
+                    value: attr[0].name,
+                });
+            }
+            if(attribute_value && attribute_value != 9999999){
+                var attr_value =  _.filter(self.ProductAttributeValue,function (item) {
+                    return item.id == attribute_value;
+                });
+                filter.push({
+                    title: 'Valor de Atributo',
+                    value: attr_value[0].name,
+                });
+            }
+            if(date && date != 9999999){
+                moment.locale('es', {
+                    months: 'Enero_Febrero_Marzo_Abril_Mayo_Junio_Julio_Agosto_Septiembre_Octubre_Noviembre_Diciembre'.split('_'),
+                });
+                if(date == 'range'){
+                    filter.push({
+                        title: 'Fecha',
+                        value:  desde +' al '+hasta,
+                    });
+                }else {
+                    var fecha;
+                    if(date == 'today'){
+                        fecha = moment().format('DD/MM/YYYY');
+                    }
+                    if(date == 'yesterday'){
+                        fecha = moment().add(-1,'days').format('DD/MM/YYYY');
+                    }
+                    if(date == 'currentMonth'){
+                        fecha = moment().format('MMMM/YYYY');
+                    }
+                    if(date == 'lastMonth'){
+                        fecha = moment().add(-1,'months').format('MMMM/YYYY');
+                    }
+                    filter.push({
+                        title: 'Fecha',
+                        value:  fecha,
+                    });
+                }
+            }
+            return filter;
+        },
+    });
+}

+ 232 - 0
static/src/reports/report_expense.xml

@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="ReportExpense">
+        <div class="report_view">
+            <div class="container search-form">
+                <div class="page-header">
+                    <h1><small>Historico de Gastos</small></h1>
+                </div>
+                <div class="row">
+                    <div class="col-lg-3 col-md-3 col-sm-6 company filter-style">
+                        <label>Empresa</label>
+                        <select id="current-company" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 store filter-style">
+                        <label>Sucursal</label>
+                        <select id="current-store" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 filter-style">
+                        <label>Estado</label>
+                        <select id="current-state" class="form-control form-control-sm">
+                            <option value="9999999">Todos los estados</option>
+                            <option value="open">Abierto</option>
+                            <option value="paid">Pagado</option>
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 journal filter-style">
+                        <label>Factura</label>
+                        <select id="current-journal" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 users filter-style">
+                        <label>Responsable</label>
+                        <select id="current-user" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 filter-style">
+                       <label>Fechas</label>
+                       <select id="current-date" class="form-control form-control-sm">
+                           <option value="9999999">Sin fechas</option>
+                           <option value="today">Hoy</option>
+                           <option value="yesterday">Ayer</option>
+                           <option value="currentMonth">Mes Actual</option>
+                           <option value="lastMonth">Mes Pasado</option>
+                           <option value="range">Busqueda Avanzada</option>
+                       </select>
+                   </div>
+                </div>
+                <div class="row" >
+                    <div class="datepicker" style="display:none;">
+                        <div class="col-lg-3 col-md-3 col-sm-6 filter-style col-md-offset-3">
+                            <div class="input-group">
+                                <span class="input-group-addon" id="basic-addon1">Desde</span>
+                                <input type="text" id="from" class="form-control" aria-describedby="basic-addon1"/>
+                            </div>
+                        </div>
+                        <div class="col-lg-3 col-md-3 col-sm-6 filter-style">
+                            <div class="input-group">
+                                <span class="input-group-addon" id="basic-addon1">Hasta</span>
+                                <input type="text" id="to" class="form-control" aria-describedby="basic-addon1"/>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+                <div class="row">
+                    <div class="text-center" style="padding-top:20px;">
+                        <button id="generate" class="myButton">Generar</button>
+                    </div>
+                    <br/>
+                </div>
+            </div>
+            <div class="report-form" style="display:none;">
+                <div id="toolbar">
+                    <button class="myButton print-report" value="pdf">Imprimir Informe</button>
+                </div>
+                <div class="container" style="width:98%;">
+                    <table id="table"
+                        data-pagination="true"
+                        data-toggle="table"
+                        data-toolbar="#toolbar"
+                        data-classes="table table-condensed"
+                        data-search="true"
+                        data-show-export="true"
+                        data-show-toggle="true"
+                        data-show-columns="true"
+                        data-show-footer="true"
+                        data-show-pagination-switch="true"
+                        data-footer-style="footerStyle"
+                        data-buttons-class="oe_button myButton"
+                        data-search-on-enter-key="true"
+                        data-undefined-text=" "
+                        data-pagination-v-align="top"
+                        >
+                        <thead style="background:none;">
+                            <tr>
+                                <th data-field="number"
+                                    data-align="left"
+                                    data-footer-formatter="Totales"
+                                    >Factura</th>
+                                <th data-field="origin"
+                                    data-align="center"
+                                    data-visible="false"
+                                    >Origen</th>
+                                <th data-field="date"
+                                    data-align="center"
+                                    >Fecha</th>
+                                <th data-field="user_name"
+                                    data-align="left"
+                                    >Vendedor</th>
+                                <th data-field="customer_name"
+                                    data-align="left"
+                                    >Cliente</th>
+                                <th data-field="residual"
+                                    data-align="right"
+                                    data-footer-formatter="ResidualFooter"
+                                    data-width="200"
+                                    >Saldo</th>
+                                <th data-field="untaxed"
+                                    data-align="right"
+                                    data-footer-formatter="UntaxedFooter"
+                                    data-width="200"
+                                    >SubTotal</th>
+                                <th data-field="tax"
+                                    data-align="right"
+                                    data-footer-formatter="TaxFooter"
+                                    data-width="200"
+                                    >Impuesto</th>
+                                <th data-field="total"
+                                    data-align="right"
+                                    data-footer-formatter="TotalFooter"
+                                    data-width="200"
+                                    >Total</th>
+                            </tr>
+                        </thead>
+                    </table>
+                </div>
+            </div>
+            <br/>
+            <script>
+                <!--
+                    RESIDUAL
+                -->
+                function ResidualFooter(rowsTable) {
+                    var self = this;
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.residual_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    UNTAXED
+                -->
+                function UntaxedFooter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.untaxed_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    TAX
+                -->
+                function TaxFooter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.tax_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    TOTAL
+                -->
+                function TotalFooter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.total_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    FOOTER STYLE
+                -->
+                function footerStyle(row, index) {
+                    return {
+                        css: {
+                          "font-weight": "bold"
+                        }
+                    };
+                };
+
+            </script>
+        </div>
+    </t>
+</template>

+ 293 - 0
static/src/reports/report_expense_analytic.xml

@@ -0,0 +1,293 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="ReportExpenseAnalytic">
+        <div class="report_view">
+            <div class="container search-form">
+                <div class="page-header">
+                    <h1><small>Análisis de Gastos</small></h1>
+                </div>
+                <div class="row">
+                    <div class="col-lg-3 col-md-3 col-sm-6 company filter-style">
+                        <label>Empresa</label>
+                        <select id="current-company" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 store filter-style">
+                        <label>Sucursal</label>
+                        <select id="current-store" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 journal filter-style">
+                        <label>Factura</label>
+                        <select id="current-journal" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 type filter-style">
+                        <label>Tipo de Venta</label>
+                        <select id="current-type" class="form-control form-control-sm">
+                            <option value="9999999">Todos los Tipos</option>
+                            <option value="tpv">Terminal</option>
+                            <option value="sale">Normal</option>
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 filter-style">
+                        <label>Categoria</label>
+                        <select id="current-category" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 brand filter-style">
+                        <label>Marca</label>
+                        <select id="current-brand" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 attribute filter-style">
+                        <label>Atributo</label>
+                        <select id="current-attribute" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 attribute-value filter-style">
+                        <label>Valor del Atributo</label>
+                        <select id="current-attribute-value" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 col-md-3 col-sm-6 filter-style">
+                        <label>Fechas</label>
+                        <select id="current-date" class="form-control form-control-sm">
+                            <option value="9999999">Sin fechas</option>
+                            <option value="today">Hoy</option>
+                            <option value="yesterday">Ayer</option>
+                            <option value="currentMonth">Mes Actual</option>
+                            <option value="lastMonth">Mes Pasado</option>
+                            <option value="range">Busqueda Avanzada</option>
+                        </select>
+                    </div>
+                </div>
+                <div class="row" >
+                    <div class="datepicker" style="display:none;">
+                        <div class="col-lg-3 col-md-3 col-sm-6 filter-style col-md-offset-3">
+                            <div class="input-group">
+                                <span class="input-group-addon" id="basic-addon1">Desde</span>
+                                <input type="text" id="from" class="form-control" aria-describedby="basic-addon1"/>
+                            </div>
+                        </div>
+                        <div class="col-lg-3 col-md-3 col-sm-6 filter-style">
+                            <div class="input-group">
+                                <span class="input-group-addon" id="basic-addon1">Hasta</span>
+                                <input type="text" id="to" class="form-control" aria-describedby="basic-addon1"/>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="row">
+                    <div class="text-center" style="padding-top:20px;">
+                        <button id="generate" class="myButton">Generar</button>
+                    </div>
+                    <br/>
+                </div>
+            </div>
+
+            <div class="report-form" style="display:none;">
+                <div id="toolbar">
+                    <button class="myButton print-report" value="pdf">Imprimir Informe</button>
+                </div>
+                <div class="container" style="width:95%;">
+                    <table id="table"
+                        data-pagination="true"
+                        data-toggle="table"
+                        data-toolbar="#toolbar"
+                        data-show-columns="true"
+                        data-classes="table table-condensed"
+                        data-search="true"
+                        data-show-export="true"
+                        data-show-toggle="true"
+                        data-show-footer="true"
+                        data-show-pagination-switch="true"
+                        data-pagination-v-align="top"
+                        data-footer-style="footerStyle"
+                        data-buttons-class="oe_button myButton"
+                        data-search-on-enter-key="true"
+                        data-undefined-text=" "
+                        >
+                        <thead style="background:none;">
+                            <tr>
+                                <th data-field="number"
+                                    data-align="center"
+                                    data-footer-formatter="Totales"
+                                    >Factura</th>
+                                <th data-field="date"
+                                    data-align="center"
+                                    >Fecha</th>
+                                <th data-field="customer_name"
+                                    data-align="left"
+                                    data-visible="false"
+                                    >Cliente</th>
+                                <th data-field="product_name"
+                                    data-align="left"
+                                    >Producto</th>
+                                <th data-field="product_category"
+                                    data-align="left"
+                                    data-width="200px"
+                                    data-visible="false"
+                                    >Categoria</th>
+                                <th data-field="price_unit"
+                                    data-align="right"
+                                    data-footer-formatter="PriceUnitFooter"
+                                    data-width="150"
+                                    >Precio Unitario</th>
+                                <th data-field="quantity"
+                                    data-align="right"
+                                    data-footer-formatter="QuantityFooter"
+                                    data-width="100px"
+                                    >Cantidad</th>
+                                <th data-field="discount"
+                                    data-align="center"
+                                    data-visible="false"
+                                    >Descuento (%)</th>
+                                <th data-field="discount_amount"
+                                    data-align="right"
+                                    data-footer-formatter="DiscountFooter"
+                                    data-width="150"
+                                    >Descuento (Monto)</th>
+                                <th data-field="untaxed"
+                                    data-align="right"
+                                    data-footer-formatter="UntaxedFooter"
+                                    data-width="150"
+                                    data-visible="false"
+                                    >SubTotal</th>
+                                <th data-field="tax"
+                                    data-align="right"
+                                    data-footer-formatter="TaxFooter"
+                                    data-width="150"
+                                    data-visible="false"
+                                    >Impuesto</th>
+                                <th data-field="total"
+                                    data-align="right"
+                                    data-footer-formatter="TotalFooter"
+                                    data-width="150"
+                                    >Total</th>
+                            </tr>
+                        </thead>
+                    </table>
+                </div>
+            </div>
+            <br/>
+            <script>
+                <!--
+                    PRICE UNIT
+                -->
+                function PriceUnitFooter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.price_unit_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    QUANTITY
+                -->
+                function QuantityFooter(rowsTable) {
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.quantity_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,2,'.',',');
+                }
+                <!--
+                    DISCOUNT AMOUNT
+                -->
+                function DiscountFooter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.discount_amount_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    SUBTOTAL
+                -->
+                function UntaxedFooter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.untaxed_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    TAX
+                -->
+                function TaxFooter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.tax_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    TOTAL
+                -->
+                function TotalFooter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places;
+                        thousands_separator = rowsTable[0].thousands_separator;
+                        decimal_separator = rowsTable[0].decimal_separator;
+                    }
+                    var total =  _.reduce(_.map(rowsTable,function(item){
+                        return item.total_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(total,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    FOOTER STYLE
+                -->
+                function footerStyle(row, index) {
+                    return {
+                        css: {
+                          "font-weight": "bold"
+                        }
+                    };
+                };
+            </script>
+        </div>
+    </t>
+</template>

+ 11 - 0
static/src/xml/eiru_reporting.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<template xml:space="preserve">
+    <t t-name="EiruReport">
+        <t t-call="EiruReportingBase">
+            <div class="oe_form_sheetbg">
+                
+            </div>
+        </t>
+    </t>
+</template>

+ 13 - 0
static/src/xml/eiru_reporting_base.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<template xml:space="preserve">
+    <t t-name="EiruReportingBase">
+        <div class="oe_form_container">
+            <div class="oe_form">
+                <div class="">
+                    <t t-raw="0" />
+                </div>
+            </div>
+        </div>
+    </t>
+</template>

+ 32 - 0
templates.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+        <template id="eiru_reports_expenses_assets" inherit_id="eiru_assets.assets">
+            <xpath expr="." position="inside">
+                <!-- configuration < main > -->
+                <script type="text/javascript" src="/eiru_reports_expenses/static/src/js/main.js" />
+                <script type="text/javascript" src="/eiru_reports_expenses/static/src/js/reporting_base.js" />
+                <script type="text/javascript" src="/eiru_reports_expenses/static/src/js/pdf.js" />
+                <script type="text/javascript" src="/eiru_reports_expenses/static/src/js/chart.js" />
+                <script type="text/javascript" src="/eiru_reports_expenses/static/src/js/datepicker.js" />
+                <!--
+                ==============================
+                    HISTORICO DE GASTOS
+                ==============================
+                -->
+                <script type="text/javascript" src="/eiru_reports_expenses/static/src/js/reports/report_expense.js"/>
+                <!--
+                ==============================
+                    ANALISIS DE GASTOS
+                ==============================
+                -->
+                <script type="text/javascript" src="/eiru_reports_expenses/static/src/js/reports/report_expense_analytic.js"/>
+            </xpath>
+        </template>
+
+        <record id="eiru_reports_sales_action" model="ir.actions.client">
+            <field name="name">Eiru Reports Expenses</field>
+            <field name="tag">eiru_reports_expenses.action_report</field>
+        </record>
+    </data>
+</openerp>

+ 23 - 0
views/actions.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+	<data>
+        <!--
+		==========================
+            HISTORICO DE GASTOS
+        ==========================
+		-->
+        <record id="expense_action" model="ir.actions.client">
+            <field name="name">Historico de Gastos</field>
+            <field name="tag">eiru_reports_expenses.expense_action</field>
+        </record>
+        <!--
+		==========================
+            ANALISIS DE GASTOS
+        ==========================
+		-->
+        <record id="expense_analytic_action" model="ir.actions.client">
+            <field name="name">Análisis de Gastos</field>
+            <field name="tag">eiru_reports_expenses.expense_analytic_action</field>
+        </record>
+    </data>
+</openerp>

+ 35 - 0
views/menus.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+        <menuitem
+            name="Gastos"
+            id="expense_parent_menu"
+            parent="eiru_reports_sales.eiru_reports_main_menu"
+            sequence="4"/>
+
+        <!--
+        ===========================
+           HISTORICO DE GASTOS
+        ===========================
+        -->
+        <menuitem
+            name="Historico de Gastos"
+            id="expense_history_menu"
+            parent="expense_parent_menu"
+            action="expense_action"
+            sequence="1"/>
+
+        <!--
+        ===========================
+           ANALISIS DE GASTOS
+        ===========================
+        -->
+        <menuitem
+            name="Análisis de Gastos"
+            id="expense_analytic_menu"
+            parent="expense_parent_menu"
+            action="expense_analytic_action"
+            sequence="2"/>
+
+    </data>
+</openerp>