import ngModule from '../module'; import './style.scss'; class Controller { constructor($scope, $state, $http, vnApp, $translate) { this.$scope = $scope; this.vnApp = vnApp; this.$translate = $translate; this.$state = $state; this.$stateParams = $state.params; this.$http = $http; this.edit = {}; this.moreOptions = [ { name: 'Send shortage SMS', callback: this.showSMSDialog }, { name: 'Mark as reserved', callback: this.markAsReserved, show: () => this.isEditable }, { name: 'Unmark as reserved', callback: this.unmarkAsReserved, show: () => this.isEditable }, { name: 'Update discount', callback: this.showEditDialog, show: () => this.isEditable }, { name: 'Add claim', callback: this.createClaim }, { name: 'Recalculate price', callback: this.calculateSalePrice, show: () => this.hasOneSaleSelected() }, ]; this._sales = []; this.imagesPath = '//verdnatura.es/vn-image-data/catalog'; } get ticket() { return this._ticket; } set ticket(value) { this._ticket = value; this.isTicketEditable(); this.isTicketLocked(); } get sales() { return this._sales; } set sales(value) { this._sales = value; this.refreshTotal(); } get editedPrice() { return this._editedPrice; } set editedPrice(value) { this._editedPrice = value; this.updateNewPrice(); } refreshTotal() { this.loadSubTotal(); this.loadVAT(); } loadSubTotal() { if (!this.$stateParams.id || !this.sales) return; this.$http.get(`Tickets/${this.$stateParams.id}/subtotal`).then(res => { this.subtotal = res.data || 0.0; }); } getSaleTotal(sale) { if (!sale.quantity || !sale.price) return; return sale.quantity * sale.price * ((100 - sale.discount) / 100); } loadVAT() { this.VAT = 0.0; if (!this.$stateParams.id || !this.sales) return; this.$http.get(`Tickets/${this.$stateParams.id}/getVAT`).then(res => { this.VAT = res.data || 0.0; }); } get total() { return this.subtotal + this.VAT; } onMoreOpen() { let options = this.moreOptions.filter(option => { const hasShowProperty = Object.hasOwnProperty.call(option, 'show'); const shouldShow = !hasShowProperty || option.show === true || typeof option.show === 'function' && option.show(); return (shouldShow && (option.always || this.isChecked)); }); this.$scope.moreButton.data = options; } onMoreChange(callback) { callback.call(this); } get isChecked() { if (this.sales) { for (let instance of this.sales) if (instance.checked) return true; } return false; } /** * Returns checked instances * * @return {Array} Checked instances */ checkedLines() { if (!this.sales) return; return this.sales.filter(sale => { return sale.checked; }); } /** * Returns new instances * * @return {Array} New instances */ newInstances() { if (!this.sales) return; return this.sales.filter(sale => { return !sale.id; }); } /** * Returns an array of indexes * from checked instances * * @return {Array} Indexes of checked instances */ checkedLinesIndex() { if (!this.sales) return; let indexes = []; this.sales.forEach((sale, index) => { if (sale.checked) indexes.push(index); }); return indexes; } firstCheckedLine() { const checkedLines = this.checkedLines(); if (checkedLines) return checkedLines[0]; } /** * Returns the total of checked instances * * @return {Number} Total checked instances */ totalCheckedLines() { const checkedLines = this.checkedLines(); if (checkedLines) return checkedLines.length; } removeCheckedLines() { const sales = this.checkedLines(); sales.forEach(sale => { const index = this.sales.indexOf(sale); this.sales.splice(index, 1); }); if (this.newInstances().length === 0) this.$scope.watcher.updateOriginalData(); this.refreshTotal(); } onStateOkClick() { let filter = {where: {code: 'OK'}, fields: ['id']}; let json = encodeURIComponent(JSON.stringify(filter)); return this.$http.get(`States?filter=${json}`).then(res => { this.onStateChange(res.data[0].id); }); } onStateChange(value) { let params = {ticketFk: this.$state.params.id, stateFk: value}; this.$http.post('TicketTrackings/changeState', params).then(() => { this.card.reload(); this.vnApp.showSuccess(this.$translate.instant('Data saved!')); }).finally(() => { if (this.newInstances().length === 0) this.$scope.watcher.updateOriginalData(); }); } onRemoveLinesClick(response) { if (response === 'accept') { let sales = this.checkedLines(); // Remove unsaved instances sales.forEach((sale, index) => { if (!sale.id) sales.splice(index); }); let params = {sales: sales, actualTicketFk: this.ticket.id}; let query = `Sales/removes`; this.$http.post(query, params).then(() => { this.removeCheckedLines(); this.vnApp.showSuccess(this.$translate.instant('Data saved!')); }); } } showRemoveLinesDialog() { this.$scope.deleteLines.show(); } showTransferPopover(event) { this.setTransferParams(); this.$scope.transfer.parent = event.target; this.$scope.transfer.show(); } setTransferParams() { const checkedSales = JSON.stringify(this.checkedLines()); const sales = JSON.parse(checkedSales); this.transfer = { lastActiveTickets: [], sales: sales }; const params = {ticketId: this.ticket.id}; const query = `clients/${this.ticket.clientFk}/lastActiveTickets`; this.$http.get(query, {params}).then(res => { this.transfer.lastActiveTickets = res.data; }); } transferSales(ticketId) { const params = { ticketId: ticketId, sales: this.transfer.sales }; this.$scope.watcher.updateOriginalData(); const query = `tickets/${this.ticket.id}/transferSales`; this.$http.post(query, params).then(res => { this.goToTicket(res.data.id); }); } createClaim() { const claim = { ticketFk: this.ticket.id, clientFk: this.ticket.clientFk, ticketCreated: this.ticket.shipped }; const sales = this.checkedLines(); if (this.newInstances().length === 0) this.$scope.watcher.updateOriginalData(); this.$http.post(`Claims/createFromSales`, {claim: claim, sales: sales}).then(res => { this.$state.go('claim.card.basicData', {id: res.data.id}); }); } goToTicket(ticketId) { this.$state.go('ticket.card.sale', {id: ticketId}); } // Slesperson Mana getManaSalespersonMana() { this.$http.get(`Tickets/${this.$state.params.id}/getSalesPersonMana`).then(res => { this.mana = res.data; }); } // Item Descriptor showDescriptor(event, itemFk) { this.quicklinks = { btnThree: { icon: 'icon-transaction', state: `item.card.diary({ id: ${itemFk}, warehouseFk: ${this.ticket.warehouseFk}, ticketFk: ${this.ticket.id} })`, tooltip: 'Item diary' } }; this.$scope.descriptor.itemFk = itemFk; this.$scope.descriptor.parent = event.target; this.$scope.descriptor.show(); } onDescriptorLoad() { this.$scope.popover.relocate(); } showEditPricePopover(event, sale) { if (!this.isEditable) return; this.sale = sale; this.editedPrice = this.sale.price; this.edit = { ticketFk: this.ticket.id, id: sale.id, quantity: sale.quantity }; this.$scope.editPricePopover.parent = event.target; this.$scope.editPricePopover.show(); } updatePrice() { if (this.editedPrice != this.sale.price) { this.$http.post(`Sales/${this.edit.id}/updatePrice`, {newPrice: this.editedPrice}).then(res => { this.sale.price = res.data.price; this.vnApp.showSuccess(this.$translate.instant('Data saved!')); }).finally(() => { if (this.newInstances().length === 0) this.$scope.watcher.updateOriginalData(); }); } this.$scope.editPricePopover.hide(); } updateNewPrice() { this.newPrice = this.sale.quantity * this.editedPrice - ((this.sale.discount * (this.sale.quantity * this.editedPrice)) / 100); } showEditDiscountPopover(event, sale) { if (this.isLocked) return; this.sale = sale; this.edit = [{ ticketFk: this.ticket.id, id: sale.id, quantity: sale.quantity, price: sale.price, discount: sale.discount }]; this.$scope.editPopover.parent = event.target; this.$scope.editPopover.show(); } showEditDialog() { this.edit = this.checkedLines(); this.$scope.editDialog.show(); } hideEditDialog() { this.$scope.model.refresh(); this.$scope.editDialog.hide(); } hideEditPopover() { this.$scope.model.refresh(); this.$scope.editPopover.hide(); } /* * Unmark sale as reserved */ unmarkAsReserved() { this.setReserved(false); } /* * Mark sale as reserved */ markAsReserved() { this.setReserved(true); } setReserved(reserved) { let selectedSales = this.checkedLines(); let params = {sales: selectedSales, ticketFk: this.ticket.id, reserved: reserved}; let reservedSales = new Map(); this.$http.post(`Sales/reserve`, params).then(res => { let isReserved = res.config.data.reserved; res.config.data.sales.forEach(sale => { reservedSales.set(sale.id, {reserved: isReserved}); }); this.sales.forEach(sale => { const reservedSale = reservedSales.get(sale.id); if (reservedSale) sale.reserved = reservedSale.reserved; }); }).finally(() => { if (this.newInstances().length === 0) this.$scope.watcher.updateOriginalData(); }); } newOrderFromTicket() { this.$http.post(`Orders/newFromTicket`, {ticketFk: this.ticket.id}).then(res => { const path = this.$state.href('order.card.catalog', {id: res.data}); window.open(path, '_blank'); this.vnApp.showSuccess(this.$translate.instant('Order created')); }); } showSMSDialog() { const address = this.ticket.address; const client = this.ticket.client; const phone = address.mobile || address.phone || client.mobile || client.phone; const sales = this.checkedLines(); const items = sales.map(sale => { return `${sale.quantity} ${sale.concept}`; }); const notAvailables = items.join(', '); const params = { ticketFk: this.ticket.id, created: this.ticket.created, notAvailables }; this.newSMS = { destinationFk: this.ticket.clientFk, destination: phone, message: this.$translate.instant('Product not available', params) }; this.$scope.sms.open(); } /** * Inserts a new instance */ add() { this.$scope.model.insert({}); } /* * Creates a new sale if it's a new instance * Updates the sale quantity for existing instance */ onChangeQuantity(sale) { if (!sale.quantity) return; if (!sale.id) return this.addSale(sale); this.updateQuantity(sale); } /* * Updates a sale quantity */ updateQuantity(sale) { const data = {quantity: parseInt(sale.quantity)}; const query = `Sales/${sale.id}/updateQuantity`; this.$http.post(query, data).then(() => { this.vnApp.showSuccess(this.$translate.instant('Data saved!')); }).catch(e => { this.$scope.model.refresh(); throw e; }).finally(() => { if (this.newInstances().length === 0) this.$scope.watcher.updateOriginalData(); }); } /* * Updates a sale concept */ updateConcept(sale) { const data = {newConcept: sale.concept}; const query = `Sales/${sale.id}/updateConcept`; this.$http.post(query, data).then(() => { this.vnApp.showSuccess(this.$translate.instant('Data saved!')); }).catch(e => { this.$scope.model.refresh(); throw e; }).finally(() => { if (this.newInstances().length === 0) this.$scope.watcher.updateOriginalData(); }); } /* * Adds a new sale */ addSale(sale) { const data = { itemId: sale.itemFk, quantity: sale.quantity }; const query = `tickets/${this.ticket.id}/addSale`; this.$http.post(query, data).then(res => { if (!res.data) return; const newSale = res.data; sale.id = newSale.id; sale.image = newSale.item.image; sale.subName = newSale.item.subName; sale.concept = newSale.concept; sale.quantity = newSale.quantity; sale.discount = newSale.discount; sale.price = newSale.price; sale.item = newSale.item; this.vnApp.showSuccess(this.$translate.instant('Data saved!')); }).finally(() => { if (this.newInstances().length === 0) this.$scope.watcher.updateOriginalData(); }); } isTicketEditable() { this.$http.get(`Tickets/${this.$state.params.id}/isEditable`).then(res => { this.isEditable = res.data; }); } isTicketLocked() { this.$http.get(`Tickets/${this.$state.params.id}/isLocked`).then(res => { this.isLocked = res.data; }); } hasOneSaleSelected() { if (this.totalCheckedLines() === 1) return true; return false; } calculateSalePrice() { const sale = this.checkedLines()[0]; const query = `Sales/${sale.id}/recalculatePrice`; this.$http.post(query).then(res => { this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.$scope.model.refresh(); }); } itemSearchFunc($search) { return /^\d+$/.test($search) ? {id: $search} : {name: {like: '%' + $search + '%'}}; } } Controller.$inject = ['$scope', '$state', '$http', 'vnApp', '$translate']; ngModule.component('vnTicketSale', { template: require('./index.html'), controller: Controller, bindings: { ticket: '<' }, require: { card: '?^vnTicketCard' } });