const Restaurant = require("../models/restaurant.js"); const Dish = require("../models/dish.js"); const User = require("../models/users.js"); const Payments = require("../models/payments.js"); const { deleteImage } = require("./oceanServices.js"); const { appendDishToLunchSet, removeDishFromLunchSet, } = require("./dataPrepServices.js"); const { newError } = require("./services.js"); const mongoose = require("mongoose"); const axios = require("axios"); const crypto = require("crypto"); async function changeUserPass(userId, newPass) { User.findByIdAndUpdate(userId, { $set: { password: newPass } }).catch((e) => { throw newError("Zmiana hasła nie powiodła się.", 500); }); } async function removeDish(dishId) { const deletedDoc = await Dish.findByIdAndDelete(dishId).catch((e) => { throw newError("Usunięcie dania nie powiodło się.", 500); }); await deleteImage(deletedDoc.imgUrl); await Restaurant.findByIdAndUpdate(deletedDoc.restaurantId, { $pull: { dishes: dishId }, }).catch((error) => { throw newError("Usunięcie dania z restauracji nie powiodło się.", 500); }); } async function removeRestaurant(restaurantId, userId) { const deletedDoc = await Restaurant.findByIdAndDelete(restaurantId).catch( (e) => { throw newError("Usunięcie nie powiodło się.", 500); } ); await deleteImage(deletedDoc.imgUrl); for (dishId of deletedDoc.dishes) { const deletedDish = await Dish.findByIdAndDelete(dishId).catch((e) => console.log(e) ); await deleteImage(deletedDish.imgUrl); } await User.findByIdAndUpdate(userId, { $pull: { restaurants: restaurantId }, }).catch((e) => { throw newError( "Usunięcie restauracji z użytkownika nie powiodło się.", 500 ); }); } async function addDishToRestaurant(restaurantId, dishId) { await Restaurant.updateOne( { _id: restaurantId }, { $push: { dishes: dishId } } ).catch((error) => { throw newError("Nie udało się dodać dania do restauracji", 500); }); } async function addRestaurantToUser(user, restaurant) { await User.findByIdAndUpdate(user.id, { $push: { restaurants: restaurant._id }, }).catch((e) => { throw newError("Nie udało się dodać restauracji do użytkownika", 500); }); } function dueDateBasedOnSubscription(restaurant, monthsToAdd) { let date; if ( restaurant.subscriptionActive === false || !restaurant.subscriptionActive ) { date = new Date(); date.setMonth(date.getMonth() + monthsToAdd); return date; } else { date = restaurant.subscriptionDue; date.setMonth(date.getMonth() + monthsToAdd); return date; } } function startDate(restaurant) { let date; if ( restaurant.subscriptionActive === true && restaurant.subscriptionStarted ) { date = restaurant.subscriptionStarted; return date; } else { date = new Date(); return date; } } async function renewSubscription(restaurantId, monthsToAdd) { const restaurant = await Restaurant.findById(restaurantId).catch((err) => { throw newError("Nie udało się pobrać restauracji.", 404); }); const dueDate = dueDateBasedOnSubscription(restaurant, monthsToAdd); const start = startDate(restaurant); await Restaurant.findByIdAndUpdate(restaurantId, { $set: { subscriptionActive: true, subscriptionDue: dueDate, subscriptionStarted: start, }, }).catch((e) => { throw newError( "Nie udało się przedłużyć subskrypcji, spróbuj ponownie.", 500 ); }); return dueDateBasedOnSubscription(restaurant, monthsToAdd); } async function startTrial(restaurantId, userData) { const restaurant = await Restaurant.findById(restaurantId).catch((err) => { throw newError("Nie udało się pobrać restauracji.", 404); }); if (!userData.trialUsed || userData.trialUsed === false) { const dueDate = dueDateBasedOnSubscription(restaurant, monthsToAdd); const start = startDate(restaurant); await Restaurant.findByIdAndUpdate(restaurantId, { $set: { subscriptionActive: true, subscriptionDue: dueDate, subscriptionStarted: start, }, }).catch((e) => { throw newError( "Nie udało się aktywować okresu próbnego.", 500 ); }); } else { throw newError("Okres próbny został już wykorzystany.", 500); } } async function checkIfCategoryExists(restaurant, category) { const categories = restaurant.categories; if (categories.includes(category)) { throw newError("Podana kategoria już istnieje", 200); } } async function checkIfSetAlreadyInLunchMenu(restaurant, setName) { const lunchMenu = restaurant.lunchMenu; for (lunchSet of lunchMenu) { if (lunchSet.lunchSetName === setName) { throw newError("Nazwa zestawu jest zajęta", 409); } return; } } async function checkIfAlreadyInSet(restaurant, setName, dishId) { const lunchMenu = restaurant.lunchMenu; for (const lunchSet of lunchMenu) { if (lunchSet.lunchSetName === setName) { const dishes = lunchSet.lunchSetDishes; if (dishes.includes(dishId)) { throw newError("Danie jest już w podanym zestawie", 500); } } } } async function changeCategory(restaurantId, categoryName, action) { if (action === "add") { const restaurant = await Restaurant.findById(restaurantId).catch((err) => { throw newError("Nie udało się pobrać restauracji.", 404); }); await checkIfCategoryExists(restaurant, categoryName); await Restaurant.findByIdAndUpdate(restaurantId, { $push: { categories: categoryName }, }).catch((e) => { throw newError("Nie udało się dodać kategorii.", 500); }); } else if (action === "delete") { await Restaurant.findByIdAndUpdate(restaurantId, { $pull: { categories: categoryName }, }).catch((e) => { throw newError("Nie udało się usunąć kategorii.", 500); }); } else { throw newError("Nieznany błąd.", 500); } } async function setDishVisibility(dishId, visible) { await Dish.findByIdAndUpdate(dishId, { $set: { hidden: !visible } }).catch( (e) => { throw newError("Nie udało się zmienić dania.", 500); } ); } async function changeLunchMenuSet(restaurantId, action, lunchSet) { if (action === "add") { const restaurant = await Restaurant.findById(restaurantId).catch((err) => { throw newError("Nie udało się pobrać restauracji.", 404); }); await checkIfSetAlreadyInLunchMenu(restaurant, lunchSet.lunchSetName); await Restaurant.findByIdAndUpdate(restaurantId, { $push: { lunchMenu: lunchSet }, }).catch((e) => { throw newError("Nie udało się dodać zestawu do lunch menu.", 500); }); } else if (action === "delete") { await Restaurant.findByIdAndUpdate(restaurantId, { $pull: { lunchMenu: lunchSet }, }).catch((e) => { throw newError("Nie udało się usunąć zestawu.", 500); }); } else { throw newError("Nie sprecyzowano akcji", 500); } } async function changeLunchMenu(restaurantId, setName, dishId, action) { if (action === "add") { const restaurant = await Restaurant.findById(restaurantId).catch((err) => { throw newError("Nie udało się pobrać restauracji.", 404); }); await checkIfAlreadyInSet(restaurant, setName, dishId); const updatedLunchMenu = appendDishToLunchSet( restaurant.lunchMenu, setName, dishId ); await Restaurant.findByIdAndUpdate(restaurantId, { $set: { lunchMenu: updatedLunchMenu }, }).catch((e) => { throw newError("Nie udało się dodać dania do lunch menu.", 500); }); } else if (action === "delete") { const restaurant = await Restaurant.findById(restaurantId).catch((err) => { throw newError("Nie udało się pobrać restauracji.", 404); }); const updatedLunchMenu = removeDishFromLunchSet( restaurant.lunchMenu, setName, dishId ); await Restaurant.findByIdAndUpdate(restaurantId, { $set: { lunchMenu: updatedLunchMenu }, }).catch((e) => { throw newError("Nie udało się usunąć dania.", 500); }); } else { throw newError("Nie sprecyzowano akcji", 500); } } async function fetchRestaurant(id) { const data = await Restaurant.findById(id).catch((e) => { throw newError("Nie udało się pobrać restauracji.", 500); }); console.log("fetched restaurant"); return data; } async function fetchMultipleRestaurants(idArray) { let data = []; for (const id of idArray) { let response = await fetchRestaurant(id); data.push(response); } return data; } async function fetchAllDishesForRestaurant(restaurant) { const idList = restaurant.dishes; const dishes = await Dish.find({ '_id': { $in: idList } }); return dishes; } async function fetchDish(id) { let data = await Dish.findById(id).catch((e) => { throw newError(`Nie udało się pobrać ${id}`, 404); }); return data; } async function fetchUser(email) { if (!email) throw newError("Brak danych", 204); const user = await User.findOne({ email: email }); if (!user) throw newError("Użytkownik nie istnieje", 404); return user; } function amountFromType(type) { if (type === 1) { return 6150; } else if (type === 12) { return 61500; } else { return 0; } } function controlSum(sessionId, merchantId, amount, currency) { const input = { sessionId: sessionId, merchantId: merchantId, amount: amount, currency: currency, crc: "???? wie co tu ma być", }; let hash = crypto.createHash("sha384"); const checkSum = hash.update(input, "utf8"); return checkSum; } async function registerTransaction(paymentInfo, userData) { const data = { merchantId: 11111, posId: paymentInfo.type, sessionId: paymentInfo._id, amount: paymentInfo.amount, currency: "PLN", description: `Subskrypcja Menui na: ${paymentInfo.months} miesięcy.`, email: userData.userEmail, client: `${userData.firstname} ${userData.lastname}`, country: "PL", language: "pl", urlReturn: "http://test.pl", sign: controlSum(paymentInfo._id, 11111, paymentInfo.amount, "PLN"), }; const response = await axios({ method: "POST", url: "https://sandbox.przelewy24.pl/api/v1", data: data, }).catch((error) => { console.log(error); throw newError("Błąd.", 500); }); return response; } async function initializePayment(restaurantId, userData, type) { const newPayment = new Payments({ _id: new mongoose.Types.ObjectId(), restaurantId: restaurantId, amount: amountFromType(type), months: type, }); const payment = await registerTransaction(newPayment, userData); newPayment.save(); return payment; } async function setRestaurantVisibility(restaurantId, visible) { await Restaurant.findByIdAndUpdate(restaurantId, { $set: { hidden: !visible } }).catch( (e) => { throw newError("Nie udało się zmienić dania.", 500); } ); } exports.changeUserPass = changeUserPass; exports.removeDish = removeDish; exports.removeRestaurant = removeRestaurant; exports.addDishToRestaurant = addDishToRestaurant; exports.addRestaurantToUser = addRestaurantToUser; exports.renewSubscription = renewSubscription; exports.changeCategory = changeCategory; exports.setDishVisibility = setDishVisibility; exports.changeLunchMenuSet = changeLunchMenuSet; exports.changeLunchMenu = changeLunchMenu; exports.fetchRestaurant = fetchRestaurant; exports.fetchMultipleRestaurants = fetchMultipleRestaurants; exports.fetchAllDishesForRestaurant = fetchAllDishesForRestaurant; exports.fetchDish = fetchDish; exports.fetchUser = fetchUser; exports.initializePayment = initializePayment; exports.setRestaurantVisibility = setRestaurantVisibility; exports.startTrial = startTrial;