Pārlūkot izejas kodu

[IMP] pos structure

Gogs 6 gadi atpakaļ
vecāks
revīzija
268a139e56

+ 124 - 145
controllers/main.py

@@ -9,11 +9,15 @@ from dateutil.relativedelta import relativedelta as rd
 from dateutil.parser import parse
 from pytz import timezone
 from gzip import GzipFile
-from StringIO import StringIO as IO
 import simplejson as json
 import gzip
 import logging
 
+try:
+    from cStringIO import StringIO as IO
+except ImportError:
+    from StringIO import StringIO as IO
+
 LOGGER = logging.getLogger(__name__)
 DATE_FORMAT = '%Y-%m-%d'
 DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
@@ -48,11 +52,12 @@ class PosSales(http.Controller):
     '''
         Check if module is installed
     '''
-    def check_module(self, module_name):
-        module = request.env['ir.module.module'].search([('name', '=', module_name), ('state', '=', 'installed')])
+    def is_module_installed(self, module_name):
+        domain = [('name', '=', module_name), ('state', '=', 'installed')]
+        module = request.env['ir.module.module'].search(domain)
 
         return len(module) != 0
-        
+    
     '''
         Get current user information
     '''
@@ -61,87 +66,51 @@ class PosSales(http.Controller):
 
         return {
             'id': user.id,
-            'name': user.name,
-            'displayName': user.display_name,
-            'currency': {
-                'id': user.company_id.currency_id.id,
-                'name': user.company_id.currency_id.name,
-                'displayName': user.company_id.currency_id.display_name,
-                'symbol': user.company_id.currency_id.symbol
-            },
+            'name': user.display_name,
             'company': {
                 'id': user.company_id.id,
-                'name': user.company_id.name,
-                'displayName': user.company_id.display_name,
+                'name': user.company_id.display_name,
                 'phone': user.company_id.phone or None,
-                'city': user.company_id.city or None,
-                'website': user.company_id.website,
-                'state': {
-                    'id': user.company_id.state_id.id,
-                    'name': user.company_id.state_id.name,
-                    'displayName': user.company_id.state_id.display_name
-                }
+                'city': user.company_id.city or None
             }
         }
 
     '''
-        Get currencies
+        Get currencies from configured journals
     '''
-    def get_currencies(self):
-        return [{
-            'id': currency.id,
-            'name': currency.name,
-            'displayName': currency.display_name,
-            'base': currency.base,
-            'accuracy': currency.accuracy,
-            'rateSilent': currency.rate_silent,
-            'rounding': currency.rounding,
-            'symbol': currency.symbol,
-            'position': currency.position,
-            'decimalSeparator': currency.decimal_separator,
-            'decimalPlaces': currency.decimal_places,
-            'thousandsSeparator': currency.thousands_separator
-        } for currency in request.env['res.currency'].search([('active', '=', True)])]
+    def get_currencies_from_journals(self):
+        domain = [('type', 'in', ['bank', 'cash']), ('active', '=', True)]
+        currencies = []
+
+        for journal in request.env['account.journal'].search(domain):
+            currency = journal.currency or journal.company_id.currency_id
+
+            currencies.append({
+                'id': currency.id,
+                'name': currency.display_name,
+                'base': currency.base,
+                'symbol': currency.symbol,
+                'position': currency.position,
+                'decimalSeparator': currency.decimal_separator,
+                'decimalPlaces': currency.decimal_places,
+                'thousandsSeparator': currency.thousands_separator
+            })
+            
+        return {c['id']:c for c in currencies}.values()
 
     '''
         Get all active journals
     '''
     def get_journals(self):
+        domain = [('type', 'in', ['bank', 'cash']), ('active', '=', True)]
+
         return [{
             'id': journal.id,
-            'name': journal.name,
-            'displayName': journal.display_name,
+            'name': journal.display_name,
             'code': journal.code,
-            'cashControl': journal.cash_control,
             'type': journal.type,
-            'currency': {
-                'id': journal.currency.id,
-                'name': journal.currency.name,
-                'displayName': journal.currency.display_name
-            },
-            'defaultCreditAccount': {
-                'id': journal.default_credit_account_id.id,
-                'name': journal.default_credit_account_id.name,
-                'displayName': journal.default_credit_account_id.display_name,
-                'code': journal.default_credit_account_id.code,
-                'exchangeRate': journal.default_credit_account_id.exchange_rate,
-                'foreignBalance': journal.default_credit_account_id.foreign_balance,
-                'reconcile': journal.default_credit_account_id.reconcile,
-                'debit': journal.default_credit_account_id.debit,
-                'credit': journal.default_credit_account_id.credit,
-                'currencyMode': journal.default_credit_account_id.currency_mode,
-                'companyCurrency': {
-                    'id': journal.default_credit_account_id.company_currency_id.id,
-                    'name': journal.default_credit_account_id.company_currency_id.name,
-                    'displayName': journal.default_credit_account_id.company_currency_id.display_name,
-                },
-                'currency': {
-                    'id': journal.default_credit_account_id.currency_id.id,
-                    'name': journal.default_credit_account_id.currency_id.name,
-                    'displayName': journal.default_credit_account_id.currency_id.display_name
-                },
-            }
-        } for journal in request.env['account.journal'].search([('type', 'in', ['bank', 'cash']), ('default_credit_account_id.currency_id', '=', False), ('active', '=', True)], order='id')]
+            'currencyId': journal.currency.id or journal.company_id.currency_id.id
+        } for journal in request.env['account.journal'].search(domain, order='id')]
     
     '''
         Get banks
@@ -149,12 +118,13 @@ class PosSales(http.Controller):
     def get_banks(self):
         banks = []
 
-        if self.check_module('eiru_bank_payments_references'):
-            banks = [{
+        if self.is_module_installed('eiru_bank_payments_references'):
+            banks = [
+                {
                     'id': bank.id,
-                    'name': bank.name,
-                    'displayName': bank.display_name
-                } for bank in request.env['res.bank'].search([('active', '=', True)])]
+                    'name': bank.display_name
+                } for bank in request.env['res.bank'].search([('active', '=', True)])
+            ]
 
         return banks
 
@@ -164,14 +134,15 @@ class PosSales(http.Controller):
     def get_bank_payment_types(self):
         bank_types = []
 
-        if self.check_module('eiru_bank_payments_references'):
-            bank_types = [{
+        if self.is_module_installed('eiru_bank_payments_references'):
+            bank_types = [
+                {
                     'id': type.id,
-                    'name': type.name,
-                    'displayName': type.display_name,
+                    'name': type.display_name,
                     'code': type.code,
                     'defaultState': type.default_state
-                } for type in request.env['res.bank.payments.type'].search([('is_receipt', '=', True)])]
+                } for type in request.env['res.bank.payments.type'].search([('is_receipt', '=', True)])
+            ]
 
         return bank_types
 
@@ -179,67 +150,75 @@ class PosSales(http.Controller):
         Get all active customers
     '''
     def get_customers(self):
-        return [{
-            'id': customer.id,
-            'name': customer.name,
-            'displayName': customer.display_name,
-            'imageMedium': customer.image_medium,
-            'ruc': customer.ruc or None,
-            'phone': customer.phone or None,
-            'mobile': customer.mobile or None,
-            'email': customer.email or None
-        } for customer in request.env['res.partner'].search([('customer', '=', True), ('active', '=', True)])]
+        domain = [('customer', '=', True), ('active', '=', True)]
+
+        return [
+            {
+                'id': customer.id,
+                'name': customer.display_name,
+                'image': customer.image_small,
+                'ruc': customer.ruc or None,
+                'phone': customer.phone or None,
+                'mobile': customer.mobile or None,
+                'email': customer.email or None
+            } for customer in request.env['res.partner'].search(domain)
+        ]
 
     '''
         Get all saleable and active products
     '''
     def get_products(self):
-        return [{
-            'id': product.id,
-            'name': product.name,
-            'displayName': product.display_name,
-            'ean13': product.ean13,
-            'defaultCode': product.default_code,
-            'imageMedium': product.image_medium,
-            'listPrice': product.list_price,
-            'variantCount': product.product_variant_count,
-            'quantity': 1,
-            'price': product.list_price,
-            'minimumPrice': product.minimum_price,
-            'maximumPrice': product.maximum_price,
-            'discount': 0,
-            'variants': [{
-                'id': variant.id,
-                'name': variant.name,
-                'displayName': variant.display_name,
-                'ean13': variant.ean13,
+        domain = [('sale_ok', '=', True), ('list_price', '>', 0), ('active', '=', True)]
+
+        return [
+            {
+                'id': product.id,
+                'name': product.display_name,
+                'ean13': product.ean13,
                 'defaultCode': product.default_code,
-                'imageMedium': variant.image_medium,
-                'listPrice': variant.list_price,
+                'image': product.image_small,
+                'listPrice': product.list_price,
+                'variantCount': product.product_variant_count,
                 'quantity': 1,
-                'price': variant.list_price,
+                'price': product.list_price,
                 'minimumPrice': product.minimum_price,
                 'maximumPrice': product.maximum_price,
                 'discount': 0,
-            } for variant in product.product_variant_ids if variant.active]
-        } for product in request.env['product.template'].search([('sale_ok', '=', True), ('list_price', '>', 0), ('active', '=', True)])]
+                'variants': [{
+                    'id': variant.id,
+                    'name': variant.display_name,
+                    'ean13': variant.ean13,
+                    'defaultCode': product.default_code,
+                    'image': variant.image_medium,
+                    'listPrice': variant.list_price,
+                    'quantity': 1,
+                    'price': variant.list_price,
+                    'minimumPrice': product.minimum_price,
+                    'maximumPrice': product.maximum_price,
+                    'discount': 0,
+                } for variant in product.product_variant_ids if variant.active]
+            } for product in request.env['product.template'].search(domain)
+        ]
 
     '''
         Get all active payment terms
     '''
     def get_payment_terms(self):
