Browse Source

commit incial

Rodney Elpidio Enciso Arias 6 years ago
commit
c512143fb0
73 changed files with 9373 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 3 0
      __init__.py
  3. BIN
      __init__.pyc
  4. 27 0
      __openerp__.py
  5. 1 0
      controller/__init__.py
  6. BIN
      controller/__init__.pyc
  7. 43 0
      controller/helpers/__init__.py
  8. BIN
      controller/helpers/__init__.pyc
  9. 82 0
      controller/helpers/account_invoice.py
  10. BIN
      controller/helpers/account_invoice.pyc
  11. 227 0
      controller/helpers/account_invoice_line.py
  12. BIN
      controller/helpers/account_invoice_line.pyc
  13. 15 0
      controller/helpers/account_journal.py
  14. BIN
      controller/helpers/account_journal.pyc
  15. 154 0
      controller/helpers/account_voucher.py
  16. BIN
      controller/helpers/account_voucher.pyc
  17. 15 0
      controller/helpers/company_logo.py
  18. 76 0
      controller/helpers/pos_order.py
  19. BIN
      controller/helpers/pos_order.pyc
  20. 238 0
      controller/helpers/pos_order_line.py
  21. BIN
      controller/helpers/pos_order_line.pyc
  22. 17 0
      controller/helpers/product_attribute.py
  23. BIN
      controller/helpers/product_attribute.pyc
  24. 23 0
      controller/helpers/product_attribute_value.py
  25. BIN
      controller/helpers/product_attribute_value.pyc
  26. 33 0
      controller/helpers/product_brand.py
  27. BIN
      controller/helpers/product_brand.pyc
  28. 25 0
      controller/helpers/product_category.py
  29. BIN
      controller/helpers/product_category.pyc
  30. 106 0
      controller/helpers/product_product.py
  31. BIN
      controller/helpers/product_product.pyc
  32. 26 0
      controller/helpers/report_category.py
  33. BIN
      controller/helpers/report_category.pyc
  34. 28 0
      controller/helpers/report_report.py
  35. BIN
      controller/helpers/report_report.pyc
  36. 24 0
      controller/helpers/res_company.py
  37. BIN
      controller/helpers/res_company.pyc
  38. 52 0
      controller/helpers/res_partner.py
  39. BIN
      controller/helpers/res_partner.pyc
  40. 13 0
      controller/helpers/res_store.py
  41. BIN
      controller/helpers/res_store.pyc
  42. 27 0
      controller/helpers/res_users.py
  43. BIN
      controller/helpers/res_users.pyc
  44. 141 0
      controller/main.py
  45. BIN
      controller/main.pyc
  46. 35 0
      models.py
  47. BIN
      models.pyc
  48. BIN
      static/description/icon.png
  49. 147 0
      static/src/css/custom.css
  50. 682 0
      static/src/js/chart.js
  51. 102 0
      static/src/js/configuration_reporting.js
  52. 40 0
      static/src/js/datepicker.js
  53. 71 0
      static/src/js/main.js
  54. 1158 0
      static/src/js/pdf.js
  55. 22 0
      static/src/js/reporting_base.js
  56. 282 0
      static/src/js/reports/report_customer.js
  57. 761 0
      static/src/js/reports/report_customer_ranking.js
  58. 509 0
      static/src/js/reports/report_expense.js
  59. 1037 0
      static/src/js/reports/report_product_list.js
  60. 759 0
      static/src/js/reports/report_sale.js
  61. 910 0
      static/src/js/reports/report_sale_analytic.js
  62. 91 0
      static/src/reports/report_customer.xml
  63. 178 0
      static/src/reports/report_customer_ranking.xml
  64. 190 0
      static/src/reports/report_product_list.xml
  65. 242 0
      static/src/reports/report_sale.xml
  66. 295 0
      static/src/reports/report_sale_analytic.xml
  67. 190 0
      static/src/reports/report_sale_ranking_product.xml
  68. 11 0
      static/src/xml/eiru_reporting.xml
  69. 13 0
      static/src/xml/eiru_reporting_base.xml
  70. 36 0
      static/src/xml/eiru_reporting_welcome.xml
  71. 60 0
      templates.xml
  72. 59 0
      views/actions.xml
  73. 96 0
      views/menus.xml

+ 1 - 0
.gitignore

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

+ 3 - 0
__init__.py

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

BIN
__init__.pyc


+ 27 - 0
__openerp__.py

@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+{
+    'name': "Eiru Reports",
+    'author': "Eiru",
+    'category': 'report',
+    'version': '1.1',
+    'depends': [
+        'base',
+        'product',
+        'account',
+        'stock',
+        'eiru_assets',
+        'account_journal_active',
+        # 'category_expense',
+        '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


+ 43 - 0
controller/helpers/__init__.py

@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# REPORT CONFIG
+from report_report import get_report_report
+from report_category import get_report_category
+# RES USERS
+from res_users import get_res_users
+from res_partner import get_customers
+
+# ACCOUNT VOUCHER
+# from account_voucher import get_account_voucher_all
+from account_voucher import get_account_voucher_customer
+# from account_voucher import get_account_voucher_supplier
+
+from res_company import get_res_company
+# from res_company import get_company_logo
+from res_store import get_res_store
+from account_journal import get_account_journal
+
+from pos_order import get_pos_order
+from pos_order_line import get_pos_order_line
+# from account_period import get_account_period
+
+# PRODUCT
+from product_category import get_product_category_all
+from product_category import get_product_category_expense
+from product_brand import get_product_brand
+from product_attribute import get_product_attribute
+from product_attribute_value import get_product_attribute_value
+from product_product import get_product_product
+
+# ACCOUNT INVOICE
+# from account_invoice import get_account_invoice_all_type
+from account_invoice import get_account_invoice_sale_type
+# from account_invoice import get_account_invoice_sale_and_refund_type
+# from account_invoice import get_account_invoice_purchase_type
+# from account_invoice import get_account_invoice_expense_type
+
+# ACCOUNT INVOICE LINE
+# from account_invoice_line import get_account_invoice_line_all_type
+from account_invoice_line import get_account_invoice_line_out_invoice
+# from account_invoice_line import get_account_invoice_line_out_invoice_and_out_refund
+# from account_invoice_line import get_account_invoice_line_in_invoice_purchase
+# from account_invoice_line import get_account_invoice_line_in_invoice_expense

BIN
controller/helpers/__init__.pyc


+ 82 - 0
controller/helpers/account_invoice.py

@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_account_invoice_sale_type():
+    company_currency_rate = r.env.user.company_id.currency_id.rate
+    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]) as invoice_rate,
+            invoice.number,
+            partner.name,
+            customer.name,
+            invoice.amount_tax,
+            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 ('out_invoice')
+        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])))
+
+    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


+ 227 - 0
controller/helpers/account_invoice_line.py

@@ -0,0 +1,227 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_account_invoice_line_out_invoice():
+    user_store = r.env.user.store_id.id
+    company_currency_rate = r.env.user.company_id.currency_id.rate
+
+    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 = 'out_invoice'
+        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 = 'out_invoice'
+        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])))
+        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])))
+        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[23],
+            } for j in r.cr.fetchall()
+        ]

BIN
controller/helpers/account_invoice_line.pyc


+ 15 - 0
controller/helpers/account_journal.py

@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+_MODEL = 'account.journal'
+
+def get_account_journal():
+    return [
+        {
+            'id': journal.id,
+            'name': journal.name,
+            'code': journal.code,
+            'type': journal.type,
+            'store_id': journal.store_ids.id
+        } for journal in r.env[_MODEL].search([])
+    ]

BIN
controller/helpers/account_journal.pyc


+ 154 - 0
controller/helpers/account_voucher.py

@@ -0,0 +1,154 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_account_voucher_all():
+    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'
+        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()
+    ]
+
+def get_account_voucher_customer():
+    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 = 'receipt'
+        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()
+    ]
+
+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


+ 15 - 0
controller/helpers/company_logo.py

@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+_MODEL = 'res.company'
+
+def get_company_logo():
+    # domain = [
+    #     ('expense','=', True)
+    # ]
+    return [
+        {
+            'id': company.id,
+            'logo': company.image_medium,
+        } for company in r.env[_MODEL].search()
+    ]

+ 76 - 0
controller/helpers/pos_order.py

@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_pos_order():
+    user_store = r.env.user.store_id.id
+
+    validate = '''
+        SELECT EXISTS(
+            SELECT table_name
+            FROM information_schema.columns
+            WHERE table_schema='public'
+                AND table_name='pos_order')
+    '''
+
+    query = '''
+        SELECT
+            pos.create_date,
+            pos.name,
+            pos.partner_id,
+            pos.user_id,
+            SUM(line.price_subtotal_incl) as amount,
+            partner.name,
+            pos.id,
+            salesperson.name,
+            SUM(line.price_subtotal) as untaxed,
+            pos.sale_journal,
+            journal.store_id,
+            pos.company_id
+        FROM pos_order as pos
+        LEFT JOIN res_store_journal_rel as journal
+        ON journal.journal_id = pos.sale_journal
+        LEFT JOIN pos_order_line AS line
+        ON line.order_id = pos.id
+        LEFT JOIN res_partner AS partner
+        ON partner.id = pos.partner_id
+        LEFT JOIN res_users AS users
+        ON users.id = pos.user_id
+        LEFT JOIN res_partner AS salesperson
+        ON salesperson.id = users.partner_id
+        GROUP BY
+            pos.create_date,
+            pos.partner_id,
+            pos.user_id,
+            pos.name,
+            partner.name,
+            pos.id,
+            salesperson.name,
+            pos.sale_journal,
+            journal.store_id,
+            pos.company_id
+    '''
+
+    r.cr.execute(validate)
+    for j in r.cr.fetchall():
+        band = j[0]
+
+    if band == True:
+        r.cr.execute(query)
+        return [
+            {
+                'date': j[0],
+                'name': j[1],
+                'customer_id': j[2],
+                'user_id': j[3],
+                'amount': j[4],
+                'customer_name': j[5],
+                'order_id': j[6],
+                'user_name': j[7],
+                'amount_untaxed': j[8],
+                'journal_id': j[9],
+                'store_id': j[10],
+                'company_id': j[11],
+            } for j in r.cr.fetchall()
+        ]
+    else:
+        return []

BIN
controller/helpers/pos_order.pyc


+ 238 - 0
controller/helpers/pos_order_line.py

@@ -0,0 +1,238 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_pos_order_line():
+    user_store = r.env.user.store_id.id
+    company_currency_rate = r.env.user.company_id.currency_id.rate
+
+    validate = '''
+        SELECT EXISTS(
+            SELECT table_name
+            FROM information_schema.columns
+            WHERE table_schema='public'
+                AND table_name='pos_order')
+    '''
+
+    validate_brand = '''
+        SELECT EXISTS(
+            SELECT table_name
+            FROM information_schema.columns
+            WHERE table_schema='public'
+                AND table_name='product_brand')
+    '''
+
+    query_with_brand = '''
+        SELECT
+        	pos.id,
+        	line.id,
+        	pos.name,
+        	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,
+        	line.qty,
+        	line.price_subtotal,
+        	line.price_subtotal_incl - line.price_subtotal AS impuestos,
+        	(array_agg(history.cost ORDER BY history.id DESC))[1] AS cost,
+            history.product_template_id,
+            journal.store_id,
+            pos.date_order,
+            pos.company_id,
+            pos.sale_journal,
+            template.categ_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,
+            product.id,
+            customer.name,
+            customer.id,
+            line.discount
+        FROM pos_order AS pos
+        LEFT JOIN pos_order_line AS line
+        ON pos.id = line.order_id
+        LEFT JOIN res_store_journal_rel as journal
+        ON journal.journal_id = pos.sale_journal
+        LEFT JOIN product_product as product
+        ON product.id = line.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 product_price_history AS history
+        ON history.product_template_id = product.product_tmpl_id
+        LEFT JOIN product_brand AS brand
+        ON brand.id = template.product_brand_id
+        LEFT JOIN res_partner AS customer
+        ON customer.id = pos.partner_id
+        WHERE pos.state NOT IN ('draft')
+        GROUP BY
+        	pos.id,
+        	line.id,
+        	pos.name,
+        	product.name_template,
+        	line.price_unit,
+        	line.qty,
+        	line.price_subtotal,
+            history.product_template_id,
+            journal.store_id,
+            pos.date_order,
+            pos.company_id,
+            pos.sale_journal,
+            template.categ_id,
+            product.default_code,
+            template.product_brand_id,
+            brand.name,
+            product.id,
+            customer.name,
+            customer.id
+    '''
+
+    query_without_brand = '''
+        SELECT
+        	pos.id,
+        	line.id,
+        	pos.name,
+        	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,
+        	line.qty,
+        	line.price_subtotal,
+        	line.price_subtotal_incl - line.price_subtotal AS impuestos,
+        	(array_agg(history.cost ORDER BY history.id DESC))[1] AS cost,
+            history.product_template_id,
+            journal.store_id,
+            pos.date_order,
+            pos.company_id,
+            pos.sale_journal,
+            template.categ_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,
+            product.id,
+            customer.name,
+            customer.id,
+            line.discount
+        FROM pos_order AS pos
+        LEFT JOIN pos_order_line AS line
+        ON pos.id = line.order_id
+        LEFT JOIN res_store_journal_rel as journal
+        ON journal.journal_id = pos.sale_journal
+        LEFT JOIN product_product as product
+        ON product.id = line.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 product_price_history AS history
+        ON history.product_template_id = product.product_tmpl_id
+        LEFT JOIN res_partner AS customer
+        ON customer.id = pos.partner_id
+        WHERE pos.state NOT IN ('draft')
+        GROUP BY
+        	pos.id,
+        	line.id,
+        	pos.name,
+        	product.name_template,
+        	line.price_unit,
+        	line.qty,
+        	line.price_subtotal,
+            history.product_template_id,
+            journal.store_id,
+            pos.date_order,
+            pos.company_id,
+            pos.sale_journal,
+            template.categ_id,
+            product.default_code,
+            template.product_brand_id,
+            product.id,
+            customer.name,
+            customer.id
+    '''
+
+    r.cr.execute(validate)
+
+    for j in r.cr.fetchall():
+        band = j[0]
+
+    if band == True:
+        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])))
+            return [
+                {
+                    'order_id': j[0],
+                    'order_line_id': j[1],
+                    'name': j[2],
+                    'product_name':j[3],
+                    'price_unit':j[4],
+                    'quantity':j[5],
+                    'subtotal':j[6],
+                    'tax': j[7],
+                    'cost': j[8],
+                    'template_id': j[9],
+                    'store_id': j[10],
+                    'date': j[11],
+                    'company_id': j[12],
+                    'journal_id': j[13],
+                    'categ_id': j[14],
+                    'attribute_value_ids': j[15],
+                    'attribute_values': j[16],
+                    'attribute_ids': j[17],
+                    'product_brand_id': j[18],
+                    'brand_name': j[19],
+                    'product_id': j[20],
+                    'customer_name': j[21],
+                    'customer_id': 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])))
+            return [
+                {
+                    'order_id': j[0],
+                    'order_line_id': j[1],
+                    'name': j[2],
+                    'product_name':j[3],
+                    'price_unit':j[4],
+                    'quantity':j[5],
+                    'subtotal':j[6],
+                    'tax': j[7],
+                    'cost': j[8],
+                    'template_id': j[9],
+                    'store_id': j[10],
+                    'date': j[11],
+                    'company_id': j[12],
+                    'journal_id': j[13],
+                    'categ_id': j[14],
+                    'attribute_value_ids': j[15],
+                    'attribute_values': j[16],
+                    'attribute_ids': j[17],
+                    'product_id': j[18],
+                    'customer_name': j[19],
+                    'customer_id': j[20],
+                    'discount': j[21],
+                } for j in r.cr.fetchall()
+            ]
+    else:
+        return []

BIN
controller/helpers/pos_order_line.pyc


+ 17 - 0
controller/helpers/product_attribute.py

@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_product_attribute():
+    query = '''
+        SELECT
+            id,
+            name
+        FROM product_attribute
+    '''
+    r.cr.execute(query)
+    return [
+        {
+            'id': j[0],
+            'name': j[1],
+        } for j in r.cr.fetchall()
+    ]

BIN
controller/helpers/product_attribute.pyc


+ 23 - 0
controller/helpers/product_attribute_value.py

@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_product_attribute_value():
+    query = '''
+        SELECT
+            attribute_value.id,
+            attribute_value.name,
+            attribute_value.attribute_id,
+            attribute.name
+        FROM product_attribute_value AS attribute_value
+        LEFT JOIN product_attribute AS attribute
+        ON attribute.id = attribute_value.attribute_id
+    '''
+    r.cr.execute(query)
+    return [
+        {
+            'id': j[0],
+            'name': j[1],
+            'attribute_id': j[2],
+            'attribute_name': j[3],
+        } for j in r.cr.fetchall()
+    ]

BIN
controller/helpers/product_attribute_value.pyc


+ 33 - 0
controller/helpers/product_brand.py

@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_product_brand():
+    validate = '''
+        SELECT EXISTS(
+            SELECT table_name
+            FROM information_schema.columns
+            WHERE table_schema='public'
+                AND table_name='product_brand')
+    '''
+
+    query = '''
+        SELECT
+            id,
+            name
+        FROM product_brand
+    '''
+
+    r.cr.execute(validate)
+    for j in r.cr.fetchall():
+        band = j[0]
+
+    if band == True:
+        r.cr.execute(query)
+        return [
+            {
+                'id': j[0],
+                'name': j[1],
+            } for j in r.cr.fetchall()
+        ]
+    else:
+        return []

BIN
controller/helpers/product_brand.pyc


+ 25 - 0
controller/helpers/product_category.py

