Răsfoiți Sursa

Merge branch 'development'

Lee Morgan 5 ani în urmă
părinte
comite
ccead983cd

+ 8 - 123
controllers/helper.js

@@ -3,126 +3,11 @@ const axios = require("axios");
 const Transaction = require("../models/transaction.js");
 
 module.exports = {
-    getCloverData: async function(merchant){
-        const subscriptionCheck = axios.get(`${process.env.CLOVER_ADDRESS}/v3/apps/${process.env.SUBLINE_CLOVER_APPID}/merchants/${merchant.posId}/billing_info?access_token=${merchant.posAccessToken}`);
-        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}`);
-        await Promise.all([subscriptionCheck, transactionRetrieval])
-            .then((response)=>{
-                if(response[0].data.status !== "ACTIVE"){
-                    req.session.error = "SUBSCRIPTION EXPIRED.  PLEASE RENEW ON CLOVER";
-                    return res.redirect("/");
-                }
-
-                const updatedTime = Date.now();
-                
-                //Create Subline transactions from Clover Transactions
-                let transactions = [];
-                for(let i = 0; i < response[1].data.elements.length; i++){
-                    let order = response[1].data.elements[i];
-                    if(order.paymentState !== "PAID"){
-                        break;
-                    }
-                    let newTransaction = new Transaction({
-                        merchant: merchant._id,
-                        date: new Date(order.createdTime),
-                        device: order.device.id,
-                        posId: order.id
-                    });
-
-                    //Go through lineItems from Clover
-                    //Get the appropriate recipe from Subline
-                    //Add it to the transaction or increment if existing
-                    for(let j = 0; j < order.lineItems.elements.length; j++){
-                        let recipe = {}
-                        for(let k = 0; k < merchant.recipes.length; k++){
-                            if(merchant.recipes[k].posId === order.lineItems.elements[j].item.id){
-                                recipe = merchant.recipes[k];
-                                break;
-                            }
-                        }
-
-                        if(recipe){
-                            let isNewRecipe = true;
-                            for(let k = 0; k < newTransaction.recipes.length; k++){
-                                if(newTransaction.recipes[k].recipe === recipe._id){
-                                    newTransaction.recipes[k].quantity++;
-                                    isNewRecipe = false;
-                                    break;
-                                }
-                            }
-
-                            if(isNewRecipe){
-                                newTransaction.recipes.push({
-                                    recipe: recipe._id,
-                                    quantity: 1
-                                });
-                            }
-
-                            //Subtract ingredients from merchants total for each ingredient in a recipe
-                            for(let k = 0; k < recipe.ingredients.length; k++){
-                                let inventoryIngredient = {};
-                                for(let l = 0; l < merchant.inventory.length; l++){
-                                    if(merchant.inventory[l].ingredient._id.toString() === recipe.ingredients[k].ingredient._id.toString()){
-                                        inventoryIngredient = merchant.inventory[l];
-                                        break;
-                                    }
-                                }
-                                inventoryIngredient.quantity = inventoryIngredient.quantity - ingredient.quantity;
-                            }
-                        }
-                    }
-
-                    transactions.push(newTransaction);
-                }
-
-                merchant.lastUpdatedTime = updatedTime;
-
-                //Remove any existing orders so that they can be replaced
-                let ids = [];
-                for(let i = 0; i < transactions.length; i++){
-                    ids.push(transactions[i].posId);
-                }
-                Transaction.deleteMany({posId: {$in: ids}});
-
-                return Transaction.create(transactions);
-            })
-            .catch((err)=>{
-                req.session.error = "ERROR: UNABLE TO RETRIEVE DATA";
-                return res.redirect("/");
-            });
-    },
-
-    getSquareData: function(merchant){
-        let now = new Date().toISOString();
-        now = `${now.substring(0, now.length - 1)}+00:00`;
-        let before = new Date(merchant.lastUpdatedTime).toISOString();
-        before = `${before.substring(0, before.length - 1)}+00:00`;
-
+    getSquareData: function(merchant, data){
         let ingredients = {};
 
-        return axios.post(`${process.env.SQUARE_ADDRESS}/v2/orders/search`, {
-            location_ids: [merchant.squareLocation],
-            query: {
-                filter: {
-                    date_time_filter: {
-                        closed_at: {
-                            start_at: before,
-                            end_at: now
-                        }
-                    },
-                    state_filter: {
-                        states: ["COMPLETED"]
-                    }
-                },
-                sort: {
-                    sort_field: "CLOSED_AT",
-                    sort_order: "DESC"
-                }
-            }
-        }, {
-            headers: {
-                Authorization: `Bearer ${merchant.posAccessToken}`
-            }
+        return axios.post(`${process.env.SQUARE_ADDRESS}/v2/orders/search`, data, {
+            headers: {Authorization: `Bearer ${merchant.square.accessToken}`}
         })
             .then((response)=>{
                 let transactions = [];
@@ -130,7 +15,7 @@ module.exports = {
                 if(response.data.orders){
                     for(let i = 0; i < response.data.orders.length; i++){
                         let transaction = new Transaction({
-                            merchant: merchant,
+                            merchant: merchant._id,
                             date: response.data.orders[i].created_at,
                             posId: response.data.orders[i].id,
                             recipes: []
@@ -159,9 +44,11 @@ module.exports = {
 
                         transactions.push(transaction);
                     }
+
+                    return Transaction.create(transactions);
                 }
 
-                return Transaction.create(transactions);
+                return [];
             })
             .then((transactions)=>{
                 const keys = Object.keys(ingredients);
@@ -174,8 +61,6 @@ module.exports = {
                     }
                 }
 
-                merchant.lastUpdatedTime = new Date();
-
                 return transactions;
             })
             .catch((err)=>{
@@ -240,7 +125,7 @@ module.exports = {
     },
 
     isSanitary: function(strings){
-        let disallowed = ["\\", "<", ">", "$", "{", "}", "(", ")"];
+        let disallowed = ["\\", "<", ">", "$", "{", "}", "."];
 
         for(let i = 0; i < strings.length; i++){
             for(let j = 0; j < disallowed.length; j++){

+ 2 - 2
controllers/ingredientData.js

@@ -94,8 +94,8 @@ module.exports = {
 
                         updatedIngredient = {
                             ingredient: ingredient,
-                            quantity: helper.convertQuantityToBaseUnit(req.body.quantity, req.body.unit),
-                            unit: req.body.unit
+                            quantity: req.body.quantity,
+                            defaultUnit: req.body.unit
                         }
                         
                         break;

+ 0 - 1
controllers/merchantData.js

@@ -46,7 +46,6 @@ module.exports = {
             email: req.body.email.toLowerCase(),
             password: hash,
             pos: "none",
-            lastUpdatedTime: Date.now(),
             createdAt: Date.now(),
             status: ["unverified"],
             inventory: [],

+ 35 - 2
controllers/recipeData.js

@@ -90,8 +90,8 @@ module.exports = {
 
     //DELETE - removes a single recipe from the merchant and the database
     removeRecipe: function(req, res){
-        if(res.locals.merchant.pos === "clover"){
-            return res.json("YOU MUST EDIT YOUR RECIPES INSIDE CLOVER");
+        if(res.locals.merchant.pos === "square"){
+            return res.json("YOU MUST EDIT YOUR RECIPES INSIDE SQUARE");
         }
         
         for(let i = 0; i < res.locals.merchant.recipes.length; i++){
@@ -228,6 +228,39 @@ module.exports = {
             });
     },
 
+    spreadsheetUpSquare: function(req, res){
+        let workbook = xlsx.readFile(req.file.path);
+        fs.unlink(req.file.path, ()=>{});
+        let array = xlsx.utils.sheet_to_json(workbook.Sheets.Items, {header: 1});
+
+        let recipes = [];
+        for(let i = 1; i < array.length; i++){
+            let name = array[i][1];
+            if(array[i][6] !== "") name = `${name} (${array[i][6]})`;
+
+            let recipe = new Recipe({
+                posId: array[i][0],
+                merchant: res.locals.merchant._id,
+                name: name,
+                price: parseInt(array[i][7] * 100) || 0,
+                ingredients: []
+            });
+
+            recipes.push(recipe);
+            res.locals.merchant.recipes.push(recipe);
+        }
+
+
+        Promise.all([Recipe.create(recipes), res.locals.merchant.save()])
+            .then((response)=>{
+                return res.json(response[0]);
+            })
+            .catch((err)=>{
+                if(err.name === "ValidationError") return res.json(err.errors[Object.keys(err.errors)[0]].properties.message);
+                return res.json("ERROR: UNABLE TO CREATE YOUR RECIPES");
+            });
+    },
+
     spreadsheetTemplate: function(req, res){
         res.locals.merchant
             .populate("inventory.ingredient")

+ 57 - 23
controllers/renderer.js

@@ -29,25 +29,15 @@ module.exports = {
     Renders inventoryPage
     */
     displayDashboard: function(req, res){
+        if(res.locals.merchant.status.includes("unverified")) {
+            req.session.error = "PLEASE VERIFY YOUR EMAIL ADDRESS";
+            return res.redirect(`/verify/email/${res.locals.merchant._id}`);
+        }
+
         res.locals.merchant
             .populate("inventory.ingredient")
             .populate("recipes")
             .execPopulate()
-            .then(async (merchant)=>{
-                if(res.locals.merchant.status.includes("unverified")){
-                    throw "unverified";
-                }
-
-                if(res.locals.merchant.pos === "clover"){
-                    await helper.getCloverData(res.locals.merchant);
-                }else if(res.locals.merchant.pos === "square"){
-                    await helper.getSquareData(res.locals.merchant);
-                }else{
-                    return;
-                }
-
-                return res.locals.merchant.save();
-            })
             .then((merchant)=>{
                 let date = new Date();
                 let firstDay = new Date(date.getFullYear(), date.getMonth() - 1, 1);
@@ -64,20 +54,64 @@ module.exports = {
                     }}
                 ]);      
             })
-            .then((transactions)=>{
+            .then(async (transactions)=>{
+                if(res.locals.pos !== "none"){
+                    let latest = null;
+                    if(transactions.length === 0){
+                        let latestTransaction = await Transaction.find({merchant: res.locals.merchant._id}).sort({date: -1}).limit(1);
+                        if(latestTransaction.length > 0) latest = new Date(latest[0].date);
+                    }else{
+                        latest = new Date(transactions[0].date);
+                    }
+
+                    if(latest !== null){
+                        latest.setMilliseconds(latest.getMilliseconds() + 1000);
+                        let now = new Date();
+
+                        let postData = {
+                            location_ids: [res.locals.merchant.square.location],
+                            query: {
+                                filter: {
+                                    date_time_filter: {
+                                        closed_at: {
+                                            start_at: latest,
+                                            end_at: now
+                                        }
+                                    },
+                                    state_filter: {
+                                        states: ["COMPLETED"]
+                                    }
+                                },
+                                sort: {
+                                    sort_field: "CLOSED_AT",
+                                    sort_order: "DESC"
+                                }
+                            },
+                            limit: 10000
+                        };
+
+                        do{
+                            let newOrders = await helper.getSquareData(res.locals.merchant, postData);
+                            postData.cursor = newOrders.cursor;
+                            for(let i = 0; i < newOrders.length; i++){
+                                for(let j = 0; j < newOrders[i].recipes.length; j++){
+                                    newOrders[i].recipes[j].recipe = newOrders[i].recipes[j].recipe._id;
+                                }
+                            }
+                            transactions = newOrders.concat(transactions);
+                        }while(postData.cursor !== undefined);
+                    }
+                }
+
                 res.locals.merchant._id = undefined;
-                res.locals.merchant.posAccessToken = undefined;
-                res.locals.merchant.lastUpdatedTime = undefined;
-                res.locals.merchant.accountStatus = undefined;
+                res.locals.password = undefined;
                 res.locals.merchant.status = undefined;
+                res.locals.square = undefined;
+                res.locals.session = undefined;
 
                 return res.render("dashboardPage/dashboard", {merchant: res.locals.merchant, transactions: transactions});
             })
             .catch((err)=>{
-                if(err === "unverified"){
-                    req.session.error = "PLEASE VERIFY YOUR EMAIL ADDRESS";
-                    return res.redirect(`/verify/email/${res.locals.merchant._id}`);
-                }
                 req.session.error = "ERROR: UNABLE TO RETRIEVE DATA";
                 return res.redirect("/");
             });

+ 337 - 0
controllers/squareData.js

@@ -0,0 +1,337 @@
+const Merchant = require("../models/merchant.js");
+const Recipe = require("../models/recipe.js");
+const Transaction = require("../models/transaction.js");
+
+const helper = require("./helper.js");
+
+const axios = require("axios");
+const bcrypt = require("bcryptjs");
+
+module.exports = {
+    /*POST - Redirects user to Square OAuth and saves input data
+    req.body = {
+        name: String,
+        email: String,
+        password: String,
+        confirmPassword: String
+    }
+    */
+    redirect: function(req, res){
+        if(req.body.password !== req.body.confirmPassword){
+            req.session.error = "YOUR PASSWORDS DO NOT MATCH";
+            return res.redirect("/");
+        }
+
+        let expirationDate = new Date();
+        expirationDate.setDate(expirationDate.getDate() + 90);
+
+        let salt = bcrypt.genSaltSync(10);
+        let hash = bcrypt.hashSync(req.body.password, salt);
+
+        let merchant = new Merchant({
+            name: req.body.name,
+            email: req.body.email,
+            password: hash,
+            pos: "square",
+            status: ["unverified"],
+            inventory: [],
+            recipes: [],
+            square: {},
+            createdAt: new Date(),
+            session: {
+                sessionId: helper.generateId(25),
+                expiration: expirationDate
+            }
+        });
+
+        merchant.save()
+            .then((response)=>{
+                req.session.user = merchant.session.sessionId;
+                return res.redirect(`${process.env.SQUARE_ADDRESS}/oauth2/authorize?client_id=${process.env.SUBLINE_SQUARE_APPID}&scope=INVENTORY_READ+ITEMS_READ+MERCHANT_PROFILE_READ+ORDERS_READ+PAYMENTS_READ`);
+            })
+            .catch((err)=>{
+                res.session.error = "ERROR: UNABLE TO CREATE NEW USER";
+                return res.redirect("/");
+            });
+    },
+
+    //GET: Gathers all data from square to create our merchant
+    //Redirects to the dashboard
+    createMerchant: function(req, res){
+        let code = req.url.slice(req.url.indexOf("code=") + 5, req.url.indexOf("&"));
+        let url = `${process.env.SQUARE_ADDRESS}/oauth2/token`;
+
+        let data = {
+            client_id: process.env.SUBLINE_SQUARE_APPID,
+            client_secret: process.env.SUBLINE_SQUARE_APPSECRET,
+            grant_type: "authorization_code",
+            code: code,
+        }
+
+        let merchant = {};
+
+        let localMerchant = Merchant.findOne({"session.sessionId": req.session.user});
+        let squareMerchant = axios.post(url, data);
+        Promise.all([localMerchant, squareMerchant])
+            .then((response)=>{
+                if(response[0] === null) throw "ERROR: UNABLE TO CREATE ACCOUNT";
+
+                merchant = response[0];
+
+                merchant.square = {
+                    id: response[1].data.merchant_id,
+                    expires: new Date(response[1].data.expires_at),
+                    refreshToken: response[1].data.refresh_token,
+                    accessToken: response[1].data.access_token
+                };
+
+                return axios.get(`${process.env.SQUARE_ADDRESS}/v2/merchants/${merchant.square.id}`, {
+                    headers: {Authorization: `Bearer ${merchant.square.accessToken}`}
+                });
+            })    
+            .then((response)=>{
+                merchant.square.location = response.data.merchant.main_location_id;
+
+                let items = axios.post(`${process.env.SQUARE_ADDRESS}/v2/catalog/search`, {
+                    object_types: ["ITEM"]
+                }, {
+                    headers: {
+                        Authorization: `Bearer ${merchant.square.accessToken}`
+                    }
+                });
+
+                let location = axios.get(`${process.env.SQUARE_ADDRESS}/v2/locations/${merchant.square.location}`, {
+                    headers: {
+                        Authorization: `Bearer ${merchant.square.accessToken}`
+                    }
+                });
+
+                return Promise.all([items, location]);
+            })
+            .then((response)=>{
+                if(merchant.email === response[1].data.location.business_email) merchant.status = [];
+                let recipes = [];
+                
+                for(let i = 0; i < response[0].data.objects.length; i++){
+                    if(response[0].data.objects[i].item_data.variations.length > 1){
+                        for(let j = 0; j < response[0].data.objects[i].item_data.variations.length; j++){
+                            let item = response[0].data.objects[i].item_data.variations[j];
+                            let price = 0;
+                            if(item.item_variation_data.price_money !== undefined) price = item.item_variation_data.price_money.amount;
+                            let recipe = new Recipe({
+                                posId: item.id,
+                                merchant: merchant._id,
+                                name: `${response[0].data.objects[i].item_data.name} '${item.item_variation_data.name}'`,
+                                price: price
+                            });
+    
+                            recipes.push(recipe);
+                            merchant.recipes.push(recipe);
+                        }
+                    }else{
+                        let recipe = new Recipe({
+                            posId: response[0].data.objects[i].item_data.variations[0].id,
+                            merchant: merchant._id,
+                            name: response[0].data.objects[i].item_data.name,
+                            price: response[0].data.objects[i].item_data.variations[0].item_variation_data.price_money.amount,
+                            ingredients: []
+                        });
+    
+                        recipes.push(recipe);
+                        merchant.recipes.push(recipe);
+                    }
+                }
+    
+                return Promise.all([Recipe.create(recipes), merchant.save()]);
+            })
+            .then((response)=>{
+                req.session.user = response[1].session.sessionId;
+    
+                res.redirect("/dashboard");
+
+                let body = {
+                    location_ids: [merchant.square.location],
+                    limit: 10000,
+                    query: {}
+                };
+                let options = {
+                    headers: {
+                        Authorization: `Bearer ${merchant.square.accessToken}`,
+                        "Content-Type": "application/json"
+                    }
+                };
+                return axios.post(`${process.env.SQUARE_ADDRESS}/v2/orders/search`, body, options);
+            })
+            .then(async (response)=>{
+                let transactions = [];
+
+                for(let i = 0; i < response.data.orders.length; i++){
+                    let transaction = new Transaction({
+                        merchant: merchant._id,
+                        date: new Date(response.data.orders[i].created_at),
+                        posId: response.data.orders[i].id,
+                        recipes: []
+                    });
+
+                    if(response.data.orders[i].line_items === undefined) continue;
+                    for(let j = 0; j < response.data.orders[i].line_items.length; j++){
+                        let item = response.data.orders[i].line_items[j];
+
+                        for(let k = 0; k < merchant.recipes.length; k++){
+                            if(merchant.recipes[k].posId === item.catalog_object_id){
+                                transaction.recipes.push({
+                                    recipe: merchant.recipes[k]._id,
+                                    quantity: parseInt(item.quantity)
+                                });
+                            }
+                        }
+                    }
+
+                    transactions.push(transaction);
+                }
+
+                let body = {
+                    location_ids: [merchant.square.location],
+                    limit: 10000,
+                    cursor: response.data.cursor,
+                    query: {}
+                };
+                let options = {
+                    headers: {
+                        Authorization: `Bearer ${merchant.square.accessToken}`,
+                        "Content-Type": "application/json"
+                    }
+                };
+
+                while(body.cursor !== undefined){
+                    let response = await axios.post(`${process.env.SQUARE_ADDRESS}/v2/orders/search`, body, options);
+                    body.cursor = response.data.cursor;
+                    
+                    for(let i = 0; i < response.data.orders.length; i++){
+                        let transaction = new Transaction({
+                            merchant: merchant._id,
+                            date: new Date(response.data.orders[i].created_at),
+                            posId: response.data.orders[i].id,
+                            recipes: []
+                        });
+    
+                        if(responose.data.orders[i].line_items === undefined) continue;
+                        for(let j = 0; j < response.data.orders[i].line_items.length; j++){
+                            let item = response.data.orders[i].line_items[j];
+    
+                            for(let k = 0; k < merchant.recipes.length; k++){
+                                if(merchant.recipes[k].posId === item.catalog_object_id){
+                                    transaction.recipes.push({
+                                        recipe: merchant.recipes[k]._id,
+                                        quantity: parseInt(item.quantity)
+                                    });
+                                }
+                            }
+                        }
+    
+                        transactions.push(transaction);
+                    }
+                }
+
+                return Transaction.create(transactions);
+            })
+            .catch((err)=>{
+                if(typeof(err) === "string"){
+                    req.session.error = err;
+                }else if(err.name === "ValidationError"){
+                    req.session.error = err.errors[Object.keys(err.errors)[0]].properties.message;
+                }else{
+                    req.session.error = "ERROR: UNABLE TO CREATE NEW USER";
+                }
+                return res.redirect("/");
+            });
+    },
+
+    updateRecipes: function(req, res){
+        let merchant = {};
+        let merchantRecipes = [];
+        let newRecipes = [];
+    
+        res.locals.merchant
+            .populate("recipes")
+            .execPopulate()
+            .then((fetchedMerchant)=>{
+                merchant = fetchedMerchant;
+                return axios.post(`${process.env.SQUARE_ADDRESS}/v2/catalog/search`, {
+                    object_types: ["ITEM"]
+                }, {
+                    headers: {
+                        Authorization: `Bearer ${merchant.square.accessToken}`
+                    }
+                });
+            })
+            .then((response)=>{
+                merchantRecipes = merchant.recipes.slice();
+    
+                
+                for(let i = 0; i < response.data.objects.length; i++){
+                    let itemData = response.data.objects[i].item_data;
+                    for(let j = 0; j < itemData.variations.length; j++){
+                        let isFound = false;
+    
+                        for(let k = 0; k < merchantRecipes.length; k++){
+                            if(itemData.variations[j].id === merchantRecipes[k].posId){
+                                merchantRecipes.splice(k, 1);
+                                k--;
+                                isFound = true;
+                                break;
+                            }
+                        }
+    
+                        if(!isFound){
+                            let newRecipe = new Recipe({
+                                posId: itemData.variations[j].id,
+                                merchant: merchant._id,
+                                name: "",
+                                price: itemData.variations[j].item_variation_data.price_money.amount,
+                                ingredients: []
+                            });
+    
+                            if(itemData.variations.length > 1){
+                                newRecipe.name = `${itemData.name} '${itemData.variations[j].item_variation_data.name}'`;
+                            }else{
+                                newRecipe.name = itemData.name;
+                            }
+    
+                            newRecipes.push(newRecipe);
+                            merchant.recipes.push(newRecipe);
+                        }
+                    }
+                }
+    
+                let ids = [];
+                for(let i = 0; i < merchantRecipes.length; i++){
+                    ids.push(merchantRecipes[i]._id);
+                    for(let j = 0; j < merchant.recipes.length; j++){
+                        if(merchantRecipes[i]._id.toString() === merchant.recipes[j]._id.toString()){
+                            merchant.recipes.splice(j, 1);
+                            j--;
+                            break;
+                        }
+                    }
+                }
+    
+                if(newRecipes.length > 0) Recipe.create(newRecipes);
+                if(merchantRecipes.length > 0) Recipe.deleteMany({_id: {$in: ids}});    
+
+                return merchant.save();
+            })
+            .then((merchant)=>{
+                return res.json({new: newRecipes, removed: merchantRecipes});
+            })
+            .catch((err)=>{
+                if(typeof(err) === "string"){
+                    return res.json(err);
+                }
+                if(err.name === "ValidationError"){
+                    return res.json(err.errors[Object.keys(err.errors)[0]].properties.message);
+                }
+                return res.json("ERROR: UNABLE TO RETRIEVE RECIPE DATA FROM SQUARE");
+            });
+    }
+}

+ 36 - 5
middleware.js

@@ -2,6 +2,8 @@ const Merchant = require("./models/merchant.js")
 
 const helper = require("./controllers/helper.js");
 
+const axios = require("axios");
+
 module.exports = {
     verifySession: function(req, res, next){
         if(req.session.user === undefined) {
@@ -10,11 +12,12 @@ module.exports = {
         }
     
         Merchant.findOne({"session.sessionId": req.session.user})
-            .then((merchant)=>{
+            .then(async (merchant)=>{
                 if(merchant === null){
-                    throw "no merchant";
+                    throw "login";
                 }
     
+                //Check if session is out of date
                 if(merchant.session.date < new Date()){
                     let newExpiration = new Date();
                     newExpiration.setDate(newExpiration.getDate() + 90);
@@ -22,10 +25,38 @@ module.exports = {
                     merchant.session.sessionId = helper.generateId(25);
                     merchant.session.date = newExpiration;
                     merchant.save();
-                    req.session.error = "PLEASE LOG IN";
-                    return res.redirect("/login");
+                    throw "login";
                 }
-    
+
+                //Check if email has not been verified
+                if(merchant.status.includes("unverified")){
+                    req.session.error = "PLEASE VERIFY YOUR EMAIL ADDRESS";
+                    return res.redirect(`/verify/email/${merchant._id}`);
+                }
+
+                //Check for suspended account
+                if(merchant.status.includes("suspended")){
+                    req.session.error = "ACCOUNT SUSPENDED. PLEASE CONTACT SUPPORT IF THIS IS IN ERROR";
+                    return res.redirect("/");
+                }
+
+                //Check for out of date access token
+                let cutoff = new Date();
+                cutoff.setDate(cutoff.getDate() + 1);
+                if(merchant.square.expires < cutoff){
+                    let data = await axios.post(`${process.env.SQUARE_ADDRESS}/oauth2/token`, {
+                        client_id: process.env.SUBLINE_SQUARE_APPID,
+                        client_secret: process.env.SUBLINE_SQUARE_APPSECRET,
+                        grant_type: "refresh_token",
+                        refresh_token: merchant.square.refreshToken
+                    });
+
+                    merchant.square.accessToken = data.data.access_token;
+                    merchant.square.expires = new Date(data.data.expires_at);
+
+                    await merchant.save();
+                }
+
                 res.locals.merchant = merchant;
                 return next();
             })

+ 8 - 11
models/merchant.js

@@ -24,26 +24,23 @@ const MerchantSchema = new mongoose.Schema({
         },
         index: true
     },
-    password: {
-        type: String,
-        required: [true, "MUST PROVIDE A PASSWORD"],
-    },
+    password: String,
     pos: {
         type: String,
         required: true
     },
-    posId: String,
-    posAccessToken: String,
-    lastUpdatedTime: {
-        type: String,
-        default: Date.now()
+    square: {
+        id: String,
+        accessToken: String,
+        expires: Date,
+        refreshToken: String,
+        location: String
     },
     createdAt: {
         type: Date,
-        default: Date.now
+        default: new Date()
     },
     status: [],
-    squareLocation: String,
     inventory: [{
         ingredient: {
             type: mongoose.Schema.Types.ObjectId,

+ 8 - 0
routes.js

@@ -8,6 +8,7 @@ const orderData = require("./controllers/orderData.js");
 const informationPages = require("./controllers/informationPages.js");
 const emailVerification = require("./controllers/emailVerification.js");
 const passwordReset = require("./controllers/passwordReset.js");
+const squareData = require("./controllers/squareData.js");
 
 const session = require("./middleware.js").verifySession;
 const banner = require("./middleware.js").formatBanner;
@@ -41,6 +42,7 @@ module.exports = function(app){
     app.put("/recipe/update", session, recipeData.updateRecipe);
     app.delete("/recipe/remove/:id", session, recipeData.removeRecipe);
     app.post("/recipes/create/spreadsheet", session, upload.single("recipes"), recipeData.createFromSpreadsheet);
+    app.post("/recipes/create/spreadsheet/square", session, upload.single("recipes"), recipeData.spreadsheetUpSquare);
     app.get("/recipes/download/spreadsheet", session, recipeData.spreadsheetTemplate);
 
     //Orders
@@ -77,4 +79,10 @@ module.exports = function(app){
     app.post("/reset/email", passwordReset.generateCode);
     app.get("/reset/:id/:code", banner, passwordReset.enterPassword);
     app.post("/reset", passwordReset.resetPassword);
+
+    //Square
+    app.post("/squarelogin", squareData.redirect);
+    app.get("/squareauth", squareData.createMerchant);
+    // app.get("/merchant/create/square", squareData.createMerchant);
+    app.get("/recipes/update/square", session, squareData.updateRecipes);
 }

+ 150 - 161
views/dashboardPage/js/classes/Merchant.js

@@ -3,11 +3,11 @@ const Recipe = require("./Recipe.js");
 const Transaction = require("./Transaction.js");
 const Order = require("./Order.js");
 
-const home = require("../strands/home.js");
-const ingredients = require("../strands/ingredients.js");
-const recipeBook = require("../strands/recipeBook");
-const analytics = require("../strands/analytics.js");
-const orders = require("../strands/orders");
+const homeStrand = require("../strands/home.js");
+const ingredientsStrand = require("../strands/ingredients.js");
+const recipeBookStrand = require("../strands/recipeBook");
+const analyticsStrand = require("../strands/analytics.js");
+const ordersStrand = require("../strands/orders");
 
 class MerchantIngredient{
     constructor(ingredient, quantity){
@@ -167,33 +167,41 @@ class Merchant{
     }
 
     /*
-    ingredient: {
-        _id: String,
-        name: String,
-        category: String,
-        unitType: String,
-        specialUnit: String || undefined,
-        unitSize: Number || undefined
-    }
-    quantity: Number
-    defaultUnit: String
+    ingredient: [{
+        ingredient: {
+            _id: String,
+            name: String,
+            category: String,
+            unitType: String,
+            specialUnit: String || undefined,
+            unitSize: Number || undefined
+        }
+        quantity: Number
+        defaultUnit: String
+    }]
     */
-    addIngredient(ingredient, quantity, defaultUnit){
-        const createdIngredient = new Ingredient(
-            ingredient._id,
-            ingredient.name,
-            ingredient.category,
-            ingredient.unitType,
-            defaultUnit,
-            this,
-            ingredient.unitSize
-        );
+    addIngredients(ingredients){
+        for(let i = 0; i < ingredients.length; i++){
+            let ingredient = ingredients[i].ingredient;
+            let quantity = ingredients[i].quantity;
+            let defaultUnit = ingredients[i].defaultUnit;
+
+            const createdIngredient = new Ingredient(
+                ingredient._id,
+                ingredient.name,
+                ingredient.category,
+                ingredient.unitType,
+                defaultUnit,
+                this,
+                ingredient.unitSize
+            );
 
-        const merchantIngredient = new MerchantIngredient(createdIngredient, quantity);
-        this._ingredients.push(merchantIngredient);
+            const merchantIngredient = new MerchantIngredient(createdIngredient, quantity);
+            this._ingredients.push(merchantIngredient);
+        }
 
-        home.isPopulated = false;
-        ingredients.isPopulated = false;
+        ingredientsStrand.populateByProperty();
+        analyticsStrand.populateButtons();
     }
 
     removeIngredient(ingredient){
@@ -204,8 +212,8 @@ class Merchant{
 
         this._ingredients.splice(index, 1);
 
-        home.isPopulated = false;
-        ingredients.isPopulated = false;
+        homeStrand.drawInventoryCheckCard();
+        ingredientsStrand.populateByProperty();
     }
 
     getIngredient(id){
@@ -220,12 +228,37 @@ class Merchant{
         return this._recipes;
     }
 
-    addRecipe(id, name, price, ingredients){
-        let recipe = new Recipe(id, name, price, ingredients, this);
+    getRecipe(id){
+        for(let i = 0; i < this._recipes.length; i++){
+            if(this._recipes[i].id === id){
+                return this._recipes[i];
+            }
+        }
+    }
 
-        this._recipes.push(recipe);
+    /*
+    recipes: [{
+        _id: String
+        name: String
+        price: Number
+        ingredients: [{
+            ingredient: String (id)
+            quantity: Number
+        }]
+    }]
+    */
+    addRecipes(recipes){
+        for(let i = 0; i < recipes.length; i++){
+            this._recipes.push(new Recipe(
+                recipes[i]._id,
+                recipes[i].name,
+                recipes[i].price,
+                recipes[i].ingredients,
+                this
+            ));
+        }
 
-        recipeBook.isPopulated = false;
+        recipeBookStrand.populateRecipes();
     }
 
     removeRecipe(recipe){
@@ -236,44 +269,7 @@ class Merchant{
 
         this._recipes.splice(index, 1);
 
-        recipeBook.isPopulated = false;
-    }
-
-    /*
-    recipe = {
-        name: required,
-        price: required,
-        ingredients: [{
-            ingredient: id of ingredient,
-            quantity: quantity of ingredient
-        }]
-    }
-    */
-    updateRecipe(recipe){
-        for(let i = 0; i < this._recipes.length; i++){
-            if(this._recipes[i].id === recipe._id){
-                this._recipes[i].name = recipe.name;
-                this._recipes[i].price = recipe.price;
-                
-                this._recipes[i].removeIngredients();
-                for(let j = 0; j < recipe.ingredients.length; j++){
-                    for(let k = 0; k < this._ingredients.length; k++){
-                        if(this._ingredients[k].ingredient.id === recipe.ingredients[j].ingredient){
-                            this._recipes[i].addIngredient(
-                                this._ingredients[k].ingredient,
-                                recipe.ingredients[j].quantity
-                            );
-
-                            break;
-                        }
-                    }
-                }
-
-                break;
-            }
-        }
-
-        recipeBook.isPopulated = false;
+        recipeBookStrand.populateRecipes();
     }
 
     get transactions(){
@@ -294,83 +290,65 @@ class Merchant{
         return this._transactions.slice(start, end + 1);
     }
 
-    addTransaction(transaction){
-        transaction = new Transaction(
-            transaction._id,
-            transaction.date,
-            transaction.recipes,
-            this
-        );
+    /*
+    transactions: [{
+        _id: String,
+        date: String (date)
+        recipes: [{
+            recipe: String (id)
+            quantity: Number
+        }]
+    }]
+    */
+    addTransactions(transactions, isNew = false){
+        for(let i = 0; i < transactions.length; i++){
+            let transaction = new Transaction(
+                transactions[i]._id,
+                transactions[i].date,
+                transactions[i].recipes,
+                this
+            );
+
+            this._transactions.push(transaction);
 
-        this._transactions.push(transaction);
-        this._transactions.sort((a, b)=>{
-            if(a.date > b.date){
-                return -1;
-            }
-            return 1;
-        });
-
-        let ingredients = {};
-        for(let i = 0; i < transaction.recipes.length; i++){
-            const recipe = transaction.recipes[i];
-            for(let j = 0; j < recipe.recipe.ingredients.length; j++){
-                const ingredient = recipe.recipe.ingredients[j];
-                if(ingredients[ingredient.ingredient.id]){
-                    ingredients[ingredient.ingredient.id] += recipe.quantity * ingredient.quantity;
-                }else{
-                    ingredients[ingredient.ingredient.id] = recipe.quantity * ingredient.quantity;
-                }
-            }
-        }
+            if(isNew === true){
+                for(let j = 0; j < transaction.recipes.length; j++){
+                    let recipe = transaction.recipes[j].recipe;
+                    for(let k = 0; k < recipe.ingredients.length; k++){
+                        let ingredient = recipe.ingredients[k].ingredient;
+                        let quantity = transaction.recipes[j].quantity * recipe.ingredients[k].quantity;
 
-        const keys = Object.keys(ingredients);
-        for(let i = 0; i < keys.length; i++){
-            for(let j = 0; j < this._ingredients.length; j++){
-                if(keys[i] === this._ingredients[j].ingredient.id){
-                    this._ingredients[j].updateQuantity(-ingredients[keys[i]]);
+                        this.getIngredient(ingredient.id).updateQuantity(-quantity);
+                    }
                 }
             }
         }
 
-        home.isPopulated = false;
-        ingredients.isPopulated = false;
-        analytics.newData = true;
+        this.transactions.sort((a, b) => (a.date > b.date) ? 1 : -1);
+
+        homeStrand.isPopulated = false;
+        ingredientsStrand.populateByProperty();
+        analyticsStrand.displayIngredient();
+        analyticsStrand.displayRecipe();
     }
 
     removeTransaction(transaction){
-        const index = this._transactions.indexOf(transaction);
-        if(index === undefined){
-            return false;
-        }
+        for(let j = 0; j < transaction.recipes.length; j++){
+            let recipe = transaction.recipes[j].recipe;
+            for(let k = 0; k < recipe.ingredients.length; k++){
+                let ingredient = recipe.ingredients[k].ingredient;
+                let quantity = transaction.recipes[j].quantity * recipe.ingredients[k].quantity;
 
-        this._transactions.splice(index, 1);
-
-        let ingredients = {};
-        for(let i = 0; i < transaction.recipes.length; i++){
-            const recipe = transaction.recipes[i];
-            for(let j = 0; j < recipe.recipe.ingredients.length; j++){
-                const ingredient = recipe.recipe.ingredients[j];
-                if(ingredients[ingredient.ingredient.id]){
-                    ingredients[ingredient.ingredient.id] += ingredient.quantity * recipe.quantity;
-                }else{
-                    ingredients[ingredient.ingredient.id] = ingredient.quantity * recipe.quantity;
-                }
+                this.getIngredient(ingredient.id).updateQuantity(quantity);
             }
         }
 
-        const keys = Object.keys(ingredients);
-        for(let i = 0; i < keys.length; i++){
-            for(let j = 0; j < this._ingredients.length; j++){
-                if(keys[i] === this._ingredients[j].ingredient.id){
-                    this._ingredients[j].updateQuantity(ingredients[keys[i]]);
-                    break;
-                }
-            }
-        }
+        this._transactions.splice(this._transactions.indexOf(transaction), 1);
 
-        home.isPopulated = false;
-        ingredients.isPopulated = false;
-        analytics.newData = true;
+        homeStrand.isPopulated = false;
+        ingredientsStrand.populateByProperty();
+        analyticsStrand.displayIngredient();
+        analyticsStrand.displayRecipe();
     }
 
     get orders(){
@@ -381,32 +359,43 @@ class Merchant{
         this._orders = [];
     }
 
-    addOrder(data, isNew = false){
-        let order = new Order(
-            data._id,
-            data.name,
-            data.date,
-            data.taxes,
-            data.fees,
-            data.ingredients,
-            this
-        );
-
-        this._orders.push(order);
-
-        if(isNew){
-            for(let i = 0; i < order.ingredients.length; i++){
-                for(let j = 0; j < this._ingredients.length; j++){
-                    if(order.ingredients[i].ingredient === this._ingredients[j].ingredient){
-                        this._ingredients[j].updateQuantity(order.ingredients[i].quantity);
-                        break;
-                    }
+    /*
+    orders: [{
+        _id: String,
+        name: String,
+        date: String (date)
+        taxes: Number
+        fees: Number
+        ingredients: [{
+            ingredient: String (id),
+            pricePerUnit: Number
+            quantity: Number
+        }]
+    }]
+    */
+    addOrders(orders, isNew = false){
+        for(let i = 0; i < orders.length; i++){
+            let order = new Order(
+                orders[i]._id,
+                orders[i].name,
+                orders[i].date,
+                orders[i].taxes,
+                orders[i].fees,
+                orders[i].ingredients,
+                this
+            );
+
+            this._orders.push(order);
+
+            if(isNew === true){
+                for(let j = 0; j < order.ingredients.length; j++){
+                    this.getIngredient(order.ingredients[j].ingredient.id).updateQuantity(order.ingredients[j].quantity);
                 }
             }
         }
 
-        ingredients.isPopulated = false;
-        orders.isPopulated = false;
+        ingredientsStrand.populateByProperty();
+        ordersStrand.displayOrders();
     }
 
     removeOrder(order){
@@ -426,8 +415,8 @@ class Merchant{
             }
         }
 
-        ingredients.isPopulated = false;
-        orders.isPopulated = false;
+        ingredientsStrand.isPopulated = false;
+        ordersStrand.isPopulated = false;
     }
 
     get units(){
@@ -448,7 +437,7 @@ class Merchant{
             }
         }
 
-        return total / 100;
+        return total;
     }
 
     /*

+ 7 - 18
views/dashboardPage/js/classes/Order.js

@@ -1,8 +1,6 @@
-const ingredients = require("../strands/ingredients.js");
-
 class OrderIngredient{
     constructor(ingredient, quantity, pricePerUnit){
-        this._ingredient = ingredient;
+        this._ingredient = merchant.getIngredient(ingredient).ingredient;
         this._quantity = quantity;
         this._pricePerUnit = pricePerUnit;
     }
@@ -98,7 +96,7 @@ date = Date Object for when the order was created
 taxes = User entered taxes associated with the order
 fees = User entered fees associated with the order
 ingredients = [{
-    ingredient: Ingredient Object,
+    ingredient: Ingredient ID,
     quantity: quantity of ingredient sold,
     pricePerUnit: price of purchase (per base unit)
 }]
@@ -115,21 +113,12 @@ class Order{
         this._parent = parent;
 
         for(let i = 0; i < ingredients.length; i++){
-            for(let j = 0; j < merchant.ingredients.length; j++){
-                if(merchant.ingredients[j].ingredient.id === ingredients[i].ingredient){
-                    let thing = new OrderIngredient(
-                        merchant.ingredients[j].ingredient,
-                        ingredients[i].quantity,
-                        ingredients[i].pricePerUnit
-                    );
-                    this._ingredients.push(thing);
-                    break;
-                }
-            }
-            
+            this._ingredients.push(new OrderIngredient(
+                ingredients[i].ingredient,
+                ingredients[i].quantity,
+                ingredients[i].pricePerUnit
+            ));
         }
-
-        ingredients.isPopulated = false;
     }
 
     get id(){

+ 8 - 21
views/dashboardPage/js/classes/Transaction.js

@@ -1,6 +1,6 @@
 class TransactionRecipe{
-    constructor(recipe, quantity){
-        this._recipe = recipe;
+    constructor(recipe, quantity, merchant){
+        this._recipe = merchant.getRecipe(recipe);
         this._quantity = quantity;
     }
 
@@ -15,25 +15,16 @@ class TransactionRecipe{
 
 class Transaction{
     constructor(id, date, recipes, parent){
-        date = new Date(date);
         this._id = id;
-        this._parent = parent;
-        this._date = date;
+        this._date = new Date(date);
         this._recipes = [];
 
         for(let i = 0; i < recipes.length; i++){
-            for(let j = 0; j < parent.recipes.length; j++){
-                if(recipes[i].recipe === parent.recipes[j].id){
-                    const transactionRecipe = new TransactionRecipe(
-                        parent.recipes[j],
-                        recipes[i].quantity
-                    )
-        
-                    this._recipes.push(transactionRecipe);
-
-                    break;
-                }
-            }
+            this._recipes.push(new TransactionRecipe(
+                recipes[i].recipe,
+                recipes[i].quantity,
+                parent
+            ));
         }
     }
 
@@ -41,10 +32,6 @@ class Transaction{
         return this._id;
     }
 
-    get parent(){
-        return this._parent;
-    }
-
     get date(){
         return this._date;
     }

+ 1 - 0
views/dashboardPage/js/dashboard.js

@@ -202,6 +202,7 @@ controller = {
                 content.style.display = "flex";
                 document.getElementById("modalSpreadsheetTitle").innerText = "recipes";
                 document.getElementById("spreadsheetDownload").href = "/recipes/download/spreadsheet";
+                document.getElementById("spreadsheetRecipeIsSquare").parentElement.style.display = "flex";
                 content.onsubmit = newRecipe.submitSpreadsheet;
                 break;
             case "orderSpreadsheet":

+ 2 - 2
views/dashboardPage/js/sidebars/editIngredient.js

@@ -77,7 +77,7 @@ let editIngredient = {
             category: document.getElementById("editIngCategory").value
         }
 
-        data.quantity = quantity;
+        data.quantity = ingredient.convertToBase(quantity);
 
         //Get the measurement unit
         let units = document.getElementById("unitButtons");
@@ -104,7 +104,7 @@ let editIngredient = {
                 controller.createBanner(response, "error");
             }else{
                 merchant.removeIngredient(merchant.getIngredient(response.ingredient._id));
-                merchant.addIngredient(response.ingredient, response.quantity, response.unit);
+                merchant.addIngredients([response]);
 
                 controller.openStrand("ingredients");
                 controller.createBanner("INGREDIENT UPDATED", "success");

+ 2 - 1
views/dashboardPage/js/sidebars/editRecipe.js

@@ -113,7 +113,8 @@ let editRecipe = {
                 if(typeof(response) === "string"){
                     controller.createBanner(response, "error");
                 }else{
-                    merchant.updateRecipe(response);
+                    merchant.removeRecipe(recipe)
+                    merchant.addRecipes([response]);
                     controller.openStrand("recipeBook");
                     controller.createBanner("RECIPE UPDATED", "success");
                 }

+ 2 - 4
views/dashboardPage/js/sidebars/newIngredient.js

@@ -61,7 +61,7 @@ let newIngredient = {
                 if(typeof(response) === "string"){
                     controller.createBanner(response, "error");
                 }else{
-                    merchant.addIngredient(response.ingredient, response.quantity, response.defaultUnit);
+                    merchant.addIngredients([response]);
                     controller.openStrand("ingredients");
 
                     controller.createBanner("INGREDIENT CREATED", "success");
@@ -95,9 +95,7 @@ let newIngredient = {
                 if(typeof(response) === "string"){
                     controller.createBanner(response, "error");
                 }else{
-                    for(let i = 0; i < response.length; i++){
-                        merchant.addIngredient(response[i].ingredient, response[i].quantity, response[i].defaultUnit);
-                    }
+                    merchant.addIngredients(response);
 
                     controller.createBanner("INGREDIENTS SUCCESSFULLY ADDED", "success");
                     controller.openStrand("ingredients");

+ 4 - 4
views/dashboardPage/js/sidebars/newOrder.js

@@ -62,7 +62,7 @@ let newOrder = {
             taxes: taxes,
             fees: fees,
             ingredients: []
-        }
+        };
 
         for(let i = 0; i < ingredients.length; i++){
             let quantity = ingredients[i].children[1].children[0].value;
@@ -90,7 +90,7 @@ let newOrder = {
                 if(typeof(response) === "string"){
                     controller.createBanner(response, "error");
                 }else{
-                    merchant.addOrder(response, true);
+                    merchant.addOrders([response], true);
                     
                     controller.openStrand("orders", merchant.orders);
                     controller.createBanner("NEW ORDER CREATED", "success");
@@ -110,7 +110,7 @@ let newOrder = {
             case "kg": return price / 1000; 
             case "oz": return price / 28.3495; 
             case "lb": return price / 453.5924; 
-            case "ml": return price * 1000; 
+            case "ml": return price * 1000;
             case "l": return price;
             case "tsp": return price * 202.8842; 
             case "tbsp": return price * 67.6278; 
@@ -149,7 +149,7 @@ let newOrder = {
                 if(typeof(response) === "string"){
                     controller.createBanner(response, "error");
                 }else{
-                    merchant.addOrder(response, true);
+                    merchant.addOrders([response], true);
 
                     controller.createBanner("ORDER CREATED AND INGREDIENTS UPDATED SUCCESSFULLY", "success");
                     controller.openStrand("orders");

+ 7 - 30
views/dashboardPage/js/sidebars/newRecipe.js

@@ -97,26 +97,7 @@ let newRecipe = {
                 if(typeof(response) === "string"){
                     controller.createBanner(response, "error");
                 }else{
-                    let ingredients = [];
-                    for(let i = 0; i < response.ingredients.length; i++){
-                        for(let j = 0; j < merchant.ingredients.length; j++){
-                            if(merchant.ingredients[j].ingredient.id === response.ingredients[i].ingredient){
-                                ingredients.push({
-                                    ingredient: merchant.ingredients[j].ingredient.id,
-                                    quantity: response.ingredients[i].quantity
-                                });
-
-                                break;
-                            }
-                        }
-                    }
-
-                    merchant.addRecipe(
-                        response._id,
-                        response.name,
-                        response.price,
-                        ingredients
-                    );
+                    merchant.addRecipes([response]);
 
                     controller.createBanner("RECIPE CREATED", "success");
                     controller.openStrand("recipeBook");
@@ -134,6 +115,9 @@ let newRecipe = {
         event.preventDefault();
         controller.closeModal();
 
+        let checkbox = document.getElementById("spreadsheetRecipeIsSquare");
+        let route = (checkbox.checked === true) ? "/recipes/create/spreadsheet/square": "/recipes/create/spreadsheet";
+
         const file = document.getElementById("spreadsheetInput").files[0];
         let data = new FormData();
         data.append("recipes", file);
@@ -141,7 +125,7 @@ let newRecipe = {
         let loader = document.getElementById("loaderContainer");
         loader.style.display = "flex";
 
-        fetch("/recipes/create/spreadsheet", {
+        fetch(route, {
             method: "post",
             body: data
         })
@@ -150,16 +134,9 @@ let newRecipe = {
                 if(typeof(response) === "string"){
                     controller.createBanner(response, "error");
                 }else{
-                    for(let i = 0; i < response.length; i++){
-                        merchant.addRecipe(
-                            response[i]._id,
-                            response[i].name,
-                            response[i].price,
-                            response[i].ingredients
-                        );
-                    }
+                    merchant.addRecipes(response);
 
-                    controller.createBanner("ALL INGREDIENTS SUCCESSFULLY CREATED", "success");
+                    controller.createBanner("ALL RECIPES SUCCESSFULLY CREATED", "success");
                     controller.openStrand("recipeBook");
                 }
             })

+ 2 - 2
views/dashboardPage/js/sidebars/newTransaction.js

@@ -75,7 +75,7 @@ let newTransaction = {
                     if(typeof(response) === "string"){
                         controller.createBanner(response, "error");
                     }else{
-                        merchant.addTransaction(response);
+                        merchant.addTransactions([response], true);
 
                         controller.updateAnalytics();
                         controller.openStrand("transactions", merchant.getTransactions());
@@ -115,7 +115,7 @@ let newTransaction = {
                     for(let i = 0; i < response.recipes.length; i++){
                         response.recipes[i].recipe = response.recipes[i].recipe._id;
                     }
-                    merchant.addTransaction(response);
+                    merchant.addTransactions([response], true);
                     controller.updateAnalytics();
 
                     controller.openStrand("transactions", merchant.transactions);

+ 1 - 1
views/dashboardPage/js/strands/home.js

@@ -264,7 +264,7 @@ let home = {
                     }else{
                         for(let i = 0; i < response.length; i++){
                             merchant.removeIngredient(merchant.getIngredient(response[i].ingredient._id));
-                            merchant.addIngredient(response[i].ingredient, response[i].quantity, response[i].defaultUnit);
+                            merchant.addIngredients(response);
                         }
                         controller.createBanner("INGREDIENTS UPDATED", "success");
                     }

+ 1 - 4
views/dashboardPage/js/strands/orders.js

@@ -51,10 +51,7 @@ let orders = {
                     controller.createBanner(response, "error");
                 }else{
                     merchant.clearOrders();
-
-                    for(let i = 0; i < response.length; i++){
-                        merchant.addOrder(response[i], true);
-                    }
+                    merchant.addOrders(response);
                 }
             })
             .catch((err)=>{

+ 7 - 5
views/dashboardPage/js/strands/recipeBook.js

@@ -11,6 +11,7 @@ let recipeBook = {
             if(merchant.pos !== "none"){
                 document.getElementById("posUpdateRecipe").onclick = ()=>{this.posUpdate()};
             }
+            
             document.getElementById("recipeSearch").oninput = ()=>{this.search()};
 
             this.populateRecipes();
@@ -66,7 +67,7 @@ let recipeBook = {
     posUpdate: function(){
         let loader = document.getElementById("loaderContainer");
         loader.style.display = "flex";
-        let url = `/recipe/update/${merchant.pos}`;
+        let url = `/recipes/update/${merchant.pos}`;
 
         fetch(url, {
             method: "GET",
@@ -79,18 +80,19 @@ let recipeBook = {
                 if(typeof(response) === "string"){
                     controller.createBanner(response, "error");
                 }else{
+                    let newRecipes = [];
                     for(let i = 0; i < response.new.length; i++){
-                        const recipe = new Recipe(
+                        newRecipes.push(new Recipe(
                             response.new[i]._id,
                             response.new[i].name,
                             response.new[i].price,
                             merchant,
                             []
-                        );
-
-                        merchant.addRecipe(recipe);
+                        ));
                     }
 
+                    merchant.addRecipes(newRecipes);
+
                     for(let i = 0; i < response.removed.length; i++){
                         for(let j = 0; j < merchant.recipes.length; j++){
                             if(merchant.recipes[j].id === response.removed[i]._id){

+ 3 - 0
views/dashboardPage/modal.ejs

@@ -9,6 +9,9 @@
             <form id="modalSpreadsheetUpload" class="modalSpreadsheetUpload" method="post">
                 <h3>Choose a file to upload your <span id="modalSpreadsheetTitle"></span></h3>
                 <input id="spreadsheetInput" class="fileUpload" name="file" type="file">
+                <label id="" style="display:none;">
+                    <input id="spreadsheetRecipeIsSquare" type="checkbox">Square Items?
+                </label>
                 <input type="hidden" name="type">
                 <input class="button" type="submit" value="SUBMIT">
                 <a id="spreadsheetDownload">download template</a>

+ 3 - 3
views/otherPages/login.ejs

@@ -33,11 +33,11 @@
     
             <input id="signIn" type="submit" value="Sign In with Email">
     
-            <!-- <h1>OR</h1>
+            <h1>OR</h1>
     
-            <a class="button buttonWithBorder" href="/cloverlogin">Sign In with Clover</a>
+            <!-- <a class="button buttonWithBorder" href="/cloverlogin">Sign In with Clover</a> -->
     
-            <a class="button buttonWithBorder" href="/squarelogin">Sign In with Square</a> -->
+            <a class="button buttonWithBorder" href="/squarelogin">Sign In with Square</a>
             
             <a href="/reset/email" class="link">Forgot your password?</a>
     

+ 19 - 6
views/otherPages/register.ejs

@@ -20,7 +20,7 @@
             <% include ../shared/banner.ejs %>
         <% } %>
 
-        <form action="/merchant/create/none" method="post">
+        <form method="post">
             <h1> Join The Subline </h1>
 
             <label id="nameLabel">Restaurant Name
@@ -40,7 +40,7 @@
             </label>
     
             <label id="agreement">
-                <input type="checkbox" name="agree">
+                <input type="checkbox" name="agree" required>
 
                 <p>I agree to the 
                     <a class="link" href="/privacy">Privacy Policy</a> and the 
@@ -48,13 +48,26 @@
                 </p>
             </label>
 
-            <input class="buttonDisabled" type="submit" value="Sign Up with Email">
+            <h2 class="customText">SIGN UP WITH:</h2>
 
-            <!-- <h1>OR</h1>
+            <button id="squareButton" class="button" formaction="/squarelogin">
+                <svg aria-hidden="true" viewBox="0 0 44 44" width="44" height="44">
+                    <path fill="currentColor" d="M36.65 0H7.354A7.354 7.354 0 0 0 0 7.354V36.65a7.354 7.354 0 0 0 7.354 7.354H36.65a7.353 7.353 0 0 0 7.354-7.354V7.354A7.352 7.352 0 0 0 36.65 0zm-.646 33.685a2.32 2.32 0 0 1-2.32 2.32H10.325a2.32 2.32 0 0 1-2.321-2.32v-23.36a2.32 2.32 0 0 1 2.321-2.321h23.359a2.32 2.32 0 0 1 2.32 2.321v23.36z"></path>
+                    <path fill="currentColor" d="M17.333 28.003c-.736 0-1.332-.6-1.332-1.339V17.34c0-.739.596-1.339 1.332-1.339h9.338c.738 0 1.332.6 1.332 1.339v9.324c0 .739-.594 1.339-1.332 1.339h-9.338z"></path>
+                </svg>
+                <svg aria-hidden="true" viewBox="0 0 66 22" width="105" height="35">
+                    <path d="M11.2 10c-.7-.2-1.3-.4-1.8-.6C8.4 9 8 8.4 8 7.6c0-1.5 1.5-2.2 3-2.2 1.4 0 2.6.6 3.5 1.6l.1.1 1.2-.9-.1-.1c-1.1-1.4-2.7-2.2-4.6-2.2-1.2 0-2.4.3-3.2.9-1 .8-1.5 1.7-1.5 2.9 0 2.7 2.6 3.4 4.6 3.9 2.1.6 3.4 1 3.4 2.6s-1.3 2.6-3.2 2.6c-1 0-2.8-.3-3.9-2l-.1-.1-1.2.9v.1c1.1 1.6 2.9 2.5 5.1 2.5 2.9 0 4.9-1.6 4.9-4.1 0-2.8-2.7-3.5-4.8-4.1z" fill="currentColor"></path>
+                    <path d="M25.5 9.5V8h1.4v14h-1.4v-5.5c-.8 1.1-2 1.7-3.4 1.7-2.7 0-4.5-2.1-4.5-5.2s1.9-5.2 4.5-5.2c1.4-.1 2.6.6 3.4 1.7zM19.1 13c0 2.9 1.6 3.9 3.2 3.9 2 0 3.3-1.5 3.3-3.9s-1.3-3.9-3.3-3.9c-2.4 0-3.2 2-3.2 3.9z" fill-rule="evenodd" clip-rule="evenodd" fill="currentColor"></path>
+                    <path d="M36.2 8v5.5c0 1.9-1.3 3.3-3.2 3.3-1.5 0-2.3-.9-2.3-2.8V8h-1.4v6.4c0 2.4 1.3 3.8 3.5 3.8 1.4 0 2.5-.6 3.3-1.6V18h1.4V8h-1.3z" fill="currentColor"></path>
+                    <path d="M40.3 9c1-.8 2.4-1.3 3.9-1.3 2.2 0 3.6 1.1 3.6 3V18h-1.4v-1.1c-.7.9-1.7 1.3-3.1 1.3-2.2 0-3.5-1.2-3.5-3.1 0-2.5 2.3-2.8 3.3-3 .2 0 .3-.1.5-.1 1.4-.2 2.7-.4 2.7-1.6 0-1.3-1.7-1.4-2.2-1.4-.9 0-2.2.3-3.1 1v.2L40.3 9zm.9 6.1c0 1.6 1.5 1.8 2.2 1.8 1.4 0 2.9-.8 2.9-2.9v-1.4c-.7.4-1.7.6-2.5.8l-.4.1c-1.5.1-2.2.5-2.2 1.6z" fill-rule="evenodd" clip-rule="evenodd" fill="currentColor"></path>
+                    <path d="M55.9 8.2c-.3-.2-.9-.4-1.4-.4-1.1 0-2.2.6-2.8 1.5V8h-1.4v10h1.4v-5.4c0-2.4 1.3-3.4 2.7-3.4.4 0 .8.1 1.1.2l.1.1.3-1.3z" fill="currentColor"></path>
+                    <path d="M56.3 13c0-3.1 1.9-5.3 4.7-5.3 2.7 0 4.5 1.9 4.5 4.7V13.2h-7.7c0 2.2 1.4 3.6 3.4 3.6 1.2 0 2.2-.5 2.8-1.3l.1-.1 1 .9-.1.1c-.7.8-1.9 1.8-3.9 1.8-2.9 0-4.8-2.1-4.8-5.2zm4.6-3.9c-1.7 0-2.9 1.1-3.1 2.9H64c-.1-1.4-1-2.9-3.1-2.9z" fill-rule="evenodd" clip-rule="evenodd" fill="currentColor"></path>
+                </svg>
+            </button>
 
-            <a class="button buttonWithBorder" href="/cloverlogin">Sign Up with Clover</a>
+            <button id="noneButton" class="button" formaction="/merchant/create/none">NO POS</button>
 
-            <a class="button buttonWithBorder" href="/squarelogin">Sign Up with Square</a> -->
+            <!-- <a class="button buttonWithBorder" href="/cloverlogin">Sign Up with Clover</a> -->
 
             <a class="link" href="/login">Already have an account? Please Sign In</a>
         </form>

+ 25 - 0
views/otherPages/style.css

@@ -50,6 +50,20 @@ form{
     color: white;
 }
 
+#squareButton{
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border: 1px solid black;
+    background: white;
+    color: black;
+}
+
+    #squareButton:hover{
+        color: white;
+        background: black;
+    }
+
 /* Public Strand */
 #publicStrand{
     display: flex;
@@ -165,6 +179,17 @@ RegisterPage
             margin-right: 15px;
         }
 
+    .customText{
+        margin: 20px auto 0 auto;
+    }
+
+    #noneButton{
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 35px;
+    }
+
 /*
 Footer Partial
 */