merchantData.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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. accountStatus: {
  223. status: "valid",
  224. //working here
  225. }
  226. });
  227. for(let item of data.inventory){
  228. merchant.inventory.push({
  229. ingredient: item.ingredient.id,
  230. quantity: item.quantity
  231. });
  232. }
  233. for(let recipe of data.recipes){
  234. recipe.merchant = merchant._id;
  235. }
  236. Recipe.create(data.recipes)
  237. .then((recipes)=>{
  238. for(let recipe of recipes){
  239. merchant.recipes.push(recipe._id);
  240. }
  241. merchant.save()
  242. .then((merchant)=>{
  243. req.session.user = merchant._id;
  244. return res.redirect("/inventory");
  245. })
  246. .catch((err)=>{
  247. let errorMessage = "There was an error and your account could not be created";
  248. let error = new Error({
  249. code: 547,
  250. displayMessage: errorMessage,
  251. error: err
  252. });
  253. error.save();
  254. return;
  255. });
  256. })
  257. .catch((err)=>{
  258. let errorMessage = "There was an error while trying to save your recipes";
  259. let error = new Error({
  260. code: 547,
  261. displayMessage: errorMessage,
  262. error: err
  263. });
  264. error.save();
  265. return;
  266. });
  267. },
  268. //POST - Adds an ingredient to merchant's inventory
  269. //Inputs:
  270. // req.body.ingredient: ingredient id
  271. // req.body.quantity: quantity for the ingredient
  272. //Returns:
  273. // ingredient: Newly added ingredient
  274. addMerchantIngredient: function(req, res){
  275. if(!req.session.user){
  276. req.session.error = "Must be logged in to do that";
  277. return res.redirect("/");
  278. }
  279. Merchant.findOne({_id: req.session.user})
  280. .then((merchant)=>{
  281. for(let item of merchant.inventory){
  282. if(item.ingredient.toString() === req.body.ingredient){
  283. return res.json("Ingredient is already in your inventory");
  284. }
  285. }
  286. merchant.inventory.push(req.body);
  287. merchant.save()
  288. .then((newMerchant)=>{
  289. newMerchant.populate("inventory.ingredient", (err)=>{
  290. if(err){
  291. let errorMessage = "Ingredient updated, page refresh required to display";
  292. let error = new Error({
  293. code: 626,
  294. displayMessage: errorMessage,
  295. error: err
  296. });
  297. error.save();
  298. return res.json(errorMessage);
  299. }else{
  300. let newIngredient = newMerchant.inventory.find(i => i.ingredient._id.toString() === req.body.ingredient);
  301. return res.json(newIngredient);
  302. }
  303. });
  304. })
  305. .catch((err)=>{
  306. let errorMessage = "Unable to save new ingredient";
  307. let error = new Error({
  308. code: 547,
  309. displayMessage: errorMessage,
  310. error: err
  311. });
  312. error.save();
  313. console.log(err);
  314. return res.json(errorMessage);
  315. });
  316. })
  317. .catch((err)=>{
  318. let errorMessage = "Unable to retrieve merchant data";
  319. let error = new Error({
  320. code: 547,
  321. displayMessage: errorMessage,
  322. error: err
  323. });
  324. error.save();
  325. console.log("error2");
  326. return res.json(errorMessage);
  327. });
  328. },
  329. //POST - Removes an ingredient from the merchant's inventory
  330. //Inputs:
  331. // ingredientId: id of ingredient to remove
  332. //Returns: Nothing
  333. removeMerchantIngredient: function(req, res){
  334. if(!req.session.user){
  335. req.session.error = "Must be logged in to do that";
  336. return res.redirect("/");
  337. }
  338. Merchant.findOne({_id: req.session.user})
  339. .then((merchant)=>{
  340. for(let i = 0; i < merchant.inventory.length; i++){
  341. if(req.body.ingredientId === merchant.inventory[i].ingredient._id.toString()){
  342. merchant.inventory.splice(i, 1);
  343. break;
  344. }
  345. }
  346. merchant.save()
  347. .then((merchant)=>{
  348. return res.json(req.body);
  349. })
  350. .catch((err)=>{
  351. let errorMessage = "Unable to update ingredients";
  352. let error = new Error({
  353. code: 547,
  354. displayMessage: errorMessage,
  355. error: err
  356. });
  357. error.save();
  358. return res.json(errorMessage);
  359. });
  360. })
  361. .catch((err)=>{
  362. let errorMessage = "Unable to retrieve merchant data";
  363. let error = new Error({
  364. code: 626,
  365. displayMessage: errorMessage,
  366. error: err
  367. });
  368. error.save();
  369. return res.json(errorMessage);
  370. });
  371. },
  372. //POST - Update the quantity for a merchant inventory item
  373. //Inputs:
  374. // req.body.ingredientId: Id of ingredient to update
  375. // req.body.quantityChange: Amount to change ingredient (not the new value)
  376. //Returns: Nothing
  377. updateMerchantIngredient: function(req, res){
  378. if(!req.session.user){
  379. req.session.error = "Must be logged in to do that";
  380. return res.redirect("/");
  381. }
  382. Merchant.findOne({_id: req.session.user})
  383. .then((merchant)=>{
  384. let updateIngredient = merchant.inventory.find(i => i.ingredient.toString() === req.body.ingredientId);
  385. updateIngredient.quantity = (updateIngredient.quantity + req.body.quantityChange).toFixed(2);
  386. merchant.save()
  387. .then((newMerchant)=>{
  388. res.json({});
  389. })
  390. .catch((err)=>{
  391. let errorMessage = "Error: your data could not be saved";
  392. let error = new Error({
  393. code: 547,
  394. displayMessage: errorMessage,
  395. error: err
  396. });
  397. error.save();
  398. return res.json(errorMessage);
  399. })
  400. })
  401. .catch((err)=>{
  402. let errorMessage = "Error: your data could not be retrieved";
  403. let error = new Error({
  404. code: 626,
  405. displayMessage: errorMessage,
  406. error: err
  407. });
  408. error.save();
  409. return res.json(errorMessage);
  410. });
  411. let invAdj = new InventoryAdjustment({
  412. date: Date.now(),
  413. merchant: req.session.user,
  414. ingredient: req.body.ingredientId,
  415. quantity: req.body.quantityChange
  416. });
  417. invAdj.save()
  418. .catch((err)=>{
  419. let error = new Error({
  420. code: 547,
  421. displayMessage: "none",
  422. error: err
  423. });
  424. error.save();
  425. });
  426. },
  427. //POST - Adds an ingredient to a recipe
  428. //Inputs:
  429. // req.body.recipeId: Id of recipe to change
  430. // req.body.item: Ingredient to add with a quantity
  431. //Returns:
  432. // recipe: Updated recipe with populated ingredients
  433. addRecipeIngredient: function(req, res){
  434. if(!req.session.user){
  435. req.session.error = "Must be logged in to do that";
  436. return res.redirect("/");
  437. }
  438. Recipe.findOne({_id: req.body.recipeId})
  439. .then((recipe)=>{
  440. recipe.ingredients.push({
  441. ingredient: req.body.item.ingredient,
  442. quantity: req.body.item.quantity
  443. });
  444. recipe.save()
  445. .then((recipe)=>{
  446. recipe.populate("ingredients.ingredient", (err)=>{
  447. if(err){
  448. let errorMessage = "Error: could not retrieve ingredients. Please refresh page to see changes";
  449. let error = new Error({
  450. code: 626,
  451. displayMessage: errorMessage,
  452. error: err
  453. });
  454. error.save();
  455. return res.json(errorMessage);
  456. }
  457. res.json(recipe);
  458. let rc = new RecipeChange({
  459. recipe: recipe,
  460. ingredient: req.body.item.ingredient,
  461. change: req.body.item.quantity
  462. });
  463. rc.save()
  464. .catch((err)=>{
  465. let error = new Error({
  466. code: 120,
  467. displayMessage: "none",
  468. error: err
  469. });
  470. error.save();
  471. });
  472. return;
  473. })
  474. })
  475. .catch((err)=>{
  476. let errorMessage = "There was an error and the recipe could not be updated";
  477. let error = new Error({
  478. code: 547,
  479. displayMessage: errorMessage,
  480. error: err
  481. });
  482. error.save();
  483. return res.json(errorMessage);
  484. });
  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: 626,
  490. displayMessage: errorMessage,
  491. error: err
  492. });
  493. error.save();
  494. return res.json(errorMessage);
  495. });
  496. },
  497. //POST - Change quantity of a recipe's ingredient
  498. //Inputs:
  499. // req.body.recipeId: Id of recipe containing the ingredient
  500. // req.body.ingredient: The ingredient to update (_id and quantity)
  501. //Returns: Nothing
  502. updateRecipeIngredient: function(req, res){
  503. if(!req.session.user){
  504. req.session.error = "Must be logged in to do that";
  505. return res.redirect("/");
  506. }
  507. Recipe.findOne({_id: req.body.recipeId})
  508. .then((recipe)=>{
  509. for(let ingredient of recipe.ingredients){
  510. if(ingredient._id.toString() === req.body.ingredient._id){
  511. let change = Number(req.body.ingredient.quantity) - ingredient.quantity;
  512. ingredient.quantity = req.body.ingredient.quantity;
  513. recipe.save()
  514. .then((recipe)=>{
  515. res.json({});
  516. let rc = new RecipeChange({
  517. recipe: recipe,
  518. ingredient: ingredient.ingredient,
  519. change: change
  520. });
  521. rc.save()
  522. .catch((err)=>{
  523. let error = new Error({
  524. code: 120,
  525. errorMessage: "none",
  526. error: err
  527. });
  528. error.save();
  529. });
  530. return;
  531. })
  532. .catch((err)=>{
  533. let errorMessage = "There was an error and the recipe could not be updated";
  534. let error = new Error({
  535. code: 547,
  536. displayMessage: errorMessage,
  537. error: err
  538. });
  539. error.save();
  540. return res.json(errorMessage);
  541. });
  542. }
  543. }
  544. })
  545. .catch((err)=>{
  546. let errorMessage = "There was an error and the recipe could not be updated";
  547. let error = new Error({
  548. code: 626,
  549. displayMessage: errorMessage,
  550. error: err
  551. });
  552. error.save();
  553. return res.json(errorMessage);
  554. });
  555. },
  556. //POST - Remove an ingredient from a recipe
  557. //Inputs:
  558. // req.body.ingredientId: Id of ingredient to be removed
  559. // req.body.recipeId: Id of recipe to remove ingredient from
  560. // req.body.quantity: quantity of recipe ingredient for storing
  561. //Returns: Nothing
  562. removeRecipeIngredient: function(req, res){
  563. if(!req.session.user){
  564. req.session.error = "Must be logged in to do that";
  565. return res.redirect("/");
  566. }
  567. Recipe.findOne({_id: req.body.recipeId})
  568. .then((recipe)=>{
  569. for(let i = 0; i < recipe.ingredients.length; i++){
  570. if(recipe.ingredients[i].ingredient._id.toString() === req.body.ingredientId){
  571. recipe.ingredients.splice(i, 1);
  572. break;
  573. }
  574. }
  575. recipe.save()
  576. .then((recipe)=>{
  577. res.json({});
  578. let rc = new RecipeChange({
  579. recipe: req.body.recipeId,
  580. ingredient: req.body.ingredientId,
  581. change: -req.body.quantity
  582. });
  583. rc.save()
  584. .catch((err)=>{
  585. let error = new Error({
  586. code: 120,
  587. displayMessage: "none",
  588. error: err
  589. });
  590. error.save();
  591. });
  592. return;
  593. })
  594. .catch((err)=>{
  595. let errorMessage = "There was an error and the ingredient could not be remove from the recipe";
  596. let error = new Error({
  597. code: 547,
  598. displayMessage: errorMessage,
  599. error: err
  600. });
  601. error.save();
  602. return res.json(errorMessage);
  603. });
  604. })
  605. .catch((err)=>{
  606. let errorMessage = "There was an error and the ingredient could not be removed from the recipe";
  607. let error = new Error({
  608. code: 626,
  609. displayMessage: errorMessage,
  610. error: err
  611. });
  612. error.save();
  613. return res.json(errorMessage);
  614. });
  615. },
  616. updateMerchant: function(req, res){
  617. console.log("Something or other");
  618. }
  619. }