├── .env ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── README.md ├── client ├── .env ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── staticwebapp.config.json ├── src │ ├── App.vue │ ├── assets │ │ ├── images │ │ │ ├── tc-logo.png │ │ │ └── yellow-pillow-bedside-table_1920x.jpg │ │ ├── logo.png │ │ └── style.css │ ├── auth │ │ ├── authGuard.js │ │ └── index.js │ ├── components │ │ ├── Footer.vue │ │ └── Header.vue │ ├── main.js │ ├── plugins │ │ └── vuetify.js │ ├── router │ │ └── index.js │ ├── services │ │ ├── consignorService.js │ │ ├── payoutService.js │ │ └── productService.js │ ├── store │ │ └── index.js │ └── views │ │ ├── ConsignorDatatable.vue │ │ ├── ConsignorDetail.vue │ │ ├── Consignors.vue │ │ ├── CreateConsignor.vue │ │ ├── CreateProduct.vue │ │ ├── Datatable.vue │ │ ├── Home.vue │ │ ├── PayoutDatatable.vue │ │ ├── PayoutDetail.vue │ │ ├── Payouts.vue │ │ ├── ProductDatatable.vue │ │ ├── ProductDetail.vue │ │ ├── Products.vue │ │ └── ProductsByVendor.vue └── yarn.lock ├── database ├── config.js └── db.js ├── db_backup ├── 2021-08-18-tconsigndb.bacpac ├── 2021-08-19_backup.bacpac └── 2021-08-22-backup.bak ├── middleware ├── auth.js └── permission.js ├── models ├── consignor-model.js ├── order-model.js ├── payout-model.js └── product-model.js ├── package-lock.json ├── package.json ├── public └── products │ ├── photo_2021-08-19_18-51-02.jpg │ └── photo_2021-08-19_18-51-12.jpg ├── routes ├── consignors.js ├── index.js ├── orders.js ├── payouts.js └── products.js ├── server.js ├── server ├── .env ├── .gitignore ├── database │ ├── config.js │ └── db.js ├── middleware │ ├── auth.js │ └── permission.js ├── models │ ├── consignor-model.js │ ├── order-model.js │ ├── payout-model.js │ └── product-model.js ├── package-lock.json ├── package.json ├── public │ └── products │ │ ├── photo_2021-08-19_18-51-02.jpg │ │ └── photo_2021-08-19_18-51-12.jpg ├── routes │ ├── consignors.js │ ├── index.js │ ├── orders.js │ ├── payouts.js │ └── products.js ├── server.js ├── services │ ├── consignorService.js │ ├── orderService.js │ ├── payoutService.js │ ├── productService.js │ └── shopify.js └── yarn.lock ├── services ├── consignorService.js ├── orderService.js ├── payoutService.js ├── productService.js └── shopify.js ├── theme_source ├── figma-ui-kit-main.zip └── materio-v1.0.zip └── yarn.lock /.env: -------------------------------------------------------------------------------- 1 | # MSSQL config 2 | DB_HOST=tconsign21.database.windows.net 3 | DB_USER=tcadmin 4 | DB_PASS=Over 12,000 sq. ft. of finds! 5 | DB_NAME=tconsign 6 | PORT=8000 7 | 8 | # Auth0 config 9 | AUTH0_DOMAIN=eclectico.us.auth0.com 10 | AUTH0_AUDIENCE=https://tacomaconsignment.com 11 | 12 | # Azure blob config 13 | AZURE_ACCOUNT_NAME=cs410032000dc000ac4 14 | AZURE_ACCOUNT_KEY=Rk5OZVd7RIUSZjHt1yg/YGRVgnf+NzM33hyNWvC3SOJQgiPBktph+G9DBTN+jPQzP+3cCCdutyYg1cbKGoIUrw== 15 | AZURE_BLOB_URL=https://cs410032000dc000ac4.blob.core.windows.net 16 | AZURE_CONTAINER_NAME=testcontainer 17 | 18 | # Shopify config 19 | SHOPIFY_API_KEY=fa4f8443ab7b37f4803230a8aebbb7b2 20 | SHOPIFY_PASSWORD=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 21 | SHOPIFY_SHOP_NAME=spfy-connection-app-store.myshopify.com 22 | SHOPIFY_ACCESS_TOKEN=prtapi_66df9304cda675601c68025aeac9a208 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env.test 73 | 74 | # parcel-bundler cache (https://parceljs.org/) 75 | .cache 76 | 77 | # Next.js build output 78 | .next 79 | 80 | # Nuxt.js build / generate output 81 | .nuxt 82 | dist 83 | 84 | # Gatsby files 85 | .cache/ 86 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 87 | # https://nextjs.org/blog/next-9-1#public-directory-support 88 | # public 89 | 90 | # vuepress build output 91 | .vuepress/dist 92 | 93 | # Serverless directories 94 | .serverless/ 95 | 96 | # FuseBox cache 97 | .fusebox/ 98 | 99 | # DynamoDB Local files 100 | .dynamodb/ 101 | 102 | # TernJS port file 103 | .tern-port 104 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Node Functions", 6 | "type": "node", 7 | "request": "attach", 8 | "port": 9229, 9 | "preLaunchTask": "func: host start" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.deploySubpath": "api", 3 | "azureFunctions.postDeployTask": "npm install (functions)", 4 | "azureFunctions.projectLanguage": "JavaScript", 5 | "azureFunctions.projectRuntime": "~3", 6 | "debug.internalConsoleOptions": "neverOpen", 7 | "azureFunctions.preDeployTask": "npm prune (functions)", 8 | "appService.defaultWebAppToDeploy": "/subscriptions/45a29aab-8b41-4d5a-8809-08ed170c5b7d/resourceGroups/appsvc_linux_centralus_premium/providers/Microsoft.Web/sites/tconsign-appservice", 9 | "appService.deploySubpath": "." 10 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "func", 6 | "command": "host start", 7 | "problemMatcher": "$func-node-watch", 8 | "isBackground": true, 9 | "dependsOn": "npm install (functions)", 10 | "options": { 11 | "cwd": "${workspaceFolder}/server" 12 | } 13 | }, 14 | { 15 | "type": "shell", 16 | "label": "npm install (functions)", 17 | "command": "npm install", 18 | "options": { 19 | "cwd": "${workspaceFolder}/server" 20 | } 21 | }, 22 | { 23 | "type": "shell", 24 | "label": "npm prune (functions)", 25 | "command": "npm prune --production", 26 | "problemMatcher": [], 27 | "options": { 28 | "cwd": "${workspaceFolder}/server" 29 | } 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tacoma Consignment Project Overview 2 | 3 | Tacoma Consignment is a "brick-and-mortar" retail consignment business specializing in furniture and art. It is transitioning from a in-person based Quickbooks POS system to a joint online/in-person commerce system based on the following technologies: 4 | 5 | * Shopify (eCommerce and POS) 6 | * Stripe for consignor payout 7 | * Azure SQL Server as master database and "source of truth" (open to discussion, but relational db preferred) 8 | * Auth0 for identity management of: 9 | * consignors 10 | * customers 11 | * store staff 12 | * store admins 13 | * Vuetify as a web front-end 14 | * Segment for referral tracking and customer insights 15 | * Axios for API management 16 | * Mailchimp for email management and marketing campaigns 17 | 18 | ## MVP Feature Overview 19 | 20 | The core system needs to enable the following roles and activities: 21 | 22 | * Vuetify front-end based Store management single-page application including product onboarding with proper commission attribution and financial treatment of vendors and consignors 23 | * Product creation page and product-image upload via Vuetify web front-end, published to Shopify 24 | * Wishlist management via customer signup (Vuetify front-end) and product tagging on Shopify website 25 | * Print QR-code based product tag with product description, price, sku on Zebra, Epson, or other wireless label printer 26 | * Open-ended wishlist form analogous to product creation flow 27 | * Customer signup flow that uses [Auth0](https://auth0.com/docs/quickstart/spa/vuejs) Shopify and other social connectors (Google, Facebook, Amazon, and [magic email links](https://auth0.com/docs/connections/passwordless/guides/email-magic-link)) to authorize customer, create an account in Azure and publish the results to appropriate Shopify and Mailchimp campaigns 28 | * New accounts trigger appropriate discount assignments and Mailchimp campaigncustomer discount via mailchimp email signup 29 | * Customer management including authentication via Auth0, referral tracking via Segment, and appropriate updating of relevant Mailchimp campaigns 30 | * New consignor onboarding system, including invite system to transition existing merchants to new portal and payout alternatives 31 | * commission structures 32 | * active and sold products 33 | * billing address 34 | * PDF versions of contracts 35 | * Vendor and consignor payout via automated payout on Stripe or manual checks generated from a PDF template and printed; Azure system must enforce proper accounting 36 | * Synching transactions within and across systems: 37 | * Products, consignors, and staff store management functionality within Azure 38 | * Automated synchronization with Shopify via Webhooks 39 | * Communicate with web front-end via Vuetify/Axios/Azure/Auth0 40 | * Job execution of automatic discounting functionality 41 | * Publishing and synching data to Shopify via Shopify REST (or Graph) API 42 | 43 | The Tacoma Consignment SQL Server database is the source of truth for all data. To do so it has to also capture all the external transactions that occur in the Shopify and Stripe systems, as well as integrate into the Vuetify front-end to enable the management of the store. 44 | 45 | 46 | ## Project setup 47 | 48 | First, clone this repo and switch into the repo folder: 49 | 50 | ```bash 51 | git clone git@github.com:auth0-blog/vue-express-auth.git 52 | cd vue-express-auth 53 | ``` 54 | 55 | Now you need to install the dependencies for the client and server code. 56 | 57 | ### Set up the Express server 58 | 59 | ```bash 60 | cd server 61 | npm install 62 | ``` 63 | 64 | ### Set up the Vue client 65 | 66 | In a new terminal tab: 67 | 68 | ```bash 69 | cd ../client 70 | npm install 71 | ``` 72 | 73 | Now click into "Settings" and fill in some information that Auth0 needs to configure authentication: 74 | 75 | **Allowed Callback URLs** — `http://localhost:8080` 76 | 77 | **Allowed Logout URLs** — `http://localhost:8080` 78 | 79 | **Allowed Web Origins** — `http://localhost:8080` 80 | 81 | Scroll down and click "Save Changes". 82 | 83 | ### Create the Auth0 API 84 | 85 | Next, click on "APIs" on the left menu. Click "Create API" and call it "Vue Express API" (or anything you'd like). For "Identifier", we recommend a URL such as `https://vue-express-api.com`. It doesn't have to be a publicly available URL and we'll never call it, it's just for naming purposes. You can leave "Signing algorithm" as is and then press "Create". 86 | 87 | That's all you need from the dashboard for now, but don't click out yet. You'll need to pull some of these values from the dashboard into your application soon. 88 | 89 | In the `client` directory, create a file for the config values: 90 | 91 | ```bash 92 | touch auth_config.json 93 | ``` 94 | 95 | > **Important:** Make sure you add `auth_config.json` to your `.gitignore` file! 96 | 97 | ### Connecting with Auth0 98 | 99 | Now open up `auth_config.json` and paste in: 100 | 101 | ```js 102 | { 103 | "domain": "your-domain.auth0.com", 104 | "clientId": "your-client-id", 105 | "audience": "https://your-identifier.com" 106 | } 107 | ``` 108 | 109 | **Finding your `auth_config` values:** 110 | 111 | * Head to the [Auth0 dashboard](https://manage.auth0.com/dashboard) 112 | * Click on "APIs" and select your API 113 | * Copy the value for "Identifier" and paste it into `audience` in `auth_config.json` 114 | * Click on "Applications" and select your application (Vue Events) 115 | * Click on "Settings" 116 | * Copy the value for "Domain" and paste it into `domain` in `auth_config.json` 117 | * Copy the value for "Client ID" and paste it into `clientId` in `auth_config.json` 118 | 119 | Now you should be able to sign in to the application, but you still won't be able to access single event details because you need to add this information to the server side where the API access token is validated. 120 | 121 | Open up `server/server.js` and find: 122 | 123 | ```js 124 | const authConfig = { 125 | domain: "YOUR-DOMAIN", 126 | audience: "YOUR-IDENTIFIER" 127 | }; 128 | ``` 129 | 130 | Replace the `domain` and `audience` placeholders with the values listed above. 131 | 132 | ### Testing the app 133 | 134 | Now that everything is set up, you can test the app. 135 | 136 | **Run the server** 137 | 138 | Make sure you're in the `server` directory in your terminal and start the server with: 139 | 140 | ```bash 141 | npm start 142 | ``` 143 | 144 | Server is running at [http://localhost:8000](http://localhost:8000). 145 | 146 | **Run the client** 147 | 148 | In your other tab, make sure you're in `client` and run: 149 | 150 | ```bash 151 | npm run serve 152 | ``` 153 | 154 | You can view the Vue app in the browser at [http://localhost:8080](http://localhost:8080). 155 | 156 | You can now also sign in, receive an API access token, and view an event's details page at [http://localhost:8080/event/1](http://localhost:8080/event/1). 157 | 158 | Be sure to [check out the full tutorial](https://auth0.com/blog/how-to-make-secure-http-requests-with-vue-and-express/) to see how this process works. 159 | -------------------------------------------------------------------------------- /client/.env: -------------------------------------------------------------------------------- 1 | VUE_APP_API_URL=https://tconsignappservice.azurewebsites.net/ -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | auth_config.json 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # vuetify 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /client/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"], 3 | }; 4 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuetify", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@auth0/auth0-spa-js": "^1.17.0", 12 | "@babel/polyfill": "^7.4.4", 13 | "@mdi/js": "^5.9.55", 14 | "axios": "^0.21.1", 15 | "core-js": "^3.6.5", 16 | "jspdf": "^2.3.1", 17 | "jspdf-autotable": "^3.5.20", 18 | "moment-timezone": "^0.5.33", 19 | "number-to-words": "^1.2.4", 20 | "vee-validate": "^3.4.11", 21 | "vue": "^2.6.11", 22 | "vue-router": "^3.2.0", 23 | "vuetify": "^2.4.0", 24 | "vuex": "^3.4.0" 25 | }, 26 | "devDependencies": { 27 | "@vue/cli-plugin-babel": "~4.5.0", 28 | "@vue/cli-plugin-eslint": "~4.5.0", 29 | "@vue/cli-plugin-router": "~4.5.0", 30 | "@vue/cli-plugin-vuex": "~4.5.0", 31 | "@vue/cli-service": "~4.5.0", 32 | "@vue/eslint-config-prettier": "^6.0.0", 33 | "babel-eslint": "^10.1.0", 34 | "eslint": "^6.7.2", 35 | "eslint-plugin-prettier": "^3.3.1", 36 | "eslint-plugin-vue": "^6.2.2", 37 | "prettier": "^2.2.1", 38 | "vue-cli-plugin-vuetify": "~2.4.2", 39 | "vue-template-compiler": "^2.6.11" 40 | }, 41 | "eslintConfig": { 42 | "root": true, 43 | "env": { 44 | "node": true 45 | }, 46 | "extends": [ 47 | "plugin:vue/essential", 48 | "eslint:recommended", 49 | "@vue/prettier" 50 | ], 51 | "parserOptions": { 52 | "parser": "babel-eslint" 53 | }, 54 | "rules": {} 55 | }, 56 | "browserslist": [ 57 | "> 1%", 58 | "last 2 versions", 59 | "not dead", 60 | "not ie <= 10" 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Tconsign-portal 9 | 10 | 11 | 12 | 13 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /client/public/staticwebapp.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationFallback": { 3 | "rewrite": "index.html", 4 | "exclude": ["/images/*.{png,jpg,gif,ico}", "/*.{css,scss,js}"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /client/src/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /client/src/assets/images/tc-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/client/src/assets/images/tc-logo.png -------------------------------------------------------------------------------- /client/src/assets/images/yellow-pillow-bedside-table_1920x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/client/src/assets/images/yellow-pillow-bedside-table_1920x.jpg -------------------------------------------------------------------------------- /client/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/client/src/assets/logo.png -------------------------------------------------------------------------------- /client/src/assets/style.css: -------------------------------------------------------------------------------- 1 | .custom-title .v-app-bar-title__content { 2 | width: max-content !important; 3 | } 4 | 5 | .grey-col { 6 | color: rgba(0, 0, 0, 0.87) !important; 7 | } 8 | 9 | .tc-title { 10 | color: #fff !important; 11 | font-weight: 700; 12 | font-size: 4rem !important; 13 | text-transform: uppercase; 14 | line-height: 1.1; 15 | text-shadow: 1px 1px 7px transparent; 16 | display: flex; 17 | justify-content: center; 18 | margin-top: 18rem; 19 | background: rgb(255, 255, 255, 0.1); 20 | } 21 | 22 | .tc-footer-layout { 23 | padding: 2rem !important; 24 | } 25 | 26 | .v-application .mb-12 { 27 | border-radius: 0px !important; 28 | margin-bottom: 0px !important; 29 | } 30 | 31 | .v-toolbar { 32 | flex: 0; 33 | } 34 | 35 | .icon-space { 36 | padding: 1rem; 37 | margin: 1rem; 38 | } 39 | 40 | .custom-spacing { 41 | margin: 2rem 4rem; 42 | } 43 | 44 | .create-button { 45 | margin: 3rem 4rem 0rem 0rem; 46 | } 47 | 48 | .create-product { 49 | padding: 1rem 4rem 2rem 4rem; 50 | } 51 | 52 | .create-title { 53 | padding: 2rem 0rem 0rem 3rem; 54 | } 55 | 56 | .tc-appbar { 57 | background: rgb(255, 255, 255, 0.93) !important; 58 | } 59 | 60 | .icon-width { 61 | width: 170px !important; 62 | } 63 | 64 | .right-space { 65 | padding-right: 8px !important; 66 | } 67 | 68 | .white-col { 69 | color: white !important; 70 | } 71 | 72 | .create-card { 73 | margin: 6rem 33% 2rem 33%; 74 | } 75 | 76 | .create-consignor { 77 | margin: 6rem 20% 2rem 20%; 78 | } 79 | 80 | .width-30 { 81 | width: 30%; 82 | } 83 | 84 | .create-footer { 85 | text-align: right; 86 | margin-top: 2rem; 87 | } 88 | 89 | .loading-button { 90 | margin-bottom: 2rem; 91 | } 92 | 93 | .custom-link{ 94 | color: rgba(0, 0, 0, 0.87) !important; 95 | text-decoration: none; 96 | } 97 | 98 | .image-label { 99 | margin: 2rem 0rem; 100 | } 101 | 102 | .payout-layout { 103 | margin: 1rem 6rem; 104 | } 105 | 106 | .p-title { 107 | padding: 1rem 1rem 3rem 0rem; 108 | } 109 | 110 | .p-sub-title { 111 | padding: 0rem 0rem 1rem 2rem; 112 | } -------------------------------------------------------------------------------- /client/src/auth/authGuard.js: -------------------------------------------------------------------------------- 1 | import { getInstance } from "./index"; 2 | 3 | export const authGuard = (to, from, next) => { 4 | const authService = getInstance(); 5 | 6 | const fn = () => { 7 | // If the user is authenticated, continue with the route 8 | if (authService.isAuthenticated) { 9 | return next(); 10 | } 11 | 12 | // Otherwise, log in 13 | authService.loginWithRedirect({ appState: { targetUrl: to.fullPath } }); 14 | }; 15 | 16 | // If loading has already finished, check our auth state using `fn()` 17 | if (!authService.loading) { 18 | return fn(); 19 | } 20 | 21 | // Watch for the loading property to change before we check isAuthenticated 22 | authService.$watch("loading", loading => { 23 | if (loading === false) { 24 | return fn(); 25 | } 26 | }); 27 | }; -------------------------------------------------------------------------------- /client/src/auth/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import createAuth0Client from "@auth0/auth0-spa-js"; 3 | 4 | /** Define a default action to perform after authentication */ 5 | const DEFAULT_REDIRECT_CALLBACK = () => 6 | window.history.replaceState({}, document.title, window.location.pathname); 7 | 8 | let instance; 9 | 10 | /** Returns the current instance of the SDK */ 11 | export const getInstance = () => instance; 12 | 13 | /** Creates an instance of the Auth0 SDK. If one has already been created, it returns that instance */ 14 | export const useAuth0 = ({ 15 | onRedirectCallback = DEFAULT_REDIRECT_CALLBACK, 16 | redirectUri = window.location.origin + "/products", 17 | ...options 18 | }) => { 19 | if (instance) return instance; 20 | 21 | // The 'instance' is simply a Vue object 22 | instance = new Vue({ 23 | data() { 24 | return { 25 | loading: true, 26 | isAuthenticated: false, 27 | user: {}, 28 | auth0Client: null, 29 | popupOpen: false, 30 | error: null 31 | }; 32 | }, 33 | methods: { 34 | /** Authenticates the user using a popup window */ 35 | async loginWithPopup(o) { 36 | this.popupOpen = true; 37 | 38 | try { 39 | await this.auth0Client.loginWithPopup(o); 40 | } catch (e) { 41 | // eslint-disable-next-line 42 | console.error(e); 43 | } finally { 44 | this.popupOpen = false; 45 | } 46 | 47 | this.user = await this.auth0Client.getUser(); 48 | this.isAuthenticated = true; 49 | }, 50 | /** Handles the callback when logging in using a redirect */ 51 | async handleRedirectCallback() { 52 | this.loading = true; 53 | try { 54 | await this.auth0Client.handleRedirectCallback(); 55 | this.user = await this.auth0Client.getUser(); 56 | this.isAuthenticated = true; 57 | } catch (e) { 58 | this.error = e; 59 | } finally { 60 | this.loading = false; 61 | } 62 | }, 63 | /** Authenticates the user using the redirect method */ 64 | loginWithRedirect(o) { 65 | return this.auth0Client.loginWithRedirect(o); 66 | }, 67 | /** Returns all the claims present in the ID token */ 68 | getIdTokenClaims(o) { 69 | return this.auth0Client.getIdTokenClaims(o); 70 | }, 71 | /** Returns the access token. If the token is invalid or missing, a new one is retrieved */ 72 | getTokenSilently(o) { 73 | return this.auth0Client.getTokenSilently(o); 74 | }, 75 | /** Gets the access token using a popup window */ 76 | 77 | getTokenWithPopup(o) { 78 | return this.auth0Client.getTokenWithPopup(o); 79 | }, 80 | /** Logs the user out and removes their session on the authorization server */ 81 | logout(o) { 82 | return this.auth0Client.logout(o); 83 | } 84 | }, 85 | /** Use this lifecycle method to instantiate the SDK client */ 86 | async created() { 87 | // Create a new instance of the SDK client using members of the given options object 88 | this.auth0Client = await createAuth0Client({ 89 | domain: options.domain, 90 | client_id: options.clientId, 91 | audience: options.audience, 92 | redirect_uri: redirectUri 93 | }); 94 | 95 | try { 96 | // If the user is returning to the app after authentication... 97 | if ( 98 | window.location.search.includes("code=") && 99 | window.location.search.includes("state=") 100 | ) { 101 | // handle the redirect and retrieve tokens 102 | const { appState } = await this.auth0Client.handleRedirectCallback(); 103 | 104 | // Notify subscribers that the redirect callback has happened, passing the appState 105 | // (useful for retrieving any pre-authentication state) 106 | onRedirectCallback(appState); 107 | } 108 | } catch (e) { 109 | this.error = e; 110 | } finally { 111 | // Initialize our internal authentication state 112 | this.isAuthenticated = await this.auth0Client.isAuthenticated(); 113 | this.user = await this.auth0Client.getUser(); 114 | this.loading = false; 115 | } 116 | } 117 | }); 118 | 119 | return instance; 120 | }; 121 | 122 | // Create a simple Vue plugin to expose the wrapper object throughout the application 123 | export const Auth0Plugin = { 124 | install(Vue, options) { 125 | Vue.prototype.$auth = useAuth0(options); 126 | } 127 | }; -------------------------------------------------------------------------------- /client/src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /client/src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /client/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | import App from "./App.vue" 3 | import router from "./router" 4 | import store from "./store" 5 | import vuetify from "./plugins/vuetify" 6 | import "@babel/polyfill" 7 | import "./assets/style.css" 8 | import moment from "moment-timezone" 9 | 10 | // Import the Auth0 configuration 11 | import { domain, clientId, audience } from "../auth_config.json" 12 | 13 | // Import the plugin here 14 | import { Auth0Plugin } from "./auth" 15 | 16 | // Install the authentication plugin here 17 | Vue.use(Auth0Plugin, { 18 | domain, 19 | clientId, 20 | audience, 21 | onRedirectCallback: appState => { 22 | router.push( 23 | appState && appState.targetUrl 24 | ? appState.targetUrl 25 | : window.location.pathname 26 | ) 27 | }, 28 | }) 29 | 30 | Vue.filter("formatDate", function (value) { 31 | if (value) { 32 | return moment(String(value)).format("MM/DD/YYYY hh:mm") 33 | } 34 | }) 35 | 36 | Vue.config.productionTip = false 37 | 38 | new Vue({ 39 | router, 40 | store, 41 | vuetify, 42 | render: h => h(App), 43 | }).$mount("#app") 44 | -------------------------------------------------------------------------------- /client/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuetify from "vuetify"; 3 | import "vuetify/dist/vuetify.min.css"; 4 | 5 | Vue.use(Vuetify); 6 | 7 | export default new Vuetify({}); 8 | -------------------------------------------------------------------------------- /client/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | import VueRouter from "vue-router" 3 | import Home from "../views/Home.vue" 4 | import { authGuard } from "../auth/authGuard" 5 | 6 | Vue.use(VueRouter) 7 | 8 | const routes = [ 9 | { 10 | path: "/", 11 | name: "Home", 12 | component: Home, 13 | }, 14 | { 15 | path: "/products", 16 | name: "Products", 17 | component: () => import("../views/Products.vue"), 18 | beforeEnter: authGuard, 19 | }, 20 | { 21 | path: "/products/:vendor", 22 | name: "ProductsByVendor", 23 | component: () => import("../views/ProductsByVendor.vue"), 24 | beforeEnter: authGuard, 25 | }, 26 | { 27 | path: "/create_product", 28 | name: "CreateProduct", 29 | component: () => import("../views/CreateProduct.vue"), 30 | beforeEnter: authGuard, 31 | }, 32 | { 33 | path: "/product/:productid", 34 | name: "ProductDetail", 35 | component: () => import("../views/ProductDetail.vue"), 36 | beforeEnter: authGuard, 37 | }, 38 | { 39 | path: "/payouts", 40 | name: "Payouts", 41 | component: () => import("../views/Payouts.vue"), 42 | beforeEnter: authGuard, 43 | }, 44 | { 45 | path: "/beforepayouts", 46 | name: "BeforePayouts", 47 | component: () => import("../views/Payouts.vue"), 48 | beforeEnter: authGuard, 49 | }, 50 | { 51 | path: "/payout/:vendor", 52 | name: "PayoutDetail", 53 | component: () => import("../views/PayoutDetail.vue"), 54 | beforeEnter: authGuard, 55 | }, 56 | { 57 | path: "/consignors", 58 | name: "Consignors", 59 | component: () => import("../views/Consignors.vue"), 60 | beforeEnter: authGuard, 61 | }, 62 | { 63 | path: "/create_consignor", 64 | name: "CreateConsignor", 65 | component: () => import("../views/CreateConsignor.vue"), 66 | beforeEnter: authGuard, 67 | }, 68 | { 69 | path: "/consignor/:id", 70 | name: "ConsignorDetail", 71 | component: () => import("../views/ConsignorDetail.vue"), 72 | beforeEnter: authGuard, 73 | }, 74 | ] 75 | 76 | const router = new VueRouter({ 77 | mode: "history", 78 | base: process.env.BASE_URL, 79 | routes, 80 | }) 81 | 82 | export default router 83 | -------------------------------------------------------------------------------- /client/src/services/consignorService.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | 3 | export default { 4 | async getConsignors() { 5 | let res = await axios.get(process.env.VUE_APP_API_URL + "consignors") 6 | return res.data 7 | }, 8 | 9 | async addConsignor(data) { 10 | let res = await axios.post(process.env.VUE_APP_API_URL + "consignor", data) 11 | return res.data 12 | }, 13 | 14 | async updateConsignor(data) { 15 | let res = await axios.put(process.env.VUE_APP_API_URL + "consignor", data) 16 | return res.data 17 | }, 18 | 19 | async deleteConsignor(id) { 20 | let res = await axios.delete(process.env.VUE_APP_API_URL + "consignor", { 21 | params: { 22 | id: id, 23 | }, 24 | }) 25 | return res.data 26 | }, 27 | 28 | async getConsignorById(id) { 29 | let res = await axios.get(process.env.VUE_APP_API_URL + "consignorbyid", { 30 | params: { 31 | id: id, 32 | }, 33 | }) 34 | return res.data 35 | }, 36 | 37 | async getConsignorByVendor(vendor) { 38 | let res = await axios.get(process.env.VUE_APP_API_URL + "consignor", { 39 | params: { 40 | vendor: vendor, 41 | }, 42 | }) 43 | return res.data 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /client/src/services/payoutService.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | 3 | export default { 4 | async getPayouts(accessToken, flag) { 5 | let res = await axios.get(process.env.VUE_APP_API_URL + "payouts", { 6 | headers: { 7 | Authorization: `Bearer ${accessToken}`, 8 | }, 9 | params: { 10 | flag: flag, 11 | }, 12 | }) 13 | return res.data 14 | }, 15 | async getPayoutDetails(vendor) { 16 | let res = await axios.get(process.env.VUE_APP_API_URL + "payout_details", { 17 | params: { 18 | vendor: vendor, 19 | }, 20 | }) 21 | return res.data 22 | }, 23 | async getPayoutByVendor(vendor) { 24 | let res = await axios.get(process.env.VUE_APP_API_URL + "payout", { 25 | params: { 26 | vendor: vendor, 27 | }, 28 | }) 29 | return res.data 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /client/src/services/productService.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | 3 | export default { 4 | async getProducts(accessToken) { 5 | let res = await axios.get(process.env.VUE_APP_API_URL + "products", { 6 | headers: { 7 | Authorization: `Bearer ${accessToken}`, 8 | }, 9 | }) 10 | return res.data 11 | }, 12 | 13 | async getProductById(product_id) { 14 | let res = await axios.get(process.env.VUE_APP_API_URL + "product", { 15 | params: { 16 | product_id: product_id, 17 | }, 18 | }) 19 | return res.data 20 | }, 21 | 22 | async getProductsByVendor(vendor) { 23 | let res = await axios.get(process.env.VUE_APP_API_URL + "productsbyvendor", { 24 | params: { 25 | vendor: vendor, 26 | }, 27 | }) 28 | return res.data 29 | }, 30 | 31 | async addProduct(formData) { 32 | let res = await axios.post( 33 | process.env.VUE_APP_API_URL + "products", 34 | formData 35 | ) 36 | return res.data 37 | }, 38 | 39 | async updateProduct(formData) { 40 | let res = await axios.put( 41 | process.env.VUE_APP_API_URL + "products", 42 | formData 43 | ) 44 | return res.data 45 | }, 46 | 47 | async deleteProduct(product_id, title) { 48 | let res = await axios.delete(process.env.VUE_APP_API_URL + "products", { 49 | params: { 50 | title: title, 51 | product_id: product_id, 52 | }, 53 | }) 54 | return res.data 55 | }, 56 | 57 | async getEventSingle(eventId, accessToken) { 58 | let res = await axios.get( 59 | process.env.VUE_APP_API_URL + "events/" + eventId, 60 | { 61 | headers: { 62 | Authorization: `Bearer ${accessToken}`, 63 | }, 64 | } 65 | ) 66 | return res.data 67 | }, 68 | } 69 | -------------------------------------------------------------------------------- /client/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | Vue.use(Vuex); 5 | 6 | export default new Vuex.Store({ 7 | state: {}, 8 | mutations: {}, 9 | actions: {}, 10 | modules: {}, 11 | }); 12 | -------------------------------------------------------------------------------- /client/src/views/ConsignorDatatable.vue: -------------------------------------------------------------------------------- 1 | 90 | 91 | 195 | -------------------------------------------------------------------------------- /client/src/views/ConsignorDetail.vue: -------------------------------------------------------------------------------- 1 | 123 | 124 | 254 | -------------------------------------------------------------------------------- /client/src/views/Consignors.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 43 | -------------------------------------------------------------------------------- /client/src/views/CreateConsignor.vue: -------------------------------------------------------------------------------- 1 | 109 | 110 | 225 | -------------------------------------------------------------------------------- /client/src/views/CreateProduct.vue: -------------------------------------------------------------------------------- 1 | 118 | 119 | 251 | -------------------------------------------------------------------------------- /client/src/views/Datatable.vue: -------------------------------------------------------------------------------- 1 | 203 | 204 | 428 | -------------------------------------------------------------------------------- /client/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | -------------------------------------------------------------------------------- /client/src/views/PayoutDatatable.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 97 | -------------------------------------------------------------------------------- /client/src/views/PayoutDetail.vue: -------------------------------------------------------------------------------- 1 | 101 | 102 | 246 | -------------------------------------------------------------------------------- /client/src/views/Payouts.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 37 | -------------------------------------------------------------------------------- /client/src/views/ProductDetail.vue: -------------------------------------------------------------------------------- 1 | 161 | 162 | 330 | -------------------------------------------------------------------------------- /client/src/views/Products.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 29 | -------------------------------------------------------------------------------- /client/src/views/ProductsByVendor.vue: -------------------------------------------------------------------------------- 1 | 120 | 121 | 182 | -------------------------------------------------------------------------------- /database/config.js: -------------------------------------------------------------------------------- 1 | 2 | // config for your mssql 3 | const config = { 4 | user: process.env.DB_USER, 5 | password: process.env.DB_PASS, 6 | server: process.env.DB_HOST, 7 | database: process.env.DB_NAME, 8 | options: { 9 | trustedConnection: true, 10 | encrypt: true, 11 | enableArithAbort: true, 12 | trustServerCertificate: true, 13 | }, 14 | } 15 | 16 | module.exports = config -------------------------------------------------------------------------------- /database/db.js: -------------------------------------------------------------------------------- 1 | const sql = require("mssql") 2 | const databaseConfig = require('./config') 3 | 4 | sql.connect(databaseConfig) 5 | 6 | module.exports = sql 7 | -------------------------------------------------------------------------------- /db_backup/2021-08-18-tconsigndb.bacpac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/db_backup/2021-08-18-tconsigndb.bacpac -------------------------------------------------------------------------------- /db_backup/2021-08-19_backup.bacpac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/db_backup/2021-08-19_backup.bacpac -------------------------------------------------------------------------------- /db_backup/2021-08-22-backup.bak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/db_backup/2021-08-22-backup.bak -------------------------------------------------------------------------------- /middleware/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require("express-jwt") 2 | const jwksRsa = require("jwks-rsa") 3 | 4 | // Create middleware to validate the JWT using express-jwt 5 | const checkJwt = jwt({ 6 | // Provide a signing key based on the key identifier in the header and the signing keys provided by your Auth0 JWKS endpoint. 7 | secret: jwksRsa.expressJwtSecret({ 8 | cache: true, 9 | rateLimit: true, 10 | jwksRequestsPerMinute: 5, 11 | jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`, 12 | }), 13 | 14 | // Validate the audience (Identifier) and the issuer (Domain). 15 | audience: process.env.AUTH0_AUDIENCE, 16 | issuer: `https://${process.env.AUTH0_DOMAIN}/`, 17 | algorithms: ["RS256"], 18 | }) 19 | 20 | module.exports = checkJwt -------------------------------------------------------------------------------- /middleware/permission.js: -------------------------------------------------------------------------------- 1 | const jwtAuthz = require("express-jwt-authz") 2 | 3 | const checkPermissions = jwtAuthz(["manage:users"], { 4 | customScopeKey: "permissions", 5 | }) 6 | 7 | module.exports = checkPermissions -------------------------------------------------------------------------------- /models/consignor-model.js: -------------------------------------------------------------------------------- 1 | const db = require("../database/db") 2 | 3 | const consignorModel = { 4 | getAllConsignors: getAllConsignors, 5 | addConsignor: addConsignor, 6 | updateConsignor: updateConsignor, 7 | getConsignorById: getConsignorById, 8 | getConsignorByVendor: getConsignorByVendor, 9 | delConsignor: delConsignor, 10 | } 11 | 12 | function getAllConsignors() { 13 | return new Promise((resolve, reject) => { 14 | var request = new db.Request() 15 | let query = "SELECT * FROM consignors" 16 | 17 | request.query(query, (error, rows) => { 18 | if (error) { 19 | reject(error.message) 20 | } else { 21 | resolve(rows.recordset) 22 | } 23 | }) 24 | }) 25 | } 26 | 27 | function addConsignor(data) { 28 | var request = new db.Request() 29 | request.input("qbCompany", db.VarChar, data.company) 30 | request.input("defaultPercentage", db.Numeric, 50) 31 | request.input("qbFirst", db.VarChar, data.first) 32 | request.input("qbLast", db.VarChar, data.last) 33 | request.input("qbStAddress1", db.VarChar, data.stAddress1) 34 | request.input("qbStAddress2", db.VarChar, data.stAddress2) 35 | request.input("qbCity", db.VarChar, data.city) 36 | request.input("qbState", db.VarChar, data.state) 37 | request.input("qbZip", db.VarChar, data.zip) 38 | request.input("qbEmail", db.VarChar, data.email) 39 | request.input("qbPhone", db.VarChar, data.phone) 40 | let query = 41 | "INSERT INTO consignors(qbCompany, defaultPercentage, qbFirst, qbLast, qbStAddress1, qbStAddress2, qbCity, qbState, qbZip, qbEmail, qbPhone ) VALUES (@qbCompany, @defaultPercentage, @qbFirst, @qbLast, @qbStAddress1, @qbStAddress2, @qbCity, @qbState, @qbZip, @qbEmail, @qbPhone)" 42 | 43 | return new Promise((resolve, reject) => { 44 | request.query(query, (error, rows) => { 45 | if (error) { 46 | reject(error.message) 47 | } else { 48 | resolve({ code: 200 }) 49 | } 50 | }) 51 | }) 52 | } 53 | 54 | function updateConsignor(data) { 55 | var request = new db.Request() 56 | request.input("id", db.VarChar, data.id) 57 | request.input("qbCompany", db.VarChar, data.company) 58 | request.input("qbFirst", db.VarChar, data.first) 59 | request.input("qbLast", db.VarChar, data.last) 60 | request.input("qbStAddress1", db.VarChar, data.stAddress1) 61 | request.input("qbStAddress2", db.VarChar, data.stAddress2) 62 | request.input("qbCity", db.VarChar, data.city) 63 | request.input("qbState", db.VarChar, data.state) 64 | request.input("qbZip", db.VarChar, data.zip) 65 | request.input("qbEmail", db.VarChar, data.email) 66 | request.input("qbPhone", db.VarChar, data.phone) 67 | let query = 68 | "UPDATE consignors SET qbCompany=@qbCompany, qbFirst=@qbFirst, qbLast=@qbLast, qbStAddress1=@qbStAddress1, qbStAddress2=@qbStAddress2, qbCity=@qbCity, qbState=@qbState, qbZip=@qbZip, qbEmail=@qbEmail, qbPhone=@qbPhone WHERE id=@id" 69 | 70 | return new Promise((resolve, reject) => { 71 | request.query(query, (error, rows) => { 72 | if (error) { 73 | reject(error.message) 74 | } else { 75 | resolve({ code: 200 }) 76 | } 77 | }) 78 | }) 79 | } 80 | 81 | function delConsignor(id) { 82 | return new Promise((resolve, reject) => { 83 | var request = new db.Request() 84 | request.input("id", db.Int, id) 85 | let query = "DELETE FROM consignors WHERE id=@id" 86 | 87 | request.query(query, (error, rows) => { 88 | if (error) { 89 | reject(error.message) 90 | } else { 91 | resolve(rows.recordset) 92 | } 93 | }) 94 | }) 95 | } 96 | 97 | function getConsignorById(id) { 98 | return new Promise((resolve, reject) => { 99 | var request = new db.Request() 100 | request.input("id", db.Int, id) 101 | let query = 102 | "SELECT * FROM consignors WHERE id=@id" 103 | 104 | request.query(query, (error, rows) => { 105 | if (error) { 106 | reject(error.message) 107 | } else { 108 | resolve(rows.recordset) 109 | } 110 | }) 111 | }) 112 | } 113 | 114 | function getConsignorByVendor(vendor) { 115 | return new Promise((resolve, reject) => { 116 | var request = new db.Request() 117 | request.input("vendor", db.VarChar, vendor) 118 | let query = 119 | "SELECT id, qbCompany, defaultPercentage, qbStAddress1, qbStAddress2, (qbCity + ', ' + qbState + ' ' + qbZip) as bottom_line FROM consignors WHERE qbCompany=@vendor" 120 | 121 | request.query(query, (error, rows) => { 122 | if (error) { 123 | reject(error.message) 124 | } else { 125 | resolve(rows.recordset) 126 | } 127 | }) 128 | }) 129 | } 130 | 131 | module.exports = consignorModel 132 | -------------------------------------------------------------------------------- /models/order-model.js: -------------------------------------------------------------------------------- 1 | const db = require("../database/db") 2 | 3 | const orderModel = { 4 | createOrders: createOrders, 5 | createOrderItem: createOrderItem, 6 | } 7 | 8 | function createOrders(req) { 9 | return new Promise((resolve, reject) => { 10 | var request = new db.Request() 11 | 12 | const spfy_order_id = req.body.name 13 | const spfy_email = req.body.contact_email 14 | const spfy_financial_status = req.body.financial_status 15 | const spfy_paid_at = req.body.processed_at 16 | const spfy_fulfillment_status = req.body.fulfillment_status 17 | const spfy_fulfilled_at = req.body.updated_at 18 | const spfy_accepts_marketing = req.body.buyer_accepts_marketing 19 | const spfy_currency = req.body.currency 20 | const spfy_subtotal = req.body.subtotal_price 21 | const spfy_shipping = req.body.requires_shipping 22 | const spfy_taxes = req.body.total_tax 23 | const spfy_total = req.body.total_price 24 | const spfy_discount_amount = req.body.total_discounts 25 | const spfy_created_at = req.body.created_at 26 | 27 | var spfy_billing_name = "" 28 | var spfy_billing_street = "" 29 | var spfy_billing_address_1 = "" 30 | var spfy_billing_address_2 = "" 31 | var spfy_billing_company = "" 32 | var spfy_billing_city = "" 33 | var spfy_billing_zip = "" 34 | var spfy_billing_state = "" 35 | var spfy_billing_province = "" 36 | var spfy_billing_country = "" 37 | var spfy_billing_phone = "" 38 | var spfy_billing_province_name = "" 39 | 40 | if (req.body.billing_address) { 41 | spfy_billing_name = req.body.billing_address.name 42 | spfy_billing_street = req.body.billing_address.address1 43 | spfy_billing_address_1 = req.body.billing_address.address1 44 | spfy_billing_address_2 = req.body.billing_address.address2 45 | spfy_billing_company = req.body.billing_address.company 46 | spfy_billing_city = req.body.billing_address.city 47 | spfy_billing_zip = req.body.billing_address.zip 48 | spfy_billing_state = req.body.billing_address.province 49 | spfy_billing_province = req.body.billing_address.province 50 | spfy_billing_country = req.body.billing_address.country 51 | spfy_billing_phone = req.body.billing_address.phone 52 | spfy_billing_province_name = req.body.billing_address.province 53 | } 54 | 55 | var spfy_shipping_name = "" 56 | var spfy_shipping_street = "" 57 | var spfy_shipping_address_1 = "" 58 | var spfy_shipping_address_2 = "" 59 | var spfy_shipping_company = "" 60 | var spfy_shipping_city = "" 61 | var spfy_shipping_zip = "" 62 | var spfy_shipping_state = "" 63 | var spfy_shipping_province = "" 64 | var spfy_shipping_country = "" 65 | var spfy_shipping_phone = "" 66 | var spfy_shipping_province_name = "" 67 | 68 | if (req.body.shipping_address) { 69 | spfy_shipping_name = req.body.shipping_address.name 70 | spfy_shipping_street = req.body.shipping_address.adress1 71 | spfy_shipping_address_1 = req.body.shipping_address.adress1 72 | spfy_shipping_address_2 = req.body.shipping_address.adress2 73 | spfy_shipping_company = req.body.shipping_address.company 74 | spfy_shipping_city = req.body.shipping_address.city 75 | spfy_shipping_zip = req.body.shipping_address.zip 76 | spfy_shipping_state = req.body.shipping_address.province 77 | spfy_shipping_province = req.body.shipping_address.province 78 | spfy_shipping_province_name = req.body.shipping_address.province 79 | spfy_shipping_country = req.body.shipping_address.country 80 | spfy_shipping_phone = req.body.shipping_address.phone 81 | } 82 | 83 | const spfy_notes = req.body.note 84 | const spfy_note_attributes = req.body.note_attributes 85 | const spfy_cancelled_at = req.body.cancelled_at 86 | const spfy_payment_method = req.body.processing_method 87 | const spfy_payment_reference_id = req.body.reference 88 | const spfy_refunded_amount = req.body.refunds.price 89 | const spfy_outstanding_balance = req.body.total_outstanding 90 | const spfy_employee = req.body.name 91 | const spfy_location = req.body.location_id 92 | const spfy_device_id = req.body.device_id 93 | const spfy_id = req.body.id 94 | const spfy_risk_level = "" 95 | const spfy_source = req.body.source_url 96 | var spfy_tax_1_name = "" 97 | var spfy_tax_1_amount = 0 98 | var spfy_tax_2_name = "" 99 | var spfy_tax_2_amount = 0 100 | var spfy_tax_3_name = "" 101 | var spfy_tax_3_amount = 0 102 | var spfy_tax_4_name = "" 103 | var spfy_tax_4_amount = 0 104 | var spfy_tax_5_name = "" 105 | var spfy_tax_5_amount = 0 106 | 107 | for (let i = 0; i < req.body.tax_lines.length; i++) { 108 | if (i == 0) { 109 | spfy_tax_1_name = req.body.tax_lines[0].title 110 | spfy_tax_1_amount = req.body.tax_lines[0].price 111 | } else if (i == 1) { 112 | spfy_tax_2_name = req.body.tax_lines[1].title 113 | spfy_tax_2_amount = req.body.tax_lines[1].price 114 | } else if (i == 2) { 115 | spfy_tax_3_name = req.body.tax_lines[2].title 116 | spfy_tax_3_amount = req.body.tax_lines[2].price 117 | } else if (i == 3) { 118 | spfy_tax_4_name = req.body.tax_lines[3].title 119 | spfy_tax_4_amount = req.body.tax_lines[3].price 120 | } else if (i == 4) { 121 | spfy_tax_5_name = req.body.tax_lines[4].title 122 | spfy_tax_5_amount = req.body.tax_lines[4].price 123 | } 124 | } 125 | 126 | const spfy_phone = req.body.phone 127 | const spfy_receipt_number = req.body.number 128 | const spfy_duties = req.body.current_total_duties_set 129 | 130 | const spfy_payment_terms_name = req.body.payment_gateway_names[0] 131 | const spfy_next_payment_due_at = "" 132 | const last_updated = req.body.updated_at 133 | const spfy_json_response = req.body 134 | 135 | request.input("spfy_order_id", db.VarChar, spfy_order_id) 136 | request.input("spfy_email", db.VarChar, spfy_email) 137 | request.input("spfy_financial_status", db.VarChar, spfy_financial_status) 138 | request.input("spfy_paid_at", db.DateTime, spfy_paid_at) 139 | request.input( 140 | "spfy_fulfillment_status", 141 | db.VarChar, 142 | spfy_fulfillment_status 143 | ) 144 | request.input("spfy_fulfilled_at", db.DateTime, spfy_fulfilled_at) 145 | request.input("spfy_accepts_marketing", db.VarChar, spfy_accepts_marketing) 146 | request.input("spfy_currency", db.VarChar, spfy_currency) 147 | request.input("spfy_subtotal", db.Numeric, spfy_subtotal) 148 | request.input("spfy_shipping", db.Numeric, spfy_shipping) 149 | request.input("spfy_taxes", db.Numeric, spfy_taxes) 150 | request.input("spfy_total", db.Numeric, spfy_total) 151 | request.input("spfy_discount_amount", db.Numeric, spfy_discount_amount) 152 | request.input("spfy_created_at", db.DateTime, spfy_created_at) 153 | request.input("spfy_billing_name", db.VarChar, spfy_billing_name) 154 | request.input("spfy_billing_street", db.VarChar, spfy_billing_street) 155 | request.input("spfy_billing_address_1", db.VarChar, spfy_billing_address_1) 156 | request.input("spfy_billing_address_2", db.VarChar, spfy_billing_address_2) 157 | request.input("spfy_billing_company", db.VarChar, spfy_billing_company) 158 | request.input("spfy_billing_city", db.VarChar, spfy_billing_city) 159 | request.input("spfy_billing_zip", db.VarChar, spfy_billing_zip) 160 | request.input("spfy_billing_state", db.VarChar, spfy_billing_state) 161 | request.input("spfy_billing_province", db.VarChar, spfy_billing_province) 162 | request.input("spfy_billing_country", db.VarChar, spfy_billing_country) 163 | request.input("spfy_billing_phone", db.Int, spfy_billing_phone) 164 | request.input( 165 | "spfy_billing_province_name", 166 | db.VarChar, 167 | spfy_billing_province_name 168 | ) 169 | request.input("spfy_shipping_name", db.VarChar, spfy_shipping_name) 170 | request.input("spfy_shipping_street", db.VarChar, spfy_shipping_street) 171 | request.input( 172 | "spfy_shipping_address_1", 173 | db.VarChar, 174 | spfy_shipping_address_1 175 | ) 176 | request.input( 177 | "spfy_shipping_address_2", 178 | db.VarChar, 179 | spfy_shipping_address_2 180 | ) 181 | request.input("spfy_shipping_company", db.VarChar, spfy_shipping_company) 182 | request.input("spfy_shipping_city", db.VarChar, spfy_shipping_city) 183 | request.input("spfy_shipping_zip", db.VarChar, spfy_shipping_zip) 184 | request.input("spfy_shipping_state", db.VarChar, spfy_shipping_state) 185 | request.input("spfy_shipping_province", db.VarChar, spfy_shipping_province) 186 | request.input( 187 | "spfy_shipping_province_name", 188 | db.VarChar, 189 | spfy_shipping_province_name 190 | ) 191 | request.input("spfy_shipping_country", db.VarChar, spfy_shipping_country) 192 | request.input("spfy_shipping_phone", db.VarChar, spfy_shipping_phone) 193 | request.input("spfy_notes", db.VarChar, spfy_notes) 194 | request.input("spfy_note_attributes", db.VarChar, spfy_note_attributes) 195 | request.input("spfy_cancelled_at", db.DateTime, spfy_cancelled_at) 196 | request.input("spfy_payment_method", db.VarChar, spfy_payment_method) 197 | request.input( 198 | "spfy_payment_reference_id", 199 | db.VarChar, 200 | spfy_payment_reference_id 201 | ) 202 | request.input("spfy_refunded_amount", db.Numeric, spfy_refunded_amount) 203 | request.input( 204 | "spfy_outstanding_balance", 205 | db.Numeric, 206 | spfy_outstanding_balance 207 | ) 208 | request.input("spfy_employee", db.VarChar, spfy_employee) 209 | request.input("spfy_location", db.VarChar, spfy_location) 210 | request.input("spfy_device_id", db.Int, spfy_device_id) 211 | request.input("spfy_id", db.VarChar, spfy_id) 212 | request.input("spfy_risk_level", db.VarChar, spfy_risk_level) 213 | request.input("spfy_source", db.VarChar, spfy_source) 214 | request.input("spfy_tax_1_name", db.VarChar, spfy_tax_1_name) 215 | request.input("spfy_tax_1_amount", db.Numeric, spfy_tax_1_amount) 216 | request.input("spfy_tax_2_name", db.VarChar, spfy_tax_2_name) 217 | request.input("spfy_tax_2_amount", db.Numeric, spfy_tax_2_amount) 218 | request.input("spfy_tax_3_name", db.VarChar, spfy_tax_3_name) 219 | request.input("spfy_tax_3_amount", db.Numeric, spfy_tax_3_amount) 220 | request.input("spfy_tax_4_name", db.VarChar, spfy_tax_4_name) 221 | request.input("spfy_tax_4_amount", db.Numeric, spfy_tax_4_amount) 222 | request.input("spfy_tax_5_name", db.VarChar, spfy_tax_5_name) 223 | request.input("spfy_tax_5_amount", db.Numeric, spfy_tax_5_amount) 224 | request.input("spfy_phone", db.VarChar, spfy_phone) 225 | request.input("spfy_receipt_number", db.VarChar, spfy_receipt_number) 226 | request.input("spfy_duties", db.Numeric, spfy_duties) 227 | request.input( 228 | "spfy_payment_terms_name", 229 | db.VarChar, 230 | spfy_payment_terms_name 231 | ) 232 | request.input( 233 | "spfy_next_payment_due_at", 234 | db.VarChar, 235 | spfy_next_payment_due_at 236 | ) 237 | request.input("last_updated", db.DateTime, last_updated) 238 | request.input("spfy_json_response", db.VarChar, spfy_json_response) 239 | 240 | let query = 241 | "INSERT INTO spfyOrders(spfy_order_id, spfy_email, spfy_financial_status, spfy_paid_at, \ 242 | spfy_fulfillment_status, spfy_fulfilled_at, spfy_accepts_marketing, spfy_currency, \ 243 | spfy_subtotal, spfy_shipping, spfy_taxes, spfy_total, spfy_discount_amount, spfy_created_at, \ 244 | spfy_billing_name, spfy_billing_street, spfy_billing_address_1, spfy_billing_address_2, \ 245 | spfy_billing_company, spfy_billing_city, spfy_billing_zip, spfy_billing_state, spfy_billing_province, \ 246 | spfy_shipping_name, spfy_shipping_street, spfy_shipping_address_1, spfy_shipping_address_2, spfy_shipping_company, \ 247 | spfy_shipping_city, spfy_shipping_zip, spfy_shipping_state, spfy_shipping_province, spfy_shipping_province_name, \ 248 | spfy_shipping_country, spfy_shipping_phone, spfy_notes, spfy_note_attributes, spfy_cancelled_at, \ 249 | spfy_payment_method, spfy_payment_reference_id, spfy_refunded_amount, spfy_outstanding_balance, spfy_employee, \ 250 | spfy_location, spfy_device_id, spfy_id, spfy_risk_level, spfy_source, spfy_tax_1_name,spfy_tax_1_amount, \ 251 | spfy_tax_2_name, spfy_tax_2_amount, spfy_tax_3_name, spfy_tax_3_amount, spfy_tax_4_name, spfy_tax_4_amount, \ 252 | spfy_tax_5_name, spfy_tax_5_amount, spfy_phone, spfy_receipt_number, spfy_duties, spfy_payment_terms_name, \ 253 | spfy_next_payment_due_at, last_updated, spfy_json_response) VALUES (@spfy_order_id, @spfy_email, @spfy_financial_status, @spfy_paid_at, \ 254 | @spfy_fulfillment_status, @spfy_fulfilled_at, @spfy_accepts_marketing, @spfy_currency, \ 255 | @spfy_subtotal, @spfy_shipping, @spfy_taxes, @spfy_total, @spfy_discount_amount, @spfy_created_at, \ 256 | @spfy_billing_name, @spfy_billing_street, @spfy_billing_address_1, @spfy_billing_address_2, \ 257 | @spfy_billing_company, @spfy_billing_city, @spfy_billing_zip, @spfy_billing_state, @spfy_billing_province, \ 258 | @spfy_shipping_name, @spfy_shipping_street, @spfy_shipping_address_1, @spfy_shipping_address_2, @spfy_shipping_company, \ 259 | @spfy_shipping_city, @spfy_shipping_zip, @spfy_shipping_state, @spfy_shipping_province, @spfy_shipping_province_name, \ 260 | @spfy_shipping_country, @spfy_shipping_phone, @spfy_notes, @spfy_note_attributes, @spfy_cancelled_at, \ 261 | @spfy_payment_method, @spfy_payment_reference_id, @spfy_refunded_amount, @spfy_outstanding_balance, @spfy_employee, \ 262 | @spfy_location, @spfy_device_id, @spfy_id, @spfy_risk_level, @spfy_source, @spfy_tax_1_name, @spfy_tax_1_amount, \ 263 | @spfy_tax_2_name, @spfy_tax_2_amount, @spfy_tax_3_name, @spfy_tax_3_amount, @spfy_tax_4_name, @spfy_tax_4_amount, \ 264 | @spfy_tax_5_name, @spfy_tax_5_amount, @spfy_phone, @spfy_receipt_number, @spfy_duties, @spfy_payment_terms_name, \ 265 | @spfy_next_payment_due_at, @last_updated, @spfy_json_response)" 266 | 267 | request.query(query, (error, rows) => { 268 | if (error) { 269 | reject(error.message) 270 | } else { 271 | resolve(rows.recordset) 272 | } 273 | }) 274 | }) 275 | } 276 | 277 | function createOrderItem( 278 | order_id, 279 | created_at, 280 | qty, 281 | name, 282 | price, 283 | compare_at_price, 284 | sku, 285 | shipping, 286 | taxable, 287 | fulfillment_status, 288 | vendor, 289 | discount_amount, 290 | last_updated 291 | ) { 292 | var request = new db.Request() 293 | request.input("spfy_order_id", db.VarChar, order_id) 294 | request.input("spfy_created_at", db.DateTime, created_at) 295 | request.input("spfy_line_item_qty", db.Numeric, qty) 296 | request.input("spfy_line_item_name", db.VarChar, name) 297 | request.input("spfy_line_item_price", db.Numeric, price) 298 | request.input("spfy_line_item_compare_at_price", db.Numeric, compare_at_price) 299 | request.input("spfy_line_item_sku", db.VarChar, sku) 300 | request.input("spfy_line_item_taxable", db.VarChar, taxable) 301 | request.input("spfy_line_item_req_shipping", db.VarChar, shipping) 302 | request.input( 303 | "spfy_line_item_fulfillment_status", 304 | db.VarChar, 305 | fulfillment_status 306 | ) 307 | request.input("spfy_line_item_discount_amount", db.Numeric, discount_amount) 308 | request.input("spfy_vendor", db.VarChar, vendor) 309 | request.input("last_updated", db.DateTime, last_updated) 310 | 311 | let subQuery = 312 | "INSERT INTO spfyOrderItems(spfy_order_id, spfy_created_at, spfy_line_item_qty, spfy_line_item_name, \ 313 | spfy_line_item_price, spfy_line_item_compare_at_price, spfy_line_item_sku, spfy_line_item_taxable, \ 314 | spfy_line_item_req_shipping, spfy_line_item_fulfillment_status, spfy_line_item_discount_amount, spfy_vendor, \ 315 | last_updated) VALUES (@spfy_order_id, @spfy_created_at, @spfy_line_item_qty, @spfy_line_item_name, \ 316 | @spfy_line_item_price, @spfy_line_item_compare_at_price, @spfy_line_item_sku, @spfy_line_item_taxable, \ 317 | @spfy_line_item_req_shipping, @spfy_line_item_fulfillment_status, @spfy_line_item_discount_amount, @spfy_vendor, @last_updated)" 318 | 319 | return new Promise((resolve, reject) => { 320 | request.query(subQuery, (err, data) => { 321 | if (err) { 322 | reject(err.message) 323 | } else { 324 | resolve({ code: 200 }) 325 | } 326 | }) 327 | }) 328 | } 329 | 330 | module.exports = orderModel 331 | -------------------------------------------------------------------------------- /models/payout-model.js: -------------------------------------------------------------------------------- 1 | const db = require("../database/db") 2 | 3 | const payoutModel = { 4 | getPayouts: getPayouts, 5 | getPayoutDetailsByVendor: getPayoutDetailsByVendor, 6 | getPayoutByVendor: getPayoutByVendor, 7 | } 8 | 9 | function getPayouts(flag) { 10 | return new Promise((resolve, reject) => { 11 | var request = new db.Request() 12 | 13 | var date = new Date() 14 | var year = date.getFullYear() 15 | var month = "" 16 | 17 | //get first and last date 18 | if (flag == "BeforePayouts") { 19 | month = date.getMonth() 20 | } else { 21 | month = date.getMonth() + 1 22 | } 23 | 24 | const firstDate = new Date(year, month - 2, 0) 25 | const lastDate = new Date(year, month - 1, 1) 26 | 27 | request.input("firstDate", db.DateTime, firstDate) 28 | request.input("lastDate", db.DateTime, lastDate) 29 | 30 | let query = 31 | "SELECT distinct(spfy_vendor), sum(spfy_line_item_qty) as items_sold, \ 32 | format((sum(spfy_line_item_qty * spfy_line_item_price)), 'C') as total_sales, defaultPercentage, \ 33 | format(sum(spfy_line_item_qty * spfy_line_item_price * defaultPercentage/100), 'C') as net_sales from tstSpfyOrderItems items \ 34 | inner join consignors csn on csn.qbCompany = items.spfy_vendor \ 35 | where spfy_created_at > @firstDate and spfy_created_at < @lastDate \ 36 | group by spfy_vendor, defaultPercentage \ 37 | order by total_sales desc" 38 | 39 | request.query(query, (error, rows) => { 40 | if (error) { 41 | reject(error.message) 42 | } else { 43 | resolve(rows.recordset) 44 | } 45 | }) 46 | }) 47 | } 48 | 49 | function getPayoutDetailsByVendor(vendor) { 50 | return new Promise((resolve, reject) => { 51 | var request = new db.Request() 52 | 53 | //get first and last date 54 | var date = new Date() 55 | var month = date.getMonth() + 1 56 | var year = date.getFullYear() 57 | const firstDate = new Date(year, month - 2, 0) 58 | const lastDate = new Date(year, month - 1, 1) 59 | 60 | request.input("firstDate", db.DateTime, firstDate) 61 | request.input("lastDate", db.DateTime, lastDate) 62 | request.input("vendor", db.VarChar, vendor) 63 | 64 | let query = 65 | "SELECT spfy_order_id, spfy_line_item_name, spfy_line_item_qty, spfy_line_item_price, spfy_line_item_qty * spfy_line_item_price as total_amount, defaultPercentage, \ 66 | format((defaultPercentage / 100 * spfy_line_item_qty * spfy_line_item_price), 'C') as net_amount from tstSpfyOrderItems items \ 67 | inner join consignors csn on csn.qbCompany = items.spfy_vendor where spfy_vendor=@vendor and spfy_created_at > @firstDate and spfy_created_at < @lastDate \ 68 | group by spfy_order_id, spfy_vendor, spfy_line_item_name, defaultPercentage, spfy_line_item_price, spfy_line_item_qty \ 69 | order by total_amount desc" 70 | 71 | request.query(query, (error, rows) => { 72 | if (error) { 73 | reject(error.message) 74 | } else { 75 | resolve(rows.recordset) 76 | } 77 | }) 78 | }) 79 | } 80 | 81 | function getPayoutByVendor(vendor) { 82 | return new Promise((resolve, reject) => { 83 | var request = new db.Request() 84 | 85 | //get first and last date 86 | var date = new Date() 87 | var month = date.getMonth() + 1 88 | var year = date.getFullYear() 89 | const firstDate = new Date(year, month - 2, 0) 90 | const lastDate = new Date(year, month - 1, 1) 91 | 92 | request.input("firstDate", db.DateTime, firstDate) 93 | request.input("lastDate", db.DateTime, lastDate) 94 | request.input("vendor", db.VarChar, vendor) 95 | 96 | let query = 97 | "SELECT distinct(spfy_vendor), sum(spfy_line_item_qty) as items_sold, \ 98 | format(sum(spfy_line_item_qty * spfy_line_item_price), 'C') as total_sales, \ 99 | defaultPercentage, sum(spfy_line_item_qty * spfy_line_item_price * defaultPercentage/100) as net_sales from tstSpfyOrderItems items \ 100 | inner join consignors csn on csn.qbCompany = items.spfy_vendor where spfy_created_at > @firstDate and spfy_created_at < @lastDate and spfy_vendor=@vendor \ 101 | group by spfy_vendor, defaultPercentage \ 102 | order by total_sales desc" 103 | 104 | request.query(query, (error, rows) => { 105 | if (error) { 106 | reject(error.message) 107 | } else { 108 | resolve(rows.recordset) 109 | } 110 | }) 111 | }) 112 | } 113 | 114 | module.exports = payoutModel 115 | -------------------------------------------------------------------------------- /models/product-model.js: -------------------------------------------------------------------------------- 1 | const db = require("../database/db") 2 | const shopify = require("../services/shopify") 3 | const azureStorage = require("azure-storage") 4 | const getStream = require("into-stream") 5 | 6 | const blobService = azureStorage.createBlobService( 7 | process.env.AZURE_ACCOUNT_NAME, 8 | process.env.AZURE_ACCOUNT_KEY 9 | ) 10 | 11 | uploadFileToBlob = async (directoryPath, title, file) => { 12 | return new Promise((resolve, reject) => { 13 | const blobName = file.originalname 14 | const stream = getStream(file.buffer) 15 | const streamLength = file.buffer.length 16 | 17 | blobService.createBlockBlobFromStream( 18 | process.env.AZURE_CONTAINER_NAME, 19 | `${directoryPath}/${title}/${blobName}`, 20 | stream, 21 | streamLength, 22 | err => { 23 | if (err) { 24 | reject(err) 25 | } else { 26 | resolve({ 27 | filename: blobName, 28 | originalname: file.originalname, 29 | size: streamLength, 30 | path: `${process.env.AZURE_CONTAINER_NAME}/${directoryPath}/${title}/${blobName}`, 31 | url: `${process.env.AZURE_BLOB_URL}${process.env.AZURE_CONTAINER_NAME}/${directoryPath}/${title}/${blobName}`, 32 | }) 33 | } 34 | } 35 | ) 36 | }) 37 | } 38 | 39 | const productModel = { 40 | getAllProducts: getAllProducts, 41 | getProductById: getProductById, 42 | getProductsByVendor: getProductsByVendor, 43 | setProducts: setProducts, 44 | updateProducts: updateProducts, 45 | deleteProduct: deleteProduct, 46 | } 47 | 48 | function getAllProducts() { 49 | return new Promise((resolve, reject) => { 50 | var request = new db.Request() 51 | let query = "SELECT * FROM products" 52 | 53 | request.query(query, (error, rows) => { 54 | if (error) { 55 | reject(error.message) 56 | } else { 57 | resolve(rows.recordset) 58 | } 59 | }) 60 | }) 61 | } 62 | 63 | function getProductById(id) { 64 | const product_id = id 65 | return new Promise((resolve, reject) => { 66 | var request = new db.Request() 67 | request.input("product_id", db.Int, product_id) 68 | let query = "SELECT * FROM products WHERE product_id=@product_id" 69 | 70 | request.query(query, (error, rows) => { 71 | var shopify_id = "" 72 | if (error) { 73 | reject(error.message) 74 | } else { 75 | shopify_id = rows.recordset[0].shopify_id 76 | shopify.get( 77 | "/admin/products/" + shopify_id + ".json", 78 | function (err, product_data, headers) { 79 | var product = product_data.product 80 | // send records as a response 81 | resolve({ data: rows.recordset[0], shopifyData: product }) 82 | } 83 | ) 84 | } 85 | }) 86 | }) 87 | } 88 | 89 | function getProductsByVendor(vendor) { 90 | return new Promise((resolve, reject) => { 91 | var request = new db.Request() 92 | request.input("vendor", db.VarChar, vendor) 93 | let query = "SELECT * FROM products WHERE vendor=@vendor" 94 | 95 | request.query(query, (error, rows) => { 96 | if (error) { 97 | reject(error.message) 98 | } else { 99 | resolve({ data: rows.recordset }) 100 | } 101 | }) 102 | }) 103 | } 104 | 105 | function setProducts(req, shopify_id) { 106 | //Assign value to variable of product from request 107 | const title = req.body.title 108 | const consignor_id = req.body.consignor_id 109 | const description = req.body.description 110 | const product_type = req.body.product_type 111 | const size = req.body.size 112 | const color = req.body.color 113 | const material = req.body.material 114 | const price = req.body.price 115 | const base_price = req.body.base_price 116 | const notes = req.body.notes 117 | const published_at = req.body.published_at 118 | const discountSchedule = req.body.discountSchedule 119 | 120 | var request = new db.Request() 121 | var datetime = new Date() 122 | var images = "" 123 | 124 | //setting variables for mssql 125 | request.input("consignor_id", db.Int, consignor_id) 126 | request.input("title", db.VarChar, title) 127 | request.input("description", db.VarChar, description) 128 | request.input("product_type", db.VarChar, product_type) 129 | request.input("base_price", db.Numeric, base_price) 130 | request.input("size", db.Int, size) 131 | request.input("color", db.VarChar, color) 132 | request.input("material", db.VarChar, material) 133 | request.input("price", db.Numeric, price) 134 | request.input("notes", db.VarChar, notes) 135 | request.input("published_at", db.VarChar, published_at) 136 | request.input("discountSchedule", db.VarChar, discountSchedule) 137 | request.input("datetime", db.DateTime, datetime) 138 | request.input("shopify_id", db.VarChar, shopify_id) 139 | 140 | for (var i = 0; i < req.files.length; i++) { 141 | images += req.files[i].originalname + "," 142 | uploadFileToBlob("products", title, req.files[i]) 143 | } 144 | 145 | let query = 146 | "INSERT INTO products(consignorID, shopify_id, vendor, title, description, product_type, size, color, material, price, base_price, notes, published_at, discountSchedule, created_at, updated_at, main_img_src) VALUES (@consignor_id, @shopify_id, 'Tacoma Consignment', @title, @description, @product_type, @size, @color, @material, @price, @base_price, @notes, @published_at, @discountSchedule, @datetime, @datetime, @main_img_src)" 147 | 148 | request.input("main_img_src", db.VarChar, images) 149 | return new Promise((resolve, reject) => { 150 | request.query(query, function (err, rows) { 151 | if (err) { 152 | reject(error.message) 153 | } else { 154 | resolve({ code: 200 }) 155 | } 156 | }) 157 | }) 158 | } 159 | 160 | function updateProducts(req) { 161 | var request = new db.Request() 162 | const title = req.body.title 163 | const product_id = req.body.product_id 164 | var images = "" 165 | 166 | var datetime = new Date() 167 | 168 | const consignor_id = req.body.consignor_id 169 | const description = req.body.description 170 | const product_type = req.body.product_type 171 | const size = req.body.size 172 | const color = req.body.color 173 | const material = req.body.material 174 | const price = req.body.price 175 | const base_price = req.body.base_price 176 | const notes = req.body.notes 177 | const published_at = req.body.published_at 178 | const discountSchedule = req.body.discountSchedule 179 | const status = req.body.status 180 | 181 | const shopify_published_at = new Date(published_at) 182 | 183 | request.input("consignor_id", db.Int, consignor_id) 184 | request.input("title", db.VarChar, title) 185 | request.input("description", db.VarChar, description) 186 | request.input("product_type", db.VarChar, product_type) 187 | request.input("base_price", db.Numeric, base_price) 188 | request.input("size", db.Int, size) 189 | request.input("color", db.VarChar, color) 190 | request.input("material", db.VarChar, material) 191 | request.input("price", db.Numeric, price) 192 | request.input("notes", db.VarChar, notes) 193 | request.input("published_at", db.VarChar, published_at) 194 | request.input("discountSchedule", db.VarChar, discountSchedule) 195 | request.input("datetime", db.DateTime, datetime) 196 | request.input("status", db.VarChar, status) 197 | 198 | request.input("product_id", db.Int, product_id) 199 | return new Promise((resolve, reject) => { 200 | request.query( 201 | "SELECT main_img_src, title, shopify_id FROM products WHERE product_id=@product_id", 202 | function (err, data) { 203 | if (err) console.log(err) 204 | var old_images = data.recordset[0].main_img_src 205 | var old_title = data.recordset[0].title 206 | var shopify_id = data.recordset[0].shopify_id 207 | 208 | var updated_data = { 209 | product: { 210 | id: shopify_id, 211 | title: title, 212 | body_html: description, 213 | vendor: "Tacoma Consignment", 214 | product_type: product_type, 215 | published_at: shopify_published_at, 216 | }, 217 | } 218 | 219 | var image_array = old_images.split(",") 220 | const blobPath = "products/" + old_title + "/" 221 | for (let i = 0; i < image_array.length - 1; i++) { 222 | var imageBlob = blobPath + image_array[i] 223 | blobService.deleteBlob( 224 | process.env.AZURE_CONTAINER_NAME, 225 | imageBlob, 226 | function (error, response) { 227 | if (!error) { 228 | console.log("deleted!") 229 | } 230 | } 231 | ) 232 | } 233 | 234 | shopify.get( 235 | "/admin/products/" + shopify_id + ".json", 236 | function (error, shopify_data) { 237 | var temp_images = shopify_data.product.images 238 | var temp_variants = shopify_data.product.variants 239 | for (let i = 0; i < temp_images.length; i++) { 240 | shopify.delete( 241 | "/admin/products/" + 242 | shopify_id + 243 | "/images/" + 244 | temp_images[i].id + 245 | ".json", 246 | function (error, shopify_data) { 247 | console.log("deleted!") 248 | } 249 | ) 250 | } 251 | for (let i = 0; i < temp_variants.length; i++) { 252 | shopify.delete( 253 | "/admin/products/" + 254 | shopify_id + 255 | "/variants/" + 256 | temp_variants[i].id + 257 | ".json", 258 | function (error, shopify_data) { 259 | console.log("deleted!") 260 | } 261 | ) 262 | } 263 | 264 | for (var i = 0; i < req.files.length; i++) { 265 | images += req.files[i].originalname + "," 266 | var tempImage = { 267 | image: { 268 | position: i + 1, 269 | attachment: req.files[i].buffer.toString("base64"), 270 | width: 640, 271 | height: 480, 272 | filename: req.files[i].originalname, 273 | }, 274 | } 275 | shopify.post( 276 | "/admin/products/" + shopify_id + "/images.json", 277 | tempImage, 278 | function (error, shopify_data) { 279 | console.log(shopify_data) 280 | } 281 | ) 282 | uploadFileToBlob("products", title, req.files[i]) 283 | } 284 | 285 | var tempVariant = { 286 | variant: { 287 | Color: color, 288 | Size: size, 289 | }, 290 | } 291 | 292 | shopify.post( 293 | "admin/products/" + shopify_id + "/variants.json", 294 | tempVariant, 295 | function (error, shopify_data) { 296 | console.log(shopify_data) 297 | } 298 | ) 299 | 300 | request.input("main_img_src", db.VarChar, images) 301 | 302 | shopify.put( 303 | "/admin/products/" + shopify_id + ".json", 304 | updated_data, 305 | function (error, shopify_data) { 306 | request.query( 307 | "UPDATE products SET consignorID=@consignor_id, title=@title, description=@description, product_type=@product_type, \ 308 | size=@size, color=@color, material=@material, price=@price, notes=@notes, published_at=@published_at, discountSchedule=@discountSchedule, status=@status,\ 309 | updated_at=@datetime, main_img_src=@main_img_src, base_price=@base_price WHERE product_id=@product_id", 310 | function (err, rows) { 311 | if (err) console.log(err.message) 312 | // send records as a response 313 | resolve({ code: 200 }) 314 | } 315 | ) 316 | } 317 | ) 318 | } 319 | ) 320 | } 321 | ) 322 | }) 323 | } 324 | 325 | function deleteProduct(req) { 326 | var request = new db.Request() 327 | const product_id = req.query.product_id 328 | const title = req.query.title 329 | const blobPath = "products/" + title + "/" 330 | request.input("product_id", db.Int, product_id) 331 | return new Promise((resolve, reject) => { 332 | request.query( 333 | "SELECT main_img_src, shopify_id FROM products WHERE product_id=@product_id", 334 | function (err, data) { 335 | if (err) console.log(err) 336 | var images = data.recordset[0].main_img_src 337 | var shopify_id = data.recordset[0].shopify_id 338 | var image_array = images.split(",") 339 | for (let i = 0; i < image_array.length - 1; i++) { 340 | var imageBlob = blobPath + image_array[i] 341 | blobService.deleteBlob( 342 | process.env.AZURE_CONTAINER_NAME, 343 | imageBlob, 344 | function (error, response) { 345 | if (!error) { 346 | console.log("deleted!") 347 | } 348 | } 349 | ) 350 | } 351 | shopify.delete( 352 | "/admin/products/" + shopify_id + ".json", 353 | function (error, shopify_data, headers) { 354 | request.query( 355 | "DELETE FROM products WHERE product_id=@product_id", 356 | function (err, data) { 357 | if (err) reject(error.message) 358 | // send records as a response 359 | resolve({ code: 200 }) 360 | } 361 | ) 362 | } 363 | ) 364 | } 365 | ) 366 | }) 367 | } 368 | 369 | module.exports = productModel 370 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tconsignment-system-api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "nodemon server.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "azure-storage": "^2.10.4", 14 | "body-parser": "^1.19.0", 15 | "cors": "^2.8.5", 16 | "dotenv": "^10.0.0", 17 | "express": "^4.17.1", 18 | "express-jwt": "^6.0.0", 19 | "express-jwt-authz": "^2.4.1", 20 | "into-stream": "^3.1.0", 21 | "jwks-rsa": "^1.6.0", 22 | "mssql": "^7.2.1", 23 | "multer": "^1.4.3", 24 | "nodemon": "^2.0.12", 25 | "shopify-node-api": "^1.5.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /public/products/photo_2021-08-19_18-51-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/public/products/photo_2021-08-19_18-51-02.jpg -------------------------------------------------------------------------------- /public/products/photo_2021-08-19_18-51-12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/public/products/photo_2021-08-19_18-51-12.jpg -------------------------------------------------------------------------------- /routes/consignors.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | const checkAuth = require("../middleware/auth") 3 | const consignorService = require("../services/consignorService") 4 | 5 | router.get("/consignors", getAllConsignors) 6 | router.post("/consignor", addConsignor) 7 | router.put("/consignor", updateConsignor) 8 | router.get("/consignorbyid", getConsignorById) 9 | router.get("/consignor", getConsignorByVendor) 10 | router.delete("/consignor", deleteConsignor) 11 | 12 | function getAllConsignors(req, res) { 13 | consignorService 14 | .getAllConsignors() 15 | .then(result => { 16 | res.json(result) 17 | }) 18 | .catch(err => { 19 | res.json(err) 20 | }) 21 | } 22 | 23 | function addConsignor(req, res) { 24 | var data = req.body 25 | consignorService 26 | .addConsignor(data) 27 | .then(result => { 28 | res.json(result) 29 | }) 30 | .catch(err => { 31 | res.json(err) 32 | }) 33 | } 34 | 35 | function updateConsignor(req, res) { 36 | var data = req.body 37 | consignorService 38 | .updateConsignor(data) 39 | .then(result => { 40 | res.json(result) 41 | }) 42 | .catch(err => { 43 | res.json(err) 44 | }) 45 | } 46 | 47 | function getConsignorById(req, res) { 48 | const id = req.query.id 49 | consignorService 50 | .getConsignorById(id) 51 | .then(result => { 52 | res.json(result) 53 | }) 54 | .catch(err => { 55 | res.json(err) 56 | }) 57 | } 58 | 59 | function getConsignorByVendor(req, res) { 60 | const vendor = req.query.vendor 61 | consignorService 62 | .getConsignorByVendor(vendor) 63 | .then(result => { 64 | res.json(result) 65 | }) 66 | .catch(err => { 67 | res.json(err) 68 | }) 69 | } 70 | 71 | function deleteConsignor(req, res) { 72 | const id = req.query.id 73 | consignorService 74 | .delConsignor(id) 75 | .then(result => { 76 | res.json(result) 77 | }) 78 | .catch(err => { 79 | res.json(err) 80 | }) 81 | } 82 | 83 | module.exports = router 84 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | 3 | const products = require('./products') 4 | const consignors = require('./consignors') 5 | const orders = require('./orders') 6 | const payouts = require('./payouts') 7 | 8 | router.use(products) 9 | router.use(consignors) 10 | router.use(orders) 11 | router.use(payouts) 12 | 13 | router.get("/", (req, res) => { 14 | res.send(`Hi! Server is listening on port ${process.env.PORT}`) 15 | }) 16 | 17 | router.use(function (err, req, res, next) { 18 | if (err.name === "ValidationError") { 19 | return res.status(422).json({ 20 | errors: Object.keys(err.errors).reduce(function (errors, key) { 21 | errors[key] = err.errors[key].message 22 | 23 | return errors 24 | }, {}), 25 | }) 26 | } 27 | 28 | return next(err) 29 | }) 30 | 31 | module.exports = router -------------------------------------------------------------------------------- /routes/orders.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | const checkAuth = require("../middleware/auth") 3 | const orderService = require("../services/orderService") 4 | 5 | //webhook routes 6 | router.post("/order/create", createOrders) 7 | 8 | // router.post("/order/update", (req, res) => { 9 | // console.log(req.body) 10 | // }) 11 | 12 | // router.post("/order/delete", (req, res) => { 13 | // console.log(req.body) 14 | // }) 15 | 16 | // router.post("/order/cancel", (req, res) => { 17 | // console.log(req.body) 18 | // }) 19 | 20 | // router.post("/order/fulfillment", (req, res) => { 21 | // console.log(req.body) 22 | // }) 23 | 24 | // router.post("/order/payment", (req, res) => { 25 | // console.log(req.body) 26 | // }) 27 | 28 | // router.post("/order/create", createOrders) 29 | 30 | function createOrders(req, res) { 31 | orderService 32 | .createOrders(req) 33 | .then(result => { 34 | res.json(result) 35 | }) 36 | .catch(err => { 37 | res.json(err) 38 | }) 39 | } 40 | 41 | module.exports = router 42 | -------------------------------------------------------------------------------- /routes/payouts.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | const checkAuth = require("../middleware/auth") 3 | const checkPermissions = require("../middleware/permission") 4 | const payoutService = require("../services/payoutService") 5 | 6 | router.get("/payouts", checkAuth, checkPermissions, getPayouts) 7 | router.get("/payout_details", getPayoutDetailsByVendor) 8 | router.get("/payout", getPayoutByVendor) 9 | 10 | function getPayouts(req, res) { 11 | payoutService 12 | .getPayouts(req.query.flag) 13 | .then(result => { 14 | res.json(result) 15 | }) 16 | .catch(err => { 17 | res.json(err) 18 | }) 19 | } 20 | 21 | function getPayoutDetailsByVendor(req, res) { 22 | const vendor = req.query.vendor 23 | payoutService 24 | .getPayoutDetailsByVendor(vendor) 25 | .then(result => { 26 | res.json(result) 27 | }) 28 | .catch(err => { 29 | res.json(err) 30 | }) 31 | } 32 | 33 | function getPayoutByVendor(req, res) { 34 | const vendor = req.query.vendor 35 | payoutService 36 | .getPayoutByVendor(vendor) 37 | .then(result => { 38 | res.json(result) 39 | }) 40 | .catch(err => { 41 | res.json(err) 42 | }) 43 | } 44 | 45 | module.exports = router 46 | -------------------------------------------------------------------------------- /routes/products.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | const multer = require("multer") 3 | const checkAuth = require("../middleware/auth") 4 | 5 | const productService = require("../services/productService") 6 | 7 | const inMemoryStorage = multer.memoryStorage() 8 | const uploadStrategy = multer({ storage: inMemoryStorage }).array("files", 10) 9 | 10 | // router.get("/products", checkJwt, (req, res) => { 11 | // res.send(data) 12 | // }) 13 | 14 | router.get("/products", checkAuth, getAllProducts) 15 | router.get("/product", getProductById) 16 | router.get("/productsbyvendor", getProductsByVendor) 17 | router.post("/products", uploadStrategy, setProducts) 18 | router.put("/products", uploadStrategy, updateProducts) 19 | router.delete("/products", deleteProduct) 20 | 21 | //get all product info from mssql 22 | function getAllProducts(req, res) { 23 | productService 24 | .getAllProducts() 25 | .then(result => { 26 | res.json(result) 27 | }) 28 | .catch(err => { 29 | res.json(err) 30 | }) 31 | } 32 | 33 | //get product info by product_id from shopify and mssql 34 | function getProductById(req, res) { 35 | const product_id = req.query.product_id 36 | productService 37 | .getProductById(product_id) 38 | .then(result => { 39 | res.json(result) 40 | }) 41 | .catch(err => { 42 | res.json(err) 43 | }) 44 | } 45 | 46 | //get products info by vendor from shopify and mssql 47 | function getProductsByVendor(req, res) { 48 | const vendor = req.query.vendor 49 | productService 50 | .getProductsByVendor(vendor) 51 | .then(result => { 52 | res.json(result) 53 | }) 54 | .catch(err => { 55 | res.json(err) 56 | }) 57 | } 58 | 59 | //Adding product info to shopify and mssql 60 | function setProducts(req, res) { 61 | productService 62 | .setProducts(req) 63 | .then(result => { 64 | res.json(result) 65 | }) 66 | .catch(err => { 67 | res.json(err) 68 | }) 69 | } 70 | 71 | //updating product on shopify and mssql 72 | function updateProducts(req, res) { 73 | productService 74 | .updateProducts(req) 75 | .then(result => { 76 | res.json(result) 77 | }) 78 | .catch(err => { 79 | res.json(err) 80 | }) 81 | } 82 | 83 | //delete product from shopify and mssql 84 | function deleteProduct(req, res) { 85 | productService 86 | .deleteProduct(req) 87 | .then(result => { 88 | res.json(result) 89 | }) 90 | .catch(err => { 91 | res.json(err) 92 | }) 93 | } 94 | 95 | module.exports = router 96 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | // server/server/js 2 | const express = require("express") 3 | const bodyParser = require("body-parser") 4 | const cors = require("cors") 5 | const app = express() 6 | const sql = require("mssql") 7 | const dotenvConf = require("dotenv").config() 8 | 9 | app.use(bodyParser.json()) 10 | app.use(cors()) 11 | app.use(express.urlencoded({ extended: true })) 12 | 13 | app.use(require("./routes")) 14 | 15 | // config for your database 16 | const config = { 17 | user: process.env.DB_USER, 18 | password: process.env.DB_PASS, 19 | server: process.env.DB_HOST, 20 | database: process.env.DB_NAME, 21 | options: { 22 | trustedConnection: true, 23 | encrypt: true, 24 | enableArithAbort: true, 25 | trustServerCertificate: true, 26 | }, 27 | } 28 | 29 | 30 | //connect to mssql 31 | sql.connect(config) 32 | 33 | // listen on the port 34 | app.listen(process.env.PORT || 8000) 35 | -------------------------------------------------------------------------------- /server/.env: -------------------------------------------------------------------------------- 1 | # MSSQL config 2 | DB_HOST=tconsign21.database.windows.net 3 | DB_USER=tcadmin 4 | DB_PASS=Over 12,000 sq. ft. of finds! 5 | DB_NAME=tconsign 6 | PORT=8000 7 | 8 | # Auth0 config 9 | AUTH0_DOMAIN=eclectico.us.auth0.com 10 | AUTH0_AUDIENCE=https://tacomaconsignment.com 11 | 12 | # Azure blob config 13 | AZURE_ACCOUNT_NAME=cs410032000dc000ac4 14 | AZURE_ACCOUNT_KEY=Rk5OZVd7RIUSZjHt1yg/YGRVgnf+NzM33hyNWvC3SOJQgiPBktph+G9DBTN+jPQzP+3cCCdutyYg1cbKGoIUrw== 15 | AZURE_BLOB_URL=https://cs410032000dc000ac4.blob.core.windows.net 16 | AZURE_CONTAINER_NAME=testcontainer 17 | 18 | # Shopify config 19 | SHOPIFY_API_KEY=fa4f8443ab7b37f4803230a8aebbb7b2 20 | SHOPIFY_PASSWORD=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 21 | SHOPIFY_SHOP_NAME=spfy-connection-app-store.myshopify.com 22 | SHOPIFY_ACCESS_TOKEN=prtapi_66df9304cda675601c68025aeac9a208 -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | auth_config.json 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /server/database/config.js: -------------------------------------------------------------------------------- 1 | 2 | // config for your mssql 3 | const config = { 4 | user: process.env.DB_USER, 5 | password: process.env.DB_PASS, 6 | server: process.env.DB_HOST, 7 | database: process.env.DB_NAME, 8 | options: { 9 | trustedConnection: true, 10 | encrypt: true, 11 | enableArithAbort: true, 12 | trustServerCertificate: true, 13 | }, 14 | } 15 | 16 | module.exports = config -------------------------------------------------------------------------------- /server/database/db.js: -------------------------------------------------------------------------------- 1 | const sql = require("mssql") 2 | const databaseConfig = require('./config') 3 | 4 | sql.connect(databaseConfig) 5 | 6 | module.exports = sql 7 | -------------------------------------------------------------------------------- /server/middleware/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require("express-jwt") 2 | const jwksRsa = require("jwks-rsa") 3 | 4 | // Create middleware to validate the JWT using express-jwt 5 | const checkJwt = jwt({ 6 | // Provide a signing key based on the key identifier in the header and the signing keys provided by your Auth0 JWKS endpoint. 7 | secret: jwksRsa.expressJwtSecret({ 8 | cache: true, 9 | rateLimit: true, 10 | jwksRequestsPerMinute: 5, 11 | jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`, 12 | }), 13 | 14 | // Validate the audience (Identifier) and the issuer (Domain). 15 | audience: process.env.AUTH0_AUDIENCE, 16 | issuer: `https://${process.env.AUTH0_DOMAIN}/`, 17 | algorithms: ["RS256"], 18 | }) 19 | 20 | module.exports = checkJwt -------------------------------------------------------------------------------- /server/middleware/permission.js: -------------------------------------------------------------------------------- 1 | const jwtAuthz = require("express-jwt-authz") 2 | 3 | const checkPermissions = jwtAuthz(["manage:users"], { 4 | customScopeKey: "permissions", 5 | }) 6 | 7 | module.exports = checkPermissions -------------------------------------------------------------------------------- /server/models/consignor-model.js: -------------------------------------------------------------------------------- 1 | const db = require("../database/db") 2 | 3 | const consignorModel = { 4 | getAllConsignors: getAllConsignors, 5 | addConsignor: addConsignor, 6 | updateConsignor: updateConsignor, 7 | getConsignorById: getConsignorById, 8 | getConsignorByVendor: getConsignorByVendor, 9 | delConsignor: delConsignor, 10 | } 11 | 12 | function getAllConsignors() { 13 | return new Promise((resolve, reject) => { 14 | var request = new db.Request() 15 | let query = "SELECT * FROM consignors" 16 | 17 | request.query(query, (error, rows) => { 18 | if (error) { 19 | reject(error.message) 20 | } else { 21 | resolve(rows.recordset) 22 | } 23 | }) 24 | }) 25 | } 26 | 27 | function addConsignor(data) { 28 | var request = new db.Request() 29 | request.input("qbCompany", db.VarChar, data.company) 30 | request.input("defaultPercentage", db.Numeric, 50) 31 | request.input("qbFirst", db.VarChar, data.first) 32 | request.input("qbLast", db.VarChar, data.last) 33 | request.input("qbStAddress1", db.VarChar, data.stAddress1) 34 | request.input("qbStAddress2", db.VarChar, data.stAddress2) 35 | request.input("qbCity", db.VarChar, data.city) 36 | request.input("qbState", db.VarChar, data.state) 37 | request.input("qbZip", db.VarChar, data.zip) 38 | request.input("qbEmail", db.VarChar, data.email) 39 | request.input("qbPhone", db.VarChar, data.phone) 40 | let query = 41 | "INSERT INTO consignors(qbCompany, defaultPercentage, qbFirst, qbLast, qbStAddress1, qbStAddress2, qbCity, qbState, qbZip, qbEmail, qbPhone ) VALUES (@qbCompany, @defaultPercentage, @qbFirst, @qbLast, @qbStAddress1, @qbStAddress2, @qbCity, @qbState, @qbZip, @qbEmail, @qbPhone)" 42 | 43 | return new Promise((resolve, reject) => { 44 | request.query(query, (error, rows) => { 45 | if (error) { 46 | reject(error.message) 47 | } else { 48 | resolve({ code: 200 }) 49 | } 50 | }) 51 | }) 52 | } 53 | 54 | function updateConsignor(data) { 55 | var request = new db.Request() 56 | request.input("id", db.VarChar, data.id) 57 | request.input("qbCompany", db.VarChar, data.company) 58 | request.input("qbFirst", db.VarChar, data.first) 59 | request.input("qbLast", db.VarChar, data.last) 60 | request.input("qbStAddress1", db.VarChar, data.stAddress1) 61 | request.input("qbStAddress2", db.VarChar, data.stAddress2) 62 | request.input("qbCity", db.VarChar, data.city) 63 | request.input("qbState", db.VarChar, data.state) 64 | request.input("qbZip", db.VarChar, data.zip) 65 | request.input("qbEmail", db.VarChar, data.email) 66 | request.input("qbPhone", db.VarChar, data.phone) 67 | let query = 68 | "UPDATE consignors SET qbCompany=@qbCompany, qbFirst=@qbFirst, qbLast=@qbLast, qbStAddress1=@qbStAddress1, qbStAddress2=@qbStAddress2, qbCity=@qbCity, qbState=@qbState, qbZip=@qbZip, qbEmail=@qbEmail, qbPhone=@qbPhone WHERE id=@id" 69 | 70 | return new Promise((resolve, reject) => { 71 | request.query(query, (error, rows) => { 72 | if (error) { 73 | reject(error.message) 74 | } else { 75 | resolve({ code: 200 }) 76 | } 77 | }) 78 | }) 79 | } 80 | 81 | function delConsignor(id) { 82 | return new Promise((resolve, reject) => { 83 | var request = new db.Request() 84 | request.input("id", db.Int, id) 85 | let query = "DELETE FROM consignors WHERE id=@id" 86 | 87 | request.query(query, (error, rows) => { 88 | if (error) { 89 | reject(error.message) 90 | } else { 91 | resolve(rows.recordset) 92 | } 93 | }) 94 | }) 95 | } 96 | 97 | function getConsignorById(id) { 98 | return new Promise((resolve, reject) => { 99 | var request = new db.Request() 100 | request.input("id", db.Int, id) 101 | let query = 102 | "SELECT * FROM consignors WHERE id=@id" 103 | 104 | request.query(query, (error, rows) => { 105 | if (error) { 106 | reject(error.message) 107 | } else { 108 | resolve(rows.recordset) 109 | } 110 | }) 111 | }) 112 | } 113 | 114 | function getConsignorByVendor(vendor) { 115 | return new Promise((resolve, reject) => { 116 | var request = new db.Request() 117 | request.input("vendor", db.VarChar, vendor) 118 | let query = 119 | "SELECT id, qbCompany, defaultPercentage, qbStAddress1, qbStAddress2, (qbCity + ', ' + qbState + ' ' + qbZip) as bottom_line FROM consignors WHERE qbCompany=@vendor" 120 | 121 | request.query(query, (error, rows) => { 122 | if (error) { 123 | reject(error.message) 124 | } else { 125 | resolve(rows.recordset) 126 | } 127 | }) 128 | }) 129 | } 130 | 131 | module.exports = consignorModel 132 | -------------------------------------------------------------------------------- /server/models/payout-model.js: -------------------------------------------------------------------------------- 1 | const db = require("../database/db") 2 | 3 | const payoutModel = { 4 | getPayouts: getPayouts, 5 | getPayoutDetailsByVendor: getPayoutDetailsByVendor, 6 | getPayoutByVendor: getPayoutByVendor, 7 | } 8 | 9 | function getPayouts(flag) { 10 | return new Promise((resolve, reject) => { 11 | var request = new db.Request() 12 | 13 | var date = new Date() 14 | var year = date.getFullYear() 15 | var month = "" 16 | 17 | //get first and last date 18 | if (flag == "BeforePayouts") { 19 | month = date.getMonth() 20 | } else { 21 | month = date.getMonth() + 1 22 | } 23 | 24 | const firstDate = new Date(year, month - 2, 0) 25 | const lastDate = new Date(year, month - 1, 1) 26 | 27 | request.input("firstDate", db.DateTime, firstDate) 28 | request.input("lastDate", db.DateTime, lastDate) 29 | 30 | let query = 31 | "SELECT distinct(spfy_vendor), sum(spfy_line_item_qty) as items_sold, \ 32 | format((sum(spfy_line_item_qty * spfy_line_item_price)), 'C') as total_sales, defaultPercentage, \ 33 | format(sum(spfy_line_item_qty * spfy_line_item_price * defaultPercentage/100), 'C') as net_sales from tstSpfyOrderItems items \ 34 | inner join consignors csn on csn.qbCompany = items.spfy_vendor \ 35 | where spfy_created_at > @firstDate and spfy_created_at < @lastDate \ 36 | group by spfy_vendor, defaultPercentage \ 37 | order by total_sales desc" 38 | 39 | request.query(query, (error, rows) => { 40 | if (error) { 41 | reject(error.message) 42 | } else { 43 | resolve(rows.recordset) 44 | } 45 | }) 46 | }) 47 | } 48 | 49 | function getPayoutDetailsByVendor(vendor) { 50 | return new Promise((resolve, reject) => { 51 | var request = new db.Request() 52 | 53 | //get first and last date 54 | var date = new Date() 55 | var month = date.getMonth() + 1 56 | var year = date.getFullYear() 57 | const firstDate = new Date(year, month - 2, 0) 58 | const lastDate = new Date(year, month - 1, 1) 59 | 60 | request.input("firstDate", db.DateTime, firstDate) 61 | request.input("lastDate", db.DateTime, lastDate) 62 | request.input("vendor", db.VarChar, vendor) 63 | 64 | let query = 65 | "SELECT spfy_order_id, spfy_line_item_name, spfy_line_item_qty, spfy_line_item_price, spfy_line_item_qty * spfy_line_item_price as total_amount, defaultPercentage, \ 66 | format((defaultPercentage / 100 * spfy_line_item_qty * spfy_line_item_price), 'C') as net_amount from tstSpfyOrderItems items \ 67 | inner join consignors csn on csn.qbCompany = items.spfy_vendor where spfy_vendor=@vendor and spfy_created_at > @firstDate and spfy_created_at < @lastDate \ 68 | group by spfy_order_id, spfy_vendor, spfy_line_item_name, defaultPercentage, spfy_line_item_price, spfy_line_item_qty \ 69 | order by total_amount desc" 70 | 71 | request.query(query, (error, rows) => { 72 | if (error) { 73 | reject(error.message) 74 | } else { 75 | resolve(rows.recordset) 76 | } 77 | }) 78 | }) 79 | } 80 | 81 | function getPayoutByVendor(vendor) { 82 | return new Promise((resolve, reject) => { 83 | var request = new db.Request() 84 | 85 | //get first and last date 86 | var date = new Date() 87 | var month = date.getMonth() + 1 88 | var year = date.getFullYear() 89 | const firstDate = new Date(year, month - 2, 0) 90 | const lastDate = new Date(year, month - 1, 1) 91 | 92 | request.input("firstDate", db.DateTime, firstDate) 93 | request.input("lastDate", db.DateTime, lastDate) 94 | request.input("vendor", db.VarChar, vendor) 95 | 96 | let query = 97 | "SELECT distinct(spfy_vendor), sum(spfy_line_item_qty) as items_sold, \ 98 | format(sum(spfy_line_item_qty * spfy_line_item_price), 'C') as total_sales, \ 99 | defaultPercentage, sum(spfy_line_item_qty * spfy_line_item_price * defaultPercentage/100) as net_sales from tstSpfyOrderItems items \ 100 | inner join consignors csn on csn.qbCompany = items.spfy_vendor where spfy_created_at > @firstDate and spfy_created_at < @lastDate and spfy_vendor=@vendor \ 101 | group by spfy_vendor, defaultPercentage \ 102 | order by total_sales desc" 103 | 104 | request.query(query, (error, rows) => { 105 | if (error) { 106 | reject(error.message) 107 | } else { 108 | resolve(rows.recordset) 109 | } 110 | }) 111 | }) 112 | } 113 | 114 | module.exports = payoutModel 115 | -------------------------------------------------------------------------------- /server/models/product-model.js: -------------------------------------------------------------------------------- 1 | const db = require("../database/db") 2 | const shopify = require("../services/shopify") 3 | const azureStorage = require("azure-storage") 4 | const getStream = require("into-stream") 5 | 6 | const blobService = azureStorage.createBlobService( 7 | process.env.AZURE_ACCOUNT_NAME, 8 | process.env.AZURE_ACCOUNT_KEY 9 | ) 10 | 11 | uploadFileToBlob = async (directoryPath, title, file) => { 12 | return new Promise((resolve, reject) => { 13 | const blobName = file.originalname 14 | const stream = getStream(file.buffer) 15 | const streamLength = file.buffer.length 16 | 17 | blobService.createBlockBlobFromStream( 18 | process.env.AZURE_CONTAINER_NAME, 19 | `${directoryPath}/${title}/${blobName}`, 20 | stream, 21 | streamLength, 22 | err => { 23 | if (err) { 24 | reject(err) 25 | } else { 26 | resolve({ 27 | filename: blobName, 28 | originalname: file.originalname, 29 | size: streamLength, 30 | path: `${process.env.AZURE_CONTAINER_NAME}/${directoryPath}/${title}/${blobName}`, 31 | url: `${process.env.AZURE_BLOB_URL}${process.env.AZURE_CONTAINER_NAME}/${directoryPath}/${title}/${blobName}`, 32 | }) 33 | } 34 | } 35 | ) 36 | }) 37 | } 38 | 39 | const productModel = { 40 | getAllProducts: getAllProducts, 41 | getProductById: getProductById, 42 | getProductsByVendor: getProductsByVendor, 43 | setProducts: setProducts, 44 | updateProducts: updateProducts, 45 | deleteProduct: deleteProduct, 46 | } 47 | 48 | function getAllProducts() { 49 | return new Promise((resolve, reject) => { 50 | var request = new db.Request() 51 | let query = "SELECT * FROM products" 52 | 53 | request.query(query, (error, rows) => { 54 | if (error) { 55 | reject(error.message) 56 | } else { 57 | resolve(rows.recordset) 58 | } 59 | }) 60 | }) 61 | } 62 | 63 | function getProductById(id) { 64 | const product_id = id 65 | return new Promise((resolve, reject) => { 66 | var request = new db.Request() 67 | request.input("product_id", db.Int, product_id) 68 | let query = "SELECT * FROM products WHERE product_id=@product_id" 69 | 70 | request.query(query, (error, rows) => { 71 | var shopify_id = "" 72 | if (error) { 73 | reject(error.message) 74 | } else { 75 | shopify_id = rows.recordset[0].shopify_id 76 | shopify.get( 77 | "/admin/products/" + shopify_id + ".json", 78 | function (err, product_data, headers) { 79 | var product = product_data.product 80 | // send records as a response 81 | resolve({ data: rows.recordset[0], shopifyData: product }) 82 | } 83 | ) 84 | } 85 | }) 86 | }) 87 | } 88 | 89 | function getProductsByVendor(vendor) { 90 | return new Promise((resolve, reject) => { 91 | var request = new db.Request() 92 | request.input("vendor", db.VarChar, vendor) 93 | let query = "SELECT * FROM products WHERE vendor=@vendor" 94 | 95 | request.query(query, (error, rows) => { 96 | if (error) { 97 | reject(error.message) 98 | } else { 99 | resolve({ data: rows.recordset }) 100 | } 101 | }) 102 | }) 103 | } 104 | 105 | function setProducts(req, shopify_id) { 106 | //Assign value to variable of product from request 107 | const title = req.body.title 108 | const consignor_id = req.body.consignor_id 109 | const description = req.body.description 110 | const product_type = req.body.product_type 111 | const size = req.body.size 112 | const color = req.body.color 113 | const material = req.body.material 114 | const price = req.body.price 115 | const base_price = req.body.base_price 116 | const notes = req.body.notes 117 | const published_at = req.body.published_at 118 | const discountSchedule = req.body.discountSchedule 119 | 120 | var request = new db.Request() 121 | var datetime = new Date() 122 | var images = "" 123 | 124 | //setting variables for mssql 125 | request.input("consignor_id", db.Int, consignor_id) 126 | request.input("title", db.VarChar, title) 127 | request.input("description", db.VarChar, description) 128 | request.input("product_type", db.VarChar, product_type) 129 | request.input("base_price", db.Numeric, base_price) 130 | request.input("size", db.Int, size) 131 | request.input("color", db.VarChar, color) 132 | request.input("material", db.VarChar, material) 133 | request.input("price", db.Numeric, price) 134 | request.input("notes", db.VarChar, notes) 135 | request.input("published_at", db.VarChar, published_at) 136 | request.input("discountSchedule", db.VarChar, discountSchedule) 137 | request.input("datetime", db.DateTime, datetime) 138 | request.input("shopify_id", db.VarChar, shopify_id) 139 | 140 | for (var i = 0; i < req.files.length; i++) { 141 | images += req.files[i].originalname + "," 142 | uploadFileToBlob("products", title, req.files[i]) 143 | } 144 | 145 | let query = 146 | "INSERT INTO products(consignorID, shopify_id, vendor, title, description, product_type, size, color, material, price, base_price, notes, published_at, discountSchedule, created_at, updated_at, main_img_src) VALUES (@consignor_id, @shopify_id, 'Tacoma Consignment', @title, @description, @product_type, @size, @color, @material, @price, @base_price, @notes, @published_at, @discountSchedule, @datetime, @datetime, @main_img_src)" 147 | 148 | request.input("main_img_src", db.VarChar, images) 149 | return new Promise((resolve, reject) => { 150 | request.query(query, function (err, rows) { 151 | if (err) { 152 | reject(error.message) 153 | } else { 154 | resolve({ code: 200 }) 155 | } 156 | }) 157 | }) 158 | } 159 | 160 | function updateProducts(req) { 161 | var request = new db.Request() 162 | const title = req.body.title 163 | const product_id = req.body.product_id 164 | var images = "" 165 | 166 | var datetime = new Date() 167 | 168 | const consignor_id = req.body.consignor_id 169 | const description = req.body.description 170 | const product_type = req.body.product_type 171 | const size = req.body.size 172 | const color = req.body.color 173 | const material = req.body.material 174 | const price = req.body.price 175 | const base_price = req.body.base_price 176 | const notes = req.body.notes 177 | const published_at = req.body.published_at 178 | const discountSchedule = req.body.discountSchedule 179 | const status = req.body.status 180 | 181 | const shopify_published_at = new Date(published_at) 182 | 183 | request.input("consignor_id", db.Int, consignor_id) 184 | request.input("title", db.VarChar, title) 185 | request.input("description", db.VarChar, description) 186 | request.input("product_type", db.VarChar, product_type) 187 | request.input("base_price", db.Numeric, base_price) 188 | request.input("size", db.Int, size) 189 | request.input("color", db.VarChar, color) 190 | request.input("material", db.VarChar, material) 191 | request.input("price", db.Numeric, price) 192 | request.input("notes", db.VarChar, notes) 193 | request.input("published_at", db.VarChar, published_at) 194 | request.input("discountSchedule", db.VarChar, discountSchedule) 195 | request.input("datetime", db.DateTime, datetime) 196 | request.input("status", db.VarChar, status) 197 | 198 | request.input("product_id", db.Int, product_id) 199 | return new Promise((resolve, reject) => { 200 | request.query( 201 | "SELECT main_img_src, title, shopify_id FROM products WHERE product_id=@product_id", 202 | function (err, data) { 203 | if (err) console.log(err) 204 | var old_images = data.recordset[0].main_img_src 205 | var old_title = data.recordset[0].title 206 | var shopify_id = data.recordset[0].shopify_id 207 | 208 | var updated_data = { 209 | product: { 210 | id: shopify_id, 211 | title: title, 212 | body_html: description, 213 | vendor: "Tacoma Consignment", 214 | product_type: product_type, 215 | published_at: shopify_published_at, 216 | }, 217 | } 218 | 219 | var image_array = old_images.split(",") 220 | const blobPath = "products/" + old_title + "/" 221 | for (let i = 0; i < image_array.length - 1; i++) { 222 | var imageBlob = blobPath + image_array[i] 223 | blobService.deleteBlob( 224 | process.env.AZURE_CONTAINER_NAME, 225 | imageBlob, 226 | function (error, response) { 227 | if (!error) { 228 | console.log("deleted!") 229 | } 230 | } 231 | ) 232 | } 233 | 234 | shopify.get( 235 | "/admin/products/" + shopify_id + ".json", 236 | function (error, shopify_data) { 237 | var temp_images = shopify_data.product.images 238 | var temp_variants = shopify_data.product.variants 239 | for (let i = 0; i < temp_images.length; i++) { 240 | shopify.delete( 241 | "/admin/products/" + 242 | shopify_id + 243 | "/images/" + 244 | temp_images[i].id + 245 | ".json", 246 | function (error, shopify_data) { 247 | console.log("deleted!") 248 | } 249 | ) 250 | } 251 | for (let i = 0; i < temp_variants.length; i++) { 252 | shopify.delete( 253 | "/admin/products/" + 254 | shopify_id + 255 | "/variants/" + 256 | temp_variants[i].id + 257 | ".json", 258 | function (error, shopify_data) { 259 | console.log("deleted!") 260 | } 261 | ) 262 | } 263 | 264 | for (var i = 0; i < req.files.length; i++) { 265 | images += req.files[i].originalname + "," 266 | var tempImage = { 267 | image: { 268 | position: i + 1, 269 | attachment: req.files[i].buffer.toString("base64"), 270 | width: 640, 271 | height: 480, 272 | filename: req.files[i].originalname, 273 | }, 274 | } 275 | shopify.post( 276 | "/admin/products/" + shopify_id + "/images.json", 277 | tempImage, 278 | function (error, shopify_data) { 279 | console.log(shopify_data) 280 | } 281 | ) 282 | uploadFileToBlob("products", title, req.files[i]) 283 | } 284 | 285 | var tempVariant = { 286 | variant: { 287 | Color: color, 288 | Size: size, 289 | }, 290 | } 291 | 292 | shopify.post( 293 | "admin/products/" + shopify_id + "/variants.json", 294 | tempVariant, 295 | function (error, shopify_data) { 296 | console.log(shopify_data) 297 | } 298 | ) 299 | 300 | request.input("main_img_src", db.VarChar, images) 301 | 302 | shopify.put( 303 | "/admin/products/" + shopify_id + ".json", 304 | updated_data, 305 | function (error, shopify_data) { 306 | request.query( 307 | "UPDATE products SET consignorID=@consignor_id, title=@title, description=@description, product_type=@product_type, \ 308 | size=@size, color=@color, material=@material, price=@price, notes=@notes, published_at=@published_at, discountSchedule=@discountSchedule, status=@status,\ 309 | updated_at=@datetime, main_img_src=@main_img_src, base_price=@base_price WHERE product_id=@product_id", 310 | function (err, rows) { 311 | if (err) console.log(err.message) 312 | // send records as a response 313 | resolve({ code: 200 }) 314 | } 315 | ) 316 | } 317 | ) 318 | } 319 | ) 320 | } 321 | ) 322 | }) 323 | } 324 | 325 | function deleteProduct(req) { 326 | var request = new db.Request() 327 | const product_id = req.query.product_id 328 | const title = req.query.title 329 | const blobPath = "products/" + title + "/" 330 | request.input("product_id", db.Int, product_id) 331 | return new Promise((resolve, reject) => { 332 | request.query( 333 | "SELECT main_img_src, shopify_id FROM products WHERE product_id=@product_id", 334 | function (err, data) { 335 | if (err) console.log(err) 336 | var images = data.recordset[0].main_img_src 337 | var shopify_id = data.recordset[0].shopify_id 338 | var image_array = images.split(",") 339 | for (let i = 0; i < image_array.length - 1; i++) { 340 | var imageBlob = blobPath + image_array[i] 341 | blobService.deleteBlob( 342 | process.env.AZURE_CONTAINER_NAME, 343 | imageBlob, 344 | function (error, response) { 345 | if (!error) { 346 | console.log("deleted!") 347 | } 348 | } 349 | ) 350 | } 351 | shopify.delete( 352 | "/admin/products/" + shopify_id + ".json", 353 | function (error, shopify_data, headers) { 354 | request.query( 355 | "DELETE FROM products WHERE product_id=@product_id", 356 | function (err, data) { 357 | if (err) reject(error.message) 358 | // send records as a response 359 | resolve({ code: 200 }) 360 | } 361 | ) 362 | } 363 | ) 364 | } 365 | ) 366 | }) 367 | } 368 | 369 | module.exports = productModel 370 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tconsignment-system-api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "nodemon server.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "azure-storage": "^2.10.4", 14 | "body-parser": "^1.19.0", 15 | "cors": "^2.8.5", 16 | "dotenv": "^10.0.0", 17 | "express": "^4.17.1", 18 | "express-jwt": "^6.0.0", 19 | "express-jwt-authz": "^2.4.1", 20 | "into-stream": "^3.1.0", 21 | "jwks-rsa": "^1.6.0", 22 | "mssql": "^7.2.1", 23 | "multer": "^1.4.3", 24 | "nodemon": "^2.0.12", 25 | "shopify-node-api": "^1.5.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /server/public/products/photo_2021-08-19_18-51-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/server/public/products/photo_2021-08-19_18-51-02.jpg -------------------------------------------------------------------------------- /server/public/products/photo_2021-08-19_18-51-12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/server/public/products/photo_2021-08-19_18-51-12.jpg -------------------------------------------------------------------------------- /server/routes/consignors.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | const checkAuth = require("../middleware/auth") 3 | const consignorService = require("../services/consignorService") 4 | 5 | router.get("/consignors", getAllConsignors) 6 | router.post("/consignor", addConsignor) 7 | router.put("/consignor", updateConsignor) 8 | router.get("/consignorbyid", getConsignorById) 9 | router.get("/consignor", getConsignorByVendor) 10 | router.delete("/consignor", deleteConsignor) 11 | 12 | function getAllConsignors(req, res) { 13 | consignorService 14 | .getAllConsignors() 15 | .then(result => { 16 | res.json(result) 17 | }) 18 | .catch(err => { 19 | res.json(err) 20 | }) 21 | } 22 | 23 | function addConsignor(req, res) { 24 | var data = req.body 25 | consignorService 26 | .addConsignor(data) 27 | .then(result => { 28 | res.json(result) 29 | }) 30 | .catch(err => { 31 | res.json(err) 32 | }) 33 | } 34 | 35 | function updateConsignor(req, res) { 36 | var data = req.body 37 | consignorService 38 | .updateConsignor(data) 39 | .then(result => { 40 | res.json(result) 41 | }) 42 | .catch(err => { 43 | res.json(err) 44 | }) 45 | } 46 | 47 | function getConsignorById(req, res) { 48 | const id = req.query.id 49 | consignorService 50 | .getConsignorById(id) 51 | .then(result => { 52 | res.json(result) 53 | }) 54 | .catch(err => { 55 | res.json(err) 56 | }) 57 | } 58 | 59 | function getConsignorByVendor(req, res) { 60 | const vendor = req.query.vendor 61 | consignorService 62 | .getConsignorByVendor(vendor) 63 | .then(result => { 64 | res.json(result) 65 | }) 66 | .catch(err => { 67 | res.json(err) 68 | }) 69 | } 70 | 71 | function deleteConsignor(req, res) { 72 | const id = req.query.id 73 | consignorService 74 | .delConsignor(id) 75 | .then(result => { 76 | res.json(result) 77 | }) 78 | .catch(err => { 79 | res.json(err) 80 | }) 81 | } 82 | 83 | module.exports = router 84 | -------------------------------------------------------------------------------- /server/routes/index.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | 3 | const products = require('./products') 4 | const consignors = require('./consignors') 5 | const orders = require('./orders') 6 | const payouts = require('./payouts') 7 | 8 | router.use(products) 9 | router.use(consignors) 10 | router.use(orders) 11 | router.use(payouts) 12 | 13 | router.get("/", (req, res) => { 14 | res.send(`Hi! Server is listening on port ${process.env.PORT}`) 15 | }) 16 | 17 | router.use(function (err, req, res, next) { 18 | if (err.name === "ValidationError") { 19 | return res.status(422).json({ 20 | errors: Object.keys(err.errors).reduce(function (errors, key) { 21 | errors[key] = err.errors[key].message 22 | 23 | return errors 24 | }, {}), 25 | }) 26 | } 27 | 28 | return next(err) 29 | }) 30 | 31 | module.exports = router -------------------------------------------------------------------------------- /server/routes/orders.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | const checkAuth = require("../middleware/auth") 3 | const orderService = require("../services/orderService") 4 | 5 | //webhook routes 6 | router.post("/order/create", createOrders) 7 | 8 | // router.post("/order/update", (req, res) => { 9 | // console.log(req.body) 10 | // }) 11 | 12 | // router.post("/order/delete", (req, res) => { 13 | // console.log(req.body) 14 | // }) 15 | 16 | // router.post("/order/cancel", (req, res) => { 17 | // console.log(req.body) 18 | // }) 19 | 20 | // router.post("/order/fulfillment", (req, res) => { 21 | // console.log(req.body) 22 | // }) 23 | 24 | // router.post("/order/payment", (req, res) => { 25 | // console.log(req.body) 26 | // }) 27 | 28 | // router.post("/order/create", createOrders) 29 | 30 | function createOrders(req, res) { 31 | orderService 32 | .createOrders(req) 33 | .then(result => { 34 | res.json(result) 35 | }) 36 | .catch(err => { 37 | res.json(err) 38 | }) 39 | } 40 | 41 | module.exports = router 42 | -------------------------------------------------------------------------------- /server/routes/payouts.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | const checkAuth = require("../middleware/auth") 3 | const checkPermissions = require("../middleware/permission") 4 | const payoutService = require("../services/payoutService") 5 | 6 | router.get("/payouts", checkAuth, checkPermissions, getPayouts) 7 | router.get("/payout_details", getPayoutDetailsByVendor) 8 | router.get("/payout", getPayoutByVendor) 9 | 10 | function getPayouts(req, res) { 11 | payoutService 12 | .getPayouts(req.query.flag) 13 | .then(result => { 14 | res.json(result) 15 | }) 16 | .catch(err => { 17 | res.json(err) 18 | }) 19 | } 20 | 21 | function getPayoutDetailsByVendor(req, res) { 22 | const vendor = req.query.vendor 23 | payoutService 24 | .getPayoutDetailsByVendor(vendor) 25 | .then(result => { 26 | res.json(result) 27 | }) 28 | .catch(err => { 29 | res.json(err) 30 | }) 31 | } 32 | 33 | function getPayoutByVendor(req, res) { 34 | const vendor = req.query.vendor 35 | payoutService 36 | .getPayoutByVendor(vendor) 37 | .then(result => { 38 | res.json(result) 39 | }) 40 | .catch(err => { 41 | res.json(err) 42 | }) 43 | } 44 | 45 | module.exports = router 46 | -------------------------------------------------------------------------------- /server/routes/products.js: -------------------------------------------------------------------------------- 1 | var router = require("express").Router() 2 | const multer = require("multer") 3 | const checkAuth = require("../middleware/auth") 4 | 5 | const productService = require("../services/productService") 6 | 7 | const inMemoryStorage = multer.memoryStorage() 8 | const uploadStrategy = multer({ storage: inMemoryStorage }).array("files", 10) 9 | 10 | // router.get("/products", checkJwt, (req, res) => { 11 | // res.send(data) 12 | // }) 13 | 14 | router.get("/products", checkAuth, getAllProducts) 15 | router.get("/product", getProductById) 16 | router.get("/productsbyvendor", getProductsByVendor) 17 | router.post("/products", uploadStrategy, setProducts) 18 | router.put("/products", uploadStrategy, updateProducts) 19 | router.delete("/products", deleteProduct) 20 | 21 | //get all product info from mssql 22 | function getAllProducts(req, res) { 23 | productService 24 | .getAllProducts() 25 | .then(result => { 26 | res.json(result) 27 | }) 28 | .catch(err => { 29 | res.json(err) 30 | }) 31 | } 32 | 33 | //get product info by product_id from shopify and mssql 34 | function getProductById(req, res) { 35 | const product_id = req.query.product_id 36 | productService 37 | .getProductById(product_id) 38 | .then(result => { 39 | res.json(result) 40 | }) 41 | .catch(err => { 42 | res.json(err) 43 | }) 44 | } 45 | 46 | //get products info by vendor from shopify and mssql 47 | function getProductsByVendor(req, res) { 48 | const vendor = req.query.vendor 49 | productService 50 | .getProductsByVendor(vendor) 51 | .then(result => { 52 | res.json(result) 53 | }) 54 | .catch(err => { 55 | res.json(err) 56 | }) 57 | } 58 | 59 | //Adding product info to shopify and mssql 60 | function setProducts(req, res) { 61 | productService 62 | .setProducts(req) 63 | .then(result => { 64 | res.json(result) 65 | }) 66 | .catch(err => { 67 | res.json(err) 68 | }) 69 | } 70 | 71 | //updating product on shopify and mssql 72 | function updateProducts(req, res) { 73 | productService 74 | .updateProducts(req) 75 | .then(result => { 76 | res.json(result) 77 | }) 78 | .catch(err => { 79 | res.json(err) 80 | }) 81 | } 82 | 83 | //delete product from shopify and mssql 84 | function deleteProduct(req, res) { 85 | productService 86 | .deleteProduct(req) 87 | .then(result => { 88 | res.json(result) 89 | }) 90 | .catch(err => { 91 | res.json(err) 92 | }) 93 | } 94 | 95 | module.exports = router 96 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | // server/server/js 2 | const express = require("express") 3 | const bodyParser = require("body-parser") 4 | const cors = require("cors") 5 | const app = express() 6 | const sql = require("mssql") 7 | const dotenvConf = require("dotenv").config() 8 | 9 | app.use(bodyParser.json()) 10 | app.use(cors()) 11 | app.use(express.urlencoded({ extended: true })) 12 | 13 | app.use(require("./routes")) 14 | 15 | // config for your database 16 | const config = { 17 | user: process.env.DB_USER, 18 | password: process.env.DB_PASS, 19 | server: process.env.DB_HOST, 20 | database: process.env.DB_NAME, 21 | options: { 22 | trustedConnection: true, 23 | encrypt: true, 24 | enableArithAbort: true, 25 | trustServerCertificate: true, 26 | }, 27 | } 28 | 29 | 30 | //connect to mssql 31 | sql.connect(config) 32 | 33 | // listen on the port 34 | app.listen(process.env.PORT || 8000) 35 | -------------------------------------------------------------------------------- /server/services/consignorService.js: -------------------------------------------------------------------------------- 1 | const consignorModel = require("../models/consignor-model") 2 | 3 | const consignorService = { 4 | getAllConsignors: getAllConsignors, 5 | addConsignor: addConsignor, 6 | updateConsignor: updateConsignor, 7 | getConsignorById: getConsignorById, 8 | getConsignorByVendor: getConsignorByVendor, 9 | delConsignor: delConsignor, 10 | } 11 | 12 | function getAllConsignors() { 13 | return new Promise((resolve, reject) => { 14 | consignorModel 15 | .getAllConsignors() 16 | .then(data => { 17 | resolve({ code: 200, data }) 18 | }) 19 | .catch(err => { 20 | reject(err.message) 21 | }) 22 | }) 23 | } 24 | 25 | function addConsignor(consignor_data) { 26 | return new Promise((resolve, reject) => { 27 | consignorModel 28 | .addConsignor(consignor_data) 29 | .then(data => { 30 | resolve({ code: 200 }) 31 | }) 32 | .catch(err => { 33 | reject(err.message) 34 | }) 35 | }) 36 | } 37 | 38 | function updateConsignor(consignor_data) { 39 | return new Promise((resolve, reject) => { 40 | consignorModel 41 | .updateConsignor(consignor_data) 42 | .then(data => { 43 | resolve({ code: 200 }) 44 | }) 45 | .catch(err => { 46 | reject(err.message) 47 | }) 48 | }) 49 | } 50 | 51 | function getConsignorById(id) { 52 | return new Promise((resolve, reject) => { 53 | consignorModel 54 | .getConsignorById(id) 55 | .then(data => { 56 | resolve({ code: 200, data }) 57 | }) 58 | .catch(err => { 59 | reject(err.message) 60 | }) 61 | }) 62 | } 63 | 64 | function getConsignorByVendor(vendor) { 65 | return new Promise((resolve, reject) => { 66 | consignorModel 67 | .getConsignorByVendor(vendor) 68 | .then(data => { 69 | resolve({ code: 200, data }) 70 | }) 71 | .catch(err => { 72 | reject(err.message) 73 | }) 74 | }) 75 | } 76 | 77 | function delConsignor(id) { 78 | return new Promise((resolve, reject) => { 79 | consignorModel 80 | .delConsignor(id) 81 | .then(data => { 82 | resolve({ code: 200, data }) 83 | }) 84 | .catch(err => { 85 | reject(err.message) 86 | }) 87 | }) 88 | } 89 | 90 | module.exports = consignorService 91 | -------------------------------------------------------------------------------- /server/services/orderService.js: -------------------------------------------------------------------------------- 1 | const orderModel = require("../models/order-model") 2 | const shopify = require("./shopify") 3 | 4 | const orderService = { 5 | createOrders: createOrders, 6 | } 7 | 8 | function createOrders(req) { 9 | return new Promise((resolve, reject) => { 10 | var order_id = req.body.name 11 | var created_at = req.body.created_at 12 | var qty = 0 13 | var name = "" 14 | var price = 0 15 | var compare_at_price = "" 16 | var sku = "" 17 | var shipping = "" 18 | var taxable = "" 19 | var fulfillment_status = "" 20 | var vendor = "" 21 | var discount_amount = 0 22 | var last_updated = req.body.updated_at 23 | orderModel 24 | .createOrders(req) 25 | .then(data => { 26 | for (let i = 0; i < req.body.line_items.length; i++) { 27 | qty = req.body.line_items[i].quantity 28 | name = req.body.line_items[i].name 29 | price = req.body.line_items[i].price 30 | compare_at_price = 0 31 | sku = req.body.line_items[i].sku 32 | shipping = req.body.line_items[i].requires_shipping 33 | taxable = req.body.line_items[i].taxable 34 | fulfillment_status = req.body.line_items[i].fulfillment_status 35 | vendor = req.body.line_items[i].vendor 36 | orderModel 37 | .createOrderItem( 38 | order_id, 39 | created_at, 40 | qty, 41 | name, 42 | price, 43 | compare_at_price, 44 | sku, 45 | shipping, 46 | taxable, 47 | fulfillment_status, 48 | vendor, 49 | discount_amount, 50 | last_updated 51 | ) 52 | .then(data => { 53 | console.log(data) 54 | }) 55 | .catch(err => { 56 | reject(err.message) 57 | console.log(err) 58 | }) 59 | } 60 | console.log(data) 61 | }) 62 | .catch(err => { 63 | reject(err.message) 64 | console.log(err) 65 | }) 66 | 67 | resolve({ code: 200 }) 68 | }) 69 | } 70 | 71 | module.exports = orderService 72 | -------------------------------------------------------------------------------- /server/services/payoutService.js: -------------------------------------------------------------------------------- 1 | const payoutModel = require("../models/payout-model") 2 | 3 | const payoutService = { 4 | getPayouts: getPayouts, 5 | getPayoutDetailsByVendor: getPayoutDetailsByVendor, 6 | getPayoutByVendor: getPayoutByVendor, 7 | } 8 | 9 | function getPayouts(flag) { 10 | return new Promise((resolve, reject) => { 11 | payoutModel 12 | .getPayouts(flag) 13 | .then(data => { 14 | resolve({ code: 200, data }) 15 | }) 16 | .catch(err => { 17 | reject(err.message) 18 | console.log(err) 19 | }) 20 | }) 21 | } 22 | 23 | function getPayoutDetailsByVendor(vendor) { 24 | return new Promise((resolve, reject) => { 25 | payoutModel 26 | .getPayoutDetailsByVendor(vendor) 27 | .then(data => { 28 | resolve({ code: 200, data }) 29 | }) 30 | .catch(err => { 31 | reject(err.message) 32 | console.log(err) 33 | }) 34 | }) 35 | } 36 | 37 | function getPayoutByVendor(vendor) { 38 | return new Promise((resolve, reject) => { 39 | payoutModel 40 | .getPayoutByVendor(vendor) 41 | .then(data => { 42 | resolve({ code: 200, data }) 43 | }) 44 | .catch(err => { 45 | reject(err.message) 46 | console.log(err) 47 | }) 48 | }) 49 | } 50 | 51 | module.exports = payoutService 52 | -------------------------------------------------------------------------------- /server/services/productService.js: -------------------------------------------------------------------------------- 1 | const productModel = require("../models/product-model") 2 | const shopify = require("./shopify") 3 | 4 | const productService = { 5 | getAllProducts: getAllProducts, 6 | getProductById: getProductById, 7 | getProductsByVendor: getProductsByVendor, 8 | setProducts: setProducts, 9 | updateProducts: updateProducts, 10 | deleteProduct: deleteProduct, 11 | } 12 | 13 | function getAllProducts() { 14 | return new Promise((resolve, reject) => { 15 | shopify.get( 16 | "/admin/products.json", 17 | function (error, shopify_data, headers) { 18 | var products = shopify_data.products 19 | productModel 20 | .getAllProducts() 21 | .then(data => { 22 | resolve({ code: 200, data: data, shopifyData: products }) 23 | }) 24 | .catch(err => { 25 | reject(err.message) 26 | }) 27 | } 28 | ) 29 | }) 30 | } 31 | 32 | function getProductById(id) { 33 | const product_id = id 34 | return new Promise((resolve, reject) => { 35 | productModel 36 | .getProductById(product_id) 37 | .then(data => { 38 | resolve({ code: 200, data: data.data, shopifyData: data.shopifyData }) 39 | }) 40 | .catch(err => { 41 | reject(err.message) 42 | }) 43 | }) 44 | } 45 | 46 | function getProductsByVendor(vendor) { 47 | return new Promise((resolve, reject) => { 48 | productModel 49 | .getProductsByVendor(vendor) 50 | .then(data => { 51 | resolve({ code: 200, data: data.data, shopifyData: data.shopifyData }) 52 | }) 53 | .catch(err => { 54 | reject(err.message) 55 | }) 56 | }) 57 | } 58 | 59 | function setProducts(req) { 60 | const title = req.body.title 61 | const description = req.body.description 62 | const product_type = req.body.product_type 63 | const size = req.body.size 64 | const color = req.body.color 65 | const price = req.body.price 66 | const published_at = req.body.published_at 67 | const shopify_published_at = new Date(published_at) 68 | 69 | //declare post_data for adding product to shopify 70 | var post_data = { 71 | product: { 72 | title: title, 73 | body_html: description, 74 | vendor: "Tacoma Consignment", 75 | product_type: product_type, 76 | published_at: shopify_published_at, 77 | variants: [ 78 | { 79 | Color: color, 80 | Size: size, 81 | price: price, 82 | }, 83 | ], 84 | images: [], 85 | }, 86 | } 87 | 88 | for (var i = 0; i < req.files.length; i++) { 89 | var tempImage = { 90 | position: i + 1, 91 | attachment: req.files[i].buffer.toString("base64"), 92 | width: 640, 93 | height: 480, 94 | filename: req.files[i].originalname, 95 | } 96 | post_data.product.images.push(tempImage) 97 | } 98 | 99 | return new Promise((resolve, reject) => { 100 | //adding products to shopify 101 | shopify.post( 102 | "/admin/products.json", 103 | post_data, 104 | function (error, shopify_data, headers) { 105 | var shopify_id = shopify_data.product.id 106 | productModel 107 | .setProducts(req, shopify_id) 108 | .then(data => { 109 | resolve({ code: 200, data: shopify_data }) 110 | }) 111 | .catch(err => { 112 | reject(err.message) 113 | }) 114 | } 115 | ) 116 | }) 117 | } 118 | 119 | function updateProducts(req) { 120 | return new Promise((resolve, reject) => { 121 | //updating products to shopify and mssql 122 | productModel 123 | .updateProducts(req) 124 | .then(data => { 125 | resolve({ code: 200 }) 126 | }) 127 | .catch(err => { 128 | reject(err.message) 129 | }) 130 | }) 131 | } 132 | 133 | function deleteProduct(req) { 134 | return new Promise((resolve, reject) => { 135 | //delete product from shopify and mssql 136 | productModel 137 | .deleteProduct(req) 138 | .then(data => { 139 | resolve({ code: 200 }) 140 | }) 141 | .catch(err => { 142 | reject(err.message) 143 | }) 144 | }) 145 | } 146 | 147 | module.exports = productService 148 | -------------------------------------------------------------------------------- /server/services/shopify.js: -------------------------------------------------------------------------------- 1 | var Shopify = require("shopify-node-api") 2 | 3 | var shopName = process.env.SHOPIFY_SHOP_NAME 4 | var apiKey = process.env.SHOPIFY_API_KEY 5 | var password = process.env.SHOPIFY_PASSWORD 6 | 7 | var shopify = new Shopify({ 8 | shop: shopName, // MYSHOP.myshopify.com 9 | shopify_api_key: apiKey, // Your API key 10 | access_token: password, // Your API password 11 | }) 12 | 13 | module.exports = shopify -------------------------------------------------------------------------------- /services/consignorService.js: -------------------------------------------------------------------------------- 1 | const consignorModel = require("../models/consignor-model") 2 | 3 | const consignorService = { 4 | getAllConsignors: getAllConsignors, 5 | addConsignor: addConsignor, 6 | updateConsignor: updateConsignor, 7 | getConsignorById: getConsignorById, 8 | getConsignorByVendor: getConsignorByVendor, 9 | delConsignor: delConsignor, 10 | } 11 | 12 | function getAllConsignors() { 13 | return new Promise((resolve, reject) => { 14 | consignorModel 15 | .getAllConsignors() 16 | .then(data => { 17 | resolve({ code: 200, data }) 18 | }) 19 | .catch(err => { 20 | reject(err.message) 21 | }) 22 | }) 23 | } 24 | 25 | function addConsignor(consignor_data) { 26 | return new Promise((resolve, reject) => { 27 | consignorModel 28 | .addConsignor(consignor_data) 29 | .then(data => { 30 | resolve({ code: 200 }) 31 | }) 32 | .catch(err => { 33 | reject(err.message) 34 | }) 35 | }) 36 | } 37 | 38 | function updateConsignor(consignor_data) { 39 | return new Promise((resolve, reject) => { 40 | consignorModel 41 | .updateConsignor(consignor_data) 42 | .then(data => { 43 | resolve({ code: 200 }) 44 | }) 45 | .catch(err => { 46 | reject(err.message) 47 | }) 48 | }) 49 | } 50 | 51 | function getConsignorById(id) { 52 | return new Promise((resolve, reject) => { 53 | consignorModel 54 | .getConsignorById(id) 55 | .then(data => { 56 | resolve({ code: 200, data }) 57 | }) 58 | .catch(err => { 59 | reject(err.message) 60 | }) 61 | }) 62 | } 63 | 64 | function getConsignorByVendor(vendor) { 65 | return new Promise((resolve, reject) => { 66 | consignorModel 67 | .getConsignorByVendor(vendor) 68 | .then(data => { 69 | resolve({ code: 200, data }) 70 | }) 71 | .catch(err => { 72 | reject(err.message) 73 | }) 74 | }) 75 | } 76 | 77 | function delConsignor(id) { 78 | return new Promise((resolve, reject) => { 79 | consignorModel 80 | .delConsignor(id) 81 | .then(data => { 82 | resolve({ code: 200, data }) 83 | }) 84 | .catch(err => { 85 | reject(err.message) 86 | }) 87 | }) 88 | } 89 | 90 | module.exports = consignorService 91 | -------------------------------------------------------------------------------- /services/orderService.js: -------------------------------------------------------------------------------- 1 | const orderModel = require("../models/order-model") 2 | const shopify = require("./shopify") 3 | 4 | const orderService = { 5 | createOrders: createOrders, 6 | } 7 | 8 | function createOrders(req) { 9 | return new Promise((resolve, reject) => { 10 | var order_id = req.body.name 11 | var created_at = req.body.created_at 12 | var qty = 0 13 | var name = "" 14 | var price = 0 15 | var compare_at_price = "" 16 | var sku = "" 17 | var shipping = "" 18 | var taxable = "" 19 | var fulfillment_status = "" 20 | var vendor = "" 21 | var discount_amount = 0 22 | var last_updated = req.body.updated_at 23 | orderModel 24 | .createOrders(req) 25 | .then(data => { 26 | for (let i = 0; i < req.body.line_items.length; i++) { 27 | qty = req.body.line_items[i].quantity 28 | name = req.body.line_items[i].name 29 | price = req.body.line_items[i].price 30 | compare_at_price = 0 31 | sku = req.body.line_items[i].sku 32 | shipping = req.body.line_items[i].requires_shipping 33 | taxable = req.body.line_items[i].taxable 34 | fulfillment_status = req.body.line_items[i].fulfillment_status 35 | vendor = req.body.line_items[i].vendor 36 | orderModel 37 | .createOrderItem( 38 | order_id, 39 | created_at, 40 | qty, 41 | name, 42 | price, 43 | compare_at_price, 44 | sku, 45 | shipping, 46 | taxable, 47 | fulfillment_status, 48 | vendor, 49 | discount_amount, 50 | last_updated 51 | ) 52 | .then(data => { 53 | console.log(data) 54 | }) 55 | .catch(err => { 56 | reject(err.message) 57 | console.log(err) 58 | }) 59 | } 60 | console.log(data) 61 | }) 62 | .catch(err => { 63 | reject(err.message) 64 | console.log(err) 65 | }) 66 | 67 | resolve({ code: 200 }) 68 | }) 69 | } 70 | 71 | module.exports = orderService 72 | -------------------------------------------------------------------------------- /services/payoutService.js: -------------------------------------------------------------------------------- 1 | const payoutModel = require("../models/payout-model") 2 | 3 | const payoutService = { 4 | getPayouts: getPayouts, 5 | getPayoutDetailsByVendor: getPayoutDetailsByVendor, 6 | getPayoutByVendor: getPayoutByVendor, 7 | } 8 | 9 | function getPayouts(flag) { 10 | return new Promise((resolve, reject) => { 11 | payoutModel 12 | .getPayouts(flag) 13 | .then(data => { 14 | resolve({ code: 200, data }) 15 | }) 16 | .catch(err => { 17 | reject(err.message) 18 | console.log(err) 19 | }) 20 | }) 21 | } 22 | 23 | function getPayoutDetailsByVendor(vendor) { 24 | return new Promise((resolve, reject) => { 25 | payoutModel 26 | .getPayoutDetailsByVendor(vendor) 27 | .then(data => { 28 | resolve({ code: 200, data }) 29 | }) 30 | .catch(err => { 31 | reject(err.message) 32 | console.log(err) 33 | }) 34 | }) 35 | } 36 | 37 | function getPayoutByVendor(vendor) { 38 | return new Promise((resolve, reject) => { 39 | payoutModel 40 | .getPayoutByVendor(vendor) 41 | .then(data => { 42 | resolve({ code: 200, data }) 43 | }) 44 | .catch(err => { 45 | reject(err.message) 46 | console.log(err) 47 | }) 48 | }) 49 | } 50 | 51 | module.exports = payoutService 52 | -------------------------------------------------------------------------------- /services/productService.js: -------------------------------------------------------------------------------- 1 | const productModel = require("../models/product-model") 2 | const shopify = require("./shopify") 3 | 4 | const productService = { 5 | getAllProducts: getAllProducts, 6 | getProductById: getProductById, 7 | getProductsByVendor: getProductsByVendor, 8 | setProducts: setProducts, 9 | updateProducts: updateProducts, 10 | deleteProduct: deleteProduct, 11 | } 12 | 13 | function getAllProducts() { 14 | return new Promise((resolve, reject) => { 15 | shopify.get( 16 | "/admin/products.json", 17 | function (error, shopify_data, headers) { 18 | var products = shopify_data.products 19 | productModel 20 | .getAllProducts() 21 | .then(data => { 22 | resolve({ code: 200, data: data, shopifyData: products }) 23 | }) 24 | .catch(err => { 25 | reject(err.message) 26 | }) 27 | } 28 | ) 29 | }) 30 | } 31 | 32 | function getProductById(id) { 33 | const product_id = id 34 | return new Promise((resolve, reject) => { 35 | productModel 36 | .getProductById(product_id) 37 | .then(data => { 38 | resolve({ code: 200, data: data.data, shopifyData: data.shopifyData }) 39 | }) 40 | .catch(err => { 41 | reject(err.message) 42 | }) 43 | }) 44 | } 45 | 46 | function getProductsByVendor(vendor) { 47 | return new Promise((resolve, reject) => { 48 | productModel 49 | .getProductsByVendor(vendor) 50 | .then(data => { 51 | resolve({ code: 200, data: data.data, shopifyData: data.shopifyData }) 52 | }) 53 | .catch(err => { 54 | reject(err.message) 55 | }) 56 | }) 57 | } 58 | 59 | function setProducts(req) { 60 | const title = req.body.title 61 | const description = req.body.description 62 | const product_type = req.body.product_type 63 | const size = req.body.size 64 | const color = req.body.color 65 | const price = req.body.price 66 | const published_at = req.body.published_at 67 | const shopify_published_at = new Date(published_at) 68 | 69 | //declare post_data for adding product to shopify 70 | var post_data = { 71 | product: { 72 | title: title, 73 | body_html: description, 74 | vendor: "Tacoma Consignment", 75 | product_type: product_type, 76 | published_at: shopify_published_at, 77 | variants: [ 78 | { 79 | Color: color, 80 | Size: size, 81 | price: price, 82 | }, 83 | ], 84 | images: [], 85 | }, 86 | } 87 | 88 | for (var i = 0; i < req.files.length; i++) { 89 | var tempImage = { 90 | position: i + 1, 91 | attachment: req.files[i].buffer.toString("base64"), 92 | width: 640, 93 | height: 480, 94 | filename: req.files[i].originalname, 95 | } 96 | post_data.product.images.push(tempImage) 97 | } 98 | 99 | return new Promise((resolve, reject) => { 100 | //adding products to shopify 101 | shopify.post( 102 | "/admin/products.json", 103 | post_data, 104 | function (error, shopify_data, headers) { 105 | var shopify_id = shopify_data.product.id 106 | productModel 107 | .setProducts(req, shopify_id) 108 | .then(data => { 109 | resolve({ code: 200, data: shopify_data }) 110 | }) 111 | .catch(err => { 112 | reject(err.message) 113 | }) 114 | } 115 | ) 116 | }) 117 | } 118 | 119 | function updateProducts(req) { 120 | return new Promise((resolve, reject) => { 121 | //updating products to shopify and mssql 122 | productModel 123 | .updateProducts(req) 124 | .then(data => { 125 | resolve({ code: 200 }) 126 | }) 127 | .catch(err => { 128 | reject(err.message) 129 | }) 130 | }) 131 | } 132 | 133 | function deleteProduct(req) { 134 | return new Promise((resolve, reject) => { 135 | //delete product from shopify and mssql 136 | productModel 137 | .deleteProduct(req) 138 | .then(data => { 139 | resolve({ code: 200 }) 140 | }) 141 | .catch(err => { 142 | reject(err.message) 143 | }) 144 | }) 145 | } 146 | 147 | module.exports = productService 148 | -------------------------------------------------------------------------------- /services/shopify.js: -------------------------------------------------------------------------------- 1 | var Shopify = require("shopify-node-api") 2 | 3 | var shopName = process.env.SHOPIFY_SHOP_NAME 4 | var apiKey = process.env.SHOPIFY_API_KEY 5 | var password = process.env.SHOPIFY_PASSWORD 6 | 7 | var shopify = new Shopify({ 8 | shop: shopName, // MYSHOP.myshopify.com 9 | shopify_api_key: apiKey, // Your API key 10 | access_token: password, // Your API password 11 | }) 12 | 13 | module.exports = shopify -------------------------------------------------------------------------------- /theme_source/figma-ui-kit-main.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/theme_source/figma-ui-kit-main.zip -------------------------------------------------------------------------------- /theme_source/materio-v1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elitedev201/Vue-shopify-api-integration/18111e9aa61c28c0034c4cae1f190d6972d3af84/theme_source/materio-v1.0.zip --------------------------------------------------------------------------------