helper.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. const axios = require("axios");
  2. const Transaction = require("../models/transaction.js");
  3. const Merchant = require("../models/merchant.js");
  4. module.exports = {
  5. getCloverData: async function(merchant){
  6. const subscriptionCheck = axios.get(`${process.env.CLOVER_ADDRESS}/v3/apps/${process.env.SUBLINE_CLOVER_APPID}/merchants/${merchant.posId}/billing_info?access_token=${merchant.posAccessToken}`);
  7. const transactionRetrieval = axios.get(`${process.env.CLOVER_ADDRESS}/v3/merchants/${merchant.posId}/orders?filter=modifiedTime>=${merchant.lastUpdatedTime}&expand=lineItems&expand=payment&access_token=${merchant.posAccessToken}`);
  8. await Promise.all([subscriptionCheck, transactionRetrieval])
  9. .then((response)=>{
  10. if(response[0].data.status !== "ACTIVE"){
  11. req.session.error = "SUBSCRIPTION EXPIRED. PLEASE RENEW ON CLOVER";
  12. return res.redirect("/");
  13. }
  14. const updatedTime = Date.now();
  15. //Create Subline transactions from Clover Transactions
  16. let transactions = [];
  17. for(let i = 0; i < response[1].data.elements.length; i++){
  18. let order = response[1].data.elements[i];
  19. if(order.paymentState !== "PAID"){
  20. break;
  21. }
  22. let newTransaction = new Transaction({
  23. merchant: merchant._id,
  24. date: new Date(order.createdTime),
  25. device: order.device.id,
  26. posId: order.id
  27. });
  28. //Go through lineItems from Clover
  29. //Get the appropriate recipe from Subline
  30. //Add it to the transaction or increment if existing
  31. for(let j = 0; j < order.lineItems.elements.length; j++){
  32. let recipe = {}
  33. for(let k = 0; k < merchant.recipes.length; k++){
  34. if(merchant.recipes[k].posId === order.lineItems.elements[j].item.id){
  35. recipe = merchant.recipes[k];
  36. break;
  37. }
  38. }
  39. if(recipe){
  40. let isNewRecipe = true;
  41. for(let k = 0; k < newTransaction.recipes.length; k++){
  42. if(newTransaction.recipes[k].recipe === recipe._id){
  43. newTransaction.recipes[k].quantity++;
  44. isNewRecipe = false;
  45. break;
  46. }
  47. }
  48. if(isNewRecipe){
  49. newTransaction.recipes.push({
  50. recipe: recipe._id,
  51. quantity: 1
  52. });
  53. }
  54. //Subtract ingredients from merchants total for each ingredient in a recipe
  55. for(let k = 0; k < recipe.ingredients.length; k++){
  56. let inventoryIngredient = {};
  57. for(let l = 0; l < merchant.inventory.length; l++){
  58. if(merchant.inventory[l].ingredient._id.toString() === recipe.ingredients[k].ingredient._id.toString()){
  59. inventoryIngredient = merchant.inventory[l];
  60. break;
  61. }
  62. }
  63. inventoryIngredient.quantity = inventoryIngredient.quantity - ingredient.quantity;
  64. }
  65. }
  66. }
  67. transactions.push(newTransaction);
  68. }
  69. merchant.lastUpdatedTime = updatedTime;
  70. //Remove any existing orders so that they can be replaced
  71. let ids = [];
  72. for(let i = 0; i < transactions.length; i++){
  73. ids.push(transactions[i].posId);
  74. }
  75. Transaction.deleteMany({posId: {$in: ids}});
  76. return Transaction.create(transactions);
  77. })
  78. .catch((err)=>{
  79. req.session.error = "ERROR: UNABLE TO RETRIEVE DATA FROM CLOVER";
  80. return res.redirect("/");
  81. });
  82. },
  83. getSquareData: function(merchant){
  84. let now = new Date().toISOString();
  85. now = `${now.substring(0, now.length - 1)}+00:00`;
  86. let before = new Date(merchant.lastUpdatedTime).toISOString();
  87. before = `${before.substring(0, before.length - 1)}+00:00`;
  88. let ingredients = {};
  89. return axios.post(`${process.env.SQUARE_ADDRESS}/v2/orders/search`, {
  90. location_ids: [merchant.squareLocation],
  91. query: {
  92. filter: {
  93. date_time_filter: {
  94. closed_at: {
  95. start_at: before,
  96. end_at: now
  97. }
  98. },
  99. state_filter: {
  100. states: ["COMPLETED"]
  101. }
  102. },
  103. sort: {
  104. sort_field: "CLOSED_AT",
  105. sort_order: "DESC"
  106. }
  107. }
  108. }, {
  109. headers: {
  110. Authorization: `Bearer ${merchant.posAccessToken}`
  111. }
  112. })
  113. .then((response)=>{
  114. let transactions = [];
  115. if(response.data.orders){
  116. for(let i = 0; i < response.data.orders.length; i++){
  117. let transaction = new Transaction({
  118. merchant: merchant,
  119. date: response.data.orders[i].created_at,
  120. posId: response.data.orders[i].id,
  121. recipes: []
  122. });
  123. for(let j = 0; j < response.data.orders[i].line_items.length; j++){
  124. for(let k = 0; k < merchant.recipes.length; k++){
  125. if(response.data.orders[i].line_items[j].catalog_object_id === merchant.recipes[k].posId){
  126. let quantitySold = parseInt(response.data.orders[i].line_items[j].quantity);
  127. transaction.recipes.push({
  128. recipe: merchant.recipes[k],
  129. quantity: quantitySold
  130. });
  131. for(let l = 0; l < merchant.recipes[k].ingredients.length; l++){
  132. let ingredient = merchant.recipes[k].ingredients[l];
  133. let quantity = quantitySold * ingredient.quantity
  134. ingredients[ingredient.ingredient] = ingredients[ingredient.ingredient] + quantity || quantity;
  135. }
  136. break;
  137. }
  138. }
  139. }
  140. transactions.push(transaction);
  141. }
  142. }
  143. return Transaction.create(transactions);
  144. })
  145. .then((transactions)=>{
  146. const keys = Object.keys(ingredients);
  147. for(let i = 0; i < keys.length; i++){
  148. for(let j = 0; j < merchant.inventory.length; j++){
  149. if(keys[i] === merchant.inventory[j].ingredient._id.toString()){
  150. merchant.inventory[j].quantity -= ingredients[keys[i]];
  151. break;
  152. }
  153. }
  154. }
  155. merchant.lastUpdatedTime = new Date();
  156. return transactions;
  157. })
  158. .catch((err)=>{
  159. return "ERROR: UNABLE TO UPDATE TRANSACTION DATA";
  160. });
  161. },
  162. /*
  163. Updates the quanties of ingredients from a list of transactions
  164. ingredients = Object. keys = ingredient ids, values = quantity to change (g)
  165. user = id of logged in user
  166. */
  167. updateIngredientQuantities: function(ingredients, user){
  168. Merchant.findOne({_id: user})
  169. .then((merchant)=>{
  170. let keys = Object.keys(ingredients);
  171. for(let i = 0; i < keys.length; i++){
  172. for(let j = 0; j < merchant.inventory.length; j++){
  173. if(merchant.inventory[j].ingredient._id.toString() === keys[i]){
  174. merchant.inventory[j].quantity -= ingredients[keys[i]];
  175. break;
  176. }
  177. }
  178. }
  179. return merchant.save();
  180. })
  181. .catch((err)=>{
  182. return false;
  183. });
  184. },
  185. convertQuantityToBaseUnit: function(quantity, unit){
  186. switch(unit){
  187. case "g":return quantity;
  188. case "kg": return quantity * 1000;
  189. case "oz": return quantity * 28.3495;
  190. case "lb": return quantity * 453.5924;
  191. case "ml": return quantity / 1000;
  192. case "l": return quantity;
  193. case "tsp": return quantity / 202.8842;
  194. case "tbsp": return quantity / 67.6278;
  195. case "ozfl": return quantity / 33.8141;
  196. case "cup": return quantity / 4.1667;
  197. case "pt": return quantity / 2.1134;
  198. case "qt": return quantity / 1.0567;
  199. case "gal": return quantity * 3.7854;
  200. case "mm": return quantity / 1000;
  201. case "cm": return quantity / 100;
  202. case "m": return quantity;
  203. case "in": return quantity / 39.3701;
  204. case "ft": return quantity / 3.2808;
  205. default: return quantity;
  206. }
  207. },
  208. generateId: function(length){
  209. let result = "";
  210. let characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  211. for(let i = 0; i < length; i++){
  212. result += characters.charAt(Math.floor(Math.random() * characters.length));
  213. }
  214. return result;
  215. }
  216. }