Browse Source

[ADD] payment component

Gogs 7 years ago
parent
commit
1aeae3963c

+ 4 - 3
controllers/main.py

@@ -63,7 +63,7 @@ class Purchases(http.Controller):
                 'name': journal.currency.name,
                 'displayName': journal.currency.display_name
             },
-            'creditAccount': {
+            'defaultCreditAccount': {
                 'id': journal.default_credit_account_id.id,
                 'name': journal.default_credit_account_id.name,
                 'displayName': journal.default_credit_account_id.display_name,
@@ -85,7 +85,7 @@ class Purchases(http.Controller):
                     'displayName': journal.default_credit_account_id.currency_id.display_name
                 },
             },
-            'debitAccount': {
+            'defaultDebitAccount': {
                 'id': journal.default_debit_account_id.id,
                 'name': journal.default_debit_account_id.name,
                 'displayName': journal.default_debit_account_id.display_name,
@@ -108,7 +108,7 @@ class Purchases(http.Controller):
                 }
 
             }
-        } for journal in request.env['account.journal'].search([('type', 'in', ['bank', 'cash']), ('active', '=', True)])]
+        } for journal in request.env['account.journal'].search([('type', 'in', ['bank', 'cash']), ('default_debit_account_id.currency_id', '=', False), ('active', '=', True)], order='id')]
 
     '''
         Get all active suppliers
@@ -134,6 +134,7 @@ class Purchases(http.Controller):
             'displayName': product.display_name,
             'ean13': product.ean13,
             'imageMedium': product.image_medium,
+            'listPrice': product.list_price,
             'variantCount': product.product_variant_count,
             'variants': [{
                 'id': variant.id,

+ 12 - 3
src/App.vue

@@ -6,7 +6,9 @@
             tab-content(title='Qué productos comprarás?')
                 products-step
             tab-content(title='Cómo quieres pagar?')
-                h2 Pago
+                journal-step
+            tab-content(:title="selectedJournal && selectedJournal.type === 'cash' ? 'Qué monto vas a pagar?' : 'Tienes alguna referencia de pago?'")
+                payment-step
 </template>
 
 <script>
@@ -14,16 +16,23 @@
 
     import SupplierStep from '@/components/supplier/SupplierStep'
     import ProductsStep from '@/components/product/ProductsStep'
+    import JournalStep from '@/components/journal/JournalStep'
+    import PaymentStep from '@/components/payment/PaymentStep'
 
-    import { mapActions } from 'vuex'
+    import { mapGetters, mapActions } from 'vuex'
 
     export default {
         components: {
             FormWizard,
             TabContent,
             SupplierStep,
-            ProductsStep
+            ProductsStep,
+            JournalStep,
+            PaymentStep
         },
+        computed: mapGetters([
+            'selectedJournal'
+        ]),
         methods: mapActions([
             'initPurchase'
         ]),

+ 77 - 0
src/components/journal/JournalStep.vue

@@ -0,0 +1,77 @@
+<template lang="pug">
+    .purchase-step
+        .journal-selector
+            form.journal-form
+                .form-separator
+                    h3 Detalles del Cliente
+                    hr
+                .form-item
+                    label.form-label Cliente
+                    input.form-input(:value="(supplierSelected && supplierSelected.name) || ''" readonly)
+                .form-separator
+                    h3 Detalles del Pago
+                    hr
+                .form-item
+                    label.form-label Método de Pago
+                    select.form-input(v-model='journal')
+                        option(v-for='journal in journals' :value='journal') {{ journal.displayName }}
+</template>
+
+<script>
+    import { mapGetters, mapActions } from 'vuex'
+
+    export default {
+        computed: {
+            journal: {
+                get() {
+                    return this.selectedJournal
+                },
+                set(value) {
+                    this.selectJournal(value)
+                }
+            },
+            ...mapGetters([
+                'supplierSelected',
+                'journals',
+                'selectedJournal'
+            ])
+        },
+        methods: mapActions([
+            'selectJournal'
+        ])
+    }
+</script>
+
+<style lang="sass">
+    .purchase-step
+        .journal-selector
+            width: 100%
+            height: 100%
+            display: flex
+            align-items: center
+            justify-content: center
+            .journal-form
+                width: 600px
+                height: 100%
+                background: #f5f5f5
+                padding: 25px
+                .form-separator
+                    h3
+                        color: #9e9e9e
+                        font-size: 8pt
+                    hr
+                        margin-top: 5px
+                .form-item
+                    width: 100%
+                    height: 45px
+                    margin-bottom: 15px
+                    .form-label
+                        width: 200px
+                        height: 45px
+                        font-size: 14pt
+                    .form-input
+                        width: 350px
+                        height: 45px
+                        font-size: 14pt
+                        border-radius: 0
+</style>

+ 82 - 0
src/components/payment/PaymentStep.vue

@@ -0,0 +1,82 @@
+<template lang="pug">
+    .purchase-step
+        .payment-wrapper
+            form.payment-form
+                .form-separator
+                    h3 Detalles del Pago
+                    hr
+                    .cash-payment(v-if="selectedJournal.type === 'cash'")
+                        .form-item
+                            label.form-label Monto a pagar
+                            input.form-input(:value='cartTotal' readonly)
+                        .form-item
+                            label.form-label Total recibido
+                            input.form-input(:value='amount' v-model='amount' autofocus)
+                        hr
+                        .form-item
+                            label.form-label Total a devolver
+                            input.form-input(:value='amountResidual' readonly)
+                    .bank-payment(v-else) Algo aquí
+</template>
+
+
+<script>
+    import { mapGetters, mapActions } from 'vuex'
+
+    export default {
+        computed: {
+            amount: {
+                get() {
+                    return this.amountPaid
+                },
+                set(value) {
+                    this.changeAmountPaid(value)
+                }
+            },
+            ...mapGetters([
+                'selectedJournal',
+                'cartTotal',
+                'amountPaid',
+                'amountResidual'
+            ])
+        },
+        methods: mapActions([
+            'changeAmountPaid'
+        ])
+    }
+
+</script>
+
+<style lang="sass">
+    .purchase-step
+        .payment-wrapper
+            width: 100%
+            height: 100%
+            display: flex
+            align-items: center
+            justify-content: center
+            .payment-form
+                width: 600px
+                height: 100%
+                background: #f5f5f5
+                padding: 25px
+                .form-separator
+                    h3
+                        color: #9e9e9e
+                        font-size: 8pt
+                    hr
+                        margin-top: 5px
+                .form-item
+                    width: 100%
+                    height: 45px
+                    margin-bottom: 15px
+                    .form-label
+                        width: 200px
+                        height: 45px
+                        font-size: 14pt
+                    .form-input
+                        width: 350px
+                        height: 45px
+                        font-size: 14pt
+                        border-radius: 0
+</style>

+ 6 - 2
src/components/product/Cart.vue

@@ -1,7 +1,7 @@
 <template lang="pug">
     .cart
         .cart-total
-            h2.currency-cart-total
+            h2.currency-cart-total {{ cartTotal }}
         .cart-items-wrapper
             transition-group(name='list' tag='ul' class='cart-items')
                 cart-item(v-for='item in cartItems' :key='item.id' :item='item')
@@ -14,7 +14,11 @@
     export default {
         components: {
             CartItem
-        }
+        },
+        computed: mapGetters([
+            'cartTotal',
+            'cartItems'
+        ])
     }
 </script>
 

+ 55 - 8
src/components/product/CartItem.vue

@@ -1,11 +1,16 @@
 <template lang="pug">
     li.cart-item
-        h3.item-name
-        input.item-quantity
+        h3.item-name {{ item.displayName }}
+        input.item-quantity(:value='quantity' v-model='quantity' number)
         span.item-x x
-        span.item-price
+        span.item-price {{ item.price }}
         span.item-equals =
-        span.item-subtotal
+        span.item-subtotal {{ item.price * item.qty }}
+        .cart-item-options-wrapper
+            .cart-item-options
+                .cart-item-option(class='fa fa-plus' @click='addToCart(item)')
+                .cart-item-option(class='fa fa-minus' @click='decrementFromCart(item)')
+                .cart-item-option(class='fa fa-trash' @click='removeFromCart(item)')
 </template>
 
 <script>
@@ -25,14 +30,20 @@
                     return this.item.qty || 1
                 },
                 set(value) {
-                    this.item.quantity = value || 1
+                    this.item.qty = value || 1
                 }
             }
         },
+        methods: {
+            ...mapActions([
+                'addToCart',
+                'decrementFromCart',
+                'removeFromCart'
+            ])
+        },
         mounted() {
             this.$set(this.item, 'qty', 1)
-            this.$set(this.item, 'price', this.item.list_price)
-            this.$set(this.item, 'discount', 0)
+            this.$set(this.item, 'price', this.item.listPrice)
         }
     }
 </script>
@@ -40,7 +51,7 @@
 <style lang="sass">
     .cart-item
         width: 100%
-        height: 90px
+        height: 85px
         list-style: none outside none
         border-bottom: 1px solid #d3d3d3
         box-sizing: border-box
@@ -63,6 +74,12 @@
             text-align: right
             float: left
         .item-x
+            width: 20px
+            height: 20px
+            margin-top: 12px
+            text-align: right
+            float: left
+        .item-price
             width: 80px
             height: 20px
             margin-top: 12px
@@ -81,4 +98,34 @@
             padding-right: 15px
             text-align: right
             font-weight: bold
+        .cart-item-options-wrapper
+            width: 100%
+            height: 20px
+            position: absolute
+            bottom: 0
+            display: flex
+            justify-content: center
+            .cart-item-options
+                width: 90px
+                height: 20px
+                border: 1px solid #d3d3d3
+                border-bottom: none
+                display: flex
+                justify-content: center
+                .cart-item-option
+                    width: 18px
+                    height: 18px
+                    margin: 0 5px
+                    color: #666
+                    &:hover
+                        cursor: pointer
+                    &.fa
+                        padding-left: 2px
+                        line-height: 20px
+                        &.fa-plus:hover
+                            color: #2196f3
+                        &.fa-minus:hover
+                            color: #ffc107
+                        &.fa-trash:hover
+                            color: #f44336
 </style>

+ 1 - 1
src/components/product/ProductCard.vue

@@ -18,7 +18,7 @@
         },
         methods: {
             getPrice() {
-                return 0
+                return this.item.listPrice
             },
             ...mapActions([
                 'selectProduct'

+ 1 - 1
src/components/supplier/SupplierDetails.vue

@@ -2,7 +2,7 @@
     .supplier-details
         form.supplier-form
             .form-separator
-                h3 Detalles generales
+                h3 Detalles Generales
                 hr
             .form-item
                 label.form-label Nombre

+ 2 - 1
src/store/index.js

@@ -27,7 +27,8 @@ const store = new Vuex.Store({
         cart,
         picking,
         payment
-    }
+    },
+    strict: false
 })
 
 export default store

+ 30 - 6
src/store/modules/cart.js

@@ -21,7 +21,7 @@ const getters = {
      * 
      * @param {*} state 
      */
-    total(state) {
+    cartTotal(state) {
         return state.cartTotal.value
     }
 }
@@ -52,19 +52,36 @@ const mutations = {
         let productFound = state.cartItems.values.find(item => item.id === payload.id)
 
         if(productFound) {
-            payload.qty = payload.qty + 1
+            payload.qty = (payload.qty || 0) + 1
             return
         }
 
         state.cartItems.values = [payload, ...state.cartItems.values]
     },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    removeFromCart(state, payload) {
+        let foundIndex = state.cartItems.values.findIndex(item => item.id === payload.id)
+        state.cartItems.values.splice(foundIndex, 1)
+    },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    decrementFromCart(state, payload) {
+        let productFound = state.cartItems.values.find(item => item.id === payload.id)
+        productFound.qty = productFound.qty - 1
+    },
     /**
      * 
      * @param {*} state 
      */
     computeTotal(state) {
-        console.log(state.cartTotal)
-        state.cartTotal.value = state.cartItems.values.reduce((total, value) => total + ((value.price || value.listPrice) * (value.qty || 1)), 0)
+        state.cartTotal.value = state.cartItems.values.reduce((sum, item) => sum + ((item.price || item.listPrice) * (item.qty || 1)), 0)
     }
 }
 
@@ -84,7 +101,8 @@ const actions = {
      * @param {*} payload 
      */
     removeFromCart({ commit }, payload) {
-        console.log(payload)
+        commit('removeFromCart', payload)
+        commit('computeTotal')
     },
     /**
      * Decrement item quantity from cart
@@ -92,7 +110,13 @@ const actions = {
      * @param {*} payload 
      */
     decrementFromCart({ commit }, payload) {
-        console.log(payload)
+        if (payload.qty > 1) {
+            commit('decrementFromCart', payload)
+        } else {
+            commit('removeFromCart', payload)
+        }
+
+        commit('computeTotal')
     }
 }
 

+ 28 - 3
src/store/modules/journal.js

@@ -2,6 +2,10 @@ const state = {
     journals: {
         default: [],
         values: this.default
+    },
+    selectedJournal: {
+        default: null,
+        value: null
     }
 }
 
@@ -12,13 +16,34 @@ const getters = {
      */
     journals(state) {
         return state.journals.values
+    },
+    /**
+     * 
+     * @param {*} state 
+     */
+    selectedJournal(state) {
+        return state.selectedJournal.value
     }
 }
 
 const mutations = {
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
     setJournals(state, payload) {
         state.journals.values = [...payload]
-    }
+        state.selectedJournal.value = state.journals.values.find(item => item.type === 'cash')
+    },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    setSelectedJournal(state, payload) {
+        state.selectedJournal.value = payload
+    },  
 }
 
 const actions = {
@@ -27,8 +52,8 @@ const actions = {
      * @param {*} param0 
      * @param {*} payload 
      */
-    setJournals({ commit }, payload) {
-        commit('setJournals', payload)
+    selectJournal({ commit }, payload) {
+        commit('setSelectedJournal', payload)
     }
 }
 

+ 57 - 2
src/store/modules/payment.js

@@ -2,6 +2,14 @@ const state = {
     paymentTerms: {
         default: [],
         values: this.default
+    },
+    amountPaid: {
+        default: 0,
+        value: 0
+    },
+    amountResidual: {
+        default: 0,
+        value: 0
     }
 }
 
@@ -13,6 +21,20 @@ const getters = {
      */
     paymentTerms(state) {
         return state.paymentTerms.values
+    },
+    /**
+     * 
+     * @param {*} state 
+     */
+    amountPaid(state) {
+        return state.amountPaid.value
+    },
+    /**
+     * 
+     * @param {*} state 
+     */
+    amountResidual(state) {
+        return state.amountResidual.value
     }
 }
 
@@ -24,12 +46,45 @@ const mutations = {
      */
     setPaymentTerms(state, payload) {
         state.paymentTerms.values = [...payload]
+    },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    setAmountPaid(state, payload) {
+        state.amountPaid.value = payload
+    },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    computeAmountResidual(state, payload) {
+        state.amountResidual.value = payload.paymentAmount >= payload.totalAmount ? payload.paymentAmount - payload.totalAmount : 0
+    },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    setAmountResidual(state, payload) {
+        state.amountResidual.value = payload
     }
 }
 
 const actions = {
-    setPaymentTerms({ commit }, payload) {
-        commit('setPaymentTerms', payload)
+    /**
+     * 
+     * @param {*} param0 
+     * @param {*} payload 
+     */
+    changeAmountPaid({ commit, getters }, payload) {
+        commit('setAmountPaid', payload)
+        commit('computeAmountResidual', {
+            totalAmount: getters.cartTotal,
+            paymentAmount: payload
+        })
     }
 }
 

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

@@ -7,7 +7,7 @@ const state = {
         default: [],
         values: []
     },
-    productVariant: {
+    productWithVariant: {
         default: null,
         value: null
     }
@@ -25,8 +25,8 @@ const getters = {
      * 
      * @param {*} state 
      */
-    selectedProduct(state) {
-        return state.selectedProduct.value
+    productWithVariant(state) {
+        return state.productWithVariant.value
     }
 }
 
@@ -44,8 +44,8 @@ const mutations = {
      * @param {*} state 
      * @param {*} payload 
      */
-    setProductVariant(state, payload) {
-        state.productVariant.value = value
+    setProductWithVariant(state, payload) {
+        state.productWithVariant.value = value
     }
 }
 
@@ -65,11 +65,11 @@ const actions = {
      */
     selectProduct({ commit, dispatch }, payload) {
         if (payload.variantCount > 1) {
-            commit('setProductVariant', payload)
+            commit('setProductWithVariant', payload)
             return
         }
 
-        dispatch('addToCart', payload)
+        dispatch('addToCart', payload.variants[0])
     },
     /**
      *