461 lines
13 KiB
JavaScript
461 lines
13 KiB
JavaScript
const DEF_DELAY = 1200;
|
||
function sleep(ms) {
|
||
return new Promise(resolve => setTimeout(resolve, ms || DEF_DELAY));
|
||
}
|
||
|
||
var config = require('./config');
|
||
|
||
const request = require('request');
|
||
|
||
function isJson(str) {
|
||
return str.constructor === ({}).constructor;
|
||
}
|
||
function canBeJson(str) {
|
||
try {
|
||
JSON.parse(str);
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
function convertDate(inputFormat) {
|
||
function pad(s) { return (s < 10) ? '0' + s : s; }
|
||
var d = new Date(inputFormat)
|
||
return [pad(d.getDate()), pad(d.getMonth()+1), d.getFullYear()].join('.')
|
||
}
|
||
|
||
const weekdays = ['Воскресенье','Понедельник','Вторник','Среда','Четверг','Пятница','Суббота']
|
||
class Courier{
|
||
|
||
free_slots = {};
|
||
old_free_slots = [];
|
||
|
||
is_waiting = false;
|
||
|
||
constructor(user) {
|
||
this.id = user.id;
|
||
this.username = user.username||'no_username';
|
||
this.password = user.password||'no_password';
|
||
this.token = user.token||'unauthorized';
|
||
this.mode = user.mode||0;
|
||
this.zones = user.zones||[];
|
||
}
|
||
|
||
updateUser(user) {
|
||
this.id = user.id||this.id;
|
||
this.username = user.username||this.username;
|
||
this.password = user.password||this.password;
|
||
this.token = user.token||this.token||'unauthorized';
|
||
this.mode = user.mode||this.mode||0;
|
||
this.zones = user.zones||this.zones||[];
|
||
}
|
||
|
||
async auth(){
|
||
var status = 'waiting';
|
||
var token = this.token;
|
||
|
||
await request.post(`https://courier.eda.yandex/api/v2/authenticate`,{
|
||
headers: {
|
||
"x-app-version": " 5.2.5"
|
||
},
|
||
body: JSON.stringify({
|
||
"username": this.username,
|
||
"password": this.password
|
||
})
|
||
}, await function(err, response, body) {
|
||
if(err) {
|
||
console.log(err)
|
||
return status = false;
|
||
}
|
||
|
||
if(canBeJson(body))body=JSON.parse(body);
|
||
|
||
if(body.isSuccess){
|
||
token = body.payload.apiKey||'unauthorized';
|
||
status = true;
|
||
}
|
||
else {
|
||
console.log(body)
|
||
return status = false;
|
||
}
|
||
});
|
||
|
||
while(status == 'waiting') {
|
||
await sleep(100);
|
||
}
|
||
this.token = token;
|
||
|
||
return status;
|
||
}
|
||
|
||
async getInfo(){
|
||
var returned_info = {
|
||
isSuccess: 'waiting'
|
||
}
|
||
|
||
await request.get(`https://courier.eda.yandex/api/v2/courier/info`,{
|
||
headers: {
|
||
"x-api-token": this.token
|
||
}
|
||
},await function(err, response, body) {
|
||
if(err) return returned_info.isSuccess = 'false';
|
||
|
||
if(canBeJson(body))body=JSON.parse(body);
|
||
|
||
if(body.isSuccess){
|
||
returned_info.isSuccess = 'true';
|
||
returned_info.user = {
|
||
id: body.payload.id,
|
||
name: body.payload.fullName.surname + ' ' + body.payload.fullName.firstName + ' ' + body.payload.fullName.patronymic,
|
||
status: body.payload.status
|
||
};
|
||
}
|
||
else return returned_info.isSuccess = 'false';
|
||
});
|
||
|
||
while(returned_info.isSuccess == 'waiting') {
|
||
await sleep(100);
|
||
}
|
||
this.info = returned_info.user;
|
||
|
||
return returned_info.isSuccess == 'true';
|
||
}
|
||
|
||
async getPlannedFromServer(){
|
||
var returned_info = {
|
||
isSuccess: 'waiting'
|
||
}
|
||
|
||
await request.get(`https://ctt.eda.yandex/courier-shifts/actual`,{
|
||
headers: {
|
||
"Authorization": 'Bearer ' + this.token
|
||
}
|
||
},await function(err, response, body) {
|
||
if(err) {
|
||
console.log(err)
|
||
return returned_info.isSuccess = 'false';
|
||
}
|
||
|
||
//console.log(body)
|
||
if(canBeJson(body))body=JSON.parse(body);
|
||
if(body.errors) {
|
||
returned_info.errors = body.errors;
|
||
return returned_info.isSuccess = 'false';
|
||
}
|
||
if(body.data)
|
||
returned_info = body.data;
|
||
});
|
||
|
||
while(returned_info.isSuccess == 'waiting') {
|
||
await sleep(100);
|
||
}
|
||
|
||
return returned_info;
|
||
}
|
||
|
||
async getPlanned(){
|
||
var info = await this.getPlannedFromServer();
|
||
var slots_info = {}
|
||
for(var slot of info){
|
||
if(slot.attributes.status == 'Planned'){
|
||
var time_start = (new Date(Date.parse(slot.attributes.startsAt)));
|
||
var time_end = (new Date(Date.parse(slot.attributes.endsAt)));
|
||
if(!slots_info[time_start.toLocaleDateString({ timeZone: 'Europe/Moscow' })]) slots_info[time_start.toLocaleDateString({ timeZone: 'Europe/Moscow' })] = [];
|
||
var myslot = {
|
||
startsAt: time_start.toLocaleTimeString('ru-RU',{ timeZone: 'Europe/Moscow', hour12: false }),
|
||
endsAt: time_end.toLocaleTimeString('ru-RU',{ timeZone: 'Europe/Moscow', hour12: false }),
|
||
startPoint: slot.attributes.startPoint.attributes.name
|
||
}
|
||
if(slot.attributes.startLocation)myslot.startLocation = slot.attributes.startLocation.name;
|
||
slots_info[time_start.toLocaleDateString({ timeZone: 'Europe/Moscow' })].push(myslot)//.push('Работаю ' + (new Date(Date.parse(slot.attributes.startsAt))).toLocaleDateString())
|
||
}
|
||
}
|
||
this.planned = slots_info;
|
||
return await this.getPlannedText();
|
||
}
|
||
|
||
async getPlannedText(){
|
||
var answer = '<b>Запланированные слоты:</b>\n\n';
|
||
for(var date in this.planned){
|
||
answer += `<i>(${convertDate(date)}, ${weekdays[new Date(date).getDay()]})</i>\n`
|
||
for(var slot of this.planned[date]){
|
||
if(slot.startLocation)
|
||
answer += '>' + slot.startLocation + '\n';
|
||
answer += `Слот с ${slot.startsAt.substring(0,5)} до ${slot.endsAt.substring(0,5)}
|
||
`
|
||
}
|
||
answer += '\n';
|
||
}
|
||
if(answer == '<b>Запланированные слоты:</b>\n\n') answer = 'Нет запланнированных слотов'
|
||
return answer;
|
||
}
|
||
|
||
async getMyZones(){
|
||
var info = await this.getPlannedFromServer();
|
||
var zones = {}
|
||
for(var slot of info){
|
||
if(!zones[slot.attributes.startPoint.attributes.name])zones[slot.attributes.startPoint.attributes.name]=0;
|
||
zones[slot.attributes.startPoint.attributes.name]++;
|
||
}
|
||
// console.log(zones)
|
||
/* var main_zone = '';
|
||
var num = 0;*/
|
||
this.clearZones();
|
||
for(var zone in zones){
|
||
/* if(zones[zone]>num){
|
||
num = zones[zone];
|
||
main_zone = zone;
|
||
}*/
|
||
this.addZone(config.points[zone]);
|
||
}
|
||
/* if(main_zone!='')
|
||
this.addZone(config.points[main_zone]);*/
|
||
return zones;
|
||
}
|
||
|
||
async getFreeSlotsFromServer(date){
|
||
var returned_info = {
|
||
isSuccess: 'waiting'
|
||
}
|
||
var zones_filter = ``;
|
||
for(var zone of this.zones)
|
||
zones_filter += `&filters%5Bzones%5D%5B%5D=${zone}`;
|
||
|
||
await request.get(`https://ctt.eda.yandex/courier-shifts?filters%5Bdate%5D=${date}${zones_filter}`,{
|
||
headers: {
|
||
"Authorization": 'Bearer ' + this.token,
|
||
"x-app-version": '5.3.2'
|
||
}
|
||
},await function(err, response, body) {
|
||
if(err) {
|
||
console.log(err)
|
||
return returned_info.isSuccess = 'false';
|
||
}
|
||
|
||
if(canBeJson(body))body=JSON.parse(body);
|
||
if(body.errors) {
|
||
returned_info.errors = body.errors;
|
||
return returned_info.isSuccess = 'false';
|
||
}
|
||
if(body.data)
|
||
returned_info = body.data;
|
||
});
|
||
|
||
while(returned_info.isSuccess == 'waiting') {
|
||
await sleep(100);
|
||
}
|
||
|
||
return returned_info;
|
||
}
|
||
|
||
async getFreeSlots(date){
|
||
var day_info = await this.getFreeSlotsFromServer(convertDate(date));
|
||
if(day_info.isSuccess != 'false'){
|
||
var returned_info = {
|
||
date: date,
|
||
// cols: day_info.opened.length,
|
||
slots: []
|
||
}
|
||
for(var slot of day_info.opened){
|
||
var time_start = (new Date(Date.parse(slot.attributes.startsAt)));
|
||
var time_end = (new Date(Date.parse(slot.attributes.endsAt)));
|
||
var myslot = {
|
||
id: slot.id,
|
||
startsAt: time_start.toLocaleTimeString('ru-RU',{ timeZone: 'Europe/Moscow', hour12: false }),
|
||
endsAt: time_end.toLocaleTimeString('ru-RU',{ timeZone: 'Europe/Moscow', hour12: false }),
|
||
startPoint: slot.attributes.startPoint.attributes.name,
|
||
}
|
||
if(slot.attributes.startLocation)myslot.startLocation = slot.attributes.startLocation.name;
|
||
this.free_slots[date+'_'+myslot.startsAt+'_'+myslot.endsAt]=myslot;
|
||
returned_info.slots.push(myslot)
|
||
}
|
||
return this.getFreeSlotsText(returned_info);
|
||
}
|
||
else return 'Возникла ошибка ( используйте /relogin )\n';
|
||
}
|
||
|
||
async getFreeSlotsText(day_info){
|
||
var answer = '';
|
||
if(day_info.slots.length>0){
|
||
answer = `(${convertDate(day_info.date)}, ${weekdays[(new Date(day_info.date)).getDay()]})\n`
|
||
/* for(var slot of day_info.slots){
|
||
answer += `Слот с ${slot.startsAt.substring(0,5)} до ${slot.endsAt.substring(0,5)}`;
|
||
if(this.zones.length>1)
|
||
answer+=`(${slot.startPoint})`;
|
||
answer+=`\n`;
|
||
}*/
|
||
if(this.zones.length == 1)
|
||
for(var slot of day_info.slots){
|
||
if(slot.startLocation)
|
||
answer += '>' + slot.startLocation + '\n';
|
||
answer += `Слот с ${slot.startsAt.substring(0,5)} до ${slot.endsAt.substring(0,5)}
|
||
`;
|
||
}
|
||
else{
|
||
var zones = {}
|
||
|
||
for(var slot of day_info.slots){
|
||
if(slot.startLocation){
|
||
if(!zones[slot.startLocation])zones[slot.startLocation] = [];
|
||
zones[slot.startLocation].push(slot);
|
||
}
|
||
else {
|
||
if(!zones[slot.startPoint])zones[slot.startPoint] = [];
|
||
zones[slot.startPoint].push(slot);
|
||
}
|
||
}
|
||
|
||
for(var zone in zones){
|
||
answer += '>' + zones[zone][0].startLocation||zones[zone][0].startPoint + '\n';
|
||
for (var slot of zones[zone]){
|
||
answer += `Слот с ${slot.startsAt.substring(0,5)} до ${slot.endsAt.substring(0,5)}`;
|
||
answer += `\n`;
|
||
}
|
||
}
|
||
}
|
||
|
||
answer += '\n'
|
||
}
|
||
return answer;
|
||
}
|
||
|
||
async getFreeSlotsWeek(){
|
||
var answer = '<b>Свободные слоты:</b>\n\n';
|
||
var date = new Date(Date.now())
|
||
for(var i = 0; i<=10; i++){
|
||
answer += await this.getFreeSlots(date.toLocaleDateString({ timeZone: 'Europe/Moscow'}));
|
||
date.setDate(date.getDate() + 1);
|
||
}
|
||
if(answer == '<b>Свободные слоты:</b>\n\n') answer = 'Свободных слотов нет'
|
||
return answer;
|
||
}
|
||
|
||
async getNewFreeSlotsWeek(){
|
||
this.free_slots = {};
|
||
var date = new Date(Date.now())
|
||
for(var i = 0; i<=10; i++){
|
||
await this.getFreeSlots(date.toLocaleDateString({ timeZone: 'Europe/Moscow'}));
|
||
date.setDate(date.getDate() + 1);
|
||
}
|
||
var newslots = {};
|
||
for(var slot in this.free_slots){
|
||
if(this.old_free_slots.indexOf(slot)==-1){
|
||
let date = slot.split('_')[0];
|
||
if(!newslots[date])newslots[date]=[];
|
||
newslots[date].push(this.free_slots[slot]);
|
||
}
|
||
}
|
||
this.old_free_slots = Object.keys(this.free_slots);
|
||
return await this.getNewFreeSlotsWeekText(newslots);
|
||
}
|
||
|
||
async getNewFreeSlotsWeekText(newslots){
|
||
var answer = '<b>Доступны новые слоты:</b>\n\n';
|
||
for(var date in newslots){
|
||
answer += `<i>(${convertDate(date)}, ${weekdays[new Date(date).getDay()]})</i>\n`
|
||
for(var slot of newslots[date]){
|
||
answer += `Слот с ${slot.startsAt.substring(0,5)} до ${slot.endsAt.substring(0,5)}
|
||
`
|
||
}
|
||
answer += '\n';
|
||
}
|
||
if(answer == '<b>Доступны новые слоты:</b>\n\n') answer = 'no_answer'
|
||
return answer;
|
||
}
|
||
|
||
async getOrders(){
|
||
var returned_info = {
|
||
isSuccess: 'waiting'
|
||
}
|
||
|
||
await request.get(`https://courier.eda.yandex/api/v2/orders`,{
|
||
headers: {
|
||
"x-api-token": this.token
|
||
}
|
||
},await function(err, response, body) {
|
||
if(err) {
|
||
returned_info.err = err;
|
||
return returned_info.isSuccess = 'false';
|
||
}
|
||
|
||
if(canBeJson(body))body=JSON.parse(body);
|
||
if(body.errors)
|
||
returned_info.errors = body.errors;
|
||
if(!body.isSuccess){
|
||
returned_info.body = body;
|
||
return returned_info.isSuccess = 'false';
|
||
}
|
||
if(body.isSuccess)
|
||
returned_info = body;
|
||
});
|
||
|
||
while(returned_info.isSuccess == 'waiting') {
|
||
await sleep(100);
|
||
}
|
||
|
||
return returned_info;
|
||
}
|
||
|
||
async getOrdersText(orders_){
|
||
var orders = orders_||await this.getOrders();
|
||
var answer = '';
|
||
if(orders.isSuccess){
|
||
if(!orders.meta) return config.defaulttext.need_reauth;
|
||
if(orders.meta.count == 0)
|
||
return 'Нет заказов'
|
||
for await(var order of orders.payload.orders){
|
||
console.log(order)
|
||
answer += `<b>Заказ N:</b> <i>${order.orderNr}</i>
|
||
<b>Адрес:</b> ${order.customer.address.title}, подъезд ${order.customer.address.entrance||'-'}, этаж ${order.customer.address.floor||'-'}, квартира ${order.customer.address.office||order.customer.address.doorcode||'-'}
|
||
`
|
||
if(order.comment!=null)
|
||
answer += `<b>Комментарий:</b> ${order.comment}\n`;
|
||
answer += `<b>Вес:</b> ${order.weight/1000} кг.\n`;
|
||
answer += `<b>Цена:</b> ${order.subtotal} ${order.currency.sign}\n`;
|
||
if(order.deliveryFee!='0')
|
||
answer += `<b>Платная доставка:</b> ${order.deliveryFee} ${order.currency.sign}\n`;
|
||
answer += `\n<b>Блюда:</b>\n`
|
||
|
||
for(var item of order.cartItems)
|
||
answer += `${item.quantity} ${item.name}\n`
|
||
answer += `\n`
|
||
|
||
answer += `<b>Клиент:</b> <i>${order.customer.firstName||''} ${order.customer.lastName||''}</i>
|
||
<b>Телефон:</b> <i>${order.customer.phoneNumber}</i>
|
||
`
|
||
}
|
||
}
|
||
else return 'Возникла ошибка';
|
||
return answer;
|
||
}
|
||
|
||
clearZones(){
|
||
this.zones = [];
|
||
}
|
||
addZone(zone){
|
||
this.zones.push(zone);
|
||
}
|
||
|
||
data(){
|
||
return {
|
||
id: this.id,
|
||
username: this.username,
|
||
password: this.password,
|
||
token: this.token,
|
||
mode: this.mode,
|
||
zones: this.zones
|
||
}
|
||
}
|
||
|
||
reset(){
|
||
this.token = 'unauthorized';
|
||
}
|
||
|
||
checkAuth(){
|
||
return !(this.token == 'unauthorized');
|
||
}
|
||
}
|
||
|
||
module.exports = Courier
|