@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+_MODEL = 'product.category'
+
+def get_product_category_all():
+    return [
+        {
+            'id': category.id,
+            'name': category.display_name,
+            'parent_id': category.parent_id.id,
+        } for category in r.env[_MODEL].search([])
+    ]
+
+def get_product_category_expense():
+    domain = [
+        ('expense','=', True)
+    ]
+    return [
+        {
+            'id': category.id,
+            'name': category.display_name,
+            'parent_id': category.parent_id.id,
+        } for category in r.env[_MODEL].search(domain)
+    ]

BIN
controller/helpers/product_category.pyc


+ 106 - 0
controller/helpers/product_product.py

@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_product_product():
+    user_store = r.env.user.store_id.id
+    company_currency_rate = r.env.user.company_id.currency_id.rate
+
+    validate_brand = '''
+        SELECT EXISTS(
+            SELECT table_name
+            FROM information_schema.columns
+            WHERE table_schema='public'
+                AND column_name='product_brand_id')
+    '''
+
+    query_with_brand = '''
+        SELECT
+        	product.id,
+        	template.categ_id,
+        	CASE
+        		WHEN product.default_code IS NOT NULL
+        		THEN ('[' || product.default_code || '] ' || product.name_template)
+        		ELSE product.name_template
+        		END AS display_name,
+        	(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
+        FROM product_product AS product
+        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 product_brand AS brand
+        ON brand.id = template.product_brand_id
+        GROUP BY
+        	product.id,
+        	template.categ_id,
+        	product.default_code,
+        	template.product_brand_id,
+        	brand.name
+    '''
+
+    query_without_brand = '''
+        SELECT
+        	product.id,
+        	template.categ_id,
+        	CASE
+        		WHEN product.default_code IS NOT NULL
+        		THEN ('[' || product.default_code || '] ' || product.name_template)
+        		ELSE product.name_template
+        		END AS display_name,
+        	(array_agg(attr_rel.att_id)) AS attr_rel,
+        	(array_agg(attr_value.name)) AS attr_value,
+        	(array_agg(attr.id)) AS attr
+        FROM product_product AS product
+        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
+        GROUP BY
+        	product.id,
+        	template.categ_id,
+        	product.default_code
+    '''
+
+    r.cr.execute(validate_brand)
+
+    for j in r.cr.fetchall():
+        brand = j[0]
+
+    if brand == True:
+        r.cr.execute(query_with_brand,([company_currency_rate]))
+        return [
+            {
+                'product_id': j[0],
+                'categ_id': j[1],
+                'product_name': j[2],
+                'attribute_value_ids':j[3],
+                'attribute_values':j[4],
+                'attribute':j[5],
+                'product_brand_id':j[6],
+                'brand_name': j[7]
+            } for j in r.cr.fetchall()
+        ]
+    else:
+        r.cr.execute(query_without_brand,([company_currency_rate]))
+        return [
+            {
+                'product_id': j[0],
+                'categ_id': j[1],
+                'product_name': j[2],
+                'attribute_value_ids':j[3],
+                'attribute_values':j[4],
+                'attribute':j[5]
+            } for j in r.cr.fetchall()
+        ]

BIN
controller/helpers/product_product.pyc


+ 26 - 0
controller/helpers/report_category.py

@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_report_category():
+    query = '''
+        SELECT
+            category.id,
+            category.name,
+            category.name_template,
+            category.description,
+            category.icon_code
+        FROM report_category AS category
+        ORDER BY category.sequence
+    '''
+
+    r.cr.execute(query)
+
+    return [
+        {
+            'id': j[0],
+            'name': j[1],
+            'name_template': j[2],
+            'description': j[3],
+            'icon_code': j[4],
+        } for j in r.cr.fetchall()
+    ]

BIN
controller/helpers/report_category.pyc


+ 28 - 0
controller/helpers/report_report.py

@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_report_report():
+    query = '''
+        SELECT
+            report.id,
+            report.name,
+            report.name_template,
+            report.description,
+            report.icon_code,
+            report.category_id
+        FROM report_report AS report
+        ORDER BY report.sequence
+    '''
+
+    r.cr.execute(query)
+
+    return [
+        {
+            'id': j[0],
+            'name': j[1],
+            'name_template': j[2],
+            'description': j[3],
+            'icon_code': j[4],
+            'category_id': j[5],
+        } for j in r.cr.fetchall()
+    ]

BIN
controller/helpers/report_report.pyc


+ 24 - 0
controller/helpers/res_company.py

@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+_MODEL = 'res.company'
+
+def get_res_company():
+    domain = []
+    return [
+        {
+            'id': company.id,
+            'name': company.name,
+            'logo': company.logo,
+            'ruc': company.partner_id.ruc,
+            'currency_id':{
+                'id':  company.currency_id.id,
+                'name':  company.currency_id.name,
+                'symbol':  company.currency_id.symbol,
+                'decimal_places':  company.currency_id.decimal_places,
+                'decimal_separator':  company.currency_id.decimal_separator,
+                'thousands_separator':  company.currency_id.thousands_separator,
+                'symbol_position':  company.currency_id.symbol_position,
+            }
+        } for company in r.env[_MODEL].search(domain)
+    ]

BIN
controller/helpers/res_company.pyc


+ 52 - 0
controller/helpers/res_partner.py

@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_customers():
+    query = '''
+        SELECT
+            partner.id,
+            partner.name,
+            partner.ruc,
+            partner.customer,
+            partner.phone,
+            partner.mobile,
+            partner.email,
+            partner.street,
+            partner.street2,
+            country.name,
+            CASE
+        		WHEN state.parent_id IS NOT NULL
+        		THEN ( parent_state.name || ' / ' || state.name)
+        		ELSE state.name
+        		END AS state,
+            partner.store_id,
+            partner.company_id
+        FROM res_partner AS partner
+        LEFT JOIN res_country AS country
+        ON country.id = partner.country_id
+        LEFT JOIN res_country_state AS state
+        ON state.id = partner.state_id
+        LEFT JOIN res_country_state AS parent_state
+        ON parent_state.id = state.parent_id
+        WHERE partner.customer = true
+    '''
+
+    r.cr.execute(query)
+
+    return [
+        {
+            'id': j[0],
+            'name': j[1],
+            'ruc': j[2],
+            'customer': j[3],
+            'phone': j[4],
+            'mobile': j[5],
+            'email': j[6],
+            'street': j[7],
+            'street2': j[8],
+            'country': j[9],
+            'state': j[10],
+            'store_id': j[11],
+            'company_id': j[12],
+        } for j in r.cr.fetchall()
+    ]

BIN
controller/helpers/res_partner.pyc


+ 13 - 0
controller/helpers/res_store.py

@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+_MODEL = 'res.store'
+
+def get_res_store():
+    return [
+        {
+            'id': store.id,
+            'name': store.name,
+            'company_id': store.company_id.id,
+        } for store in r.env[_MODEL].search([])
+    ]

BIN
controller/helpers/res_store.pyc


+ 27 - 0
controller/helpers/res_users.py

@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request as r
+
+def get_res_users():
+    query = '''
+        SELECT
+            users.id,
+            users.company_id,
+            users.store_id,
+            partner.name
+        FROM res_users AS users
+        LEFT JOIN res_partner AS partner
+        ON partner.id = users.partner_id
+        WHERE users.active = true
+    '''
+
+    r.cr.execute(query)
+
+    return [
+        {
+            'id': j[0],
+            'company_id': j[1],
+            'store_id': j[2],
+            'name': j[3],
+
+        } for j in r.cr.fetchall()
+    ]

BIN
controller/helpers/res_users.pyc


+ 141 - 0
controller/main.py

@@ -0,0 +1,141 @@
+# -*- 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):
+
+    # CONSULTA INICIAL
+    @http.route('/report-filter-data', auth='user', methods=['GET', 'POST'])
+    def getFilterData(self, **kw):
+        return make_gzip_response({
+            'companies': hp.get_res_company(),
+            'stores': hp.get_res_store(),
+            'journals': hp.get_account_journal(),
+            'users': hp.get_res_users(),
+            'categories': hp.get_product_category_all(),
+            'brands': hp.get_product_brand(),
+            'attributes': hp.get_product_attribute(),
+            'attribute_values': hp.get_product_attribute_value(),
+        })
+
+    # HISTORICO DE VENTAS
+    @http.route('/report-sale-history', auth='user', methods=['GET', 'POST'])
+    def getSaleHistory(self, **kw):
+        return make_gzip_response({
+            'invoices': hp.get_account_invoice_sale_type(),
+            'orders': hp.get_pos_order(),
+            'vouchers': hp.get_account_voucher_customer(),
+        })
+
+    # ANALISIS DE VENTAS
+    @http.route('/report-sale-analytic', auth='user', methods=['GET', 'POST'])
+    def getSaleAnalytic(self, **kw):
+        return make_gzip_response({
+            'invoice_lines': hp.get_account_invoice_line_out_invoice(),
+            'order_lines': hp.get_pos_order_line(),
+        })
+
+    # Clientes
+    @http.route('/report-customers', auth='user', methods=['GET', 'POST'])
+    def getCustomers(self, **kw):
+        return make_gzip_response({
+            'customers': hp.get_customers(),
+        })
+
+    # # HISTORICO DE COMPRAS
+    # @http.route('/report-purchase-history', auth='user', methods=['GET', 'POST'])
+    # def getPurchaseHistory(self, **kw):
+    #     return make_gzip_response({
+    #         'invoices': hp.get_account_invoice_purchase_type(),
+    #         'vouchers': hp.get_account_voucher_supplier(),
+    #     })
+    #
+    # # ANALISIS DE COMPRAS
+    # @http.route('/report-purchase-analytic', auth='user', methods=['GET', 'POST'])
+    # def getPurchaseAnalytic(self, **kw):
+    #     return make_gzip_response({
+    #         'invoice_lines': hp.get_account_invoice_line_in_invoice_purchase(),
+    #     })
+
+    # # 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_type(),
+    #         '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_in_invoice_expense(),
+    #     })
+
+    # RANKING DE PRODUCTOS
+    @http.route('/report-sale-product-ranking', auth='user', methods=['GET', 'POST'])
+    def getSaleProductRanking(self, **kw):
+        return make_gzip_response({
+            'invoice_lines': hp.get_account_invoice_line_out_invoice(),
+            'order_lines': hp.get_pos_order_line(),
+            'products': hp.get_product_product(),
+        })
+
+    # RANKING DE CLIENTES
+    @http.route('/report-sale-customer-ranking', auth='user', methods=['GET', 'POST'])
+    def getSaleCustomerRanking(self, **kw):
+        return make_gzip_response({
+            'invoice_lines': hp.get_account_invoice_line_out_invoice(),
+            'order_lines': hp.get_pos_order_line(),
+            'partners': hp.get_customers(),
+        })
+
+    # # RESUMEN DE VENTAS
+    # @http.route('/report-sale-summary', auth='user', methods=['GET', 'POST'])
+    # def getSaleSummary(self, **kw):
+    #     return make_gzip_response({
+    #         'invoices': hp.get_account_invoice_sale_and_refund_type(),
+    #         'orders': hp.get_pos_order(),
+    #     })
+    #
+    # # PERDIDAS Y GANANCIAS
+    # @http.route('/report-profit-loss', auth='user', methods=['GET', 'POST'])
+    # def getProfitLoss(self, **kw):
+    #     return make_gzip_response({
+    #         'invoice_lines': hp.get_account_invoice_line_all_type(),
+    #         'order_lines': hp.get_pos_order_line(),
+    #         'product_categories': hp.get_product_category_expense(),
+    #     })
+    #
+    # # ANALISIS DE UTILIDAD DE VENTAS
+    # @http.route('/report-sale-utility-analytic', auth='user', methods=['GET', 'POST'])
+    # def getSaleUtilityAnalytic(self, **kw):
+    #     return make_gzip_response({
+    #         'invoice_lines': hp.get_account_invoice_line_out_invoice_and_out_refund(),
+    #         'order_lines': hp.get_pos_order_line(),
+    #     })

BIN
controller/main.pyc


+ 35 - 0
models.py

@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+
+from openerp import models, fields, api
+
+class ProductPriceList(models.Model):
+	_inherit = 'product.pricelist'
+
+	@api.model
+	def getProductPriceList(self,domain):
+		ProductPriceList = self.env['product.pricelist'].search(domain)
+		values = []
+
+		for pricelist in ProductPriceList:
+			version_ids = map(lambda x: x.id, pricelist.version_id)
+			versionIDS = []
+			for item in self.env['product.pricelist'].search([('id', 'in', version_ids)]):
+				versionIDS.append(item.id)
+
+			values.append({
+		        'id' : pricelist.id,
+		        'name' : pricelist.name,
+		        'type' : pricelist.type,
+		        'version_id' : versionIDS,
+		        'store_id' : {
+		            'id' : pricelist.store_id.id,
+		            'name' : pricelist.store_id.name,
+		        },
+		        'currency_id' : {
+		            'id' : pricelist.currency_id.id,
+		            'name' : pricelist.currency_id.name,
+					'rate_silent': pricelist.currency_id.rate_silent,
+		        },
+		    })
+
+		return values

BIN
models.pyc


BIN
static/description/icon.png


+ 147 - 0
static/src/css/custom.css

@@ -0,0 +1,147 @@
+.search-form{
+    border-bottom:1px solid #eee;
+    width:98%;
+}
+.range-style {
+    padding-bottom: 9px;
+    border-bottom: 1px solid #eee;
+}
+
+.hover:hover{
+  cursor: grab;
+  cursor: -webkit-grab;
+}
+
+/*
+=============================================
+    FIRST STYLE
+=============================================
+*/
+.panel-first-style {
+    border: 1px solid #bbdefb !important;
+}
+
+.panel-header-first-style {
+    background: #bbdefb !important;
+    text-align: center;
+    font-weight: normal;
+}
+
+/*
+=============================================
+    SECOND STYLE
+=============================================
+*/
+
+.panel-second-style {
+    border: 1px solid #c8e6c9 !important;
+}
+
+.panel-header-second-style {
+    background-color: #c8e6c9 !important;
+    text-align: center;
+    font-weight: bold;
+}
+
+/*
+=============================================
+    THIRD STYLE
+=============================================
+*/
+
+.panel-third-style {
+    border: 1px solid #ffccbc !important;
+}
+
+.panel-header-third-style {
+    background-color: #ffccbc !important;
+    text-align: center;
+    font-weight: bold;
+}
+
+/*
+=============================================
+    BUTTON STYLE
+=============================================
+*/
+
+.myButton{
+    background: #d9534f !important;
+    /* background: #d9534f !important; */
+    /* color: #37474f !important; */
+    color: #fff !important;
+    height: 34px !important;
+    /* border: 1px solid #bdbdbd !important; */
+    /* border: 1px solid #428bca !important; */
+    border: none !important;
+}
+
+.dropdown-menu > li > a {
+    color: #37474f !important;
+}
+
+.dropdown-menu > .active > a {
+    color:#fff !important;
+    background-color: #d9534f !important;
+}
+
+.detail-icon {
+    color: #e57373 !important;
+}
+
+.pagination > .active > a{
+    color:#fff !important;
+    background-color: #d9534f !important;
+    border-color: #d9534f !important;
+}
+
+.filter-style {
+    padding-top: 10px;
+}
+
+.sale-button {
+    color: #fff !important;
+    background: #81c784;
+    border-color: #81c784;
+}
+.sale-button:hover{
+    color: #fff !important;
+    background: #81c784;
+    border-color: #81c784;
+}
+
+.purchase-button {
+    color: #fff !important;
+    background: #ffb74d;
+    border-color: #ffb74d;
+}
+.purchase-button:hover{
+    color: #fff !important;
+    background: #ffb74d;
+    border-color: #ffb74d;
+}
+
+.expense-button {
+    color: #fff !important;
+    background: #e57373;
+    border-color: #e57373;
+}
+.expense-button:hover{
+    color: #fff !important;
+    background: #e57373;
+    border-color: #e57373;
+}
+
+.balance-button {
+    color: #fff !important;
+    background: #0288d1;
+    border-color: #0288d1;
+}
+.balance-button:hover{
+    color: #fff !important;
+    background: #0288d1;
+    border-color: #0288d1;
+}
+.chart-container{
+    width: 100%;
+}

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

