Python物流运输管理系统源代码,基于Django实现,实现了运单录入、发车出库、到货签收、客户签收等基本功能,含测试账号
Python物流运输管理系统源代码,基于Django实现,实现了运单录入、发车出库、到货签收、客户签收等基本功能,含测试账号。拥有较为完善的报表功能和财务管理功能。可以通过后台界面对各个用户进行权限管理。
程序运行截图
核心代码:
""" Django settings for PPWuLiu project. Generated by 'django-admin startproject' using Django 3.1.2. For more information on this file, see https://docs.djangoproject.com/en/3.1/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/3.1/ref/settings/ """ import os from pathlib import Path from django.contrib.messages import constants # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # 创建日志的路径 LOG_PATH = os.path.join(BASE_DIR, "logs") if not os.path.isdir(LOG_PATH): if os.path.isfile(LOG_PATH): os.remove(LOG_PATH) os.makedirs(LOG_PATH) # 启用Django Debug Toolbar ENABLE_DJANGO_TOOLBAR = False # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = os.getenv("DJANGO_TMS_SECRET_KEY") #SECRET_KEY = os.environ["SECRET_KEY"] PBKDF2_ITERATIONS = 3 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ # 'channels', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # 'rest_framework', # 'django_filters', 'wuliu.apps.WuliuConfig', 'utils', ] if DEBUG: try: import django_extensions INSTALLED_APPS.append('django_extensions') # print SQL queries in shell_plus SHELL_PLUS_PRINT_SQL = True except ImportError: pass MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] # Pyinstrument, 暂时不用, 因为Django Debug Toolbar更好用更强大 # if DEBUG: # try: # import pyinstrument # MIDDLEWARE.append('pyinstrument.middleware.ProfilerMiddleware') # except ImportError: # pass # Django Debug Toolbar if ENABLE_DJANGO_TOOLBAR: # debug_toolbar依赖于django.contrib.staticfiles if DEBUG and 'django.contrib.staticfiles' in INSTALLED_APPS: try: import debug_toolbar INSTALLED_APPS.append('debug_toolbar') MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware') # Internal IPs INTERNAL_IPS = [ '127.0.0.1', ] except ImportError: pass ROOT_URLCONF = 'PPWuLiu.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'wuliu.processor.pros' ], }, }, ] WSGI_APPLICATION = 'PPWuLiu.wsgi.application' # Database # https://docs.djangoproject.com/en/3.1/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': os.getenv("DJANGO_TMS_MYSQL_DATABASE_NAME"), 'USER': os.getenv("DJANGO_TMS_MYSQL_USER"), 'PASSWORD': os.getenv("DJANGO_TMS_MYSQL_PASSWORD"), 'HOST': os.getenv("DJANGO_TMS_MYSQL_HOST"), 'PORT': os.getenv("DJANGO_TMS_MYSQL_PORT"), } } # Password validation # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/3.1/topics/i18n/ LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.1/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static") ] # Custom CACHES = { 'default': { # 基于本地内存的缓存 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', } } # 关闭浏览器使会话立即过期 SESSION_EXPIRE_AT_BROWSER_CLOSE = True MESSAGE_TAGS = { constants.ERROR: "danger", } LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse', }, 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'handlers': { 'console': { 'level': 'INFO', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', }, # Unused 'file': { 'level': 'INFO', 'class': 'logging.FileHandler', 'filename': '%s/log.txt' % LOG_PATH, 'encoding': 'utf-8', }, 'request_exceptions': { 'level': 'INFO', 'class': 'logging.FileHandler', 'filename': '%s/request_exceptions.txt' % LOG_PATH, 'encoding': 'utf-8', }, 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' } }, 'loggers': { 'django': { 'handlers': ['console', 'mail_admins'], 'level': 'INFO', }, 'wuliu.apps': { 'handlers': ['request_exceptions'], 'level': 'INFO', 'propagate': True, }, 'utils.common.expire_lru_cache': { 'handlers': ['console'], 'level': 'INFO', 'propagate': True, }, }, } ''' # channels相关配置, 暂时不用 ASGI_APPLICATION = "PPWuLiu.asgi.application" CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { 'hosts': [('127.0.0.1', 6379)], }, }, } '''
commn.py
from functools import wraps from django.shortcuts import redirect from django.http import Http404, HttpResponseForbidden from django.utils import timezone from .models import ( User, Waybill, TransportOut, DepartmentPayment, CargoPricePayment, Permission, PermissionGroup, _get_global_settings, ) from utils.common import ExpireLruCache, model_to_dict_ expire_lru_cache_three_hours = ExpireLruCache(expire_time=timezone.timedelta(hours=3)) expire_lru_cache_one_minute = ExpireLruCache(expire_time=timezone.timedelta(minutes=1)) get_global_settings = expire_lru_cache_three_hours(_get_global_settings) @expire_lru_cache_one_minute def _get_logged_user_by_id(user_id: int) -> User: """ 根据用户名返回用户模型对象 """ return User.objects.get(id=user_id) def get_logged_user(request) -> User: """ 获取已登录的用户对象 """ return _get_logged_user_by_id(request.session["user"]["id"]) def get_logged_user_type(request) -> User.Types: """ 获取已登录的用户的用户类型 """ return get_logged_user(request).get_type @expire_lru_cache_one_minute def _get_user_permissions(user: User) -> set: """ 获取用户拥有的权限, 注意该方法返回的是集合而不是QuerySet """ return set(user.permission.all().values_list("name", flat=True)) def is_logged_user_has_perm(request, perm_name: str) -> bool: """ 检查已登录用户是否具有perm_name权限 :return: True或False """ if not perm_name: return True return perm_name in _get_user_permissions(get_logged_user(request)) def is_logged_user_is_goods_yard(request) -> bool: """ 判断已登录的用户是否属于货场 """ return get_logged_user_type(request) == User.Types.GoodsYard def _gen_permission_tree_list(root_pg_=PermissionGroup.objects.get(father__isnull=True)) -> list: """ 根据所有的权限组和权限的层级结构生成列表, 用于前端渲染 """ tree_list = [] for pg in PermissionGroup.objects.filter(father=root_pg_): tree_list.append({ "id": pg.id, "name": pg.name, "print_name": pg.print_name, "children": _gen_permission_tree_list(pg) }) for p in Permission.objects.filter(father=root_pg_): tree_list.append({ "id": p.id, "name": p.name, "print_name": p.print_name, }) return tree_list PERMISSION_TREE_LIST = _gen_permission_tree_list() def login_required(raise_404=False): """ 自定义装饰器, 用于装饰路由方法 若用户未登录, 则跳转到登录页面 raise_404为True时, 则跳转到404页面 """ def _login_required(func): @wraps(func) def login_check(request, *args, **kwargs): if not request.session.get("user"): if raise_404: raise Http404 return redirect("wuliu:login") return func(request, *args, **kwargs) return login_check return _login_required def check_permission(perm_name: str): """ 自定义装饰器, 用于在请求前检查用户是否具有perm_name权限 若无perm_name权限则跳转至403页面 """ def _check_permission(func): @wraps(func) def perm_check(request, *args, **kwargs): if perm_name and not is_logged_user_has_perm(request, perm_name): return HttpResponseForbidden() return func(request, *args, **kwargs) return perm_check return _check_permission def check_administrator(func): """ 自定义装饰器, 用于在请求前检查用户是否为管理员 若不是管理员则跳转至403页面 """ @wraps(func) def admin_check(request, *args, **kwargs): if not get_logged_user(request).administrator: return HttpResponseForbidden() return func(request, *args, **kwargs) return admin_check def waybill_to_dict(waybill_obj: Waybill) -> dict: """ 将Waybill对象转为字典 """ waybill_dic = model_to_dict_(waybill_obj) waybill_dic["id_"] = waybill_obj.get_full_id waybill_dic["fee_type_id"] = waybill_dic["fee_type"] waybill_dic["fee_type"] = waybill_obj.get_fee_type_display() waybill_dic["status_id"] = waybill_dic["status"] waybill_dic["status"] = waybill_obj.get_status_display() if waybill_obj.return_waybill is not None: waybill_dic["return_waybill"] = waybill_to_dict(waybill_obj.return_waybill) else: waybill_dic["return_waybill"] = None return waybill_dic def transport_out_to_dict(transport_out_obj: TransportOut) -> dict: """ 将TransportOut对象转为字典 """ to_dic = model_to_dict_(transport_out_obj) to_dic["id_"] = transport_out_obj.get_full_id to_dic["status_id"] = to_dic["status"] to_dic["status"] = transport_out_obj.get_status_display() to_dic.update(transport_out_obj.gen_waybills_info()) return to_dic def department_payment_to_dict(department_payment_obj: DepartmentPayment) -> dict: """ 将DepartmentPayment对象转为字典 """ dp_dic = model_to_dict_(department_payment_obj) dp_dic["id_"] = department_payment_obj.get_full_id dp_dic["status_id"] = dp_dic["status"] dp_dic["status"] = department_payment_obj.get_status_display() total_fee_dic = department_payment_obj.gen_total_fee() dp_dic["total_fee_now"] = total_fee_dic["fee_now"] dp_dic["total_fee_sign_for"] = total_fee_dic["fee_sign_for"] dp_dic["total_cargo_price"] = total_fee_dic["cargo_price"] dp_dic["final_total_fee"] = sum(total_fee_dic.values()) return dp_dic def cargo_price_payment_to_dict(cargo_price_payment_obj: CargoPricePayment) -> dict: """ 将CargoPricePayment对象转为字典 """ cpp_dic = model_to_dict_(cargo_price_payment_obj) cpp_dic["id_"] = cargo_price_payment_obj.get_full_id cpp_dic["status_id"] = cpp_dic["status"] cpp_dic["status"] = cargo_price_payment_obj.get_status_display() total_fee_dic = cargo_price_payment_obj.gen_total_fee() cpp_dic["total_cargo_price"] = total_fee_dic["cargo_price"] cpp_dic["total_deduction_fee"] = total_fee_dic["deduction_fee"] cpp_dic["total_cargo_handling_fee"] = total_fee_dic["cargo_handling_fee"] cpp_dic["final_fee"] = ( total_fee_dic["cargo_price"] - total_fee_dic["deduction_fee"] - total_fee_dic["cargo_handling_fee"] ) return cpp_dic
测试数据账号密码如下:
#用户名 密码 用户类型 #csshd 666666 收货点 #csfgs 666666 分公司(到货点) #kj_1 666666 会计(财务部) #zxg_1 666666 货物装卸工1(货台) #zxg_2 666666 货物装卸工2(货台) #pzqqt 88888888 管理员