merchantData.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. const axios = require("axios");
  2. const bcrypt = require("bcryptjs");
  3. const Error = require("../models/error");
  4. const Merchant = require("../models/merchant");
  5. const Recipe = require("../models/recipe");
  6. const Ingredient = require("../models/ingredient");
  7. const InventoryAdjustment = require("../models/inventoryAdjustment");
  8. const token = "b48068eb-411a-918e-ea64-52007147e42c";
  9. module.exports = {
  10. //GET - Checks clover for new or deleted recipes
  11. //Returns:
  12. // merchant: Full merchant (recipe ingredients populated)
  13. // count: Number of new recipes
  14. updateRecipes: function(req, res){
  15. if(!req.session.user){
  16. req.session.error = "Must be logged in to do that";
  17. return res.redirect("/");
  18. }
  19. Merchant.findOne({_id: req.session.user})
  20. .populate("recipes")
  21. .then((merchant)=>{
  22. axios.get(`https://apisandbox.dev.clover.com/v3/merchants/${merchant.posId}/items?access_token=${token}`)
  23. .then((result)=>{
  24. let deletedRecipes = merchant.recipes.slice();
  25. for(let i = 0; i < result.data.elements.length; i++){
  26. for(let j = 0; j < deletedRecipes.length; j++){
  27. if(result.data.elements[i].id === deletedRecipes[j].posId){
  28. result.data.elements.splice(i, 1);
  29. deletedRecipes.splice(j, 1);
  30. i--;
  31. break;
  32. }
  33. }
  34. }
  35. for(let recipe of deletedRecipes){
  36. for(let i = 0; i < merchant.recipes.length; i++){
  37. if(recipe._id === merchant.recipes[i]._id){
  38. merchant.recipes.splice(i, 1);
  39. break;
  40. }
  41. }
  42. }
  43. let newRecipes = []
  44. for(let recipe of result.data.elements){
  45. let newRecipe = new Recipe({
  46. posId: recipe.id,
  47. merchant: merchant._id,
  48. name: recipe.name,
  49. ingredients: []
  50. });
  51. merchant.recipes.push(newRecipe);
  52. newRecipes.push(newRecipe);
  53. }
  54. Recipe.create(newRecipes)
  55. .catch((err)=>{
  56. let errorMessage = "There was an error and your new recipes could not be saved";
  57. let error = new Error({
  58. code: 547,
  59. displayMessage: errorMessage,
  60. error: err
  61. });
  62. error.save();
  63. return res.json(errorMessage);
  64. });
  65. merchant.save()
  66. .then((newMerchant)=>{
  67. newMerchant.populate("recipes.ingredients.ingredient").execPopulate()
  68. .then((newestMerchant)=>{
  69. merchant.password = undefined;
  70. return res.json({merchant: newestMerchant, count: result.data.elements.length});
  71. })
  72. .catch((err)=>{
  73. let errorMessage = "Unable to retrieve recipe ingredients";
  74. let error = new Error({
  75. code: 626,
  76. displayMessage: errorMessage,
  77. error: err
  78. });
  79. error.save();
  80. return res.json(errorMessage);
  81. });
  82. })
  83. .catch((err)=>{
  84. let errorMessage = "Unable to save changes from Clover";
  85. let error = new Error({
  86. code: 547,
  87. displayMessage: errorMessage,
  88. error: err
  89. });
  90. error.save();
  91. return res.json(errorMessage);
  92. });
  93. })
  94. .catch((err)=>{
  95. let errorMessage = "Unable to retrieve data from Clover";
  96. let error = new Error({
  97. code: 111,
  98. displayMessage: errorMessage,
  99. error: err
  100. });
  101. error.save();
  102. return res.json(errorMessage);
  103. });
  104. })
  105. .catch((err)=>{
  106. let errorMessage = "Unable to retrieve merchant data";
  107. let error = new Error({
  108. code: 626,
  109. displayMessage: errorMessage,
  110. error: err
  111. });
  112. error.save();
  113. return res.json(errorMessage);
  114. });
  115. },
  116. //POST - Creates a Clover merchant from all entered data
  117. //Inputs:
  118. // req.body.data: All data from frontend in form of merchant model
  119. //Redirect to "/inventory"
  120. createMerchantClover: function(req, res){
  121. let data = JSON.parse(req.body.data);
  122. data.email = data.email.toLowerCase();
  123. if(data.password.length < 15 || data.password !== data.confirmPassword){
  124. req.session.error = "Passwords must match and contain at least 15 characters";
  125. return res.redirect("/");
  126. }
  127. if(!this.isUniqueEmail){
  128. req.session.error = "Email already in use";
  129. return res.redirect("/");
  130. }
  131. axios.get(`https://apisandbox.dev.clover.com/v3/merchants/${req.session.posId}?access_token=${token}`)
  132. .then((cloverMerchant)=>{
  133. req.session.posId = undefined;
  134. let salt = bcrypt.genSaltSync(10);
  135. let hash = bcrypt.hashSync(data.password, salt);
  136. let merchant = new Merchant({
  137. name: cloverMerchant.data.name,
  138. email: data.email,
  139. password: hash,
  140. pos: "clover",
  141. posId: cloverMerchant.data.id
  142. });
  143. for(let item of data.inventory){
  144. merchant.inventory.push({
  145. ingredient: item.ingredient.id,
  146. quantity: item.quantity
  147. });
  148. }
  149. for(let recipe of data.recipes){
  150. recipe.merchant = merchant._id;
  151. }
  152. Recipe.create(data.recipes)
  153. .then((recipes)=>{
  154. for(let recipe of recipes){
  155. merchant.recipes.push(recipe._id);
  156. }
  157. merchant.save()
  158. .then((merchant)=>{
  159. req.session.user = merchant._id;
  160. return res.redirect("/inventory");
  161. })
  162. .catch((err)=>{
  163. let errorMessage = "There was an error and your account could not be created";
  164. let error = new Error({
  165. code: 547,
  166. displayMessage: errorMessage,
  167. error: err
  168. });
  169. error.save();
  170. return;
  171. });
  172. })
  173. .catch((err)=>{
  174. let errorMessage = "There was an error and your recipes could not be saved";
  175. let error = new Error({
  176. code: 547,
  177. displaymessage: errorMessage,
  178. error: err
  179. });
  180. error.save();
  181. return;
  182. });
  183. })
  184. .catch((err)=>{
  185. let errorMessage = "Unable to retrieve your data from Clover";
  186. let error = new Error({
  187. code: 111,
  188. displayMessage: errorMessage,
  189. error: err
  190. });
  191. error.save();
  192. return;
  193. });
  194. },
  195. //POST - Creates a non-pos merchant from all entered data
  196. //Inputs:
  197. // req.body.data: All data from frontend in form of merchant model
  198. //Redirects to "/inventory"
  199. createMerchantNone: function(req, res){
  200. let data = JSON.parse(req.body.data);
  201. data.email = data.email.toLowerCase();
  202. if(data.password.length < 15 || data.password !== data.confirmPassword){
  203. req.session.error = "Passwords must match and contain at least 15 characters";
  204. return res.redirect("/");
  205. }
  206. if(!this.isUniqueEmail){
  207. req.session.error = "Email already in use";
  208. return res.redirect("/");
  209. }
  210. let salt = bcrypt.genSaltSync(10);
  211. let hash = bcrypt.hashSync(data.password, salt);
  212. let merchant = new Merchant({
  213. name: data.name,
  214. email: data.email,
  215. password: hash,
  216. pos: "none"
  217. });
  218. for(let item of data.inventory){
  219. merchant.inventory.push({
  220. ingredient: item.ingredient.id,
  221. quantity: item.quantity
  222. });
  223. }
  224. for(let recipe of data.recipes){
  225. recipe.merchant = merchant._id;
  226. }
  227. Recipe.create(data.recipes)
  228. .then((recipes)=>{
  229. for(let recipe of recipes){
  230. merchant.recipes.push(recipe._id);
  231. }
  232. merchant.save()
  233. .then((merchant)=>{
  234. req.session.user = merchant._id;
  235. return res.redirect("/inventory");
  236. })
  237. .catch((err)=>{
  238. let errorMessage = "There was an error and your account could not be created";
  239. let error = new Error({
  240. code: 547,
  241. displayMessage: errorMessage,
  242. error: err
  243. });
  244. error.save();
  245. return;
  246. });
  247. })
  248. .catch((err)=>{
  249. let errorMessage = "There was an error while trying to save your recipes";
  250. let error = new Error({
  251. code: 547,
  252. displayMessage: errorMessage,
  253. error: err
  254. });
  255. error.save();
  256. return;
  257. });
  258. },
  259. //POST - Adds an ingredient to merchant's inventory
  260. //Inputs:
  261. // req.body: A merchant inventory item (ingredient id and quantity)
  262. //Returns:
  263. // ingredient: Newly added ingredient
  264. addMerchantIngredient: function(req, res){
  265. if(!req.session.user){
  266. req.session.error = "Must be logged in to do that";
  267. return res.redirect("/");
  268. }
  269. Merchant.findOne({_id: req.session.user})
  270. .then((merchant)=>{
  271. merchant.inventory.push(req.body);
  272. merchant.save()
  273. .then((newMerchant)=>{
  274. newMerchant.populate("inventory.ingredient", (err)=>{
  275. if(err){
  276. let errorMessage = "Ingredient updated, page refresh required to display";
  277. let error = new Error({
  278. code: 626,
  279. displayMessage: errorMessage,
  280. error: err
  281. });
  282. error.save();
  283. return res.json(errorMessage);
  284. }else{
  285. let newIngredient = newMerchant.inventory.find(i => i.ingredient._id.toString() === req.body.ingredient);
  286. return res.json(newIngredient);
  287. }
  288. });
  289. })
  290. .catch((err)=>{
  291. let errorMessage = "Unable to save new ingredient";
  292. let error = new Error({
  293. code: 547,
  294. displayMessage: errorMessage,
  295. error: err
  296. });
  297. error.save();
  298. console.log(err);
  299. return res.json(errorMessage);
  300. });
  301. })
  302. .catch((err)=>{
  303. let errorMessage = "Unable to retrieve merchant data";
  304. let error = new Error({
  305. code: 547,
  306. displayMessage: errorMessage,
  307. error: err
  308. });
  309. error.save();
  310. console.log("error2");
  311. return res.json(errorMessage);
  312. });
  313. },
  314. //POST - Removes an ingredient from the merchant's inventory
  315. //Inputs:
  316. // ingredientId: id of ingredient to remove
  317. //Returns: Nothing
  318. removeMerchantIngredient: function(req, res){
  319. if(!req.session.user){
  320. req.session.error = "Must be logged in to do that";
  321. return res.redirect("/");
  322. }
  323. Merchant.findOne({_id: req.session.user})
  324. .then((merchant)=>{
  325. for(let i = 0; i < merchant.inventory.length; i++){
  326. if(req.body.ingredientId === merchant.inventory[i]._id.toString()){
  327. merchant.inventory.splice(i, 1);
  328. break;
  329. }
  330. }
  331. merchant.save()
  332. .then((merchant)=>{
  333. return res.json(req.body);
  334. })
  335. .catch((err)=>{
  336. let errorMessage = "Unable to update ingredients";
  337. let error = new Error({
  338. code: 547,
  339. displayMessage: errorMessage,
  340. error: err
  341. });
  342. error.save();
  343. return res.json(errorMessage);
  344. });
  345. })
  346. .catch((err)=>{
  347. let errorMessage = "Unable to retrieve merchant data";
  348. let error = new Error({
  349. code: 626,
  350. displayMessage: errorMessage,
  351. error: err
  352. });
  353. error.save();
  354. return res.json(errorMessage);
  355. });
  356. },
  357. //POST - Update the quantity for a merchant inventory item
  358. //Inputs:
  359. // req.body.ingredientId: Id of ingredient to update
  360. // req.body.quantityChange: Amount to change ingredient (not the new value)
  361. //Returns: Nothing
  362. updateMerchantIngredient: function(req, res){
  363. if(!req.session.user){
  364. req.session.error = "Must be logged in to do that";
  365. return res.redirect("/");
  366. }
  367. Merchant.findOne({_id: req.session.user})
  368. .then((merchant)=>{
  369. let updateIngredient = merchant.inventory.find(i => i._id.toString() === req.body.ingredientId);
  370. updateIngredient.quantity += req.body.quantityChange;
  371. merchant.save()
  372. .then((merchant)=>{
  373. res.json(req.body.quantityChange);
  374. })
  375. .catch((err)=>{
  376. let errorMessage = "There was an error and your data could not be saved";
  377. let error = new Error({
  378. code: 547,
  379. displayMessage: errorMessage,
  380. error: err
  381. });
  382. error.save();
  383. return res.json(errorMessage);
  384. })
  385. })
  386. .catch((err)=>{
  387. let errorMessage = "There was an error and we could not retrieve your data";
  388. let error = new Error({
  389. code: 626,
  390. displayMessage: errorMessage,
  391. error: err
  392. });
  393. error.save();
  394. return res.json(errorMessage);
  395. });
  396. let invAdj = new InventoryAdjustment({
  397. date: Date.now(),
  398. merchant: req.session.user,
  399. ingredient: req.body.ingredientId,
  400. quantity: req.body.quantityChange
  401. });
  402. invAdj.save()
  403. .catch((err)=>{
  404. let error = new Error({
  405. code: 547,
  406. displayMessage: "none",
  407. error: err
  408. });
  409. error.save();
  410. });
  411. },
  412. //POST - Adds an ingredient to a recipe
  413. //Inputs:
  414. // req.body.recipeId: Id of recipe to change
  415. // req.body.item: Ingredient to add with a quantity
  416. //Returns:
  417. // recipe: Updated recipe with populated ingredients
  418. addRecipeIngredient: function(req, res){
  419. if(!req.session.user){
  420. req.session.error = "Must be logged in to do that";
  421. return res.redirect("/");
  422. }
  423. Recipe.findOne({_id: req.body.recipeId})
  424. .then((recipe)=>{
  425. recipe.ingredients.push({
  426. ingredient: req.body.item.ingredient,
  427. quantity: req.body.item.quantity
  428. });
  429. recipe.save()
  430. .then((recipe)=>{
  431. recipe.populate("ingredients.ingredient", (err)=>{
  432. if(err){
  433. let errorMessage = "Error: could not retrieve ingredients. Please refresh page to see changes";
  434. let error = new Error({
  435. code: 626,
  436. displayMessage: errorMessage,
  437. error: err
  438. });
  439. error.save();
  440. return res.json(errorMessage);
  441. }
  442. return res.json(recipe);
  443. })
  444. })
  445. .catch((err)=>{
  446. let errorMessage = "There was an error and the recipe could not be updated";
  447. let error = new Error({
  448. code: 547,
  449. displayMessage: errorMessage,
  450. error: err
  451. });
  452. error.save();
  453. return res.json(errorMessage);
  454. });
  455. })
  456. .catch((err)=>{
  457. let errorMessage = "There was an error and the recipe could not be updated"
  458. let error = new Error({
  459. code: 626,
  460. displayMessage: errorMessage,
  461. error: err
  462. });
  463. error.save();
  464. return res.json(errorMessage);
  465. });
  466. },
  467. //POST - Change quantity of a recipe's ingredient
  468. //Inputs:
  469. // req.body.recipeId: Id of recipe containing the ingredient
  470. // req.body.ingredient: The ingredient to update (_id and quantity)
  471. //Returns: Nothing
  472. updateRecipeIngredient: function(req, res){
  473. if(!req.session.user){
  474. req.session.error = "Must be logged in to do that";
  475. return res.redirect("/");
  476. }
  477. Recipe.findOne({_id: req.body.recipeId})
  478. .then((recipe)=>{
  479. for(let ingredient of recipe.ingredients){
  480. if(ingredient._id.toString() === req.body.ingredient._id){
  481. ingredient.quantity = req.body.ingredient.quantity;
  482. recipe.save()
  483. .then((recipe)=>{
  484. return res.json({});
  485. })
  486. .catch((err)=>{
  487. let errorMessage = "There was an error and the recipe could not be updated";
  488. let error = new Error({
  489. code: 547,
  490. displayMessage: errorMessage,
  491. error: err
  492. });
  493. error.save();
  494. return res.json(errorMessage);
  495. });
  496. }
  497. }
  498. })
  499. .catch((err)=>{
  500. let errorMessage = "There was an error and the recipe could not be updated";
  501. let error = new Error({
  502. code: 626,
  503. displayMessage: errorMessage,
  504. error: err
  505. });
  506. error.save();
  507. return res.json(errorMessage);
  508. });
  509. },
  510. //POST - Remove an ingredient from a recipe
  511. //Inputs:
  512. // req.body.ingredientId: Id of ingredient to be removed
  513. // req.body.recipeId: Id of recipe to remove ingredient from
  514. //Returns: Nothing
  515. removeRecipeIngredient: function(req, res){
  516. if(!req.session.user){
  517. req.session.error = "Must be logged in to do that";
  518. return res.redirect("/");
  519. }
  520. Recipe.findOne({_id: req.body.recipeId})
  521. .then((recipe)=>{
  522. for(let i = 0; i < recipe.ingredients.length; i++){
  523. if(recipe.ingredients[i]._id.toString() === req.body.ingredientId){
  524. recipe.ingredients.splice(i, 1);
  525. }
  526. }
  527. recipe.save()
  528. .then((recipe)=>{
  529. return res.json({});
  530. })
  531. .catch((err)=>{
  532. let errorMessage = "There was an error and the ingredient could not be remove from the recipe";
  533. let error = new Error({
  534. code: 547,
  535. displayMessage: errorMessage,
  536. error: err
  537. });
  538. error.save();
  539. return res.json(errorMessage);
  540. });
  541. })
  542. .catch((err)=>{
  543. let errorMessage = "There was an error and the ingredient could not be removed from the recipe";
  544. let error = new Error({
  545. code: 626,
  546. displayMessage: errorMessage,
  547. error: err
  548. });
  549. error.save();
  550. return res.json(errorMessage);
  551. });
  552. },
  553. //Helper
  554. isUniqueEmail: function(email){
  555. Merchant.findOne({email: email})
  556. .then((merchant)=>{
  557. if(merchant){
  558. return false;
  559. }else{
  560. return true;
  561. }
  562. });
  563. return false;
  564. }
  565. }