Pārlūkot izejas kodu

[ADD] stock picking

robert 6 gadi atpakaļ
vecāks
revīzija
7e02dd91a4

+ 3 - 2
controllers/account_invoice.py

@@ -8,14 +8,15 @@ _MODEL = 'account.invoice'
 
 '''
 '''
-def create_invoice(sale_order_id, currency_id, date_today):
+def create_invoice(sale_order_id, currency_id, date_today, picking_done=True):
     sale_order = request.env['sale.order'].browse(sale_order_id)
     invoice_id = sale_order.action_invoice_create()
     invoice = request.env[_MODEL].browse(invoice_id)
 
     for picking in sale_order.picking_ids:
         picking.force_assign()
-        picking.action_done()
+        if picking_done:
+            picking.action_done()
 
     date_due = parse(date_today) + rd(days=max(invoice.payment_term.line_ids.mapped(lambda x: x.days + x.days2)))
 

+ 67 - 5
controllers/main.py

@@ -41,6 +41,7 @@ class PosSales(http.Controller):
         from res_bank_cheque_type import get_cheque_types
         from res_store import get_stores
         from sale_order import get_sale_orders
+        from stock_picking import get_pickings
 
         # Logic 
         check_base_currency()
@@ -81,6 +82,7 @@ class PosSales(http.Controller):
             data = {
                 'saleOrders': get_sale_orders(),
                 'currencies': get_currencies_from_journals(),
+                'customers': get_customers(image_type=config.get('imageType')),
                 'journals': get_journals(),
                 'paymentTerms': get_payment_terms(),
                 'banks': get_banks(),
@@ -91,7 +93,9 @@ class PosSales(http.Controller):
 
         # Take data for delivery
         if mode == 'product_delivery':
-            data = {}
+            data = {
+                'stockPickings': get_pickings()
+            }
     
         return make_gzip_response(data)
 
@@ -164,6 +168,7 @@ class PosSales(http.Controller):
 
         # Imports
         from server_datetime import get_date, get_datetime
+        from account_journal import get_currency
         
         '''
         ╔═╗╦╔╗╔╦╔═╗╦ ╦  ╔╗ ╦ ╦╔╦╗╔═╗╔═╗╔╦╗  ╔═╗╔═╗╔═╗  ╔═╗╦═╗╔═╗╔═╗╔═╗╔╦╗╦ ╦╦═╗╔═╗
@@ -177,6 +182,10 @@ class PosSales(http.Controller):
 
             # Get currency
             currency_id = get_currency(journal_id)
+
+            if not currency_id:
+                currency_id = request.env.user.company_id.currency_id.id
+
             self.make_info_log('[OK] Getting journal')
 
             # Create sale order
@@ -268,8 +277,57 @@ class PosSales(http.Controller):
         ╠╣ ║║║║║╚═╗╠═╣  ╠═╝╠═╣╚╦╝║║║║╣ ║║║ ║ 
         ╚  ╩╝╚╝╩╚═╝╩ ╩  ╩  ╩ ╩ ╩ ╩ ╩╚═╝╝╚╝ ╩ 
         '''
-        def finish_payment():
-            pass
+        def finish_payment(sale_order_id, currency_id, date_now, payment_term_id, payment, payment_method, bank_payment_data):
+            # Imports
+            from account_invoice import (
+                create_invoice, 
+                create_invoice_move_lines,
+                number_invoice,
+                close_invoice
+            )
+            from account_move import create_account_move
+            from account_voucher import create_account_voucher
+            from account_bank_statement import create_bank_statement
+            from res_bank_payment import create_bank_payment_statement
+
+            # Payment term
+            sale_order = request.env['sale.order'].browse(sale_order_id)
+            sale_order.write({
+                'payment_term': payment_term_id
+            })
+
+            # Create invoice
+            invoice = create_invoice(sale_order_id, currency_id, date_now, False)
+            self.make_info_log('[OK] Creating invoice')
+
+            # Create invoice move lines
+            invoice_move_lines = create_invoice_move_lines(invoice.id, payment, date_now)
+            self.make_info_log('[OK] Creating invoice move lines')
+
+            # Create account move
+            account_move = create_account_move(invoice.id, invoice_move_lines)
+            self.make_info_log('[OK] Creating account move')
+
+            # Number invoice
+            number_invoice(invoice.id)
+            self.make_info_log('[OK] Number invoice')
+
+            # Create account voucher
+            account_voucher = create_account_voucher(account_move.id, journal_id, currency_id, payment)
+            self.make_info_log('[OK] Creating account voucher')
+
+            # Close invoice
+            close_invoice(invoice.id)
+            self.make_info_log('[OK] Closing invoice')
+
+            # Create bank statement
+            create_bank_statement(account_voucher.id, date_now)
+            self.make_info_log('[OK] Creating account bank statement')
+            
+            # Create bank payment statement
+            if payment_method == 'Banco':
+                create_bank_payment_statement(bank_payment_data, invoice.id, account_voucher.id)
+                self.make_info_log('[OK] Creating bank payment statement')
 
         '''
         ╔═╗╦╔╗╔╦╔═╗╦ ╦  ╔═╗╦═╗╔═╗╔╦╗╦ ╦╔═╗╔╦╗  ╔╦╗╔═╗╦  ╦╦  ╦╔═╗╦═╗╦ ╦
@@ -284,6 +342,7 @@ class PosSales(http.Controller):
         ╠═╝╠╦╝║ ║║  ║╣ ╚═╗╚═╗  ╠╣ ║║║║║╚═╗╠═╣   ║║║╣ ║  ║╚═╗║║ ║║║║
         ╩  ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝  ╚  ╩╝╚╝╩╚═╝╩ ╩  ═╩╝╚═╝╚═╝╩╚═╝╩╚═╝╝╚╝
         '''
+
         data = kw.get('data', [])
         date_now = get_date()
 
@@ -298,7 +357,7 @@ class PosSales(http.Controller):
             bank_payment_data = row.get('bankPaymentData', {})
 
             if mode == 'budget':
-                finish_budget_pos(journal_id, customer_id, cart_items, date_now, currency_id, payment_term_id)
+                finish_budget_pos(journal_id, customer_id, cart_items, date_now, payment_term_id)
 
             if mode == 'sale':
                 finish_sale_pos(journal_id, customer_id, cart_items, date_now, payment_term_id, payment, payment_method, bank_payment_data)
@@ -307,7 +366,10 @@ class PosSales(http.Controller):
                 finish_process_picking(journal_id, customer_id, cart_items, date_now, payment_term_id)
 
             if mode == 'payment':
-                finish_payment()
+                sale_order_id = row.get('saleOrderId', None)
+                currency_id = row.get('currencyId', None)
+
+                finish_payment(sale_order_id, currency_id, date_now, payment_term_id, payment, payment_method, bank_payment_data)
             
             if mode == 'product_delivery':
                 finish_product_delivery()

+ 14 - 4
controllers/sale_order.py

@@ -17,16 +17,26 @@ def get_sale_orders():
             'id': sale_order.id,
             'name': sale_order.display_name,
             'createDate': sale_order.create_date,
-            'partnerId': sale_order.partner_id.id,
+            'partner': {
+                'id': sale_order.partner_id.id,
+                'name': sale_order.partner_id.display_name,
+                'image': sale_order.partner_id.image_medium or None,
+                'ruc': sale_order.partner_id.ruc or None,
+                'phone': sale_order.partner_id.phone or None,
+                'mobile': sale_order.partner_id.mobile or None,
+                'email': sale_order.partner_id.email or None
+            },
             'userId': sale_order.user_id.id,
             'warehouseId': sale_order.warehouse_id.id,
             'amountTotal': sale_order.amount_total,
             'lines': [
                 {
-                    'productId': line.product_id.id,
-                    'productTmplId': line.product_tmpl_id.id,
-                    'priceUnit': line.price_unit,
+                    'id': line.product_id.id,
+                    'name': line.product_id.display_name,
+                    'listPrice': line.product_id.list_price,
                     'quantity': line.product_uom_qty,
+                    'price': line.product_id.list_price,
+                    'discount': 0
                 } for line in sale_order.order_line
             ]
         } for sale_order in request.env[_MODEL].search(domain)

