From a3311f60934abf01587a9a5d7152ed746c4d6f2b Mon Sep 17 00:00:00 2001 From: Carlos Jimenez Ruiz Date: Fri, 24 May 2019 15:30:50 +0200 Subject: [PATCH] #1250 ticket.line al mover todas las lineas delete --- loopback/locale/es.json | 7 +- .../back/methods/sale/moveToNewTicket.js | 76 ---------------- .../ticket/back/methods/sale/moveToTicket.js | 78 +++++++++++++--- .../methods/sale/specs/moveToTicket.spec.js | 89 ++++++++++++------- .../back/methods/ticket/checkEmptiness.js | 37 ++++++++ .../ticket/specs/checkEmptiness.spec.js | 27 ++++++ .../methods/ticket/specs/isEditable.spec.js | 8 +- modules/ticket/back/models/sale.js | 1 - modules/ticket/back/models/ticket.js | 1 + modules/ticket/front/sale/index.html | 14 ++- modules/ticket/front/sale/index.js | 65 ++++++++------ modules/ticket/front/sale/locale/es.yml | 4 +- 12 files changed, 249 insertions(+), 158 deletions(-) delete mode 100644 modules/ticket/back/methods/sale/moveToNewTicket.js create mode 100644 modules/ticket/back/methods/ticket/checkEmptiness.js create mode 100644 modules/ticket/back/methods/ticket/specs/checkEmptiness.spec.js diff --git a/loopback/locale/es.json b/loopback/locale/es.json index b42c10be1..b8dec397f 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -25,7 +25,6 @@ "Observation type must be unique": "El tipo de observación no puede repetirse", "The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero", "The grade must be similar to the last one": "El grade debe ser similar al último", - "NO_AGENCY_AVAILABLE": "NO_AGENCY_AVAILABLE", "Only manager can change the credit": "Solo el gerente puede cambiar el credito de este cliente", "Name cannot be blank": "El nombre no puede estar en blanco", "Phone cannot be blank": "El teléfono no puede estar en blanco", @@ -54,7 +53,6 @@ "Agency cannot be blank": "La agencia no puede quedar en blanco", "You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados", "This address doesn't exist": "Este consignatario no existe", - "The sales of this ticket can't be modified": "Los movimientos de este tiquet no pueden ser modificadas", "You can't create an order for a inactive client": "You can't create an order for a inactive client", "You can't create an order for a client that doesn't has tax data verified": "You can't create an order for a client that doesn't has tax data verified", "You must delete the claim id %d first": "Antes debes borrar la reclamacion %d", @@ -84,5 +82,8 @@ "You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado", "This ticket can not be modified": "Este ticket no puede ser modificado", "The introduced hour already exists": "Esta hora ya ha sido introducida", - "INFINITE_LOOP": "Existe una dependencia entre dos Jefes" + "INFINITE_LOOP": "Existe una dependencia entre dos Jefes", + "The sales of the current ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", + "The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas", + "NO_AGENCY_AVAILABLE": "No hay agencias disponibles" } \ No newline at end of file diff --git a/modules/ticket/back/methods/sale/moveToNewTicket.js b/modules/ticket/back/methods/sale/moveToNewTicket.js deleted file mode 100644 index d58ab08c7..000000000 --- a/modules/ticket/back/methods/sale/moveToNewTicket.js +++ /dev/null @@ -1,76 +0,0 @@ -let UserError = require('vn-loopback/util/user-error'); - -module.exports = Self => { - Self.remoteMethodCtx('moveToNewTicket', { - description: 'Change the state of a ticket', - accessType: '', - accepts: [{ - arg: 'ticketParams', - type: 'object', - required: true, - description: '[sales IDs], newTicketFk, actualTicketFk', - http: {source: 'body'} - }, { - arg: 'sales', - type: 'object', - required: true, - description: '[sales IDs]', - http: {source: 'body'} - }], - returns: { - type: 'string', - root: true - }, - http: { - path: `/moveToNewTicket`, - verb: 'post' - } - }); - - Self.moveToNewTicket = async(ctx, params) => { - let userId = ctx.req.accessToken.userId; - let model = Self.app.models; - let thisTicketIsEditable = await model.Ticket.isEditable(params.ticket.oldTicketFk); - if (!thisTicketIsEditable) - throw new UserError(`The sales of this ticket can't be modified`); - - let travelDates = await model.Agency.getFirstShipped(params.ticket); - let shipped = new Date(travelDates.vShipped); - shipped.setMinutes(shipped.getMinutes() + shipped.getTimezoneOffset()); - - let landed = new Date(travelDates.vLanded); - landed.setMinutes(landed.getMinutes() + landed.getTimezoneOffset()); - - let newTicketParams = { - clientFk: params.ticket.clientFk, - addressFk: params.ticket.addressFk, - agencyModeFk: params.ticket.agencyModeFk, - warehouseFk: params.ticket.warehouseFk, - shipped: shipped, - landed: landed, - userId: userId - }; - - let transaction = await Self.beginTransaction({}); - try { - let newTicket = await model.Ticket.new(ctx, newTicketParams, {transaction: transaction}); - - let selectedSalesId = []; - params.sales.forEach(sale => { - selectedSalesId.push(sale.id); - }); - - await model.Sale.updateAll( - {id: {inq: selectedSalesId}}, - {ticketFk: newTicket.id}, - {transaction}); - - await transaction.commit(); - - return newTicket; - } catch (e) { - await transaction.rollback(); - throw e; - } - }; -}; diff --git a/modules/ticket/back/methods/sale/moveToTicket.js b/modules/ticket/back/methods/sale/moveToTicket.js index 5e3779551..e7055d920 100644 --- a/modules/ticket/back/methods/sale/moveToTicket.js +++ b/modules/ticket/back/methods/sale/moveToTicket.js @@ -1,14 +1,13 @@ let UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - Self.remoteMethod('moveToTicket', { - description: 'Moves a line to a given ticket', - accessType: '', + Self.remoteMethodCtx('moveToTicket', { + description: 'Moves lines to a new or a given ticket', accepts: [{ arg: 'params', type: 'object', required: true, - description: '[sales IDs], newTicketFk, actualTicketFk', + description: 'currentTicket, receiverTicket, [sales IDs], removeEmptyTicket', http: {source: 'body'} }], returns: { @@ -21,16 +20,69 @@ module.exports = Self => { } }); - Self.moveToTicket = async params => { - let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(params.actualTicketFk); - if (!thisTicketIsEditable) - throw new UserError(`The sales of this ticket can't be modified`); + Self.moveToTicket = async(ctx, params) => { + const models = Self.app.models; + const userId = ctx.req.accessToken.userId; + let currentTicket = await models.Ticket.findById(params.currentTicket.currentTicketId); + let newTicketData = {}; + let receiverTicket = params.receiverTicket; + let transaction = await Self.beginTransaction({}); + let options = {transaction}; - let newTicketIsEditable = await Self.app.models.Ticket.isEditable(params.newTicketFk); - if (!newTicketIsEditable) - throw new UserError(`The sales of this ticket can't be modified`); + let isCurrentTicketEditable = await models.Ticket.isEditable(params.currentTicket.currentTicketId); + if (!isCurrentTicketEditable) + throw new UserError(`The sales of the current ticket can't be modified`); - for (let i = 0; i < params.sales.length; i++) - await Self.app.models.Sale.update({id: params.sales[i].id}, {ticketFk: params.newTicketFk}); + if (params.receiverTicket.id) { + let isReceiverTicketEditable = await models.Ticket.isEditable(params.receiverTicket.id); + if (!isReceiverTicketEditable) + throw new UserError(`The sales of the receiver ticket can't be modified`); + } + + if (!params.receiverTicket.id) { + let travelDates = await models.Agency.getFirstShipped(params.currentTicket); + let shipped = new Date(travelDates.vShipped); + shipped.setMinutes(shipped.getMinutes() + shipped.getTimezoneOffset()); + + let landed = new Date(travelDates.vLanded); + landed.setMinutes(landed.getMinutes() + landed.getTimezoneOffset()); + + newTicketData = { + clientFk: params.currentTicket.clientFk, + addressFk: params.currentTicket.addressFk, + agencyModeFk: params.currentTicket.agencyModeFk, + warehouseFk: params.currentTicket.warehouseFk, + shipped: shipped, + landed: landed, + userId: userId + }; + } + + try { + if (!params.receiverTicket.id) + receiverTicket = await models.Ticket.new(ctx, newTicketData, options); + + let promises = []; + for (let sale of params.sales) { + promises.push( + models.Sale.update( + {id: sale.id}, + {ticketFk: receiverTicket.id}, + options + ) + ); + } + + if (params.removeEmptyTicket) + promises.push(currentTicket.updateAttributes({isDeleted: true}, options)); + + await Promise.all(promises); + await transaction.commit(); + + return receiverTicket; + } catch (error) { + await transaction.rollback(); + throw error; + } }; }; diff --git a/modules/ticket/back/methods/sale/specs/moveToTicket.spec.js b/modules/ticket/back/methods/sale/specs/moveToTicket.spec.js index 1cf540a1b..4f771ee3f 100644 --- a/modules/ticket/back/methods/sale/specs/moveToTicket.spec.js +++ b/modules/ticket/back/methods/sale/specs/moveToTicket.spec.js @@ -1,14 +1,22 @@ const app = require('vn-loopback/server/server'); describe('sale moveToTicket()', () => { + let createdTicketId; + + afterAll(async done => { + await app.models.Ticket.destroyById(createdTicketId); + done(); + }); + it('should throw an error if the ticket is not editable', async() => { + const ctx = {req: {accessToken: {userId: 101}}}; let error; - let params = {actualTicketFk: 10}; + const params = {currentTicket: {currentTicketId: 10}}; - await app.models.Sale.moveToTicket(params) + await app.models.Sale.moveToTicket(ctx, params) .catch(response => { - expect(response.message).toEqual(`The sales of this ticket can't be modified`); + expect(response.message).toEqual(`The sales of the current ticket can't be modified`); error = response; }); @@ -16,64 +24,83 @@ describe('sale moveToTicket()', () => { }); it('should throw an error if the receiving ticket is not editable', async() => { + const ctx = {req: {accessToken: {userId: 101}}}; let error; - let params = {actualTicketFk: 1, newTicketFk: 10}; + const params = {currentTicket: {currentTicketId: 16}, receiverTicket: {id: 1}}; - await app.models.Sale.moveToTicket(params) + await app.models.Sale.moveToTicket(ctx, params) .catch(response => { - expect(response.message).toEqual(`The sales of this ticket can't be modified`); + expect(response.message).toEqual(`The sales of the receiver ticket can't be modified`); error = response; }); expect(error).toBeDefined(); }); - it('should transfer the sales from one ticket to another', async() => { - let senderTicketSales = await app.models.Ticket.getSales(11); - let receiverTicketSales = await app.models.Ticket.getSales(13); + it('should transfer the sales from one ticket to a new one', async() => { + const ctx = {req: {accessToken: {userId: 101}}}; + let currentTicket = await app.models.Ticket.findById(8); + currentTicket.currentTicketId = currentTicket.id; + currentTicket.id = undefined; - expect(senderTicketSales.length).toEqual(2); - expect(receiverTicketSales.length).toEqual(0); + let currentTicketSales = await app.models.Ticket.getSales(currentTicket.currentTicketId); + + expect(currentTicketSales.length).toEqual(2); let params = { - actualTicketFk: 11, - newTicketFk: 13, + currentTicket: currentTicket, + receiverTicket: {id: undefined}, sales: [ - {id: 7}, - {id: 8}] + {id: 13}, + {id: 14} + ] }; - await app.models.Sale.moveToTicket(params); + let createdTicket = await app.models.Sale.moveToTicket(ctx, params); + createdTicketId = createdTicket.id; - senderTicketSales = await app.models.Ticket.getSales(11); - receiverTicketSales = await app.models.Ticket.getSales(13); + currentTicketSales = await app.models.Ticket.getSales(currentTicket.currentTicketId); + receiverTicketSales = await app.models.Ticket.getSales(createdTicket.id); - expect(senderTicketSales.length).toEqual(0); + expect(currentTicketSales.length).toEqual(0); expect(receiverTicketSales.length).toEqual(2); }); - it('should transfers back the sales', async() => { - let senderTicketSales = await app.models.Ticket.getSales(13); - let receiverTicketSales = await app.models.Ticket.getSales(11); + it('should transfers back the sales and set the created ticket as deleted', async() => { + const ctx = {req: {accessToken: {userId: 101}}}; + let receiverTicketId = 8; + let currentTicket = await app.models.Ticket.findById(createdTicketId); + currentTicket.currentTicketId = createdTicketId; + currentTicket.id = undefined; - expect(senderTicketSales.length).toEqual(2); + let createdTicket = await app.models.Ticket.findById(createdTicketId); + let createdTicketSales = await app.models.Ticket.getSales(createdTicketId); + let receiverTicketSales = await app.models.Ticket.getSales(receiverTicketId); + + expect(createdTicket.isDeleted).toBeFalsy(); + expect(createdTicketSales.length).toEqual(2); expect(receiverTicketSales.length).toEqual(0); let params = { - actualTicketFk: 13, - newTicketFk: 11, + removeEmptyTicket: true, + currentTicket: currentTicket, + receiverTicket: {id: receiverTicketId}, sales: [ - {id: 7}, - {id: 8}] + {id: 13}, + {id: 14} + ] }; - await app.models.Sale.moveToTicket(params); + await app.models.Sale.moveToTicket(ctx, params); - senderTicketSales = await app.models.Ticket.getSales(13); - receiverTicketSales = await app.models.Ticket.getSales(11); + createdTicket = await app.models.Ticket.findById(createdTicketId); - expect(senderTicketSales.length).toEqual(0); + createdTicketSales = await app.models.Ticket.getSales(createdTicketId); + receiverTicketSales = await app.models.Ticket.getSales(receiverTicketId); + + expect(createdTicket.isDeleted).toBeTruthy(); + expect(createdTicketSales.length).toEqual(0); expect(receiverTicketSales.length).toEqual(2); }); }); diff --git a/modules/ticket/back/methods/ticket/checkEmptiness.js b/modules/ticket/back/methods/ticket/checkEmptiness.js new file mode 100644 index 000000000..2cc70deda --- /dev/null +++ b/modules/ticket/back/methods/ticket/checkEmptiness.js @@ -0,0 +1,37 @@ +module.exports = function(Self) { + Self.remoteMethod('checkEmptiness', { + description: 'Checks if the ticket has no packages, componenets and purchase requests', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'Ticket id', + http: {source: 'path'} + } + ], + returns: { + arg: 'data', + type: 'boolean', + root: true + }, + http: { + path: `/:id/checkEmptiness`, + verb: 'get' + } + }); + + Self.checkEmptiness = async id => { + const packages = await Self.app.models.TicketPackaging.find({where: {ticketFk: id}}); + const services = await Self.app.models.TicketService.find({where: {ticketFk: id}}); + const purchaseRequests = await Self.app.models.TicketRequest.find({where: {ticketFk: id}}); + + emptyTicket = !packages.length && !services.length && !purchaseRequests.length; + + if (emptyTicket) + return true; + + return false; + }; +}; diff --git a/modules/ticket/back/methods/ticket/specs/checkEmptiness.spec.js b/modules/ticket/back/methods/ticket/specs/checkEmptiness.spec.js new file mode 100644 index 000000000..1d67f4c98 --- /dev/null +++ b/modules/ticket/back/methods/ticket/specs/checkEmptiness.spec.js @@ -0,0 +1,27 @@ +const app = require('vn-loopback/server/server'); + +describe('ticket checkEmptiness()', () => { + it('should return false if the ticket contains any packages', async() => { + let result = await app.models.Ticket.checkEmptiness(3); + + expect(result).toBeFalsy(); + }); + + it('should return false if the ticket contains any services', async() => { + let result = await app.models.Ticket.checkEmptiness(8); + + expect(result).toBeFalsy(); + }); + + it('should return false if the ticket contains any purchase request', async() => { + let result = await app.models.Ticket.checkEmptiness(11); + + expect(result).toBeFalsy(); + }); + + it('should return true if the ticket does not contain any packages, services or purchase request', async() => { + let result = await app.models.Ticket.checkEmptiness(4); + + expect(result).toBeTruthy(); + }); +}); diff --git a/modules/ticket/back/methods/ticket/specs/isEditable.spec.js b/modules/ticket/back/methods/ticket/specs/isEditable.spec.js index 87523dbf1..1ccc4560c 100644 --- a/modules/ticket/back/methods/ticket/specs/isEditable.spec.js +++ b/modules/ticket/back/methods/ticket/specs/isEditable.spec.js @@ -1,25 +1,25 @@ const app = require('vn-loopback/server/server'); describe('ticket isEditable()', () => { - it('should return false if the ticket given is not editable', async () => { + it('should return false if the ticket given is not editable', async() => { let result = await app.models.Ticket.isEditable(2); expect(result).toEqual(false); }); - it('should return false if the ticket given does not exist', async () => { + it('should return false if the ticket given does not exist', async() => { let result = await app.models.Ticket.isEditable(99999); expect(result).toEqual(false); }); - it('should return false if the ticket given isDeleted', async () => { + it('should return false if the ticket given isDeleted', async() => { let result = await app.models.Ticket.isEditable(21); expect(result).toEqual(false); }); - it('should return true if the ticket given is editable', async () => { + it('should return true if the ticket given is editable', async() => { let result = await app.models.Ticket.isEditable(16); expect(result).toEqual(true); diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index 129d14bb8..2d7f8cbe6 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -3,7 +3,6 @@ module.exports = Self => { require('../methods/sale/priceDifference')(Self); require('../methods/sale/moveToTicket')(Self); require('../methods/sale/reserve')(Self); - require('../methods/sale/moveToNewTicket')(Self); require('../methods/sale/removes')(Self); require('../methods/sale/updateDiscount')(Self); require('../methods/sale/updatePrice')(Self); diff --git a/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js index a465aa6ea..a5419c257 100644 --- a/modules/ticket/back/models/ticket.js +++ b/modules/ticket/back/models/ticket.js @@ -21,4 +21,5 @@ module.exports = Self => { require('../methods/ticket/canBeInvoiced')(Self); require('../methods/ticket/makeInvoice')(Self); require('../methods/ticket/updateEditableTicket')(Self); + require('../methods/ticket/checkEmptiness')(Self); }; diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index 8cd345e79..19b5414f8 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -252,7 +252,7 @@ + ng-click="$ctrl.checkEmptiness(ticket.id)"> {{::ticket.id}} {{::ticket.shipped | dateTime: 'dd/MM/yyyy HH:mm'}} {{::ticket.agencyName}} @@ -263,18 +263,18 @@ + ng-click="$ctrl.checkEmptiness($ctrl.receiverTicketId)"> + ng-click="$ctrl.checkEmptiness()"> + + { + this.$http.get(`/api/Tickets/${this.$stateParams.id}/subtotal`).then(res => { this.subtotal = res.data || 0.0; }); } @@ -50,7 +50,7 @@ class Controller { loadVAT() { this.VAT = 0.0; if (!this.$stateParams.id || !this.sales) return; - this.$http.get(`/ticket/api/Tickets/${this.$stateParams.id}/getVAT`).then(res => { + this.$http.get(`/api/Tickets/${this.$stateParams.id}/getVAT`).then(res => { this.VAT = res.data || 0.0; }); } @@ -103,29 +103,27 @@ class Controller { return lines; } - // Change State onStateOkClick() { let filter = {where: {code: 'OK'}, fields: ['id']}; let json = encodeURIComponent(JSON.stringify(filter)); - this.$http.get(`/ticket/api/States?filter=${json}`).then(res => { + this.$http.get(`/api/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(`/ticket/api/TicketTrackings/changeState`, params).then(() => { + this.$http.post(`/api/TicketTrackings/changeState`, params).then(() => { this.card.reload(); this.vnApp.showSuccess(this.$translate.instant('Data saved!')); }); } - // Remove Lines onRemoveLinesClick(response) { if (response === 'ACCEPT') { let sales = this.getCheckedLines(); let params = {sales: sales, actualTicketFk: this.ticket.id}; - let query = `/ticket/api/Sales/removes`; + let query = `/api/Sales/removes`; this.$http.post(query, params).then(() => { this.removeInstances(sales); this.vnApp.showSuccess(this.$translate.instant('Data saved!')); @@ -143,11 +141,10 @@ class Controller { this.$scope.deleteLines.show(); } - // Move Lines showTransferPopover(event) { let filter = {clientFk: this.ticket.clientFk, ticketFk: this.ticket.id}; let json = encodeURIComponent(JSON.stringify(filter)); - let query = `/ticket/api/Tickets/threeLastActive?filter=${json}`; + let query = `/api/Tickets/threeLastActive?filter=${json}`; this.$http.get(query).then(res => { this.lastThreeTickets = res.data; }); @@ -155,31 +152,50 @@ class Controller { this.$scope.transfer.show(); } - moveLines(ticketID) { - let sales = this.getCheckedLines(); - let params = {sales: sales, newTicketFk: ticketID, actualTicketFk: this.ticket.id}; - this.$http.post(`/ticket/api/Sales/moveToTicket`, params).then(() => { - this.goToTicket(ticketID); - }); + checkEmptiness(receiverTicketId) { + let sales = this.getCheckedLines(); + let areAllSalesSelected = sales.length === this.$scope.model.data.length; + this.receiverTicketId = receiverTicketId; + + + if (areAllSalesSelected) { + let query = `/api/Tickets/${this.ticket.id}/checkEmptiness`; + this.$http.get(query).then(res => { + if (res.data) + this.$scope.deleteTicket.show(); + if (!res.data) + this.moveLines(false); + }); + } + + if (!areAllSalesSelected) + this.moveLines(false); } - linesToNewTicket() { - let ticket = { - oldTicketFk: this.ticket.id, + moveLines(removeEmptyTicket) { + let sales = this.getCheckedLines(); + + let currentTicketData = { + currentTicketId: this.ticket.id, clientFk: this.ticket.clientFk, addressFk: this.ticket.addressFk, agencyModeFk: this.ticket.agencyModeFk, warehouseFk: this.ticket.warehouseFk }; - let sales = this.getCheckedLines(); + let params = { + currentTicket: currentTicketData, + receiverTicket: this.receiverTicketId ? {id: this.receiverTicketId} : currentTicketData, + sales: sales, + removeEmptyTicket: removeEmptyTicket + }; - this.$http.post(`/api/Sales/MoveToNewTicket`, {ticket: ticket, sales: sales}).then(res => { - let url = this.$state.href('ticket.card.sale', {id: res.data.id}, {absolute: true}); - window.open(url, '_blank'); - this.$scope.transfer.hide(); - this.$scope.model.refresh(); + this.$http.post(`/api/Sales/moveToTicket`, params).then(res => { + if (res.data) { + this.receiverTicketId = null; + this.goToTicket(res.data.id); + } }); } @@ -230,7 +246,6 @@ class Controller { this.$scope.popover.relocate(); } - // Edit Line showEditPricePopover(event, sale) { this.sale = sale; this.editedPrice = this.sale.price; diff --git a/modules/ticket/front/sale/locale/es.yml b/modules/ticket/front/sale/locale/es.yml index e6db9420f..235ca9e41 100644 --- a/modules/ticket/front/sale/locale/es.yml +++ b/modules/ticket/front/sale/locale/es.yml @@ -24,4 +24,6 @@ Reserved: Reservado SMSAvailability: >- Verdnatura le comunica: Pedido {{ticketFk}} día {{created | date: "dd/MM/yyyy"}}. {{notAvailables}} no disponible/s. Disculpe las molestias. -Continue anyway?: ¿Continuar de todas formas? \ No newline at end of file +Continue anyway?: ¿Continuar de todas formas? +This ticket is now empty: El ticket ha quedado vacio +Do you want to delete it?: ¿Quieres borrarlo? \ No newline at end of file