commit
5f53e16dec
@ -0,0 +1,3 @@
|
||||
db.sqlite3
|
||||
venv/
|
||||
__pycache__/
|
@ -0,0 +1,4 @@
|
||||
rm db.sqlite3 jobs/migrations/00*
|
||||
python manage.py makemigrations
|
||||
python manage.py migrate
|
||||
python manage.py loaddata data.yaml
|
@ -0,0 +1,691 @@
|
||||
- model: jobs.address
|
||||
pk: 1
|
||||
fields:
|
||||
name: Jobsite
|
||||
street_address: 705 Pike St
|
||||
street_address2: ''
|
||||
city: Seattle
|
||||
state: WA
|
||||
zip_code: '98101'
|
||||
- model: jobs.address
|
||||
pk: 2
|
||||
fields:
|
||||
name: American Bridge Company
|
||||
street_address: 1390 Willow Pass Road
|
||||
street_address2: ''
|
||||
city: Concord
|
||||
state: CA
|
||||
zip_code: '94520'
|
||||
- model: jobs.address
|
||||
pk: 3
|
||||
fields:
|
||||
name: American Bridge Kenmore Yard
|
||||
street_address: 6423 NE 175th St
|
||||
street_address2: ''
|
||||
city: Kenmore
|
||||
state: WA
|
||||
zip_code: '98028'
|
||||
- model: jobs.address
|
||||
pk: 4
|
||||
fields:
|
||||
name: American Bridge New Snohomish Yard
|
||||
street_address: 9525 Airport Way
|
||||
street_address2: ''
|
||||
city: Snohomish
|
||||
state: WA
|
||||
zip_code: '98296'
|
||||
- model: jobs.address
|
||||
pk: 5
|
||||
fields:
|
||||
name: American Bridge Office
|
||||
street_address: 1100 Olive Way, Suite 940
|
||||
street_address2: ''
|
||||
city: Seattle
|
||||
state: WA
|
||||
zip_code: '98401'
|
||||
- model: jobs.address
|
||||
pk: 6
|
||||
fields:
|
||||
name: Jobsite
|
||||
street_address: 277 27th Street
|
||||
street_address2: ''
|
||||
city: Oakland
|
||||
state: CA
|
||||
zip_code: '94612'
|
||||
- model: jobs.company
|
||||
pk: 1
|
||||
fields:
|
||||
name: Howard S Wright
|
||||
- model: jobs.company
|
||||
pk: 2
|
||||
fields:
|
||||
name: GBD Architects, Inc
|
||||
- model: jobs.company
|
||||
pk: 3
|
||||
fields:
|
||||
name: KPFF
|
||||
- model: jobs.company
|
||||
pk: 4
|
||||
fields:
|
||||
name: McGinnis Structural
|
||||
- model: jobs.company
|
||||
pk: 5
|
||||
fields:
|
||||
name: Clark / Lease Crutcher Lewis Joint Venture
|
||||
- model: jobs.company
|
||||
pk: 6
|
||||
fields:
|
||||
name: LMN Architects
|
||||
- model: jobs.company
|
||||
pk: 7
|
||||
fields:
|
||||
name: Magnussen Klemencic Associates
|
||||
- model: jobs.company
|
||||
pk: 8
|
||||
fields:
|
||||
name: American Bridge Company
|
||||
- model: jobs.company
|
||||
pk: 9
|
||||
fields:
|
||||
name: Alliance Engineering
|
||||
- model: jobs.company
|
||||
pk: 10
|
||||
fields:
|
||||
name: Holland Partner Group
|
||||
- model: jobs.company
|
||||
pk: 11
|
||||
fields:
|
||||
name: HKS Architects
|
||||
- model: jobs.contact
|
||||
pk: 1
|
||||
fields:
|
||||
name: Brian Petersen
|
||||
email: bpetersen@americanbridge.net
|
||||
company: 8
|
||||
- model: jobs.contact
|
||||
pk: 2
|
||||
fields:
|
||||
name: Paul Prowant
|
||||
email: ''
|
||||
company: 8
|
||||
- model: jobs.contact
|
||||
pk: 3
|
||||
fields:
|
||||
name: Ben Mueller
|
||||
email: ''
|
||||
company: 8
|
||||
- model: jobs.detailer
|
||||
pk: 1
|
||||
fields:
|
||||
name: Peter Ley
|
||||
email: pley@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 2
|
||||
fields:
|
||||
name: Matt Walz
|
||||
email: mwalz@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 3
|
||||
fields:
|
||||
name: Craig Graham
|
||||
email: cgraham@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 4
|
||||
fields:
|
||||
name: Nick Reutzel
|
||||
email: nreutzel@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 5
|
||||
fields:
|
||||
name: Joe Handy
|
||||
email: jhandy@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 6
|
||||
fields:
|
||||
name: Austin Lee
|
||||
email: alee@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 7
|
||||
fields:
|
||||
name: Carl Markley
|
||||
email: cmarkley@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 8
|
||||
fields:
|
||||
name: Brooke Wren
|
||||
email: bwren@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 9
|
||||
fields:
|
||||
name: Tyler Nunn
|
||||
email: tnunn@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 10
|
||||
fields:
|
||||
name: Ray Miller
|
||||
email: rmiller@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 11
|
||||
fields:
|
||||
name: Dennis Dreischmeyer
|
||||
email: dennisd@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 12
|
||||
fields:
|
||||
name: Megan Nyburg
|
||||
email: mnyburg@pacificstair.com
|
||||
- model: jobs.detailer
|
||||
pk: 13
|
||||
fields:
|
||||
name: Dolan Classen
|
||||
email: ''
|
||||
- model: jobs.projectmanager
|
||||
pk: 1
|
||||
fields:
|
||||
name: Scott Mack
|
||||
email: smack@pacificstair.com
|
||||
- model: jobs.projectmanager
|
||||
pk: 2
|
||||
fields:
|
||||
name: Tyler Gardner
|
||||
email: tyler@pacificstair.com
|
||||
- model: jobs.projectmanager
|
||||
pk: 3
|
||||
fields:
|
||||
name: Ken Stodola
|
||||
email: kstodola@pacificstair.com
|
||||
- model: jobs.projectmanager
|
||||
pk: 4
|
||||
fields:
|
||||
name: Jason Mowery
|
||||
email: jmowery@pacificstair.com
|
||||
- model: jobs.projectmanager
|
||||
pk: 5
|
||||
fields:
|
||||
name: Tracey Goettsch
|
||||
email: tracy@pacificstair.com
|
||||
- model: jobs.job
|
||||
pk: 1290
|
||||
fields:
|
||||
name: Washington State Convention Center Addition
|
||||
contractor: 5
|
||||
architect: 6
|
||||
eor: 7
|
||||
customer: 8
|
||||
project_manager: 1
|
||||
award_date: 2018-03-01
|
||||
modeling: true
|
||||
model_upload: ''
|
||||
addresses:
|
||||
- 2
|
||||
- 3
|
||||
- 1
|
||||
- 4
|
||||
- 5
|
||||
contacts:
|
||||
- 3
|
||||
- 1
|
||||
- 2
|
||||
sub_detailers:
|
||||
- 7
|
||||
fab_detailers:
|
||||
- 6
|
||||
engineers:
|
||||
- 9
|
||||
- 4
|
||||
installers: []
|
||||
- model: jobs.job
|
||||
pk: 1360
|
||||
fields:
|
||||
name: 24th & Harrison
|
||||
contractor: 10
|
||||
architect: 11
|
||||
eor: 7
|
||||
customer: 10
|
||||
project_manager: 5
|
||||
award_date: 2019-03-13
|
||||
modeling: false
|
||||
model_upload: ''
|
||||
addresses:
|
||||
- 6
|
||||
contacts: []
|
||||
sub_detailers:
|
||||
- 12
|
||||
fab_detailers:
|
||||
- 13
|
||||
engineers:
|
||||
- 9
|
||||
installers: []
|
||||
- model: jobs.submittal
|
||||
pk: 1
|
||||
fields:
|
||||
job: 1290
|
||||
number: 1
|
||||
- model: jobs.submittal
|
||||
pk: 2
|
||||
fields:
|
||||
job: 1360
|
||||
number: 1
|
||||
- model: auth.permission
|
||||
pk: 1
|
||||
fields:
|
||||
name: Can add address
|
||||
content_type: 1
|
||||
codename: add_address
|
||||
- model: auth.permission
|
||||
pk: 2
|
||||
fields:
|
||||
name: Can change address
|
||||
content_type: 1
|
||||
codename: change_address
|
||||
- model: auth.permission
|
||||
pk: 3
|
||||
fields:
|
||||
name: Can delete address
|
||||
content_type: 1
|
||||
codename: delete_address
|
||||
- model: auth.permission
|
||||
pk: 4
|
||||
fields:
|
||||
name: Can view address
|
||||
content_type: 1
|
||||
codename: view_address
|
||||
- model: auth.permission
|
||||
pk: 5
|
||||
fields:
|
||||
name: Can add company
|
||||
content_type: 2
|
||||
codename: add_company
|
||||
- model: auth.permission
|
||||
pk: 6
|
||||
fields:
|
||||
name: Can change company
|
||||
content_type: 2
|
||||
codename: change_company
|
||||
- model: auth.permission
|
||||
pk: 7
|
||||
fields:
|
||||
name: Can delete company
|
||||
content_type: 2
|
||||
codename: delete_company
|
||||
- model: auth.permission
|
||||
pk: 8
|
||||
fields:
|
||||
name: Can view company
|
||||
content_type: 2
|
||||
codename: view_company
|
||||
- model: auth.permission
|
||||
pk: 9
|
||||
fields:
|
||||
name: Can add contact
|
||||
content_type: 3
|
||||
codename: add_contact
|
||||
- model: auth.permission
|
||||
pk: 10
|
||||
fields:
|
||||
name: Can change contact
|
||||
content_type: 3
|
||||
codename: change_contact
|
||||
- model: auth.permission
|
||||
pk: 11
|
||||
fields:
|
||||
name: Can delete contact
|
||||
content_type: 3
|
||||
codename: delete_contact
|
||||
- model: auth.permission
|
||||
pk: 12
|
||||
fields:
|
||||
name: Can view contact
|
||||
content_type: 3
|
||||
codename: view_contact
|
||||
- model: auth.permission
|
||||
pk: 13
|
||||
fields:
|
||||
name: Can add detailer
|
||||
content_type: 4
|
||||
codename: add_detailer
|
||||
- model: auth.permission
|
||||
pk: 14
|
||||
fields:
|
||||
name: Can change detailer
|
||||
content_type: 4
|
||||
codename: change_detailer
|
||||
- model: auth.permission
|
||||
pk: 15
|
||||
fields:
|
||||
name: Can delete detailer
|
||||
content_type: 4
|
||||
codename: delete_detailer
|
||||
- model: auth.permission
|
||||
pk: 16
|
||||
fields:
|
||||
name: Can view detailer
|
||||
content_type: 4
|
||||
codename: view_detailer
|
||||
- model: auth.permission
|
||||
pk: 17
|
||||
fields:
|
||||
name: Can add job
|
||||
content_type: 5
|
||||
codename: add_job
|
||||
- model: auth.permission
|
||||
pk: 18
|
||||
fields:
|
||||
name: Can change job
|
||||
content_type: 5
|
||||
codename: change_job
|
||||
- model: auth.permission
|
||||
pk: 19
|
||||
fields:
|
||||
name: Can delete job
|
||||
content_type: 5
|
||||
codename: delete_job
|
||||
- model: auth.permission
|
||||
pk: 20
|
||||
fields:
|
||||
name: Can view job
|
||||
content_type: 5
|
||||
codename: view_job
|
||||
- model: auth.permission
|
||||
pk: 21
|
||||
fields:
|
||||
name: Can add project manager
|
||||
content_type: 6
|
||||
codename: add_projectmanager
|
||||
- model: auth.permission
|
||||
pk: 22
|
||||
fields:
|
||||
name: Can change project manager
|
||||
content_type: 6
|
||||
codename: change_projectmanager
|
||||
- model: auth.permission
|
||||
pk: 23
|
||||
fields:
|
||||
name: Can delete project manager
|
||||
content_type: 6
|
||||
codename: delete_projectmanager
|
||||
- model: auth.permission
|
||||
pk: 24
|
||||
fields:
|
||||
name: Can view project manager
|
||||
content_type: 6
|
||||
codename: view_projectmanager
|
||||
- model: auth.permission
|
||||
pk: 25
|
||||
fields:
|
||||
name: Can add stair
|
||||
content_type: 7
|
||||
codename: add_stair
|
||||
- model: auth.permission
|
||||
pk: 26
|
||||
fields:
|
||||
name: Can change stair
|
||||
content_type: 7
|
||||
codename: change_stair
|
||||
- model: auth.permission
|
||||
pk: 27
|
||||
fields:
|
||||
name: Can delete stair
|
||||
content_type: 7
|
||||
codename: delete_stair
|
||||
- model: auth.permission
|
||||
pk: 28
|
||||
fields:
|
||||
name: Can view stair
|
||||
content_type: 7
|
||||
codename: view_stair
|
||||
- model: auth.permission
|
||||
pk: 29
|
||||
fields:
|
||||
name: Can add submittal
|
||||
content_type: 8
|
||||
codename: add_submittal
|
||||
- model: auth.permission
|
||||
pk: 30
|
||||
fields:
|
||||
name: Can change submittal
|
||||
content_type: 8
|
||||
codename: change_submittal
|
||||
- model: auth.permission
|
||||
pk: 31
|
||||
fields:
|
||||
name: Can delete submittal
|
||||
content_type: 8
|
||||
codename: delete_submittal
|
||||
- model: auth.permission
|
||||
pk: 32
|
||||
fields:
|
||||
name: Can view submittal
|
||||
content_type: 8
|
||||
codename: view_submittal
|
||||
- model: auth.permission
|
||||
pk: 33
|
||||
fields:
|
||||
name: Can add stair revision
|
||||
content_type: 9
|
||||
codename: add_stairrevision
|
||||
- model: auth.permission
|
||||
pk: 34
|
||||
fields:
|
||||
name: Can change stair revision
|
||||
content_type: 9
|
||||
codename: change_stairrevision
|
||||
- model: auth.permission
|
||||
pk: 35
|
||||
fields:
|
||||
name: Can delete stair revision
|
||||
content_type: 9
|
||||
codename: delete_stairrevision
|
||||
- model: auth.permission
|
||||
pk: 36
|
||||
fields:
|
||||
name: Can view stair revision
|
||||
content_type: 9
|
||||
codename: view_stairrevision
|
||||
- model: auth.permission
|
||||
pk: 37
|
||||
fields:
|
||||
name: Can add job note
|
||||
content_type: 10
|
||||
codename: add_jobnote
|
||||
- model: auth.permission
|
||||
pk: 38
|
||||
fields:
|
||||
name: Can change job note
|
||||
content_type: 10
|
||||
codename: change_jobnote
|
||||
- model: auth.permission
|
||||
pk: 39
|
||||
fields:
|
||||
name: Can delete job note
|
||||
content_type: 10
|
||||
codename: delete_jobnote
|
||||
- model: auth.permission
|
||||
pk: 40
|
||||
fields:
|
||||
name: Can view job note
|
||||
content_type: 10
|
||||
codename: view_jobnote
|
||||
- model: auth.permission
|
||||
pk: 41
|
||||
fields:
|
||||
name: Can add log entry
|
||||
content_type: 11
|
||||
codename: add_logentry
|
||||
- model: auth.permission
|
||||
pk: 42
|
||||
fields:
|
||||
name: Can change log entry
|
||||
content_type: 11
|
||||
codename: change_logentry
|
||||
- model: auth.permission
|
||||
pk: 43
|
||||
fields:
|
||||
name: Can delete log entry
|
||||
content_type: 11
|
||||
codename: delete_logentry
|
||||
- model: auth.permission
|
||||
pk: 44
|
||||
fields:
|
||||
name: Can view log entry
|
||||
content_type: 11
|
||||
codename: view_logentry
|
||||
- model: auth.permission
|
||||
pk: 45
|
||||
fields:
|
||||
name: Can add permission
|
||||
content_type: 12
|
||||
codename: add_permission
|
||||
- model: auth.permission
|
||||
pk: 46
|
||||
fields:
|
||||
name: Can change permission
|
||||
content_type: 12
|
||||
codename: change_permission
|
||||
- model: auth.permission
|
||||
pk: 47
|
||||
fields:
|
||||
name: Can delete permission
|
||||
content_type: 12
|
||||
codename: delete_permission
|
||||
- model: auth.permission
|
||||
pk: 48
|
||||
fields:
|
||||
name: Can view permission
|
||||
content_type: 12
|
||||
codename: view_permission
|
||||
- model: auth.permission
|
||||
pk: 49
|
||||
fields:
|
||||
name: Can add group
|
||||
content_type: 13
|
||||
codename: add_group
|
||||
- model: auth.permission
|
||||
pk: 50
|
||||
fields:
|
||||
name: Can change group
|
||||
content_type: 13
|
||||
codename: change_group
|
||||
- model: auth.permission
|
||||
pk: 51
|
||||
fields:
|
||||
name: Can delete group
|
||||
content_type: 13
|
||||
codename: delete_group
|
||||
- model: auth.permission
|
||||
pk: 52
|
||||
fields:
|
||||
name: Can view group
|
||||
content_type: 13
|
||||
codename: view_group
|
||||
- model: auth.permission
|
||||
pk: 53
|
||||
fields:
|
||||
name: Can add user
|
||||
content_type: 14
|
||||
codename: add_user
|
||||
- model: auth.permission
|
||||
pk: 54
|
||||
fields:
|
||||
name: Can change user
|
||||
content_type: 14
|
||||
codename: change_user
|
||||
- model: auth.permission
|
||||
pk: 55
|
||||
fields:
|
||||
name: Can delete user
|
||||
content_type: 14
|
||||
codename: delete_user
|
||||
- model: auth.permission
|
||||
pk: 56
|
||||
fields:
|
||||
name: Can view user
|
||||
content_type: 14
|
||||
codename: view_user
|
||||
- model: auth.permission
|
||||
pk: 57
|
||||
fields:
|
||||
name: Can add content type
|
||||
content_type: 15
|
||||
codename: add_contenttype
|
||||
- model: auth.permission
|
||||
pk: 58
|
||||
fields:
|
||||
name: Can change content type
|
||||
content_type: 15
|
||||
codename: change_contenttype
|
||||
- model: auth.permission
|
||||
pk: 59
|
||||
fields:
|
||||
name: Can delete content type
|
||||
content_type: 15
|
||||
codename: delete_contenttype
|
||||
- model: auth.permission
|
||||
pk: 60
|
||||
fields:
|
||||
name: Can view content type
|
||||
content_type: 15
|
||||
codename: view_contenttype
|
||||
- model: auth.permission
|
||||
pk: 61
|
||||
fields:
|
||||
name: Can add session
|
||||
content_type: 16
|
||||
codename: add_session
|
||||
- model: auth.permission
|
||||
pk: 62
|
||||
fields:
|
||||
name: Can change session
|
||||
content_type: 16
|
||||
codename: change_session
|
||||
- model: auth.permission
|
||||
pk: 63
|
||||
fields:
|
||||
name: Can delete session
|
||||
content_type: 16
|
||||
codename: delete_session
|
||||
- model: auth.permission
|
||||
pk: 64
|
||||
fields:
|
||||
name: Can view session
|
||||
content_type: 16
|
||||
codename: view_session
|
||||
- model: auth.permission
|
||||
pk: 65
|
||||
fields:
|
||||
name: Can add session
|
||||
content_type: 17
|
||||
codename: add_session
|
||||
- model: auth.permission
|
||||
pk: 66
|
||||
fields:
|
||||
name: Can change session
|
||||
content_type: 17
|
||||
codename: change_session
|
||||
- model: auth.permission
|
||||
pk: 67
|
||||
fields:
|
||||
name: Can delete session
|
||||
content_type: 17
|
||||
codename: delete_session
|
||||
- model: auth.permission
|
||||
pk: 68
|
||||
fields:
|
||||
name: Can view session
|
||||
content_type: 17
|
||||
codename: view_session
|
||||
- model: auth.user
|
||||
pk: 1
|
||||
fields:
|
||||
password: pbkdf2_sha256$390000$WCTvDu5CuzaHt3ZHCDHJ4p$YoRBlufp9vIo6EXPymvSijAIrF/9ZD5WUR23hOoUL8s=
|
||||
last_login: 2022-12-29 17:47:01.105541+00:00
|
||||
is_superuser: true
|
||||
username: brian
|
||||
first_name: ''
|
||||
last_name: ''
|
||||
email: bhendricks@pacificstair.com
|
||||
is_staff: true
|
||||
is_active: true
|
||||
date_joined: 2022-12-29 17:21:56.918033+00:00
|
||||
groups: []
|
||||
user_permissions: []
|
@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for dwgstatus project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dwgstatus.settings")
|
||||
|
||||
application = get_asgi_application()
|
@ -0,0 +1,125 @@
|
||||
"""
|
||||
Django settings for dwgstatus project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 4.1.4.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.1/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = "django-insecure-%q_1-ql04zin3dy32cx@gtj_)onxaa1fm9wvvmf+2qhwyz4_&r"
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'jobs',
|
||||
"django.contrib.admin",
|
||||
'django.contrib.admindocs',
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
]
|
||||
|
||||
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",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "dwgstatus.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",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "dwgstatus.wsgi.application"
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.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/4.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = "America/Los_Angeles"
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/
|
||||
|
||||
STATIC_URL = "static/"
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
@ -0,0 +1,22 @@
|
||||
"""dwgstatus URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.1/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
path('', include('jobs.urls')),
|
||||
path("admin/", admin.site.urls),
|
||||
]
|
@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for dwgstatus project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dwgstatus.settings")
|
||||
|
||||
application = get_wsgi_application()
|
@ -0,0 +1,194 @@
|
||||
from django.contrib import admin
|
||||
from django.forms.models import BaseInlineFormSet
|
||||
from django import forms
|
||||
|
||||
from .models import (
|
||||
Address,
|
||||
Job,
|
||||
JobNote,
|
||||
Submittal,
|
||||
Stair,
|
||||
StairRevision,
|
||||
Company,
|
||||
Detailer,
|
||||
ProjectManager,
|
||||
Contact,
|
||||
)
|
||||
|
||||
admin.site.site_header = 'Drawing Status admin'
|
||||
admin.site.site_title = 'Drawing Status'
|
||||
|
||||
|
||||
class SubInline(admin.TabularInline):
|
||||
show_change_link = True
|
||||
model = Submittal
|
||||
extra = 1
|
||||
|
||||
|
||||
class JobNoteInline(admin.TabularInline):
|
||||
model = JobNote
|
||||
extra = 0
|
||||
|
||||
|
||||
@admin.register(Job)
|
||||
class JobAdmin(admin.ModelAdmin):
|
||||
list_display = ['number', 'name']
|
||||
list_display_links = ['name']
|
||||
list_filter = [
|
||||
'addresses__state',
|
||||
]
|
||||
search_fields = ['number', 'name', 'addresses']
|
||||
inlines = [SubInline, JobNoteInline]
|
||||
fieldsets = [
|
||||
(None, {
|
||||
'fields': [
|
||||
('number',
|
||||
'name',
|
||||
'award_date',),
|
||||
'addresses',
|
||||
]
|
||||
}),
|
||||
('Client Info', {
|
||||
'fields': [
|
||||
'contractor',
|
||||
'architect',
|
||||
'eor',
|
||||
'customer',
|
||||
'contacts',
|
||||
]
|
||||
}),
|
||||
('In-house Info', {
|
||||
'fields': [
|
||||
'project_manager',
|
||||
('sub_detailers',
|
||||
'fab_detailers',),
|
||||
'engineers',
|
||||
'installers',
|
||||
]
|
||||
}),
|
||||
('Options', {
|
||||
'fields': [
|
||||
'modeling',
|
||||
'model_upload',
|
||||
]
|
||||
}),
|
||||
]
|
||||
autocomplete_fields = [
|
||||
'addresses',
|
||||
'contractor',
|
||||
'architect',
|
||||
'eor',
|
||||
'customer',
|
||||
'contacts',
|
||||
'engineers',
|
||||
'installers',
|
||||
]
|
||||
|
||||
|
||||
class CloneInlineFormset(BaseInlineFormSet):
|
||||
def add_fields(self, form, index):
|
||||
super().add_fields(form, index)
|
||||
form.fields["CLONE"] = forms.BooleanField(required=False)
|
||||
|
||||
|
||||
class StackedInlineWithClone(admin.StackedInline):
|
||||
template = "admin/edit_inline/stacked_with_clone.html"
|
||||
formset = CloneInlineFormset
|
||||
|
||||
|
||||
class StairInline(StackedInlineWithClone):
|
||||
model = Stair
|
||||
extra = 0
|
||||
show_change_link = True
|
||||
fieldsets = [
|
||||
(None, {'fields': [
|
||||
('name', 'grid', 'levels', 'stn',),
|
||||
]}),
|
||||
('Flights', {'fields': [
|
||||
'flights',
|
||||
('stringer_type', 'stringer_custom'),
|
||||
('stair_con', 'stair_con_custom',),
|
||||
'stair_qt',
|
||||
]}),
|
||||
('Landings', {'fields': [
|
||||
'landings',
|
||||
('land_con', 'land_con_custom',),
|
||||
'land_qt',
|
||||
]}),
|
||||
('Rails', {'fields': [
|
||||
('rail_type', 'rail_type_custom'),
|
||||
]}),
|
||||
]
|
||||
|
||||
|
||||
class CloneStairInlineMixin():
|
||||
def save_formset(self, request, form, formset, change):
|
||||
ret = super().save_formset(request, form, formset, change)
|
||||
stairs_to_clone = []
|
||||
|
||||
for data in formset.cleaned_data:
|
||||
if isinstance(data.get('id'), Stair):
|
||||
if data.get('CLONE'):
|
||||
stairs_to_clone.append(data.get('id').id)
|
||||
|
||||
for stair in Stair.objects.filter(id__in=stairs_to_clone):
|
||||
stair.id = None
|
||||
stair.save()
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@admin.register(Submittal)
|
||||
class SubmittalAdmin(admin.ModelAdmin, CloneStairInlineMixin):
|
||||
ordering = ['job__number', 'number']
|
||||
inlines = [StairInline]
|
||||
search_fields = ['job__number', 'job__name']
|
||||
autocomplete_fields = ['job']
|
||||
|
||||
|
||||
class StairRevInline(admin.StackedInline):
|
||||
model = StairRevision
|
||||
extra = 0
|
||||
|
||||
|
||||
@admin.register(Stair)
|
||||
class StairAdmin(admin.ModelAdmin):
|
||||
ordering = ['submittal__job__number', 'submittal__number', 'name']
|
||||
autocomplete_fields = ['submittal']
|
||||
search_fields = ['submittal__job__number', 'submittal__job__name']
|
||||
inlines = [StairRevInline]
|
||||
|
||||
|
||||
class Named(admin.ModelAdmin):
|
||||
search_fields = ['name']
|
||||
|
||||
|
||||
@admin.register(Contact)
|
||||
class ContactAdmin(Named):
|
||||
autocomplete_fields = ['company']
|
||||
|
||||
|
||||
admin.site.register(Company, Named)
|
||||
admin.site.register(Detailer, Named)
|
||||
admin.site.register(ProjectManager, Named)
|
||||
|
||||
|
||||
@admin.register(Address)
|
||||
class AddressAdmin(admin.ModelAdmin):
|
||||
list_display = [
|
||||
'name',
|
||||
'street_address',
|
||||
'street_address2',
|
||||
'city',
|
||||
'state',
|
||||
'zip_code',
|
||||
]
|
||||
search_fields = [
|
||||
'name',
|
||||
'street_address',
|
||||
'street_address2',
|
||||
'city',
|
||||
'state',
|
||||
'zip_code',
|
||||
]
|
||||
list_filter = ['city', 'state']
|
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class JobsConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "jobs"
|
@ -0,0 +1,549 @@
|
||||
# Generated by Django 4.1.4 on 2022-12-29 18:09
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Address",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(default="Jobsite", max_length=100)),
|
||||
("street_address", models.CharField(max_length=100)),
|
||||
("street_address2", models.CharField(blank=True, max_length=100)),
|
||||
("city", models.CharField(max_length=100)),
|
||||
(
|
||||
"state",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("AL", "Alabama"),
|
||||
("AK", "Alaska"),
|
||||
("AS", "American Samoa"),
|
||||
("AZ", "Arizona"),
|
||||
("AR", "Arkansas"),
|
||||
("AA", "Armed Forces Americas"),
|
||||
("AE", "Armed Forces Europe"),
|
||||
("AP", "Armed Forces Pacific"),
|
||||
("CA", "California"),
|
||||
("CO", "Colorado"),
|
||||
("CT", "Connecticut"),
|
||||
("DE", "Delaware"),
|
||||
("DC", "District of Columbia"),
|
||||
("FL", "Florida"),
|
||||
("GA", "Georgia"),
|
||||
("GU", "Guam"),
|
||||
("HI", "Hawaii"),
|
||||
("ID", "Idaho"),
|
||||
("IL", "Illinois"),
|
||||
("IN", "Indiana"),
|
||||
("IA", "Iowa"),
|
||||
("KS", "Kansas"),
|
||||
("KY", "Kentucky"),
|
||||
("LA", "Louisiana"),
|
||||
("ME", "Maine"),
|
||||
("MD", "Maryland"),
|
||||
("MA", "Massachusetts"),
|
||||
("MI", "Michigan"),
|
||||
("MN", "Minnesota"),
|
||||
("MS", "Mississippi"),
|
||||
("MO", "Missouri"),
|
||||
("MT", "Montana"),
|
||||
("NE", "Nebraska"),
|
||||
("NV", "Nevada"),
|
||||
("NH", "New Hampshire"),
|
||||
("NJ", "New Jersey"),
|
||||
("NM", "New Mexico"),
|
||||
("NY", "New York"),
|
||||
("NC", "North Carolina"),
|
||||
("ND", "North Dakota"),
|
||||
("MP", "Northern Mariana Islands"),
|
||||
("OH", "Ohio"),
|
||||
("OK", "Oklahoma"),
|
||||
("OR", "Oregon"),
|
||||
("PA", "Pennsylvania"),
|
||||
("PR", "Puerto Rico"),
|
||||
("RI", "Rhode Island"),
|
||||
("SC", "South Carolina"),
|
||||
("SD", "South Dakota"),
|
||||
("TN", "Tennessee"),
|
||||
("TX", "Texas"),
|
||||
("UT", "Utah"),
|
||||
("VT", "Vermont"),
|
||||
("VI", "Virgin Islands"),
|
||||
("VA", "Virginia"),
|
||||
("WA", "Washington"),
|
||||
("WV", "West Virginia"),
|
||||
("WI", "Wisconsin"),
|
||||
("WY", "Wyoming"),
|
||||
],
|
||||
max_length=2,
|
||||
),
|
||||
),
|
||||
("zip_code", models.CharField(max_length=5)),
|
||||
],
|
||||
options={
|
||||
"verbose_name_plural": "addresses",
|
||||
"ordering": ["state", "zip_code", "street_address", "street_address2"],
|
||||
"unique_together": {
|
||||
("street_address", "street_address2", "city", "state", "zip_code")
|
||||
},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Company",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100)),
|
||||
],
|
||||
options={
|
||||
"verbose_name_plural": "companies",
|
||||
"ordering": ["name"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Contact",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("email", models.EmailField(blank=True, max_length=254)),
|
||||
(
|
||||
"company",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT, to="jobs.company"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["name"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Detailer",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("email", models.EmailField(blank=True, max_length=254)),
|
||||
],
|
||||
options={
|
||||
"ordering": ["name"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Job",
|
||||
fields=[
|
||||
("number", models.IntegerField(primary_key=True, serialize=False)),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("award_date", models.DateField()),
|
||||
("modeling", models.BooleanField(verbose_name="3D modeling included")),
|
||||
(
|
||||
"model_upload",
|
||||
models.CharField(
|
||||
blank=True, max_length=200, verbose_name="3D model upload link"
|
||||
),
|
||||
),
|
||||
("addresses", models.ManyToManyField(blank=True, to="jobs.address")),
|
||||
(
|
||||
"architect",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="architect_jobs",
|
||||
to="jobs.company",
|
||||
),
|
||||
),
|
||||
("contacts", models.ManyToManyField(blank=True, to="jobs.contact")),
|
||||
(
|
||||
"contractor",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="contractor_jobs",
|
||||
to="jobs.company",
|
||||
),
|
||||
),
|
||||
(
|
||||
"customer",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="customer_jobs",
|
||||
to="jobs.company",
|
||||
),
|
||||
),
|
||||
(
|
||||
"engineers",
|
||||
models.ManyToManyField(
|
||||
blank=True, related_name="engineer_jobs", to="jobs.company"
|
||||
),
|
||||
),
|
||||
(
|
||||
"eor",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="eor_jobs",
|
||||
to="jobs.company",
|
||||
verbose_name="engineer of record",
|
||||
),
|
||||
),
|
||||
(
|
||||
"fab_detailers",
|
||||
models.ManyToManyField(
|
||||
blank=True, related_name="fab_jobs", to="jobs.detailer"
|
||||
),
|
||||
),
|
||||
(
|
||||
"installers",
|
||||
models.ManyToManyField(
|
||||
blank=True, related_name="installer_jobs", to="jobs.company"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["number"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ProjectManager",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("email", models.EmailField(blank=True, max_length=254)),
|
||||
],
|
||||
options={
|
||||
"ordering": ["name"],
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Stair",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("grid", models.CharField(max_length=100)),
|
||||
("levels", models.CharField(max_length=100)),
|
||||
("flights", models.IntegerField()),
|
||||
(
|
||||
"stringer_type",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("C", "C Channel"),
|
||||
("MC", "MC Channel"),
|
||||
("PL", "Plate"),
|
||||
("CU", "Custom"),
|
||||
],
|
||||
default="PL",
|
||||
max_length=2,
|
||||
),
|
||||
),
|
||||
("stringer_custom", models.CharField(blank=True, max_length=50)),
|
||||
(
|
||||
"stair_con",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("PF", "Pan-filled"),
|
||||
("CP", "Checker"),
|
||||
("PC", "Precast"),
|
||||
("GT", "Grating"),
|
||||
("CU", "Custom"),
|
||||
("BO", "By other"),
|
||||
],
|
||||
default="PF",
|
||||
max_length=2,
|
||||
verbose_name="stair construction",
|
||||
),
|
||||
),
|
||||
(
|
||||
"stair_con_custom",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
max_length=50,
|
||||
verbose_name="custom stair construction",
|
||||
),
|
||||
),
|
||||
("stair_qt", models.BooleanField(verbose_name="stair quiet tread")),
|
||||
("landings", models.IntegerField()),
|
||||
(
|
||||
"land_con",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("PF", "Pan-filled"),
|
||||
("CP", "Checker"),
|
||||
("PC", "Precast"),
|
||||
("GT", "Grating"),
|
||||
("CU", "Custom"),
|
||||
("BO", "By other"),
|
||||
],
|
||||
default="PF",
|
||||
max_length=2,
|
||||
verbose_name="landing construction",
|
||||
),
|
||||
),
|
||||
(
|
||||
"land_con_custom",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
max_length=50,
|
||||
verbose_name="custom landing construction",
|
||||
),
|
||||
),
|
||||
("land_qt", models.BooleanField(verbose_name="landing quiet tread")),
|
||||
(
|
||||
"rail_type",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("1", "100 Pipe"),
|
||||
("2", "200 Pipe"),
|
||||
("3", "300 Rec tube"),
|
||||
("4", "400 Picket"),
|
||||
("5", "500 Mesh"),
|
||||
("6", "600 Cable"),
|
||||
("7", "700 Rod"),
|
||||
("8", "800 Glass"),
|
||||
("C", "Custom"),
|
||||
("B", "By other"),
|
||||
],
|
||||
default="2",
|
||||
max_length=1,
|
||||
),
|
||||
),
|
||||
("rail_type_custom", models.CharField(blank=True, max_length=50)),
|
||||
(
|
||||
"stn",
|
||||
models.CharField(blank=True, max_length=50, verbose_name="STN"),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Submittal",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("number", models.IntegerField()),
|
||||
(
|
||||
"job",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="jobs.job"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="StairRevision",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("number", models.PositiveIntegerField()),
|
||||
(
|
||||
"to_engr",
|
||||
models.DateField(
|
||||
blank=True, null=True, verbose_name="sent to engineer"
|
||||
),
|
||||
),
|
||||
(
|
||||
"due_from_engr",
|
||||
models.DateField(
|
||||
blank=True, null=True, verbose_name="due from engineer"
|
||||
),
|
||||
),
|
||||
(
|
||||
"rec_from_engr",
|
||||
models.DateField(
|
||||
blank=True, null=True, verbose_name="received from engineer"
|
||||
),
|
||||
),
|
||||
("submitted", models.DateField(blank=True, null=True)),
|
||||
(
|
||||
"rec_from_cust",
|
||||
models.DateField(
|
||||
blank=True, null=True, verbose_name="received from customer"
|
||||
),
|
||||
),
|
||||
(
|
||||
"status",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("NS", "Not started"),
|
||||
("IP", "In progress"),
|
||||
("SU", "Submitted"),
|
||||
("RT", "Returned"),
|
||||
],
|
||||
max_length=2,
|
||||
),
|
||||
),
|
||||
(
|
||||
"response",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("NC", "Approved"),
|
||||
("AN", "Approved as noted"),
|
||||
("RR", "Revise and resubmit"),
|
||||
("U", "Update"),
|
||||
],
|
||||
max_length=2,
|
||||
),
|
||||
),
|
||||
("stair_fabs", models.DateField(blank=True, null=True)),
|
||||
("land_fabs", models.DateField(blank=True, null=True)),
|
||||
("rail_fabs", models.DateField(blank=True, null=True)),
|
||||
("embeds_shop", models.DateField(blank=True, null=True)),
|
||||
("stairs_shop", models.DateField(blank=True, null=True)),
|
||||
("lands_shop", models.DateField(blank=True, null=True)),
|
||||
(
|
||||
"stair",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT, to="jobs.stair"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="stair",
|
||||
name="submittal",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="jobs.submittal"
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="PhoneNumber",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(default="Main", max_length=100)),
|
||||
("number", models.CharField(max_length=25)),
|
||||
(
|
||||
"owner",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="jobs.contact"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="JobNote",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("date", models.DateTimeField(auto_now=True)),
|
||||
("note", models.TextField(max_length=1000)),
|
||||
("link", models.CharField(blank=True, max_length=300)),
|
||||
(
|
||||
"job",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="jobs.job"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="job",
|
||||
name="project_manager",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="jobs.projectmanager",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="job",
|
||||
name="sub_detailers",
|
||||
field=models.ManyToManyField(
|
||||
blank=True, related_name="sub_jobs", to="jobs.detailer"
|
||||
),
|
||||
),
|
||||
]
|
@ -0,0 +1,316 @@
|
||||
import datetime
|
||||
from django.db import models
|
||||
from localflavor.us.us_states import STATE_CHOICES
|
||||
|
||||
|
||||
class Address(models.Model):
|
||||
name = models.CharField(max_length=100, default='Jobsite')
|
||||
street_address = models.CharField(max_length=100)
|
||||
street_address2 = models.CharField(max_length=100, blank=True)
|
||||
city = models.CharField(max_length=100)
|
||||
state = models.CharField(max_length=2, choices=STATE_CHOICES)
|
||||
zip_code = models.CharField(max_length=5)
|
||||
|
||||
def location(self):
|
||||
return f'{self.city}, {self.state}'
|
||||
|
||||
def __str__(self):
|
||||
string = f'{self.name}\n{self.street_address}\n'
|
||||
if self.street_address2 != '':
|
||||
string += f'{self.street_address}\n'
|
||||
string += f'{self.location()} {self.zip_code}'
|
||||
return string
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'addresses'
|
||||
unique_together = [[
|
||||
'street_address',
|
||||
'street_address2',
|
||||
'city',
|
||||
'state',
|
||||
'zip_code',
|
||||
]]
|
||||
ordering = ['state', 'zip_code', 'street_address', 'street_address2']
|
||||
|
||||
|
||||
class Company(models.Model):
|
||||
'''A company we do business with'''
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'companies'
|
||||
ordering = ['name']
|
||||
|
||||
|
||||
class Person(models.Model):
|
||||
'''Abstract class representing any person'''
|
||||
name = models.CharField(max_length=100)
|
||||
email = models.EmailField(blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
ordering = ['name']
|
||||
|
||||
|
||||
class Contact(Person):
|
||||
'''A contact at a client company'''
|
||||
company = models.ForeignKey(Company, on_delete=models.PROTECT)
|
||||
|
||||
|
||||
class PhoneNumber(models.Model):
|
||||
'''A phone number for a Contact'''
|
||||
owner = models.ForeignKey(Contact, on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=100, default='Main')
|
||||
number = models.CharField(max_length=25)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.number}'
|
||||
|
||||
|
||||
class Detailer(Person):
|
||||
'''A PSC detailer'''
|
||||
|
||||
|
||||
class ProjectManager(Person):
|
||||
'''A PSC project manager'''
|
||||
|
||||
|
||||
class Job(models.Model):
|
||||
number = models.IntegerField(primary_key=True)
|
||||
name = models.CharField(max_length=100)
|
||||
addresses = models.ManyToManyField(
|
||||
Address,
|
||||
blank=True,
|
||||
)
|
||||
contractor = models.ForeignKey(
|
||||
Company,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='contractor_jobs',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
architect = models.ForeignKey(
|
||||
Company,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='architect_jobs',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
eor = models.ForeignKey(
|
||||
Company,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='eor_jobs',
|
||||
verbose_name='engineer of record',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
customer = models.ForeignKey(
|
||||
Company,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='customer_jobs',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
contacts = models.ManyToManyField(Contact, blank=True)
|
||||
project_manager = models.ForeignKey(
|
||||
ProjectManager,
|
||||
on_delete=models.PROTECT,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
sub_detailers = models.ManyToManyField(
|
||||
Detailer,
|
||||
related_name='sub_jobs',
|
||||
blank=True,
|
||||
)
|
||||
fab_detailers = models.ManyToManyField(
|
||||
Detailer,
|
||||
related_name='fab_jobs',
|
||||
blank=True,
|
||||
)
|
||||
engineers = models.ManyToManyField(
|
||||
Company,
|
||||
related_name='engineer_jobs',
|
||||
blank=True,
|
||||
)
|
||||
installers = models.ManyToManyField(
|
||||
Company,
|
||||
related_name='installer_jobs',
|
||||
blank=True,
|
||||
)
|
||||
award_date = models.DateField()
|
||||
|
||||
def award_plus_8(self):
|
||||
return self.award_date + datetime.timedelta(weeks=8)
|
||||
|
||||
def award_plus_10(self):
|
||||
return self.award_date + datetime.timedelta(weeks=10)
|
||||
|
||||
modeling = models.BooleanField('3D modeling included')
|
||||
model_upload = models.CharField(
|
||||
'3D model upload link',
|
||||
max_length=200,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.number} - {self.name}"
|
||||
|
||||
class Meta:
|
||||
ordering = ['number']
|
||||
|
||||
|
||||
class JobNote(models.Model):
|
||||
job = models.ForeignKey(Job, on_delete=models.CASCADE)
|
||||
date = models.DateTimeField(auto_now=True)
|
||||
note = models.TextField(max_length=1000)
|
||||
link = models.CharField(max_length=300, blank=True)
|
||||
|
||||
|
||||
class Submittal(models.Model):
|
||||
job = models.ForeignKey(Job, on_delete=models.CASCADE)
|
||||
number = models.IntegerField()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.job} sub {self.number}"
|
||||
|
||||
|
||||
class Stair(models.Model):
|
||||
submittal = models.ForeignKey(Submittal, on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=100)
|
||||
grid = models.CharField(max_length=100)
|
||||
levels = models.CharField(max_length=100)
|
||||
flights = models.IntegerField()
|
||||
STRINGER_CHOICES = [
|
||||
('C', 'C Channel'),
|
||||
('MC', 'MC Channel'),
|
||||
('PL', 'Plate'),
|
||||
('CU', 'Custom'),
|
||||
]
|
||||
stringer_type = models.CharField(
|
||||
max_length=2,
|
||||
choices=STRINGER_CHOICES,
|
||||
default='PL',
|
||||
blank=True,
|
||||
)
|
||||
stringer_custom = models.CharField(max_length=50, blank=True)
|
||||
CONSTRUCTION_CHOICES = [
|
||||
('PF', 'Pan-filled'),
|
||||
('CP', 'Checker'),
|
||||
('PC', 'Precast'),
|
||||
('GT', 'Grating'),
|
||||
('CU', 'Custom'),
|
||||
('BO', 'By other'),
|
||||
]
|
||||
stair_con = models.CharField(
|
||||
'stair construction',
|
||||
max_length=2,
|
||||
choices=CONSTRUCTION_CHOICES,
|
||||
default='PF',
|
||||
blank=True,
|
||||
)
|
||||
stair_con_custom = models.CharField(
|
||||
'custom stair construction',
|
||||
max_length=50,
|
||||
blank=True
|
||||
)
|
||||
stair_qt = models.BooleanField('stair quiet tread')
|
||||
landings = models.IntegerField()
|
||||
land_con = models.CharField(
|
||||
'landing construction',
|
||||
max_length=2,
|
||||
choices=CONSTRUCTION_CHOICES,
|
||||
default='PF',
|
||||
blank=True,
|
||||
)
|
||||
land_con_custom = models.CharField(
|
||||
'custom landing construction',
|
||||
max_length=50,
|
||||
blank=True
|
||||
)
|
||||
land_qt = models.BooleanField('landing quiet tread')
|
||||
RAIL_CHOICES = [
|
||||
('1', '100 Pipe'),
|
||||
('2', '200 Pipe'),
|
||||
('3', '300 Rec tube'),
|
||||
('4', '400 Picket'),
|
||||
('5', '500 Mesh'),
|
||||
('6', '600 Cable'),
|
||||
('7', '700 Rod'),
|
||||
('8', '800 Glass'),
|
||||
('C', 'Custom'),
|
||||
('B', 'By other'),
|
||||
]
|
||||
rail_type = models.CharField(
|
||||
max_length=1,
|
||||
choices=RAIL_CHOICES,
|
||||
default='2',
|
||||
blank=True,
|
||||
)
|
||||
rail_type_custom = models.CharField(max_length=50, blank=True)
|
||||
stn = models.CharField('STN', max_length=50, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.submittal} stair {self.name}"
|
||||
|
||||
|
||||
class StairRevision(models.Model):
|
||||
stair = models.ForeignKey(Stair, on_delete=models.PROTECT)
|
||||
number = models.PositiveIntegerField()
|
||||
to_engr = models.DateField(
|
||||
'sent to engineer',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
due_from_engr = models.DateField(
|
||||
'due from engineer',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
rec_from_engr = models.DateField(
|
||||
'received from engineer',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
submitted = models.DateField(blank=True, null=True)
|
||||
rec_from_cust = models.DateField(
|
||||
'received from customer',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
STATUS_CHOICES = [
|
||||
('NS', 'Not started'),
|
||||
('IP', 'In progress'),
|
||||
('SU', 'Submitted'),
|
||||
('RT', 'Returned'),
|
||||
]
|
||||
status = models.CharField(
|
||||
max_length=2,
|
||||
choices=STATUS_CHOICES,
|
||||
)
|
||||
RESPONSE_CHOICES = [
|
||||
('NC', 'Approved'),
|
||||
('AN', 'Approved as noted'),
|
||||
('RR', 'Revise and resubmit'),
|
||||
('U', 'Update'),
|
||||
]
|
||||
response = models.CharField(
|
||||
max_length=2,
|
||||
choices=RESPONSE_CHOICES,
|
||||
blank=True,
|
||||
)
|
||||
stair_fabs = models.DateField(blank=True, null=True)
|
||||
land_fabs = models.DateField(blank=True, null=True)
|
||||
rail_fabs = models.DateField(blank=True, null=True)
|
||||
embeds_shop = models.DateField(blank=True, null=True)
|
||||
stairs_shop = models.DateField(blank=True, null=True)
|
||||
lands_shop = models.DateField(blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.stair} rev {self.number}"
|
@ -0,0 +1,4 @@
|
||||
body {
|
||||
background-color: #dddddd;
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{% load static %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" href="{% static 'jobs/style.css' %}"/>
|
||||
<title>{% block title %}Drawing Status{% endblock %}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Drawing Status</h1>
|
||||
<ul id="menu">
|
||||
<li><a href="/">Job List</a></li>
|
||||
</ul>
|
||||
{% block content %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,66 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{block.super}} | {{ job }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{ job }}</h2>
|
||||
|
||||
<dl id="cust_info">
|
||||
<dt>Addresses</dt>
|
||||
{% for address in job.addresses.all %}
|
||||
<dd>{{ address|linebreaks }}</dd>
|
||||
{% endfor %}
|
||||
|
||||
<dt>Contractor</dt>
|
||||
<dd>{{ job.contractor }}</dd>
|
||||
|
||||
<dt>Architect</dt>
|
||||
<dd>{{ job.architect }}</dd>
|
||||
|
||||
<dt>Engineer of Record</dt>
|
||||
<dd>{{ job.eor }}</dd>
|
||||
|
||||
<dt>Customer</dt>
|
||||
<dd>{{ job.customer }}</dd>
|
||||
|
||||
<dt>Contact{{ job.contacts.all|pluralize }}</dt>
|
||||
{% for contact in job.contacts.all %}
|
||||
<dd><a href="mailto:{{contact.email}}">{{ contact.name }}</a></dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
|
||||
<dl id="award_date">
|
||||
<dt>Award Date</dt>
|
||||
<dd>{{ job.award_date }}</dd>
|
||||
|
||||
<dt>+8 week lead</dt>
|
||||
<dd>{{ job.award_plus_8 }}</dd>
|
||||
|
||||
<dt>+10 week lead</dt>
|
||||
<dd>{{ job.award_plus_10 }}</dd>
|
||||
|
||||
<dt>Current Delta</dt>
|
||||
<dd>{{ job.award_date|timesince }}</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="inhouse_info">
|
||||
<dt>Project Manager</dt>
|
||||
<dd>{{ job.project_manager }}</dd>
|
||||
|
||||
<dt>Submittal Detailer{{ job.sub_detailers.all|pluralize }}</dt>
|
||||
{% for detailer in job.sub_detailers.all %}
|
||||
<dd>{{ detailer }}</dd>
|
||||
{% endfor %}
|
||||
|
||||
<dt>Fab Detailer{{ job.fab_detailers.all|pluralize }}</dt>
|
||||
{% for detailer in job.fab_detailers.all %}
|
||||
<dd>{{ detailer }}</dd>
|
||||
{% endfor %}
|
||||
|
||||
<dt>Engineer{{ job.engineers.all|pluralize }}</dt>
|
||||
{% for egr in job.engineers.all %}
|
||||
<dd>{{ egr }}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
|
||||
{% endblock %}
|
@ -0,0 +1,12 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ block.super }} | Index{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Index</h2>
|
||||
<ul>
|
||||
{% for job in jobs %}
|
||||
<li><a href="{% url 'jobs:detail' job.number %}">{{ job }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = 'jobs'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.IndexView.as_view(), name='index'),
|
||||
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
|
||||
]
|
@ -0,0 +1,17 @@
|
||||
from django.views import generic
|
||||
from .models import Job
|
||||
|
||||
|
||||
class IndexView(generic.ListView):
|
||||
template_name = 'jobs/index.html'
|
||||
context_object_name = 'jobs'
|
||||
|
||||
def get_queryset(self):
|
||||
return Job.objects.all()
|
||||
|
||||
|
||||
class DetailView(generic.DetailView):
|
||||
model = Job
|
||||
template_name = 'jobs/detail.html'
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dwgstatus.settings")
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in new issue