+ 27 - 0
controllers/stock_picking.py

@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+from openerp.http import request
+
+_MODEL = 'stock.picking'
+
+def pick_assign(sale_order_id, picking_done=True):
+    sale_order = request.env['sale.order'].browse(sale_order_id)
+
+    for picking in sale_order.picking_ids:
+        picking.force_assign()
+        if picking_done:
+            picking.action_done()
+
+def get_pickings():
+    sale_orders = request.env['sale.order'].search([('from_pos', '=', True)])
+    sale_orders = sale_orders.mapped(lambda x: x.name)
+
+    return [
+        {
+            'id': sp.id,
+            'name': sp.display_name,
+            'origin': sp.origin
+        } for sp in request.env[_MODEL].search([
+            ('origin', 'in', sale_orders),
+            ('state', '=', 'assigned')
+        ])
+    ]

+ 2 - 0
package.json

@@ -32,6 +32,8 @@
 	"dependencies": {
 		"axios": "^0.17.1",
 		"fuse.js": "^3.2.0",
+		"install": "^0.12.1",
+		"velocity-animate": "^2.0.5",
 		"vue": "^2.5.13",
 		"vue-form-wizard": "^0.8.2",
 		"vue-js-modal": "^1.3.9",

+ 60 - 41
src/App.vue

@@ -6,38 +6,56 @@
             color='#7c7bad'
             ref='wizard'
         )