@@ -0,0 +1,682 @@
+function chart(reporting) {
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportChartWidget = reporting.Base.extend({
+
+        BuildDemoChart: 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 chartData = {
+    			labels: label,
+    			datasets: [{
+    				type: 'line',
+    				label: 'Balance',
+    				borderColor: '#0288d1',
+                    fill:false,
+    				data: [
+                        '10500',
+                        '5000',
+                        '3000',
+                        '19000',
+                        '4000',
+                        '70000',
+                        '8000',
+                        '43000',
+                        '25000',
+                        '39000',
+                        '36000',
+                        '47000',
+    				],
+    				borderWidth: 2
+    			}, {
+    				type: 'bar',
+    				label: 'Ventas',
+                    backgroundColor: '#81c784',
+    				borderWidth: 1,
+    				data: [
+                        '10000',
+                        '5000',
+                        '3000',
+                        '15000',
+                        '45000',
+                        '70000',
+                        '90000',
+                        '40000',
+                        '25000',
+                        '70000',
+                        '30000',
+                        '50000',
+    				]
+    			}, {
+    				type: 'bar',
+    				label: 'Compras',
+    				backgroundColor: '#ffb74d',
+    				data: [
+                        '10000',
+                        '5000',
+                        '3000',
+                        '15000',
+                        '4000',
+                        '70000',
+                        '8000',
+                        '40000',
+                        '25000',
+                        '35000',
+                        '30000',
+                        '40000',
+    				],
+    				borderWidth: 1
+    			}, {
+    				type: 'bar',
+    				label: 'Gastos',
+    				backgroundColor: '#e57373',
+    				data: [
+                        '10500',
+                        '5000',
+                        '3000',
+                        '19000',
+                        '4000',
+                        '70000',
+                        '8000',
+                        '43000',
+                        '25000',
+                        '39000',
+                        '36000',
+                        '47000',
+    				],
+    				borderWidth: 1
+    			}]
+    		};
+            var chart = new Chart($(".reporting-chart"), {
+                type: 'bar',
+                data: chartData,
+                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;
+                            }
+                        }
+                    }
+                }
+            });
+        },
+
+        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',
+                        // position: 'none',
+                    },
+                    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',
+                        // position: 'none',
+                    },
+                    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'],
+                }
+            });
+        },
+
+        BuildMultipleChart: function (CurrencyBase,label,body_subtotal,body_tax,body_cost,body_total,body_profit) {
+            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 chartData = {
+    			labels: label,
+    			datasets: [
+                    /*
+                    ================
+                        BENEFICIO
+                    ================
+                    */
+                    {
+    				type: 'line',
+    				label: 'Beneficio',
+                    borderColor: '#03a9f4',
+                    fill: false,
+                    borderWidth: 2,
+    				data: body_profit,
+
+                    },
+                    /*
+                    ================
+                        TOTAL
+                    ================
+                    */
+                    {
+    				type: 'bar',
+    				label: 'Total',
+                    borderColor: '#BCCEF4',
+    				backgroundColor: '#BCCEF4',
+                    borderWidth: 1,
+    				data: body_total,
+                    },
+                    /*
+                    ================
+                        SUB TOTAL
+                    ================
+                    */
+                    {
+    				type: 'bar',
+    				label: 'Sub-Total',
+    				borderColor: '#A9E5E3',
+                    backgroundColor: '#A9E5E3',
+    				borderWidth: 1,
+    				data: body_subtotal,
+    			    },
+                    /*
+                    ================
+                        IMPUESTOS
+                    ================
+                    */
+                    {
+    				type: 'bar',
+    				label: 'Impuestos',
+                    borderColor: '#A0D995',
+    				backgroundColor: '#A0D995',
+                    borderWidth: 1,
+    				data:body_tax,
+    			    },
+                    /*
+                    ================
+                        COSTE
+                    ================
+                    */
+                    {
+    				type: 'bar',
+    				label: 'Coste',
+                    borderColor: '#C5D084',
+    				backgroundColor: '#C5D084',
+                    borderWidth: 1,
+    				data: body_cost,
+                    },
+                ]
+    		};
+            var chart = new Chart($(".reporting-chart"), {
+                type: 'bar',
+                data: chartData,
+                options: {
+                    responsive: true,
+                    responsiveAnimationDuration:20,
+                    maintainAspectRatio:false,
+                    title: {
+                        display: false,
+                    },
+                    hover: {
+                        mode: 'nearest',
+                        intersect: true
+                    },
+                    legend: {
+                       display: false,
+                    },
+                    layout: {
+                        padding: {
+                            top: 15,
+                            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;
+                            }
+                        }
+                    }
+                }
+            });
+        },
+
+        BuildMultipleBarChart: function (
+            data,
+            CurrencyBase,
+            first_label,
+            first_body,
+            second_label,
+            second_body,
+            third_label,
+            third_body,
+            fourth_label,
+            fourth_body,
+            label
+            ) {
+            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 chartData = {
+    			labels: label,
+    			datasets: [
+
+                    {
+    				type: 'bar',
+    				label: first_label,
+                    borderColor: '#BCCEF4',
+    				backgroundColor: '#BCCEF4',
+                    borderWidth: 1,
+    				data: first_body,
+                    },
+
+                    {
+    				type: 'bar',
+    				label: second_label,
+    				borderColor: '#A9E5E3',
+                    backgroundColor: '#A9E5E3',
+    				borderWidth: 1,
+    				data: second_body,
+    			    },
+
+                    {
+    				type: 'bar',
+    				label: third_label,
+                    borderColor: '#A0D995',
+    				backgroundColor: '#A0D995',
+                    borderWidth: 1,
+    				data: third_body,
+    			    },
+
+                    {
+    				type: 'bar',
+    				label: fourth_label,
+                    borderColor: '#0288d1',
+    				backgroundColor: '#0288d1',
+                    borderWidth: 1,
+    				data: fourth_body,
+    			    },
+                ]
+    		};
+
+            var chart = new Chart($(".reporting-chart"), {
+                type: 'bar',
+                data: chartData,
+                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.yLabel, CurrencyBase.symbol, CurrencyBase.decimal_places, CurrencyBase.thousands_separator, CurrencyBase.decimal_separator);
+                                return label;
+                            }
+                        }
+                    },
+                    events: ['click'],
+                }
+            });
+        },
+    });
+}

+ 102 - 0
static/src/js/configuration_reporting.js

