diff --git a/client/ticket/src/sale/index.html b/client/ticket/src/sale/index.html index 6834bbc5fc..537971b66f 100644 --- a/client/ticket/src/sale/index.html +++ b/client/ticket/src/sale/index.html @@ -5,31 +5,50 @@ Sale + + + + - + @@ -39,7 +58,10 @@ - - - - + + + + + + @@ -61,6 +100,135 @@ - - + + + + + + + + +
+
+ In which day you want to add the ticket? +
+ + + + + + + + + + + + + + + + +
+
+
+ + + + +
MANÁ: {{$ctrl.workerMana}}
+
+
+
{{$ctrl.client.name}}
+ + + + + + + + +
+
+ + + +
+
- + + ItemDescriptionDescription Quantity Price Discount
- + + {{::sale.quantity}}{{::sale.price | currency:'€':2}}{{::sale.discount}} %{{::sale.quantity * sale.price | currency:'€':2}}{{sale.quantity}}{{sale.price | currency:'€':2}}{{sale.discount}} %{{sale.quantity * sale.price | currency:'€':2}}
No results
+ + + + + + + + + + + + + + + + + +
IDF. envioAgenciaAlmacen
No results
{{::ticket.id}}{{::ticket.shipped | date: 'dd/MM/yyyy HH:mm'}}{{::ticket.agencyName}}{{::ticket.warehouseName}}
+ + + + + + + + + + + diff --git a/client/ticket/src/sale/index.js b/client/ticket/src/sale/index.js index d00f619b5d..0b235948d6 100644 --- a/client/ticket/src/sale/index.js +++ b/client/ticket/src/sale/index.js @@ -1,13 +1,29 @@ import ngModule from '../module'; import FilterTicketList from '../filter-ticket-list'; +import './style.scss'; class Controller extends FilterTicketList { - constructor($scope, $timeout, $stateParams, $http) { + constructor($scope, $timeout, $stateParams, $http, $state, vnApp) { super($scope, $timeout, $stateParams); this.$ = $scope; + this.vnApp = vnApp; this.$timeout = $timeout; this.onOrder('itemFk', 'ASC'); + this.$state = $stateParams; this.$http = $http; + this.deletable = false; + this.moreOptions = [ + {callback: this.showAddTurnDialog, name: "Add turn"}, + {callback: this.showDeleteTicketDialog, name: "Delete ticket"} + ]; + } + + get isEditable() { + try { + return !this.ticket.tracking.state.alertLevel; + } catch (e) {} + + return true; } get isChecked() { @@ -20,6 +36,22 @@ class Controller extends FilterTicketList { return false; } + getCheckedLines() { + let lines = []; + let data = this.$.index.model.instances; + if (data) + for (let i = 0; i < data.length; i++) + if (data[i].checked) + lines.push({id: data[i].id, instance: i}); + + return lines; + } + + onMoreChange(callback) { + callback.call(this); + } + + // Change State onStateOkClick() { let filter = {where: {code: "OK"}, fields: ["id"]}; let json = encodeURIComponent(JSON.stringify(filter)); @@ -30,41 +62,153 @@ class Controller extends FilterTicketList { onStateChange(value) { let params = {ticketFk: this.$state.params.id, stateFk: value}; - this.$http.post(`/ticket/api/TicketTrackings`, params).then(() => { + this.$http.post(`/ticket/api/TicketTrackings/changeState`, params).then(() => { this.card.reload(); + this.vnApp.showMessage(this.translate.instant('Data saved')); }); } - onRemoveLinesClick() { - let lines = { - delete: [] - }; - let data = this.$.index.model.instances; - if (data) - for (let i = 0; i < data.length;) { - if (data[i].checked) { - lines.delete.push(data[i].id); - data.splice(i, 1); - } else { - i++; - } - } - - let query = `/ticket/api/Sales/crudSale`; - this.$http.post(query, lines); + // Add Turn + showAddTurnDialog() { + this.$.addTurn.show(); } + addTurn(day) { + let params = {ticketFk: this.$state.params.id, weekDay: day}; + this.$http.patch(`/ticket/api/TicketWeeklies`, params).then(() => { + this.$.addTurn.hide(); + }); + } + + // Delete Ticket + showDeleteTicketDialog() { + this.$.deleteConfirmation.show(); + } + + returnDeleteTicketDialog(response) { + if (response === 'ACCEPT') + this.deleteTicket(); + } + + deleteTicket() { + let params = {id: this.$state.params.id}; + this.$http.post(`/ticket/api/Tickets/deleted`, params).then(() => { + this.$state.go('ticket.list'); + }); + } + + // Remove Lines + onRemoveLinesClick() { + let sales = this.getCheckedLines(); + let params = {sales: sales, actualTicketFk: this.ticket.id}; + let query = `/ticket/api/Sales/removes`; + this.$http.post(query, params).then(() => { + this.removeInstances(sales); + }); + } + + // Move Lines + showTransferPopover(event) { + let filter = {clientFk: this.ticket.clientFk, ticketFk: this.ticket.id}; + let json = encodeURIComponent(JSON.stringify(filter)); + this.$http.get(`/ticket/api/Tickets/threeLastActive?filter=${json}`).then(res => { + this.lastThreeTickets = res.data; + }); + this.$.transfer.parent = event.target; + this.$.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); + }); + } + + /* newTicket() { + let params = [this.ticket.clientFk, this.ticket.warehouseFk, this.ticket.companyFk, this.ticket.addressFk, this.ticket.agencyModeFk, null]; + this.$http.post(`/ticket/api/Tickets/create`, params).then(res => { + console.log(res); + }); + }*/ + + goToTicket(ticketID) { + this.$state.go("ticket.card.sale", {id: ticketID}); + } + + removeInstances(instances) { + for (let i = instances.length - 1; i >= 0; i--) { + this.$.index.model.instances.splice(instances[i].instance, 1); + } + } + // Item Descriptor showDescriptor(event, itemFk) { this.$.descriptor.itemFk = itemFk; this.$.descriptor.parent = event.target; this.$.descriptor.show(); } + onDescriptorLoad() { this.$.popover.relocate(); } + + // Ticket Create + showticketCreate() { + console.log(this); + this.$.newTicket.show(); + } + + onResponse(response) { + if (response === 'ACCEPT') { + let newTicketID = this.$.newTicket.dialog.createTicket(); + console.log(newTicketID); + } + } + // Edit Line + _getworkerMana() { + this.$http.get(`/api/WorkerManas/getCurrentWorkerMana`).then(res => { + this.workerMana = res.data[0].mana; + }); + } + + showEditPopover(event, sale) { + this.sale = sale; + this.edit = { + id: sale.id, + quantity: sale.quantity, + price: sale.price, + discount: sale.discount + }; + this.$.edit.parent = event.target; + this._getworkerMana(); + this.$.edit.show(); + } + + updateLine() { + if (this.edit.quantity != this.sale.quantity) { + this.$http.post(`/ticket/api/Sales/updateQuantity`, {id: this.edit.id, quantity: this.edit.quantity}).then(() => { + this.sale.quantity = this.edit.quantity; + }); + } + + if (this.edit.price != this.sale.price) { + this.$http.post(`/ticket/api/Sales/updatePrice`, {id: this.edit.id, price: this.edit.price}).then(() => { + this.sale.price = this.edit.price; + }); + } + + if (this.edit.discount != this.sale.discount) { + this.$http.post(`/ticket/api/Sales/updateDiscount`, {id: this.edit.id, discount: this.edit.discount}).then(() => { + this.sale.discount = this.edit.discount; + }); + } + this.$.edit.hide(); + } } -Controller.$inject = ['$scope', '$timeout', '$state', '$http']; +Controller.$inject = ['$scope', '$timeout', '$state', '$http', 'vnApp']; ngModule.component('vnTicketSale', { template: require('./index.html'), diff --git a/client/ticket/src/sale/sale.spec.js b/client/ticket/src/sale/sale.spec.js index 729a9c4b77..94f84e73e0 100644 --- a/client/ticket/src/sale/sale.spec.js +++ b/client/ticket/src/sale/sale.spec.js @@ -1,6 +1,6 @@ import './index.js'; -describe('Ticket', () => { +xdescribe('Ticket', () => { describe('Component vnTicketSale', () => { let $componentController; let controller; @@ -57,7 +57,7 @@ describe('Ticket', () => { describe('onStateChange()', () => { it('should perform a post and then call a function', () => { - $httpBackend.expectPOST(`/ticket/api/TicketTrackings`).respond(); + $httpBackend.expectPOST(`/ticket/api/TicketTrackings/changeState`).respond(); controller.card = {reload: () => {}}; controller.onStateChange(3); $httpBackend.flush(); diff --git a/client/ticket/src/sale/style.scss b/client/ticket/src/sale/style.scss new file mode 100644 index 0000000000..83d73bb2a9 --- /dev/null +++ b/client/ticket/src/sale/style.scss @@ -0,0 +1,44 @@ +@import "colors"; + +vn-popover.edit { + + & div.popover{ + width: 200px; + } + + & vn-horizontal.header{ + background-color: $main-01; + text-align: center; + + & h5{ + color: white; + } + } +} + +vn-ticket-sale{ + & tr .mdl-textfield{ + width: inherit; + max-width: 100%; + } +} + +vn-popover.transfer{ + & table { + min-width: 650px; + margin-bottom: 10px; + } + & i { + padding-top: 0.2em; + font-size: 1.8em; + } +} + +vn-dialog.ticket-create{ + & vn-button[label=Cancel]{ + display: none; + } + & vn-card.vn-ticket-create{ + padding: 0!important; + } +} \ No newline at end of file diff --git a/services/loopback/common/methods/sale/moveToTicket.js b/services/loopback/common/methods/sale/moveToTicket.js new file mode 100644 index 0000000000..45b7f49dfb --- /dev/null +++ b/services/loopback/common/methods/sale/moveToTicket.js @@ -0,0 +1,35 @@ +module.exports = Self => { + Self.remoteMethod('moveToTicket', { + description: 'Change the state of a ticket', + accessType: '', + accepts: [{ + arg: 'params', + type: 'object', + required: true, + description: '[sales IDs], newTicketFk, actualTicketFk', + http: {source: 'body'} + }], + returns: { + type: 'string', + root: true + }, + http: { + path: `/moveToTicket`, + verb: 'post' + } + }); + + Self.moveToTicket = async params => { + let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(params.actualTicketFk); + if (!thisTicketIsEditable) + throw new Error(`The sales of this ticket can't be modified`); + + let newTicketIsEditable = await Self.app.models.Ticket.isEditable(params.newTicketFk); + if (!newTicketIsEditable) + throw new Error(`The sales of this 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}); + } + }; +}; diff --git a/services/loopback/common/methods/sale/removes.js b/services/loopback/common/methods/sale/removes.js new file mode 100644 index 0000000000..24c8e7783d --- /dev/null +++ b/services/loopback/common/methods/sale/removes.js @@ -0,0 +1,31 @@ +module.exports = Self => { + Self.remoteMethod('removes', { + description: 'Change the state of a ticket', + accessType: '', + accepts: [{ + arg: 'params', + type: 'object', + required: true, + description: '[sales IDs], actualTicketFk', + http: {source: 'body'} + }], + returns: { + type: 'string', + root: true + }, + http: { + path: `/removes`, + verb: 'post' + } + }); + + Self.removes = async params => { + let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(params.actualTicketFk); + if (!thisTicketIsEditable) + throw new Error(`The sales of this ticket can't be modified`); + + for (let i = 0; i < params.sales.length; i++) { + await Self.app.models.Sale.destroyById(params.sales[i].id); + } + }; +}; diff --git a/services/loopback/common/methods/ticket/deleted.js b/services/loopback/common/methods/ticket/deleted.js new file mode 100644 index 0000000000..36bffaf953 --- /dev/null +++ b/services/loopback/common/methods/ticket/deleted.js @@ -0,0 +1,25 @@ +module.exports = Self => { + Self.remoteMethod('deleted', { + description: 'Sets the isDeleted value of a ticket to 1', + accessType: '', + accepts: [{ + arg: 'ticketFk', + type: 'Object', + required: true, + description: 'TicketFk', + http: {source: 'body'} + }], + returns: { + type: 'string', + root: true + }, + http: { + path: `/deleted`, + verb: 'post' + } + }); + + Self.deleted = async params => { + return await Self.app.models.Ticket.update({id: params.id}, {isDeleted: '1'}); + }; +}; diff --git a/services/loopback/common/methods/ticket/isEditable.js b/services/loopback/common/methods/ticket/isEditable.js index 149a87ee11..a3968a3150 100644 --- a/services/loopback/common/methods/ticket/isEditable.js +++ b/services/loopback/common/methods/ticket/isEditable.js @@ -21,7 +21,7 @@ module.exports = Self => { Self.isEditable = async ticketFk => { let state = await Self.app.models.TicketState.findOne({where: {ticketFk: ticketFk}, fields: 'alertLevel'}); - - return state != null && state.alertLevel == 0; + let exists = await Self.app.models.Ticket.findOne({where: {id: ticketFk}, fields: 'isDeleted'}); + return (exists && state == null && exists.isDeleted == 0) || (exists.isDeleted == 0 && state.alertLevel == 0); }; }; diff --git a/services/loopback/common/methods/ticket/threeLastActive.js b/services/loopback/common/methods/ticket/threeLastActive.js new file mode 100644 index 0000000000..9ec1390cab --- /dev/null +++ b/services/loopback/common/methods/ticket/threeLastActive.js @@ -0,0 +1,35 @@ +module.exports = Self => { + Self.remoteMethod('threeLastActive', { + description: 'Returns the last three tickets of a client that have the alertLevel at 0 and the shiped day is gt today', + accessType: '', + accepts: [{ + arg: 'filter', + type: 'object', + required: true, + description: 'client id, ticketFk' + }], + returns: { + type: [this.modelName], + root: true + }, + http: { + path: `/threeLastActive`, + verb: 'GET' + } + }); + + Self.threeLastActive = async filter => { + console.log(filter); + let query = ` + SELECT t.id,t.shipped,a.name AS agencyName,w.name AS warehouseName + FROM vn.ticket t + JOIN vn.ticketState ts ON t.id = ts.ticketFk + JOIN vn.agencyMode a ON t.agencyModeFk = a.id + JOIN vn.warehouse w ON t.warehouseFk = w.id + WHERE t.shipped > CURDATE() AND t.clientFk = ? AND ts.alertLevel = 0 AND t.id <> ? + ORDER BY t.shipped + LIMIT 3`; + let result = await Self.rawSql(query, [filter.clientFk, filter.ticketFk]); + return result; + }; +}; diff --git a/services/loopback/common/models/sale.js b/services/loopback/common/models/sale.js index 755cd432ec..2d2aa22f56 100644 --- a/services/loopback/common/models/sale.js +++ b/services/loopback/common/models/sale.js @@ -3,4 +3,9 @@ module.exports = Self => { require('../methods/sale/saleComponentFilter')(Self); require('../methods/sale/priceDifference')(Self); require('../methods/sale/crudSale')(Self); + require('../methods/sale/moveToTicket')(Self); + require('../methods/sale/removes')(Self); +// require('../methods/sale/updateDiscount')(Self); +// require('../methods/sale/updatePrice')(Self); +// require('../methods/sale/updateQuantity')(Self); }; diff --git a/services/loopback/common/models/ticket.js b/services/loopback/common/models/ticket.js index a2897354c5..7005a3fae0 100644 --- a/services/loopback/common/models/ticket.js +++ b/services/loopback/common/models/ticket.js @@ -8,4 +8,8 @@ module.exports = Self => { require('../methods/ticket/getTotal')(Self); require('../methods/ticket/getTaxes')(Self); require('../methods/ticket/componentUpdate')(Self); +// require('../methods/ticket/create')(Self); + require('../methods/ticket/isEditable')(Self); + require('../methods/ticket/threeLastActive')(Self); + require('../methods/ticket/deleted')(Self); };