-            tab-content(
-                v-if='isSale || isSaleProductPicking'
-                title='Qué productos necesita?'
-                :beforeChange='checkCart'
-            )
-                product-step
-            tab-content(
-                v-if='isSale || isSaleProductPicking'
-                title='Quién es el cliente?'
-                :beforeChange='checkCustomer'
-            )
-                customer-step
-            tab-content(
-                v-if='isSalePayment'
-                title='Qué presupuesto es?'
-            )
-                budget-step             
-            tab-content(
-                v-if='isSale || isSalePayment'
-                title='Cómo quieres pagar?'
-            )
-                payment-step
-            tab-content(
-                v-if='isSaleDelivery',
-                title='Cuál es la venta?'
-            )
-                delivery-step
-            tab-content(
-                v-if='isSaleDelivery'
-                title='Entrega de productos'
-            )
-                delivery-step
+            // Sale or Budget
+            template(v-if='isSale')
+                tab-content(
+                    title='Qué productos necesita?'
+                    :beforeChange='checkCart',
+                )
+                    product-step
+                tab-content(
+                    title='Quién es el cliente?'
+                    :beforeChange='checkCustomer'
+                )
+                    customer-step
+                tab-content(
+                    title='Cómo quieres pagar?'
+                )
+                    payment-step
+            // Step 1
+            template(v-else-if='isSaleProductPicking')
+                tab-content(
+                    title='Qué productos necesita?'
+                    :beforeChange='checkCart',
+                )
+                    product-step
+                tab-content(
+                    title='Quién es el cliente?'
+                    :beforeChange='checkCustomer'
+                )
+                    customer-step
+            // Step 2
+            template(v-else-if='isSalePayment')
+                tab-content(
+                    title='Qué presupuesto es?'
+                    :beforeChange='checkSaleOrder'
+                )
+                    budget-step
+                tab-content(
+                    title='Cómo quieres pagar?'
+                )
+                    payment-step
+            // Step 3
+            template(v-else='isSaleDelivery')
+                tab-content(
+                    title='Cuál es la venta?'
+                )
+                    delivery-step
+                tab-content(
+                    title='Entrega de productos'
+                )
+                    delivery-step
+            // Footer
             template(
                 slot='footer'
                 slot-scope='props'
@@ -95,17 +113,17 @@
 
     import SettingsModal from './components/modals/SettingsModal'
     import {
-        Product as ProductStep, 
-        Customer as CustomerStep, 
-        Budget as BudgetStep, 
+        Product as ProductStep,
+        Customer as CustomerStep,
+        Budget as BudgetStep,
         Payment as PaymentStep,
         Delivery as DeliveryStep
     } from './components/steps'
-    import { 
-        LoadingOverlay, 
-        SettingsButton, 
-        InputSelect, 
-        ConnectionStatus 
+    import {
+        LoadingOverlay,
+        SettingsButton,
+        InputSelect,
+        ConnectionStatus
     } from './components/common'
 
     export default {
@@ -175,6 +193,7 @@
                 'initProcess',
                 'checkCart',
                 'checkCustomer',
+                'checkSaleOrder',
                 'toggleSettingsVisibility',
                 'changeSetting',
                 'changeInitialPayment',
@@ -189,7 +208,7 @@
                 if (!value) {
                     return
                 }
-                
+
                 this.$refs.wizard.changeTab(2, 0, false)
                 this.resetProcess()
             }

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

@@ -3,7 +3,8 @@
         :class="{ 'selected-card': isSelected }"
         @click='onClick'
     )
-        h2.card-title {{ title }}
+        .card-title
+            h2.card-title-item(v-for='t in getTitle()') {{ t }}
         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')
             span(v-for='detail in details') {{ computeDetail(detail) }}
@@ -13,7 +14,7 @@
     export default {
         props: {
             title: {
-                type: String,
+                type: String || Array,
                 default: 'Sin título'
             },
             image: {
@@ -40,6 +41,13 @@
             }
         },
         methods: {
+            getTitle() {
+                if (typeof this.title === 'string') {
+                    return [this.title]
+                }
+
+                return this.title
+            },
             computeDetail(detail) {
                 if (detail.format === 'currency') {
                     return this.$options.filters.currency(detail.value, {...this.currencyOptions})
@@ -71,13 +79,17 @@
             cursor: pointer
         .card-title
             width: 100%
-            height: 30px
-            font-size: 9pt
-            text-align: center
-            margin-top: 10px
+            height: 60px
             position: absolute
             top: 0
             z-index: 1
+            .card-title-item
+                font-size: 8pt
+                text-align: center
+                margin-top: 10px
+                margin-bottom: 0
+                &:nth-child(2n)
+                    margin-top: 5px
         .card-image
             width: 75px
             height: 75px

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

@@ -5,21 +5,29 @@
                 v-if='canAdd'
                 @onClickAdd='onClickAdd'
             )
+            //- transition-group(
+            //-     name='card-fade'
+            //-     v-bind:css='false'
+            //-     v-on:before-enter='onBeforeEnter'
+            //-     v-on:enter='onEnter'
+            //-     v-on:leave='onLeaver'
+            //- )
             card(
                 v-for='item in items'
                 :key='item.id'
-                :title='item.name'
-                :image='item.image'
+                :title='getHeader(item)'
+                :image='getImage(item)'
                 :isSelected='item.id === selectedId'
-                :details='computeDetails(item)'
+                :details='getFooter(item)'
                 :currencyOptions='currencyOptions'
                 @onClick='onClickCard(item)'
             )
-        .no-items
+        .no-items(v-show='!items || items.length == 0')
             p No hay items
 </template>
 
 <script>
+    import Velocity from 'velocity-animate'
     import AddCard from '@/components/common/AddCard'
     import Card from '@/components/common/Card'
     import Spinner from '@/components/common/Spinner'
@@ -34,7 +42,15 @@
                 type: Boolean,
                 default: false
             },
-            details: {
+            headerKeys: {
+                type: Array,
+                default: []
+            },
+            imageKey: {
+                type: String,
+                default: null
+            },
+            footerKeys: {
                 type: Array,
                 default: []
             },
@@ -60,17 +76,45 @@
             }
         },
         methods: {
-            computeDetails(item) {
-                if (!this.details) {
+            getHeader(item) {
+                if (this.headerKeys.length == 0) {
+                    return item.name
+                }
+
+                return this.headerKeys.map(key => {
+                    let value = item
+
+                    for (let k of key.split('.')) {
+                        value = value[k]
+                    }
+
+                    return value
+                })
+            },
+            getImage(item) {
+                if (!this.imageKey) {
+                    return item.image 
+                }
+
+                let image = item
+
+                for (let part of this.imageKey.split('.')) {
+                    image = image[part]
+                }
+
+                return image
+            },
+            getFooter(item) {
+                if (!this.footerKeys) {
                     return []
                 }
 
-                if (this.details.length === 0) {
+                if (this.footerKeys.length === 0) {
                     return []
                 }
 
                 let results = []
-                let computableDetails = this.details.map(item => item.split(/:/))
+                let computableDetails = this.footerKeys.map(item => item.split(/:/))
 
                 for (let detail of computableDetails) {
                     for (let field in item) {
@@ -114,6 +158,34 @@
                     this.defaultOptions.currency[key] = value[key]
                 }
             },
+            onBeforeEnter(el) {
+                el.style.opacity = 0
+                el.style.width = 0
+            },
+            onEnter(el, done) {
+                let delay = el.dataset.index * 150
+
+                setTimeout(() => {
+                    Velocity(el, {
+                        opacity: 1,
+                        width: '130px'
+                    }, {
+                        complete: done
+                    })
+                }, delay)
+            },
+            onLeave(el, done) {
+                let delay = el.dataset.index * 150
+
+                setTimeout(() => {
+                    Velocity(el, {
+                        opacity: 0,
+                        width: 0
+                    }, {
+                        complete: done
+                    })
+                }, delay)
+            },
             onClickAdd() {
                 this.$emit('onAdd')
             },

+ 17 - 4
src/components/common/Searcher.vue

@@ -107,11 +107,23 @@
                                 continue
                             }
 
-                            if (this.keys.length !== 0 && this.keys.indexOf(field) === -1) {
-                                continue
+                            let fieldValue = null
+                            let finded = false
+
+                            for (let key of this.keys) {
+                                fieldValue = item
+
+                                for (let k of key.split('.')) {
+                                    fieldValue = fieldValue[k]
+                                }
+
+                                if (!!fieldValue && fieldValue.toLowerCase().indexOf(value.toLowerCase()) !== -1) {
+                                    finded = true
+                                    break
+                                }
                             }
 
-                            if (item[field].toLowerCase().indexOf(value.toLowerCase()) !== -1) {
+                            if (finded) {
                                 this.results.push(item)
                                 break
                             }
@@ -124,7 +136,8 @@
             return {
                 fuse: null,
                 search: '',
-                results: []
+                results: [],
+                lastTime: 0 
             }
         },
         mounted() {

+ 88 - 3
src/components/steps/Budget.vue

@@ -2,18 +2,69 @@
     .pos-step
         .budget-selector-step
             .budget-selector
-                searcher
-                card-grid
+                searcher(
+                    mode='normal'
+                    :items='saleOrders'
+                    :keys="['name', 'partner.name']"
+                    @onSearch='filterSaleOrders'
+                )
+                card-grid(
+                    imageKey='partner.image'
+                    :items='visibleSaleOrders'
+                    :headerKeys="['name', 'partner.name']"
+                    :footerKeys="['amountTotal:c']"
+                    :loading='loadingSaleOrders'
+                    @onSelect='selectSaleOrder'
+                )
+            transition(name='slide-fade')
+                form.sale-order-form(v-if='!!selectedSaleOrder')
+                    .form-separator
+                        h3 Detalles Generales
+                        hr
+                    .form-item
+                        label.form-label Descripción
+                        input.form-input(v-model='selectedSaleOrder.name' readonly)
+                    .form-item
+                        label.form-label Monto
+                        input.form-input(v-model='selectedSaleOrder.amountTotal' readonly)
+                    .form-separator
+                        h3 Items
+                        hr
+                    .form-item
+                        table
+                            thead
+                                tr
+                                    th Descripción
+                                    th Precio
+                                    th Cantidad
+                            tbody
+                                tr(v-for='item in cartItems')
+                                    td {{ item.name }}
+                                    td {{ item.price }}
+                                    td {{ item.quantity }}
 </template>
 
 <script>
+    import { mapGetters, mapActions } from 'vuex'
     import { Searcher, CardGrid } from '../common'
 
     export default {
         components: {
             Searcher,
             CardGrid
-        }
+        },
+        computed: mapGetters([
+            'saleOrders',
+            'visibleSaleOrders',
+            'customers',
+            'selectedSaleOrder',
+            'cartItems',
+            'loadingSaleOrders'
+        ]),
+        methods: mapActions([
+            'filterSaleOrders',
+            'selectSaleOrder'
+        ])
     }
 </script>
 
@@ -26,4 +77,38 @@
             .budget-selector
                 width: 100%
                 height: 100%
+            .sale-order-form
+                width: 380px
+                height: 100%
+                margin-right: 0
+                .form-separator
+                    h3
+                        color: #9e9e9e
+                        font-size: 8pt
+                    hr
+                        margin-top: 5px
+                .form-item
+                    width: 100%
+                    margin-bottom: 15px
+                    height: 35px
+                    .form-label
+                        width: 30%
+                        height: 35px
+                        font-size: 10pt
+                    .form-input
+                        width: 70%
+                        height: 35px
+                        font-size: 10pt
+                        border-radius: 0
+                    table
+                        width: 100%
+                        tr
+                            background: #fff
+                            th, td
+                                font-size: 8pt
+            .slide-fade-enter-active
+                transition: all 300ms ease
+            .slide-fade-enter
+                transform: translateX(300px)
+                opacity: 0
 </style>

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

@@ -3,6 +3,7 @@
         .customer-selection-step
             .customer-selector
                 searcher(
+                    mode='normal'
                     :items='customers'
                     :keys="['name', 'phone', 'mobile', 'email']"
                     @onSearch='filterCustomers'
@@ -71,7 +72,7 @@
                 width: 100%
                 height: 100%
             .slide-fade-enter-active
-                transition: all 300ms ease;
+                transition: all 300ms ease
             .slide-fade-enter
                 transform: translateX(300px)
                 opacity: 0

+ 23 - 3
src/components/steps/Delivery.vue

@@ -2,18 +2,38 @@
     .pos-step
         .sale-selector-step
             .sale-selector
-                searcher
-                card-grid
+                searcher(
+                    mode='normal'
+                    :items='stockPickings'
+                    :keys="['name', 'origin']"
+                    @onSearch='filterStockPickings'
+                )
+                card-grid(
+                    :items='visibleStockPickings'
+                    :footerKeys="['origin']"
+                    :loading='loadingStockPickings'
+                    @onSelect='selectStockPicking'
+                )
 </template>
 
 <script>
+    import { mapGetters, mapActions } from 'vuex'
     import { Searcher, CardGrid } from '../common'
 
     export default {
         components: {
             Searcher,
             CardGrid
-        }
+        },
+        computed: mapGetters([
+            'stockPickings',
+            'visibleStockPickings',
+            'loadingStockPickings'
+        ]),
+        methods: mapActions([
+            'filterStockPickings',
+            'selectStockPicking'
+        ])
     }
 </script>
 

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

@@ -10,7 +10,7 @@
             card-grid(
                 @onAdd='showProductForm'
                 :items='visibleProducts'
-                :details="['price:c']"
+                :footerKeys="['price:c']"
                 :currencyOptions='baseCurrency'
                 :loading='loadingProducts'
                 @onSelect='selectProduct'

+ 10 - 29
src/store/actions.js

@@ -5,12 +5,8 @@ const actions = {
         openerp.web.notification.do_warn('Atención', message)
         return false
     },
-    initProcess({ getters, commit, dispatch }, payload) {
-        if (!payload) {
-            return
-        }
-
-        commit('setMode', payload || getters.mode)
+    initProcess({ getters, commit, dispatch }, mode) {
+        commit('setMode', mode || getters.mode)
         commit('setResult', '')
         
         commit('setLoading', true)
@@ -80,6 +76,9 @@ const actions = {
 
         return !!getters.selectedCustomer || dispatch('notify', 'Necesitas seleccionar un cliente para continuar')
     },
+    checkSaleOrder({ getters, dispatch }) {
+        return !!getters.selectedSaleOrder || dispatch('notify', 'Necesitas seleccionar un presupuesto para continuar')
+    },
     checkPaymentMethod({ getters }) {
         if (getters.processing) {
             return dispatch('notify', 'Espere mientras se está procesando')
@@ -97,7 +96,7 @@ const actions = {
     toggleSettingsVisibility({ commit }) {
         commit('setSettingsVisibility')
     },
-    changeSetting({dispatch, commit}, setting) {
+    changeSetting({ dispatch, commit }, setting) {
         commit('setLoading', true)
 
         return axios.post('/eiru_sales/save_settings', {
@@ -167,37 +166,19 @@ const actions = {
             data = {
                 ...data,
                 total: getters.cartTotal,
+                saleOrderId: (getters.selectedSaleOrder && getters.selectedSaleOrder.id) || null, 
                 paymentTermId: getters.paymentTerm.id,
                 journalId: getters.selectedJournal.id,
                 payment: getters.initialPayment > getters.amountToPay ? getters.amountToPay : getters.initialPayment,
                 paymentMethod: getters.paymentMethod,
+                customerId: getters.selectedCustomer.id,
+                currencyId: getters.selectedCurrency.id,
                 bankPaymentData: {
                     ...getters.bankPaymentData
                 }
             }
         }
 
-        // const data = {
-        //     mode,
-        //     items: getters.cartItems.map(item => {
-        //         return {
-        //             id: item.id,
-        //             quantity: item.quantity,
-        //             price: item.price
-        //         }
-        //     }),
-        //     customerId: getters.selectedCustomer.id,
-        //     total: getters.cartTotal,
-        //     paymentTermId: getters.paymentTerm.id,
-        //     journalId: getters.selectedJournal.id,
-        //     payment: getters.initialPayment > getters.amountToPay ? getters.amountToPay : getters.initialPayment,
-        //     currencyId: getters.selectedCurrency.id,
-        //     paymentMethod: getters.paymentMethod,
-        //     bankPaymentData: {
-        //         ...getters.bankPaymentData
-        //     }
-        // }
-
         dispatch('storeData', data)
 
         if (getters.isWired) {
@@ -317,7 +298,7 @@ const actions = {
     resetSettings() {
         // Ignore this
     },
-    resetProcess({rootState, dispatch}) {
+    resetProcess({ rootState, dispatch }) {
         for (let key in rootState) {
             if (!(rootState[key] instanceof Object)) {
                 continue

+ 3 - 1
src/store/index.js

@@ -20,6 +20,7 @@ import bankPaymentTypeModule from '@/store/modules/bankPaymentType'
 import chequeTypeModule from './modules/chequeType'
 import storeModule from './modules/store'
 import saleOrderModule from './modules/saleOrder'
+import stockPickingModule from './modules/stockPicking';
 
 Vue.use(Vuex)
 
@@ -41,7 +42,8 @@ const store = new Vuex.Store({
         bankPaymentTypeModule,
         chequeTypeModule,
         storeModule,
-        saleOrderModule
+        saleOrderModule,
+        stockPickingModule
     },
     plugins: [
         createPersistedState({

+ 16 - 0
src/store/modules/cart.js

@@ -105,6 +105,22 @@ const actions = {
         commit('setCartTotal', payload)
         dispatch('changeAmountToPay', payload)
     },
+    updateFromSaleOrder({ commit, dispatch }, saleOrder) {
+        dispatch('resetCart', [])
+
+        if (!saleOrder) {
+            return
+        }
+
+        let total = 0
+        for (let line of saleOrder.lines) {
+            total = total + (line.price * line.quantity)
+
+            commit('pushToCart', line)
+        }
+
+        dispatch('changeCartTotal', total)
+    },
     resetCart ({ commit }) {
         commit('setCart', [])
         commit('setCartTotal', 0)

+ 9 - 0
src/store/modules/customer.js

@@ -78,6 +78,15 @@ const actions = {
     selectCustomer({ commit }, payload) {
         commit('setSelectedCustomer', payload)
     },
+    updateFromSaleOrder({ commit }, saleOrder) {
+        commit('setSelectedCustomer', null)
+
+        if (!saleOrder) {
+            return
+        }
+
+        commit('setSelectedCustomer', saleOrder.partner)
+    },
     resetCustomer({ getters, commit }) {
         if (getters.isWired) {
             commit('setLoadingCustomers', true)

+ 18 - 7
src/store/modules/saleOrder.js

@@ -1,6 +1,7 @@
 const state = {
-    loadingSaleOrders: false,
     saleOrders: [],
+    filteredSaleOrders: [],
+    loadingSaleOrders: false,
     selectedSaleOrder: null
 }
 
@@ -11,6 +12,9 @@ const getters = {
     saleOrders(state) {
         return state.saleOrders
     },
+    visibleSaleOrders(state) {
+        return state.filteredSaleOrders.length === 0 ? state.saleOrders : state.filteredSaleOrders
+    },
     selectedSaleOrder(state) {
         return state.selectedSaleOrder
     }
@@ -23,12 +27,11 @@ const mutations = {
     setSaleOrders(state, saleOrders) {
         state.saleOrders = saleOrders
     },
-    setSelectedSaleOrder(state, saleOrdeId) {
-        if (!saleOrdeId) {
-            return
-        }
-
-        state.selectedSaleOrder = state.saleOrders.find(s => s.id === saleOrdeId)
+    setFilteredSaleOrders(state, payload) {
+        state.filteredSaleOrders = [...payload]
+    },
+    setSelectedSaleOrder(state, saleOrder) {
+        state.selectedSaleOrder = saleOrder
     }
 }
 
@@ -37,7 +40,15 @@ const actions = {
         commit('setSaleOrders', saleOrders)
         commit('setLoadingSaleOrders')
     },
+    filterSaleOrders({ commit }, payload) {
+        commit('setFilteredSaleOrders', payload)
+    },
+    selectSaleOrder({ commit, dispatch }, payload) {
+        commit('setSelectedSaleOrder', payload)
+        dispatch('updateFromSaleOrder', payload)
+    },
     resetSaleOrder({ commit }) {
+        commit('setLoadingSaleOrders', true)
         commit('setSaleOrders', [])
         commit('setSelectedSaleOrder', null)
     }

+ 60 - 0
src/store/modules/stockPicking.js

@@ -0,0 +1,60 @@
+const state = {
+    stockPickings: [],
+    filteredStockPickings: [],
+    loadingStockPickings: false,
+    selectedStockPicking: null
+}
+
+const getters = {
+    loadingStockPickings(state) {
+        return state.loadingStockPickings
+    },
+    stockPickings(state) {
+        return state.stockPickings
+    },
+    visibleStockPickings(state) {
+        return state.filteredStockPickings.length === 0 ? state.stockPickings : state.filteredStockPickings
+    },
+    selectedStockPicking(state) {
+        return state.selectedStockPicking
+    }
+}
+
+const mutations = {
+    setLoadingStockPickings(state, loading) {
+        state.loadingStockPickings = !!loading
+    },
+    setStockPickings(state, stockPickings) {
+        state.stockPickings = stockPickings
+    },
+    setFilteredStockPickings(state, payload) {
+        state.filteredStockPickings = [...payload]
+    },
+    setSelectedStockPicking(state, stockPicking) {
+        state.selectedStockPicking = stockPicking
+    }
+}
+
+const actions = {
+    initStockPickings({ commit }, stockPickings) {
+        commit('setStockPickings', stockPickings)
+        commit('setLoadingStockPickings')
+    },
+    filterStockPickings({ commit }, payload) {
+        commit('setFilteredStockPickings', payload)
+    },
+    selectStockPicking({ commit, dispatch }, payload) {
+        commit('setSelectedStockPicking', payload)
+    },
+    resetStockPicking({ commit }) {
+        commit('setStockPickings', [])
+        commit('setSelectedStockPicking', null)
+    }
+}
+
+export default {
+    state,
+    getters,
+    actions,
+    mutations
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 198 - 21
yarn-error.log


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 233 - 75
yarn.lock


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels