553 lines
15 KiB
JavaScript
553 lines
15 KiB
JavaScript
import ngModule from '../module';
|
|
import Section from 'salix/components/section';
|
|
import './style.scss';
|
|
|
|
class Controller extends Section {
|
|
constructor($element, $) {
|
|
super($element, $);
|
|
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 = [];
|
|
}
|
|
|
|
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.$params.id || !this.sales) return;
|
|
this.$http.get(`Tickets/${this.$params.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.$params.id || !this.sales) return;
|
|
this.$http.get(`Tickets/${this.$params.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.$.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.$.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.$.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!'));
|
|
});
|
|
}
|
|
}
|
|
|
|
showTransferPopover(event) {
|
|
this.setTransferParams();
|
|
this.$.transfer.parent = event.target;
|
|
this.$.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.$.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.$.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;
|
|
});
|
|
}
|
|
|
|
showEditPricePopover(event, sale) {
|
|
if (!this.isEditable) return;
|
|
this.sale = sale;
|
|
this.newPrice = this.sale.price;
|
|
this.edit = {
|
|
ticketFk: this.ticket.id,
|
|
id: sale.id,
|
|
quantity: sale.quantity
|
|
};
|
|
this.$.editPricePopover.parent = event.target;
|
|
this.$.editPricePopover.show();
|
|
}
|
|
|
|
updatePrice() {
|
|
if (this.newPrice && this.newPrice != this.sale.price) {
|
|
const query = `Sales/${this.edit.id}/updatePrice`;
|
|
this.$http.post(query, {newPrice: this.newPrice}).then(res => {
|
|
this.sale.price = res.data.price;
|
|
|
|
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
|
|
}).finally(() => {
|
|
if (this.newInstances().length === 0)
|
|
this.$.watcher.updateOriginalData();
|
|
});
|
|
}
|
|
|
|
this.$.editPricePopover.hide();
|
|
}
|
|
|
|
updateNewPrice() {
|
|
this.newPrice = this.sale.quantity * this.newPrice - ((this.sale.discount * (this.sale.quantity * this.newPrice)) / 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.$.editPopover.parent = event.target;
|
|
this.$.editPopover.show();
|
|
}
|
|
|
|
showEditDialog() {
|
|
this.edit = this.checkedLines();
|
|
this.$.editDialog.show();
|
|
}
|
|
|
|
hideEditDialog() {
|
|
this.$.model.refresh();
|
|
this.$.editDialog.hide();
|
|
}
|
|
|
|
hideEditPopover() {
|
|
this.$.model.refresh();
|
|
this.$.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.$.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.$.sms.open();
|
|
}
|
|
|
|
/**
|
|
* Inserts a new instance
|
|
*/
|
|
add() {
|
|
this.$.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.$.model.refresh();
|
|
throw e;
|
|
}).finally(() => {
|
|
if (this.newInstances().length === 0)
|
|
this.$.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.$.model.refresh();
|
|
throw e;
|
|
}).finally(() => {
|
|
if (this.newInstances().length === 0)
|
|
this.$.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.$.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.$.model.refresh();
|
|
});
|
|
}
|
|
|
|
itemSearchFunc($search) {
|
|
return /^\d+$/.test($search)
|
|
? {id: $search}
|
|
: {name: {like: '%' + $search + '%'}};
|
|
}
|
|
}
|
|
|
|
ngModule.component('vnTicketSale', {
|
|
template: require('./index.html'),
|
|
controller: Controller,
|
|
bindings: {
|
|
ticket: '<'
|
|
},
|
|
require: {
|
|
card: '?^vnTicketCard'
|
|
}
|
|
});
|