-        return [{
-            'id': payment_term.id,
-            'name': payment_term.name,
-            'displayName': payment_term.display_name,
-            'lines': [{
-                'id': line.id,
-                'days': line.days,
-                'days2': line.days2,
-                'value': line.value,
-                'valueAmount': line.value_amount
-            } for line in payment_term.line_ids]
-        } for payment_term in request.env['account.payment.term'].search([('active', '=', True)])]
+        domain = [('active', '=', True)]
+
+        return [
+            {
+                'id': payment_term.id,
+                'name': payment_term.display_name,
+                'lines': [{
+                    'id': line.id,
+                    'days': line.days,
+                    'days2': line.days2,
+                    'value': line.value,
+                    'valueAmount': line.value_amount
+                } for line in payment_term.line_ids]
+            } for payment_term in request.env['account.payment.term'].search(domain)
+        ]
 
     '''
         Make JSON response
@@ -252,6 +231,7 @@ class PosSales(http.Controller):
     '''
     def make_gzip_response(self, 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))
         
@@ -264,7 +244,7 @@ class PosSales(http.Controller):
         headers.add('Content-Length', len(contents))
 
         return Response(contents, status=status, headers=headers, content_type='application/json')
-
+    
     '''
     '''
     def make_info_log(self, log):
@@ -277,17 +257,19 @@ class PosSales(http.Controller):
     def init_sale(self, **kw):
         self.make_info_log('Sending JSON response')
     
