merchantData.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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 InventoryAdjustment = require("../models/inventoryAdjustment");
  7. const RecipeChange = require("../models/recipeChange");
  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", "inventory.ingredient"]).execPopulate()
  68. .then((newestMerchant)=>{
  69. merchant.password = undefined;
  70. return res.json(newestMerchant);
  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: async function(req, res){
  121. let data = JSON.parse(req.body.data);
  122. data.email = data.email.toLowerCase();
  123. let merchant = await Merchant.findOne({email: data.email});
  124. if(merchant){
  125. req.session.error = "Email already in use";
  126. return res.redirect("/merchant/new/clover");
  127. }
  128. if(data.password.length < 15 || data.password !== data.confirmPassword){
  129. req.session.error = "Passwords must match and contain at least 15 characters";
  130. return res.redirect("/");
  131. }
  132. axios.get(`https://apisandbox.dev.clover.com/v3/merchants/${req.session.merchantId}?access_token=${req.session.accessToken}`)
  133. .then((cloverMerchant)=>{
  134. req.session.posId = undefined;
  135. let salt = bcrypt.genSaltSync(10);
  136. let hash = bcrypt.hashSync(data.password, salt);
  137. let merchant = new Merchant({
  138. name: cloverMerchant.data.name,
  139. email: data.email,
  140. password: hash,
  141. pos: "clover",
  142. posId: cloverMerchant.data.id,
  143. posAccessToken: req.session.accessToken
  144. });
  145. req.session.merchantId = undefined;
  146. req.session.accessToken = undefined;
  147. for(let item of data.inventory){
  148. merchant.inventory.push({
  149. ingredient: item.ingredient.id,
  150. quantity: item.quantity
  151. });
  152. }
  153. for(let recipe of data.recipes){
  154. recipe.merchant = merchant._id;
  155. }
  156. Recipe.create(data.recipes)
  157. .then((recipes)=>{
  158. for(let recipe of recipes){
  159. merchant.recipes.push(recipe._id);
  160. }
  161. merchant.save()
  162. .then((merchant)=>{
  163. req.session.user = merchant._id;
  164. return res.redirect("/inventory");
  165. })
  166. .catch((err)=>{
  167. let errorMessage = "There was an error and your account could not be created";
  168. let error = new Error({
  169. code: 547,
  170. displayMessage: errorMessage,
  171. error: err
  172. });
  173. error.save();
  174. return;
  175. });
  176. })
  177. .catch((err)=>{
  178. let errorMessage = "There was an error and your recipes could not be saved";
  179. let error = new Error({
  180. code: 547,
  181. displaymessage: errorMessage,
  182. error: err
  183. });
  184. error.save();
  185. return;
  186. });
  187. })
  188. .catch((err)=>{
  189. let errorMessage = "Unable to retrieve your data from Clover";
  190. let error = new Error({
  191. code: 111,
  192. displayMessage: errorMessage,
  193. error: err
  194. });
  195. error.save()
  196. return;
  197. });
  198. },
  199. //POST - Creates a non-pos merchant from all entered data
  200. //Inputs:
  201. // req.body.data: All data from frontend in form of merchant model
  202. //Redirects to "/inventory"
  203. createMerchantNone: async function(req, res){
  204. let data = JSON.parse(req.body.data);
  205. data.email = data.email.toLowerCase();
  206. let merchantExists = await Merchant.findOne({email: data.email});
  207. if(merchantExists){
  208. req.session.error = "Email already in use";
  209. return res.redirect("/merchant/new/none");
  210. }
  211. if(data.password.length < 15 || data.password !== data.confirmPassword){
  212. req.session.error = "Passwords must match and contain at least 15 characters";
  213. return res.redirect("/");
  214. }
  215. let salt = bcrypt.genSaltSync(10);
  216. let hash = bcrypt.hashSync(data.password, salt);
  217. let merchant = new Merchant({
  218. name: data.name,
  219. email: data.email,
  220. password: hash,
  221. pos: "none"
  222. });
  223. for(let item of data.inventory){
  224. merchant.inventory.push({
  225. ingredient: item.ingredient.id,
  226. quantity: item.quantity
  227. });
  228. }
  229. for(let recipe of data.recipes){
  230. recipe.merchant = merchant._id;
  231. }
  232. Recipe.create(data.recipes)
  233. .then((recipes)=>{
  234. for(let recipe of recipes){
  235. merchant.recipes.push(recipe._id);
  236. }
  237. merchant.save()
  238. .then((merchant)=>{
  239. req.session.user = merchant._id;
  240. return res.redirect("/inventory");
  241. })
  242. .catch((err)=>{
  243. let errorMessage = "There was an error and your account could not be created";
  244. let error = new Error({
  245. code: 547,
  246. displayMessage: errorMessage,
  247. error: err
  248. });
  249. error.save();
  250. return;
  251. });
  252. })
  253. .catch((err)=>{
  254. let errorMessage = "There was an error while trying to save your recipes";
  255. let error = new Error({
  256. code: 547,
  257. displayMessage: errorMessage,
  258. error: err
  259. });
  260. error.save();
  261. return;
  262. });
  263. },
  264. //POST - Adds an ingredient to merchant's inventory
  265. //Inputs:
  266. // req.body.ingredient: ingredient id
  267. // req.body.quantity: quantity for the ingredient
  268. //Returns:
  269. // ingredient: Newly added ingredient
  270. addMerchantIngredient: function(req, res){
  271. if(!req.session.user){
  272. req.session.error = "Must be logged in to do that";
  273. return res.redirect("/");
  274. }
  275. Merchant.findOne({_id: req.session.user})
  276. .then((merchant)=>{
  277. for(let item of merchant.inventory){
  278. if(item.ingredient.toString() === req.body.ingredient){
  279. return res.json("Ingredient is already in your inventory");
  280. }
  281. }
  282. merchant.inventory.push(req.body);
  283. merchant.save()
  284. .then((newMerchant)=>{
  285. newMerchant.populate("inventory.ingredient", (err)=>{
  286. if(err){
  287. let errorMessage = "Ingredient updated, page refresh required to display";
  288. let error = new Error({
  289. code: 626,
  290. displayMessage: errorMessage,
  291. error: err
  292. });
  293. error.save();
  294. return res.json(errorMessage);
  295. }else{
  296. let newIngredient = newMerchant.inventory.find(i => i.ingredient._id.toString() === req.body.ingredient);
  297. return res.json(newIngredient);
  298. }
  299. });
  300. })
  301. .catch((err)=>{
  302. let errorMessage = "Unable to save new ingredient";
  303. let error = new Error({
  304. code: 547,
  305. displayMessage: errorMessage,
  306. error: err
  307. });
  308. error.save();
  309. console.log(err);
  310. return res.json(errorMessage);
  311. });
  312. })
  313. .catch((err)=>{
  314. let errorMessage = "Unable to retrieve merchant data";
  315. let error = new Error({
  316. code: 547,
  317. displayMessage: errorMessage,
  318. error: err
  319. });
  320. error.save();
  321. console.log("error2");
  322. return res.json(errorMessage);
  323. });
  324. },
  325. //POST - Removes an ingredient from the merchant's inventory
  326. //Inputs:
  327. // ingredientId: id of ingredient to remove
  328. //Returns: Nothing
  329. removeMerchantIngredient: function(req, res){
  330. if(!req.session.user){
  331. req.session.error = "Must be logged in to do that";
  332. return res.redirect("/");
  333. }
  334. Merchant.findOne({_id: req.session.user})
  335. .then((merchant)=>{
  336. for(let i = 0; i < merchant.inventory.length; i++){
  337. if(req.body.ingredientId === merchant.inventory[i].ingredient._id.toString()){
  338. merchant.inventory.splice(i, 1);
  339. break;
  340. }
  341. }
  342. merchant.save()
  343. .then((merchant)=>{
  344. return res.json(req.body);
  345. })
  346. .catch((err)=>{
  347. let errorMessage = "Unable to update ingredients";
  348. let error = new Error({
  349. code: 547,
  350. displayMessage: errorMessage,
  351. error: err
  352. });
  353. error.save();
  354. return res.json(errorMessage);
  355. });
  356. })
  357. .catch((err)=>{
  358. let errorMessage = "Unable to retrieve merchant data";
  359. let error = new Error({
  360. code: 626,
  361. displayMessage: errorMessage,
  362. error: err
  363. });
  364. error.save();
  365. return res.json(errorMessage);
  366. });
  367. },
  368. //POST - Update the quantity for a merchant inventory item
  369. //Inputs:
  370. // req.body.ingredientId: Id of ingredient to update
  371. // req.body.quantityChange: Amount to change ingredient (not the new value)
  372. //Returns: Nothing
  373. updateMerchantIngredient: function(req, res){
  374. if(!req.session.user){
  375. req.session.error = "Must be logged in to do that";
  376. return res.redirect("/");
  377. }
  378. Merchant.findOne({_id: req.session.user})
  379. .then((merchant)=>{
  380. let updateIngredient = merchant.inventory.find(i => i.ingredient.toString() === req.body.ingredientId);
  381. updateIngredient.quantity = (updateIngredient.quantity + req.body.quantityChange).toFixed(2);
  382. merchant.save()
  383. .then((newMerchant)=>{
  384. res.json(req.body.quantityChange);
  385. })
  386. .catch((err)=>{
  387. let errorMessage = "Error: your data could not be saved";
  388. let error = new Error({
  389. code: 547,
  390. displayMessage: errorMessage,
  391. error: err
  392. });
  393. error.save();
  394. return res.json(errorMessage);
  395. })
  396. })
  397. .catch((err)=>{
  398. let errorMessage = "Error: your data could not be retrieved";
  399. let error = new Error({
  400. code: 626,
  401. displayMessage: errorMessage,
  402. error: err
  403. });
  404. error.save();
  405. return res.json(errorMessage);
  406. });
  407. let invAdj = new InventoryAdjustment({
  408. date: Date.now(),
  409. merchant: req.session.user,
  410. ingredient: req.body.ingredientId,
  411. quantity: req.body.quantityChange
  412. });
  413. invAdj.save()
  414. .catch((err)=>{
  415. let error = new Error({
  416. code: 547,
  417. displayMessage: "none",
  418. error: err
  419. });
  420. error.save();
  421. });
  422. },
  423. //POST - Adds an ingredient to a recipe
  424. //Inputs:
  425. // req.body.recipeId: Id of recipe to change
  426. // req.body.item: Ingredient to add with a quantity
  427. //Returns:
  428. // recipe: Updated recipe with populated ingredients
  429. addRecipeIngredient: function(req, res){
  430. if(!req.session.user){
  431. req.session.error = "Must be logged in to do that";
  432. return res.redirect("/");
  433. }
  434. Recipe.findOne({_id: req.body.recipeId})
  435. .then((recipe)=>{
  436. recipe.ingredients.push({
  437. ingredient: req.body.item.ingredient,
  438. quantity: req.body.item.quantity
  439. });
  440. recipe.save()
  441. .then((recipe)=>{
  442. recipe.populate("ingredients.ingredient", (err)=>{
  443. if(err){
  444. let errorMessage = "Error: could not retrieve ingredients. Please refresh page to see changes";
  445. let error = new Error({
  446. code: 626,
  447. displayMessage: errorMessage,
  448. error: err
  449. });
  450. error.save();
  451. return res.json(errorMessage);
  452. }
  453. res.json(recipe);
  454. let rc = new RecipeChange({
  455. recipe: recipe,
  456. ingredient: req.body.item.ingredient,
  457. change: req.body.item.quantity
  458. });
  459. rc.save()
  460. .catch((err)=>{
  461. let error = new Error({
  462. code: 120,
  463. displayMessage: "none",
  464. error: err
  465. });
  466. error.save();
  467. });
  468. return;
  469. })
  470. })
  471. .catch((err)=>{
  472. let errorMessage = "There was an error and the recipe could not be updated";
  473. let error = new Error({
  474. code: 547,
  475. displayMessage: errorMessage,
  476. error: err
  477. });
  478. error.save();
  479. return res.json(errorMessage);
  480. });
  481. })
  482. .catch((err)=>{
  483. let errorMessage = "There was an error and the recipe could not be updated"
  484. let error = new Error({
  485. code: 626,
  486. displayMessage: errorMessage,
  487. error: err
  488. });
  489. error.save();
  490. return res.json(errorMessage);
  491. });
  492. },
  493. //POST - Change quantity of a recipe's ingredient
  494. //Inputs:
  495. // req.body.recipeId: Id of recipe containing the ingredient
  496. // req.body.ingredient: The ingredient to update (_id and quantity)
  497. //Returns: Nothing
  498. updateRecipeIngredient: function(req, res){
  499. if(!req.session.user){
  500. req.session.error = "Must be logged in to do that";
  501. return res.redirect("/");
  502. }
  503. Recipe.findOne({_id: req.body.recipeId})
  504. .then((recipe)=>{
  505. for(let ingredient of recipe.ingredients){
  506. if(ingredient._id.toString() === req.body.ingredient._id){
  507. let change = Number(req.body.ingredient.quantity) - ingredient.quantity;
  508. ingredient.quantity = req.body.ingredient.quantity;
  509. recipe.save()
  510. .then((recipe)=>{
  511. res.json({});
  512. let rc = new RecipeChange({
  513. recipe: recipe,
  514. ingredient: ingredient.ingredient,
  515. change: change
  516. });
  517. rc.save()
  518. .catch((err)=>{
  519. let error = new Error({
  520. code: 120,
  521. errorMessage: "none",
  522. error: err
  523. });
  524. error.save();
  525. });
  526. return;
  527. })
  528. .catch((err)=>{
  529. let errorMessage = "There was an error and the recipe could not be updated";
  530. let error = new Error({
  531. code: 547,
  532. displayMessage: errorMessage,
  533. error: err
  534. });
  535. error.save();
  536. return res.json(errorMessage);
  537. });
  538. }
  539. }
  540. })
  541. .catch((err)=>{
  542. let errorMessage = "There was an error and the recipe could not be updated";
  543. let error = new Error({
  544. code: 626,
  545. displayMessage: errorMessage,
  546. error: err
  547. });
  548. error.save();
  549. return res.json(errorMessage);
  550. });
  551. },
  552. //POST - Remove an ingredient from a recipe
  553. //Inputs:
  554. // req.body.ingredientId: Id of ingredient to be removed
  555. // req.body.recipeId: Id of recipe to remove ingredient from
  556. // req.body.quantity: quantity of recipe ingredient for storing
  557. //Returns: Nothing
  558. removeRecipeIngredient: function(req, res){
  559. if(!req.session.user){
  560. req.session.error = "Must be logged in to do that";
  561. return res.redirect("/");
  562. }
  563. Recipe.findOne({_id: req.body.recipeId})
  564. .then((recipe)=>{
  565. for(let i = 0; i < recipe.ingredients.length; i++){
  566. if(recipe.ingredients[i].ingredient._id.toString() === req.body.ingredientId){
  567. recipe.ingredients.splice(i, 1);
  568. break;
  569. }
  570. }
  571. recipe.save()
  572. .then((recipe)=>{
  573. res.json({});
  574. let rc = new RecipeChange({
  575. recipe: req.body.recipeId,
  576. ingredient: req.body.ingredientId,
  577. change: -req.body.quantity
  578. });
  579. rc.save()
  580. .catch((err)=>{
  581. let error = new Error({
  582. code: 120,
  583. displayMessage: "none",
  584. error: err
  585. });
  586. error.save();
  587. });
  588. return;
  589. })
  590. .catch((err)=>{
  591. let errorMessage = "There was an error and the ingredient could not be remove from the recipe";
  592. let error = new Error({
  593. code: 547,
  594. displayMessage: errorMessage,
  595. error: err
  596. });
  597. error.save();
  598. return res.json(errorMessage);
  599. });
  600. })
  601. .catch((err)=>{
  602. let errorMessage = "There was an error and the ingredient could not be removed from the recipe";
  603. let error = new Error({
  604. code: 626,
  605. displayMessage: errorMessage,
  606. error: err
  607. });
  608. error.save();
  609. return res.json(errorMessage);
  610. });
  611. }
  612. }