├── wms ├── pages │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── admin.py │ ├── tests.py │ ├── apps.py │ ├── urls.py │ ├── static │ │ └── events │ │ │ └── dashboard │ │ │ ├── img │ │ │ ├── mglogo.png │ │ │ ├── avatars │ │ │ │ ├── profiles │ │ │ │ │ ├── avatar-1.jpg │ │ │ │ │ ├── avatar-2.jpg │ │ │ │ │ ├── avatar-3.jpg │ │ │ │ │ ├── avatar-4.jpg │ │ │ │ │ ├── avatar-5.jpg │ │ │ │ │ ├── avatar-6.jpg │ │ │ │ │ ├── avatar-7.jpg │ │ │ │ │ └── avatar-8.jpg │ │ │ │ ├── projects │ │ │ │ │ ├── project-1.jpg │ │ │ │ │ ├── project-2.jpg │ │ │ │ │ ├── project-3.jpg │ │ │ │ │ └── project-5.jpg │ │ │ │ └── teams │ │ │ │ │ ├── team-logo-1.jpg │ │ │ │ │ └── team-logo-2.jpg │ │ │ ├── svg │ │ │ │ ├── clipboard.svg │ │ │ │ ├── share2.svg │ │ │ │ ├── location-pin.svg │ │ │ │ ├── messenger.svg │ │ │ │ ├── fb.svg │ │ │ │ ├── calendar.svg │ │ │ │ ├── twitter.svg │ │ │ │ ├── share.svg │ │ │ │ └── whatsapp.svg │ │ │ └── logo.svg │ │ │ ├── fonts │ │ │ ├── feather │ │ │ │ ├── fonts │ │ │ │ │ └── Feather.ttf │ │ │ │ └── feather.min.css │ │ │ └── cerebrisans │ │ │ │ ├── cerebrisans-medium.woff │ │ │ │ ├── cerebrisans-regular.woff │ │ │ │ └── cerebrisans-semibold.woff │ │ │ └── libs │ │ │ ├── chart.js │ │ │ └── Chart.extension.min.js │ │ │ ├── highlightjs │ │ │ └── styles │ │ │ │ └── vs2015.css │ │ │ └── magnific │ │ │ └── magnific.min.css │ ├── api_v1_urls.py │ ├── views.py │ ├── api_v1_views.py │ └── templates │ │ └── pages │ │ └── index.html ├── stock │ ├── __init__.py │ ├── migrations │ │ ├── __init__.py │ │ ├── 0003_auto_20200215_1536.py │ │ ├── 0004_auto_20200215_1558.py │ │ ├── 0007_product_price.py │ │ ├── 0006_auto_20200216_1708.py │ │ ├── 0002_auto_20200215_1038.py │ │ ├── 0005_auto_20200216_1442.py │ │ └── 0001_initial.py │ ├── tests.py │ ├── apps.py │ ├── admin.py │ ├── forms.py │ ├── templates │ │ └── stock │ │ │ ├── ProductDelete.html │ │ │ ├── CustomerDelete.html │ │ │ ├── ShipmentDelete.html │ │ │ ├── CustomerCreation.html │ │ │ ├── customer_update_form.html │ │ │ ├── customer_list.html │ │ │ ├── product_list.html │ │ │ ├── product_update_form.html │ │ │ ├── ProductCreation.html │ │ │ ├── shipment_update_form.html │ │ │ ├── shipment_list.html │ │ │ └── ShipmentCreation.html │ ├── serializers.py │ ├── urls.py │ ├── models.py │ └── views.py ├── users │ ├── __init__.py │ ├── migrations │ │ ├── __init__.py │ │ ├── 0003_remove_profile_photo.py │ │ ├── 0002_profile_is_approved.py │ │ └── 0001_initial.py │ ├── templates │ │ ├── users │ │ │ └── login.html │ │ ├── account │ │ │ ├── base.html │ │ │ ├── messages │ │ │ │ ├── logged_out.txt │ │ │ │ ├── password_set.txt │ │ │ │ ├── email_confirmed.txt │ │ │ │ ├── email_deleted.txt │ │ │ │ ├── password_changed.txt │ │ │ │ ├── primary_email_set.txt │ │ │ │ ├── email_confirmation_sent.txt │ │ │ │ ├── unverified_primary_email.txt │ │ │ │ ├── cannot_delete_primary_email.txt │ │ │ │ └── logged_in.txt │ │ │ ├── email │ │ │ │ ├── email_confirmation_signup_message.txt │ │ │ │ ├── email_confirmation_signup_subject.txt │ │ │ │ ├── password_reset_key_subject.txt │ │ │ │ ├── email_confirmation_subject.txt │ │ │ │ ├── email_confirmation_message.txt │ │ │ │ └── password_reset_key_message.txt │ │ │ ├── snippets │ │ │ │ └── already_logged_in.html │ │ │ ├── account_inactive.html │ │ │ ├── signup_closed.html │ │ │ ├── password_reset_from_key_done.html │ │ │ ├── password_set.html │ │ │ ├── verification_sent.html │ │ │ ├── password_reset_done.html │ │ │ ├── verified_email_required.html │ │ │ ├── logout.html │ │ │ ├── email_confirm.html │ │ │ ├── password_reset.html │ │ │ ├── password_change.html │ │ │ ├── signup.html │ │ │ ├── password_reset_from_key.html │ │ │ ├── email.html │ │ │ └── login.html │ │ ├── socialaccount │ │ │ ├── base.html │ │ │ ├── snippets │ │ │ │ ├── login_extra.html │ │ │ │ └── provider_list.html │ │ │ ├── messages │ │ │ │ ├── account_connected_updated.txt │ │ │ │ ├── account_connected.txt │ │ │ │ ├── account_disconnected.txt │ │ │ │ └── account_connected_other.txt │ │ │ ├── authentication_error.html │ │ │ ├── login_cancelled.html │ │ │ ├── signup.html │ │ │ └── connections.html │ │ └── base.html │ ├── tests.py │ ├── apps.py │ ├── admin.py │ ├── api_v1_views.py │ ├── views.py │ ├── serializers.py │ ├── managers.py │ └── models.py ├── wms │ ├── __init__.py │ ├── asgi.py │ ├── wsgi.py │ ├── middleware │ │ └── HelloMiddleWare.py │ ├── urls.py │ └── settings.py ├── WMS WORKSPACE.code-workspace ├── .travisss.yml ├── Dockerfile ├── manage.py ├── requirements.txt └── Readme.md ├── wms-frontend ├── .vscode │ └── last.sql ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── index.html ├── src │ ├── auth-context.js │ ├── fonts │ │ └── feather │ │ │ ├── fonts │ │ │ └── Feather.ttf │ │ │ └── feather.min.css │ ├── setupTests.js │ ├── index.css │ ├── common │ │ ├── InputElement.js │ │ ├── Header.js │ │ └── Table.js │ ├── index.js │ ├── Pages │ │ ├── Customers.js │ │ ├── ProductsPage.js │ │ ├── ShipmentsPage.js │ │ ├── CreateCustomerPage.js │ │ ├── CreateProductPage.js │ │ ├── LoginPage.js │ │ ├── CreateShipmentPage.js │ │ └── Homepage.js │ ├── axiosInstance.js │ ├── App.js │ ├── logo.svg │ └── serviceWorker.js ├── .gitignore ├── package.json └── README.md ├── .vscode └── settings.json ├── Readme.md └── .gitignore /wms/pages/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/stock/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/users/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/wms/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms-frontend/.vscode/last.sql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/pages/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/stock/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/users/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/users/templates/users/login.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/users/templates/account/base.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/base.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | -------------------------------------------------------------------------------- /wms/pages/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /wms/pages/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /wms/pages/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /wms/stock/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /wms/users/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /wms-frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /wms-frontend/src/auth-context.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | 4 | const AuthContext = React.createContext() -------------------------------------------------------------------------------- /wms/pages/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PagesConfig(AppConfig): 5 | name = 'pages' 6 | -------------------------------------------------------------------------------- /wms/stock/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class StockConfig(AppConfig): 5 | name = 'stock' 6 | -------------------------------------------------------------------------------- /wms/users/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class UsersConfig(AppConfig): 5 | name = 'users' 6 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/snippets/login_extra.html: -------------------------------------------------------------------------------- 1 | {% load socialaccount %} 2 | 3 | {% providers_media_js %} 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.pythonPath": "env\\Scripts\\python.exe", 3 | "python.formatting.provider": "black" 4 | } -------------------------------------------------------------------------------- /wms/users/templates/account/messages/logged_out.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}You have signed out.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/templates/account/email/email_confirmation_signup_message.txt: -------------------------------------------------------------------------------- 1 | {% include "account/email/email_confirmation_message.txt" %} 2 | -------------------------------------------------------------------------------- /wms/users/templates/account/email/email_confirmation_signup_subject.txt: -------------------------------------------------------------------------------- 1 | {% include "account/email/email_confirmation_subject.txt" %} 2 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/messages/account_connected_updated.txt: -------------------------------------------------------------------------------- 1 | {% extends "socialaccount/messages/account_connected.txt" %} 2 | -------------------------------------------------------------------------------- /wms/users/templates/account/messages/password_set.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}Password successfully set.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms-frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms-frontend/public/favicon.ico -------------------------------------------------------------------------------- /wms-frontend/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms-frontend/public/logo192.png -------------------------------------------------------------------------------- /wms-frontend/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms-frontend/public/logo512.png -------------------------------------------------------------------------------- /wms/users/templates/account/messages/email_confirmed.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}You have confirmed {{email}}.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/templates/account/messages/email_deleted.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}Removed e-mail address {{email}}.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/templates/account/messages/password_changed.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}Password successfully changed.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/templates/account/messages/primary_email_set.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}Primary e-mail address set.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/pages/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | 5 | urlpatterns = [ 6 | path('', views.index, name='home'), 7 | ] -------------------------------------------------------------------------------- /wms/users/templates/account/messages/email_confirmation_sent.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}Confirmation e-mail sent to {{email}}.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/messages/account_connected.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}The social account has been connected.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/messages/account_disconnected.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}The social account has been disconnected.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import stockUser , Profile 3 | 4 | admin.site.register(stockUser) 5 | admin.site.register(Profile) 6 | -------------------------------------------------------------------------------- /wms/users/templates/account/messages/unverified_primary_email.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}Your primary e-mail address must be verified.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms-frontend/src/fonts/feather/fonts/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms-frontend/src/fonts/feather/fonts/Feather.ttf -------------------------------------------------------------------------------- /wms/WMS WORKSPACE.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | }, 6 | { 7 | "path": "..\\wms-frontend" 8 | } 9 | ], 10 | "settings": {} 11 | } -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/mglogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/mglogo.png -------------------------------------------------------------------------------- /wms/users/templates/account/messages/cannot_delete_primary_email.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}You cannot remove your primary e-mail address ({{email}}).{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/messages/account_connected_other.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans %}The social account is already connected to a different account.{% endblocktrans %} 3 | -------------------------------------------------------------------------------- /wms/users/templates/account/email/password_reset_key_subject.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% autoescape off %} 3 | {% blocktrans %}Password Reset E-mail{% endblocktrans %} 4 | {% endautoescape %} 5 | -------------------------------------------------------------------------------- /wms/users/templates/account/email/email_confirmation_subject.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% autoescape off %} 3 | {% blocktrans %}Please Confirm Your E-mail Address{% endblocktrans %} 4 | {% endautoescape %} 5 | -------------------------------------------------------------------------------- /wms/users/templates/account/messages/logged_in.txt: -------------------------------------------------------------------------------- 1 | {% load account %} 2 | {% load i18n %} 3 | {% user_display user as name %} 4 | {% blocktrans %}Successfully signed in as {{user}}.{% endblocktrans %} 5 | -------------------------------------------------------------------------------- /wms/users/api_v1_views.py: -------------------------------------------------------------------------------- 1 | from restframework.views import APIView 2 | from restframework.authentication import 3 | 4 | class AuthView(APIView): 5 | authentication_classes = [TokenAuthentication] 6 | pass -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/fonts/feather/fonts/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/fonts/feather/fonts/Feather.ttf -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/profiles/avatar-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/profiles/avatar-1.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/profiles/avatar-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/profiles/avatar-2.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/profiles/avatar-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/profiles/avatar-3.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/profiles/avatar-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/profiles/avatar-4.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/profiles/avatar-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/profiles/avatar-5.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/profiles/avatar-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/profiles/avatar-6.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/profiles/avatar-7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/profiles/avatar-7.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/profiles/avatar-8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/profiles/avatar-8.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/projects/project-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/projects/project-1.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/projects/project-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/projects/project-2.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/projects/project-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/projects/project-3.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/projects/project-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/projects/project-5.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/teams/team-logo-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/teams/team-logo-1.jpg -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/avatars/teams/team-logo-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/img/avatars/teams/team-logo-2.jpg -------------------------------------------------------------------------------- /wms/stock/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import * 3 | 4 | admin.site.register(Warehouse) 5 | admin.site.register(Product) 6 | admin.site.register(Customer) 7 | admin.site.register(Shipment) 8 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/fonts/cerebrisans/cerebrisans-medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/fonts/cerebrisans/cerebrisans-medium.woff -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/fonts/cerebrisans/cerebrisans-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/fonts/cerebrisans/cerebrisans-regular.woff -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/fonts/cerebrisans/cerebrisans-semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nyamador/Django-React-Warehouse-Management-System/HEAD/wms/pages/static/events/dashboard/fonts/cerebrisans/cerebrisans-semibold.woff -------------------------------------------------------------------------------- /wms/.travisss.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.7" 4 | branches: 5 | only: 6 | - master 7 | install: 8 | - pip install -r requirements.txt 9 | script: 10 | - python manage.py test --settings=velocity.local -------------------------------------------------------------------------------- /wms/users/templates/account/snippets/already_logged_in.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% load account %} 3 | 4 | {% user_display user as user_display %} 5 |

{% trans "Note" %}: {% blocktrans %}you are already logged in as {{ user_display }}.{% endblocktrans %}

6 | -------------------------------------------------------------------------------- /wms-frontend/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /wms/users/templates/account/account_inactive.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Account Inactive" %}{% endblock %} 6 | 7 | {% block content %} 8 |

{% trans "Account Inactive" %}

9 | 10 |

{% trans "This account is inactive." %}

11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /wms/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8-alpine3.10 2 | 3 | WORKDIR /code 4 | 5 | COPY requirements.txt /code 6 | 7 | 8 | RUN pip install -r requirements.txt 9 | 10 | COPY . /code 11 | 12 | RUN python manage.py makemigrations && python manage.py migrate 13 | 14 | EXPOSE 8000 15 | 16 | ENTRYPOINT ["python", "manage.py"] 17 | CMD ["runserver", "0.0.0.0:8000"] -------------------------------------------------------------------------------- /wms/users/templates/account/signup_closed.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Sign Up Closed" %}{% endblock %} 6 | 7 | {% block content %} 8 |

{% trans "Sign Up Closed" %}

9 | 10 |

{% trans "We are sorry, but the sign up is currently closed." %}

11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/clipboard.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/share2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/location-pin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/authentication_error.html: -------------------------------------------------------------------------------- 1 | {% extends "socialaccount/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Social Network Login Failure" %}{% endblock %} 6 | 7 | {% block content %} 8 |

{% trans "Social Network Login Failure" %}

9 | 10 |

{% trans "An error occurred while attempting to login via your social network account." %}

11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /wms-frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /wms-frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /wms/users/migrations/0003_remove_profile_photo.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-03-20 17:12 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('users', '0002_profile_is_approved'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='profile', 15 | name='photo', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /wms/wms/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for wms project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wms.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /wms/wms/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for wms project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wms.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /wms-frontend/src/common/InputElement.js: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | 3 | 4 | const InputElement = (props) => { 5 | 6 | const [value, setValue] = useState(); 7 | 8 | return ( 9 | setValue(e.target.value)}/> 11 | ) 12 | } 13 | 14 | export default InputElement; -------------------------------------------------------------------------------- /wms/users/templates/account/password_reset_from_key_done.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | {% block head_title %}{% trans "Change Password" %}{% endblock %} 5 | 6 | {% block content %} 7 |

{% trans "Change Password" %}

8 |

{% trans 'Your password has been changed successfully.' %}

9 | 10 | Home 11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /wms/users/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.db.models.signals import post_save 3 | from django.dispatch import receiver 4 | from rest_framework.authtoken.models import Token 5 | from django.shortcuts import render 6 | 7 | # Create your views here. 8 | @receiver(post_save, sender=settings.AUTH_USER_MODEL) 9 | def create_auth_token(sender, instance, created=False, **kwargs): 10 | if created: 11 | Token.objects.create(user=instance) 12 | -------------------------------------------------------------------------------- /wms/stock/migrations/0003_auto_20200215_1536.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-15 15:36 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('stock', '0002_auto_20200215_1038'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='product', 15 | old_name='created_by', 16 | new_name='user', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /wms/users/templates/account/password_set.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Set Password" %}{% endblock %} 6 | 7 | {% block content %} 8 |

{% trans "Set Password" %}

9 | 10 |
11 | {% csrf_token %} 12 | {{ form.as_p }} 13 | 14 |
15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /wms/users/templates/account/verification_sent.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} 6 | 7 | {% block content %} 8 |

{% trans "Verify Your E-mail Address" %}

9 | 10 |

{% blocktrans %}We have sent an e-mail to you for verification. Follow the link provided to finalize the signup process. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}