-        return self.make_gzip_response({
-            'date': self.get_server_datetime(),
-            'user': self.get_user(),
-            'currencies': self.get_currencies(),
-            'journals': self.get_journals(),
-            'customers': self.get_customers(),
-            'products': self.get_products(),
-            'paymentTerms': self.get_payment_terms(),
-            'banks': self.get_banks(),
-            'bankPaymentTypes': self.get_bank_payment_types()
-        })
+        return self.make_gzip_response(
+            {
+                'date': self.get_server_datetime(),
+                'user': self.get_user(),
+                'currencies': self.get_currencies_from_journals(),
+                'journals': self.get_journals(),
+                'customers': self.get_customers(),
+                'products': self.get_products(),
+                'paymentTerms': self.get_payment_terms(),
+                'banks': self.get_banks(),
+                'bankPaymentTypes': self.get_bank_payment_types()
+            }
+        )
 
     
     '''
@@ -306,9 +288,8 @@ class PosSales(http.Controller):
 
         return {
             'id': customer.id,
-            'name': customer.name,
-            'displayName': customer.display_name,
-            'imageMedium': customer.image_medium,
+            'name': customer.display_name,
+            'image': customer.image_small,
             'ruc': customer.ruc or None,
             'phone': customer.phone or None,
             'mobile': customer.mobile or None,
@@ -330,10 +311,9 @@ class PosSales(http.Controller):
 
         return {
             'id': product.id,
-            'name': product.name,
-            'displayName': product.display_name,
+            'name': product.display_name,
             'ean13': product.ean13,
-            'imageMedium': product.image_medium,
+            'image': product.image_small,
             'listPrice': product.list_price,
             'variantCount': product.product_variant_count,
             'quantity': 1,
@@ -341,10 +321,9 @@ class PosSales(http.Controller):
             'discount': 0,
             'variants': [{
                 'id': variant.id,
-                'name': variant.name,
-                'displayName': variant.display_name,
+                'name': variant.display_name,
                 'ean13': variant.ean13,
-                'imageMedium': variant.image_medium,
+                'image': variant.image_small,
                 'listPrice': variant.list_price,
                 'quantity': 1,
                 'price': variant.list_price,

+ 32 - 35
src/App.vue

@@ -1,12 +1,33 @@
 <template lang="pug">
     .pos
-        form-wizard(title='' subtitle='' finishButtonText='Finalizar' :hideButtons='processing' color='#7c7bad' nextButtonText='Continuar' backButtonText='Volver' @on-complete='createSale' ref='wizard')
-            tab-content(title="Qué productos necesita?" :beforeChange="checkCart")
+        form-wizard(
+            title=''
+            subtitle=''
+            finishButtonText='Finalizar' 
+            color='#7c7bad' 
+            nextButtonText='Continuar' 
+            backButtonText='Volver' 
+            ref='wizard'
+            :hideButtons='processing' 
+            @on-complete='createSale'
+        )
+            tab-content(
+                title="Qué productos necesita?"
+                :beforeChange="checkCart"
+            )
                 product-step
-            tab-content(title="Quién es el cliente?" :beforeChange="checkCustomer")
+            tab-content(
+                title="Quién es el cliente?"
+                :beforeChange="checkCustomer"
+            )
                 customer-step
-            tab-content(v-if='isSale' title="Cómo quieres pagar?" :beforeChange="checkPaymentMethod")
+            tab-content(
+                v-if='isSale'
+                title="Cómo quieres pagar?"
+                :beforeChange="checkPaymentMethod"
+            )
                 payment-step
+        loading-overlay(:show='loading')
 </template>
 
 <script>
@@ -17,11 +38,8 @@
 
     import ProductStep from '@@/steps/Product'
     import CustomerStep from '@@/steps/Customer'
-    import PaymentMethodStep from '@@/steps/PaymentMethod'
-    import PaymentAmountStep from '@@/steps/PaymentAmount'
-
-    import InputDropdown from '@@/common/InputDropdown'
     import PaymentStep from '@@/steps/Payment'
+    import { LoadingOverlay } from './components/common'
 
     export default {
         components: {
@@ -29,15 +47,13 @@
             TabContent,
             ProductStep,
             CustomerStep,
-            PaymentMethodStep,
-            PaymentAmountStep,
-            InputDropdown,
-            PaymentStep
+            PaymentStep,
+            LoadingOverlay
         },
         computed: mapGetters([
             'isSale',
             'selectedBank',
-            'processing',
+            'loading',
             'completed'
         ]),
         methods: mapActions([
@@ -69,28 +85,6 @@
         },
         mounted() {
             this.initSale(this.$root.mode)
-        },
-        data() {
-            return {
-                options: [
-                    {
-                        id: '1',
-                        name: 'Option 1'  
-                    },
-                    {
-                        id: '2',
-                        name: 'Option 2'  
-                    },
-                    {
-                        id: '3',
-                        name: 'Option 3'  
-                    },
-                    {
-                        id: '4',
-                        name: 'Option 4'  
-                    }
-                ]
-            }
         }
     }
 </script>
@@ -101,6 +95,9 @@
         width: 100%
         height: 100%
         position: absolute
+        .v--modal-overlay
+            background: rgba(0, 0, 0, 0.7)
+            z-index: 9999
         .vue-form-wizard
             width: 100%
             height: 100%

+ 6 - 3
src/components/common/Card.vue

@@ -1,5 +1,8 @@
 <template lang="pug">
-    .card(@click='onClick' :class="{ 'selected-card': isSelected }")
+    .card(
+        :class="{ 'selected-card': isSelected }"
+        @click='onClick'
+    )
         h2.card-title {{ title }}
         img.card-image(:src="'data:image/png;base64,' + (image || 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAACXZwQWcAAABAAAAAQADq8/hgAAAEWklEQVRYw9WX6XKjRhCAef8HiySQvGt5vfZuEselOUAcEpe4GdI9MAgQOjb5k3SVyzY1801PX9OtNf9StP80QJR5miRpXtb/AFCnvmMySgmhlJn2Mal+BSBSj1NCGeNSGAMOd0/iQYCI95TAXnm+FCr/I2ZYPwJILEJhPaGm7flBFIW+Z5sUvwEivguovG7pMR0cV2e+BbYArF3cBqQclKfEvryvSB2KaHa6BYhgDSP7ZN7gmUNQCf86wCdgcBaKq04/cTzAuwbA/czKb8VdZYMSI8IAEOJ+XjTiFkF4SDjOARIIHLiBK+4E/xHOIdEloMSAAwZx7hEOBKIquwA4lFPbR/3uEhzCqSUmgBiwrGgeIlQm5b0zO0CN3yKw34QgQC4JKZqrGAFC0MpWvuwJ3V6hWD3BI5wchoDaBAumzYQgmsrd7ewZx5bosHIAAAtQp4+nXUuA+2yXy9Xyi4OsIorjauBLZQWtd0Gqrt3EvCXQlb4BMZYfsPP7cr0gvS4FaNw6Qus0ovtez8DZcYyHt8Wmk9XWdF+Mjf570Ke4q46UgAgUCtX55mKl/wSbsD83hrEE0VGJ1RrEWHz2aaXuIAEe7b3SNG/601oSzL/W20/T2r2uDNACARvjWelZQTTaCiCg2vSR1bzrsFgSQMk8SbPi8FWX+0GFbX2OXMarDoAmOGfo+wpXt7cwj4Hv+1n+rSMYW3HOfS4TAgHZIDIVYG38wNzchyB+kj4ZUwB4npw6ABokmgA2qz9kfbIkoWDLzQSQ0tbw2gA20kA/nmyqCHG8nmqQd2prbSKQZAIwnk5B5PSE/EWfACCUZGFSgHQKeE6DsCcExfc5wKEDRLMaJHBwTwA/zFzhOLBBPGODoCfEyYUb0XVBB1AGHXvho/SVDsSjF15QrtMG1xlpsDbCrCewj7UxAWAJSjsAlJOuHI0AX9Mi8IMgsJnMC2MMOJA2f7RhXI8AG/2LVxZZVlQWmKElnAFiT5nMH62L67Mb3lTmbIzVK3Uc9r6GvJAEyMa6d0KXP1oXliqbRPPzN0NvBcrBAmSpr37wlrB8GeRS6zkJECZVNRKeuLfty1C+wc/zp7TD9jVQN7DUDq2vkUEzfAymIl9uZ5iL1B0U1Rw7surmc4SE/sUBE3KaDB8Wd1QS7hJQga4Kayow2aAsXiV0L458HE/jx9UbPi33CIf+ITwDSnxM/IcIcAGIrHzaH+BX8Ky4awdq41nBZYsjG4/kEQLjg9Q5A9A1jJ7u3CJEa1OzmuvSKgubwPA24IT7WT7fJ5YmEtwbASWO2AkP94871WpPOCc8vmYHaORhv5lf75VrV3bD+9nZIrUJamhXN9v9kMlu3wonYVlGe9msU1/cGTgKpx0YmO2fsrKq66rMk8Bh7dd99sDIk+xxxsE5icqhqfsLflkz1pkbukSCBzI5bqG0EGrPGvfK2FeGDseRi1I5eVFuB8WvDp51FvsH13Fcz4+y6n86Oz8kfwPMD02INEiadQAAAABJRU5ErkJggg==')")
         .card-details(v-if='details.length > 0')
@@ -69,8 +72,8 @@
             position: absolute
             top: 0
         .card-image
-            width: 80px
-            height: 80px;
+            width: 75px
+            height: 75px
             margin: 0
             border: none
             position: absolute

+ 23 - 9
src/components/common/CardGrid.vue

@@ -1,10 +1,20 @@
 <template lang="pug">
     .card-grid-wrapper
-        .card-grid-loading(v-if='loading')
-            spinner(type='wave')
-        .card-grid(v-else)
-            add-card(v-if='canAdd' @onClickAdd='onClickAdd')
-            card(v-for='item in items' :key='item.id' :title='item.name' :image='item.imageMedium' :isSelected='item.id === selectedId' :details='computeDetails(item)' :options='defaultOptions.currency' @onClick='onClickCard(item)')
+        .card-grid
+            add-card(
+                v-if='canAdd'
+                @onClickAdd='onClickAdd'
+            )
+            card(
+                v-for='item in items'
+                :key='item.id'
+                :title='item.name'
+                :image='item.image'
+                :isSelected='item.id === selectedId'
+                :details='computeDetails(item)'
+                :options='defaultOptions.currency'
+                @onClick='onClickCard(item)'
+            )
 </template>
 
 <script>
@@ -26,10 +36,6 @@
                 type: Array,
                 default: []
             },
-            loading: {
-                type: Boolean,
-                default: false
-            },
             options: {
                 type: Object,
                 default: {}
@@ -131,6 +137,14 @@
         height: calc(100% - 50px)
         margin-top: 10px
         overflow-y: auto
+        &::-webkit-scrollbar
+            width: 2px
+            background: #f5f5f5
+        &::-webkit-scrollbar-thumb
+            background: #7c7bad
+        &::-webkit-scrollbar-track
+            -webkit-box-shadow: inset 0 0 6px #d3d3d3
+            background: #f5f5f5
         .card-grid-loading
             width: 100%
             height: 100%

+ 27 - 2
src/components/common/Cart.vue

@@ -3,8 +3,25 @@
         .cart-total
             h2.currency-cart-total {{ total | currency(...defaultOptions.currency) }}
         .cart-items-wrapper
-            transition-group(name='list' tag='ul' class='cart-items')
-                cart-item(v-for='(item, index) in items' :key='index' :index='index' :item='item' @onClickQuantity='onClickQuantity' @onChange='onItemChanged' @onClickIncrement='onIncrementQty' @onClickDecrement='onDecrementQty' @onClickMoney='onChangePrice' @onClickUndo='onUndoPrice' @onClickDelete='onDeleteItem' :options='defaultOptions.currency')
+            transition-group(
+                name='list' 
+                tag='ul' 
+                class='cart-items'
+            )
+                cart-item(
+                    v-for='(item, index) in items'
+                    :key='index'
+                    :index='index'
+                    :item='item'
+                    :options='defaultOptions.currency'
+                    @onClickQuantity='onClickQuantity'
+                    @onChange='onItemChanged'
+                    @onClickIncrement='onIncrementQty'
+                    @onClickDecrement='onDecrementQty'
+                    @onClickMoney='onChangePrice'
+                    @onClickUndo='onUndoPrice'
+                    @onClickDelete='onDeleteItem'
+                )
 </template>
 
 <script>
@@ -118,6 +135,14 @@
             height: calc(100% - 100px)
             overflow-y: auto
             overflow-x: hidden
+            &::-webkit-scrollbar
+                width: 2px
+                background: #f5f5f5
+            &::-webkit-scrollbar-thumb
+                background: #7c7bad
+            &::-webkit-scrollbar-track
+                -webkit-box-shadow: inset 0 0 6px #d3d3d3
+                background: #f5f5f5
             .cart-items
                 width: 100%
                 padding: 0

+ 27 - 7
src/components/common/CartItem.vue

@@ -1,18 +1,38 @@
 <template lang="pug">
     li.cart-item(:class="{'cart-item-invalid': !isValid()}")
-        h3.item-name {{ item.displayName }}
-        input.item-quantity(type='number' v-model.number='quantity' @focus='onFocus' @blur='onBlur')
+        h3.item-name {{ item.name }}
+        input.item-quantity(
+            type='number'
+            v-model.number='quantity'
+            @focus='onFocus'
+            @blur='onBlur'
+        )
         span.item-x x
         span.item-price {{ item.price | currency(...options) }}
         span.item-equals =
         span.item-subtotal {{ (item.price * (item.quantity || 1)) | currency(...options) }}
         .cart-item-options-wrapper
             .cart-item-options
-                .cart-item-option(class='fa fa-plus' @click='onClickIncrement')
-                .cart-item-option(class='fa fa-minus' @click='onClickDecrement')
-                .cart-item-option(class='fa fa-money' @click='onClickMoney')
-                .cart-item-option(class='fa fa-undo' @click='onClickUndo')
-                .cart-item-option(class='fa fa-trash' @click='onClickDelete')
+                .cart-item-option(
+                    class='fa fa-plus'
+                    @click='onClickIncrement'
+                )
+                .cart-item-option(
+                    class='fa fa-minus'
+                    @click='onClickDecrement'
+                )
+                .cart-item-option(
+                    class='fa fa-money'
+                    @click='onClickMoney'
+                )
+                .cart-item-option(
+                    class='fa fa-undo'
+                    @click='onClickUndo'
+                )
+                .cart-item-option(
+                    class='fa fa-trash'
+                    @click='onClickDelete'
+                )
 </template>
 
 <script>

+ 10 - 2
src/components/common/DropdownSearcher.vue

@@ -1,10 +1,18 @@
 <template lang="pug">
     .searcher
         span.input-icon.fa.fa-search(@click='onClickOptions')
-        input.search-input(v-model='search' :placeholder='placeholder' autofocus)
+        input.search-input(
+            v-model='search'
+            :placeholder='placeholder'
+            autofocus
+        )
         .dropdown-options(:class="{'input-show': showOptions }")
             ul.input-options
-                li.input-option(v-for='option in getOptions()' :key='option.id' @click='onSelectOption(option)') {{ option.name }}
+                li.input-option(
+                    v-for='option in getOptions()'
+                    :key='option.id'
+                    @click='onSelectOption(option)'
+                ) {{ option.name }}
 </template>
 
 <script>

+ 19 - 4
src/components/common/InputDropdown.vue

@@ -3,12 +3,27 @@
         .input-group
             .input-group-button(v-if='hasPrefix()')
                 button(type='button') {{ prefix }}
-            input.input-formatted(type='text' v-model='formattedValue' :disabled='!editable' :autofocus='focus')
+            input.input-formatted(
+                v-model='formattedValue'
+                type='text'
+                :disabled='!editable'
+                :autofocus='focus'
+            )
             .input-group-button(v-if='hasSuffix()')
-                button(type='button' @click='onShowOptions()' ref='suffixButton') {{ suffix }}
+                button(
+                    type='button'
+                    @click='onShowOptions()'
+                    ref='suffixButton'
+                ) {{ suffix }}
                     span.caret(:style="{'display': hasOptions() ? 'inline-block' : 'none'}")
-                ul.dropdown(:style="{'display': isShowOptions ? 'block' : 'none'}" ref='suffixDropdown')
-                    li(v-for='(option, index) in options' :key='index')
+                ul.dropdown(
+                    :style="{'display': isShowOptions ? 'block' : 'none'}"
+                    ref='suffixDropdown'
+                )
+                    li(
+                        v-for='(option, index) in options'
+                        :key='index'
+                    )
                         a(@click='onClickOption(option)') {{ option }}
 </template>
 

+ 48 - 0
src/components/common/LoadingOverlay.vue

@@ -0,0 +1,48 @@
+<template lang="pug">
+    transition(name='fade')
+        .loading-overlay(v-show='show')
+            spinner(type='wave')
+            h2.loading-text Cargando, espere...
+</template>
+
+<script>
+    import Spinner from './Spinner'
+
+    export default {
+        props: {
+            show: {
+                type: Boolean,
+                default: false
+            }
+        },
+        components: {
+            Spinner
+        }
+    }
+</script>
+
+<style lang="sass">
+    .loading-overlay
+        display: flex
+        justify-content: center
+        align-items: center
+        flex-direction: column
+        width: 100%
+        height: 100%
+        background: rgba(0, 0, 0, 0.8)
+        position: fixed
+        top: 0
+        left: 0
+        z-index: 9999
+        .spinner-wave
+            margin: auto !important
+            .spinner-rect
+                background: #fff !important
+        .loading-text
+            color: #fff
+            font-size: 8pt
+    .fade-enter-active, .fade-leave-active
+        transition: opacity .8s
+    .fade-enter, .fade-leave-to
+        opacity: 0
+</style>

+ 6 - 1
src/components/common/Searcher.vue

@@ -1,5 +1,10 @@
 <template lang="pug">
-    input.searcher(type='search' :placeholder='placeholder' :style='{ width, height }' v-model='search')
+    input.searcher(
+        v-model='search'
+        type='search'
+        :placeholder='placeholder'
+        :style='{ width, height }'
+    )
 </template>
 
 <script>

+ 6 - 2
src/components/common/index.js

@@ -1,9 +1,11 @@
 import CardGrid from './CardGrid'
 import Cart from './Cart'
 import Searcher from './Searcher'
-import DropdownSearcher from './DropdownSearcher'
 import Ticket from './Ticket'
 import Spinner from './Spinner'
+import DropdownSearcher from './DropdownSearcher'
+import InputDropdown from './InputDropdown'
+import LoadingOverlay from './LoadingOverlay'
 
 export {
     CardGrid,
@@ -11,5 +13,7 @@ export {
     Searcher,
     Ticket,
     Spinner,
-    DropdownSearcher
+    DropdownSearcher,
+    InputDropdown,
+    LoadingOverlay
 }

+ 132 - 0
src/components/modals/BankPaymentModal.vue

@@ -0,0 +1,132 @@
+<template lang="pug">
+    modal(
+        name='payment-bank-modal'
+        adaptive='true'
+        width='800px'
+        height='500px'
+        transition='nice-modal-fade'
+        :classes="['v--modal', 'payment-bank-modal']"
+        @before-close='beforeClose'
+    )
+        form-wizard(
+            title='Pago Bancario'
+            subtitle=''
+            next-button-text='Continuar'
+            back-button-text='Volver'
+            finish-button-text='Completar'
+            color='#7c7bad'
+        )
+            tab-content(
+                title='Qué tipo de operación es?'
+            )
+                form.journal-form
+                    ul
+                        li
+                            input.form-input(
+                                type='radio'
+                                id='cash'
+                            )
+                            label Banco (PYG)
+                        li
+                            input.form-input(
+                                type='radio'
+                                id='cash'
+                            )
+                            label Cheques (PYG)
+                        li
+                            input.form-input(
+                                type='radio'
+                                id='cash'
+                            )
+                            label Tarjeta de crédito (PYG)
+                        li
+                            input.form-input(
+                                type='radio'
+                                id='cash'
+                            )
+                            label Tarjeta de débito (PYG)
+                        li
+                            input.form-input(
+                                type='radio'
+                                id='cash'
+                            )
+                            label Billera Tigo (PYG)
+            tab-content(
+                title='Qué detalles necesita?'
+            )
+            tab-content(
+                title='De qué monto es la operación?'
+            )
+
+</template>
+
+<script>
+    import { FormWizard, TabContent } from 'vue-form-wizard'
+
+    export default {
+        props: {
+            show: {
+                type: Boolean,
+                required: true
+            }
+        },
+        components: {
+            FormWizard,
+            TabContent
+        },
+        watch: {
+            show(value) {
+                if (!value) {
+                    this.$modal.hide('payment-bank-modal')
+                    return
+                }
+
+                this.$modal.show('payment-bank-modal')
+            }
+        },
+        methods: {
+            beforeClose(e) {
+                if (this.show) {
+                    e.stop()
+                }
+
+                console.log(this.show)
+            },
+            onFinalize() {
+                this.$emit('onFinalize')
+            },
+            onCancel() {
+                this.$emit('onCancel')
+            }
+        }
+    }
+</script>
+
+<style lang="sass">
+    .payment-bank-modal
+        padding: 0 !important
+        &::before
+            content: ''
+            display: block
+            position: absolute
+            background-size: cover
+            filter: blur(3px)
+            z-index: -1
+        .wizard-tab-container
+            display: flex !important
+            justify-content: center !important
+            align-items: center !important
+            .journal-form
+                width: 400px
+                background: #fff
+                ul
+                    list-style: none
+                    li
+                        margin-bottom: 3px
+                        input
+                            width: 20px
+                            height: 20px
+                        label
+                            font-size: 12pt
+                            margin: 0 35px 15px 5px
+</style>

+ 11 - 2
src/components/modals/CustomerModal.vue

@@ -1,6 +1,15 @@
 <template lang="pug">
-    modal(name='customer-modal' transition='nice-modal-fade' @before-close='beforeClose' :classes="['v--modal', 'customer-modal']")
-        customer-form(:type='medium' @onAccept='onAccept' @onCancel='onCancel')
+    modal(
+        name='customer-modal'
+        transition='nice-modal-fade'
+        :classes="['v--modal', 'customer-modal']"
+        @before-close='beforeClose'
+    )
+        customer-form(
+            :type='medium'
+            @onAccept='onAccept'
+            @onCancel='onCancel'
+        )
 </template>
 
 <script>

+ 8 - 1
src/components/modals/PaymentBankModal.vue

@@ -1,5 +1,12 @@
 <template lang="pug">
-    modal(name='payment-bank-modal' transition='nice-modal-fade' @before-close='beforeClose' height='auto' width='670' :classes="['v--modal', 'payment-bank-modal']")
+    modal(
+        name='payment-bank-modal'
+        transition='nice-modal-fade'
+        height='auto'
+        width='670'
+        :classes="['v--modal', 'payment-bank-modal']"
+        @before-close='beforeClose' 
+    )
         h2.modal-title
         form
             .form-item

+ 11 - 2
src/components/modals/ProductModal.vue

@@ -1,6 +1,15 @@
 <template lang="pug">
-    modal(name='product-modal' transition='nice-modal-fade' @before-close='beforeClose' :classes="['v--modal', 'product-modal']")
-        product-form(title='Nuevo Producto' @onAccept='onAccept' @onCancel='onCancel')
+    modal(
+        name='product-modal'
+        transition='nice-modal-fade'
+        :classes="['v--modal', 'product-modal']"
+        @before-close='beforeClose'
+    )
+        product-form(
+            title='Nuevo Producto'
+            @onAccept='onAccept'
+            @onCancel='onCancel'
+        )
 </template>
 
 <script>

+ 3 - 3
src/components/modals/VariantModal.vue

@@ -1,11 +1,11 @@
 <template lang="pug">
     modal(name='variant-selector' transition='nice-modal-fade' height="500" @closed='handleClosed' :classes="['v--modal', 'variant-modal']")
-        searcher(:items='getItems()' :keys="['name', 'displayName']" @onSearch='filterVariants')
+        searcher(:items='getItems()' :keys="['name']" @onSearch='filterVariants')
         .product-variants
             .product-variant(v-for='item in getItems()' :key='item.id' @click='selectProduct(item)')
-                img.variant-image(:src="'data:image/png;base64,' + (item.imageMedium || 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAACXZwQWcAAABAAAAAQADq8/hgAAAEWklEQVRYw9WX6XKjRhCAef8HiySQvGt5vfZuEselOUAcEpe4GdI9MAgQOjb5k3SVyzY1801PX9OtNf9StP80QJR5miRpXtb/AFCnvmMySgmhlJn2Mal+BSBSj1NCGeNSGAMOd0/iQYCI95TAXnm+FCr/I2ZYPwJILEJhPaGm7flBFIW+Z5sUvwEivguovG7pMR0cV2e+BbYArF3cBqQclKfEvryvSB2KaHa6BYhgDSP7ZN7gmUNQCf86wCdgcBaKq04/cTzAuwbA/czKb8VdZYMSI8IAEOJ+XjTiFkF4SDjOARIIHLiBK+4E/xHOIdEloMSAAwZx7hEOBKIquwA4lFPbR/3uEhzCqSUmgBiwrGgeIlQm5b0zO0CN3yKw34QgQC4JKZqrGAFC0MpWvuwJ3V6hWD3BI5wchoDaBAumzYQgmsrd7ewZx5bosHIAAAtQp4+nXUuA+2yXy9Xyi4OsIorjauBLZQWtd0Gqrt3EvCXQlb4BMZYfsPP7cr0gvS4FaNw6Qus0ovtez8DZcYyHt8Wmk9XWdF+Mjf570Ke4q46UgAgUCtX55mKl/wSbsD83hrEE0VGJ1RrEWHz2aaXuIAEe7b3SNG/601oSzL/W20/T2r2uDNACARvjWelZQTTaCiCg2vSR1bzrsFgSQMk8SbPi8FWX+0GFbX2OXMarDoAmOGfo+wpXt7cwj4Hv+1n+rSMYW3HOfS4TAgHZIDIVYG38wNzchyB+kj4ZUwB4npw6ABokmgA2qz9kfbIkoWDLzQSQ0tbw2gA20kA/nmyqCHG8nmqQd2prbSKQZAIwnk5B5PSE/EWfACCUZGFSgHQKeE6DsCcExfc5wKEDRLMaJHBwTwA/zFzhOLBBPGODoCfEyYUb0XVBB1AGHXvho/SVDsSjF15QrtMG1xlpsDbCrCewj7UxAWAJSjsAlJOuHI0AX9Mi8IMgsJnMC2MMOJA2f7RhXI8AG/2LVxZZVlQWmKElnAFiT5nMH62L67Mb3lTmbIzVK3Uc9r6GvJAEyMa6d0KXP1oXliqbRPPzN0NvBcrBAmSpr37wlrB8GeRS6zkJECZVNRKeuLfty1C+wc/zp7TD9jVQN7DUDq2vkUEzfAymIl9uZ5iL1B0U1Rw7surmc4SE/sUBE3KaDB8Wd1QS7hJQga4Kayow2aAsXiV0L458HE/jx9UbPi33CIf+ITwDSnxM/IcIcAGIrHzaH+BX8Ky4awdq41nBZYsjG4/kEQLjg9Q5A9A1jJ7u3CJEa1OzmuvSKgubwPA24IT7WT7fJ5YmEtwbASWO2AkP94871WpPOCc8vmYHaORhv5lf75VrV3bD+9nZIrUJamhXN9v9kMlu3wonYVlGe9msU1/cGTgKpx0YmO2fsrKq66rMk8Bh7dd99sDIk+xxxsE5icqhqfsLflkz1pkbukSCBzI5bqG0EGrPGvfK2FeGDseRi1I5eVFuB8WvDp51FvsH13Fcz4+y6n86Oz8kfwPMD02INEiadQAAAABJRU5ErkJggg==')")
+                img.variant-image(:src="'data:image/png;base64,' + (item.image || 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAAAAACPAi4CAAAACXZwQWcAAABAAAAAQADq8/hgAAAEWklEQVRYw9WX6XKjRhCAef8HiySQvGt5vfZuEselOUAcEpe4GdI9MAgQOjb5k3SVyzY1801PX9OtNf9StP80QJR5miRpXtb/AFCnvmMySgmhlJn2Mal+BSBSj1NCGeNSGAMOd0/iQYCI95TAXnm+FCr/I2ZYPwJILEJhPaGm7flBFIW+Z5sUvwEivguovG7pMR0cV2e+BbYArF3cBqQclKfEvryvSB2KaHa6BYhgDSP7ZN7gmUNQCf86wCdgcBaKq04/cTzAuwbA/czKb8VdZYMSI8IAEOJ+XjTiFkF4SDjOARIIHLiBK+4E/xHOIdEloMSAAwZx7hEOBKIquwA4lFPbR/3uEhzCqSUmgBiwrGgeIlQm5b0zO0CN3yKw34QgQC4JKZqrGAFC0MpWvuwJ3V6hWD3BI5wchoDaBAumzYQgmsrd7ewZx5bosHIAAAtQp4+nXUuA+2yXy9Xyi4OsIorjauBLZQWtd0Gqrt3EvCXQlb4BMZYfsPP7cr0gvS4FaNw6Qus0ovtez8DZcYyHt8Wmk9XWdF+Mjf570Ke4q46UgAgUCtX55mKl/wSbsD83hrEE0VGJ1RrEWHz2aaXuIAEe7b3SNG/601oSzL/W20/T2r2uDNACARvjWelZQTTaCiCg2vSR1bzrsFgSQMk8SbPi8FWX+0GFbX2OXMarDoAmOGfo+wpXt7cwj4Hv+1n+rSMYW3HOfS4TAgHZIDIVYG38wNzchyB+kj4ZUwB4npw6ABokmgA2qz9kfbIkoWDLzQSQ0tbw2gA20kA/nmyqCHG8nmqQd2prbSKQZAIwnk5B5PSE/EWfACCUZGFSgHQKeE6DsCcExfc5wKEDRLMaJHBwTwA/zFzhOLBBPGODoCfEyYUb0XVBB1AGHXvho/SVDsSjF15QrtMG1xlpsDbCrCewj7UxAWAJSjsAlJOuHI0AX9Mi8IMgsJnMC2MMOJA2f7RhXI8AG/2LVxZZVlQWmKElnAFiT5nMH62L67Mb3lTmbIzVK3Uc9r6GvJAEyMa6d0KXP1oXliqbRPPzN0NvBcrBAmSpr37wlrB8GeRS6zkJECZVNRKeuLfty1C+wc/zp7TD9jVQN7DUDq2vkUEzfAymIl9uZ5iL1B0U1Rw7surmc4SE/sUBE3KaDB8Wd1QS7hJQga4Kayow2aAsXiV0L458HE/jx9UbPi33CIf+ITwDSnxM/IcIcAGIrHzaH+BX8Ky4awdq41nBZYsjG4/kEQLjg9Q5A9A1jJ7u3CJEa1OzmuvSKgubwPA24IT7WT7fJ5YmEtwbASWO2AkP94871WpPOCc8vmYHaORhv5lf75VrV3bD+9nZIrUJamhXN9v9kMlu3wonYVlGe9msU1/cGTgKpx0YmO2fsrKq66rMk8Bh7dd99sDIk+xxxsE5icqhqfsLflkz1pkbukSCBzI5bqG0EGrPGvfK2FeGDseRi1I5eVFuB8WvDp51FvsH13Fcz4+y6n86Oz8kfwPMD02INEiadQAAAABJRU5ErkJggg==')")
                 .variant-details
-                    h2.variant-name {{ item.displayName }}    
+                    h2.variant-name {{ item.name }}    
 </template>
 
 <script>

+ 1 - 1
src/components/steps/Customer.vue

@@ -2,7 +2,7 @@
     .pos-step
         .customer-selection-step
             .customer-selector
-                searcher(:items='customers' :keys="['name', 'displayName', 'phone', 'mobile', 'email']" @onSearch='filterCustomers')
+                searcher(:items='customers' :keys="['name', 'phone', 'mobile', 'email']" @onSearch='filterCustomers')
                 card-grid(:items='visibleCustomers' :loading='loadingCustomers' canAdd @onAdd='showCustomerForm' @onSelect='selectCustomer')
                 customer-modal(:show='showingCustomerForm' @onAccept='submitCustomer' @onCancel='hideCustomerForm')
             transition(name='slide-fade')

+ 68 - 21
src/components/steps/Payment.vue

@@ -6,24 +6,53 @@
             .form-item
                 label.form-label Forma de Pago
                 .form-item-option
-                    input.form-input(type='radio' id='cash' value='cash' v-model='selectedPaymentType')
+                    input.form-input(
+                        type='radio'
+                        id='cash'
+                        value='cash'
+                        v-model='selectedPaymentType'
+                    )
                     label(for='cash') Contado
                 .form-item-option
-                    input.form-input(type='radio' id='credit' value='credit' v-model='selectedPaymentType')
+                    input.form-input(
+                        type='radio'
+                        id='credit'
+                        value='credit'
+                        v-model='selectedPaymentType'
+                    )
                     label(for='credit') Crédito
             //- input para condiciones de pago en caso de pago a crédito
             transition(name='fade')
                 .form-item(v-show="selectedPaymentType === 'credit'")
-                    select.form-input.input-only(v-model='selectedPaymentTermId')
-                        option(v-for='term in paymentTerms' :value='term.id' v-if="term.lines.length > 0 && (term.lines[0].days !== 0 || term.lines[0].value !==  'balance')") {{ term.displayName }}
+                    select.form-input.input-only(v-model='paymentTermId')
+                        option(
+                            :value='term.id' 
+                            v-for='term in paymentTerms'
+                            v-if="term.lines.length > 0 && (term.lines[0].days !== 0 || term.lines[0].value !==  'balance')"
+                        ) {{ term.name }}
             //- input para monto de pago
             .form-item
                 label.form-label Monto a Pagar
-                input-dropdown.form-input(value='0' format='number' :editable='false' :suffix='selectedCurrency && selectedCurrency.symbol' :options=['G$', 'R$'] @onChangeValue='onChangeValue' @onClickOption='onClick')
+                input-dropdown.form-input(
+                    value='0'
+                    format='number'
+                    :editable='false'
+                    :suffix='currencySymbol'
+                    :options='currencySymbols'
+                    @onChangeValue='onChangeValue'
+                    @onClickOption='changeCurrency'
+                )
             //- input para el monto recibido
             .form-item
                 label.form-label Monto Recibido
-                input-dropdown.form-input(value='0' suffix='Efectivo PYG' :options=['G$', 'R$'] :focus='true')
+                input-dropdown.form-input(
+                    value='0'
+                    format='number'
+                    :suffix='paymentMethod'
+                    :options='paymentMethods'
+                    :focus='true'
+                    @onClickOption='changePaymentMethod'
+                )
             //- input para el vuelto del pago en caso de pago en efectivo
             div(v-show="selectedPaymentType === 'cash'")
                 hr
@@ -38,18 +67,23 @@
                             tr
                                 th Monto a Pagar
                                 th Fecha de Pago
+        bank-payment-modal(
+            :show='showBankPayment'
+            @onAccept='',
+            @onCancel=`changePaymentMethod('Efectivo')`
+        )
 </template>
 
 <script>
     import { mapGetters, mapActions } from 'vuex'
-
-    import Ticket from '@@/common/Ticket'
-    import InputDropdown from '@@/common/InputDropdown'
+    import { Ticket, InputDropdown } from '../common'
+    import BankPaymentModal from '../modals/BankPaymentModal'
 
     export default {
         components: {
             Ticket,
-            InputDropdown
+            InputDropdown,
+            BankPaymentModal
         },
         computed: {
             selectedPaymentType: {
@@ -60,9 +94,9 @@
                     this.changePaymentType(value)
                 }
             },
-            selectedPaymentTermId: {
+            paymentTermId: {
                 get() {
-                    return (this.selectedPaymentTerm && this.selectedPaymentTerm.id) || -1
+                    return (this.paymentTerm && this.paymentTerm.id) || -1
                 },
                 set(value) {
                     this.selectPaymentTerm(value)
@@ -70,15 +104,28 @@
             },
             ...mapGetters([
                 'paymentType',
+                'paymentTerm',
+                'paymentMethod',
+                'currency',
+                'currencySymbol',
+                'currencies',
+                'currencySymbols',
+                'selectedJournal',
+                'journals',
                 'paymentTerms',
-                'selectedPaymentTerm',
-                'selectedCurrency'
+                'paymentMethods',
+                'showBankPayment'
             ])
         },
-        methods: mapActions([
-            'changePaymentType',
-            'selectPaymentTerm'
-        ])
+        methods: {
+            ...mapActions([
+                'changePaymentType',
+                'changePaymentMethod',
+                'selectPaymentTerm',
+                'selectJournal',
+                'changeCurrency'
+            ])
+        }
     }
 </script>
 
@@ -103,17 +150,17 @@
                     display: inline-block
                     vertical-align: top
                 .form-label
-                    width: 250px
+                    width: 200px
                     height: 35px
                     font-size: 13pt
                     line-height: 30px
                 .form-input
-                    width: 350px
+                    width: 400px
                     height: 35px
                     font-size: 12pt
                     border-radius: 0
                     &.input-only
-                        margin-left: 250px
+                        margin-left: 200px
                         margin-bottom: 15px
                 .form-item-option
                     display: inline-block

+ 49 - 20
src/components/steps/Product.vue

@@ -1,12 +1,43 @@
 <template lang="pug">
     .pos-step
         .products-selector
-            searcher(:items='products' :keys="['name', 'displayName', 'ean13', 'defaultCode']" mode='normal' @onSearch='filterProducts')
-            card-grid(:items='visibleProducts' :loading='loadingProducts' @onAdd='showProductForm' :details="['price:c']" :options='selectedCurrency' @onSelect='selectProduct')
-            product-modal(:show='showingProductForm' @onAccept='submitProduct' @onCancel='hideProductForm')
+            searcher(
+                mode='normal'
+                :items='products'
+                :keys="['name', 'ean13', 'defaultCode']"
+                @onSearch='filterProducts'
+            )
+            card-grid(
+                @onAdd='showProductForm'
+                :items='visibleProducts'
+                :details="['price:c']"
+                :options='currency'
+                :loading='loadingProducts'
+                @onSelect='selectProduct'
+            )
+            product-modal(
+                :show='showingProductForm'
+                @onAccept='submitProduct'
+                @onCancel='hideProductForm'
+            )
             variant-modal
-            discount-modal(:item='itemToDiscount' :options='selectedCurrency' :show='!!itemToDiscount' @onAccept='applyPrice' @onCancel='applyPrice')
-        cart(:items='cartItems' @onTotalComputed='changeCartTotal' @onIncrementQty='addToCart' @onUndoPrice='undoPrice' @onChangePrice='changePrice' @onDecrementQty='decreaseFromCart' @onDeleteItem='removeFromCart' :options='selectedCurrency')
+            discount-modal(
+                :item='itemToDiscount' 
+                :options='currency'
+                :show='!!itemToDiscount'
+                @onAccept='applyPrice'
+                @onCancel='applyPrice'
+            )
+        cart(
+            :items='cartItems' 
+            :options='currency'
+            @onTotalComputed='changeCartTotal'
+            @onIncrementQty='addToCart'
+            @onUndoPrice='undoPrice'
+            @onChangePrice='changePrice'
+            @onDecrementQty='decreaseFromCart'
+            @onDeleteItem='removeFromCart' 
+        )
 </template>
 
 <script>
@@ -16,8 +47,6 @@
     import VariantModal from '@@/modals/VariantModal'
     import DiscountModal from '@@/modals/DiscountModal'
 
-    import { FILTER_PRODUCTS, SELECT_PRODUCT, SHOW_PRODUCT_FORM, HIDE_PRODUCT_FORM, SUBMIT_PRODUCT, CHANGE_CART_TOTAL, ADD_TO_CART, DECREASE_FROM_CART, UNDO_PRICE, CHANGE_PRICE, APPLY_PRICE, REMOVE_FROM_CART } from '@/constants/actionTypes'
-
     export default {
         components: {
             Searcher,
@@ -35,22 +64,22 @@
                 'showingProductForm',
                 'cartItems',
                 'itemToDiscount',
-                'selectedCurrency'
+                'currency'
             ])
         },
         methods: mapActions([
-            FILTER_PRODUCTS,
-            SELECT_PRODUCT,
-            SHOW_PRODUCT_FORM,
-            HIDE_PRODUCT_FORM,
-            SUBMIT_PRODUCT,
-            CHANGE_CART_TOTAL,
-            ADD_TO_CART,
-            DECREASE_FROM_CART,
-            UNDO_PRICE,
-            CHANGE_PRICE,
-            APPLY_PRICE,
-            REMOVE_FROM_CART
+            'filterProducts',
+            'selectProduct',
+            'showProductForm',
+            'hideProductForm',
+            'submitProduct',
+            'changeCartTotal',
+            'addToCart',
+            'decreaseFromCart',
+            'undoPrice',
+            'changePrice',
+            'applyPrice',
+            'removeFromCart'
         ])
     }
 </script>

+ 10 - 8
src/store/actions.js

@@ -41,7 +41,7 @@ const actions = {
      * @param {*} param0 
      * @param {*} payload 
      */
-    [NOTIFY] ({ commit }, payload) {
+    notify({ commit }, payload) {
         openerp.web.notification.do_warn('Atención', payload)
         return false
     },
@@ -49,13 +49,15 @@ const actions = {
      * 
      * @param {*} param0 
      */
-    [INIT_SALE] ({ getters, commit, dispatch }, payload) {
-        commit(SET_MODE, payload || getters.mode)
-        commit(SET_RESULT, '')
+    initSale({ getters, commit, dispatch }, payload) {
+        commit('setMode', payload || getters.mode)
+        commit('setResult', '')
         
         return axios.get(INIT_SALE_URL).then(response => {
-            dispatch(COMPLETE_SALE, false)
-            dispatch(EXPLODE_DATA, response.data)            
+            commit('setLoading', false)
+            
+            dispatch('completeSale', false)
+            dispatch('explodeData', response.data)            
         }).catch(error => {
             console.log(error)
         })
@@ -65,7 +67,7 @@ const actions = {
      * @param {*} param0 
      * @param {*} payload 
      */
-    [EXPLODE_DATA] ({ dispatch }, payload) {
+    explodeData({ dispatch }, payload) {
         for (let value in payload) {
             dispatch(`init${value[0].toUpperCase()}${value.slice(1)}`, payload[value])
         }
@@ -75,7 +77,7 @@ const actions = {
      * @param {*} param0 
      * @param {*} payload 
      */
-    [CREATE_PRODUCT] ({ dispatch }, payload) {
+    createProduct({ dispatch }, payload) {
         const data = {
             jsonrpc: '2.0',
             method: 'call',

+ 2 - 2
src/store/getters.js

@@ -17,8 +17,8 @@ const getters = {
      * 
      * @param {*} state 
      */
-    processing(state) {
-        return state.processing
+    loading(state) {
+        return state.loading
     },
     /**
      * 

+ 1 - 4
src/store/index.js

@@ -37,10 +37,7 @@ const store = new Vuex.Store({
         bank,
         bankPaymentType
     },
-    strict: true,
-    plugins: [createPersistedState({
-        key: 'eiruPOS'
-    })]
+    strict: true
 })
 
 export default store

+ 11 - 64
src/store/modules/bank.js

@@ -4,118 +4,65 @@ const state = {
     bankOperationNumber: null,
     bankDueDate: null,
     accountBankNumber: null,
-    holderBankName: null
+    holderBankName: null,
+    showBankPayment: false
 }
 
 const getters = {
-    /**
-     * 
-     * @param {*} state 
-     */
     banks(state) {
         return state.banks
     },
-    /**
-     * 
-     * @param {*} state 
-     */
     selectedBank(state) {
         return state.selectedBank
     },
-    /**
-     * 
-     * @param {*} state 
-     */
     bankOperationNumber(state) {
         return state.bankOperationNumber
     },
-    /**
-     * 
-     * @param {*} state 
-     */
     bankDueDate(state) {
         return state.dueDate
     },
-    /**
-     * 
-     * @param {*} state 
-     */
     accountBankNumber(state) {
         return state.accountBankNumber
     },
-    /**
-     * 
-     * @param {*} state 
-     */
     holderBankName(state) {
         return state.holderBankName
+    },
+    showBankPayment(state) {
+        return state.showBankPayment
     }
 }
 
 const mutations = {
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
     setBanks (state, payload) {
         state.banks = payload
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
     setSelectedBank(state, payload) {
         state.selectedBank = payload
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
     setBankOperationNumber(state, payload) {
         state.bankOperationNumber = payload
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
     setBankDueDate(state, payload) {
         state.bankDueDate = payload
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
     setAccountBankNumber(state, payload) {
         state.accountBankNumber = payload
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
     setHolderBankName(state, payload) {
         state.holderBankName = payload
+    },
+    toggleBankPayment(state) {
+        state.showBankPayment = !state.showBankPayment
     }
 }
 
 const actions = {
-    /**
-     * 
-     * @param {*} param0 
-     * @param {*} payload 
-     */
     initBanks ({ commit}, payload) {
         commit('setBanks', payload)
     },
-    /**
-     * 
-     * @param {*} param0 
-     */
+    toggleBankPayment({ commit }) {
+        commit('toggleBankPayment')
+    },
     resetBanks ({ commit }) {
 
     }

+ 36 - 50
src/store/modules/currency.js

@@ -1,57 +1,42 @@
-import { 
-    SET_CURRENCIES, 
-    SET_LOADING_CURRENCIES,
-    AUTOSELECT_CURRENCY
-} from '@/constants/mutationTypes'
-
-import { 
-    INIT_CURRENCIES, 
-    RESET_CURRENCY
-} from '@/constants/actionTypes'
-
-const initialState = {
+const state = {
     currencies: [],
+    currency: null, 
     loadingCurrencies: false,
-    selectedCurrency: null
-}
-
-const state = {
-    currencies: initialState.currencies,
-    loadingCurrencies: !initialState.currencies,
-    selectedCurrency: initialState.selectedCurrency  
 }
 
 const getters = {
-    /**
-     * 
-     * @param {*} state 
-     */
     currencies(state) {
         return state.currencies
     },
-    /**
-     * 
-     * @param {*} state 
-     */
+    currencySymbols(state) {
+        return state.currencies && state.currencies.filter(c => state.currency.id !== c.id).map(c => c.symbol)
+    },
+    currency(state) {
+        return state.currency
+    },
+    currencySymbol(state) {
+        return state.currency && state.currency.symbol
+    },
     loadingCurrencies(state) {
         return state.loadingCurrencies
-    },
-    /**
-     * 
-     * @param {*} state 
-     */
-    selectedCurrency(state) {
-        return state.selectedCurrency
     }
 }
 
 const mutations = {
+    setCurrency(state, currencySymbol) {
+        if (currencySymbol) {
+            state.currency = state.currencies.find(c => (c.symbol === currencySymbol))
+            return
+        }
+        
+        state.currency = state.currencies.find(c => (c.base === true))
+    },
     /**
      * 
      * @param {*} state 
      * @param {*} payload 
      */
-    [SET_CURRENCIES] (state, payload) {
+    setCurrencies(state, payload) {
         state.currencies = payload
     },
     /**
@@ -59,15 +44,8 @@ const mutations = {
      * @param {*} state 
      * @param {*} payload 
      */
-    [SET_LOADING_CURRENCIES] (state, payload) {
+    setLoadingCurrencies(state, payload) {
         state.loadingCurrencies = !!payload
-    },
-    /**
-     * 
-     * @param {*} state 
-     */
-    [AUTOSELECT_CURRENCY] (state) {
-        state.selectedCurrency = state.currencies.find(item => item.base === true)
     }
 }
 
@@ -77,19 +55,27 @@ const actions = {
      * @param {*} param0 
      * @param {*} payload 
      */
-    [INIT_CURRENCIES] ({ commit }, payload) {
-        commit(SET_CURRENCIES, payload)
-        commit(AUTOSELECT_CURRENCY)
-        commit(SET_LOADING_CURRENCIES)
+    initCurrencies({ commit }, payload) {
+        commit('setCurrencies', payload)
+        commit('setCurrency')
+        commit('setLoadingCurrencies')
+    },
+    /**
+     * 
+     * @param {*} param0 
+     * @param {*} payload 
+     */
+    resetCurrency({ commit }) {
+        commit('setLoadingCurrencies', true)
+        commit('setCurrencies', [])
     },
     /**
      * 
      * @param {*} param0 
      * @param {*} payload 
      */
-    [RESET_CURRENCY] ({ commit }) {
-        commit(SET_LOADING_CURRENCIES, true)
-        commit(SET_CURRENCIES, [])
+    changeCurrency({ commit }, currencySymbol) {
+        commit('setCurrency', currencySymbol)
     }
 }
 

+ 59 - 156
src/store/modules/payment.js

@@ -1,149 +1,74 @@
-import { 
-    SET_PAYMENT_TERMS, 
-    SET_LOADING_PAYMENT_TERMS, 
-    AUTOSELECT_PAYMENT_TERM, 
-    SET_SELECTED_PAYMENT_TERM, 
-    SET_PAYMENT_TYPE, 
-    SET_INITIAL_PAYMENT, 
-    SET_PAYMENT_LINES 
-} from '@/constants/mutationTypes'
-
-import { 
-    INIT_PAYMENT_TERMS, 
-    SELECT_PAYMENT_TERM, 
-    CHANGE_PAYMENT_TYPE, 
-    CHANGE_INITIAL_PAYMENT, 
-    COMPUTE_PAYMENT_LINES,
-    RESET_PAYMENT
-} from '@/constants/actionTypes'
-
-const initialState = {
-    paymentTerms: [],
+const state = {
     loadingPaymentTerms: false,
-    selectedPaymentTerm: null,
+    paymentTerms: [],
+    paymentMethods: ['Efectivo', 'Banco'],
+    paymentTerm: null,
     paymentType: 'cash',
+    paymentMethod: 'Efectivo',
     initialPayment: 0,
+    paymentResidual: 0,
     paymentLines: []
 }
 
-const state = {
-    paymentTerms: initialState.paymentTerms,
-    loadingPaymentTerms: !initialState.loadingPaymentTerms,
-    selectedPaymentTerm: initialState.selectedPaymentTerm,
-    paymentType: initialState.paymentType,
-    initialPayment: initialState.initialPayment,
-    paymentResidual: initialState.paymentResidual,
-    paymentLines: initialState.paymentLines
-}
-
 const getters = {
-    /**
-     * 
-     * @param {*} state 
-     */
     paymentTerms(state) {
         return state.paymentTerms
     },
-    /**
-     * 
-     * @param {*} state 
-     */
+    paymentMethods(state) {
+        return state.paymentMethods.filter(p => p !== state.paymentMethod)
+    },
     loadingPaymentTerms(state) {
         return state.loadingPaymentTerms
     },
-    /**
-     * 
-     * @param {*} state 
-     */
-    selectedPaymentTerm(state) {
-        return state.selectedPaymentTerm
+    paymentTerm(state) {
+        return state.paymentTerm
     },
-    /**
-     * 
-     * @param {*} state 
-     */
     paymentType(state) {
         return state.paymentType
     },
-    /**
-     * 
-     * @param {*} state 
-     */
+    paymentMethod(state) {
+        return state.paymentMethod
+    },
     initialPayment(state) {
         return state.initialPayment
     },
-    /**
-     * 
-     * @param {*} state 
-     */
     paymentLines(state) {
         return state.paymentLines
     }
 }
 
 const mutations = {
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
-    [SET_PAYMENT_TERMS] (state, payload) {
+    setPaymentTerms(state, payload) {
         state.paymentTerms = payload
     },
-    /**
-     * 
-     * @param {*} state 
-     */
-    [SET_LOADING_PAYMENT_TERMS] (state, payload) {
+    setLoadingPaymentTerms(state, payload) {
         state.loadingPaymentTerms = !!payload
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
-    [AUTOSELECT_PAYMENT_TERM] (state, payload) {
+    autoSelectPaymentTerm(state, payload) {
         if (!payload || payload === 'cash') {
-            state.selectedPaymentTerm = state.paymentTerms.find(t => t.lines.length === 1 && t.lines[0].days === 0) || state.paymentTerms.find(t => t.lines.length === 1 && t.lines[0].days >= 0)
+            state.paymentTerm = state.paymentTerms.find(t => t.lines.length === 1 && t.lines[0].days === 0) || state.paymentTerms.find(t => t.lines.length === 1 && t.lines[0].days >= 0)
         } else {
-            state.selectedPaymentTerm = state.paymentTerms.find(t => t.lines[0].days > 0)
+            state.paymentTerm = state.paymentTerms.find(t => t.lines[0].days > 0)
         }
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
-    [SET_SELECTED_PAYMENT_TERM] (state, payload) {
+    setPaymentTerm(state, payload) {
         if (!payload) {
-            state.selectedPaymentTerm = payload
+            state.paymentTerm = payload
             return
         }
 
-        state.selectedPaymentTerm = state.paymentTerms.find(item => item.id === payload)
+        state.paymentTerm = state.paymentTerms.find(item => item.id === payload)
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
-    [SET_PAYMENT_TYPE] (state, payload) {
+    setPaymentType(state, payload) {
         state.paymentType = payload
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
-    [SET_INITIAL_PAYMENT] (state, payload) {
+    setPaymentMethod(state, payload) {
+        state.paymentMethod = payload
+    },
+    setInitialPayment(state, payload) {
         state.initialPayment = payload
     },
-    /**
-     * 
-     * @param {*} state 
-     * @param {*} payload 
-     */
-    [SET_PAYMENT_LINES] (state, payload) {
+    setPaymentLines(state, payload) {
         state.paymentLines = []
 
         if (!payload) {
@@ -151,12 +76,12 @@ const mutations = {
         }
 
         let percentPaid = state.initialPayment / payload.total
-        let distributedPercentage = -(percentPaid / state.selectedPaymentTerm.lines.length)
+        let distributedPercentage = -(percentPaid / state.paymentTerm.lines.length)
         let totals = []
         let residual = payload.total
         let dueDate = null
 
-        for (let line of state.selectedPaymentTerm.lines) {
+        for (let line of state.paymentTerm.lines) {
             dueDate = moment(payload.date).add(line.days + line.days2, 'days').format('YYYY-MM-DD')
 
             if(percentPaid && percentPaid < 1) {
@@ -164,7 +89,7 @@ const mutations = {
                 percentPaid = 0
 
                 if (dueDate === payload.date) {
-                    distributedPercentage = ((totals[0][1] - line.valueAmount) / (state.selectedPaymentTerm.lines.length - 1))
+                    distributedPercentage = ((totals[0][1] - line.valueAmount) / (state.paymentTerm.lines.length - 1))
                     continue
                 }
             }
@@ -197,68 +122,46 @@ const mutations = {
 }
 
 const actions = {
-    /**
-     * 
-     * @param {*} param0 
-     * @param {*} payload 
-     */
-    [INIT_PAYMENT_TERMS] ({ commit }, payload) {
-        commit(SET_PAYMENT_TERMS, payload)
-        commit(AUTOSELECT_PAYMENT_TERM)
-        commit(SET_LOADING_PAYMENT_TERMS)
+    initPaymentTerms({ commit }, payload) {
+        commit('setPaymentTerms', payload)
+        commit('autoSelectPaymentTerm')
+        commit('setLoadingPaymentTerms')
     },
-    /**
-     * 
-     * @param {*} param0 
-     * @param {*} payload 
-     */
-    [SELECT_PAYMENT_TERM] ({ commit }, payload) {
+    selectPaymentTerm({ commit }, payload) {
         if (!payload) {
             return
         }
 
-        commit(SET_SELECTED_PAYMENT_TERM, payload)
+        commit('setPaymentTerm', payload)
     },
-    /**
-     * 
-     * @param {*} param0 
-     * @param {*} payload 
-     */
-    [CHANGE_PAYMENT_TYPE] ({ commit }, payload) {
-        commit(SET_PAYMENT_TYPE, payload)
-        commit(AUTOSELECT_PAYMENT_TERM, payload)
-        commit(SET_INITIAL_PAYMENT, 0)
-        commit(SET_PAYMENT_LINES)
+    changePaymentType({ commit }, payload) {
+        commit('setPaymentType', payload)
+        commit('autoSelectPaymentTerm', payload)
+        commit('setInitialPayment', 0)
+        commit('setPaymentLines')
+    },
+    changePaymentMethod({ commit, dispatch }, methodName) {
+        if (methodName === 'Banco') {
+            dispatch('toggleBankPayment')
+        }
+
+        commit('setPaymentMethod', methodName)
     },
-    /**
-     * 
-     * @param {*} param0 
-     * @param {*} payload 
-     */
-    [CHANGE_INITIAL_PAYMENT] ({ commit }, payload) {
-        commit(SET_INITIAL_PAYMENT, payload)
+    changeInitialPayment({ commit }, payload) {
+        commit('setInitialPayment', payload)
     },
-    /**
-     * 
-     * @param {*} param0 
-     * @param {*} payload 
-     */
-    [COMPUTE_PAYMENT_LINES] ({ commit, getters }) {
-        commit(SET_PAYMENT_LINES, {
+    computePaymentLines({ commit, getters }) {
+        commit('setPaymentLines', {
             date: getters.date,
             total: getters.cartTotal
         })
     },
-    /**
-     * 
-     * @param {*} param0 
-     */
-    [RESET_PAYMENT] ({ commit }) {
-        commit(SET_LOADING_PAYMENT_TERMS, true)
-        commit(SET_PAYMENT_TERMS, [])
-        commit(SET_SELECTED_PAYMENT_TERM, null)
-        commit(SET_PAYMENT_TYPE, 'cash')
-        commit(SET_INITIAL_PAYMENT, 0)
+    resetPayment({ commit }) {
+        commit('setLoading', true)
+        commit('setPaymentTerms', [])
+        commit('setPaymentTerm', null)
+        commit('setPaymentType', 'cash')
+        commit('setInitialPayment', 0)
     }
 }
 

+ 1 - 1
src/store/modules/product.js

@@ -191,7 +191,7 @@ const actions = {
      * @param {*} param0 
      * @param {*} payload 
      */
-    [SELECT_PRODUCT] ({ commit, dispatch }, payload) {
+    selectProduct({ commit, dispatch }, payload) {
         if (!payload) {
             commit(SET_PRODUCT_WITH_VARIANT, null)
             return

+ 6 - 27
src/store/mutations.js

@@ -1,40 +1,19 @@
-import { 
-    SET_MODE,
-    SET_PROCESSING,
-    SET_ASK_FOR_PRINT,
-    SET_COMPLETED,
-    SET_RESULT
- } from '@/constants/mutationTypes'
-
 const mutations = {
-    [SET_MODE] (state, payload) {
+    setMode(state, payload) {
         state.mode = payload
     },
-    /**
-     * 
-     */
-    [SET_PROCESSING] (state, payload) {
-        state.processing = payload
+    setLoading(state, loading) {
+        state.loading = loading
     },
-    /**
-     * 
-     */
-    [SET_ASK_FOR_PRINT] (state, payload) {
+    setAskForPrint(state, payload) {
         state.askForPrint = payload
     },
-    /**
-     * 
-     */
-    [SET_COMPLETED] (state, payload) {
+    setCompleted(state, payload) {
         state.completed = payload
     },
-    /**
-     * 
-     */
-    [SET_RESULT] (state, payload) {
+    setResult(state, payload) {
         state.result = payload
     }
-
 }
 
 export default mutations

+ 1 - 1
src/store/state.js

@@ -1,6 +1,6 @@
 const state = {
     mode: 'sale',
-    processing: false,
+    loading: true,
     completed: false,
     result: '',
     askForPrint: false,