577 lines
16 KiB
JavaScript
577 lines
16 KiB
JavaScript
import ngModule from '../module';
|
|
import Section from 'salix/components/section';
|
|
import './style.scss';
|
|
|
|
class Controller extends Section {
|
|
constructor($element, $) {
|
|
super($element, $);
|
|
this._sales = [];
|
|
this.manaCode = 'mana';
|
|
this.getConfig();
|
|
}
|
|
|
|
sortBy(propertyName) {
|
|
this.reverse = (this.propertyName === propertyName) ? !this.reverse : false;
|
|
this.propertyName = propertyName;
|
|
}
|
|
|
|
get manaCode() {
|
|
return this._manaCode;
|
|
}
|
|
|
|
set manaCode(value) {
|
|
this._manaCode = value;
|
|
}
|
|
|
|
get ticket() {
|
|
return this._ticket;
|
|
}
|
|
|
|
set ticket(value) {
|
|
this._ticket = value;
|
|
this.isTicketEditable();
|
|
this.isTicketLocked();
|
|
}
|
|
|
|
get sales() {
|
|
if (this._sales) {
|
|
for (let sale of this._sales)
|
|
sale.amount = this.getSaleTotal(sale);
|
|
}
|
|
|
|
return this._sales;
|
|
}
|
|
|
|
set sales(value) {
|
|
this._sales = value;
|
|
}
|
|
|
|
get ticketState() {
|
|
const ticket = this.ticket;
|
|
if (!ticket) return null;
|
|
|
|
const ticketState = ticket.ticketState;
|
|
|
|
return ticketState && ticketState.state.code;
|
|
}
|
|
|
|
getConfig() {
|
|
let filter = {
|
|
fields: ['daysForWarningClaim'],
|
|
};
|
|
this.$http.get(`TicketConfigs`, {filter})
|
|
.then(res => {
|
|
this.ticketConfig = res.data;
|
|
});
|
|
}
|
|
|
|
get isClaimable() {
|
|
if (this.ticket) {
|
|
const landedPlusWeek = new Date(this.ticket.landed);
|
|
landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
|
|
|
|
const hasClaimManagerRole = this.aclService.hasAny(['claimManager']);
|
|
|
|
return landedPlusWeek >= Date.vnNew() || hasClaimManagerRole;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
getSaleTotal(sale) {
|
|
if (sale.quantity == null || sale.price == null)
|
|
return null;
|
|
|
|
const price = sale.quantity * sale.price;
|
|
const discount = (sale.discount * price) / 100;
|
|
|
|
return price - discount;
|
|
}
|
|
|
|
getMana() {
|
|
this.$http.get(`Tickets/${this.$params.id}/getSalesPersonMana`)
|
|
.then(res => {
|
|
this.edit.mana = res.data;
|
|
this.$.$applyAsync(() => {
|
|
this.$.editDiscount.relocate();
|
|
this.$.editPricePopover.relocate();
|
|
});
|
|
});
|
|
this.getUsesMana();
|
|
}
|
|
|
|
getUsesMana() {
|
|
this.$http.get(`Sales/usesMana`)
|
|
.then(res => {
|
|
this.usesMana = res.data;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Returns checked instances
|
|
*
|
|
* @return {Array} Checked instances
|
|
*/
|
|
selectedSales() {
|
|
if (!this.sales) return;
|
|
|
|
return this.sales.filter(sale => {
|
|
return sale.checked;
|
|
});
|
|
}
|
|
|
|
selectedValidSales() {
|
|
if (!this.sales) return;
|
|
|
|
const selectedSales = this.selectedSales();
|
|
return selectedSales.filter(sale => {
|
|
return sale.id != undefined;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Returns the total of checked instances
|
|
*
|
|
* @return {Number} Total checked instances
|
|
*/
|
|
selectedSalesCount() {
|
|
const selectedSales = this.selectedSales();
|
|
if (selectedSales)
|
|
return selectedSales.length;
|
|
|
|
return 0;
|
|
}
|
|
|
|
hasSelectedSales() {
|
|
return this.selectedSalesCount() > 0;
|
|
}
|
|
|
|
hasOneSaleSelected() {
|
|
if (this.selectedSalesCount() === 1)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns new instances
|
|
*
|
|
* @return {Array} New instances
|
|
*/
|
|
newInstances() {
|
|
if (!this.sales) return;
|
|
|
|
return this.sales.filter(sale => {
|
|
return !sale.id;
|
|
});
|
|
}
|
|
|
|
resetChanges() {
|
|
if (this.newInstances().length === 0)
|
|
this.$.watcher.updateOriginalData();
|
|
|
|
this.card.reload();
|
|
}
|
|
|
|
state(value) {
|
|
const params = {ticketFk: this.$params.id, code: value};
|
|
return this.$http.post('Tickets/state', params).then(() => {
|
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
this.card.reload();
|
|
}).finally(() => this.resetChanges());
|
|
}
|
|
|
|
removeSales() {
|
|
const sales = this.selectedValidSales();
|
|
const params = {sales: sales, ticketId: this.ticket.id};
|
|
this.$http.post(`Sales/deleteSales`, params).then(() => {
|
|
this.removeSelectedSales();
|
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
}).finally(() => this.resetChanges());
|
|
}
|
|
|
|
removeSelectedSales() {
|
|
const sales = this.selectedSales();
|
|
sales.forEach(sale => {
|
|
const index = this.sales.indexOf(sale);
|
|
this.sales.splice(index, 1);
|
|
});
|
|
}
|
|
|
|
createClaim() {
|
|
const today = new Date();
|
|
today.setHours(0, 0, 0, 0);
|
|
const timeDifference = today.getTime() - new Date(this.ticket.landed).getTime();
|
|
|
|
const pastDays = Math.floor(timeDifference / 86400000);
|
|
|
|
if (pastDays >= this.ticketConfig[0].daysForWarningClaim)
|
|
this.$.claimConfirm.show();
|
|
else
|
|
this.$.claimSure.show();
|
|
}
|
|
|
|
onCreateClaimAccepted() {
|
|
const sales = this.selectedValidSales();
|
|
const params = {ticketId: this.ticket.id, sales: sales};
|
|
this.resetChanges();
|
|
this.$http.post(`Claims/createFromSales`, params)
|
|
.then(async res => window.location.href = await this.vnApp.getUrl(`claim/${res.data.id}/basic-data`));
|
|
}
|
|
|
|
showTransferPopover(event) {
|
|
this.setTransferParams();
|
|
this.$.transfer.show(event);
|
|
}
|
|
|
|
setTransferParams() {
|
|
const checkedSales = JSON.stringify(this.selectedValidSales());
|
|
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 => {
|
|
if (res.data && res.data.id === this.ticket.id) {
|
|
this.$.transfer.hide();
|
|
this.$.model.refresh();
|
|
} else this.$state.go('ticket.card.sale', {id: res.data.id});
|
|
});
|
|
}
|
|
|
|
showEditPricePopover(event, sale) {
|
|
if (!this.isEditable) return;
|
|
|
|
this.edit = {
|
|
price: sale.price,
|
|
sale: sale
|
|
};
|
|
this.$.editPricePopover.show(event);
|
|
}
|
|
|
|
updatePrice() {
|
|
const sale = this.edit.sale;
|
|
const newPrice = this.edit.price;
|
|
if (newPrice != null && newPrice != sale.price) {
|
|
const query = `Sales/${sale.id}/updatePrice`;
|
|
this.$http.post(query, {newPrice}).then(res => {
|
|
sale.price = res.data.price;
|
|
this.edit = null;
|
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
}).finally(() => this.resetChanges());
|
|
}
|
|
|
|
this.$.editPricePopover.hide();
|
|
}
|
|
|
|
showEditDiscountPopover(event, sale) {
|
|
if (this.isLocked) return;
|
|
if (sale) {
|
|
this.edit = {
|
|
discount: sale.discount,
|
|
sale: sale
|
|
};
|
|
} else {
|
|
this.edit = {
|
|
discount: null,
|
|
sales: this.selectedValidSales()
|
|
};
|
|
}
|
|
|
|
this.$.editDiscount.show(event);
|
|
}
|
|
|
|
changeDiscount() {
|
|
const sale = this.edit.sale;
|
|
const newDiscount = this.edit.discount;
|
|
if (newDiscount != null && newDiscount != sale.discount)
|
|
this.updateDiscount([sale]);
|
|
|
|
this.$.editDiscount.hide();
|
|
}
|
|
|
|
changeMultipleDiscount() {
|
|
const sales = this.edit.sales;
|
|
const newDiscount = this.edit.discount;
|
|
const hasChanges = sales.some(sale => {
|
|
return sale.discount != newDiscount;
|
|
});
|
|
if (newDiscount != null && hasChanges)
|
|
this.updateDiscount(sales);
|
|
|
|
this.$.editDiscount.hide();
|
|
}
|
|
|
|
updateDiscount(sales) {
|
|
const saleIds = sales.map(sale => {
|
|
return sale.id;
|
|
});
|
|
|
|
const params = {salesIds: saleIds, newDiscount: this.edit.discount, manaCode: this.manaCode};
|
|
const query = `Tickets/${this.$params.id}/updateDiscount`;
|
|
this.$http.post(query, params).then(() => {
|
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
|
|
for (let sale of sales)
|
|
sale.discount = this.edit.discount;
|
|
|
|
this.edit = null;
|
|
}).finally(() => this.resetChanges());
|
|
}
|
|
|
|
getNewPrice() {
|
|
if (this.edit.sale) {
|
|
const sale = this.edit.sale;
|
|
let newDiscount = sale.discount;
|
|
let newPrice = this.edit.price || sale.price;
|
|
|
|
if (this.edit.discount != null)
|
|
newDiscount = this.edit.discount;
|
|
|
|
if (this.edit.price != null)
|
|
newPrice = this.edit.price;
|
|
|
|
const price = sale.quantity * newPrice;
|
|
const discount = (newDiscount * price) / 100;
|
|
|
|
return price - discount;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
hasReserves() {
|
|
return this.sales.some(sale => {
|
|
return sale.reserved == true;
|
|
});
|
|
}
|
|
|
|
/*
|
|
* Unmark sale as reserved
|
|
*/
|
|
unmarkAsReserved() {
|
|
this.setReserved(false);
|
|
}
|
|
|
|
/*
|
|
* Mark sale as reserved
|
|
*/
|
|
markAsReserved() {
|
|
this.setReserved(true);
|
|
}
|
|
|
|
setReserved(reserved) {
|
|
const selectedSales = this.selectedValidSales();
|
|
const params = {ticketId: this.ticket.id, sales: selectedSales, reserved: reserved};
|
|
this.$http.post(`Sales/reserve`, params).then(() => {
|
|
selectedSales.forEach(sale => {
|
|
sale.reserved = reserved;
|
|
});
|
|
}).finally(() => this.resetChanges());
|
|
}
|
|
|
|
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.$t('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.selectedValidSales();
|
|
const items = sales.map(sale => {
|
|
return `${sale.quantity} ${sale.concept}`;
|
|
});
|
|
const notAvailables = items.join(', ');
|
|
const params = {
|
|
ticketFk: this.ticket.id,
|
|
created: this.ticket.updated,
|
|
landed: this.ticket.landed,
|
|
notAvailables
|
|
};
|
|
this.newSMS = {
|
|
ticketId: this.ticket.id,
|
|
destinationFk: this.ticket.clientFk,
|
|
destination: phone,
|
|
message: this.$t('Product not available', params)
|
|
};
|
|
this.$.sms.open();
|
|
}
|
|
|
|
onSmsSend(sms) {
|
|
return this.$http.post(`Tickets/${this.ticket.id}/sendSms`, sms)
|
|
.then(() => this.vnApp.showSuccess(this.$t('SMS sent')));
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
changeQuantity(sale) {
|
|
if (!sale.itemFk || sale.quantity == null) return;
|
|
|
|
if (!sale.id)
|
|
return this.addSale(sale);
|
|
|
|
this.updateQuantity(sale);
|
|
}
|
|
|
|
/*
|
|
* Changes a sale quantity
|
|
*/
|
|
updateQuantity(sale) {
|
|
const data = {quantity: sale.quantity};
|
|
this.$http.post(`Sales/${sale.id}/updateQuantity`, data).then(() => {
|
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
}).catch(e => {
|
|
this.$.model.refresh();
|
|
throw e;
|
|
}).finally(() => this.resetChanges());
|
|
}
|
|
|
|
/*
|
|
* Changes a sale concept
|
|
*/
|
|
updateConcept(sale) {
|
|
const data = {newConcept: sale.concept};
|
|
this.$http.post(`Sales/${sale.id}/updateConcept`, data).then(() => {
|
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
}).catch(e => {
|
|
this.$.model.refresh();
|
|
throw e;
|
|
}).finally(() => this.resetChanges());
|
|
}
|
|
|
|
/*
|
|
* Adds a new sale
|
|
*/
|
|
addSale(sale) {
|
|
const data = {
|
|
barcode: 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.$t('Data saved!'));
|
|
}).finally(() => this.resetChanges());
|
|
}
|
|
|
|
isTicketEditable() {
|
|
this.$http.get(`Tickets/${this.$params.id}/isEditable`)
|
|
.then(res => this.isEditable = res.data);
|
|
}
|
|
|
|
isTicketLocked() {
|
|
this.$http.get(`Tickets/${this.$params.id}/isLocked`)
|
|
.then(res => this.isLocked = res.data);
|
|
}
|
|
|
|
calculateSalePrice() {
|
|
const sales = this.selectedValidSales();
|
|
if (!sales) return;
|
|
|
|
const query = `Sales/recalculatePrice`;
|
|
this.$http.post(query, sales).then(() => {
|
|
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
this.$.model.refresh();
|
|
});
|
|
}
|
|
|
|
createRefund(withWarehouse) {
|
|
const sales = this.selectedValidSales();
|
|
if (!sales) return;
|
|
|
|
const salesIds = sales.map(sale => sale.id);
|
|
const params = {salesIds: salesIds, withWarehouse: withWarehouse, negative: true};
|
|
const query = 'Sales/clone';
|
|
this.$http.post(query, params).then(res => {
|
|
const [refundTicket] = res.data;
|
|
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
|
|
ticketId: refundTicket.id
|
|
}));
|
|
this.$state.go('ticket.card.sale', {id: refundTicket.id});
|
|
|
|
this.resetChanges();
|
|
});
|
|
}
|
|
|
|
itemSearchFunc($search) {
|
|
return /^\d+$/.test($search)
|
|
? {id: $search}
|
|
: {name: {like: '%' + $search + '%'}};
|
|
}
|
|
|
|
save() {
|
|
if (this.edit.sale) this.changeDiscount();
|
|
if (this.edit.sales) this.changeMultipleDiscount();
|
|
}
|
|
|
|
cancel() {
|
|
this.$.editDiscount.hide();
|
|
}
|
|
|
|
goToLog(saleId) {
|
|
this.$state.go('ticket.card.log', {
|
|
originId: this.$params.id,
|
|
changedModel: 'Sale',
|
|
changedModelId: saleId
|
|
});
|
|
}
|
|
|
|
async goToLilium(section, id) {
|
|
window.location.href = await this.vnApp.getUrl(`claim/${id}/${section}`);
|
|
}
|
|
}
|
|
|
|
ngModule.vnComponent('vnTicketSale', {
|
|
template: require('./index.html'),
|
|
controller: Controller,
|
|
bindings: {
|
|
ticket: '<'
|
|
},
|
|
require: {
|
|
card: '?^vnTicketCard'
|
|
}
|
|
});
|