Merchant.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. const Ingredient = require("./Ingredient.js");
  2. const Recipe = require("./Recipe.js");
  3. const Transaction = require("./Transaction.js");
  4. class Merchant{
  5. constructor(oldMerchant, transactions){
  6. this.name = oldMerchant.name;
  7. this.pos = oldMerchant.pos;
  8. this.ingredients = [];
  9. this.recipes = [];
  10. this.transactions = [];
  11. this.orders = [];
  12. this.units = {
  13. mass: ["g", "kg", "oz", "lb"],
  14. volume: ["ml", "l", "tsp", "tbsp", "ozfl", "cup", "pt", "qt", "gal"],
  15. length: ["mm", "cm", "m", "in", "foot"],
  16. other: ["each"]
  17. }
  18. for(let i = 0; i < oldMerchant.inventory.length; i++){
  19. this.ingredients.push({
  20. ingredient: new Ingredient(
  21. oldMerchant.inventory[i].ingredient._id,
  22. oldMerchant.inventory[i].ingredient.name,
  23. oldMerchant.inventory[i].ingredient.category,
  24. oldMerchant.inventory[i].ingredient.unitType,
  25. oldMerchant.inventory[i].defaultUnit,
  26. this
  27. ),
  28. quantity: oldMerchant.inventory[i].quantity
  29. });
  30. }
  31. for(let i = 0; i < oldMerchant.recipes.length; i++){
  32. this.recipes.push(new Recipe(
  33. oldMerchant.recipes[i]._id,
  34. oldMerchant.recipes[i].name,
  35. oldMerchant.recipes[i].price,
  36. oldMerchant.recipes[i].ingredients,
  37. this
  38. ));
  39. }
  40. for(let i = 0; i < transactions.length; i++){
  41. this.transactions.push(new Transaction(
  42. transactions[i]._id,
  43. transactions[i].date,
  44. transactions[i].recipes,
  45. this
  46. ));
  47. }
  48. }
  49. /*
  50. Updates all specified item in the merchant's inventory and updates the page
  51. If ingredient doesn't exist, add it
  52. ingredients = {
  53. ingredient: Ingredient object,
  54. quantity: new quantity,
  55. defaultUnit: the default unit to be displayed
  56. }
  57. remove = set true if removing
  58. isOrder = set true if this is coming from an order
  59. */
  60. editIngredients(ingredients, remove = false, isOrder = false){
  61. for(let i = 0; i < ingredients.length; i++){
  62. let isNew = true;
  63. for(let j = 0; j < merchant.ingredients.length; j++){
  64. if(merchant.ingredients[j].ingredient === ingredients[i].ingredient){
  65. if(remove){
  66. merchant.ingredients.splice(j, 1);
  67. }else if(!remove && isOrder){
  68. merchant.ingredients[j].quantity += ingredients[i].quantity;
  69. }else{
  70. merchant.ingredients[j].quantity = ingredients[i].quantity;
  71. }
  72. isNew = false;
  73. break;
  74. }
  75. }
  76. if(isNew){
  77. merchant.ingredients.push({
  78. ingredient: ingredients[i].ingredient,
  79. quantity: parseFloat(ingredients[i].quantity),
  80. defaultUnit: ingredients[i].defaultUnit
  81. });
  82. }
  83. }
  84. ingredientsStrandObj.populateByProperty("category");
  85. addIngredientsComp.isPopulated = false;
  86. closeSidebar();
  87. }
  88. /*
  89. Updates a recipe in the merchants list of recipes
  90. Can create, edit or remove
  91. recipe = [Recipe object]
  92. remove = will remove recipe when true
  93. */
  94. editRecipes(recipes, remove = false){
  95. let isNew = true;
  96. for(let i = 0; i < recipes.length; i++){
  97. for(let j = 0; j < this.recipes.length; j++){
  98. if(recipes[i] === this.recipes[j]){
  99. if(remove){
  100. this.recipes.splice(j, 1);
  101. }else{
  102. this.recipes[j] = recipes[i];
  103. }
  104. isNew = false;
  105. break;
  106. }
  107. }
  108. if(isNew){
  109. merchant.recipes.push(recipes[i]);
  110. }
  111. }
  112. transactionsStrandObj.isPopulated = false;
  113. recipeBookStrandObj.populateRecipes();
  114. closeSidebar();
  115. }
  116. /*
  117. Updates a list of orders in the merchants list of orders
  118. Create/edit/remove
  119. orders = [Order object]
  120. remove = will remove order when true
  121. */
  122. editOrders(orders, remove = false){
  123. for(let i = 0; i < orders.length; i++){
  124. let isNew = true;
  125. for(let j = 0; j < this.orders.length; j++){
  126. if(orders[i] === this.orders[j]){
  127. if(remove){
  128. this.orders.splice(j, 1);
  129. }else{
  130. this.orders[j] = orders[i];
  131. }
  132. isNew = false;
  133. break;
  134. }
  135. }
  136. if(isNew){
  137. this.orders.push(orders[i]);
  138. }
  139. }
  140. ordersStrandObj.populate();
  141. closeSidebar();
  142. }
  143. editTransactions(transaction, remove = false){
  144. let isNew = true;
  145. for(let i = 0; i < this.transactions.length; i++){
  146. if(this.transactions[i] === transaction){
  147. if(remove){
  148. this.transactions.splice(i, 1);
  149. }
  150. isNew = false;
  151. break;
  152. }
  153. }
  154. if(isNew){
  155. this.transactions.push(transaction);
  156. this.transactions.sort((a, b) => a.date > b.date ? 1 : -1);
  157. }
  158. transactionsStrandObj.isPopulated = false;
  159. transactionsStrandObj.display();
  160. closeSidebar();
  161. }
  162. /*
  163. Gets the indices of two dates from transactions
  164. Inputs
  165. from: starting date
  166. to: ending date (default to now)
  167. Output
  168. Array containing starting index and ending index
  169. Note: Will return false if it cannot find both necessary dates
  170. */
  171. transactionIndices(from, to = new Date()){
  172. let indices = [];
  173. for(let i = 0; i < this.transactions.length; i++){
  174. if(this.transactions[i].date > from){
  175. indices.push(i);
  176. break;
  177. }
  178. }
  179. for(let i = this.transactions.length - 1; i >=0; i--){
  180. if(this.transactions[i].date < to){
  181. indices.push(i);
  182. break;
  183. }
  184. }
  185. if(indices.length < 2){
  186. return false;
  187. }
  188. return indices;
  189. }
  190. revenue(indices){
  191. let total = 0;
  192. for(let i = indices[0]; i <= indices[1]; i++){
  193. for(let j = 0; j < this.transactions[i].recipes.length; j++){
  194. for(let k = 0; k < this.recipes.length; k++){
  195. if(this.transactions[i].recipes[j].recipe === this.recipes[k]){
  196. total += this.transactions[i].recipes[j].quantity * this.recipes[k].price;
  197. }
  198. }
  199. }
  200. }
  201. return total / 100;
  202. }
  203. /*
  204. Gets the quantity of each ingredient sold between two dates (dateRange)
  205. Inputs
  206. dateRange: list containing a start date and an end date
  207. Return:
  208. [{
  209. ingredient: Ingredient object,
  210. quantity: quantity of ingredient sold
  211. }]
  212. */
  213. ingredientsSold(dateRange){
  214. if(!dateRange){
  215. return false;
  216. }
  217. let recipes = this.recipesSold(dateRange);
  218. let ingredientList = [];
  219. for(let i = 0; i < recipes.length; i++){
  220. for(let j = 0; j < recipes[i].recipe.ingredients.length; j++){
  221. let exists = false;
  222. for(let k = 0; k < ingredientList.length; k++){
  223. if(ingredientList[k].ingredient === recipes[i].recipe.ingredients[j].ingredient){
  224. exists = true;
  225. ingredientList[k].quantity += recipes[i].quantity * recipes[i].recipe.ingredients[j].quantity;
  226. break;
  227. }
  228. }
  229. if(!exists){
  230. ingredientList.push({
  231. ingredient: recipes[i].recipe.ingredients[j].ingredient,
  232. quantity: recipes[i].quantity * recipes[i].recipe.ingredients[j].quantity
  233. });
  234. }
  235. }
  236. }
  237. return ingredientList;
  238. }
  239. singleIngredientSold(dateRange, ingredient){
  240. let total = 0;
  241. for(let i = dateRange[0]; i < dateRange[1]; i++){
  242. for(let j = 0; j < this.transactions[i].recipes.length; j++){
  243. for(let k = 0; k < this.transactions[i].recipes[j].recipe.ingredients.length; k++){
  244. if(this.transactions[i].recipes[j].recipe.ingredients[k].ingredient === ingredient.ingredient){
  245. total += this.transactions[i].recipes[j].recipe.ingredients[k].quantity;
  246. break;
  247. }
  248. }
  249. }
  250. }
  251. return total;
  252. }
  253. /*
  254. Gets the number of recipes sold between two dates (dateRange)
  255. Inputs:
  256. dateRange: array containing a start date and an end date
  257. Return:
  258. [{
  259. recipe: a recipe object
  260. quantity: quantity of the recipe sold
  261. }]
  262. */
  263. recipesSold(dateRange){
  264. let recipeList = [];
  265. for(let i = dateRange[0]; i <= dateRange[1]; i++){
  266. for(let j = 0; j < this.transactions[i].recipes.length; j++){
  267. let exists = false;
  268. for(let k = 0; k < recipeList.length; k++){
  269. if(recipeList[k].recipe === this.transactions[i].recipes[j].recipe){
  270. exists = true;
  271. recipeList[k].quantity += this.transactions[i].recipes[j].quantity;
  272. break;
  273. }
  274. }
  275. if(!exists){
  276. recipeList.push({
  277. recipe: this.transactions[i].recipes[j].recipe,
  278. quantity: this.transactions[i].recipes[j].quantity
  279. });
  280. }
  281. }
  282. }
  283. return recipeList;
  284. }
  285. /*
  286. Create revenue data for graphing
  287. Input:
  288. dateRange: [start index, end index] (this.transactionIndices)
  289. Return:
  290. [total revenue for each day]
  291. */
  292. graphDailyRevenue(dateRange){
  293. if(!dateRange){
  294. return false;
  295. }
  296. let dataList = new Array(30).fill(0);
  297. let currentDate = this.transactions[dateRange[0]].date;
  298. let arrayIndex = 0;
  299. for(let i = dateRange[0]; i <= dateRange[1]; i++){
  300. if(this.transactions[i].date.getDate() !== currentDate.getDate()){
  301. currentDate = this.transactions[i].date;
  302. arrayIndex++;
  303. }
  304. for(let j = 0; j < this.transactions[i].recipes.length; j++){
  305. dataList[arrayIndex] += (this.transactions[i].recipes[j].recipe.price / 100) * this.transactions[i].recipes[j].quantity;
  306. }
  307. }
  308. return dataList;
  309. }
  310. /*
  311. Groups all of the merchant's ingredients by their category
  312. Return: [{
  313. name: category name,
  314. ingredients: [Ingredient Object]
  315. }]
  316. */
  317. categorizeIngredients(){
  318. let ingredientsByCategory = [];
  319. for(let i = 0; i < this.ingredients.length; i++){
  320. let categoryExists = false;
  321. for(let j = 0; j < ingredientsByCategory.length; j++){
  322. if(this.ingredients[i].ingredient.category === ingredientsByCategory[j].name){
  323. ingredientsByCategory[j].ingredients.push(this.ingredients[i]);
  324. categoryExists = true;
  325. break;
  326. }
  327. }
  328. if(!categoryExists){
  329. ingredientsByCategory.push({
  330. name: this.ingredients[i].ingredient.category,
  331. ingredients: [this.ingredients[i]]
  332. });
  333. }
  334. }
  335. return ingredientsByCategory;
  336. }
  337. unitizeIngredients(){
  338. let ingredientsByUnit = [];
  339. for(let i = 0; i < this.ingredients.length; i++){
  340. let unitExists = false;
  341. for(let j = 0; j < ingredientsByUnit.length; j++){
  342. if(this.ingredients[i].ingredient.unit === ingredientsByUnit[j].name){
  343. ingredientsByUnit[j].ingredients.push(this.ingredients[i]);
  344. unitExists = true;
  345. break;
  346. }
  347. }
  348. if(!unitExists){
  349. ingredientsByUnit.push({
  350. name: this.ingredients[i].ingredient.unit,
  351. ingredients: [this.ingredients[i]]
  352. });
  353. }
  354. }
  355. return ingredientsByUnit;
  356. }
  357. getRecipesForIngredient(ingredient){
  358. let recipes = [];
  359. for(let i = 0; i < this.recipes.length; i++){
  360. for(let j = 0; j < this.recipes[i].ingredients.length; j++){
  361. if(this.recipes[i].ingredients[j].ingredient === ingredient){
  362. recipes.push(this.recipes[i]);
  363. }
  364. }
  365. }
  366. return recipes;
  367. }
  368. }
  369. module.exports = Merchant;