11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /wms/users/migrations/0002_profile_is_approved.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-17 14:11 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('users', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='profile', 15 | name='is_approved', 16 | field=models.BooleanField(default=False, verbose_name='Approved user'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/messenger.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/stock/migrations/0004_auto_20200215_1558.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-15 15:58 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('stock', '0003_auto_20200215_1536'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='product', 15 | name='sku', 16 | field=models.CharField(max_length=50, unique=True, verbose_name='Stock Keeping Unit'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/login_cancelled.html: -------------------------------------------------------------------------------- 1 | {% extends "socialaccount/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Login Cancelled" %}{% endblock %} 6 | 7 | {% block content %} 8 | 9 |

{% trans "Login Cancelled" %}

10 | 11 | {% url 'account_login' as login_url %} 12 | 13 |

{% blocktrans %}You decided to cancel logging in to our site using one of your existing accounts. If this was a mistake, please proceed to sign in.{% endblocktrans %}

14 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /wms/stock/forms.py: -------------------------------------------------------------------------------- 1 | from django.forms import ModelForm 2 | from .models import Product, Customer, Shipment 3 | 4 | class ProductCreationForm(ModelForm): 5 | class Meta: 6 | model = Product 7 | fields = ('name', 'quantity', 'price', 'sku') 8 | 9 | class CustomerCreationForm(ModelForm): 10 | class Meta: 11 | model = Customer 12 | fields = ('firstname', 'lastname', 'email') 13 | 14 | class ShipmentCreationForm(ModelForm): 15 | class Meta: 16 | model = Shipment 17 | fields = ('customer', 'destination', 'product','quantity') -------------------------------------------------------------------------------- /wms-frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want your app to work offline and load faster, you can change 15 | // unregister() to register() below. Note this comes with some pitfalls. 16 | // Learn more about service workers: https://bit.ly/CRA-PWA 17 | serviceWorker.unregister(); 18 | -------------------------------------------------------------------------------- /wms/stock/migrations/0007_product_price.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-17 08:10 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('stock', '0006_auto_20200216_1708'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='product', 15 | name='price', 16 | field=models.DecimalField(decimal_places=2, default=2.0, max_digits=10, verbose_name='Unit Price'), 17 | preserve_default=False, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/fb.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms-frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /wms/users/templates/account/email/email_confirmation_message.txt: -------------------------------------------------------------------------------- 1 | {% load account %}{% user_display user as user_display %}{% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Hello from {{ site_name }}! 2 | 3 | You're receiving this e-mail because user {{ user_display }} has given yours as an e-mail address to connect their account. 4 | 5 | To confirm this is correct, go to {{ activate_url }} 6 | {% endblocktrans %} 7 | {% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Thank you from {{ site_name }}! 8 | {{ site_domain }}{% endblocktrans %} 9 | {% endautoescape %} 10 | -------------------------------------------------------------------------------- /wms/stock/templates/stock/ProductDelete.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | 3 | 4 | {% block content %} 5 |
6 | 7 | 8 |

9 | Do you want to delete {{ product }} 10 |

11 | 12 | 13 | 14 |
15 | {% csrf_token %} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 |
26 | {% endblock content %} -------------------------------------------------------------------------------- /wms/users/templates/account/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | {% load account %} 5 | 6 | {% block head_title %}{% trans "Password Reset" %}{% endblock %} 7 | 8 | {% block content %} 9 |

{% trans "Password Reset" %}

10 | 11 | {% if user.is_authenticated %} 12 | {% include "account/snippets/already_logged_in.html" %} 13 | {% endif %} 14 | 15 |

{% blocktrans %}We have sent you an e-mail. Please contact us if you do not receive it within a few minutes.{% endblocktrans %}

16 | 17 | Go Home 18 | 19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /wms/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'wms.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /wms/stock/templates/stock/CustomerDelete.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | 3 | 4 | {% block content %} 5 |
6 | 7 | 8 |

9 | Do you want to delete {{ customer }} 10 |

11 | 12 | 13 | 14 | 15 |
16 | {% csrf_token %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 | {% endblock content %} -------------------------------------------------------------------------------- /wms/stock/templates/stock/ShipmentDelete.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | 3 | 4 | {% block content %} 5 |
6 | 7 | 8 |

9 | Do you want to delete {{ shipment }} 10 |

11 | 12 | 13 | 14 | 15 |
16 | {% csrf_token %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 | {% endblock content %} -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/calendar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/users/templates/account/email/password_reset_key_message.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Hello from {{ site_name }}! 2 | 3 | You're receiving this e-mail because you or someone else has requested a password for your user account. 4 | It can be safely ignored if you did not request a password reset. Click the link below to reset your password.{% endblocktrans %} 5 | 6 | {{ password_reset_url }} 7 | 8 | {% if username %}{% blocktrans %}In case you forgot, your username is {{ username }}.{% endblocktrans %} 9 | 10 | {% endif %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Thank you for using {{ site_name }}! 11 | {{ site_domain }}{% endblocktrans %} 12 | {% endautoescape %} 13 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/snippets/provider_list.html: -------------------------------------------------------------------------------- 1 | {% load socialaccount %} 2 | 3 | {% get_providers as socialaccount_providers %} 4 | 5 | {% for provider in socialaccount_providers %} 6 | {% if provider.id == "openid" %} 7 | {% for brand in provider.get_brands %} 8 |
  • 9 | {{brand.name}} 13 |
  • 14 | {% endfor %} 15 | {% endif %} 16 |
  • 17 | {{provider.name}} 19 |
  • 20 | {% endfor %} 21 | -------------------------------------------------------------------------------- /wms/pages/api_v1_urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | # from rest_framework.authtoken import views as authtokenviews 4 | from . import api_v1_views 5 | 6 | 7 | urlpatterns = [ 8 | # List Routes 9 | path("products/all", api_v1_views.Products.as_view(), name="api_product_list"), 10 | path( 11 | "products/create", 12 | api_v1_views.ProductCreateAPIView.as_view(), 13 | name="api_product_create", 14 | ), 15 | path("customers/all", api_v1_views.Customers.as_view(), name="api_customer_list"), 16 | path( 17 | "warehouses/all", api_v1_views.Warehouses.as_view(), name="api_warehouse_list" 18 | ), 19 | path("shipments/all", api_v1_views.Shipments.as_view(), name="api_shipment_list"), 20 | # TOKENAUTH 21 | # path('api-token-auth', authtokenviews.obtain_auth_token), 22 | ] 23 | -------------------------------------------------------------------------------- /wms/stock/migrations/0006_auto_20200216_1708.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-16 17:08 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('stock', '0005_auto_20200216_1442'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='shipment', 15 | name='destination', 16 | field=models.CharField(default=1, max_length=100, verbose_name='Destination of Shipment'), 17 | preserve_default=False, 18 | ), 19 | migrations.AddField( 20 | model_name='shipment', 21 | name='quantity', 22 | field=models.PositiveIntegerField(default=1, verbose_name='Product Quantity'), 23 | preserve_default=False, 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /wms/stock/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | 3 | from .models import Product, Customer, Warehouse, Shipment 4 | 5 | 6 | class ProductSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = Product 9 | fields = ["user", "warehouse", "name", "price", "quantity", "sku", "date"] 10 | 11 | 12 | class CustomerSerializer(serializers.ModelSerializer): 13 | class Meta: 14 | model = Customer 15 | fields = ["firstname", "lastname", "email"] 16 | 17 | 18 | class WarehouseSerializer(serializers.ModelSerializer): 19 | class Meta: 20 | model = Warehouse 21 | fields = ["id", "name", "location"] 22 | 23 | 24 | class ShipmentSerializer(serializers.ModelSerializer): 25 | class Meta: 26 | model = Shipment 27 | fields = ["user", "customer", "destination", "product", "quantity"] 28 | 29 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "socialaccount/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Signup" %}{% endblock %} 6 | 7 | {% block content %} 8 |

    {% trans "Sign Up" %}

    9 | 10 |

    {% blocktrans with provider_name=account.get_provider.name site_name=site.name %}You are about to use your {{provider_name}} account to login to 11 | {{site_name}}. As a final step, please complete the following form:{% endblocktrans %}

    12 | 13 |
    14 | {% csrf_token %} 15 | {{ form.as_p }} 16 | {% if redirect_field_value %} 17 | 18 | {% endif %} 19 | 20 |
    21 | 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /wms/users/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework_simplejwt.serializers import TokenObtainPairSerializer 2 | from rest_framework import serializers 3 | from .models import stockUser 4 | 5 | 6 | class CustomUserSerializer(serializers.ModelSerializer): 7 | email = serializers.EmailField(required=True) 8 | password = serializers.CharField(min_length=8, write_only=True) 9 | 10 | class Meta: 11 | model = stockUser 12 | field = ('email', 'password') 13 | extra_kwargs = {'password': {'write_only': True}} 14 | 15 | def create(self, validated_data): 16 | password = validated_data.pop('password', None) 17 | instance = self.Meta.model(**validated_data) # as long as the fields are the same, we can just use this 18 | if password is not None: 19 | instance.set_password(password) 20 | instance.save() 21 | return instance 22 | -------------------------------------------------------------------------------- /wms/users/templates/account/verified_email_required.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %} 6 | 7 | {% block content %} 8 |

    {% trans "Verify Your E-mail Address" %}

    9 | 10 | {% url 'account_email' as email_url %} 11 | 12 |

    {% blocktrans %}This part of the site requires us to verify that 13 | you are who you claim to be. For this purpose, we require that you 14 | verify ownership of your e-mail address. {% endblocktrans %}

    15 | 16 |

    {% blocktrans %}We have sent an e-mail to you for 17 | verification. Please click on the link inside this e-mail. Please 18 | contact us if you do not receive it within a few minutes.{% endblocktrans %}

    19 | 20 |

    {% blocktrans %}Note: you can still change your e-mail address.{% endblocktrans %}

    21 | 22 | 23 | {% endblock %} 24 | -------------------------------------------------------------------------------- /wms/stock/migrations/0002_auto_20200215_1038.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-15 10:38 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ('stock', '0001_initial'), 15 | ] 16 | 17 | operations = [ 18 | migrations.AddField( 19 | model_name='product', 20 | name='created_by', 21 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), 22 | ), 23 | migrations.AddField( 24 | model_name='product', 25 | name='warehouse', 26 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.Warehouse'), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /wms-frontend/src/Pages/Customers.js: -------------------------------------------------------------------------------- 1 | import React, {useState, useEffect} from 'react'; 2 | import Header from '../common/Header'; 3 | import Table from '../common/Table'; 4 | 5 | const Customers = () => { 6 | const [dataList, setdataList] = useState([]); 7 | const [isLoading, setisLoading] = useState(true); 8 | 9 | const dataHeadings = ['Firstname', 'Lastname', 'Email']; 10 | 11 | 12 | useEffect( () => { 13 | fetch('http://127.0.0.1:8000/api/v1/customers/all') 14 | .then( res => res.json()) 15 | .then( data => setdataList([...data]) ) 16 | .then(setisLoading(false)) 17 | .catch(err => setisLoading(true)); 18 | }, []) 19 | 20 | return ( 21 | <> 22 |
    23 | 24 | { isLoading ?
    Loading...
    25 | : } 26 | 27 | ); 28 | }; 29 | 30 | export default Customers; 31 | -------------------------------------------------------------------------------- /wms/users/templates/account/logout.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Sign Out" %}{% endblock %} 6 | 7 | 8 | {% if messages %} 9 | {% for message in messages %} 10 | 13 | {% endfor %} 14 | {% endif %} 15 | 16 | {% block content %} 17 |

    {% trans "Sign Out" %}

    18 | 19 |

    {% trans 'Are you sure you want to sign out?' %}

    20 | 21 | 22 | {% csrf_token %} 23 | {% if redirect_field_value %} 24 | 25 | {% endif %} 26 | 27 | 28 | 29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /wms-frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wms-frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "license": "BSD", 6 | "dependencies": { 7 | "@testing-library/jest-dom": "^4.2.4", 8 | "@testing-library/react": "^9.3.2", 9 | "@testing-library/user-event": "^7.1.2", 10 | "react": "^16.13.1", 11 | "react-dom": "^16.13.1", 12 | "react-router-dom": "^5.2.0", 13 | "react-scripts": "3.4.1" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": "react-app" 23 | }, 24 | "browserslist": { 25 | "production": [ 26 | ">0.2%", 27 | "not dead", 28 | "not op_mini all" 29 | ], 30 | "development": [ 31 | "last 1 chrome version", 32 | "last 1 firefox version", 33 | "last 1 safari version" 34 | ] 35 | }, 36 | "devDependencies": { 37 | "axios": "^0.19.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /wms-frontend/src/Pages/ProductsPage.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import Header from '../common/Header'; 3 | import Table from '../common/Table'; 4 | 5 | const ProductsPage = () => { 6 | const [productsList, setProductsList] = useState([]); 7 | const [isLoading, setisLoading] = useState(true); 8 | 9 | const dataHeadings = ['Name', 'Quantity', 'Sku']; 10 | useEffect(() => { 11 | fetch('http://127.0.0.1:8000/api/v1/products/all') 12 | .then((res) => res.json()) 13 | .then((data) => setProductsList([...data])) 14 | .then(setisLoading(false)); 15 | }, []); 16 | 17 | return ( 18 | <> 19 |
    20 | {isLoading ? ( 21 |
    22 | {' '} 23 | Loading...{' '} 24 |
    25 | ) : ( 26 |
    27 | )} 28 | 29 | ); 30 | }; 31 | 32 | export default ProductsPage; 33 | -------------------------------------------------------------------------------- /wms/pages/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.core.cache.backends.base import DEFAULT_TIMEOUT 3 | from django.views.decorators.cache import cache_page 4 | from django.shortcuts import render 5 | from django.contrib.auth.decorators import login_required 6 | from django.db.models import Sum 7 | from stock.models import (Product, Customer) 8 | 9 | CACHE_TTL = getattr(settings, 'CACHE_TTL', DEFAULT_TIMEOUT) 10 | 11 | @cache_page(CACHE_TTL) 12 | @login_required() 13 | def index(request): 14 | 15 | product_count = Product.objects.count() 16 | customer_count = Customer.objects.count() 17 | total_stock_price = Product.objects.all().aggregate(Sum('price')) 18 | 19 | print("Desmond", request.META['Desmond']) 20 | print("Seller", request.META['seller_subdomain']) 21 | 22 | context = { 23 | 'product_count' :product_count, 24 | "customer_count" : customer_count, 25 | "total_stock_price": abs(total_stock_price['price__sum']) 26 | } 27 | return render(request, 'pages/index.html', context) 28 | -------------------------------------------------------------------------------- /wms-frontend/src/Pages/ShipmentsPage.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import Header from '../common/Header'; 3 | import Table from '../common/Table'; 4 | 5 | const ShipmentsPage = () => { 6 | const [shipmentsList, setshipmentsList] = useState([]); 7 | const [isLoading, setisLoading] = useState(true); 8 | 9 | const dataHeadings = ['Destination', 'Quantity', 'Product']; 10 | useEffect(() => { 11 | fetch('http://127.0.0.1:8000/api/v1/shipments/all') 12 | .then((res) => res.json()) 13 | .then((data) => setshipmentsList([...data])) 14 | .then(setisLoading(false)); 15 | }, []); 16 | 17 | return ( 18 | <> 19 |
    20 | {isLoading ? ( 21 |
    22 | {' '} 23 | Loading...{' '} 24 |
    25 | ) : ( 26 |
    27 | )} 28 | 29 | ); 30 | }; 31 | 32 | export default ShipmentsPage; 33 | -------------------------------------------------------------------------------- /wms/pages/api_v1_views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import generics 2 | from rest_framework.authentication import TokenAuthentication 3 | from rest_framework.permissions import IsAuthenticated 4 | from stock.models import Product, Customer, Warehouse, Shipment 5 | from stock.serializers import ProductSerializer, CustomerSerializer, WarehouseSerializer, ShipmentSerializer 6 | 7 | 8 | #LIST API VIEWS 9 | class Products(generics.ListAPIView): 10 | 11 | queryset = Product.objects.all() 12 | serializer_class = ProductSerializer 13 | 14 | 15 | class ProductCreateAPIView(generics.CreateAPIView): 16 | 17 | serializer_class = ProductSerializer 18 | 19 | 20 | class Customers(generics.ListAPIView): 21 | 22 | queryset = Customer.objects.all() 23 | serializer_class = CustomerSerializer 24 | 25 | 26 | class Warehouses(generics.ListAPIView): 27 | queryset = Warehouse.objects.all() 28 | serializer_class = WarehouseSerializer 29 | 30 | 31 | class Shipments(generics.ListAPIView): 32 | queryset = Shipment.objects.all() 33 | serializer_class = ShipmentSerializer -------------------------------------------------------------------------------- /wms/users/templates/account/email_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | 3 | {% load i18n %} 4 | {% load account %} 5 | 6 | {% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %} 7 | 8 | 9 | {% block content %} 10 |

    {% trans "Confirm E-mail Address" %}

    11 | 12 | {% if confirmation %} 13 | 14 | {% user_display confirmation.email_address.user as user_display %} 15 | 16 |

    {% blocktrans with confirmation.email_address.email as email %}Please confirm that {{ email }} is an e-mail address for user {{ user_display }}.{% endblocktrans %}

    17 | 18 | 19 | {% csrf_token %} 20 | 21 | 22 | 23 | {% else %} 24 | 25 | {% url 'account_email' as email_url %} 26 | 27 |

    {% blocktrans %}This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request.{% endblocktrans %}

    28 | 29 | {% endif %} 30 | 31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/wms/middleware/HelloMiddleWare.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | class SimpleMiddleware: 4 | def __init__(self, get_response): 5 | self.get_response = get_response 6 | # One-time configuration and initialization. 7 | 8 | def __call__(self, request): 9 | # Code to be executed for each request before 10 | # the view (and later middleware) are called. 11 | 12 | request.META['Desmond'] = "Selasi" 13 | 14 | 15 | uri = request.build_absolute_uri() #https://foo.myvelocity.tech 16 | link_without_slashes = uri.split('/')[2] # foo.myvelocity.tech 17 | seller_subdomain = link_without_slashes.split('.')[0] #foo 18 | 19 | request.META['seller_subdomain'] = seller_subdomain 20 | 21 | 22 | response = self.get_response(request) 23 | 24 | # Code to be executed for each request/response after 25 | # the view is called. 26 | 27 | 28 | return response 29 | 30 | # def process_view(request, view_func, view_args, view_kwargs): 31 | # # view_kwargs['name'] = "Hello" 32 | # response = HttpResponse() 33 | # response['Desmond'] = 120 34 | # return response -------------------------------------------------------------------------------- /wms/wms/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.conf import settings 3 | from django.conf.urls.static import static 4 | from django.urls import path, include 5 | from rest_framework_simplejwt.views import ( 6 | TokenObtainPairView, TokenRefreshView, TokenVerifyView) 7 | from rest_framework.authtoken import views as TokenViews 8 | from stock import views as stock_views 9 | 10 | urlpatterns = [ 11 | path('admin/', admin.site.urls), 12 | path('accounts/', include('allauth.urls')), 13 | path('stock/', include('stock.urls')), 14 | path('customers/new', stock_views.CustomerCreationView.as_view(),name='add-customer'), 15 | path('', include('pages.urls')), 16 | path('api-auth/', include('rest_framework.urls')), 17 | path('api/v1/', include('pages.api_v1_urls')), 18 | # path('api-token-auth/', TokenViews.obtain_auth_token), 19 | 20 | # JWT Authentication Views 21 | path('api/token', TokenObtainPairView.as_view(), name='token_obtain_pair'), 22 | path('api/token/refresh', TokenRefreshView.as_view(), name='token_refresh'), 23 | path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'), 24 | ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 25 | -------------------------------------------------------------------------------- /wms/stock/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | urlpatterns = [ 5 | #Customers 6 | path('customers', views.CustomerListView.as_view(), name="all-customers"), 7 | path('customers//delete', views.CustomerDeleteView.as_view(), name="delete-customer"), 8 | path('customers//edit', views.CustomerUpdateView.as_view(), name="edit-customer"), 9 | # Products 10 | path('/products', views.ProductListView.as_view(), name="all-products"), 11 | path('products/all', views.CachedProductListView, name='cached'), 12 | path('/products/new', views.ProductCreationView, name="add-product"), 13 | path('products//delete', views.ProductDeleteView.as_view(), name="delete-product"), 14 | path('products//edit', views.ProductUpdateView.as_view(), name="edit-product"), 15 | #Shipments 16 | path('/shipments/new', views.ShipmentCreationView.as_view(), name="add-shipment"), 17 | path('/shipments', views.ShipmentListView.as_view(), name="all-shipment"), 18 | path('shipments//delete', views.ShipmentDeleteView.as_view(), name="delete-shipment"), 19 | path('shipments//edit', views.ShipmentUpdateView.as_view(), name="edit-shipment"), 20 | ] -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/libs/chart.js/Chart.extension.min.js: -------------------------------------------------------------------------------- 1 | Chart.elements.Rectangle.prototype.draw=function(){var t,e,i,r,h,o,d,a=this._chart.ctx,n=this._view,l=n.borderWidth;if(d=n.horizontal?(t=n.base,e=n.x,i=n.y-n.height/2,r=n.y+n.height/2,h=theight/2&&(m=height/2),m>width/2&&(m=width/2),a.moveTo(x+m,y),a.lineTo(x+width-m,y),a.quadraticCurveTo(x+width,y,x+width,y+m),a.lineTo(x+width,y+height-m),a.quadraticCurveTo(x+width,y+height,x+width-m,y+height),a.lineTo(x+m,y+height),a.quadraticCurveTo(x,y+height,x,y+height-m),a.lineTo(x,y+m),a.quadraticCurveTo(x,y,x+m,y)}a.fill(),l&&a.stroke()}; -------------------------------------------------------------------------------- /wms-frontend/src/axiosInstance.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const axiosInstance = axios.create({ 4 | baseURL: 'http://127.0.0.1:8000', 5 | timeout: 5000, 6 | headers:{ 7 | 'Authorization': 'JWT' + localStorage.getItem('access_token'), 8 | 'Content-Type': 'application/json', 9 | 'Accept': 'application/json' 10 | } 11 | }) 12 | 13 | axiosInstance.interceptors.response.use(response => response, 14 | error => { 15 | const originalRequest = error.config; 16 | if (error.response.status === 401 && error.response.statusText === "Unauthorized"){ 17 | const refresh_token = localStorage.getItem('refresh_token'); 18 | 19 | return axiosInstance.post('/api/token', {refresh: refresh_token}) 20 | .then(response => { 21 | localStorage.setItem('access_token', response.data.access); 22 | localStorage.setItem('refresh_token', response.data.refresh); 23 | 24 | axiosInstance.defaults['Authorization'] = "JWT" + response.data.access; 25 | originalRequest.headers['Authorization'] = "JWT" + response.data.access; 26 | 27 | return axiosInstance(originalRequest); 28 | }) 29 | .catch(err => console.error(err)); 30 | } 31 | return Promise.reject(error) 32 | } 33 | ) 34 | 35 | export default axiosInstance; -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/share.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/users/managers.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.base_user import BaseUserManager 2 | from django.utils.translation import ugettext_lazy as _ 3 | from django.db import models 4 | 5 | 6 | class stockUserManager(BaseUserManager): 7 | """ 8 | Custom user model manager 9 | """ 10 | def create_user(self, email, password, **extra_fields): 11 | """ 12 | Create and save a User with the given email and password. 13 | """ 14 | if not email: 15 | raise ValueError(_('The Email must be set')) 16 | email = self.normalize_email(email) 17 | user = self.model(email=email, **extra_fields) 18 | user.set_password(password) 19 | user.save() 20 | return user 21 | 22 | def create_superuser(self, email, password, **extra_fields): 23 | """ 24 | Create and save a SuperUser with the given email and password. 25 | """ 26 | extra_fields.setdefault('is_staff', True) 27 | extra_fields.setdefault('is_superuser', True) 28 | extra_fields.setdefault('is_active', True) 29 | 30 | if extra_fields.get('is_staff') is not True: 31 | raise ValueError(_('Superuser must have is_staff=True.')) 32 | if extra_fields.get('is_superuser') is not True: 33 | raise ValueError(_('Superuser must have is_superuser=True.')) 34 | return self.create_user(email, password, **extra_fields) -------------------------------------------------------------------------------- /wms/stock/migrations/0005_auto_20200216_1442.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-16 14:42 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 12 | ('stock', '0004_auto_20200215_1558'), 13 | ] 14 | 15 | operations = [ 16 | migrations.AlterField( 17 | model_name='customer', 18 | name='firstname', 19 | field=models.CharField(max_length=50, verbose_name='Firstname'), 20 | ), 21 | migrations.AlterField( 22 | model_name='customer', 23 | name='lastname', 24 | field=models.CharField(max_length=50, verbose_name='Lastname'), 25 | ), 26 | migrations.CreateModel( 27 | name='Shipment', 28 | fields=[ 29 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 30 | ('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.Customer')), 31 | ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.Product')), 32 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 33 | ], 34 | ), 35 | ] 36 | -------------------------------------------------------------------------------- /wms/requirements.txt: -------------------------------------------------------------------------------- 1 | algoliasearch==2.2.0 2 | aniso8601==7.0.0 3 | asgiref==3.2.3 4 | astroid==2.3.3 5 | autopep8==1.4.4 6 | awsebcli==3.18.0 7 | beautifulsoup4==4.8.1 8 | boto3==1.11.15 9 | botocore==1.15.41 10 | cement==2.8.2 11 | certifi==2019.11.28 12 | cffi==1.13.2 13 | chardet==3.0.4 14 | colorama==0.4.3 15 | cryptography==2.8 16 | Django==3.0 17 | django-filter==2.2.0 18 | django-graphql-jwt==0.3.1 19 | djangorestframework==3.10.3 20 | docutils==0.15.2 21 | elasticsearch==7.5.1 22 | elasticsearch-dsl==7.1.0 23 | et-xmlfile==1.0.1 24 | future==0.16.0 25 | graphene==2.1.8 26 | graphene-django==2.10.0 27 | graphql-core==2.3.1 28 | graphql-relay==2.0.1 29 | gunicorn==20.0.4 30 | idna==2.7 31 | isort==4.3.21 32 | jdcal==1.4.1 33 | jmespath==0.9.4 34 | jwcrypto==0.6.0 35 | KalturaApiClient==15.14.0 36 | lazy-object-proxy==1.4.3 37 | lxml==4.4.1 38 | mccabe==0.6.1 39 | numpy==1.18.1 40 | openpyxl==3.0.3 41 | pandas==1.0.1 42 | pathspec==0.5.9 43 | Pillow==7.1.2 44 | promise==2.3 45 | pycodestyle==2.5.0 46 | pycparser==2.19 47 | PyJWT==1.7.1 48 | pylint==2.4.4 49 | pyperclip==1.7.0 50 | pypiwin32==223 51 | python-dateutil==2.8.0 52 | pytz==2019.3 53 | pywin32==227 54 | PyYAML==5.3.1 55 | requests==2.20.1 56 | requests-toolbelt==0.9.1 57 | Rx==1.6.1 58 | s3transfer==0.3.3 59 | selenium==3.141.0 60 | semantic-version==2.5.0 61 | singledispatch==3.4.0.3 62 | six==1.14.0 63 | soupsieve==1.9.5 64 | sqlparse==0.3.0 65 | termcolor==1.1.0 66 | urllib3==1.24.3 67 | virtualenv==16.7.7 68 | wcwidth==0.1.9 69 | wrapt==1.11.2 70 | -------------------------------------------------------------------------------- /wms-frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './App.css'; 3 | import HomePage from './Pages/Homepage'; 4 | import ProductsPage from './Pages/ProductsPage'; 5 | import ShipmentsPage from './Pages/ShipmentsPage'; 6 | import LoginPage from './Pages/LoginPage'; 7 | import Customers from './Pages/Customers'; 8 | import CreateShipmentPage from './Pages/CreateShipmentPage'; 9 | import CreateProductPage from './Pages/CreateProductPage'; 10 | import CreateCustomerPage from './Pages/CreateCustomerPage'; 11 | import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; 12 | 13 | function App() { 14 | return ( 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ); 51 | } 52 | 53 | export default App; 54 | -------------------------------------------------------------------------------- /wms-frontend/src/common/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Link} from 'react-router-dom'; 3 | 4 | 5 | const Header = () => { 6 | return ( 7 | 51 | ) 52 | } 53 | 54 | 55 | export default Header; -------------------------------------------------------------------------------- /wms/users/models.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | from django.contrib.auth.models import AbstractUser 3 | from django.db import models 4 | from .managers import stockUserManager 5 | from stock.models import Warehouse 6 | 7 | 8 | class stockUser(AbstractUser): 9 | 10 | email = models.EmailField(verbose_name="Email Adddress", max_length=255, unique=True) 11 | 12 | USERNAME_FIELD = 'email' 13 | REQUIRED_FIELDS = [] 14 | 15 | objects = stockUserManager() 16 | 17 | def __str__(self): 18 | return self.email 19 | 20 | 21 | class Profile(models.Model): 22 | prefix_list = ( 23 | ('Mr', 'Mr.'), 24 | ('Mrs', 'Mrs.'), 25 | ('Ms', 'Ms.'), 26 | ('Mis', 'Miss.'), 27 | ('Mx', 'Mx.'), 28 | ('Dr', 'Dr.'), 29 | ('Prf', 'Prof.'), 30 | ('Rv', 'Rev.'), 31 | ) 32 | 33 | user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) 34 | prefix = models.CharField(verbose_name="Prefix", choices=prefix_list , max_length=5) 35 | firstname = models.CharField(verbose_name="First Name", max_length=100) 36 | lastname = models.CharField(verbose_name="Last Name", max_length=100) 37 | cellphone = models.CharField(verbose_name="Mobile Number", max_length=20) 38 | warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE) 39 | is_approved = models.BooleanField(verbose_name="Approved user", default=False) 40 | 41 | def __str__(self): 42 | return f'{self.prefix} {self.firstname} {self.lastname}' 43 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/img/svg/whatsapp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wms/users/templates/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | {% block head_title %}{% endblock %} 8 | 9 | 10 | 11 | 12 | {% block extra_head %} 13 | {% endblock %} 14 | 15 | 16 | 17 | {% block body %} 18 |
    19 |
    20 |
    21 | {% block content %} 22 | {% endblock %} 23 | {% endblock %} 24 |
    25 |
    26 |
    27 | {% block extra_body %} 28 | {% endblock %} 29 | 30 | 31 | 32 | {% block extra_js %} 33 | {% endblock extra_js %} 34 | 35 | 36 | -------------------------------------------------------------------------------- /wms/users/templates/socialaccount/connections.html: -------------------------------------------------------------------------------- 1 | {% extends "socialaccount/base.html" %} 2 | 3 | {% load i18n %} 4 | 5 | {% block head_title %}{% trans "Account Connections" %}{% endblock %} 6 | 7 | {% block content %} 8 |

    {% trans "Account Connections" %}

    9 | 10 | {% if form.accounts %} 11 |

    {% blocktrans %}You can sign in to your account using any of the following third party accounts:{% endblocktrans %}

    12 | 13 | 14 |
    15 | {% csrf_token %} 16 | 17 |
    18 | {% if form.non_field_errors %} 19 |
    {{ form.non_field_errors }}
    20 | {% endif %} 21 | 22 | {% for base_account in form.accounts %} 23 | {% with base_account.get_provider_account as account %} 24 |
    25 | 30 |
    31 | {% endwith %} 32 | {% endfor %} 33 | 34 |
    35 | 36 |
    37 | 38 |
    39 | 40 | 41 | 42 | {% else %} 43 |

    {% trans 'You currently have no social network accounts connected to this account.' %}

    44 | {% endif %} 45 | 46 |

    {% trans 'Add a 3rd Party Account' %}

    47 | 48 |
      49 | {% include "socialaccount/snippets/provider_list.html" with process="connect" %} 50 |
    51 | 52 | {% include "socialaccount/snippets/login_extra.html" %} 53 | 54 | {% endblock %} 55 | -------------------------------------------------------------------------------- /wms/Readme.md: -------------------------------------------------------------------------------- 1 | ###### Warehouse Management Software Built With React and Django 2 | 3 | **Backend - Django** 4 | 5 | 1. Clone this repository 6 | 2. `git clone https://github.com/Nyamador/wms` 7 | 3. Create a virtual environment with virtualenv `virtual {your-virtual-environment-name}` 8 | 4. Activate your virtual environment , from your virtual environment root `.\Scripts\activate` 9 | 5. Go back to your project root where the `requirements.txt` lives 10 | 6. Install dependencies `pip install -r requirements.txt` 11 | 7. `cd wms` 12 | 8. Run your migrations => `manage.py makemigrations` then `manage.py migrate` 13 | 9. Run the project `python manage.py runserver` 14 | 15 | 16 | **Frontend - Reaact** 17 | 1. cd `wms-frontend` 18 | 2. If you prefer using `npm` -> Run `npm i` or `yarn add` for Yarn 19 | 20 | **Redis - Caching** 21 | 1. Download Redis From The Official Website ( You need Redis > 3.x.x ) 22 | 2. If you run windows download the Binary (Not Official) from this link [Redis Windows Binary 3.2.100](https://github-production-release-asset-2e65be.s3.amazonaws.com/3402186/bb47f4a2-3fac-11e6-9e71-9a4261699bd5?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20200609%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200609T073851Z&X-Amz-Expires=300&X-Amz-Signature=46ff45abdcac77c3992179d4f5e4d8af73a988638f04fa93d5c4e40f456506fe&X-Amz-SignedHeaders=host&actor_id=48738520&repo_id=3402186&response-content-disposition=attachment%3B%20filename%3DRedis-x64-3.2.100.zip&response-content-type=application%2Foctet-stream) 23 | 3. If you want be able to run the Redis-Server with `redis-server` without having to open the \bin directory of the binary everytime, add it to your path. You should be able to start the server with `redis-server`. 24 | 4. To verify the server is running open another terminal window and run `redis-cli`, then enter `PING`. You should see `PONG` on your screen. -------------------------------------------------------------------------------- /wms-frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
    32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /wms/stock/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-15 10:38 2 | 3 | from django.db import migrations, models 4 | import uuid 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Customer', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('firstname', models.CharField(max_length=50, verbose_name='Customer Name')), 20 | ('lastname', models.CharField(max_length=50, verbose_name='Customer Name')), 21 | ('email', models.EmailField(max_length=100, verbose_name='Email Address')), 22 | ], 23 | ), 24 | migrations.CreateModel( 25 | name='Product', 26 | fields=[ 27 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 28 | ('name', models.CharField(max_length=300, verbose_name='Product Name')), 29 | ('quantity', models.PositiveIntegerField(verbose_name='Product Quantity')), 30 | ('sku', models.CharField(max_length=50, verbose_name='Stock Keeping Unit')), 31 | ('date', models.DateField(auto_now_add=True, verbose_name='Date Created')), 32 | ], 33 | ), 34 | migrations.CreateModel( 35 | name='Warehouse', 36 | fields=[ 37 | ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), 38 | ('name', models.CharField(max_length=300, verbose_name='Warehouse name')), 39 | ('location', models.CharField(max_length=300, verbose_name='Warehouse Location')), 40 | ], 41 | ), 42 | ] 43 | -------------------------------------------------------------------------------- /wms/stock/templates/stock/CustomerCreation.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | {% load widget_tweaks %} 3 | 4 | 5 | 6 | {% block content %} 7 |
    8 |
    9 |
    10 |
    11 | 12 | 13 | 14 |

    15 | 16 | Add a Customer 17 |

    18 | 19 |
    20 |
    21 |
    22 |
    23 | 24 |
    25 | {% csrf_token %} 26 | {% with WIDGET_ERROR_CLASS='is-invalid' WIDGET_REQUIRED_CLASS="required" %} 27 | 28 |
    29 | 30 | {% render_field form.firstname|add_class:'form-control'|add_error_class:"is-invalid" %} 31 |
    32 | {{ form.firstname.errors }} 33 |
    34 |
    35 | 36 |
    37 | 38 | {% render_field form.lastname|add_class:'form-control'|add_error_class:"is-invalid" %} 39 |
    40 | {{ form.lastname.errors }} 41 |
    42 |
    43 | 44 |
    45 | 46 | {% render_field form.email|add_class:'form-control'|add_error_class:"is-invalid" %} 47 |
    48 | {{ form.email.errors }} 49 |
    50 |
    51 | 52 | 53 | {% endwith %} 54 | 55 | {% endblock content %} -------------------------------------------------------------------------------- /wms/stock/templates/stock/customer_update_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | {% load widget_tweaks %} 3 | 4 | {% block content %} 5 | 6 | 7 |
    8 |
    9 |
    10 |
    11 | 12 | 13 | 14 |

    15 | 16 | Edit {{object.name}} 17 |

    18 | 19 |
    20 |
    21 |
    22 |
    23 | 24 | 25 |
    26 | {% csrf_token %} 27 | {% with WIDGET_ERROR_CLASS='is-invalid' WIDGET_REQUIRED_CLASS="required" %} 28 | 29 |
    30 | 31 | {% render_field form.firstname|add_class:'form-control'|add_error_class:"is-invalid" %} 32 |
    33 | {{ form.firstname.errors }} 34 |
    35 |
    36 | 37 |
    38 | 39 | {% render_field form.lastname|add_class:'form-control'|add_error_class:"is-invalid" %} 40 |
    41 | {{ form.lastname.errors }} 42 |
    43 |
    44 | 45 |
    46 | 47 | {% render_field form.email|add_class:'form-control'|add_error_class:"is-invalid" %} 48 |
    49 | {{ form.email.errors }} 50 |
    51 |
    52 | 53 | 54 | 55 | 56 | {% endwith %} 57 | 58 | {% endblock content %} 59 | -------------------------------------------------------------------------------- /wms/users/templates/account/password_reset.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | {% load widget_tweaks %} 3 | {% load i18n %} 4 | {% load account %} 5 | 6 | {% block head_title %}{% trans "Password Reset" %}{% endblock %} 7 | 8 | {% block content %} 9 | 10 |

    {% trans "Password Reset" %}

    11 | {% if user.is_authenticated %} 12 | {% include "account/snippets/already_logged_in.html" %} 13 | {% endif %} 14 | 15 |

    {% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}

    16 | 17 |
    18 | {% if form.non_field_errors %} 19 | {% for error in form.non_field_errors %} 20 | 26 | {% endfor %} 27 | {% endif %} 28 | {% csrf_token %} 29 | {% with WIDGET_ERROR_CLASS='is-invalid' %} 30 |
    31 | 32 | {% render_field form.email|add_class:'form-control'|add_error_class:"is-invalid" %} 33 |
    34 | {{ form.email.errors }} 35 |
    36 |
    37 | {% endwith %} 38 | 39 | 40 | 41 |

    {% blocktrans %}Please contact us if you have any trouble resetting your password.{% endblocktrans %}

    42 | {% endblock %} 43 | -------------------------------------------------------------------------------- /wms-frontend/src/common/Table.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Table = ({data, editable, list}) => { 4 | return ( 5 |
    6 |
    7 |
    8 |
    14 |
    15 | 16 | 17 | { data.map( item => 18 | ( 19 | 24 | ) 25 | ) 26 | } 27 | 28 | 29 | 30 | 31 | { 32 | list.map( 33 | datapoint => 34 | 35 | 38 | 41 | 44 | 45 | ) 46 | } 47 | 48 | 49 |
    20 |

    21 | {item} 22 |

    23 |
    36 | {datapoint.firstname || datapoint.name || datapoint.destination} 37 | 39 | {datapoint.lastname || datapoint.quantity } 40 | 42 | {datapoint.email || datapoint.sku || datapoint.product} 43 |
    50 | 51 | 52 | 53 | 54 | ); 55 | }; 56 | 57 | export default Table; 58 | -------------------------------------------------------------------------------- /wms/users/templates/account/password_change.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | {% load widget_tweaks %} 3 | 4 | {% load i18n %} 5 | 6 | {% block head_title %}{% trans "Change Password" %}{% endblock %} 7 | {% if messages %} 8 | {% for message in messages %} 9 | 12 | {% endfor %} 13 | {% endif %} 14 | 15 | 16 | {% block content %} 17 |

    {% trans "Change Password" %}

    18 | 19 |
    20 | {% csrf_token %} 21 | {% if form.errors %} 22 | {% for field in form %} 23 | {% for error in field.errors %} 24 |
    25 | {{ error }} 26 |
    27 | {% endfor %} 28 | {% endfor %} 29 | 30 | {% endif %} 31 | {% with WIDGET_ERROR_CLASS='is-invalid' %} 32 | {% endwith %} 33 |
    34 | 35 | {% render_field form.oldpassword|add_class:'form-control'|add_error_class:"is-invalid" %} 36 |
    37 | {{ form.oldpassword.errors }} 38 |
    39 |
    40 | 41 |
    42 | 43 | {% render_field form.password1|add_class:'form-control'|add_error_class:"is-invalid" %} 44 |
    45 | {{ form.password1.errors }} 46 |
    47 |
    48 | 49 |
    50 | 51 | {% render_field form.password2|add_class:'form-control'|add_error_class:"is-invalid" %} 52 |
    53 | {{ form.password2.errors }} 54 |
    55 |
    56 | 57 | 58 |
    59 | {% endblock %} 60 | -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/libs/highlightjs/styles/vs2015.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Visual Studio 2015 dark style 3 | * Author: Nicolas LLOBERA 4 | */ 5 | 6 | .hljs { 7 | display: block; 8 | overflow-x: auto; 9 | padding: 0.5em; 10 | background: #1E1E1E; 11 | color: #DCDCDC; 12 | } 13 | 14 | .hljs-keyword, 15 | .hljs-literal, 16 | .hljs-symbol, 17 | .hljs-name { 18 | color: #569CD6; 19 | } 20 | .hljs-link { 21 | color: #569CD6; 22 | text-decoration: underline; 23 | } 24 | 25 | .hljs-built_in, 26 | .hljs-type { 27 | color: #4EC9B0; 28 | } 29 | 30 | .hljs-number, 31 | .hljs-class { 32 | color: #B8D7A3; 33 | } 34 | 35 | .hljs-string, 36 | .hljs-meta-string { 37 | color: #D69D85; 38 | } 39 | 40 | .hljs-regexp, 41 | .hljs-template-tag { 42 | color: #9A5334; 43 | } 44 | 45 | .hljs-subst, 46 | .hljs-function, 47 | .hljs-title, 48 | .hljs-params, 49 | .hljs-formula { 50 | color: #DCDCDC; 51 | } 52 | 53 | .hljs-comment, 54 | .hljs-quote { 55 | color: #57A64A; 56 | font-style: italic; 57 | } 58 | 59 | .hljs-doctag { 60 | color: #608B4E; 61 | } 62 | 63 | .hljs-meta, 64 | .hljs-meta-keyword, 65 | .hljs-tag { 66 | color: #9B9B9B; 67 | } 68 | 69 | .hljs-variable, 70 | .hljs-template-variable { 71 | color: #BD63C5; 72 | } 73 | 74 | .hljs-attr, 75 | .hljs-attribute, 76 | .hljs-builtin-name { 77 | color: #9CDCFE; 78 | } 79 | 80 | .hljs-section { 81 | color: gold; 82 | } 83 | 84 | .hljs-emphasis { 85 | font-style: italic; 86 | } 87 | 88 | .hljs-strong { 89 | font-weight: bold; 90 | } 91 | 92 | /*.hljs-code { 93 | font-family:'Monospace'; 94 | }*/ 95 | 96 | .hljs-bullet, 97 | .hljs-selector-tag, 98 | .hljs-selector-id, 99 | .hljs-selector-class, 100 | .hljs-selector-attr, 101 | .hljs-selector-pseudo { 102 | color: #D7BA7D; 103 | } 104 | 105 | .hljs-addition { 106 | background-color: #144212; 107 | display: inline-block; 108 | width: 100%; 109 | } 110 | 111 | .hljs-deletion { 112 | background-color: #600; 113 | display: inline-block; 114 | width: 100%; 115 | } 116 | -------------------------------------------------------------------------------- /wms/stock/models.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | from django.db import models 3 | from django.conf import settings 4 | 5 | class Warehouse(models.Model): 6 | id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) 7 | name = models.CharField(verbose_name="Warehouse name", blank=False, null=False, max_length=300) 8 | location = models.CharField(verbose_name="Warehouse Location",max_length=300, null=False, blank=False) 9 | 10 | def __str__(self): 11 | return self.name 12 | 13 | # class Warehous(models.Model): 14 | 15 | 16 | class Product(models.Model): 17 | user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) 18 | warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE) 19 | name = models.CharField(verbose_name="Product Name", max_length=300) 20 | price = models.DecimalField(verbose_name="Unit Price", max_digits=10, decimal_places=2) 21 | quantity = models.PositiveIntegerField(verbose_name="Product Quantity") 22 | sku = models.CharField(verbose_name="Stock Keeping Unit", max_length=50, null=False, blank=False, unique=True) 23 | date = models.DateField(verbose_name="Date Created", auto_now_add=True) 24 | 25 | 26 | def __str__(self): 27 | return self.name 28 | 29 | 30 | class Customer(models.Model): 31 | firstname = models.CharField("Firstname", max_length=50) 32 | lastname = models.CharField("Lastname", max_length=50) 33 | email = models.EmailField(verbose_name="Email Address", max_length=100) 34 | 35 | def __str__(self): 36 | return f'{self.firstname} {self.lastname}' 37 | 38 | 39 | class Shipment(models.Model): 40 | user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) 41 | customer = models.ForeignKey(Customer, on_delete=models.CASCADE) 42 | destination = models.CharField(verbose_name="Destination of Shipment", max_length=100, null=False, blank=False) 43 | product = models.ForeignKey(Product, on_delete=models.CASCADE) 44 | quantity = models.PositiveIntegerField(verbose_name="Product Quantity") 45 | 46 | 47 | def __str__(self): 48 | return f'Shipment #{self.id}' -------------------------------------------------------------------------------- /wms-frontend/src/Pages/CreateCustomerPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Header from '../common/Header'; 3 | 4 | 5 | const CreateCustomerPage = () => { 6 | return( 7 | <> 8 |
    9 | 10 |
    11 |
    12 |
    13 | 14 |
    15 |
    16 |
    17 |
    18 | 19 | 20 | 21 |

    22 | 23 | Add a Customer 24 |

    25 | 26 |
    27 |
    28 |
    29 |
    30 | 31 |
    32 | 33 | 34 |
    35 | 36 | 37 |
    38 | 39 |
    40 |
    41 | 42 |
    43 | 44 | 45 |
    46 | 47 |
    48 |
    49 | 50 |
    51 | 52 | 53 |
    54 | 55 |
    56 |
    57 | 58 | 59 | 60 |
    61 | 62 |
    63 |
    64 |
    65 | 66 | ) 67 | } 68 | 69 | 70 | export default CreateCustomerPage; -------------------------------------------------------------------------------- /wms/stock/templates/stock/customer_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | 3 | {% block content %} 4 |
    5 |
    6 | 7 | 8 |

    9 | {{ user.profile.warehouse }} Products 10 |

    11 | 12 | 13 |

    14 | {{ user }} 15 |

    16 | 17 |
    18 |
    19 | 20 |
    21 | 22 | 23 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 43 | 44 | 45 | {% for customer in customers %} 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {% endfor %} 55 | 56 |
    25 | # 26 | 28 | Firstname 29 | 31 | Lastname 32 | 34 | Email 35 | 37 | Delete 38 | 40 | Edit 41 |
    {{ customer.id }}{{ customer.firstname }}{{ customer.lastname }}{{ customer.email }}
    57 |
    58 | 59 | 60 | {% endblock content %} -------------------------------------------------------------------------------- /wms/stock/templates/stock/product_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | 3 | {% block content %} 4 |
    5 |
    6 | 7 | 8 |

    9 | {{ user.profile.warehouse }} Products 10 |

    11 | 12 | 13 |

    14 | {{ user }} 15 |

    16 | 17 |
    18 |
    19 | 20 |
    22 | 23 | 24 | 25 | 28 | 31 | 34 | 37 | 40 | 43 | 44 | 45 | 46 | {% for product in products %} 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | {% endfor %} 56 | 57 |
    26 | # 27 | 29 | Name 30 | 32 | Quantity 33 | 35 | SKU 36 | 38 | Delete 39 | 41 | Edit 42 |
    {{ product.id }}{{ product.name }}{{ product.quantity }}{{ product.sku }}
    58 |
    59 | 60 | 61 | {% endblock content %} -------------------------------------------------------------------------------- /wms/stock/templates/stock/product_update_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | {% load widget_tweaks %} 3 | 4 | {% block content %} 5 | 6 | 7 |
    8 |
    9 |
    10 |
    11 | 12 | 13 | 14 |

    15 | 16 | Edit {{object.name}} 17 |

    18 | 19 |
    20 |
    21 |
    22 |
    23 | 24 | 25 |
    26 | {% csrf_token %} 27 | {% with WIDGET_ERROR_CLASS='is-invalid' WIDGET_REQUIRED_CLASS="required" %} 28 | 29 |
    30 | 31 | {% render_field form.name|add_class:'form-control'|add_error_class:"is-invalid" %} 32 |
    33 | {{ form.name.errors }} 34 |
    35 |
    36 | 37 |
    38 | 39 | {% render_field form.quantity|add_class:'form-control'|add_error_class:"is-invalid" %} 40 |
    41 | {{ form.quantity.errors }} 42 |
    43 |
    44 | 45 |
    46 | 47 | {% render_field form.price|add_class:'form-control'|add_error_class:"is-invalid" %} 48 |
    49 | {{ form.price.errors }} 50 |
    51 |
    52 | 53 |
    54 | 55 | {% render_field form.sku|add_class:'form-control'|add_error_class:"is-invalid" %} 56 |
    57 | {{ form.sku.errors }} 58 |
    59 |
    60 | 61 | 62 | 63 | {% endwith %} 64 |
    65 | {% endblock content %} 66 | -------------------------------------------------------------------------------- /wms/stock/templates/stock/ProductCreation.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | {% load widget_tweaks %} 3 | 4 | {% block content %} 5 |
    6 |
    7 |
    8 |
    9 | 10 | 11 | 12 |

    13 | 14 | Add a product 15 |

    16 | 17 |
    18 |
    19 |
    20 |
    21 | 22 | 23 |
    24 | {% csrf_token %} 25 | {% with WIDGET_ERROR_CLASS='is-invalid' WIDGET_REQUIRED_CLASS="required" %} 26 | 27 |
    28 | 29 | {% render_field form.name|add_class:'form-control'|add_error_class:"is-invalid" %} 30 |
    31 | {{ form.name.errors }} 32 |
    33 |
    34 | 35 |
    36 | 37 | {% render_field form.quantity|add_class:'form-control'|add_error_class:"is-invalid" %} 38 |
    39 | {{ form.quantity.errors }} 40 |
    41 |
    42 | 43 |
    44 | 45 | {% render_field form.price|add_class:'form-control'|add_error_class:"is-invalid" %} 46 |
    47 | {{ form.price.errors }} 48 |
    49 |
    50 | 51 |
    52 | 53 | {% render_field form.sku|add_class:'form-control'|add_error_class:"is-invalid" %} 54 |
    55 | {{ form.sku.errors }} 56 |
    57 |
    58 | 59 | 60 | 61 | {% endwith %} 62 |
    63 | 64 | {% endblock content %} 65 | -------------------------------------------------------------------------------- /wms/stock/templates/stock/shipment_update_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | {% load widget_tweaks %} 3 | 4 | {% block content %} 5 | 6 | 7 |
    8 |
    9 |
    10 |
    11 | 12 | 13 | 14 |

    15 | 16 | Edit {{object.name}} 17 |

    18 | 19 |
    20 |
    21 |
    22 |
    23 | 24 | 25 |
    26 | {% csrf_token %} 27 | {% with WIDGET_ERROR_CLASS='is-invalid' WIDGET_REQUIRED_CLASS="required" %} 28 | 29 |
    30 | 31 | {% render_field form.customer|add_class:'form-control'|add_error_class:"is-invalid" %} 32 |
    33 | {{ form.customer.errors }} 34 |
    35 |
    36 | 37 |
    38 | 39 | {% render_field form.destination|add_class:'form-control'|add_error_class:"is-invalid" %} 40 |
    41 | {{ form.destination.errors }} 42 |
    43 |
    44 | 45 |
    46 | 47 | {% render_field form.product|add_class:'form-control'|add_error_class:"is-invalid" %} 48 |
    49 | {{ form.product.errors }} 50 |
    51 |
    52 | 53 |
    54 | 55 | {% render_field form.quantity|add_class:'form-control'|add_error_class:"is-invalid" %} 56 |
    57 | {{ form.quantity.errors }} 58 |
    59 |
    60 | 61 | 62 | 63 | {% endwith %} 64 |
    65 | {% endblock content %} 66 | -------------------------------------------------------------------------------- /wms/stock/templates/stock/shipment_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | 3 | {% block content %} 4 |
    5 |
    6 | 7 | 8 |

    9 | {{ user.profile.warehouse }} Products 10 |

    11 | 12 | 13 |

    14 | {{ user }} 15 |

    16 | 17 |
    18 |
    19 | 20 |
    22 | 23 | 24 | 25 | 28 | 31 | 34 | 37 | 40 | 43 | 46 | 47 | 48 | 49 | {% for shipment in shipments %} 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {% endfor %} 60 | 61 |
    26 | # 27 | 29 | Customer 30 | 32 | Product 33 | 35 | Quantity 36 | 38 | Destination 39 | 41 | Delete 42 | 44 | Update 45 |
    {{ shipment.id }}{{ shipment.customer }}{{ shipment.product }}{{ shipment.quantity }}{{ shipment.destination }}
    62 |
    63 | 64 | 65 | {% endblock content %} -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ###### Warehouse Management Software Built With React and Django 2 | 3 | 4 | 5 | ### Dashboard Homepage 6 | ![](https://res.cloudinary.com/practicaldev/image/fetch/s--24aTo1kF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gl1ylklhiegp5fuckmzv.png) 7 | 8 | ### Shipment Creation Page 9 | ![](https://res.cloudinary.com/practicaldev/image/fetch/s--pArJKj8P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/t4eewisrshm5wbk0hx90.png) 10 | 11 | ![](https://res.cloudinary.com/practicaldev/image/fetch/s--fg960Mld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m60quk032kyxlh1ciaff.png) 12 | 13 | **Backend - Django** 14 | 15 | 1. Clone this repository 16 | 2. `git clone https://github.com/Nyamador/wms` 17 | 3. Create a virtual environment with virtualenv `virtual {your-virtual-environment-name}` 18 | 4. Activate your virtual environment , from your virtual environment root `.\Scripts\activate` 19 | 5. Go back to your project root where the `requirements.txt` lives 20 | 6. Install dependencies `pip install -r requirements.txt` 21 | 7. `cd wms` 22 | 8. Run your migrations => `manage.py makemigrations` then `manage.py migrate` 23 | 9. Run the project `python manage.py runserver` 24 | 25 | 26 | **Frontend - Reaact** 27 | 1. cd `wms-frontend` 28 | 2. If you prefer using `npm` -> Run `npm i` or `yarn add` for Yarn 29 | 30 | **Redis - Caching** 31 | 1. Download Redis From The Official Website ( You need Redis > 3.x.x ) 32 | 2. If you run windows download the Binary (Not Official) from this link [Redis Windows Binary 3.2.100](https://github-production-release-asset-2e65be.s3.amazonaws.com/3402186/bb47f4a2-3fac-11e6-9e71-9a4261699bd5?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20200609%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200609T073851Z&X-Amz-Expires=300&X-Amz-Signature=46ff45abdcac77c3992179d4f5e4d8af73a988638f04fa93d5c4e40f456506fe&X-Amz-SignedHeaders=host&actor_id=48738520&repo_id=3402186&response-content-disposition=attachment%3B%20filename%3DRedis-x64-3.2.100.zip&response-content-type=application%2Foctet-stream) 33 | 3. If you want be able to run the Redis-Server with `redis-server` without having to open the \bin directory of the binary everytime, add it to your path. You should be able to start the server with `redis-server`. 34 | 4. To verify the server is running open another terminal window and run `redis-cli`, then enter `PING`. You should see `PONG` on your screen. 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # virtualenv 10 | env/ 11 | .env/ 12 | 13 | # Distribution / packaging 14 | .Python 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | pip-wheel-metadata/ 28 | share/python-wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | MANIFEST 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | *.py,cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | 78 | # PyBuilder 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 99 | __pypackages__/ 100 | 101 | # Celery stuff 102 | celerybeat-schedule 103 | celerybeat.pid 104 | 105 | # SageMath parsed files 106 | *.sage.py 107 | 108 | # Environments 109 | .env 110 | .venv 111 | env/ 112 | venv/ 113 | ENV/ 114 | env.bak/ 115 | venv.bak/ 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # mkdocs documentation 125 | /site 126 | 127 | # mypy 128 | .mypy_cache/ 129 | .dmypy.json 130 | dmypy.json 131 | 132 | # Pyre type checker 133 | .pyre/ 134 | -------------------------------------------------------------------------------- /wms-frontend/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /wms-frontend/src/Pages/CreateProductPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Header from '../common/Header'; 3 | import InputElement from '../common/InputElement'; 4 | 5 | 6 | 7 | const CreateProductPage = () => { 8 | 9 | return ( 10 | 11 |
    12 | 13 |
    14 |
    15 |
    16 | 17 |
    18 |
    19 |
    20 |
    21 | 22 | 23 | 24 |

    25 | 26 | Add a product 27 |

    28 | 29 |
    30 |
    31 |
    32 |
    33 | 34 | 35 |
    36 | 37 | 38 |
    39 | 40 | 41 |
    42 | 43 |
    44 |
    45 | 46 |
    47 | 48 | 49 |
    50 | 51 |
    52 |
    53 | 54 |
    55 | 56 | 57 |
    58 | 59 |
    60 |
    61 | 62 |
    63 | 64 | 65 |
    66 | 67 |
    68 |
    69 | 70 | 71 | 72 | 73 |
    74 | 75 | 76 |
    77 |
    78 |
    79 | 80 | ) 81 | } 82 | 83 | 84 | export default CreateProductPage; -------------------------------------------------------------------------------- /wms/users/templates/account/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | {% load widget_tweaks %} 3 | {% load static %} 4 | 5 | {% load i18n %} 6 | 7 | {% block head_title %}{% trans "Signup" %}{% endblock %} 8 | {% block extra_head %} 9 | 10 | {% endblock extra_head %} 11 | 12 | 13 | {% block content %} 14 |

    {% trans "Sign Up" %}

    15 | 16 | {% if form.non_field_errors %} 17 | {% for error in form.non_field_errors %} 18 | 24 | {% endfor %} 25 | {% endif %} 26 | 54 | 55 | {% endblock %} 56 | 57 | 58 | {% block extra_js %} 59 | 60 | {% endblock extra_js %} -------------------------------------------------------------------------------- /wms/users/templates/account/password_reset_from_key.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | {% load widget_tweaks %} 3 | 4 | {% load i18n %} 5 | {% block head_title %}{% trans "Change Password" %}{% endblock %} 6 | 7 | {% block content %} 8 |

    {% if token_fail %}{% trans "Bad Token" %}{% else %}{% trans "Change Password" %}{% endif %}

    9 | 10 | {% if token_fail %} 11 | {% url 'account_reset_password' as passwd_reset_url %} 12 |

    {% blocktrans %}The password reset link was invalid, possibly because it has already been used. Please request a new password reset.{% endblocktrans %}

    13 | {% else %} 14 | {% if form %} 15 |
    16 | {% if form.non_field_errors %} 17 | {% for error in form.non_field_errors %} 18 | 24 | {% endfor %} 25 | {% endif %} 26 | {% csrf_token %} 27 | {% with WIDGET_ERROR_CLASS='is-invalid' %} 28 |
    29 | 30 | {% render_field form.password1|add_class:'form-control'|add_error_class:"is-invalid" %} 31 |
    32 | {{ form.password1.errors }} 33 |
    34 |
    35 | 36 |
    37 | 38 | {% render_field form.password2|add_class:'form-control'|add_error_class:"is-invalid" %} 39 |
    40 | {{ form.password2.errors }} 41 |
    42 |
    43 | {% endwith %} 44 | 45 |
    46 | {% else %} 47 |

    {% trans 'Your password is now changed.' %}

    48 | {% endif %} 49 | {% endif %} 50 | {% endblock %} 51 | -------------------------------------------------------------------------------- /wms-frontend/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `yarn start` 8 | 9 | Runs the app in the development mode.
    10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
    13 | You will also see any lint errors in the console. 14 | 15 | ### `yarn test` 16 | 17 | Launches the test runner in the interactive watch mode.
    18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `yarn build` 21 | 22 | Builds the app for production to the `build` folder.
    23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
    26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `yarn eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `yarn build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /wms/users/templates/account/email.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | {% load widget_tweaks %} 3 | 4 | 5 | {% load i18n %} 6 | 7 | {% block head_title %}{% trans "Account" %}{% endblock %} 8 | 9 | {% block content %} 10 |

    {% trans "E-mail Addresses" %}

    11 | {% if user.emailaddress_set.all %} 12 |

    {% trans 'The following e-mail addresses are associated with your account:' %}

    13 | 14 | 43 | 44 | {% else %} 45 |

    {% trans 'Warning:'%} {% trans "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %}

    46 | 47 | {% endif %} 48 | 49 | 50 |

    {% trans "Add E-mail Address" %}

    51 | 52 |
    53 | {% csrf_token %} 54 | {% with WIDGET_ERROR_CLASS='is-invalid' %} 55 |
    56 | 57 | {% render_field form.email|add_class:'form-control'|add_error_class:"is-invalid" %} 58 |
    59 | {{ form.email.errors }} 60 |
    61 |
    62 | {% endwith %} 63 | 64 |
    65 | 66 | {% endblock %} 67 | 68 | 69 | {% block extra_body %} 70 | 83 | {% endblock %} 84 | -------------------------------------------------------------------------------- /wms/stock/templates/stock/ShipmentCreation.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | {% load widget_tweaks %} 3 | 4 | 5 | {% block content %} 6 |
    7 |
    8 |
    9 |
    10 | 11 | 12 | 13 |

    14 | 15 | Create A New Shipment 16 |

    17 | 18 |
    19 |
    20 |
    21 |
    22 | 23 |
    24 | {% csrf_token %} 25 | {% with WIDGET_ERROR_CLASS='is-invalid' WIDGET_REQUIRED_CLASS="required" %} 26 | 27 |
    28 |
    29 | 30 | {% render_field form.customer|add_class:'form-control'|add_error_class:"is-invalid" %} 31 |
    32 | {{ form.customer.errors }} 33 |
    34 |
    35 |
    36 | 37 |
    38 |
    39 | 40 | {% render_field form.destination|add_class:'form-control'|add_error_class:"is-invalid" %} 41 |
    42 | {{ form.destination.errors }} 43 |
    44 |
    45 |
    46 | 47 |
    48 |
    49 | 50 | {% render_field form.product|add_class:'form-control'|add_error_class:"is-invalid" %} 51 |
    52 | {{ form.product.errors }} 53 |
    54 |
    55 |
    56 | 57 |
    58 |
    59 | 60 | {% render_field form.quantity|add_class:'form-control'|add_error_class:"is-invalid" %} 61 |
    62 | {{ form.quantity.errors }} 63 |
    64 |
    65 |
    66 | 67 | {% endwith %} 68 |
    69 | 70 | 71 | {% endblock content %} -------------------------------------------------------------------------------- /wms-frontend/src/Pages/LoginPage.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import {Redirect} from 'react-router-dom' 3 | import axiosInstance from '../axiosInstance'; 4 | 5 | const LoginPage = () => { 6 | const [email, setEmail] = useState(''); 7 | const [password, setPassword] = useState(''); 8 | const [isLoggedIn, setisLoggedIn] = useState(false) 9 | 10 | useEffect(() => { 11 | 12 | }); 13 | 14 | const handleEmailChange = (event) => { 15 | setEmail(event.target.value); 16 | }; 17 | 18 | const handlePasswordChange = (event) => { 19 | setPassword(event.target.value); 20 | }; 21 | 22 | const handleSubmit = async (event) => { 23 | event.preventDefault(); 24 | try{ 25 | const response = await axiosInstance.post('/api/token',{ 26 | email: email, 27 | password: password 28 | }); 29 | axiosInstance.defaults.headers['Authorization'] = "JWT" + response.data.access; 30 | localStorage.setItem('access_token', response.data.access); 31 | localStorage.setItem('refresh_token', response.data.refresh); 32 | setisLoggedIn(true); 33 | }catch(error){ 34 | setisLoggedIn(false); 35 | throw error; 36 | } 37 | }; 38 | 39 | return isLoggedIn ? : ( 40 |
    41 |
    42 |
    43 |

    Sign In

    44 | 45 |
    46 |
    47 | 48 | 58 |
    59 |
    60 |
    61 |
    62 |
    63 | 64 |
    65 | 73 |
    74 | 75 |
    76 | 86 |
    87 | 88 | 89 | 90 |
    91 |
    92 |
    93 | 94 | 100 |
    101 | 102 | Don"t have an account yet?{' '} 103 | Sign up . 104 | 105 |
    106 |
    107 |
    108 |
    109 |
    110 | ); 111 | }; 112 | 113 | export default LoginPage; 114 | -------------------------------------------------------------------------------- /wms/users/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.3 on 2020-02-15 10:38 2 | 3 | from django.conf import settings 4 | import django.contrib.auth.validators 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | import django.utils.timezone 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | ('auth', '0011_update_proxy_permissions'), 16 | ('stock', '0001_initial'), 17 | ] 18 | 19 | operations = [ 20 | migrations.CreateModel( 21 | name='stockUser', 22 | fields=[ 23 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 24 | ('password', models.CharField(max_length=128, verbose_name='password')), 25 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), 26 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), 27 | ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), 28 | ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')), 29 | ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), 30 | ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), 31 | ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), 32 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), 33 | ('email', models.EmailField(max_length=255, unique=True, verbose_name='Email Adddress')), 34 | ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), 35 | ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), 36 | ], 37 | options={ 38 | 'verbose_name': 'user', 39 | 'verbose_name_plural': 'users', 40 | 'abstract': False, 41 | }, 42 | ), 43 | migrations.CreateModel( 44 | name='Profile', 45 | fields=[ 46 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 47 | ('photo', models.ImageField(default='profilep.jpg', max_length=200, upload_to='profile/%Y/%m/%d/', verbose_name='Profile Photo')), 48 | ('prefix', models.CharField(choices=[('Mr', 'Mr.'), ('Mrs', 'Mrs.'), ('Ms', 'Ms.'), ('Mis', 'Miss.'), ('Mx', 'Mx.'), ('Dr', 'Dr.'), ('Prf', 'Prof.'), ('Rv', 'Rev.')], max_length=5, verbose_name='Prefix')), 49 | ('firstname', models.CharField(max_length=100, verbose_name='First Name')), 50 | ('lastname', models.CharField(max_length=100, verbose_name='Last Name')), 51 | ('cellphone', models.CharField(max_length=20, verbose_name='Mobile Number')), 52 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 53 | ('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.Warehouse')), 54 | ], 55 | ), 56 | ] 57 | -------------------------------------------------------------------------------- /wms-frontend/src/Pages/CreateShipmentPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Header from '../common/Header'; 3 | 4 | 5 | const CreateShipmentPage = () => { 6 | return ( 7 | <> 8 |
    9 | 10 | 11 |
    12 |
    13 |
    14 | 15 |
    16 |
    17 |
    18 |
    19 | 20 | 21 | 22 |

    23 | 24 | Create A New Shipment 25 |

    26 | 27 |
    28 |
    29 |
    30 |
    31 | 32 |
    33 | 34 | 35 |
    36 |
    37 | 38 | 52 |
    53 | 54 |
    55 |
    56 |
    57 | 58 |
    59 |
    60 | 61 | 62 |
    63 | 64 |
    65 |
    66 |
    67 | 68 |
    69 |
    70 | 71 | 83 |
    84 | 85 |
    86 |
    87 |
    88 | 89 |
    90 |
    91 | 92 | 93 |
    94 | 95 |
    96 |
    97 |
    98 | 99 | 100 |
    101 | 102 | 103 | 104 |
    105 |
    106 |
    107 | 108 | 109 | ); 110 | } 111 | 112 | export default CreateShipmentPage; -------------------------------------------------------------------------------- /wms/stock/views.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | # from django.core.cache.backends.base import DEFAULT_TIMEOUT 3 | from django.shortcuts import render,reverse,redirect 4 | from django.views.generic.edit import CreateView, DeleteView, UpdateView 5 | from django.views.generic import ListView 6 | from django.contrib.auth.mixins import LoginRequiredMixin 7 | from django.contrib.auth.decorators import login_required 8 | from django.contrib.messages.views import SuccessMessageMixin 9 | from django.contrib import messages 10 | from django.views.decorators.cache import cache_page 11 | 12 | from .forms import ProductCreationForm, CustomerCreationForm, ShipmentCreationForm 13 | from .models import Product, Customer, Shipment 14 | 15 | 16 | # CACHE_TTL = getattr(settings, 'CACHE_TTL', DEFAULT_TIMEOUT) 17 | 18 | @login_required() 19 | def ProductCreationView(request, uuid): 20 | # Form processing 21 | if request.method == 'POST': 22 | # Create an instance of the form 23 | form = ProductCreationForm(request.POST) 24 | if form.is_valid(): 25 | product = form.save(commit=False) 26 | product.user = request.user 27 | product.warehouse = request.user.profile.warehouse 28 | product.save() 29 | messages.success(request, f'{product.name} was created successfully') 30 | # return redirect(reverse('home')) 31 | form = ProductCreationForm() 32 | 33 | context = { 34 | 'form' : form, 35 | } 36 | 37 | return render(request, 'stock/ProductCreation.html', context) 38 | 39 | 40 | class CustomerCreationView(SuccessMessageMixin, LoginRequiredMixin, CreateView): 41 | template_name = 'stock/CustomerCreation.html' 42 | form_class = CustomerCreationForm 43 | success_url = '/' 44 | success_message = "%(firstname)s was created successfully" 45 | 46 | 47 | class ShipmentCreationView(SuccessMessageMixin, LoginRequiredMixin, CreateView): 48 | template_name = 'stock/ShipmentCreation.html' 49 | form_class = ShipmentCreationForm 50 | success_url = '/' 51 | success_message = "%(id)s was created successfully" 52 | 53 | 54 | # List Views 55 | # @cache_page(CACHE_TTL) 56 | def CachedProductListView(request): 57 | products = Product.objects.all() 58 | context = { 59 | 'products': products 60 | } 61 | return render(request, 'stock/product_list.html', context) 62 | 63 | class ProductListView(ListView, LoginRequiredMixin): 64 | template_name = "stock/ProductListView" 65 | queryset = Product.objects.all() 66 | context_object_name = "products" 67 | 68 | class CustomerListView(ListView, LoginRequiredMixin): 69 | template_name = "stock/CustomerListView" 70 | queryset = Customer.objects.all() 71 | context_object_name = "customers" 72 | 73 | class ShipmentListView(ListView, LoginRequiredMixin): 74 | template_name = "stock/shipment_list.html" 75 | queryset = Shipment.objects.all() 76 | context_object_name = "shipments" 77 | 78 | 79 | #Delete Views 80 | class ProductDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView): 81 | model = Product 82 | context_object_name = "product" 83 | pk_url_kwarg = 'id' 84 | success_url = '/' 85 | template_name = 'stock/ProductDelete.html' 86 | success_message = "%(product)s was deleted successfully" 87 | 88 | class CustomerDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView): 89 | model = Customer 90 | context_object_name = "customer" 91 | pk_url_kwarg = 'id' 92 | success_url = '/' 93 | template_name = 'stock/CustomerDelete.html' 94 | success_message = "%(customer)s was deleted successfully" 95 | 96 | class ShipmentDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView): 97 | model = Shipment 98 | context_object_name = "shipment" 99 | pk_url_kwarg = 'id' 100 | success_url = '/' 101 | template_name = 'stock/ShipmentDelete.html' 102 | success_message = "%(shipment)s was deleted successfully" 103 | 104 | 105 | #Update Views 106 | class ProductUpdateView(SuccessMessageMixin, UpdateView): 107 | model = Product 108 | pk_url_kwarg = 'id' 109 | template_name_suffix = '_update_form' 110 | fields = ['name', 'price', 'sku', 'quantity'] 111 | success_url = '/' 112 | success_message = "%(name)s was edited successfully" 113 | 114 | class CustomerUpdateView(SuccessMessageMixin, UpdateView): 115 | model = Customer 116 | pk_url_kwarg = 'id' 117 | template_name_suffix = '_update_form' 118 | fields = ['firstname', 'lastname', 'email'] 119 | success_url = '/' 120 | success_message = "%(name)s was edited successfully" 121 | 122 | class ShipmentUpdateView(SuccessMessageMixin, UpdateView): 123 | model = Shipment 124 | pk_url_kwarg = 'id' 125 | template_name_suffix = '_update_form' 126 | fields = ['customer', 'destination', 'product', 'quantity'] 127 | success_url = '/' 128 | success_message = "%(name)s was edited successfully" 129 | -------------------------------------------------------------------------------- /wms/users/templates/account/login.html: -------------------------------------------------------------------------------- 1 | {% extends "account/base.html" %} 2 | {% load widget_tweaks %} 3 | 4 | {% load i18n %} 5 | {% load account socialaccount %} 6 | 7 | {% block head_title %}{% trans "Sign In" %}{% endblock %} 8 | 9 | 10 | {% if messages %} 11 | {% for message in messages %} 12 | 15 | {% endfor %} 16 | {% endif %} 17 | {% block content %} 18 | 19 | 20 |

    {% trans "Sign In" %}

    21 | 22 | {% get_providers as socialaccount_providers %} 23 | 24 | {% if socialaccount_providers %} 25 |

    {% blocktrans with site.name as site_name %}Please sign in with one 26 | of your existing third party accounts. Or, sign up 27 | for a {{ site_name }} account and sign in below:{% endblocktrans %}

    28 | 29 |
    30 | 31 |
      32 | {% include "socialaccount/snippets/provider_list.html" with process="login" %} 33 |
    34 | 35 | 36 | 37 |
    38 | 39 | {% include "socialaccount/snippets/login_extra.html" %} 40 | 41 | {% else %} 42 | {% endif %} 43 | {% if form.non_field_errors %} 44 | {% for error in form.non_field_errors %} 45 | 51 | {% endfor %} 52 | {% endif %} 53 | 54 | 120 | {% endblock %} 121 | -------------------------------------------------------------------------------- /wms-frontend/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl, { 104 | headers: { 'Service-Worker': 'script' }, 105 | }) 106 | .then(response => { 107 | // Ensure service worker exists, and that we really are getting a JS file. 108 | const contentType = response.headers.get('content-type'); 109 | if ( 110 | response.status === 404 || 111 | (contentType != null && contentType.indexOf('javascript') === -1) 112 | ) { 113 | // No service worker found. Probably a different app. Reload the page. 114 | navigator.serviceWorker.ready.then(registration => { 115 | registration.unregister().then(() => { 116 | window.location.reload(); 117 | }); 118 | }); 119 | } else { 120 | // Service worker found. Proceed as normal. 121 | registerValidSW(swUrl, config); 122 | } 123 | }) 124 | .catch(() => { 125 | console.log( 126 | 'No internet connection found. App is running in offline mode.' 127 | ); 128 | }); 129 | } 130 | 131 | export function unregister() { 132 | if ('serviceWorker' in navigator) { 133 | navigator.serviceWorker.ready 134 | .then(registration => { 135 | registration.unregister(); 136 | }) 137 | .catch(error => { 138 | console.error(error.message); 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /wms/wms/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import timedelta 3 | 4 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 5 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 6 | 7 | 8 | # Quick-start development settings - unsuitable for production 9 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ 10 | 11 | # SECURITY WARNING: keep the secret key used in production secret! 12 | SECRET_KEY = "%@(mp@w9bs7e7=!n)x88nk)$cc^!m62)ca()6+5r6-f9y$ax6n" 13 | 14 | # SECURITY WARNING: don't run with debug turned on in production! 15 | DEBUG = True 16 | 17 | ALLOWED_HOSTS = ["*"] 18 | 19 | 20 | # Application definition 21 | 22 | INSTALLED_APPS = [ 23 | "django.contrib.admin", 24 | "django.contrib.auth", 25 | "django.contrib.contenttypes", 26 | "django.contrib.sessions", 27 | "django.contrib.messages", 28 | "django.contrib.staticfiles", 29 | "django.contrib.sites", 30 | "stock.apps.StockConfig", 31 | "users.apps.UsersConfig", 32 | "pages.apps.PagesConfig", 33 | # 3rd party 34 | "allauth", 35 | "allauth.account", 36 | "allauth.socialaccount", 37 | "widget_tweaks", 38 | "rest_framework", 39 | # 'rest_framework.authtoken', 40 | "corsheaders", 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | "corsheaders.middleware.CorsMiddleware", 45 | "django.middleware.security.SecurityMiddleware", 46 | "django.contrib.sessions.middleware.SessionMiddleware", 47 | "django.middleware.common.CommonMiddleware", 48 | "django.middleware.csrf.CsrfViewMiddleware", 49 | "django.contrib.auth.middleware.AuthenticationMiddleware", 50 | "django.contrib.messages.middleware.MessageMiddleware", 51 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 52 | "wms.middleware.HelloMiddleWare.SimpleMiddleware", 53 | ] 54 | 55 | ROOT_URLCONF = "wms.urls" 56 | 57 | TEMPLATES = [ 58 | { 59 | "BACKEND": "django.template.backends.django.DjangoTemplates", 60 | "DIRS": [], 61 | "APP_DIRS": True, 62 | "OPTIONS": { 63 | "context_processors": [ 64 | "django.template.context_processors.debug", 65 | "django.template.context_processors.request", 66 | "django.contrib.auth.context_processors.auth", 67 | "django.contrib.messages.context_processors.messages", 68 | ], 69 | }, 70 | }, 71 | ] 72 | 73 | WSGI_APPLICATION = "wms.wsgi.application" 74 | 75 | 76 | # Database 77 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases 78 | 79 | DATABASES = { 80 | "default": { 81 | "ENGINE": "django.db.backends.sqlite3", 82 | "NAME": os.path.join(BASE_DIR, "db.sqlite3"), 83 | } 84 | } 85 | 86 | 87 | # Password validation 88 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators 89 | 90 | AUTH_PASSWORD_VALIDATORS = [ 91 | { 92 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 93 | }, 94 | {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",}, 95 | {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",}, 96 | {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",}, 97 | ] 98 | 99 | 100 | # Internationalization 101 | # https://docs.djangoproject.com/en/3.0/topics/i18n/ 102 | 103 | LANGUAGE_CODE = "en-us" 104 | 105 | TIME_ZONE = "UTC" 106 | 107 | USE_I18N = True 108 | 109 | USE_L10N = True 110 | 111 | USE_TZ = True 112 | 113 | 114 | # Static files (CSS, JavaScript, Images) 115 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ 116 | 117 | STATIC_URL = "/static/" 118 | 119 | MEDIA_URL = "/media/" 120 | 121 | STATIC_ROOT = os.path.join(BASE_DIR, "static_root") 122 | 123 | MEDIA_ROOT = os.path.join(BASE_DIR, "media_root") 124 | 125 | 126 | # AllAuth 127 | AUTHENTICATION_BACKENDS = ( 128 | # Needed to login by username in Django admin, regardless of `allauth` 129 | "django.contrib.auth.backends.ModelBackend", 130 | # `allauth` specific authentication methods, such as login by e-mail 131 | "allauth.account.auth_backends.AuthenticationBackend", 132 | ) 133 | 134 | SITE_ID = 1 135 | 136 | AUTH_USER_MODEL = "users.stockUser" 137 | 138 | ACCOUNT_USERNAME_REQUIRED = False 139 | 140 | ACCOUNT_AUTHENTICATION_METHOD = "email" 141 | 142 | ACCOUNT_EMAIL_REQUIRED = True 143 | 144 | ACCOUNT_UNIQUE_EMAIL = True 145 | 146 | ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = False 147 | 148 | if DEBUG: 149 | EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" 150 | 151 | # EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' 152 | 153 | # EMAIL_HOST = 'smtp.sendgrid.net' 154 | 155 | # EMAIL_PORT = 587 156 | 157 | # EMAIL_SUBJECT_PREFIX = 'Magtickets' 158 | 159 | LOGIN_REDIRECT_URL = "home" 160 | 161 | LOGOUT_REDIRECT_URL = "home" 162 | 163 | 164 | # CORS HEADERS 165 | # CORS_ORIGIN_WHITELIST = () 166 | 167 | CACHES = { 168 | "default": { 169 | "BACKEND": "django_redis.cache.RedisCache", 170 | "LOCATION": "redis://127.0.0.1:6379/1", 171 | "OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"}, 172 | "KEY_PREFIX": "wms", 173 | } 174 | } 175 | 176 | CACHE_TTL = 60 * 15 177 | 178 | CORS_ORIGIN_ALLOW_ALL = True 179 | 180 | # CORS_ORIGIN_ALLOW_ALL = False 181 | CORS_ORIGIN_WHITELIST = ("http://127.0.0.1:3000",) 182 | 183 | REST_FRAMEWORK = { 184 | "DEFAULT_AUTHENTICATION_CLASSES": ( 185 | "rest_framework_simplejwt.authentication.JWTAuthentication", 186 | ), 187 | "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning", 188 | } 189 | 190 | SIMPLE_JWT = { 191 | "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), 192 | "REFRESH_TOKEN_LIFETIME": timedelta(days=14), 193 | "ROTATE_REFRESH_TOKENS": True, 194 | "BLACKLIST_AFTER_ROTATION": False, 195 | "ALGORITHM": "HS256", 196 | "SIGNING_KEY": SECRET_KEY, 197 | "VERIFYING_KEY": None, 198 | "AUTH_HEADER_TYPES": ("JWT",), 199 | "USER_ID_FIELD": "id", 200 | "USER_ID_CLAIM": "user_id", 201 | "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",), 202 | "TOKEN_TYPE_CLAIM": "token_type", 203 | } 204 | 205 | -------------------------------------------------------------------------------- /wms-frontend/src/Pages/Homepage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import '../fonts/feather/feather.min.css'; 3 | import Header from '../common/Header'; 4 | import {Link} from 'react-router-dom'; 5 | 6 | 7 | const Homepage = () => { 8 | return ( 9 | <> 10 |
    11 |
    12 |
    13 |
    14 |
    15 |
    16 |

    Warehouse Name

    17 | 18 |

    Welcome - Desmond

    19 |
    20 |
    21 | 22 |
    23 |
    24 |
    25 |
    26 |
    27 |
    28 |
    29 | Total Orders 30 |
    31 | 32 | GHS 200 33 |
    34 |
    35 |
    36 |
    37 |
    38 |
    39 |
    40 | 41 |
    42 |
    43 |
    44 |
    45 |
    46 |
    47 |
    48 | Total Products 49 |
    50 | 51 | 100 52 |
    53 |
    54 | 55 |
    56 |
    57 |
    58 |
    59 |
    60 |
    61 |
    62 |
    63 |
    64 |
    65 |
    66 | Customers 67 |
    68 | 69 |
    70 |
    71 | 20 72 |
    73 |
    74 |
    75 |
    76 | 77 |
    78 |
    79 |
    80 |
    81 |
    82 |
    83 | 84 |
    85 |
    86 |
    87 |
    88 |

    89 |     Shipments 90 |

    91 |
    92 | 93 |
    94 |

    95 | 96 |     97 | Add New 98 | 99 |

    100 |
    101 | 102 |
    103 |

    104 | 105 |     All Shipments 106 | 107 |

    108 |
    109 |
    110 |
    111 | 112 |
    113 |
    114 |
    115 |

    116 |     Products 117 |

    118 |
    119 | 120 |
    121 |

    122 | 123 |     124 | Add New 125 | 126 |

    127 |
    128 | 129 |
    130 |

    131 | 132 |     All Products 133 | 134 |

    135 |
    136 |
    137 |
    138 | 139 |
    140 |
    141 |
    142 |

    143 |    Customers 144 |

    145 |
    146 | 147 |
    148 |

    149 | 150 |     151 | Add New 152 | 153 |

    154 |
    155 | 156 |
    157 |

    158 | 159 |     All Customers 160 | 161 |

    162 |
    163 |
    164 |
    165 |
    166 |
    167 |
    168 |
    169 | 170 | ); 171 | }; 172 | 173 | export default Homepage; 174 | -------------------------------------------------------------------------------- /wms/pages/templates/pages/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'pages/_base.html' %} 2 | {% load cache %} 3 | 4 | 5 | {% block content %} 6 | 7 | 8 | {% if user.profile.is_approved %} 9 | {% cache 500 username %} 10 |
    11 |
    12 | 13 | 14 |

    15 | {{ user.profile.warehouse }} 16 |

    17 | 18 | 19 |

    20 | Welcome - {{ user }} 21 |

    22 | 23 |
    24 |
    25 | {% endcache %} 26 |
    27 | 28 |
    29 | 30 | 31 |
    32 |
    33 |
    34 |
    35 | 36 | 37 |
    38 | Total Orders 39 |
    40 | 41 | 42 | 43 | GHS {{ total_stock_price | floatformat }} 44 | 45 | 46 |
    47 |
    48 | 49 |
    50 |
    51 | 52 |
    53 |
    54 | 55 |
    56 |
    57 | 58 |
    59 |
    60 | 61 | 62 |
    63 |
    64 |
    65 |
    66 | 67 | 68 |
    69 | Total Products 70 |
    71 | 72 | 73 | 74 | {{ product_count }} 75 | 76 | 77 |
    78 |
    79 | 80 | 81 | 82 | 83 |
    84 |
    85 | 86 |
    87 |
    88 | 89 |
    90 |
    91 | 92 | 93 |
    94 |
    95 |
    96 |
    97 | 98 | 99 |
    100 | Customers 101 |
    102 | 103 |
    104 |
    105 | 106 | 107 | 108 | {{ customer_count }} 109 | 110 | 111 |
    112 |
    113 | 114 |
    115 |
    116 | 117 | 118 | 119 | 120 |
    121 |
    122 | 123 |
    124 |
    125 | 126 |
    127 |
    128 | 129 | 130 |
    131 |
    132 |
    133 |
    134 | 135 |

    136 |     137 | Shipments 138 |

    139 | 140 |
    141 | 142 | 143 |
    144 |

    145 | 146 |     147 | Add New 148 | 149 |

    150 |
    151 | 152 | 160 | 161 |
    162 |
    163 | 164 |
    165 |
    166 |
    167 |

    168 |     169 | Products 170 |

    171 | 172 |
    173 | 174 |
    175 |

    176 | 177 |     178 | Add New 179 | 180 |

    181 |
    182 | 183 | 191 | 192 | 193 |
    194 |
    195 | 196 |
    197 |
    198 |
    199 | 200 |

    201 |    202 | Customers 203 |

    204 | 205 |
    206 | 207 | 208 |
    209 |

    210 | 211 |     212 | Add New 213 | 214 |

    215 |
    216 | 217 | 225 | 226 |
    227 |
    228 |
    229 | {% else %} 230 | 231 |
    232 |
    233 | 234 |
    235 | 236 | 237 |
    238 | Aproval error 239 |
    240 | 241 | 242 |

    243 | Your account has not been approved.💔 244 |

    245 | 246 | 247 |

    248 | You might have to contact your administrator. 249 |

    250 | 251 | 252 | 253 | 254 | 255 | 256 |
    257 | 258 |
    259 |
    260 |

    261 | {% endif %} 262 | {% endblock content %} -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/libs/magnific/magnific.min.css: -------------------------------------------------------------------------------- 1 | /* Magnific Popup CSS */ 2 | .mfp-bg { 3 | top: 0; 4 | left: 0; 5 | width: 100%; 6 | height: 100%; 7 | z-index: 1042; 8 | overflow: hidden; 9 | position: fixed; 10 | background: #0b0b0b; 11 | opacity: 0.8; } 12 | 13 | .mfp-wrap { 14 | top: 0; 15 | left: 0; 16 | width: 100%; 17 | height: 100%; 18 | z-index: 1043; 19 | position: fixed; 20 | outline: none !important; 21 | -webkit-backface-visibility: hidden; } 22 | 23 | .mfp-container { 24 | text-align: center; 25 | position: absolute; 26 | width: 100%; 27 | height: 100%; 28 | left: 0; 29 | top: 0; 30 | padding: 0 8px; 31 | box-sizing: border-box; } 32 | 33 | .mfp-container:before { 34 | content: ''; 35 | display: inline-block; 36 | height: 100%; 37 | vertical-align: middle; } 38 | 39 | .mfp-align-top .mfp-container:before { 40 | display: none; } 41 | 42 | .mfp-content { 43 | position: relative; 44 | display: inline-block; 45 | vertical-align: middle; 46 | margin: 0 auto; 47 | text-align: left; 48 | z-index: 1045; } 49 | 50 | .mfp-inline-holder .mfp-content, 51 | .mfp-ajax-holder .mfp-content { 52 | width: 100%; 53 | cursor: auto; } 54 | 55 | .mfp-ajax-cur { 56 | cursor: progress; } 57 | 58 | .mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close { 59 | cursor: -moz-zoom-out; 60 | cursor: -webkit-zoom-out; 61 | cursor: zoom-out; } 62 | 63 | .mfp-zoom { 64 | cursor: pointer; 65 | cursor: -webkit-zoom-in; 66 | cursor: -moz-zoom-in; 67 | cursor: zoom-in; } 68 | 69 | .mfp-auto-cursor .mfp-content { 70 | cursor: auto; } 71 | 72 | .mfp-close, 73 | .mfp-arrow, 74 | .mfp-preloader, 75 | .mfp-counter { 76 | -webkit-user-select: none; 77 | -moz-user-select: none; 78 | user-select: none; } 79 | 80 | .mfp-loading.mfp-figure { 81 | display: none; } 82 | 83 | .mfp-hide { 84 | display: none !important; } 85 | 86 | .mfp-preloader { 87 | color: #CCC; 88 | position: absolute; 89 | top: 50%; 90 | width: auto; 91 | text-align: center; 92 | margin-top: -0.8em; 93 | left: 8px; 94 | right: 8px; 95 | z-index: 1044; } 96 | .mfp-preloader a { 97 | color: #CCC; } 98 | .mfp-preloader a:hover { 99 | color: #FFF; } 100 | 101 | .mfp-s-ready .mfp-preloader { 102 | display: none; } 103 | 104 | .mfp-s-error .mfp-content { 105 | display: none; } 106 | 107 | button.mfp-close, 108 | button.mfp-arrow { 109 | overflow: visible; 110 | cursor: pointer; 111 | background: transparent; 112 | border: 0; 113 | -webkit-appearance: none; 114 | display: block; 115 | outline: none; 116 | padding: 0; 117 | z-index: 1046; 118 | box-shadow: none; 119 | touch-action: manipulation; } 120 | 121 | button::-moz-focus-inner { 122 | padding: 0; 123 | border: 0; } 124 | 125 | .mfp-close { 126 | width: 44px; 127 | height: 44px; 128 | line-height: 44px; 129 | position: absolute; 130 | right: 0; 131 | top: 0; 132 | text-decoration: none; 133 | text-align: center; 134 | opacity: 0.65; 135 | padding: 0 0 18px 10px; 136 | color: #FFF; 137 | font-style: normal; 138 | font-size: 28px; 139 | font-family: Arial, Baskerville, monospace; } 140 | .mfp-close:hover, 141 | .mfp-close:focus { 142 | opacity: 1; } 143 | .mfp-close:active { 144 | top: 1px; } 145 | 146 | .mfp-close-btn-in .mfp-close { 147 | color: #333; } 148 | 149 | .mfp-image-holder .mfp-close, 150 | .mfp-iframe-holder .mfp-close { 151 | color: #FFF; 152 | right: -6px; 153 | text-align: right; 154 | padding-right: 6px; 155 | width: 100%; } 156 | 157 | .mfp-counter { 158 | position: absolute; 159 | top: 0; 160 | right: 0; 161 | color: #CCC; 162 | font-size: 12px; 163 | line-height: 18px; 164 | white-space: nowrap; } 165 | 166 | .mfp-arrow { 167 | position: absolute; 168 | opacity: 0.65; 169 | margin: 0; 170 | top: 50%; 171 | margin-top: -55px; 172 | padding: 0; 173 | width: 90px; 174 | height: 110px; 175 | -webkit-tap-highlight-color: transparent; } 176 | .mfp-arrow:active { 177 | margin-top: -54px; } 178 | .mfp-arrow:hover, 179 | .mfp-arrow:focus { 180 | opacity: 1; } 181 | .mfp-arrow:before, 182 | .mfp-arrow:after { 183 | content: ''; 184 | display: block; 185 | width: 0; 186 | height: 0; 187 | position: absolute; 188 | left: 0; 189 | top: 0; 190 | margin-top: 35px; 191 | margin-left: 35px; 192 | border: medium inset transparent; } 193 | .mfp-arrow:after { 194 | border-top-width: 13px; 195 | border-bottom-width: 13px; 196 | top: 8px; } 197 | .mfp-arrow:before { 198 | border-top-width: 21px; 199 | border-bottom-width: 21px; 200 | opacity: 0.7; } 201 | 202 | .mfp-arrow-left { 203 | left: 0; } 204 | .mfp-arrow-left:after { 205 | border-right: 17px solid #FFF; 206 | margin-left: 31px; } 207 | .mfp-arrow-left:before { 208 | margin-left: 25px; 209 | border-right: 27px solid #3F3F3F; } 210 | 211 | .mfp-arrow-right { 212 | right: 0; } 213 | .mfp-arrow-right:after { 214 | border-left: 17px solid #FFF; 215 | margin-left: 39px; } 216 | .mfp-arrow-right:before { 217 | border-left: 27px solid #3F3F3F; } 218 | 219 | .mfp-iframe-holder { 220 | padding-top: 40px; 221 | padding-bottom: 40px; } 222 | .mfp-iframe-holder .mfp-content { 223 | line-height: 0; 224 | width: 100%; 225 | max-width: 900px; } 226 | .mfp-iframe-holder .mfp-close { 227 | top: -40px; } 228 | 229 | .mfp-iframe-scaler { 230 | width: 100%; 231 | height: 0; 232 | overflow: hidden; 233 | padding-top: 56.25%; } 234 | .mfp-iframe-scaler iframe { 235 | position: absolute; 236 | display: block; 237 | top: 0; 238 | left: 0; 239 | width: 100%; 240 | height: 100%; 241 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); 242 | background: #000; } 243 | 244 | /* Main image in popup */ 245 | img.mfp-img { 246 | width: auto; 247 | max-width: 100%; 248 | height: auto; 249 | display: block; 250 | line-height: 0; 251 | box-sizing: border-box; 252 | padding: 40px 0 40px; 253 | margin: 0 auto; } 254 | 255 | /* The shadow behind the image */ 256 | .mfp-figure { 257 | line-height: 0; } 258 | .mfp-figure:after { 259 | content: ''; 260 | position: absolute; 261 | left: 0; 262 | top: 40px; 263 | bottom: 40px; 264 | display: block; 265 | right: 0; 266 | width: auto; 267 | height: auto; 268 | z-index: -1; 269 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); 270 | background: #444; } 271 | .mfp-figure small { 272 | color: #BDBDBD; 273 | display: block; 274 | font-size: 12px; 275 | line-height: 14px; } 276 | .mfp-figure figure { 277 | margin: 0; } 278 | 279 | .mfp-bottom-bar { 280 | margin-top: -36px; 281 | position: absolute; 282 | top: 100%; 283 | left: 0; 284 | width: 100%; 285 | cursor: auto; } 286 | 287 | .mfp-title { 288 | text-align: left; 289 | line-height: 18px; 290 | color: #F3F3F3; 291 | word-wrap: break-word; 292 | padding-right: 36px; } 293 | 294 | .mfp-image-holder .mfp-content { 295 | max-width: 100%; } 296 | 297 | .mfp-gallery .mfp-image-holder .mfp-figure { 298 | cursor: pointer; } 299 | 300 | @media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) { 301 | /** 302 | * Remove all paddings around the image on small screen 303 | */ 304 | .mfp-img-mobile .mfp-image-holder { 305 | padding-left: 0; 306 | padding-right: 0; } 307 | .mfp-img-mobile img.mfp-img { 308 | padding: 0; } 309 | .mfp-img-mobile .mfp-figure:after { 310 | top: 0; 311 | bottom: 0; } 312 | .mfp-img-mobile .mfp-figure small { 313 | display: inline; 314 | margin-left: 5px; } 315 | .mfp-img-mobile .mfp-bottom-bar { 316 | background: rgba(0, 0, 0, 0.6); 317 | bottom: 0; 318 | margin: 0; 319 | top: auto; 320 | padding: 3px 5px; 321 | position: fixed; 322 | box-sizing: border-box; } 323 | .mfp-img-mobile .mfp-bottom-bar:empty { 324 | padding: 0; } 325 | .mfp-img-mobile .mfp-counter { 326 | right: 5px; 327 | top: 3px; } 328 | .mfp-img-mobile .mfp-close { 329 | top: 0; 330 | right: 0; 331 | width: 35px; 332 | height: 35px; 333 | line-height: 35px; 334 | background: rgba(0, 0, 0, 0.6); 335 | position: fixed; 336 | text-align: center; 337 | padding: 0; } } 338 | 339 | @media all and (max-width: 900px) { 340 | .mfp-arrow { 341 | -webkit-transform: scale(0.75); 342 | transform: scale(0.75); } 343 | .mfp-arrow-left { 344 | -webkit-transform-origin: 0; 345 | transform-origin: 0; } 346 | .mfp-arrow-right { 347 | -webkit-transform-origin: 100%; 348 | transform-origin: 100%; } 349 | .mfp-container { 350 | padding-left: 6px; 351 | padding-right: 6px; } } -------------------------------------------------------------------------------- /wms-frontend/src/fonts/feather/feather.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:Feather;src:url(fonts/Feather.ttf?sdxovp) format("truetype");font-weight:400;font-style:normal}.fe{font-family:Feather!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fe-activity:before{content:"\e900"}.fe-airplay:before{content:"\e901"}.fe-alert-circle:before{content:"\e902"}.fe-alert-octagon:before{content:"\e903"}.fe-alert-triangle:before{content:"\e904"}.fe-align-center:before{content:"\e905"}.fe-align-justify:before{content:"\e906"}.fe-align-left:before{content:"\e907"}.fe-align-right:before{content:"\e908"}.fe-anchor:before{content:"\e909"}.fe-aperture:before{content:"\e90a"}.fe-archive:before{content:"\e90b"}.fe-arrow-down:before{content:"\e90c"}.fe-arrow-down-circle:before{content:"\e90d"}.fe-arrow-down-left:before{content:"\e90e"}.fe-arrow-down-right:before{content:"\e90f"}.fe-arrow-left:before{content:"\e910"}.fe-arrow-left-circle:before{content:"\e911"}.fe-arrow-right:before{content:"\e912"}.fe-arrow-right-circle:before{content:"\e913"}.fe-arrow-up:before{content:"\e914"}.fe-arrow-up-circle:before{content:"\e915"}.fe-arrow-up-left:before{content:"\e916"}.fe-arrow-up-right:before{content:"\e917"}.fe-at-sign:before{content:"\e918"}.fe-award:before{content:"\e919"}.fe-bar-chart:before{content:"\e91a"}.fe-bar-chart-2:before{content:"\e91b"}.fe-battery:before{content:"\e91c"}.fe-battery-charging:before{content:"\e91d"}.fe-bell:before{content:"\e91e"}.fe-bell-off:before{content:"\e91f"}.fe-bluetooth:before{content:"\e920"}.fe-bold:before{content:"\e921"}.fe-book:before{content:"\e922"}.fe-book-open:before{content:"\e923"}.fe-bookmark:before{content:"\e924"}.fe-box:before{content:"\e925"}.fe-briefcase:before{content:"\e926"}.fe-calendar:before{content:"\e927"}.fe-camera:before{content:"\e928"}.fe-camera-off:before{content:"\e929"}.fe-cast:before{content:"\e92a"}.fe-check:before{content:"\e92b"}.fe-check-circle:before{content:"\e92c"}.fe-check-square:before{content:"\e92d"}.fe-chevron-down:before{content:"\e92e"}.fe-chevron-left:before{content:"\e92f"}.fe-chevron-right:before{content:"\e930"}.fe-chevron-up:before{content:"\e931"}.fe-chevrons-down:before{content:"\e932"}.fe-chevrons-left:before{content:"\e933"}.fe-chevrons-right:before{content:"\e934"}.fe-chevrons-up:before{content:"\e935"}.fe-chrome:before{content:"\e936"}.fe-circle:before{content:"\e937"}.fe-clipboard:before{content:"\e938"}.fe-clock:before{content:"\e939"}.fe-cloud:before{content:"\e93a"}.fe-cloud-drizzle:before{content:"\e93b"}.fe-cloud-lightning:before{content:"\e93c"}.fe-cloud-off:before{content:"\e93d"}.fe-cloud-rain:before{content:"\e93e"}.fe-cloud-snow:before{content:"\e93f"}.fe-code:before{content:"\e940"}.fe-codepen:before{content:"\e941"}.fe-command:before{content:"\e942"}.fe-compass:before{content:"\e943"}.fe-copy:before{content:"\e944"}.fe-corner-down-left:before{content:"\e945"}.fe-corner-down-right:before{content:"\e946"}.fe-corner-left-down:before{content:"\e947"}.fe-corner-left-up:before{content:"\e948"}.fe-corner-right-down:before{content:"\e949"}.fe-corner-right-up:before{content:"\e94a"}.fe-corner-up-left:before{content:"\e94b"}.fe-corner-up-right:before{content:"\e94c"}.fe-cpu:before{content:"\e94d"}.fe-credit-card:before{content:"\e94e"}.fe-crop:before{content:"\e94f"}.fe-crosshair:before{content:"\e950"}.fe-database:before{content:"\e951"}.fe-delete:before{content:"\e952"}.fe-disc:before{content:"\e953"}.fe-dollar-sign:before{content:"\e954"}.fe-download:before{content:"\e955"}.fe-download-cloud:before{content:"\e956"}.fe-droplet:before{content:"\e957"}.fe-edit:before{content:"\e958"}.fe-edit-2:before{content:"\e959"}.fe-edit-3:before{content:"\e95a"}.fe-external-link:before{content:"\e95b"}.fe-eye:before{content:"\e95c"}.fe-eye-off:before{content:"\e95d"}.fe-facebook:before{content:"\e95e"}.fe-fast-forward:before{content:"\e95f"}.fe-feather:before{content:"\e960"}.fe-file:before{content:"\e961"}.fe-file-minus:before{content:"\e962"}.fe-file-plus:before{content:"\e963"}.fe-file-text:before{content:"\e964"}.fe-film:before{content:"\e965"}.fe-filter:before{content:"\e966"}.fe-flag:before{content:"\e967"}.fe-folder:before{content:"\e968"}.fe-folder-minus:before{content:"\e969"}.fe-folder-plus:before{content:"\e96a"}.fe-gift:before{content:"\e96b"}.fe-git-branch:before{content:"\e96c"}.fe-git-commit:before{content:"\e96d"}.fe-git-merge:before{content:"\e96e"}.fe-git-pull-request:before{content:"\e96f"}.fe-github:before{content:"\e970"}.fe-gitlab:before{content:"\e971"}.fe-globe:before{content:"\e972"}.fe-grid:before{content:"\e973"}.fe-hard-drive:before{content:"\e974"}.fe-hash:before{content:"\e975"}.fe-headphones:before{content:"\e976"}.fe-heart:before{content:"\e977"}.fe-help-circle:before{content:"\e978"}.fe-home:before{content:"\e979"}.fe-image:before{content:"\e97a"}.fe-inbox:before{content:"\e97b"}.fe-info:before{content:"\e97c"}.fe-instagram:before{content:"\e97d"}.fe-italic:before{content:"\e97e"}.fe-layers:before{content:"\e97f"}.fe-layout:before{content:"\e980"}.fe-life-buoy:before{content:"\e981"}.fe-link:before{content:"\e982"}.fe-link-2:before{content:"\e983"}.fe-linkedin:before{content:"\e984"}.fe-list:before{content:"\e985"}.fe-loader:before{content:"\e986"}.fe-lock:before{content:"\e987"}.fe-log-in:before{content:"\e988"}.fe-log-out:before{content:"\e989"}.fe-mail:before{content:"\e98a"}.fe-map:before{content:"\e98b"}.fe-map-pin:before{content:"\e98c"}.fe-maximize:before{content:"\e98d"}.fe-maximize-2:before{content:"\e98e"}.fe-menu:before{content:"\e98f"}.fe-message-circle:before{content:"\e990"}.fe-message-square:before{content:"\e991"}.fe-mic:before{content:"\e992"}.fe-mic-off:before{content:"\e993"}.fe-minimize:before{content:"\e994"}.fe-minimize-2:before{content:"\e995"}.fe-minus:before{content:"\e996"}.fe-minus-circle:before{content:"\e997"}.fe-minus-square:before{content:"\e998"}.fe-monitor:before{content:"\e999"}.fe-moon:before{content:"\e99a"}.fe-more-horizontal:before{content:"\e99b"}.fe-more-vertical:before{content:"\e99c"}.fe-move:before{content:"\e99d"}.fe-music:before{content:"\e99e"}.fe-navigation:before{content:"\e99f"}.fe-navigation-2:before{content:"\e9a0"}.fe-octagon:before{content:"\e9a1"}.fe-package:before{content:"\e9a2"}.fe-paperclip:before{content:"\e9a3"}.fe-pause:before{content:"\e9a4"}.fe-pause-circle:before{content:"\e9a5"}.fe-percent:before{content:"\e9a6"}.fe-phone:before{content:"\e9a7"}.fe-phone-call:before{content:"\e9a8"}.fe-phone-forwarded:before{content:"\e9a9"}.fe-phone-incoming:before{content:"\e9aa"}.fe-phone-missed:before{content:"\e9ab"}.fe-phone-off:before{content:"\e9ac"}.fe-phone-outgoing:before{content:"\e9ad"}.fe-pie-chart:before{content:"\e9ae"}.fe-play:before{content:"\e9af"}.fe-play-circle:before{content:"\e9b0"}.fe-plus:before{content:"\e9b1"}.fe-plus-circle:before{content:"\e9b2"}.fe-plus-square:before{content:"\e9b3"}.fe-pocket:before{content:"\e9b4"}.fe-power:before{content:"\e9b5"}.fe-printer:before{content:"\e9b6"}.fe-radio:before{content:"\e9b7"}.fe-refresh-ccw:before{content:"\e9b8"}.fe-refresh-cw:before{content:"\e9b9"}.fe-repeat:before{content:"\e9ba"}.fe-rewind:before{content:"\e9bb"}.fe-rotate-ccw:before{content:"\e9bc"}.fe-rotate-cw:before{content:"\e9bd"}.fe-rss:before{content:"\e9be"}.fe-save:before{content:"\e9bf"}.fe-scissors:before{content:"\e9c0"}.fe-search:before{content:"\e9c1"}.fe-send:before{content:"\e9c2"}.fe-server:before{content:"\e9c3"}.fe-settings:before{content:"\e9c4"}.fe-share:before{content:"\e9c5"}.fe-share-2:before{content:"\e9c6"}.fe-shield:before{content:"\e9c7"}.fe-shield-off:before{content:"\e9c8"}.fe-shopping-bag:before{content:"\e9c9"}.fe-shopping-cart:before{content:"\e9ca"}.fe-shuffle:before{content:"\e9cb"}.fe-sidebar:before{content:"\e9cc"}.fe-skip-back:before{content:"\e9cd"}.fe-skip-forward:before{content:"\e9ce"}.fe-slack:before{content:"\e9cf"}.fe-slash:before{content:"\e9d0"}.fe-sliders:before{content:"\e9d1"}.fe-smartphone:before{content:"\e9d2"}.fe-speaker:before{content:"\e9d3"}.fe-square:before{content:"\e9d4"}.fe-star:before{content:"\e9d5"}.fe-stop-circle:before{content:"\e9d6"}.fe-sun:before{content:"\e9d7"}.fe-sunrise:before{content:"\e9d8"}.fe-sunset:before{content:"\e9d9"}.fe-tablet:before{content:"\e9da"}.fe-tag:before{content:"\e9db"}.fe-target:before{content:"\e9dc"}.fe-terminal:before{content:"\e9dd"}.fe-thermometer:before{content:"\e9de"}.fe-thumbs-down:before{content:"\e9df"}.fe-thumbs-up:before{content:"\e9e0"}.fe-toggle-left:before{content:"\e9e1"}.fe-toggle-right:before{content:"\e9e2"}.fe-trash:before{content:"\e9e3"}.fe-trash-2:before{content:"\e9e4"}.fe-trending-down:before{content:"\e9e5"}.fe-trending-up:before{content:"\e9e6"}.fe-triangle:before{content:"\e9e7"}.fe-truck:before{content:"\e9e8"}.fe-tv:before{content:"\e9e9"}.fe-twitter:before{content:"\e9ea"}.fe-type:before{content:"\e9eb"}.fe-umbrella:before{content:"\e9ec"}.fe-underline:before{content:"\e9ed"}.fe-unlock:before{content:"\e9ee"}.fe-upload:before{content:"\e9ef"}.fe-upload-cloud:before{content:"\e9f0"}.fe-user:before{content:"\e9f1"}.fe-user-check:before{content:"\e9f2"}.fe-user-minus:before{content:"\e9f3"}.fe-user-plus:before{content:"\e9f4"}.fe-user-x:before{content:"\e9f5"}.fe-users:before{content:"\e9f6"}.fe-video:before{content:"\e9f7"}.fe-video-off:before{content:"\e9f8"}.fe-voicemail:before{content:"\e9f9"}.fe-volume:before{content:"\e9fa"}.fe-volume-1:before{content:"\e9fb"}.fe-volume-2:before{content:"\e9fc"}.fe-volume-x:before{content:"\e9fd"}.fe-watch:before{content:"\e9fe"}.fe-wifi:before{content:"\e9ff"}.fe-wifi-off:before{content:"\ea00"}.fe-wind:before{content:"\ea01"}.fe-x:before{content:"\ea02"}.fe-x-circle:before{content:"\ea03"}.fe-x-square:before{content:"\ea04"}.fe-youtube:before{content:"\ea05"}.fe-zap:before{content:"\ea06"}.fe-zap-off:before{content:"\ea07"}.fe-zoom-in:before{content:"\ea08"}.fe-zoom-out:before{content:"\ea09"} -------------------------------------------------------------------------------- /wms/pages/static/events/dashboard/fonts/feather/feather.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:Feather;src:url(fonts/Feather.ttf?sdxovp) format("truetype"),url(fonts/Feather.woff?sdxovp) format("woff"),url(fonts/Feather.svg?sdxovp#Feather) format("svg");font-weight:400;font-style:normal}.fe{font-family:Feather!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fe-activity:before{content:"\e900"}.fe-airplay:before{content:"\e901"}.fe-alert-circle:before{content:"\e902"}.fe-alert-octagon:before{content:"\e903"}.fe-alert-triangle:before{content:"\e904"}.fe-align-center:before{content:"\e905"}.fe-align-justify:before{content:"\e906"}.fe-align-left:before{content:"\e907"}.fe-align-right:before{content:"\e908"}.fe-anchor:before{content:"\e909"}.fe-aperture:before{content:"\e90a"}.fe-archive:before{content:"\e90b"}.fe-arrow-down:before{content:"\e90c"}.fe-arrow-down-circle:before{content:"\e90d"}.fe-arrow-down-left:before{content:"\e90e"}.fe-arrow-down-right:before{content:"\e90f"}.fe-arrow-left:before{content:"\e910"}.fe-arrow-left-circle:before{content:"\e911"}.fe-arrow-right:before{content:"\e912"}.fe-arrow-right-circle:before{content:"\e913"}.fe-arrow-up:before{content:"\e914"}.fe-arrow-up-circle:before{content:"\e915"}.fe-arrow-up-left:before{content:"\e916"}.fe-arrow-up-right:before{content:"\e917"}.fe-at-sign:before{content:"\e918"}.fe-award:before{content:"\e919"}.fe-bar-chart:before{content:"\e91a"}.fe-bar-chart-2:before{content:"\e91b"}.fe-battery:before{content:"\e91c"}.fe-battery-charging:before{content:"\e91d"}.fe-bell:before{content:"\e91e"}.fe-bell-off:before{content:"\e91f"}.fe-bluetooth:before{content:"\e920"}.fe-bold:before{content:"\e921"}.fe-book:before{content:"\e922"}.fe-book-open:before{content:"\e923"}.fe-bookmark:before{content:"\e924"}.fe-box:before{content:"\e925"}.fe-briefcase:before{content:"\e926"}.fe-calendar:before{content:"\e927"}.fe-camera:before{content:"\e928"}.fe-camera-off:before{content:"\e929"}.fe-cast:before{content:"\e92a"}.fe-check:before{content:"\e92b"}.fe-check-circle:before{content:"\e92c"}.fe-check-square:before{content:"\e92d"}.fe-chevron-down:before{content:"\e92e"}.fe-chevron-left:before{content:"\e92f"}.fe-chevron-right:before{content:"\e930"}.fe-chevron-up:before{content:"\e931"}.fe-chevrons-down:before{content:"\e932"}.fe-chevrons-left:before{content:"\e933"}.fe-chevrons-right:before{content:"\e934"}.fe-chevrons-up:before{content:"\e935"}.fe-chrome:before{content:"\e936"}.fe-circle:before{content:"\e937"}.fe-clipboard:before{content:"\e938"}.fe-clock:before{content:"\e939"}.fe-cloud:before{content:"\e93a"}.fe-cloud-drizzle:before{content:"\e93b"}.fe-cloud-lightning:before{content:"\e93c"}.fe-cloud-off:before{content:"\e93d"}.fe-cloud-rain:before{content:"\e93e"}.fe-cloud-snow:before{content:"\e93f"}.fe-code:before{content:"\e940"}.fe-codepen:before{content:"\e941"}.fe-command:before{content:"\e942"}.fe-compass:before{content:"\e943"}.fe-copy:before{content:"\e944"}.fe-corner-down-left:before{content:"\e945"}.fe-corner-down-right:before{content:"\e946"}.fe-corner-left-down:before{content:"\e947"}.fe-corner-left-up:before{content:"\e948"}.fe-corner-right-down:before{content:"\e949"}.fe-corner-right-up:before{content:"\e94a"}.fe-corner-up-left:before{content:"\e94b"}.fe-corner-up-right:before{content:"\e94c"}.fe-cpu:before{content:"\e94d"}.fe-credit-card:before{content:"\e94e"}.fe-crop:before{content:"\e94f"}.fe-crosshair:before{content:"\e950"}.fe-database:before{content:"\e951"}.fe-delete:before{content:"\e952"}.fe-disc:before{content:"\e953"}.fe-dollar-sign:before{content:"\e954"}.fe-download:before{content:"\e955"}.fe-download-cloud:before{content:"\e956"}.fe-droplet:before{content:"\e957"}.fe-edit:before{content:"\e958"}.fe-edit-2:before{content:"\e959"}.fe-edit-3:before{content:"\e95a"}.fe-external-link:before{content:"\e95b"}.fe-eye:before{content:"\e95c"}.fe-eye-off:before{content:"\e95d"}.fe-facebook:before{content:"\e95e"}.fe-fast-forward:before{content:"\e95f"}.fe-feather:before{content:"\e960"}.fe-file:before{content:"\e961"}.fe-file-minus:before{content:"\e962"}.fe-file-plus:before{content:"\e963"}.fe-file-text:before{content:"\e964"}.fe-film:before{content:"\e965"}.fe-filter:before{content:"\e966"}.fe-flag:before{content:"\e967"}.fe-folder:before{content:"\e968"}.fe-folder-minus:before{content:"\e969"}.fe-folder-plus:before{content:"\e96a"}.fe-gift:before{content:"\e96b"}.fe-git-branch:before{content:"\e96c"}.fe-git-commit:before{content:"\e96d"}.fe-git-merge:before{content:"\e96e"}.fe-git-pull-request:before{content:"\e96f"}.fe-github:before{content:"\e970"}.fe-gitlab:before{content:"\e971"}.fe-globe:before{content:"\e972"}.fe-grid:before{content:"\e973"}.fe-hard-drive:before{content:"\e974"}.fe-hash:before{content:"\e975"}.fe-headphones:before{content:"\e976"}.fe-heart:before{content:"\e977"}.fe-help-circle:before{content:"\e978"}.fe-home:before{content:"\e979"}.fe-image:before{content:"\e97a"}.fe-inbox:before{content:"\e97b"}.fe-info:before{content:"\e97c"}.fe-instagram:before{content:"\e97d"}.fe-italic:before{content:"\e97e"}.fe-layers:before{content:"\e97f"}.fe-layout:before{content:"\e980"}.fe-life-buoy:before{content:"\e981"}.fe-link:before{content:"\e982"}.fe-link-2:before{content:"\e983"}.fe-linkedin:before{content:"\e984"}.fe-list:before{content:"\e985"}.fe-loader:before{content:"\e986"}.fe-lock:before{content:"\e987"}.fe-log-in:before{content:"\e988"}.fe-log-out:before{content:"\e989"}.fe-mail:before{content:"\e98a"}.fe-map:before{content:"\e98b"}.fe-map-pin:before{content:"\e98c"}.fe-maximize:before{content:"\e98d"}.fe-maximize-2:before{content:"\e98e"}.fe-menu:before{content:"\e98f"}.fe-message-circle:before{content:"\e990"}.fe-message-square:before{content:"\e991"}.fe-mic:before{content:"\e992"}.fe-mic-off:before{content:"\e993"}.fe-minimize:before{content:"\e994"}.fe-minimize-2:before{content:"\e995"}.fe-minus:before{content:"\e996"}.fe-minus-circle:before{content:"\e997"}.fe-minus-square:before{content:"\e998"}.fe-monitor:before{content:"\e999"}.fe-moon:before{content:"\e99a"}.fe-more-horizontal:before{content:"\e99b"}.fe-more-vertical:before{content:"\e99c"}.fe-move:before{content:"\e99d"}.fe-music:before{content:"\e99e"}.fe-navigation:before{content:"\e99f"}.fe-navigation-2:before{content:"\e9a0"}.fe-octagon:before{content:"\e9a1"}.fe-package:before{content:"\e9a2"}.fe-paperclip:before{content:"\e9a3"}.fe-pause:before{content:"\e9a4"}.fe-pause-circle:before{content:"\e9a5"}.fe-percent:before{content:"\e9a6"}.fe-phone:before{content:"\e9a7"}.fe-phone-call:before{content:"\e9a8"}.fe-phone-forwarded:before{content:"\e9a9"}.fe-phone-incoming:before{content:"\e9aa"}.fe-phone-missed:before{content:"\e9ab"}.fe-phone-off:before{content:"\e9ac"}.fe-phone-outgoing:before{content:"\e9ad"}.fe-pie-chart:before{content:"\e9ae"}.fe-play:before{content:"\e9af"}.fe-play-circle:before{content:"\e9b0"}.fe-plus:before{content:"\e9b1"}.fe-plus-circle:before{content:"\e9b2"}.fe-plus-square:before{content:"\e9b3"}.fe-pocket:before{content:"\e9b4"}.fe-power:before{content:"\e9b5"}.fe-printer:before{content:"\e9b6"}.fe-radio:before{content:"\e9b7"}.fe-refresh-ccw:before{content:"\e9b8"}.fe-refresh-cw:before{content:"\e9b9"}.fe-repeat:before{content:"\e9ba"}.fe-rewind:before{content:"\e9bb"}.fe-rotate-ccw:before{content:"\e9bc"}.fe-rotate-cw:before{content:"\e9bd"}.fe-rss:before{content:"\e9be"}.fe-save:before{content:"\e9bf"}.fe-scissors:before{content:"\e9c0"}.fe-search:before{content:"\e9c1"}.fe-send:before{content:"\e9c2"}.fe-server:before{content:"\e9c3"}.fe-settings:before{content:"\e9c4"}.fe-share:before{content:"\e9c5"}.fe-share-2:before{content:"\e9c6"}.fe-shield:before{content:"\e9c7"}.fe-shield-off:before{content:"\e9c8"}.fe-shopping-bag:before{content:"\e9c9"}.fe-shopping-cart:before{content:"\e9ca"}.fe-shuffle:before{content:"\e9cb"}.fe-sidebar:before{content:"\e9cc"}.fe-skip-back:before{content:"\e9cd"}.fe-skip-forward:before{content:"\e9ce"}.fe-slack:before{content:"\e9cf"}.fe-slash:before{content:"\e9d0"}.fe-sliders:before{content:"\e9d1"}.fe-smartphone:before{content:"\e9d2"}.fe-speaker:before{content:"\e9d3"}.fe-square:before{content:"\e9d4"}.fe-star:before{content:"\e9d5"}.fe-stop-circle:before{content:"\e9d6"}.fe-sun:before{content:"\e9d7"}.fe-sunrise:before{content:"\e9d8"}.fe-sunset:before{content:"\e9d9"}.fe-tablet:before{content:"\e9da"}.fe-tag:before{content:"\e9db"}.fe-target:before{content:"\e9dc"}.fe-terminal:before{content:"\e9dd"}.fe-thermometer:before{content:"\e9de"}.fe-thumbs-down:before{content:"\e9df"}.fe-thumbs-up:before{content:"\e9e0"}.fe-toggle-left:before{content:"\e9e1"}.fe-toggle-right:before{content:"\e9e2"}.fe-trash:before{content:"\e9e3"}.fe-trash-2:before{content:"\e9e4"}.fe-trending-down:before{content:"\e9e5"}.fe-trending-up:before{content:"\e9e6"}.fe-triangle:before{content:"\e9e7"}.fe-truck:before{content:"\e9e8"}.fe-tv:before{content:"\e9e9"}.fe-twitter:before{content:"\e9ea"}.fe-type:before{content:"\e9eb"}.fe-umbrella:before{content:"\e9ec"}.fe-underline:before{content:"\e9ed"}.fe-unlock:before{content:"\e9ee"}.fe-upload:before{content:"\e9ef"}.fe-upload-cloud:before{content:"\e9f0"}.fe-user:before{content:"\e9f1"}.fe-user-check:before{content:"\e9f2"}.fe-user-minus:before{content:"\e9f3"}.fe-user-plus:before{content:"\e9f4"}.fe-user-x:before{content:"\e9f5"}.fe-users:before{content:"\e9f6"}.fe-video:before{content:"\e9f7"}.fe-video-off:before{content:"\e9f8"}.fe-voicemail:before{content:"\e9f9"}.fe-volume:before{content:"\e9fa"}.fe-volume-1:before{content:"\e9fb"}.fe-volume-2:before{content:"\e9fc"}.fe-volume-x:before{content:"\e9fd"}.fe-watch:before{content:"\e9fe"}.fe-wifi:before{content:"\e9ff"}.fe-wifi-off:before{content:"\ea00"}.fe-wind:before{content:"\ea01"}.fe-x:before{content:"\ea02"}.fe-x-circle:before{content:"\ea03"}.fe-x-square:before{content:"\ea04"}.fe-youtube:before{content:"\ea05"}.fe-zap:before{content:"\ea06"}.fe-zap-off:before{content:"\ea07"}.fe-zoom-in:before{content:"\ea08"}.fe-zoom-out:before{content:"\ea09"} --------------------------------------------------------------------------------