@@ -0,0 +1,102 @@
+function configuration_reporting (reporting, instance, widget) {
+    "use strict";
+    var widgets = widget;
+
+    widget.ReportingWidget = instance.Widget.extend({
+        template: 'EiruReport',
+        events: {},
+
+        start: function () {
+            var self = this;
+            self.fetchInitial();
+            self.BuildChart();
+        },
+
+        fetchInitial:function() {
+            var self = this;
+            self.fetchResUser().then(function (ResUser) {
+                return ResUser;
+            }).then(function (ResUser) {
+                self.ResUser = ResUser;
+                return self.fetchResCurrency();
+            }).then(function (ResCurrency) {
+                self.ResCurrency = ResCurrency;
+                self.BuildChart();
+                return self.InsertUser();
+            });
+        },
+
+        fetchResUser: function() {
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['id','name'];
+            var domain = [['id','=',self.session.uid]];
+            var ResUser = new instance.web.Model('res.users');
+            ResUser.query(fields).filter(domain).all().then(function (results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        /*====================================================================
+            RES CURRENCY
+        ====================================================================*/
+        fetchResCurrency : function(){
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['id','name', 'symbol', 'rate_silent', 'base', 'decimal_separator', 'decimal_places', 'thousands_separator', 'symbol_position'];
+            var domain = [
+                ['base','=',true],
+            ];
+            var ResCurrency = new instance.web.Model('res.currency');
+            ResCurrency.query(fields).filter(domain).all().then(function(results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        BuildChart: function(){
+            var self = this;
+            var label = [
+                'Enero',
+                'Febrero',
+                'Marzo',
+                'Abril',
+                'Mayo',
+                'Junio',
+                'Julio',
+                'Agosto',
+                'Septiembre',
+                'Octubre',
+                'Noviembre',
+                'Diciembre',
+            ];
+            var body = [
+                '20000',
+                '30000',
+                '80000',
+                '50000',
+                '60000',
+                '70000',
+                '90000',
+                '40000',
+                '100000',
+                '70000',
+                '30000',
+                '50000',
+            ];
+            var CurrencyBase = self.ResCurrency;
+            if(CurrencyBase){
+                var chart = new reporting.ReportChartWidget(self);
+                chart.BuildDemoChart(label,body,CurrencyBase[0]);
+            }
+        },
+
+        InsertUser: function(id) {
+            var self = this;
+            var user = self.ResUser[0].name;
+            self.$el.find('.user-content').find('p').text("Hola " + user + " ...!");
+        },
+
+    });
+}

+ 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;
+            }
+        },
+    });
+}

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

@@ -0,0 +1,71 @@
+openerp.eiru_reports_sales = function (instance) {
+    "use strict";
+
+    var reporting = instance.eiru_reports_sales;
+
+    reporting_base(instance,reporting);
+    configuration_reporting(reporting,instance,reporting);
+
+    try {
+        /*
+        ================================
+            BASE
+        ================================
+        */
+        pdf(reporting);
+        chart(reporting);
+        datepicker(reporting);
+        /*
+        ================================
+            VENTAS
+        ================================
+        */
+        report_sale(reporting);
+        report_sale_analytic(reporting);
+        report_customer(reporting);
+        report_customer_ranking(reporting);
+        report_sale_ranking_product(reporting);
+        report_product_list(reporting);
+    } catch (e) {
+        // ignorar error
+    }
+
+    /*
+    ================================================================================
+        HISTORICO DE VENTAS
+    ================================================================================
+    */
+    instance.web.client_actions.add('eiru_reports_sales.sale_action', 'instance.eiru_reports_sales.ReportSaleWidget');
+
+    /*
+    ================================================================================
+        ANALISIS DE VENTAS
+    ================================================================================
+     */
+    instance.web.client_actions.add('eiru_reports_sales.sale_analytic_action', 'instance.eiru_reports_sales.ReportSaleAnalyticWidget');
+
+    /*
+    ================================================================================
+        CLIENTES
+    ================================================================================
+     */
+    instance.web.client_actions.add('eiru_reports_sales.customer_action', 'instance.eiru_reports_sales.ReportCustomerWidget');
+
+    /*
+    ================================================================================
+        RANKING DE CLIENTES
+    ================================================================================
+    */
+    instance.web.client_actions.add('eiru_reports_sales.customer_ranking_action', 'instance.eiru_reports_sales.ReportCustomerRankingWidget');
+
+    /*
+    ================================================================================
+        RANKING DE PRODUCTOS MAS VENDIDOS
+    ================================================================================
+    */
+    instance.web.client_actions.add(
+        'eiru_reports_sales.sale_ranking_product_action',
+        'instance.eiru_reports_sales.ReportSaleRankingProductWidget'
+    );
+
+};

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

@@ -0,0 +1,1158 @@
+function pdf(reporting) {
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportPdfWidget = 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;
+        if(pdf_type == 'l'){
+          var col1_title = 15;
+          var col1_value = 55;
+          var col2_title = 150;
+          var col2_value = 190;
+        }
+        else{
+          var col1_title = 10;
+          var col1_value = 50;
+          var col2_title = 110;
+          var 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, {
+            // showHeader: 'firstPage',
+            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'
+        });
+      },
+
+        drawStockPDF: function (
+            index,
+            getColumns,
+            row,
+            ResCompany,
+            pdf_title,
+            pdf_type,
+            pdf_name,
+            pdf_columnStyles,
+            current_location) {
+            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);
+            getColumns.shift();
+            pdfDoc.autoTable(getColumns, row, {
+                theme: 'grid',
+                styles: {
+                    overflow: 'linebreak',
+                    columnWidth: 'auto',
+                    fontSize: 7,
+                },
+                headerStyles: {
+                    fillColor: [76, 133, 248],
+                    fontSize: 8
+                },
+                columnStyles: pdf_columnStyles,
+                margin: { top: 20, horizontal: 7, bottom: 40,},
+
+                drawCell: function(cell, data) {
+                    var rows = data.table.rows;
+                    if (data.row.index == rows.length - 1) {
+                        pdfDoc.setFontStyle('bold');
+                    };
+                },
+
+                addPageContent: function (data) {
+                    pdfDoc.addImage(base64Img, 'png', 7, 2, 0, 15);
+                    if(pdf_type == 'l'){
+                        pdfDoc.setFontSize(12);
+                        pdfDoc.setFontStyle('bold');
+                        pdfDoc.setTextColor(40);
+                        pdfDoc.text(pdf_title,130,10);
+                    }else{
+                        pdfDoc.setFontSize(12);
+                        pdfDoc.setFontStyle('bold');
+                        pdfDoc.setTextColor(40);
+                        pdfDoc.text(pdf_title,80,10);
+                    }
+                    if(current_location.length > 0){
+                        pdfDoc.setFontSize(9);
+                        pdfDoc.setFontStyle('normal');
+                        pdfDoc.setTextColor(40)
+                        pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 54, 18,"Ubicación: " + current_location[0].parent_name);
+                    }
+                    pdfDoc.setFontSize(9);
+                    pdfDoc.setFontStyle('normal');
+                    pdfDoc.setTextColor(40)
+                    pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 55, 14," Fecha de Expedición: " + hoy);
+
+                    /*===========
+                        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.text(str, pdfDoc.internal.pageSize.getWidth() - 55, pageHeight - 5);
+                }
+            });
+            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');
+        },
+
+        drawSaleJournalPDF: function (getColumns,row,ResCompany,pdf_title,pdf_type,pdf_name,pdf_columnStyles,desde,hasta) {
+            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);
+
+            /*
+            ==============================================
+                PRIMERA COLUMNA
+            ==============================================
+            */
+
+            // Title
+            pdfDoc.setFontSize(15);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text(pdf_title,7,10);
+
+            // DEL
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text('DEL: ' + desde,7,20);
+
+            // AL
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text('AL: ' + hasta ,7,24);
+
+            /*
+            ==============================================
+                SEGUNDA COLUMNA
+            ==============================================
+            */
+
+            // CODIGO DESDE
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text('Código Desde: ' + 1 ,50,20);
+
+            // CODIGO HASTA
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text('Código Hasta: ' + (row.length - 1),50,24);
+
+            /*
+            ==============================================
+                QUINTA COLUMNA
+            ==============================================
+            */
+
+            // Empresa
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text('Empresa: ' + ResCompany.name ,100,20);
+
+            // RUC
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text('R.U.C: ' + ResCompany.company_ruc ,100,24);
+
+            /*
+            ==============================================
+                CREACION DEL PDF
+            ==============================================
+            */
+
+            pdfDoc.autoTable(getColumns, row, {
+                showHeader: 'false',
+                theme: 'grid',
+
+                drawRow: function (row, data) {
+                    if(pdf_type == "l"){
+                        if (row.index === 0) {
+                            pdfDoc.setTextColor(40);
+                            pdfDoc.setFontSize(8);
+                            pdfDoc.setFontStyle('bold');
+                            // Documento
+                            pdfDoc.rect(data.settings.margin.left, row.y, 52, 8, 'S');
+                            // Clientes
+                            pdfDoc.rect(59, row.y, 72, 8, 'S');
+                            // Total de Ventas
+                            pdfDoc.rect(131, row.y, 162, 8, 'S');
+                            pdfDoc.autoTableText("DOCUMENTO", 33, row.y + row.height / 2, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            pdfDoc.autoTableText("CLIENTES", 95, row.y + row.height / 2, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            pdfDoc.autoTableText("TOTAL DE VENTAS", 210, row.y + row.height / 2, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // NUM
+                            pdfDoc.rect(data.settings.margin.left, row.y + 8, 31, 8, 'S');
+                            pdfDoc.autoTableText("NUM", 22, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // FECHA
+                            pdfDoc.rect(38, row.y + 8, 21, 8, 'S');
+                            pdfDoc.autoTableText("FECHA", 47, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // RAZON SOCIAL
+                            pdfDoc.rect(59, row.y + 8, 52, 8, 'S');
+                            pdfDoc.autoTableText("RAZON SOCIAL", 83, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // RUC
+                            pdfDoc.rect(111, row.y + 8, 20, 8, 'S');
+                            pdfDoc.autoTableText("RUC", 120, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // GRAVADAS
+                            pdfDoc.rect(131, row.y + 8, 28, 8, 'S');
+                            pdfDoc.autoTableText("GRAVADAS", 145, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // %
+                            pdfDoc.rect(159, row.y + 8, 9, 8, 'S');
+                            pdfDoc.autoTableText("%", 163, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // IMPUESTOS
+                            pdfDoc.rect(168, row.y + 8, 25, 8, 'S');
+                            pdfDoc.autoTableText("IMPUESTOS", 180, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // EXENTAS
+                            pdfDoc.rect(193, row.y + 8, 30, 8, 'S');
+                            pdfDoc.autoTableText("EXENTAS", 209, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // Ret IVA
+                            pdfDoc.rect(223, row.y + 8, 20, 8, 'S');
+                            pdfDoc.autoTableText("Ret IVA", 232, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // Ret Renta
+                            pdfDoc.rect(243, row.y + 8, 20, 8, 'S');
+                            pdfDoc.autoTableText("Ret RENTA", 253, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // TOTAL
+                            pdfDoc.rect(263, row.y + 8, 30, 8, 'S');
+                            pdfDoc.autoTableText("TOTAL", 276, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            data.cursor.y += 16;
+                        };
+                    }else{
+                        if (row.index === 0) {
+                            pdfDoc.setTextColor(40);
+                            pdfDoc.setFontSize(8);
+                            pdfDoc.setFontStyle('bold');
+                            // Documento
+                            pdfDoc.rect(data.settings.margin.left, row.y, 43, 8, 'S');
+                            // Clientes
+                            pdfDoc.rect(50, row.y, 53, 8, 'S');
+                            // Total de Ventas
+                            pdfDoc.rect(103, row.y, 100, 8, 'S');
+                            pdfDoc.autoTableText("DOCUMENTO", 29, row.y + row.height / 2, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            pdfDoc.autoTableText("CLIENTES", 77, row.y + row.height / 2, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            pdfDoc.autoTableText("TOTAL DE VENTAS",148, row.y + row.height / 2, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // NUM
+                            pdfDoc.setFontSize(6);
+                            pdfDoc.rect(data.settings.margin.left, row.y + 8, 27, 8, 'S');
+                            pdfDoc.autoTableText("NUM", 21, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // FECHA
+                            pdfDoc.rect(34, row.y + 8, 16, 8, 'S');
+                            pdfDoc.autoTableText("FECHA", 42, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // RAZON SOCIAL
+                            pdfDoc.rect(50, row.y + 8, 35, 8, 'S');
+                            pdfDoc.autoTableText("RAZON SOCIAL", 68, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // RUC
+                            pdfDoc.rect(85, row.y + 8, 18, 8, 'S');
+                            pdfDoc.autoTableText("RUC", 95, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // GRAVADAS
+                            pdfDoc.rect(103, row.y + 8, 20, 8, 'S');
+                            pdfDoc.autoTableText("GRAVADAS", 113, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // %
+                            pdfDoc.rect(123, row.y + 8, 5, 8, 'S');
+                            pdfDoc.autoTableText("%", 126, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // IMPUESTOS
+                            pdfDoc.rect(128, row.y + 8, 15, 8, 'S');
+                            pdfDoc.autoTableText("IMPUESTOS", 136, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // EXENTAS
+                            pdfDoc.rect(143, row.y + 8, 20, 8, 'S');
+                            pdfDoc.autoTableText("EXENTAS", 152, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // Ret IVA
+                            pdfDoc.rect(163, row.y + 8, 10, 8, 'S');
+                            pdfDoc.autoTableText("Ret", 168, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            pdfDoc.autoTableText("IVA", 168, row.y + row.height / 2 + 10, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // Ret Renta
+                            pdfDoc.rect(173, row.y + 8, 10, 8, 'S');
+                            pdfDoc.autoTableText("Ret", 179, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            pdfDoc.autoTableText("RENTA", 178, row.y + row.height / 2 + 10, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            // TOTAL
+                            pdfDoc.rect(183, row.y + 8, 20, 8, 'S');
+                            pdfDoc.autoTableText("TOTAL", 192, row.y + row.height / 2 + 8, {
+                                halign: 'center',
+                                valign: 'middle'
+                            });
+                            data.cursor.y += 16;
+                        };
+                    }
+                },
+
+                drawCell: function(cell, data) {
+                    var rows = data.table.rows;
+                    if (data.row.index == rows.length - 1) {
+                        pdfDoc.setFillColor(200, 200, 255);
+                    }
+                },
+
+                styles: {
+                    overflow: 'linebreak',
+                    columnWidth: 'auto',
+                    fontSize: 7,
+                },
+                headerStyles: {
+                    fillColor: [76, 133, 248],
+                    fontSize: 9
+                },
+
+                columnStyles: pdf_columnStyles,
+                margin: { top: 28, horizontal: 7},
+
+                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.text(str, pdfDoc.internal.pageSize.getWidth() - 55, pageHeight - 5);
+                }
+            });
+
+            pdfDoc.setFontSize(9);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text('Listado concluido', 7, pdfDoc.autoTable.previous.finalY + 5);
+
+            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');
+        },
+
+        drawWithDetails: function (getColumns,row,ResCompany,pdf_title,pdf_type,pdf_name,pdf_columnStyles,amount) {
+            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 title = [];
+            title.push({
+                title : 'Metodo de Pago',
+                dataKey: 'name',
+                align: 'left',
+            });
+            title.push({
+                title : 'Monto',
+                dataKey: 'amount',
+                align: 'right',
+            });
+            var i = 0;
+            var position = 25;
+            _.each(row, function(item){
+                var docItem = [];
+                if(item.info != 'undefined'){
+                    _.each(item.info, function(index){
+                        docItem.push({
+                            name: index.journal,
+                            amount: index.amount_total
+                        });
+                    });
+                };
+                docItem.push({
+                    name: 'Total',
+                    amount: item.amount_total
+                });
+
+                if(row.length <= 2 & row.length == i+1){
+                    return false;
+                };
+
+                if(i > 0){
+                    let first = pdfDoc.autoTable.previous;
+                    position = first.finalY + 7;
+                    pdfDoc.rect(7, position - 7, 196, 10, 'S');
+                };
+                pdfDoc.setFontSize(10);
+                pdfDoc.autoTableText(item.store, 102, position - 3, {
+                    halign: 'center',
+                    valign: 'middle'
+                });
+                pdfDoc.autoTable(title, docItem, {
+                    showHeader: false,
+                    startY: position,
+                    theme: 'grid',
+                    styles: {
+                        overflow: 'linebreak',
+                        columnWidth: 'auto',
+                        fontSize: 7,
+                    },
+                    headerStyles: {
+                        fillColor: [76, 133, 248],
+                        fontSize: 9
+                    },
+                    columnStyles: {
+                        name:{halign:'left'},
+                        amount:{columnWidth: 50, halign:'right'},
+                    },
+                    margin: { horizontal: 7},
+                    drawCell: function(cell, data) {
+                        var rows = data.table.rows;
+                        if (data.row.index == rows.length - 1) {
+                            pdfDoc.setFontStyle('bold');
+                        }
+                    },
+                    addPageContent: function (data) {
+                        if(i == 0){
+                            pdfDoc.addImage(base64Img, 'png', 7, 2, 0, 15);
+                            if(pdf_type == 'l'){
+                                pdfDoc.setFontSize(12);
+                                pdfDoc.setFontStyle('bold');
+                                pdfDoc.setTextColor(40);
+                                pdfDoc.text(pdf_title,130,10);
+                            }else{
+                                pdfDoc.setFontSize(12);
+                                pdfDoc.setFontStyle('bold');
+                                pdfDoc.setTextColor(40);
+                                pdfDoc.text(pdf_title,80,10);
+                            }
+                            pdfDoc.setFontSize(9);
+                            pdfDoc.setFontStyle('normal');
+                            pdfDoc.setTextColor(40)
+                            pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 55, 14," Fecha de Expedición: " + hoy);
+
+                            /*===========
+                                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.text(str, pdfDoc.internal.pageSize.getWidth() - 55, pageHeight - 5);
+                        }
+                    }
+                });
+                i++;
+            });
+
+            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');
+        },
+
+        drawProfitAndLossPDF: function (
+            getColumns,
+            row,
+            ResCompany,
+            pdf_title,
+            pdf_type,
+            pdf_name,
+            amount
+            ) {
+            var self = this;
+            var sale = [];
+            var expense = [];
+            var column = [];
+            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);
+
+            /*
+            ============================
+                VENTAS
+            ============================
+            */
+            var coste = 0;
+            var profit = 0;
+            _.each(row, function(item){
+                if(item.type == 'sale'){
+                    sale.push({
+                        name : item.store,
+                        total : item.amount_total,
+                    });
+                };
+                if(item.expense == true){
+                    coste = item.amount_total;
+                };
+                if(item.profit == true){
+                    profit = item.amount_total;
+                };
+                if(item.expense_detail == true){
+                    expense.push({
+                        name : item.store,
+                        total : item.amount_total,
+                    });
+                };
+            });
+            column.push({
+                title : 'Name',
+                dataKey: 'name',
+                align: 'left',
+            });
+            column.push({
+                title : 'total',
+                dataKey: 'total',
+                align: 'right',
+            });
+
+            /*
+            ==============================
+                LOGO
+            ==============================
+            */
+            pdfDoc.addImage(base64Img, 'png', 10, 10, 0, 20);
+            /*
+            ==============================
+                FECHA
+            ==============================
+            */
+            pdfDoc.setFontSize(13);
+            pdfDoc.setFontStyle('normal');
+            pdfDoc.setTextColor(40)
+            pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 32, 12,hoy);
+            /*
+            ==============================
+                TITULO
+            ==============================
+            */
+            pdfDoc.setFontSize(15);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor('#0288d1');
+            pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 75, 18, pdf_title);
+            /*
+            ==============================
+                DESCRIPCION
+            ==============================
+            */
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor('#424242');
+            pdfDoc.text(10, 38, 'Descripción');
+            /*
+            ==============================
+                LINEA
+            ==============================
+            */
+            pdfDoc.setLineWidth(0.5);
+            pdfDoc.setDrawColor('#424242');
+            pdfDoc.line(10, 40, pdfDoc.internal.pageSize.getWidth() - 10 , 40);
+            /*
+            ==============================
+                VENTAS
+            ==============================
+            */
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor('#424242');
+            pdfDoc.text(10, 45, 'VENTAS');
+
+            /*
+            ==============================
+                PRIMERA TABLA
+            ==============================
+            */
+            pdfDoc.autoTable(column, sale, {
+                showHeader: false,
+                theme: 'plain',
+                styles: {
+                    overflow: 'linebreak',
+                    columnWidth: 'auto',
+                    fontSize: 9,
+                },
+                columnStyles: {
+                    amount:{halign:'left'},
+                    total:{columnWidth: 50, halign:'right'},
+                },
+                margin: { top: 48, horizontal: 20},
+                drawCell: function(cell, data) {
+                    var rows = data.table.rows;
+                    if (data.row.index == rows.length - 1) {
+                        pdfDoc.setTextColor('#0288d1');
+                        pdfDoc.setFontStyle('bold');
+                    };
+                },
+            });
+            /*
+            ==============================
+                LINEA
+            ==============================
+            */
+            pdfDoc.setLineWidth(0.5);
+            pdfDoc.setDrawColor('#424242');
+            pdfDoc.line(10, pdfDoc.autoTable.previous.finalY + 1, pdfDoc.internal.pageSize.getWidth() - 10 , pdfDoc.autoTable.previous.finalY + 1);
+            /*
+            ==============================
+                COSTE DE VENTAS
+            ==============================
+            */
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor('#424242');
+            pdfDoc.text(10, pdfDoc.autoTable.previous.finalY + 7, 'Coste de ventas');
+            /*
+            ==============================
+                COSTE DE VENTAS - valor
+            ==============================
+            */
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor('#424242');
+            pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 35, pdfDoc.autoTable.previous.finalY + 7, coste);
+            /*
+            ==============================
+                LINEA
+            ==============================
+            */
+            pdfDoc.setLineWidth(0.5);
+            pdfDoc.setDrawColor('#424242');
+            pdfDoc.line(10, pdfDoc.autoTable.previous.finalY + 10, pdfDoc.internal.pageSize.getWidth() - 10 , pdfDoc.autoTable.previous.finalY + 10);
+            /*
+            ==============================
+                BENEFICIO
+            ==============================
+            */
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text(10, pdfDoc.autoTable.previous.finalY + 15, 'BENEFICIO BRUTO');
+            /*
+            ==============================
+                BENEFICIO - valor
+            ==============================
+            */
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor('#0288d1');
+            pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 35, pdfDoc.autoTable.previous.finalY + 15, profit);
+            /*
+            ==============================
+                SEGUNDA TABLA
+            ==============================
+            */
+            var dynamic_top = pdfDoc.autoTable.previous.finalY + 25;
+            pdfDoc.autoTable(column, expense, {
+                showHeader: false,
+                theme: 'plain',
+                styles: {
+                    overflow: 'linebreak',
+                    columnWidth: 'auto',
+                    fontSize: 9,
+                },
+                columnStyles: {
+                    amount:{halign:'left'},
+                    total:{columnWidth: 50, halign:'right'},
+                },
+                startY: pdfDoc.autoTable.previous.finalY + 25,
+                margin: {
+                    horizontal: 20
+                },
+                drawCell: function(cell, data) {
+                    var rows = data.table.rows;
+                    if (data.row.index == rows.length - 1) {
+                        pdfDoc.setTextColor('#0288d1');
+                        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.text(str, pdfDoc.internal.pageSize.getWidth() - 55, pageHeight - 5);
+                },
+            });
+
+            /*
+            ==============================
+                LINEA
+            ==============================
+            */
+            pdfDoc.setLineWidth(0.5);
+            pdfDoc.setDrawColor('#424242');
+            pdfDoc.line(10, pdfDoc.autoTable.previous.finalY + 10, pdfDoc.internal.pageSize.getWidth() - 10 , pdfDoc.autoTable.previous.finalY + 10);
+            /*
+            ==============================
+                RESULTADO
+            ==============================
+            */
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor(40);
+            pdfDoc.text(10, pdfDoc.autoTable.previous.finalY + 15, 'RESULTADO');
+            /*
+            ==============================
+                VALOR FINAL
+            ==============================
+            */
+            pdfDoc.setFontSize(10);
+            pdfDoc.setFontStyle('bold');
+            pdfDoc.setTextColor('#0288d1');
+            pdfDoc.text(pdfDoc.internal.pageSize.getWidth() - 35, pdfDoc.autoTable.previous.finalY + 15, amount);
+
+            if (typeof pdfDoc.putTotalPages === 'function') {
+                pdfDoc.putTotalPages(totalPagesExp);
+            }
+
+            if(model.printer_bridge){
+                var data = pdfDoc.output('datauristring');
+                model.printer_bridge.print(data);
+                return;
+            };
+            pdfDoc.save(pdf_name + hoy + '.pdf');
+        },
+
+        getPDFFileButton: function  () {
+            var canvas = $(".reporting-chart").get(0);
+            var dataURL = canvas.toDataURL();
+            var pdf = new jsPDF();
+            pdf.addImage(dataURL, 'JPEG', 10, 10, 190, 70);
+            pdf.save("chart.pdf");
+        },
+
+        // pdf resumen de ventas diarias cod:3
+        drawPdf3: function (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 title = [];
+          var currentpage = 0;
+          var i = 0;
+          var position = 27;
+          var y_position2 = 27;
+
+          title.push({
+            title : 'Fecha',
+            dataKey: 'date',
+            align: 'center',
+          });
+          title.push({
+            title : 'Sucursal',
+            dataKey: 'store',
+            align: 'center',
+          });
+          title.push({
+            title : 'Cantidad',
+            dataKey: 'qty',
+            align: 'center',
+          });
+          title.push({
+            title : 'Monto de Venta',
+            dataKey: 'price',
+            align: 'right',
+          });
+          title.push({
+            title : 'Promedio de Venta Total',
+            dataKey: 'average',
+            align: 'right',
+          });
+
+          //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 ii=0;
+          if(pdf_type == 'l'){
+            var col1_title = 15;
+            var col1_value = 55;
+            var col2_title = 150;
+            var col2_value = 190;
+          }
+          else{
+            var col1_title = 10;
+            var col1_value = 50;
+            var col2_title = 110;
+            var col2_value = 150;
+          }
+          if(filter.length >0){
+            _.each(filter,function(item){
+              if(ii<4){
+                self.addFilter(pdfDoc,item.title,item.value,col1_title,col1_value,position);
+                position = position + 5;
+              }else{
+                self.addFilter(pdfDoc,item.title,item.value,col2_title,col2_value,y_position2);
+                y_position2 = y_position2 + 5;
+              }
+                ii++;
+            });
+            pdfDoc.setLineWidth(0.5);
+            pdfDoc.setDrawColor('#424242');
+
+            if(position >= y_position2){
+              position = position;
+              pdfDoc.line(10, position, pdfDoc.internal.pageSize.getWidth() - 10 , position);
+            }else{
+              position = y_position2;
+              pdfDoc.line(10, y_position2, pdfDoc.internal.pageSize.getWidth() - 10 , y_position2);
+            }
+          }
+
+          _.each(row, function(item){
+            if(i > 0){
+              let first = pdfDoc.autoTable.previous;
+              position = first.finalY + 5;
+            };
+
+            var docItem = [];
+            if(item.info != 'undefined'){
+              _.each(item.info, function(index){
+                docItem.push({
+                  date: index.date,
+                  store: index.store,
+                  qty: index.qty,
+                  price: index.price,
+                  average: index.average,
+                })
+              });
+            }
+
+            pdfDoc.setDrawColor(0);
+            pdfDoc.setFillColor(76, 133, 248);
+            pdfDoc.rect(7, position+5, 196, 8, 'F');
+
+            pdfDoc.setFontSize(9);
+            pdfDoc.setTextColor(255,255,255)
+            pdfDoc.setFontStyle('bold');
+
+            pdfDoc.autoTableText('Vendedor: ', 15, position+9, {
+              halign: 'left',
+              valign: 'middle'
+            });
+
+            pdfDoc.autoTableText(item.user, 33, position+9, {
+              halign: 'left',
+              valign: 'middle'
+            });
+
+            pdfDoc.autoTableText('Cantidad: ', 110, position+9, {
+              halign: 'left',
+              valign: 'middle'
+            });
+
+            pdfDoc.autoTableText(item.qty, 126, position+9, {
+              halign: 'left',
+              valign: 'middle'
+            });
+
+            pdfDoc.autoTableText('Monto Total: ', 145, position+9, {
+              halign: 'left',
+              valign: 'middle'
+            });
+
+            pdfDoc.autoTableText(item.price, 165, position+9, {
+              halign: 'left',
+              valign: 'middle'
+            });
+
+            pdfDoc.autoTable(title, docItem, {
+              //  showHeader: false,
+              startY: position+15,
+              theme: 'grid',
+              styles: {
+                overflow: 'linebreak',
+                fontSize: 8,
+                margin: 50,
+                lineWidth: 0.3,
+                lineColor: [132,132,132]
+              },
+              headerStyles: {
+                fillColor: [255,255,255],
+                fontSize: 9,
+                textColor: [0,0,0],
+                lineWidth: 0.3,
+                lineColor: [132,132,132]
+              },
+              columnStyles: pdf_columnStyles,
+              margin: 'auto',
+              tableWidth: 'auto',
+
+              addPageContent: function (data) {
+                // FOOTER
+                if (currentpage < pdfDoc.internal.getNumberOfPages()) {
+                  var str = "Página " + pdfDoc.internal.getNumberOfPages();
+                  str = str + " de " + totalPagesExp;
+                  pdfDoc.setFontSize(9);
+                  pdfDoc.setFontStyle('bold');
+                  pdfDoc.setTextColor(40);
+                  var pageHeight = pdfDoc.internal.pageSize.height || pdfDoc.internal.pageSize.getHeight();
+                  pdfDoc.text(str, pdfDoc.internal.pageSize.getWidth() - 55, pageHeight - 5);
+                  currentpage = pdfDoc.internal.getNumberOfPages();
+                }
+              }
+            });
+            i++;
+          });
+          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');
+        },
+        //end cod:3
+
+    });
+}

+ 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;
+        }
+    });
+}

+ 282 - 0
static/src/js/reports/report_customer.js

@@ -0,0 +1,282 @@
+function report_customer(reporting){
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportCustomerWidget = reporting.Base.extend({
+        template: 'ReportCustomer',
+        rowsData :[],
+        content :[],
+
+        events:{
+            'click #toolbar > button' : 'clickOnAction',
+            'click #generate' : 'fetchGenerate',
+        },
+
+        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;
+        },
+
+        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');
+                // }
+            });
+            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.ResPartner = DataSQL.customers;
+                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-customers');
+            return data;
+        },
+
+        getResPartner: function(){
+            var self = this;
+            var content = self.ResPartner;
+            var company = self.$el.find('#current-company').val();
+            var store = self.$el.find('#current-store').val();
+
+            var company_ids = _.flatten(_.map(self.ResCompany, function (item) {
+                return item.id;
+            }));
+            company_ids.push(null);
+
+            var store_ids = _.flatten(_.map(self.ResStore, function (item) {
+                return item.id;
+            }));
+            store_ids.push(null);
+
+            content = _.flatten(_.filter(content,function (item) {
+                return _.contains(store_ids, item.store_id);
+            }));
+
+            content = _.flatten(_.filter(content,function (item) {
+                return _.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;
+                }));
+            }
+
+            return content;
+        },
+
+        BuildTable: function(){
+            var self = this;
+            var data = [];
+            console.log(self);
+            var ResPartner = self.getResPartner();
+            _.each(ResPartner, function(item){
+                data.push({
+                    id : item.id,
+                    ruc : self.valorNull(item.ruc),
+                    name : item.name,
+                    street : self.valorNull(item.street) + ' ' + self.valorNull(item.street2),
+                    phone : self.valorNull(item.phone),
+                    mobile : self.valorNull(item.mobile),
+                    email : self.valorNull(item.email),
+                    country : self.valorNull(item.country),
+                    state : self.valorNull(item.state),
+                });
+            });
+
+            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();
+        },
+
+        /*====================================================================
+            LOAD BOOTSTRAP TABLE
+        ====================================================================*/
+        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.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');
+
+            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 = 'Clientes.';
+                var pdf_type = 'l';
+                var pdf_name = 'clientes_';
+                var pdf_columnStyles = {
+                    ruc : {columnWidth: 20, halign:'left'},
+                    name : {halign:'left'},
+                    street : {columnWidth: 30, halign:'left'},
+                    state : {columnWidth: 30, halign:'left'},
+                    country : {columnWidth: 30, halign:'left'},
+                    phone : {columnWidth: 30, halign:'left'},
+                    mobile : {columnWidth: 30, halign:'left'},
+                    email : {columnWidth: 40, halign:'left'},
+                };
+                /*
+                ============================================================
+                    LLAMAR FUNCION DE IMPRESION
+                ============================================================
+                */
+                var filter = self.getFilter();
+                var pdf = new reporting.ReportPdfWidget(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 type = self.$el.find('#current-type').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(type && type != 9999999){
+                filter.push({
+                    title: 'Tipo de Cliente',
+                    value: $('#current-type option:selected').text(),
+                });
+            }
+            return filter;
+        },
+    });
+}

+ 761 - 0
static/src/js/reports/report_customer_ranking.js

@@ -0,0 +1,761 @@
+function report_customer_ranking(reporting){
+  "use strict";
+
+  var model = openerp;
+
+    reporting.ReportCustomerRankingWidget = reporting.Base.extend({
+        template : 'ReportCustomerRanking',
+        rowsData : [],
+        content : [],
+        modules : ['product_brand','point_of_sale'],
+
+        events : {
+            'click #generate' : 'fetchGenerate',
+            'change #current-date' : 'ShowDateRange',
+            'change #current-company': 'updateSelections',
+            'change #current-attribute': 'updateAttributeSelections',
+            '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;
+        },
+
+        checkModule: function(module) {
+            var self = this;
+            return _.filter(self.session.module_list, function(item) {
+                return item == module;
+            });
+        },
+
+        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;
+                if(self.AccountJournal.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">Todos las Categorias</option>');
+                    _.each(self.ProductCategory,function(item){
+                        self.$el.find('#current-category').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }
+                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">Todas 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">Todas 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');
+                }
+            }).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('.chart-container').css('display', 'none');
+            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;
+                self.ResPartner = DataSQL.partners;
+                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-sale-customer-ranking');
+            return data;
+        },
+
+        fetchCheckType: function() {
+            var self = this;
+            var modules = self.checkModule('point_of_sale');
+            if (modules.length == 0) {
+                self.$el.find('.type').css('display', 'none');
+            }
+        },
+
+        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>');
+                });
+            }
+        },
+
+        getPosOrderLine:function() {
+            var self = this;
+            var content = self.PosOrderLine;
+            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(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 == 'sale'){
+                    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) {
+                            var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                            utc = moment(utc._d).format('YYYY-MM-DD');
+                            return moment(utc).format('YYYY-MM-DD') >= date;
+                        }));
+                    }
+                    if(hasta){
+                        date = hasta.split('/');
+                        date = (date[2]+"-"+date[1]+"-"+date[0]);
+                        content = _.flatten(_.filter(content,function (inv) {
+                            var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                            utc = moment(utc._d).format('YYYY-MM-DD');
+                            return moment(utc).format('YYYY-MM-DD') <= date;
+                        }));
+                    }
+                }
+                if(date == 'today'){
+                    var today = moment().format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM-DD') === today;
+                    }));
+                }
+                if(date == 'yesterday'){
+                    var yesterday = moment().add(-1,'days').format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM-DD') === yesterday;
+                    }));
+                }
+                if(date == 'currentMonth'){
+                    var currentMonth = moment().format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM') === currentMonth;
+                    }));
+                }
+                if(date == 'lastMonth'){
+                    var lastMonth = moment().add(-1,'months').format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).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;
+        },
+
+        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(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;
+        },
+
+        getAccountInvoiceLineByCustomer:function(partner_id,type) {
+            var self = this;
+            return  _.filter(self.AccountInvoiceLine,function (item) {
+                return item.partner_id == partner_id && item.type == type;
+            });
+        },
+
+        getPosOrderLineByCustomer:function(partner_id) {
+            var self = this;
+            return  _.filter(self.PosOrderLine,function (item) {
+                return item.customer_id == partner_id;
+            });
+        },
+
+        BuildTable: function(){
+            var self = this;
+            console.log(self);
+            var data = [];
+            var CurrencyBase = self.ResCompany[0].currency_id;
+            self.AccountInvoiceLine = self.getAccountInvoiceLine();
+            self.PosOrderLine = self.getPosOrderLine();
+            var ResPartner = self.ResPartner;
+            _.each(ResPartner, function(item){
+
+                /*
+                    INVOICE
+                */
+                var AccountInvoiceLine = self.getAccountInvoiceLineByCustomer(item.id,'out_invoice');
+                var InvoiceLineAmount = _.reduce(_.map(AccountInvoiceLine, function(map) {
+                    return map.subtotal + map.tax;
+                }), function(meno, num) {
+                    return meno + num;
+                }, 0);
+                /*
+                    INVOICE REFUND
+                */
+                var AccountInvoiceLineRefund = self.getAccountInvoiceLineByCustomer(item.id,'out_refund');
+                var InvoiceLineRefundAmount = _.reduce(_.map(AccountInvoiceLineRefund, function(map) {
+                    return map.subtotal + map.tax;
+                }), function(meno, num) {
+                    return meno + num;
+                }, 0);
+                /*
+                    POS ORDER
+                */
+                var PosOrderLine = self.getPosOrderLineByCustomer(item.id);
+                var PosOrderAmount = _.reduce(_.map(PosOrderLine, function(map) {
+                    return map.subtotal + map.tax;
+                }), function(meno, num) {
+                    return meno + num;
+                }, 0);
+
+                var amount = InvoiceLineAmount + PosOrderAmount - InvoiceLineRefundAmount;
+
+                if(amount > 0){
+                    data.push({
+                        ruc:item.ruc,
+                        name:item.name,
+                        total:accounting.formatMoney(amount,'',CurrencyBase.decimal_places,CurrencyBase.thousands_separator,CurrencyBase.decimal_separator),
+                        /*
+                        =======================
+                            NO FORMAT
+                        =======================
+                        */
+                        total_no_format:amount,
+                        /*
+                        =======================
+                            FOOTER
+                        =======================
+                        */
+                        decimal_places: CurrencyBase.decimal_places,
+                        thousands_separator: CurrencyBase.thousands_separator,
+                        decimal_separator: CurrencyBase.decimal_separator,
+                    });
+                }
+            });
+            data.sort(function(a, b) {
+                return b.total_no_format - a.total_no_format;
+            });
+            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.CompanyLogo,function (inv) {
+                    return inv.id == company;
+                }));
+                ResCompany = ResCompany[0];
+                CurrencyBase = ResCompany[0].currency_id;
+            }else{
+                ResCompany = self.CompanyLogo[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 total = TotalFooter(row);
+
+            row.push({
+                name: 'Totales',
+                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 = 'Ranking de Clientes (+Compras)';
+                var pdf_type = '';
+                var pdf_name = 'ranking_clientes_';
+                var pdf_columnStyles = {
+                    ruc:{hcolumnWidth:45, align:'left'},
+                    name:{columnWidth:70,halign:'left'},
+                    total:{halign:'right'},
+                };
+                /*
+                ============================================================
+                    LLAMAR FUNCION DE IMPRESION
+                ============================================================
+                */
+                var filter = self.getFilter();
+                var pdf = new reporting.ReportPdfWidget(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 user = self.$el.find('#current-user').val();
+            var type = self.$el.find('#current-type').val();
+            var product = self.$el.find('#current-product').val();
+            var brand = self.$el.find('#current-brand').val();
+            var category = self.$el.find('#current-category').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(user && user != 9999999){
+                var ResUser =  _.filter(self.ResUser,function (item) {
+                    return item.id == user;
+                });
+                filter.push({
+                    title: 'Vendedor',
+                    value:  ResUser[0].name,
+                });
+            }
+
+            if(type && type != 9999999){
+                filter.push({
+                    title: 'Tipo de Venta',
+                    value:  $("#current-type option:selected").text(),
+                });
+            }
+
+            if(brand && brand != 9999999){
+                brand =  _.filter(self.ProductBrand,function (item) {
+                    return item.id == brand;
+                });
+                filter.push({
+                    title: 'Marca',
+                    value: brand[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(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;
+        }
+    });
+}

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

@@ -0,0 +1,509 @@
+function report_expense(reporting){
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportExpenseWidget = reporting.Base.extend({
+        template: 'ReportExpense',
+        rowsData :[],
+        content :[],
+
+        events:{
+            'click #generate':'fetchGenerate',
+            'change #current-company':'updateSelections',
+            '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;
+                if(self.AccountJournal.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');
+                }
+                /*
+                =================================
+                    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>');
+                    });
+                }
+            });
+            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>');
+                });
+            }
+        },
+
+        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 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();
+
+            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(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;
+            console.log(self);
+            var data = [];
+            var residual = 0;
+            var CurrencyBase = self.ResCompany[0].currency_id;
+            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({
+                    /*
+                    =======================
+                        IDS
+                    =======================
+                    */
+                    id:item.id,
+                    /*
+                    =======================
+                        INFO
+                    =======================
+                    */
+                    origin:item.origin,
+                    number:item.number,
+                    date:moment(item.date).format('DD/MM/YYYY'),
+                    user_name:item.user_name,
+                    user_id:item.user_id,
+                    supplier_name:self.valorNull(item.supplier_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.CompanyLogo,function (inv) {
+                    return inv.id == company;
+                }));
+                ResCompany = ResCompany[0];
+                CurrencyBase = ResCompany[0].currency_id;
+            }else{
+                ResCompany = self.CompanyLogo[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 Gastos.';
+                var pdf_type = '';
+                var pdf_name = 'facturas_de_gastos_';
+                var pdf_columnStyles = {
+                    number:{columnWidth: 30,halign:'left'},
+                    date:{halign:'center'},
+                    user_name:{ halign:'left'},
+                    supplier_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.ReportPdfWidget(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 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(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;
+        },
+    });
+}

+ 1037 - 0
static/src/js/reports/report_product_list.js

@@ -0,0 +1,1037 @@
+function report_product_list(reporting){
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportProductListWidget = reporting.Base.extend({
+        template: 'ReportProductList',
+        rowsData :[],
+        content :[],
+        modules: ['product_brand'],
+
+        events:{
+            'click #toolbar > button' : 'clickOnAction',
+            'click #generate' : 'fetchGenerate',
+            'click-row.bs.table #table' : 'clickAnalysisDetail',
+            'change #current-company' : 'updateSelections',
+            'change #current-attribute' : 'updateAttributeSelections',
+        },
+
+        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;
+        },
+        checkModel : function(model){
+            var self = this;
+            return _.filter(self.IrModuleModule,function(item){
+                return item.name === model
+            });
+        },
+
+        clickAnalysisDetail: function(e, row, $element,field){
+            if (field == 'name'){
+                this.do_action({
+                    name:"Producto",
+                    type: 'ir.actions.act_window',
+                    res_model: "product.product",
+                    views: [[false,'form']],
+                    target: 'new',
+                    domain: [['id','=', row.id]],
+                    context: {},
+                    flags: {'form': {'action_buttons': false, 'options': {'mode': 'view'}}},
+                    res_id: row.id,
+                });
+            }
+            e.stopImmediatePropagation();
+        },
+
+        fetchInitial: function () {
+            var self = this;
+            self.fecthIrModuleModule().then(function (IrModuleModule) {
+                return IrModuleModule;
+            }).then(function(IrModuleModule) {
+                self.IrModuleModule = IrModuleModule;
+                return self.fetchResUser();
+            }).then(function (ResUser) {
+                self.ResUser = ResUser;
+                return self.fetchResCompany();
+            }).then(function(ResCompany){
+                self.ResCompany = ResCompany;
+                if(ResCompany.length > 1){
+                    self.$el.find('#current-company').append('<option value="9999999">Todas las empresas</option>');
+                    _.each(ResCompany,function(item){
+                        self.$el.find('#current-company').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.company').css('display','none');
+                }
+                return self.fetchResStore();
+            }).then(function(ResStore){
+                self.ResStore = ResStore;
+                if(ResStore.length > 1){
+                    self.$el.find('#current-store').append('<option value="9999999">Todas las sucursales</option>');
+                    _.each(ResStore,function(item){
+                        self.$el.find('#current-store').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.store').css('display','none');
+                }
+                return self.fetchProductCategory();
+            }).then(function(ProductCategory){
+                self.ProductCategory = ProductCategory;
+                self.$el.find('#current-category').append('<option value="9999999">Todas las categorias</option>');
+                _.each(ProductCategory,function(item){
+                    self.$el.find('#current-category').append('<option value="' + item.id + '">' + item.complete_name + '</option>');
+                });
+                return self.fetchProductBrand();
+            }).then(function(ProductBrand){
+                self.ProductBrand = ProductBrand;
+                if(ProductBrand.length > 0){
+                    self.$el.find('#current-brand').append('<option value="9999999">Todas las marcas</option>');
+                    _.each(ProductBrand,function(item){
+                        self.$el.find('#current-brand').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.brand').css('display','none');
+                }
+                return self.fetchProductAttribute();
+            }).then(function(ProductAttribute){
+                self.ProductAttribute = ProductAttribute;
+                if(ProductAttribute.length > 0){
+                    self.$el.find('#current-attribute').append('<option value="9999999">Todos los atributos</option>');
+                    _.each(ProductAttribute,function(item){
+                        self.$el.find('#current-attribute').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    });
+                }else{
+                    self.$el.find('.attribute').css('display','none');
+                }
+                return self.fetchProductAttributeValue();
+            }).then(function(ProductAttributeValue){
+                self.ProductAttributeValue = ProductAttributeValue;
+                if(ProductAttributeValue.length > 0){
+                    self.$el.find('#current-attribute-value').append('<option value="9999999">Todos los valores de atributos</option>');
+                    _.each(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.fetchProductPriceList();
+            }).then(function(ProductPriceList){
+                self.ProductPriceList = ProductPriceList;
+                if(ProductPriceList.length > 0){
+                  var sale = _.filter(ProductPriceList,function (item) {
+                      return item.type == 'sale';
+                  });
+                  var purchase = _.filter(ProductPriceList,function (item) {
+                      return item.type == 'purchase';
+                  });
+                  self.$el.find('#current-sale-price').append('<option value="9999999">Precio Base</option>');
+                  _.each(sale,function(item){
+                      self.$el.find('#current-sale-price').append('<option value="' + item.id + '">' + item.name + '</option>');
+                  });
+
+                  self.$el.find('#current-purchase-price').append('<option value="9999999">Precio Base</option>');
+                  _.each(purchase,function(item){
+                      self.$el.find('#current-purchase-price').append('<option value="' + item.id + '">' + item.name + '</option>');
+                  });
+               }else{
+                  self.$el.find('.salePrice').css('display','none');
+                  self.$el.find('.buyPrice').css('display','none');
+              }
+                return self.fetchPricelistVersion();
+            }).then(function(PricelistVersion){
+                self.PricelistVersion = PricelistVersion;
+                return self.fetchPricelistVersionItem();
+            }).then(function(PricelistVersionItem){
+                self.PricelistVersionItem = PricelistVersionItem;
+                return self.fetchResCurrency();
+            }).then(function(ResCurrency){
+                self.ResCurrency = ResCurrency;
+                return self.fetchProductTemplate();
+            }).then(function(ProductTemplate){
+                self.ProductTemplate = ProductTemplate;
+            });
+            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.fetchProductProduct().then(function(ProductProduct) {
+                return ProductProduct;
+            }).then(function (ProductProduct) {
+                self.ProductProduct = ProductProduct;
+                return self.BuildTable();
+            });
+        },
+
+        /*=====================================================================
+            IR MODULE
+        =====================================================================*/
+        fecthIrModuleModule: 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;
+        },
+
+
+
+        /*=====================================================================
+            USER
+        =====================================================================*/
+        fetchResUser: function() {
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['id','name','store_id'];
+            var domain = [['id','=',self.session.uid]];
+            var ResUser = new model.web.Model('res.users');
+            ResUser.query(fields).filter(domain).all().then(function (results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        /*=====================================================================
+            PRICE LIST
+        =====================================================================*/
+        fetchProductPriceList: function() {
+            var self = this;
+            var domain = [];
+            var ProductProduct = new model.web.Model('product.pricelist');
+            return ProductProduct.call('getProductPriceList',[domain], {
+                context: new model.web.CompoundContext()
+            });
+        },
+
+        /*=====================================================================
+            PRICE LIST VERSION
+        =====================================================================*/
+        fetchPricelistVersion: function() {
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['id','name','listprice_id','items_id','date_start','date_end'];
+            var domain = [['active','=',true]];
+            var ResUser = new model.web.Model('product.pricelist.version');
+            ResUser.query(fields).filter(domain).all().then(function (results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        /*=====================================================================
+            PRICE LIST VERSION ITEMS
+        =====================================================================*/
+        fetchPricelistVersionItem: function() {
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['name','product_id','categ_id','min_quantity','product_tmpl_id','sequence','base','price_discount','price_surcharge','price_round','price_min_margin','price_max_margin'];
+            var ResUser = new model.web.Model('product.pricelist.item');
+            ResUser.query(fields).filter().all().then(function (results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        /*====================================================================
+            RES COMPANY
+        ====================================================================*/
+        fetchResCompany: function(){
+            var self = this;
+            var defer = $.Deferred();
+            var currency = new model.web.Model('res.company');
+            var field=['id','name','currency_id','logo'];
+            currency.query(field).filter().all().then(function(results){
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        /*====================================================================
+            RES STORE
+        ====================================================================*/
+        fetchResStore: function(){
+            var self = this;
+            var defer = $.Deferred();
+            var field = ['id','name','company_id'];
+            var ResStore = new model.web.Model('res.store');
+            ResStore.query(field).all().then(function(results){
+                defer.resolve(results);
+            });
+            return defer;
+        },
+        /*====================================================================
+            PRODUCT TEMPLATE
+        ====================================================================*/
+        fetchProductTemplate: function(){
+            var self = this;
+            var defer = $.Deferred();
+            var field = ['id','name','product_variant_ids','store_id'];
+            var domain =[
+              ['active','=', true],
+              ['sale_ok','=',true]];
+
+            var ProductTemplate = new model.web.Model('product.template');
+            ProductTemplate.query(field).filter(domain).all().then(function(results){
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        /*====================================================================
+            PRODUCT CATEGORY
+        ====================================================================*/
+        fetchProductCategory : function(){
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['id','name','parent_id','complete_name'];
+            var ProductCategory = new model.web.Model('product.category');
+            ProductCategory.query(fields).filter().all().then(function(results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+        /*====================================================================
+            PRODUCT BRAND
+        ====================================================================*/
+        fetchProductBrand : function(){
+            var self = this;
+            var defer = $.Deferred();
+            var modules = self.checkModel('product_brand');
+            if (modules.length > 0){
+                var fields = ['id','name'];
+                var ProductBrand = new model.web.Model('product.brand');
+                ProductBrand.query(fields).filter().all().then(function(results) {
+                    defer.resolve(results);
+                });
+                return defer;
+            }else{
+                var ProductBrand = [];
+                return ProductBrand;
+            }
+        },
+
+        /*====================================================================
+            PRODUCT ATTRIBUTE
+        ====================================================================*/
+        fetchProductAttribute : function(){
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['id','name'];
+            var ProductAttribute = new model.web.Model('product.attribute');
+            ProductAttribute.query(fields).filter().all().then(function(results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        /*====================================================================
+            PRODUCT ATTRIBUTE VALUE
+        ====================================================================*/
+        fetchProductAttributeValue : function(){
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['id','name','attribute_id'];
+            var ProductAttributeValue = new model.web.Model('product.attribute.value');
+            ProductAttributeValue.query(fields).filter().all().then(function(results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+
+        /*====================================================================
+            RES CURRENCY
+        ====================================================================*/
+        fetchResCurrency : function(){
+            var self = this;
+            var defer = $.Deferred();
+            var fields = ['id','name', 'symbol', 'rate_silent', 'base', 'decimal_separator', 'decimal_places', 'thousands_separator', 'symbol_position'];
+            var domain = [['active', '=', true]];
+            var ResCurrency = new model.web.Model('res.currency');
+            ResCurrency.query(fields).filter(domain).all().then(function(results) {
+                defer.resolve(results);
+            });
+            return defer;
+        },
+
+        /*====================================================================
+            RES PARTNER
+        ====================================================================*/
+        fetchProductProduct: function() {
+            var self = this;
+            var categ_ids = [];
+            var templates_ids =[];
+            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 type = self.$el.find('#current-type').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 domain = [
+                ['active', '=', true],
+                ['sale_ok','=',true],
+            ];
+
+            if(company && company != 9999999){
+                domain.push(['company_id','=',parseInt(company)]);
+            }
+
+            if(store && store != 9999999){
+                _.map(_.filter(self.ProductTemplate, function (item) {
+                  return item.store_id[0] == store;
+                }), function(map){
+
+                    if(map.product_variant_ids.length > 1){
+                        _.each(map.product_variant_ids, function(each){
+                            templates_ids.push(each);
+                        });
+                    }else{
+                        templates_ids.push(map.product_variant_ids[0]);
+                    }
+                });
+                domain.push(['id','in', templates_ids]);
+            }
+
+            if(state && state != 9999999){
+              if(state == 'available'){
+                domain.push(['qty_available','>',0]);
+              }
+              if(state == 'unavailable'){
+                domain.push(['qty_available','<=',0]);
+              }
+            }
+
+            if(type && type != 9999999){
+              domain.push(['type','=',type]);
+            }
+
+            if(category){
+              // Nivel 0, nivel 1
+              var category_ids = _.map(_.filter(self.ProductCategory,function (item) {
+                  return item.id == category || item.parent_id[0] == category;
+              }), function(map){
+                  return map.id;
+              });
+
+              // Nivel 0, nivel 1, nivel 2
+              var category_children_ids = _.map(_.filter(self.ProductCategory,function (item) {
+                  return _.contains(category_ids, item.parent_id[0]) || item.id == category;
+              }), function(map){
+                  return map.id;
+              });
+
+              // Nivel 0, nivel 1, nivel 2, nivel 3
+              var category_grandchildren_ids = _.map(_.filter(self.ProductCategory,function (item) {
+                  return _.contains(category_children_ids, item.parent_id[0]) || item.id == category;
+              }), function(map){
+                  return map.id;
+              }) ;
+
+              // Nivel 0, nivel 1, nivel 2, nivel 3, nivel 4
+              categ_ids =  _.map(_.filter(self.ProductCategory,function (item) {
+                  return _.contains(category_grandchildren_ids, item.parent_id[0]) || item.id == category;
+              }), function(map){
+                  return map.id;
+              });
+            }
+
+            if(category && category != 9999999){
+              domain.push(['categ_id','in',categ_ids]);
+            }
+
+            if(brand && brand != 9999999){
+              domain.push(['product_brand_id','=',parseInt(brand)]);
+            }
+
+            var attribute_ids = _.map(_.filter(self.ProductAttribute,function (item) {
+              return item.id == attribute;
+            }), function(map){
+              return map.id;
+           });
+
+           var attribute_value_ids = _.map(_.filter(self.ProductAttributeValue,function (item) {
+              return item.id == attribute_value;
+            }), function(map){
+              return map.id;
+           });
+
+           if(attribute && attribute != 9999999){
+             domain.push(['attribute_line_ids.attribute_id', 'in', attribute_ids]);
+           }
+
+           if(attribute_value && attribute_value != 9999999){
+             domain.push(['attribute_value_ids', 'in', attribute_value_ids]);
+           }
+
+           var ProductProduct = new model.web.Model('product.product');
+           return ProductProduct.call('getProductProduct',[domain], {
+                context: new model.web.CompoundContext()
+           });
+        },
+
+
+        /*====================================================================
+            UPDATE SELECTIONS
+        ====================================================================*/
+        updateSelections: function () {
+            var self = this;
+            var company = self.$el.find('#current-company').val();
+            if(company != 9999999){
+                /*===================
+                    STORE SELECTION
+                ===================*/
+                var 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 SELECTION
+                ===================*/
+                var 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 = self.$el.find('#current-attribute').val();
+            if(attribute != 9999999){
+                /*=============================
+                    ATTRIBUTE VALUE SELECTION
+                =============================*/
+                var 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[0]){
+                        self.$el.find('#current-attribute-value').append('<option value="' + item.id + '">' + item.name + '</option>');
+                    }
+                });
+            }else{
+                /*=============================
+                    ATTRIBUTE VALUE SELECTION
+                =============================*/
+                var 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>');
+                });
+            }
+        },
+
+
+
+
+        /*====================================================================
+            GET RES COMPANY
+        ====================================================================*/
+        getResCompany: function (id) {
+            var self = this;
+            return _.filter(self.ResCompany,function (item) {
+                return item.id == id;
+            })
+        },
+
+        /*====================================================================
+            GET RES CURRENCY BASE
+        ====================================================================*/
+        getResCurrency: function (id) {
+            var self = this;
+            return _.filter(self.ResCurrency,function (item) {
+                return item.id === id;
+            })
+        },
+
+        getPricelistVersion: function(id){
+          var self = this;
+          return _.filter(self.PricelistVersion,function (item) {
+              return item.id === id;
+          })
+        },
+
+        getPricelistVersionItem: function(id){
+          var self = this;
+          var item= _.filter(self.PricelistVersionItem,function (item) {
+              return item.id === id;
+
+          })
+            return item[0];
+        },
+
+        getProductSalePrice: function(product){
+          var self = this;
+          var r;
+          var CurrencyBase;
+          var today = moment().format('YYYY-MM-DD');
+          var salePrice = self.$el.find('#current-sale-price').val();
+          var company = self.$el.find('#current-company').val();
+
+          if(company && company != 9999999){
+              var ResCompany = self.getResCompany(company).shift();
+              CurrencyBase = self.getResCurrency(ResCompany.currency_id[0]).shift();
+          }else{
+              CurrencyBase = self.getResCurrency(self.ResCompany[0].currency_id[0]).shift();
+          }
+
+          if(salePrice && salePrice != 9999999){
+            var priceList= _.filter(self.ProductPriceList,function (item) {
+              return item.id == salePrice;
+            });
+
+            var x = _.map(priceList, function(map){
+              if(map.version_id.length > 0){
+                _.each(map.version_id, function(v){
+                  var version = self.getPricelistVersion(v);
+                  var date_start = version.date_start;
+                  var date_end = version.date_end;
+                  r= _.filter(version, function(a){
+                    return ((a.date_start == false) || (a.date_start <= today)) && ((a.date_end == false) || (a.date_end >= today));
+                  });
+                });
+
+                var item=  _.map(r[0].items_id,function(i){
+                  return self.getPricelistVersionItem(i);
+                });
+
+                var items =[];
+                var items2 = [];
+                _.each(item, function(index){
+                  if(index.product_tmpl_id && index.product_tmpl_id[0] == product.product_tmpl_id){
+                    items.push(index);
+                  }
+                  if(index.sequence > 1) {
+                    items2.push(index);
+                  }
+                });
+
+                if(items.length > 0){
+                  return items[0];
+                }
+                else{
+                  if(items2.length > 0){
+                    items2.sort(function(a, b) {
+                      return a.sequence - b.sequence
+                    });
+                    return items2[0];
+                  }
+                }
+              }
+            });
+            if(CurrencyBase.id == priceList[0].currency_id.id){
+              return product.lst_price*(1+x[0].price_discount)+x[0].price_surcharge;
+            }
+            else {
+              return (product.lst_price*priceList[0].currency_id.rate_silent)*(1+x[0].price_discount)+x[0].price_surcharge;
+            }
+          }
+          else{
+            return product.lst_price;
+          }
+        },
+
+        getProductBuyPrice: function(product){
+          var self = this;
+          var r;
+          var CurrencyBase;
+          var today = moment().format('YYYY-MM-DD');
+          var company = self.$el.find('#current-company').val();
+          var purchasePrice = self.$el.find('#current-purchase-price').val();
+
+          if(company && company != 9999999){
+              var ResCompany = self.getResCompany(company).shift();
+              CurrencyBase = self.getResCurrency(ResCompany.currency_id[0]).shift();
+          }else{
+              CurrencyBase = self.getResCurrency(self.ResCompany[0].currency_id[0]).shift();
+          }
+
+          if(purchasePrice && purchasePrice != 9999999){
+            var priceList = _.filter(self.ProductPriceList,function (item) {
+              return item.id == purchasePrice;
+            });
+
+            var x = _.map(priceList, function(map){
+              if(map.version_id.length > 0){
+                _.each(map.version_id, function(v){
+                  var version = self.getPricelistVersion(v);
+                  var date_start = version.date_start;
+                  var date_end = version.date_end;
+                  r= _.filter(version, function(a){
+                    return ((a.date_start == false) || (a.date_start <= today)) && ((a.date_end == false) || (a.date_end >= today));
+                  });
+                });
+
+                var item=  _.map(r[0].items_id,function(i){
+                  return self.getPricelistVersionItem(i);
+                });
+                var items =[];
+                var items2 = [];
+                _.each(item, function(index){
+                  if(index.product_tmpl_id && index.product_tmpl_id[0] == product.product_tmpl_id){
+                    items.push(index);
+                  }
+                  if(index.sequence > 1) {
+                    items2.push(index);
+                  }
+                });
+
+                if(items.length > 0){
+                  return items[0];
+                }
+                else{
+                  if(items2.length > 0){
+                    items2.sort(function(a, b) {
+                      return a.sequence - b.sequence
+                    });
+                    return items2[0];
+                  }
+                }
+              }
+            });
+
+            if(CurrencyBase.id == priceList[0].currency_id.id){
+              return product.standard_price*(1+x[0].price_discount)+x[0].price_surcharge;
+            }
+            else {
+              return (product.standard_price*priceList[0].currency_id.rate_silent)*(1+x[0].price_discount)+x[0].price_surcharge;
+            }
+          }
+          else{
+            return product.standard_price;
+          }
+        },
+
+
+        /*====================================================================
+            BUILD
+        ====================================================================*/
+        BuildTable: function(){
+            var self = this;
+            var data = [];
+            var company = $('#current-company').val();
+            var purchasePrice = self.$el.find('#current-purchase-price').val();
+            var salePrice = self.$el.find('#current-sale-price').val();
+
+            if(company && company != 9999999){
+                var ResCompany = self.getResCompany(company).shift();
+                var CurrencyBase = self.getResCurrency(ResCompany.currency_id[0]).shift();
+            }else{
+                var CurrencyBase = self.getResCurrency(self.ResCompany[0].currency_id[0]).shift();
+            }
+
+            if(purchasePrice && purchasePrice != 9999999){
+                var priceList =  _.filter(self.ProductPriceList,function (item) {
+                    return item.id == purchasePrice;
+                });
+                var CurrencyBasePurchase = self.getResCurrency(priceList[0].currency_id.id).shift();
+            }else{
+                var CurrencyBasePurchase = CurrencyBase;
+            }
+            if(salePrice && salePrice != 9999999){
+                var priceList = _.filter(self.ProductPriceList,function (item) {
+                  return item.id == salePrice;
+                });
+                var CurrencyBaseSale = self.getResCurrency(priceList[0].currency_id.id).shift();
+            }else{
+                var CurrencyBaseSale = CurrencyBase;
+            }
+
+            var ProductProduct = self.ProductProduct;
+            _.each(ProductProduct, function(item){
+              var salePrice = self.getProductSalePrice(item);
+              var purchasePrice = self.getProductBuyPrice(item);
+
+                if(item.image_medium){
+                  var src='data:image/png;base64,'+ item.image_medium;
+                }
+                else{
+                  var src="/web/static/src/img/placeholder.png";
+              }
+
+              var brand = _.map(_.filter(self.ProductBrand,function (a) {
+                  return a.id == item.product_brand_id;
+              }), function(map){
+                  return map.name;
+              });
+
+                data.push({
+                    id : item.id,
+                    image_medium : src,
+                    name : item.display_name,
+                    brand: brand,
+                    default_code : self.valorNull(item.default_code),
+                    categ_id : item.categ_id.complete_name,
+                    standard_price : accounting.formatMoney(purchasePrice, '', CurrencyBasePurchase.decimal_places, CurrencyBasePurchase.thousands_separator, CurrencyBasePurchase.decimal_separator),
+                    lst_price : accounting.formatMoney(salePrice, '', CurrencyBaseSale.decimal_places, CurrencyBaseSale.thousands_separator, CurrencyBaseSale.decimal_separator),
+                    qty_available : accounting.formatNumber(item.qty_available,'',CurrencyBase.thousands_separator,CurrencyBase.decimal_separator),
+
+                    standard_price_no_format: purchasePrice,
+                    lst_price_no_formart: salePrice,
+                    qty_no_formart: item.qty_available,
+
+                    /*==============================
+                        TOTAL FOOTER CONFIGURATION
+                    ==============================*/
+                    decimal_places : CurrencyBase.decimal_places,
+                    thousands_separator: CurrencyBase.thousands_separator,
+                    decimal_separator: CurrencyBase.decimal_separator,
+
+                    decimal_places_sale : CurrencyBaseSale.decimal_places,
+                    thousands_separator_sale: CurrencyBaseSale.thousands_separator,
+                    decimal_separator_sale: CurrencyBaseSale.decimal_separator,
+                    symbol_sale: CurrencyBaseSale.symbol,
+
+                    decimal_places_purchase : CurrencyBasePurchase.decimal_places,
+                    thousands_separator_purchase: CurrencyBasePurchase.thousands_separator,
+                    decimal_separator_purchase: CurrencyBasePurchase.decimal_separator,
+                    symbol_purchase: CurrencyBasePurchase.symbol,
+                });
+            });
+
+            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();
+        },
+
+        /*====================================================================
+            LOAD BOOTSTRAP TABLE
+        ====================================================================*/
+        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 action = this.$el.find(e.target).val();
+            var company = $('#current-company').val();
+
+            if(company && company != 9999999){
+                ResCompany = self.getResCompany(company).shift();
+                var CurrencyBase = self.getResCurrency(ResCompany.currency_id[0]).shift();
+            }else{
+                ResCompany = self.ResCompany[0];
+                var CurrencyBase = self.getResCurrency(self.ResCompany[0].currency_id[0]).shift();
+            }
+
+            var getColumns=[];
+            var rows=[];
+            var table = this.$el.find("#table");
+            var column = table.bootstrapTable('getVisibleColumns');
+            var row = table.bootstrapTable('getData');
+
+            if (action === 'pdf') {
+              var data = _.map(column, function (val){ return val.field});
+              _.each(_.map(column,function(val){
+                  return val
+              }), function(item){
+                  if(item.field != 'image_medium'){
+                      getColumns.push([{
+                          title: item.title,
+                          dataKey: item.field
+                      }]);
+                  }
+              });
+
+              var standard_price = purchaseTotalFormatter(row);
+              var lst_price = saleTotalFormatter(row);
+              var qty_available = qtyTotalFormatter(row);
+
+              row.push({
+                  default_code : 'Totales',
+                  standard_price : standard_price,
+                  lst_price: lst_price,
+                  qty_available: qty_available,
+              });
+
+                var pdf_title = 'Lista de Productos.';
+                var pdf_type = 'l';
+                var pdf_name = 'lista_de_productos_';
+
+                var pdf_columnStyles = {
+                  name :{halign:'left'},
+                  brand :{columnWidth: 25, halign:'center'},
+                  default_code :{columnWidth: 25,halign:'left'},
+                  categ_id :{halign:'left'},
+                  standard_price :{columnWidth: 25, halign:'right'},
+                  lst_price :{columnWidth: 25, halign:'right'},
+                  qty_available :{columnWidth: 20, halign:'center'},
+                }
+
+                var filter = self.getFilter();
+                var pdf = new reporting.ReportPdfWidget(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 type = self.$el.find('#current-type').val();
+          var salePrice = self.$el.find('#current-sale-price').val();
+          var purchasePrice = self.$el.find('#current-purchase-price').val();
+          var brand = self.$el.find('#current-brand').val();
+          var category = self.$el.find('#current-category').val();
+          var attribute = self.$el.find('#current-attribute').val();
+          var attribute_value = self.$el.find('#current-attribute-value').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(type && type != 9999999){
+            filter.push({
+                 title: 'Tipo',
+                 value:  $("#current-type option:selected").text(),
+               });
+          }
+
+          if(salePrice && salePrice != 9999999){
+            var sale =  _.filter(self.ProductPriceList,function (item) {
+                return item.id == salePrice;
+            });
+            filter.push({
+                 title: 'Precio de Venta',
+                 value: sale[0].name,
+               });
+          }
+
+          if(purchasePrice && purchasePrice != 9999999){
+            var purchase =  _.filter(self.ProductPriceList,function (item) {
+                return item.id == purchasePrice;
+            });
+            filter.push({
+                 title: 'Precio de Compra',
+                 value: purchase[0].name,
+               });
+          }
+
+          if(brand && brand != 9999999){
+            var brand =  _.filter(self.ProductBrand,function (item) {
+                return item.id == brand;
+            });
+            filter.push({
+                 title: 'Marca',
+                 value: brand[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(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,
+               });
+          }
+          return filter;
+        }
+    });
+}

+ 759 - 0
static/src/js/reports/report_sale.js

@@ -0,0 +1,759 @@
+function report_sale(reporting){
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportSaleWidget = reporting.Base.extend({
+        template: 'ReportSale',
+        rowsData :[],
+        content :[],
+        modules: ['point_of_sale'],
+
+        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();
+        },
+
+        checkModel : 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');
+                }
+                /*
+                =================================
+                    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 Vendedores</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');
+                }
+                return self.fethIrModuleModule();
+            }).then(function(IrModuleModule) {
+                self.IrModuleModule = IrModuleModule;
+                return self.fethCheckType();
+            });
+            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-sale-history');
+            return data;
+        },
+
+        fethIrModuleModule: 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;
+        },
+
+        /*=====================================================================
+            Check type
+        =====================================================================*/
+        fethCheckType: function(){
+            var self = this;
+            var modules = self.checkModel('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[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 Vendedores</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 == 'sale'){
+                        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>');
+                });
+            }
+        },
+
+        getPosOrder:function() {
+            var self = this;
+            var content = self.PosOrder;
+            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 type = self.$el.find('#current-type').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();
+
+            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){
+                if(state == 'open'){
+                    content = [];
+                }
+            }
+            if(type && type != 9999999){
+                if(type == 'sale'){
+                    content = [];
+                }
+            }
+            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) {
+                            var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                            utc = moment(utc._d).format('YYYY-MM-DD');
+                            return moment(utc).format('YYYY-MM-DD') >= date;
+                        }));
+                    }
+                    if(hasta){
+                        date = hasta.split('/');
+                        date = (date[2]+"-"+date[1]+"-"+date[0]);
+                        content = _.flatten(_.filter(content,function (inv) {
+                            var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                            utc = moment(utc._d).format('YYYY-MM-DD');
+                            return moment(utc).format('YYYY-MM-DD') <= date;
+                        }));
+                    }
+                }
+                if(date == 'today'){
+                    var today = moment().format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM-DD') === today;
+                    }));
+                }
+                if(date == 'yesterday'){
+                    var yesterday = moment().add(-1,'days').format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM-DD') === yesterday;
+                    }));
+                }
+                if(date == 'currentMonth'){
+                    var currentMonth = moment().format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM') === currentMonth;
+                    }));
+                }
+                if(date == 'lastMonth'){
+                    var lastMonth = moment().add(-1,'months').format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM') === lastMonth;
+                    }));
+                }
+            }
+            return content;
+        },
+
+        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 type = self.$el.find('#current-type').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();
+
+            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(type && type != 9999999){
+                if(type == 'tpv'){
+                    content = [];
+                }
+            }
+            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;
+            console.log(self);
+            var data = [];
+            var residual = 0;
+            var CurrencyBase = self.ResCompany[0].currency_id;
+            /*
+            ==========================================
+                POS ORDER
+            ==========================================
+            */
+            var PosOrder = self.getPosOrder();
+            _.each(PosOrder, function(item){
+                var utc = moment.utc(item.date,'YYYY-MM-DD h:mm:ss A');
+                data.push({
+                    id:item.id,
+                    origin:'',
+                    number:item.name,
+                    date:moment(utc._d).format('DD/MM/YYYY'),
+                    user_name:item.user_name,
+                    user_id:item.user_id,
+                    customer_name:self.valorNull(item.customer_name),
+                    residual:0,
+                    untaxed:accounting.formatMoney(item.amount_untaxed,'',CurrencyBase.decimal_places,CurrencyBase.thousands_separator,CurrencyBase.decimal_separator),
+                    tax:accounting.formatMoney(item.amount - item.amount_untaxed,'',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(utc._d).format('YYYY-MM-DD'),
+                    residual_no_format: 0,
+                    untaxed_no_format:item.amount_untaxed,
+                    tax_no_format:item.amount - item.amount_untaxed,
+                    total_no_format:item.amount,
+                    /*
+                    ===========================
+                        FOOTER
+                    ===========================
+                    */
+                    decimal_places:CurrencyBase.decimal_places,
+                    thousands_separator:CurrencyBase.thousands_separator,
+                    decimal_separator:CurrencyBase.decimal_separator,
+                });
+            });
+            /*
+            ==========================================
+                ACCOUNT INVOICE
+            ==========================================
+            */
+            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 Venta.';
+                var pdf_type = '';
+                var pdf_name = 'facturas_de_venta_';
+                var pdf_columnStyles = {
+                    number:{columnWidth: 25,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.ReportPdfWidget(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 type = self.$el.find('#current-type').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(type && type != 9999999){
+                filter.push({
+                    title: 'Tipo de Venta',
+                    value: $('#current-type option:selected').text(),
+                });
+            }
+            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;
+        },
+    });
+}

+ 910 - 0
static/src/js/reports/report_sale_analytic.js

@@ -0,0 +1,910 @@
+function report_sale_analytic(reporting){
+    "use strict";
+
+    var model = openerp;
+
+    reporting.ReportSaleAnalyticWidget = reporting.Base.extend({
+        template: 'ReportSaleAnalytic',
+        rowsData :[],
+        content :[],
+        modules: ['product_brand','point_of_sale'],
+
+        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>');
+                    });
+                }
+                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-sale-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;
+        },
+
+        getPosOrderLine:function() {
+            var self = this;
+            var content = self.PosOrderLine;
+            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();
+
+            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 == 'sale'){
+                    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) {
+                            var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                            utc = moment(utc._d).format('YYYY-MM-DD');
+                            return moment(utc).format('YYYY-MM-DD') >= date;
+                        }));
+                    }
+                    if(hasta){
+                        date = hasta.split('/');
+                        date = (date[2]+"-"+date[1]+"-"+date[0]);
+                        content = _.flatten(_.filter(content,function (inv) {
+                            var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                            utc = moment(utc._d).format('YYYY-MM-DD');
+                            return moment(utc).format('YYYY-MM-DD') <= date;
+                        }));
+                    }
+                }
+                if(date == 'today'){
+                    var today = moment().format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM-DD') === today;
+                    }));
+                }
+                if(date == 'yesterday'){
+                    var yesterday = moment().add(-1,'days').format('YYYY-MM-DD');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM-DD') === yesterday;
+                    }));
+                }
+                if(date == 'currentMonth'){
+                    var currentMonth = moment().format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).format('YYYY-MM') === currentMonth;
+                    }));
+                }
+                if(date == 'lastMonth'){
+                    var lastMonth = moment().add(-1,'months').format('YYYY-MM');
+                    content = _.flatten(_.filter(content,function (inv) {
+                        var utc = moment.utc(inv.date,'YYYY-MM-DD h:mm:ss A');
+                        utc = moment(utc._d).format('YYYY-MM-DD');
+                        return moment(utc).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;
+        },
+
+        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();
+
+            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;
+            console.log(self);
+            var data = [];
+            var CurrencyBase = self.ResCompany[0].currency_id;
+            var PosOrderLine = self.getPosOrderLine();
+            var display_name;
+            var discount_amount;
+            var modules = self.checkModule('product_brand');
+            _.each(PosOrderLine,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.order_line_id,
+                    number:item.name,
+                    date:moment(item.date).format('DD/MM/YYYY'),
+                    customer_name:self.valorNull(item.customer_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,
+                });
+            });
+            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 Venta.';
+                var pdf_type = 'l';
+                var pdf_name = 'analisis_de_venta_';
+                var pdf_columnStyles = {
+                    number:{columnWidth: 25, 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.ReportPdfWidget(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 type = self.$el.find('#current-type').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(type && type != 9999999){
+                filter.push({
+                    title: 'Tipo de Venta',
+                    value: $('#current-type option:selected').text(),
+                });
+            }
+            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;
+        },
+    });
+}

+ 91 - 0
static/src/reports/report_customer.xml

@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="ReportCustomer">
+        <div class="report_view">
+            <div class="container search-form">
+                <div class="page-header">
+                    <h1><small>Clientes</small></h1>
+                </div>
+                <div class="row">
+                    <div class="col-lg-3 company filter-style">
+                        <label>Empresa</label>
+                        <select id="current-company" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 store filter-style">
+                        <label>Sucursal</label>
+                        <select id="current-store" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 filter-style">
+                        <label>Tipo</label>
+                        <select id="current-type" class="form-control form-control-sm">
+                            <option value="9999999">Todos los tipos</option>
+                            <option value="company">Empresa</option>
+                            <option value="people">Persona</option>
+                        </select>
+                    </div>
+                </div>
+                <div class="row">
+                    <div class="text-center" style="padding-top:20px;">
+                        <button id="generate" class="myButton" aria-label="Left Align" style="color:#fff;display:none;">
+                            Generar
+                        </button>
+                    </div>
+                    <br/>
+                </div>
+            </div>
+
+            <div class="report-form" style="display:none;">
+                <div id="toolbar">
+                    <button class="oe_button myButton" 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-classes="table table-condensed"
+                        data-search="true"
+                        data-show-export="true"
+                        data-show-toggle="true"
+                        data-show-columns="true"
+                        data-show-pagination-switch="true"
+                        data-pagination-v-align="top"
+                        data-buttons-class="oe_button myButton"
+                        data-search-on-enter-key="true"
+                        data-undefined-text=" "
+                        >
+                        <thead style="background:none;">
+                            <tr>
+                                <th data-field="ruc"
+                                    data-align="left"
+                                    >RUC</th>
+                                <th data-field="name"
+                                    data-align="left"
+                                    >Nombre y Apellido</th>
+                                <th data-field="street"
+                                    data-align="left"
+                                    >Dirección</th>
+                                <th data-field="state"
+                                    data-align="left"
+                                    >Depart./Ciudad</th>
+                                <th data-field="country"
+                                    data-align="left"
+                                    >Pais</th>
+                                <th data-field="phone"
+                                    data-align="left"
+                                    >Teléfono</th>
+                                <th data-field="mobile"
+                                    data-align="left"
+                                    >Celular</th>
+                                <th data-field="email"
+                                    data-align="left"
+                                    >Email</th>
+                            </tr>
+                        </thead>
+                    </table>
+                </div>
+            </div>
+            <br/>
+        </div>
+    </t>
+</template>

+ 178 - 0
static/src/reports/report_customer_ranking.xml

@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="ReportCustomerRanking">
+        <div class="report_view">
+            <div class="container search-form">
+                <div class="page-header">
+                    <h1><small>Ranking de Clientes</small></h1>
+                </div>
+                <div class="row">
+                    <div class="col-lg-3 company filter-style">
+                        <label>Empresa</label>
+                        <select id="current-company" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 store filter-style">
+                        <label>Sucursal</label>
+                        <select id="current-store" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 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 category filter-style">
+                        <label>Categoría</label>
+                        <select id="current-category" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 brand filter-style">
+                        <label>Marca</label>
+                        <select id="current-brand" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 attribute filter-style">
+                        <label>Atributo</label>
+                        <select id="current-attribute" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 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 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 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 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="oe_button oe_form_button 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 class="table" id="table"
+                        data-pagination="true"
+                        data-toggle="table"
+                        data-toolbar="#toolbar"
+                        data-show-columns="true"
+                        data-classes="table table-condensed"
+                        data-row-style="rowStyle"
+                        data-search="true"
+                        data-show-export="true"
+                        data-show-toggle="true"
+                        data-show-footer="true"
+                        data-footer-style="footerStyle"
+                        data-buttons-class="oe_button oe_form_button myButton"
+                        data-show-pagination-switch="true"
+                        data-page-size="10"
+                        data-search-on-enter-key="true"
+                        data-undefined-text=" "
+                        data-pagination-v-align="top"
+                        >
+                        <thead style="background:none;">
+                            <tr>
+                                <th data-field="ruc"
+                                    data-align="left"
+                                    data-footer-formatter="Totales"
+                                    >RUC</th>
+                                <th data-field="name"
+                                    data-align="left"
+                                    >Clientes</th>
+                                <th data-field="total"
+                                    data-align="right"
+                                    data-footer-formatter="TotalFooter"
+                                    >Monto</th>
+                            </tr>
+                        </thead>
+                    </table>
+                </div>
+            </div>
+            <script>
+                <!--
+                    TOTAL CANTIDAD
+                -->
+
+                function QuantityFooter(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 amount =  _.reduce(_.map(rowsTable,function(item){
+                        return item.quantity_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(amount,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    TOTAL MONTO
+                -->
+                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 amount =  _.reduce(_.map(rowsTable,function(item){
+                        return item.total_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(amount,decimal_places,thousands_separator,decimal_separator);
+                }
+                <!--
+                    FOOTER STYLE
+                -->
+                function footerStyle(row, index) {
+                    return {
+                        css: {
+                          "font-weight": "bold"
+                        }
+                    };
+                };
+            </script>
+        </div>
+    </t>
+</template>

+ 190 - 0
static/src/reports/report_product_list.xml

@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="ReportProductList">
+      <head>
+        <script src="//cdnjs.cloudflare.com/ajax/libs/holder/2.6.0/holder.js"></script>
+      </head>
+        <div class="report_view">
+            <div class="reporting_page_header">
+                <h1 class="report_title">Lista de Productos</h1>
+            </div>
+            <div class="container search-form" style="border-bottom:1px solid #eee; width:95%;">
+                <div class="row">
+                    <div class="col-lg-3 company filter-style">
+                        <label>Empresa</label>
+                        <select id="current-company" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 store filter-style">
+                        <label>Sucursal</label>
+                        <select id="current-store" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 filter-style">
+                        <label>Estado</label>
+                        <select id="current-state" class="form-control form-control-sm">
+                            <option value="9999999">Todos los estados</option>
+                            <option value="available">Disponible</option>
+                            <option value="unavailable">No Disponible</option>
+                        </select>
+                    </div>
+                    <div class="col-lg-3 filter-style">
+                        <label>Tipo</label>
+                        <select id="current-type" class="form-control form-control-sm">
+                            <option value="9999999">Todos los tipos</option>
+                            <option value="product">Almacenable</option>
+                            <option value="service">Servicio</option>
+                        </select>
+                    </div>
+                    <div class="col-lg-3 salePrice filter-style">
+                        <label>Precio de Venta</label>
+                        <select id="current-sale-price" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 purchasePrice filter-style">
+                        <label>Precio de Costo </label>
+                        <select id="current-purchase-price" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 filter-style">
+                        <label>Categoria</label>
+                        <select id="current-category" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 brand filter-style">
+                        <label>Marca</label>
+                        <select id="current-brand" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 attribute filter-style">
+                        <label>Atributo</label>
+                        <select id="current-attribute" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 attribute-value filter-style">
+                        <label>Valor del Atributo</label>
+                        <select id="current-attribute-value" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                </div>
+                <div class="row">
+                    <div class="text-center" style="padding-top:20px;">
+                        <button id="generate" class="oe_button oe_form_button myButton">Generar</button>
+                    </div>
+                    <br/>
+                </div>
+            </div>
+
+            <div class="report-form" style="display:none;">
+                <div id="toolbar">
+                    <button class="oe_button oe_form_button myButton" 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-height="auto"
+                        data-classes="table table-hover table-condensed  table-no-bordered"
+                        data-row-style="rowStyle"
+                        data-search="true"
+                        data-show-export="true"
+                        data-show-toggle="true"
+                        data-pagination-detail-h-align="left"
+                        data-show-footer="true"
+                        data-footer-style="footerStyle"
+                        data-buttons-class="oe_button oe_form_button myButton"
+                        data-show-pagination-switch="true"
+                        data-page-size="10"
+                        data-search-on-enter-key="true"
+                        data-undefined-text=" "
+                        >
+                        <thead style="background:none;">
+                            <tr>
+                               <th data-field="image_medium" data-formatter="imageFormatter" data-footer-formatter="Totales">Imagen</th>
+                                <th data-field="default_code" data-align="left" >Referencia Interna</th>
+                                <th data-field="name" data-align="left">Producto</th>
+                                <th data-field="brand" data-align="left">Marca</th>
+                                <th data-field="categ_id" data-align="left">Categoría</th>
+                                <th data-field="standard_price" data-align="right" data-footer-formatter="purchaseTotalFormatter">Precio Costo</th>
+                                <th data-field="lst_price" data-align="right" data-footer-formatter="saleTotalFormatter">Precio Venta </th>
+                                <th data-field="qty_available" data-align="center" data-footer-formatter="qtyTotalFormatter">Cantidad Disponible</th>
+                            </tr>
+                        </thead>
+                    </table>
+                </div>
+            </div>
+            <script>
+
+              function imageFormatter(value) {
+              return '<img style="width:60px; height:60px" src="'+ value +'"></img>';
+
+              }
+                <!--
+                    TOTAL
+                -->
+                function purchaseTotalFormatter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    var symbol;
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places_purchase;
+                        thousands_separator = rowsTable[0].thousands_separator_purchase;
+                        decimal_separator = rowsTable[0].decimal_separator_purchase;
+                        symbol=rowsTable[0].symbol_purchase;
+                    }
+                    var amount =  _.reduce(_.map(rowsTable,function(item){
+                        return (item.standard_price_no_format);
+                    }), function(memo, num){
+                    return memo + num; },0)
+                    return accounting.formatMoney(amount,symbol,decimal_places,thousands_separator,decimal_separator,'%s %v');
+                }
+
+                function saleTotalFormatter(rowsTable) {
+                    var decimal_places = 0;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    var symbol;
+                    if(rowsTable.length > 0){
+                        decimal_places = rowsTable[0].decimal_places_sale;
+                        thousands_separator = rowsTable[0].thousands_separator_sale;
+                        decimal_separator = rowsTable[0].decimal_separator_sale;
+                        symbol = rowsTable[0].symbol_sale;
+                    }
+                    var amount =  _.reduce(_.map(rowsTable,function(item){
+                        return (item.lst_price_no_formart);
+                    }), function(memo, num){
+                    return memo + num; },0)
+                    return accounting.formatMoney(amount,symbol,decimal_places,thousands_separator,decimal_separator,'%s %v');
+                }
+
+                function qtyTotalFormatter(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 amount =  _.reduce(_.map(rowsTable,function(item){
+                        return (item.qty_no_formart);
+                    }), function(memo, num){
+                    return memo + num; },0)
+                    return accounting.formatNumber(amount,'',thousands_separator,decimal_separator);
+                }
+                <!--
+                    FOOTER STYLE
+                -->
+                function footerStyle(row, index) {
+                    return {
+                        css: {
+                          "font-weight": "bold"
+                        }
+                    };
+                };
+            </script>
+        </div>
+    </t>
+</template>

+ 242 - 0
static/src/reports/report_sale.xml

@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="ReportSale">
+        <div class="report_view">
+            <div class="container search-form">
+                <div class="page-header">
+                    <h1><small>Historico de Ventas</small></h1>
+                </div>
+                <div class="row">
+                    <div class="col-lg-3 company filter-style">
+                        <label>Empresa</label>
+                        <select id="current-company" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 store filter-style">
+                        <label>Sucursal</label>
+                        <select id="current-store" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 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 journal filter-style">
+                        <label>Factura</label>
+                        <select id="current-journal" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 users filter-style">
+                        <label>Vendedor</label>
+                        <select id="current-user" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 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 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 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 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" aria-label="Left Align" style="color:#fff;display:none;">
+                            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>

+ 295 - 0
static/src/reports/report_sale_analytic.xml

@@ -0,0 +1,295 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="ReportSaleAnalytic">
+        <div class="report_view">
+            <div class="container search-form">
+                <div class="page-header">
+                    <h1><small>Análisis de Ventas</small></h1>
+                </div>
+                <div class="row">
+                    <div class="col-lg-3 company filter-style">
+                        <label>Empresa</label>
+                        <select id="current-company" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 store filter-style">
+                        <label>Sucursal</label>
+                        <select id="current-store" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 journal filter-style">
+                        <label>Factura</label>
+                        <select id="current-journal" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 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 filter-style">
+                        <label>Categoria</label>
+                        <select id="current-category" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 brand filter-style">
+                        <label>Marca</label>
+                        <select id="current-brand" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 attribute filter-style">
+                        <label>Atributo</label>
+                        <select id="current-attribute" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 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 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 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 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" aria-label="Left Align" style="color:#fff;display:none;">
+                            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>

+ 190 - 0
static/src/reports/report_sale_ranking_product.xml

@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<template xml:space="preserve">
+    <t t-name="ReportSaleRankingProduct">
+        <div class="report_view">
+            <div class="reporting_page_header">
+                <h1 class="report_title">Ranking de productos (+ Vendidos)</h1>
+            </div>
+            <div class="container search-form" style="border-bottom:1px solid #eee; width:95%;">
+                <div class="row">
+                    <div class="col-lg-3 company filter-style">
+                        <label>Empresa</label>
+                        <select id="current-company" class="form-control form-control-sm"></select>
+                    </div>
+                    <div class="col-lg-3 store filter-style">
+                        <label>Sucursal</label>
+                        <select id="current-store" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 journal filter-style">
+                        <label>Factura</label>
+                        <select id="current-journal" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 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 filter-style">
+                        <label>Categoria</label>
+                        <select id="current-category" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 brand filter-style">
+                        <label>Marca</label>
+                        <select id="current-brand" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 attribute filter-style">
+                        <label>Atributo</label>
+                        <select id="current-attribute" class="form-control form-control-sm">
+                        </select>
+                    </div>
+                    <div class="col-lg-3 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 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 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 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" aria-label="Left Align" style="color:#fff;display:none;">
+                          Generar
+                      </button>
+                    </div>
+                    <br/>
+                </div>
+            </div>
+
+            <div class="report-form" style="display:none;">
+                <div class="chart-container center-block" style="padding-top:20px;height:300px;border-bottom:1px solid #eee; width:95%;">
+                    <canvas class="reporting-chart"></canvas>
+                </div>
+                <div class="chart-container center-block" style="padding-top:20px; height:300px;border-bottom:1px solid #eee; width:95%;">
+                    <canvas class="reporting-pie-chart"></canvas>
+                </div>
+                <div class="chart-container center-block doughnut-chart" style="padding-top:20px; height:300px; padding-bottom:20px;border-bottom:1px solid #eee; width:95%;display:none;">
+                    <canvas class="reporting-doughnut-chart"></canvas>
+                </div>
+                <div id="toolbar">
+                    <button class="oe_button myButton build-chart">Graficar</button>
+                    <button class="oe_button 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-pagination-detail-h-align="left"
+                        data-show-footer="true"
+                        data-footer-style="footerStyle"
+                        data-buttons-class="oe_button myButton"
+                        data-show-pagination-switch="true"
+                        data-page-size="10"
+                        data-search-on-enter-key="true"
+                        data-undefined-text=" "
+                        data-pagination-v-align="top"
+                        >
+                        <thead style="background:none;">
+                            <tr>
+                                <th data-field="name"
+                                    data-align="left"
+                                    data-footer-formatter="Totales"
+                                    >Producto</th>
+                                <th data-field="quantity"
+                                    data-align="right"
+                                    data-footer-formatter="QuantityFooter"
+                                    >Cantidad</th>
+                                <th data-field="amount"
+                                    data-align="right"
+                                    data-footer-formatter="TotalFooter"
+                                    >Monto</th>
+                            </tr>
+                        </thead>
+                    </table>
+                </div>
+            </div>
+            <script>
+                <!--
+                    CANTIDAD
+                -->
+                function QuantityFooter(rowsTable) {
+                    var decimal_places = 2;
+                    var thousands_separator = '.';
+                    var decimal_separator = ',';
+                    var amount =  _.reduce(_.map(rowsTable,function(item){
+                        return item.quantity_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(amount,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 quantity =  _.reduce(_.map(rowsTable,function(item){
+                        return item.amount_no_format;
+                    }), function(memo, num){
+                        return memo + num;
+                    },0);
+                    return accounting.formatNumber(quantity,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>

+ 36 - 0
static/src/xml/eiru_reporting_welcome.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<template xml:space="preserve">
+    <t t-name="EiruReportingWelcome">
+        <div class="container" style="height:100%;width:100%;">
+            <div class="row">
+                <div class="col-md-12">
+                    <div class="page-header">
+                        <div align="left">
+                            <h1>AREA DE REPORTES</h1>
+                        </div>
+                    </div>
+                    <div class="row" align="center">
+                        <div class="btn-group" role="group">
+                            <a type="button" class="btn btn-default sale-button">
+                                Ventas
+                            </a>
+                            <a type="button" class="btn btn-default purchase-button">
+                                Compras
+                            </a>
+                            <a type="button" class="btn btn-default expense-button">
+                                Gastos
+                            </a>
+                            <a type="button" class="btn btn-default balance-button">
+                                Balance
+                            </a>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="chart-container center-block" style="padding-top:40px; height:400px;width:90%;">
+                <canvas class="reporting-chart"></canvas>
+            </div>
+        </div>
+    </t>
+</template>

+ 60 - 0
templates.xml

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+        <template id="eiru_reports_sales_assets" inherit_id="eiru_assets.assets">
+            <xpath expr="." position="inside">
+                <!-- Report style -->
+                <link rel="stylesheet" href="/eiru_reports_sales/static/src/css/custom.css"/>
+
+                <!-- configuration < main > -->
+                <script type="text/javascript" src="/eiru_reports_sales/static/src/js/main.js" />
+                <script type="text/javascript" src="/eiru_reports_sales/static/src/js/reporting_base.js" />
+                <script type="text/javascript" src="/eiru_reports_sales/static/src/js/configuration_reporting.js" />
+                <script type="text/javascript" src="/eiru_reports_sales/static/src/js/pdf.js" />
+                <script type="text/javascript" src="/eiru_reports_sales/static/src/js/chart.js" />
+                <script type="text/javascript" src="/eiru_reports_sales/static/src/js/datepicker.js" />
+
+                <!--
+                ======================================================================
+                    VENTAS
+                ======================================================================
+                -->
+
+                    <!--=============================
+                        Historico de ventas
+                    ==============================-->
+                    <script type="text/javascript" src="/eiru_reports_sales/static/src/js/reports/report_sale.js"/>
+
+                    <!--=============================
+                        Analisis de ventas
+                    ==============================-->
+                    <script type="text/javascript" src="/eiru_reports_sales/static/src/js/reports/report_sale_analytic.js"/>
+
+                    <!--=============================
+                        Clientes
+                    ==============================-->
+                    <script type="text/javascript" src="/eiru_reports_sales/static/src/js/reports/report_customer.js"/>
+
+                    <!--=============================
+                        Ranking de Clientes
+                    ==============================-->
+                    <script type="text/javascript" src="/eiru_reports_sales/static/src/js/reports/report_customer_ranking.js"/>
+
+                    <!--=============================
+                        Ranking de productos mas vendidos
+                    ==============================-->
+                    <!-- <script type="text/javascript" src="/eiru_reports_sales/static/src/js/reports/report_sale_ranking_product.js"/> -->
+
+                    <!--=============================
+                        Lista de productos
+                      ==============================-->
+                    <script type="text/javascript" src="/eiru_reports_sales/static/src/js/reports/report_product_list.js"/>
+            </xpath>
+        </template>
+
+        <record id="eiru_reports_sales_action" model="ir.actions.client">
+            <field name="name">Eiru Reports</field>
+            <field name="tag">eiru_reports_sales.action_report</field>
+        </record>
+    </data>
+</openerp>

+ 59 - 0
views/actions.xml

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+	<data>
+        <!--
+		==========================
+            HISTORICO DE VENTAS
+        ==========================
+		-->
+        <record id="sale_action" model="ir.actions.client">
+            <field name="name">Historico de Ventas</field>
+            <field name="tag">eiru_reports_sales.sale_action</field>
+        </record>
+        <!--
+		==========================
+            ANALISIS DE VENTAS
+        ==========================
+		-->
+        <record id="sale_analytic_action" model="ir.actions.client">
+            <field name="name">Análisis de Ventas</field>
+            <field name="tag">eiru_reports_sales.sale_analytic_action</field>
+        </record>
+        <!--
+		==========================
+            CLIENTES
+        ==========================
+		-->
+        <record id="customer_action" model="ir.actions.client">
+            <field name="name">Clientes</field>
+            <field name="tag">eiru_reports_sales.customer_action</field>
+        </record>
+		<!--
+		==========================
+			RANKING DE CLIENTES
+		==========================
+		-->
+		<record id="customer_ranking_action" model="ir.actions.client">
+				<field name="name">Ranking de Clientes</field>
+				<field name="tag">eiru_reports_sales.customer_ranking_action</field>
+		</record>
+		<!--
+		==========================
+            RANKING DE PRODUCTOS
+        ==========================
+		-->
+        <record id="sale_ranking_product_action" model="ir.actions.client">
+            <field name="name">Ranking de productos (+Vendidos)</field>
+            <field name="tag">eiru_reports_sales.sale_ranking_product_action</field>
+        </record>
+		<!--
+		==========================
+			LISTA DE PRODUCTOS
+		==========================
+		-->
+		<record id="product_list_action" model="ir.actions.client">
+				<field name="name">Lista de Productos</field>
+				<field name="tag">eiru_reports_sales.product_list_action</field>
+		</record>
+    </data>
+</openerp>

+ 96 - 0
views/menus.xml

@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<openerp>
+    <data>
+        <!--
+        ===========================
+            MENU PRINCIPAL
+        ===========================
+         -->
+        <menuitem
+            name="Informes"
+            id="eiru_reports_main_menu"
+            sequence="175"/>
+
+        <!--
+        ===========================
+            VENTAS
+        ===========================
+        -->
+            <menuitem
+                name="Ventas"
+                id="sale_parent_menu"
+                parent="eiru_reports_main_menu"
+                sequence="3"/>
+
+            <!--
+            ===========================
+               HISTORICO DE VENTAS
+            ===========================
+            -->
+            <menuitem
+                name="Historico de Ventas"
+                id="sale_history_menu"
+                parent="sale_parent_menu"
+                action="sale_action"
+                sequence="1"/>
+
+            <!--
+            ===========================
+               ANALISIS DE VENTAS
+            ===========================
+            -->
+            <menuitem
+                name="Análisis de Ventas"
+                id="sale_analytic_menu"
+                parent="sale_parent_menu"
+                action="sale_analytic_action"
+                sequence="2"/>
+
+            <!--
+            ===========================
+               CLIENTES
+            ===========================
+            -->
+            <menuitem
+                name="Clientes"
+                id="customer_menu"
+                parent="sale_parent_menu"
+                action="customer_action"
+                sequence="3"/>
+
+            <!--
+            ===========================
+                RANKING DE CLIENTES
+            ===========================
+            -->
+            <menuitem
+                name="Ranking de Clientes"
+                id="customer_ranking_menu"
+                parent="sale_parent_menu"
+                action="customer_ranking_action"
+                sequence="4"/>
+
+            <!--
+            ===========================
+                RANKING DE PRODUCTOS
+            ===========================
+            -->
+            <menuitem
+                name="Ranking de Productos"
+                id="sale_ranking_product_menu"
+                parent="sale_parent_menu"
+                action="sale_ranking_product_action"
+                sequence="5"/>
+            <!--
+            ===========================
+                LISTA DE PRECIOS
+            ===========================
+            -->
+            <menuitem
+                name="Lista de Productos"
+                id="product_list_menu"
+                parent="sale_parent_menu"
+                action="product_list_action"
+                sequence="6"/>
+    </data>
+</openerp>