9 Commits

Author SHA1 Message Date
33ae8fe124 Pagination 2024-04-12 20:50:47 +02:00
d3471d54ea Continue with list 2024-04-11 20:56:10 +02:00
b1ecdd1f0c Base filled up 2024-04-11 16:04:25 +02:00
163f59844f Models 2024-04-11 08:08:28 +02:00
929e16e2ec Models 2024-04-10 22:04:10 +02:00
f06b72343b Reformat 2024-04-07 10:41:21 +02:00
76e81be6bf JS alert toasts 2024-04-07 10:13:41 +02:00
84a34d8049 Local settings 2024-04-07 09:51:49 +02:00
126caff1ba Toast 2024-04-07 09:30:57 +02:00
34 changed files with 14539 additions and 203 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
/.venv
__pycache__
/db.sqlite3
/project/settings_local.py

0
db.template.sqlite3 Normal file
View File

6775
media/postanski-brojevi.csv Normal file

File diff suppressed because it is too large Load Diff

33
poetry.lock generated
View File

@ -52,6 +52,26 @@ files = [
django = ">=3.2"
jinja2 = ">=3"
[[package]]
name = "gunicorn"
version = "21.2.0"
description = "WSGI HTTP Server for UNIX"
optional = false
python-versions = ">=3.5"
files = [
{file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"},
{file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"},
]
[package.dependencies]
packaging = "*"
[package.extras]
eventlet = ["eventlet (>=0.24.1)"]
gevent = ["gevent (>=1.4.0)"]
setproctitle = ["setproctitle"]
tornado = ["tornado (>=0.2)"]
[[package]]
name = "jinja2"
version = "3.1.3"
@ -138,6 +158,17 @@ files = [
{file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
]
[[package]]
name = "packaging"
version = "24.0"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
{file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
]
[[package]]
name = "sqlparse"
version = "0.4.4"
@ -179,4 +210,4 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "5221e53a0bd37605e95d6feb1c511e8a66ea71fbc94c47d0651a1846aea3a6dc"
content-hash = "6c86d5721314c92afa919983780e664a1573ebb7c25a8b54622393b97990e509"

View File

@ -3,4 +3,4 @@ from django.apps import AppConfig
class MainConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "main"
name = "project.main"

View File

@ -0,0 +1,84 @@
# Generated by Django 5.0.4 on 2024-04-10 19:31
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="County",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
],
options={
"db_table": "counties",
"ordering": ["name"],
},
),
migrations.CreateModel(
name="PostOffice",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("zip", models.PositiveIntegerField()),
("name", models.CharField(max_length=100)),
],
options={
"db_table": "post_offices",
"ordering": ["zip"],
},
),
migrations.CreateModel(
name="Area",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
(
"county",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="main.county"
),
),
(
"post_office",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="main.postoffice",
),
),
],
options={
"db_table": "areas",
"ordering": ["name"],
},
),
]

View File

@ -0,0 +1,48 @@
# Generated by Django 5.0.4 on 2024-04-10 19:42
from django.db import migrations
counties = [
'Koprivničko-križevačka',
'Međimurska',
'Dubrovačko-neretvanska',
'Zagrebačka',
'Primorsko-goranska',
'Požeško-slavonska',
'Vukovarsko-srijemska',
'Karlovačka',
'Zadarska',
'Bjelovarsko-bilogorska',
'Splitsko-dalmatinska',
'Virovitičko-podravska',
'Ličko-senjska',
'Grad Zagreb',
'Brodsko-posavska',
'Osječko-baranjska',
'Sisačko-moslavačka',
'Krapinsko-zagorska',
'Istarska',
'Šibensko-kninska',
'Varaždinska',
]
def create_counties(apps, schema_editor):
County = apps.get_model("main", "County")
bulk = []
for county in counties:
bulk.append(County(name=county))
County.objects.bulk_create(bulk)
class Migration(migrations.Migration):
dependencies = [
("main", "0001_initial"),
]
operations = [
migrations.RunPython(create_counties),
]

View File

@ -0,0 +1,333 @@
# Generated by Django 5.0.4 on 2024-04-10 19:59
from django.db import migrations
post_offices = {
10000: 'Zagreb',
10010: 'Zagreb-Sloboština',
10020: 'Zagreb-Novi Zagreb',
10040: 'Zagreb-Dubrava',
10090: 'Zagreb-Susedgrad',
10104: 'Zagreb',
10105: 'Zagreb',
10108: 'Zagreb',
10109: 'Zagreb',
10110: 'Zagreb',
10135: 'Zagreb',
10172: 'Zagreb',
10250: 'Lučko',
10255: 'Gornji Stupnik',
10257: 'Brezovica',
10290: 'Zaprešić',
10291: 'Prigorje Brdovečko',
10292: 'Šenkovec',
10295: 'Kupljenovo',
10297: 'Jakovlje',
10298: 'Bistra',
10310: 'Ivanić Grad',
10315: 'Novoselec',
10340: 'Vrbovec',
10342: 'Dubrava',
10360: 'Sesvete',
10361: 'Sesvete Kraljevec',
10362: 'Kašina',
10370: 'Dugo Selo',
10380: 'Sveti Ivan Zelina',
10410: 'Velika Gorica',
10413: 'Kravarsko',
10414: 'Pokupsko',
10430: 'Samobor',
10431: 'Sveta Nedelja',
10435: 'Sveti Martin pod Okićem',
10437: 'Bestovje',
10450: 'Jastrebarsko',
10451: 'Pisarovina',
10454: 'Krašić',
20000: 'Dubrovnik',
20207: 'Mlini',
20210: 'Cavtat',
20215: 'Gruda',
20221: 'Koločep',
20222: 'Lopud',
20223: 'Šipanska Luka',
20225: 'Babino Polje',
20230: 'Ston',
20232: 'Slano',
20235: 'Zaton Veliki',
20236: 'Mokošica',
20240: 'Trpanj',
20244: 'Potomje',
20246: 'Janjina',
20250: 'Orebić',
20260: 'Korčula',
20270: 'Vela Luka',
20271: 'Blato',
20290: 'Lastovo',
20340: 'Ploče',
20350: 'Metković',
20355: 'Opuzen',
21000: 'Split',
21203: 'Donji Muć',
21204: 'Dugopolje',
21210: 'Solin',
21212: 'Kaštel Sućurac',
21214: 'Kaštel Kambelovac',
21217: 'Kaštel Štafilić',
21220: 'Trogir',
21222: 'Marina',
21225: 'Drvenik Veliki',
21230: 'Sinj',
21240: 'Trilj',
21232: 'Dicmo',
21233: 'Hrvace',
21236: 'Vrlika',
21238: 'Otok (Dalmacija)',
21250: 'Šestanovac',
21256: 'Cista Provo',
21260: 'Imotski',
21270: 'Zagvozd',
21276: 'Vrgorac',
21300: 'Makarska',
21310: 'Omiš',
21311: 'Stobreč',
21315: 'Dugi Rat',
21320: 'Baška Voda',
21327: 'Podgora',
21330: 'Gradac',
21400: 'Supetar',
21405: 'Milna',
21412: 'Pučišća',
21420: 'Bol',
21425: 'Selca',
21430: 'Grohote',
21450: 'Hvar',
21460: 'Stari Grad',
21465: 'Jelsa',
21469: 'Sućuraj',
21480: 'Vis',
21485: 'Komiža',
22000: 'Šibenik',
22202: 'Primošten',
22211: 'Vodice',
22213: 'Pirovac',
22222: 'Skradin',
22232: 'Zlarin',
22233: 'Prvić Luka',
22234: 'Prvić Šepurine',
22235: 'Kaprije',
22236: 'Žirje',
22240: 'Tisno',
22243: 'Murter',
22300: 'Knin',
22320: 'Drniš',
22323: 'Unešić',
23000: 'Zadar',
23205: 'Bibinje',
23206: 'Sukošan',
23210: 'Biograd na Moru',
23212: 'Tkon',
23222: 'Zemunik',
23223: 'Škabrnja',
23232: 'Nin',
23233: 'Privlaka',
23234: 'Vir',
23235: 'Vrsi',
23241: 'Poličnik',
23242: 'Posedarje',
23244: 'Starigrad Paklenica',
23248: 'Ražanac',
23250: 'Pag',
23271: 'Kukljica',
23273: 'Preko',
23281: 'Sali',
23283: 'Rava',
23284: 'Veli Iž',
23286: 'Božava',
23287: 'Veli Rat',
23291: 'Sestrunj',
23292: 'Molat',
23293: 'Ist',
23294: 'Premuda',
23295: 'Silba',
23296: 'Olib',
23312: 'Novigrad (Dalmacija)',
23420: 'Benkovac',
23422: 'Stankovci',
23440: 'Gračac',
23450: 'Obrovac',
31000: 'Osijek',
31200: 'Osijek',
31207: 'Tenja',
31226: 'Dalj',
31300: 'Beli Manastir',
31326: 'Darda',
31400: 'Đakovo',
31431: 'Čepin',
31500: 'Našice',
31540: 'Donji Miholjac',
31550: 'Valpovo',
31551: 'Belišće',
32000: 'Vukovar',
32100: 'Vinkovci',
32236: 'Ilok',
32242: 'Slakovci',
32249: 'Tovarnik',
32252: 'Otok',
32257: 'Drenovci',
32270: 'Županja',
32284: 'Stari Mikanovci',
33000: 'Virovitica',
33405: 'Pitomača',
33410: 'Suhopolje',
33515: 'Orahovica',
33520: 'Slatina',
34000: 'Požega',
34310: 'Pleternica',
34340: 'Kutjevo',
34550: 'Pakrac',
35000: 'Slavonski Brod',
35212: 'Garčin',
35214: 'Donji Andrijevci',
35220: 'Slavonski Šamac',
35222: 'Gundinci',
35250: 'Oriovac',
35252: 'Sibinj',
35400: 'Nova Gradiška',
35410: 'Nova Kapela',
35420: 'Staro Petrovo Selo',
35430: 'Okučani',
40000: 'Čakovec',
40313: 'Sveti Martin na Muri',
40315: 'Mursko Središče',
40320: 'Donji Kraljevec',
40323: 'Prelog',
42000: 'Varaždin',
42202: 'Trnovec Bartolovečki',
42204: 'Turčin',
42208: 'Cestica',
42220: 'Novi Marof',
42223: 'Varaždinske Toplice',
42230: 'Ludbreg',
42240: 'Ivanec',
42243: 'Maruševec',
42250: 'Lepoglava',
43000: 'Bjelovar',
43240: 'Čazma',
43270: 'Veliki Grđevac',
43280: 'Garešnica',
43290: 'Grubišno Polje',
43500: 'Daruvar',
44000: 'Sisak',
44010: 'Sisak-Caprag',
44210: 'Sunja',
44250: 'Petrinja',
44317: 'Popovača',
44320: 'Kutina',
44330: 'Novska',
44400: 'Glina',
44410: 'Vrginmost',
44430: 'Hrvatska Kostajnica',
44440: 'Dvor',
47000: 'Karlovac',
47220: 'Vojnić',
47240: 'Slunj',
47250: 'Duga Resa',
47280: 'Ozalj',
47300: 'Ogulin',
48000: 'Koprivnica',
48214: 'Sveti Ivan Žabno',
48260: 'Križevci',
48316: 'Đelekovec',
48350: 'Đurđevac',
49000: 'Krapina',
49210: 'Zabok',
49216: 'Desinić',
49217: 'Krapinske Toplice',
49218: 'Pregrada',
49221: 'Bedekovčina',
49223: 'Sveti Križ Začretje',
49225: 'Đurmanec',
49231: 'Hum na Sutli',
49240: 'Donja Stubica',
49243: 'Oroslavje',
49246: 'Marija Bistrica',
49250: 'Zlatar',
49252: 'Mihovljan',
49282: 'Konjščina',
49284: 'Budinščina',
49290: 'Klanjec',
51000: 'Rijeka',
51211: 'Matulji',
51215: 'Kastav',
51216: 'Viškovo',
51217: 'Klana',
51218: 'Dražice',
51224: 'Krasica',
51226: 'Hreljin',
51250: 'Novi Vinodolski',
51260: 'Crikvenica',
51262: 'Kraljevica',
51280: 'Rab',
51300: 'Delnice',
51306: 'Čabar',
51326: 'Vrbovsko',
51410: 'Opatija',
51415: 'Lovran',
51417: 'Mošćenička Draga',
51500: 'Krk',
51511: 'Malinska',
51523: 'Baška',
51550: 'Mali Lošinj',
51552: 'Ilovik',
51556: 'Martinšćica',
51557: 'Cres',
51561: 'Susak',
51562: 'Unije',
52000: 'Pazin',
52100: 'Pula (Pola)',
52207: 'Barban',
52210: 'Rovinj (Rovigno)',
52220: 'Labin',
52333: 'Podpićan',
52341: 'Žminj',
52420: 'Buzet',
52424: 'Motovun (Montona)',
52440: 'Poreč (Parenzo)',
52460: 'Buje (Buie)',
52466: 'Novigrad-Cittanova',
52470: 'Umag (Umago)',
53000: 'Gospić',
53202: 'Perušić',
53220: 'Otočac',
53230: 'Korenica',
53234: 'Udbina',
53250: 'Donji Lapac',
53260: 'Brinje',
53270: 'Senj',
53288: 'Karlobag',
53291: 'Novalja',
}
def create_post_offices(apps, schema_editor):
PostOffice = apps.get_model("main", "PostOffice")
bulk = []
for key, name in post_offices.items():
bulk.append(PostOffice(
zip=key,
name=name,
))
PostOffice.objects.bulk_create(bulk)
class Migration(migrations.Migration):
dependencies = [
("main", "0002_auto_20240410_1942"),
]
operations = [
migrations.RunPython(create_post_offices),
]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
from .area import Area
from .county import County
from .post_office import PostOffice

View File

@ -0,0 +1,11 @@
from django.db import models
class Area(models.Model):
name = models.CharField(max_length=100)
post_office = models.ForeignKey("PostOffice", on_delete=models.CASCADE)
county = models.ForeignKey("County", on_delete=models.CASCADE)
class Meta:
db_table = "areas"
ordering = ["name"]

View File

@ -0,0 +1,9 @@
from django.db import models
class County(models.Model):
name = models.CharField(max_length=100)
class Meta:
db_table = "counties"
ordering = ["name"]

View File

@ -0,0 +1,10 @@
from django.db import models
class PostOffice(models.Model):
zip = models.PositiveIntegerField()
name = models.CharField(max_length=100)
class Meta:
db_table = "post_offices"
ordering = ["zip"]

View File

@ -5,6 +5,7 @@
<meta name="viewport"
content="width=100%, user-scalable=yes, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js" integrity="sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+" crossorigin="anonymous"></script>
<script src="https://unpkg.com/htmx.org@1.9.11" integrity="sha384-0gxUXCCR8yv9FM2b+U3FDbsKthCI66oH5IA9fHppQq9DDMHuMauqq1ZHBpJxQ0J0" crossorigin="anonymous"></script>
<title>{{ title or "Django-html demo" }}</title>
</head>

View File

@ -1,7 +1,10 @@
{% extends "main/base/layout.html" %}
{% from "main/components/js_alert.html" import no_js_alert %}
{% block content %}
{{ no_js_alert() }}
<form>
<div class="row mb-4">
<div

View File

@ -4,61 +4,21 @@
{% set indent_2 = "ms-5" %}
<div class="card p-3 h-100">
{{ checkbox(
title="Enable Reports",
name="reports",
state=state.enabled
) }}
{{ checkbox(title="Enable Reports", name="reports", state=state.enabled) }}
<hr>
{{ checkbox(
title="Allow empty cashbag",
name="allow_empty_cashbag",
state=state.allow_empty_cashbag
) }}
{{ checkbox(
title="Reports builder",
name="reports_builder",
state=state.reports_builder
) }}
{{ checkbox(
title="Tax reports",
name="tax_reports",
state=state.tax_reports
) }}
{{ checkbox(
title="Transaction list",
name="transaction_list",
state=state.transaction_list
) }}
{{ checkbox(
title="Reports generator",
name="reports_generator",
state=state.reports_generator
) }}
{{ checkbox(
title="Technical center reports",
name="technical_center_reports",
state=state.technical_center_reports
) }}
{{ checkbox(
title="Dispense list",
name="dispense_list",
state=state.dispense_list
) }}
{{ checkbox(title="Allow empty cashbag", name="allow_empty_cashbag", state=state.allow_empty_cashbag) }}
{{ checkbox(title="Reports builder", name="reports_builder", state=state.reports_builder) }}
{{ checkbox(title="Tax reports", name="tax_reports", state=state.tax_reports) }}
{{ checkbox(title="Transaction list", name="transaction_list", state=state.transaction_list) }}
{{ checkbox(title="Reports generator", name="reports_generator", state=state.reports_generator) }}
{{ checkbox(title="Technical center reports", name="technical_center_reports", state=state.technical_center_reports) }}
{{ checkbox(title="Dispense list", name="dispense_list", state=state.dispense_list) }}
{{ checkbox(title="Cash conformity", name="cash_conformity", state=state.cash_conformity) }}
{{ checkbox(title="Scan 2nd barcode", name="scan_2nd_bardcode", state=state.scan_2nd_bardcode, cls=indent_1) }}
{{ checkbox(
title="Cash conformity",
name="cash_conformity",
state=state.cash_conformity
) }}
{{ checkbox(
title="Scan 2nd barcode",
name="scan_2nd_bardcode",
state=state.scan_2nd_bardcode,
cls=indent_1
) }}
{{ select(
title="Days between CC",
name="days_between_cc",
@ -82,5 +42,4 @@
state=state.days_between_cc,
cls=indent_1
) }}
</div>

View File

@ -4,71 +4,19 @@
{% set indent_2 = "ms-5" %}
<div class="card p-3 h-100">
{{ checkbox(
title="Enable Route module",
name="route_module",
state=state.enabled
) }}
{{ checkbox(title="Enable Route module", name="route_module", state=state.enabled) }}
<hr>
{{ checkbox(
title="Smart routing",
name="smart_routing",
state=state.smart_routing
) }}
{{ checkbox(
title="Predictive pickup",
name="predictive_pickup",
state=state.predictive_pickup,
cls=indent_1
) }}
{{ checkbox(
title="Automatic planning",
name="automatic_planning",
state=state.automatic_planning,
cls=indent_1
) }}
{{ checkbox(
title="Geo routing",
name="geo_routing",
state=state.geo_routing
) }}
{{ checkbox(
title="Warehouse",
name="warehouse",
state=state.warehouse
) }}
{{ checkbox(
title="End warehouse tracking",
name="end_warehouse_tracking",
state=state.end_warehouse_tracking,
cls=indent_1
) }}
{{ checkbox(
title="Pick&Pack application",
name="pick_and_pack_application",
state=state.pick_and_pack_application,
cls=indent_1
) }}
{{ checkbox(
title="Custom forms in routing",
name="custom_forms_in_routing",
state=state.custom_forms_in_routing
) }}
{{ checkbox(
title="Money bag tracking",
name="money_bag_tracking",
state=state.money_bag_tracking
) }}
{{ checkbox(title="Smart routing", name="smart_routing", state=state.smart_routing) }}
{{ checkbox(title="Predictive pickup", name="predictive_pickup", state=state.predictive_pickup, cls=indent_1) }}
{{ checkbox(title="Automatic planning", name="automatic_planning", state=state.automatic_planning, cls=indent_1) }}
{{ checkbox(title="Geo routing", name="geo_routing", state=state.geo_routing) }}
{{ checkbox(title="Warehouse", name="warehouse", state=state.warehouse) }}
{{ checkbox(title="End warehouse tracking", name="end_warehouse_tracking", state=state.end_warehouse_tracking, cls=indent_1) }}
{{ checkbox(title="Pick&Pack application", name="pick_and_pack_application", state=state.pick_and_pack_application, cls=indent_1) }}
{{ checkbox(title="Custom forms in routing", name="custom_forms_in_routing", state=state.custom_forms_in_routing) }}
{{ checkbox(title="Money bag tracking", name="money_bag_tracking", state=state.money_bag_tracking) }}
{{ select(
title="Packing model",
@ -81,24 +29,7 @@
state=state.packing_model
) }}
{{ checkbox(
title="Prekitting to box",
name="prekitting_to_box",
state=state.prekitting_to_box,
cls=indent_1
) }}
{{ checkbox(
title="Prekitting to pallet",
name="prekitting_to_pallet",
state=state.prekitting_to_pallet,
cls=indent_1
) }}
{{ checkbox(
title="Real time stock",
name="real_time_stock",
state=state.real_time_stock,
cls=indent_1
) }}
{{ checkbox(title="Prekitting to box", name="prekitting_to_box", state=state.prekitting_to_box, cls=indent_1) }}
{{ checkbox(title="Prekitting to pallet", name="prekitting_to_pallet", state=state.prekitting_to_pallet, cls=indent_1) }}
{{ checkbox(title="Real time stock", name="real_time_stock", state=state.real_time_stock, cls=indent_1) }}
</div>

View File

@ -4,12 +4,7 @@
{% set indent_2 = "ms-5" %}
<div class="card p-3 h-100">
{{ checkbox(
title="Product warehouse",
name="product_warehouse",
state=state.product_warehouse
) }}
{{ checkbox(title="Product warehouse", name="product_warehouse", state=state.product_warehouse) }}
{{ select(
title="Delivery option",
name="delivery_option",
@ -20,39 +15,10 @@
state=state.delivery_option,
cls=indent_1
) }}
{{ checkbox(
title="Allow negative stock",
name="allow_negative_stock",
state=state.allow_negative_stock,
cls=indent_1
) }}
{{ checkbox(
title="Route reserve stock",
name="route_reserve_stock",
state=state.route_reserve_stock,
cls=indent_1
) }}
{{ checkbox(
title="Refill log",
name="refill_log",
state=state.refill_log,
cls=indent_1
) }}
{{ checkbox(
title="Product order",
name="product_order",
state=state.product_order,
cls=indent_1
) }}
{{ checkbox(
title="Spare parts warehouse",
name="spare_parts_warehouse",
state=state.spare_parts_warehouse
) }}
{{ checkbox(
title="Purchase module",
name="purchase_module",
state=state.purchase_module
) }}
{{ checkbox(title="Allow negative stock", name="allow_negative_stock", state=state.allow_negative_stock, cls=indent_1) }}
{{ checkbox(title="Route reserve stock", name="route_reserve_stock", state=state.route_reserve_stock, cls=indent_1) }}
{{ checkbox(title="Refill log", name="refill_log", state=state.refill_log, cls=indent_1) }}
{{ checkbox(title="Product order", name="product_order", state=state.product_order, cls=indent_1) }}
{{ checkbox(title="Spare parts warehouse", name="spare_parts_warehouse", state=state.spare_parts_warehouse) }}
{{ checkbox(title="Purchase module", name="purchase_module", state=state.purchase_module) }}
</div>

View File

@ -0,0 +1,25 @@
{% macro no_js_alert() %}
<div class="alert alert-success d-flex align-items-center mb-5" role="alert">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-success me-3" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
</svg>
<div>
No JavaScript is used creating this page.
</div>
</div>
{% endmacro %}
{% macro js_alert(content) %}
<div class="alert alert-warning d-flex align-items-center mb-5" role="alert">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-warning me-3" viewBox="0 0 16 16">
<path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/>
</svg>
<div>
{{ content }}
</div>
</div>
{% endmacro %}
{% macro js_alert_work_in_progress() %}
{{ js_alert("Work in progress.") }}
{% endmacro %}

View File

@ -0,0 +1,53 @@
{% macro pagination(page) %}
{% macro render_link(title, page_number) %}
<a
class="page-link"
href="#"
hx-get="{{ url("filter-list-filter") }}"
hx-trigger="click"
hx-target="#filter-list-container"
hx-include="[name='zip'],[name='area'],[name='county']"
hx-vals='{"page": "{{ page_number }}"}'
>
{{ title }}
</a>
{% endmacro %}
{% if page.has_other_pages() %}
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if page.has_previous() %}
<li class="page-item">
{{ render_link(title="Previous", page_number=page.number - 1) }}
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#">Previous</a>
</li>
{% endif %}
{% for p in page.paginator.get_elided_page_range(page.number, on_each_side=2, on_ends=3) %}
{% if p != page.paginator.ELLIPSIS %}
<li class="page-item {% if page.number == p %}active{% endif %}">
{{ render_link(title=p, page_number=p) }}
</li>
{% else %}
<li class="page-item">
<span class="page-link border-top-0 border-bottom-0">{{ page.paginator.ELLIPSIS }}</span>
</li>
{% endif %}
{% endfor %}
{% if page.has_next() %}
<li class="page-item">
{{ render_link(title="Next", page_number=page.number + 1) }}
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#">Next</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% endmacro %}

View File

@ -0,0 +1,9 @@
{% macro toast(title, id) %}
<div class="toast-container position-absolute top-0 start-50 translate-middle-x mt-2">
<div id="{{ id }}" class="toast text-bg-success">
<div class="toast-body">
{{ title }}
</div>
</div>
</div>
{% endmacro %}

View File

@ -1,8 +1,68 @@
{% extends "main/base/layout.html" %}
{% from "main/components/js_alert.html" import js_alert_work_in_progress %}
{% block content %}
<p>
This is some filter list content bellow.
</p>
<div class="card mb-2">
<div class="card-body">
<form id="filter-form"
class="row g-2 align-items-center"
>
<div class="col-auto">
<label class="form-label mb-0">ZIP:</label>
</div>
<div class="col-auto">
<input
type="number"
name="zip"
class="form-control"
hx-get="{{ url("filter-list-filter") }}"
hx-trigger="keyup"
hx-target="#filter-list-container"
hx-include="[name='area'],[name='county']"
/>
</div>
<div class="col-auto">
<label class="form-label mb-0">Area:</label>
</div>
<div class="col-auto">
<input
type="text"
name="area"
class="form-control"
hx-get="{{ url("filter-list-filter") }}"
hx-trigger="keyup"
hx-target="#filter-list-container"
hx-include="[name='zip'],[name='county']"
/>
</div>
<div class="col-auto">
<label class="form-label mb-0">County:</label>
</div>
<div class="col-auto">
<select
name="county"
class="form-select"
hx-get="{{ url("filter-list-filter") }}"
hx-trigger="change"
hx-target="#filter-list-container"
hx-include="[name='zip'],[name='area']"
>
<option value="">
- All -
</option>
{% for county in counties %}
<option value="{{ county.id }}">
{{ county.name }}
</option>
{% endfor %}
</select>
</div>
</form>
</div>
</div>
<div id="filter-list-container">
{% include "main/filter_list_content.html" %}
</div>
{% endblock %}

View File

@ -0,0 +1,25 @@
{% from "main/components/pagination.html" import pagination %}
<table class="table">
<thead>
<tr>
<th>Zip Code</th>
<th>Post Office</th>
<th>Area</th>
<th>County</th>
</tr>
</thead>
<tbody>
{% for area in page.object_list %}
<tr>
<td>{{ area.post_office.zip }}</td>
<td>{{ area.post_office.name }}</td>
<td>{{ area.name }}</td>
<td>{{ area.county.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{{ pagination(page) }}

View File

@ -1,19 +1,37 @@
{% extends "main/base/layout.html" %}
{% from "main/components/toast.html" import toast %}
{% from "main/components/js_alert.html" import js_alert %}
{% block content %}
<form
hx-post="{{ url("form-validation") }}"
hx-target="#validation-form-content"
hx-swap="outerHTML"
>
<div class="card p-4">
{% include "main/form_validation_content.html" %}
<div class="d-flex">
<button type="submit" class="btn btn-success ms-auto">
Submit
</button>
</div>
</div>
</form>
{{ js_alert("Just few lines of JavaScript used to pop toast.") }}
<form
hx-post="{{ url("form-validation") }}"
hx-target="#validation-form-content"
hx-swap="outerHTML"
>
<div class="card p-4">
{% include "main/form_validation_content.html" %}
<div class="d-flex">
<button type="submit" class="btn btn-success ms-auto">
Submit
</button>
</div>
</div>
</form>
{{ toast(title="Form validated and saved successfully. Sorry, but I used few lines of JS code for this toast.", id="toast-success") }}
<script>
let toastSuccess = null;
document.addEventListener("DOMContentLoaded", function () {
const toastElement = document.querySelector("#toast-success");
toastSuccess = new bootstrap.Toast(toastElement, {
delay: 3000,
})
});
</script>
{% endblock %}

View File

@ -57,3 +57,10 @@
{% endif %}
</div>
</div>
{% if validation.is_valid %}
<script>
toastSuccess.show();
</script>
{% endif %}

View File

@ -1,4 +1,5 @@
{% extends "main/base/layout.html" %}
{% from "main/components/js_alert.html" import no_js_alert %}
{% block content %}
@ -13,6 +14,8 @@
</button>
{% endmacro %}
{{ no_js_alert() }}
{{ render_btn(title="Initial", cls="btn-outline-secondary", content="initial") }}
{{ render_btn(title="Swap to content 1", cls="btn-info", content="info") }}
{{ render_btn(title="Swap to content 2", cls="btn-warning", content="warning") }}

View File

@ -1,8 +1,7 @@
{% extends "main/base/layout.html" %}
{% from "main/components/js_alert.html" import js_alert_work_in_progress %}
{% block content %}
<p>
This is some table inline edit content bellow.
</p>
{{ js_alert_work_in_progress() }}
{% endblock %}

View File

@ -4,7 +4,7 @@ from .complex_form.views import (
RouteModuleHandleView,
WarehouseManagementHandleView,
)
from .filter_list import FilterListView
from .filter_list import FilterListFilterView, FilterListView
from .form_validation import FormValidationView
from .home import HomeView
from .swap import SwapView

View File

@ -1,7 +1,76 @@
from typing import Any
from django.core.paginator import Page, Paginator
from django.db.models import Q, QuerySet
from project.main.models import Area, County
from project.main.views.demo_view_base import DemoViewBase
PAGE_SIZE = 20
class FilterListView(DemoViewBase):
def get_all_counties() -> QuerySet[County]:
return County.objects.all()
class FilterListViewBase(DemoViewBase):
def paginate(self, qs: QuerySet[Area]) -> Page:
page = int(self.request.GET.get("page", 1))
page_size = int(self.request.GET.get("page_size", PAGE_SIZE))
paginator = Paginator(
object_list=qs,
per_page=page_size,
)
return paginator.get_page(page)
class FilterListView(FilterListViewBase):
template_name = "main/filter_list.html"
active_section = "filter-list"
title = "Filter List"
def get_context_data(self, **kwargs) -> dict[str, Any]:
context_data = super().get_context_data(**kwargs)
page = self.paginate(
qs=Area.objects.select_related("county", "post_office").all(),
)
context_data.update(
{
"page": page,
"counties": get_all_counties(),
}
)
return context_data
class FilterListFilterView(FilterListViewBase):
template_name = "main/filter_list_content.html"
def get_context_data(self, **kwargs) -> dict[str, Any]:
context_data = super().get_context_data(**kwargs)
q = Q()
zip = self.request.GET.get("zip", None)
area = self.request.GET.get("area", None)
county = self.request.GET.get("county", None)
if zip:
q &= Q(post_office__zip=zip)
if area:
q &= Q(name__icontains=area)
if county:
q &= Q(county_id=county)
page = self.paginate(
qs=Area.objects.select_related("county", "post_office").filter(q),
)
context_data.update(
{
"page": page,
"counties": get_all_counties(),
}
)
return context_data

View File

@ -11,6 +11,7 @@ from project.main.views.demo_view_base import DemoViewBase
@dataclass
class Validation:
validated: bool = False
is_valid: bool = False
name: Optional[str] = None
consent: Optional[bool] = None
@ -57,6 +58,10 @@ class FormValidationView(DemoViewBase):
if not validation.consent:
validation.consent_error = "You should consent"
validation.is_valid = not (
validation.name_error or validation.age_error or validation.consent_error
)
return render(
context={
"validation": validation,

View File

@ -37,6 +37,7 @@ INSTALLED_APPS = [
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"project.main",
]
MIDDLEWARE = [
@ -146,3 +147,5 @@ STATIC_URL = "static/"
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
from project.settings_local import *

View File

@ -0,0 +1,2 @@
ALLOWED_HOSTS = ["*"]
DEBUG = True

View File

@ -1,3 +1,7 @@
import shutil
from pathlib import Path
from django.conf import settings
from django.urls import path
from project.main import views
@ -6,10 +10,35 @@ urlpatterns = [
path("", views.HomeView.as_view(), name="home"),
path("swap", views.SwapView.as_view(), name="swap"),
path("filter-list", views.FilterListView.as_view(), name="filter-list"),
path(
"filter-list/filter", views.FilterListFilterView.as_view(), name="filter-list-filter"
),
path("form-validation", views.FormValidationView.as_view(), name="form-validation"),
path("complex-form", views.ComplexFormView.as_view(), name="complex-form"),
path("complex-form/handle/route-module", views.RouteModuleHandleView.as_view(), name="complex-form-handle-route-module"),
path("complex-form/handle/reports", views.ReportsHandleView.as_view(), name="complex-form-handle-reports"),
path("complex-form/handle/warehouse-management", views.WarehouseManagementHandleView.as_view(), name="complex-form-handle-warehouse-management"),
path("table-inline-edit", views.TableInlineEditView.as_view(), name="table-inline-edit"),
path(
"complex-form/handle/route-module",
views.RouteModuleHandleView.as_view(),
name="complex-form-handle-route-module",
),
path(
"complex-form/handle/reports",
views.ReportsHandleView.as_view(),
name="complex-form-handle-reports",
),
path(
"complex-form/handle/warehouse-management",
views.WarehouseManagementHandleView.as_view(),
name="complex-form-handle-warehouse-management",
),
path(
"table-inline-edit",
views.TableInlineEditView.as_view(),
name="table-inline-edit",
),
]
# check if db exists, and copy from template if not
if not Path.exists(settings.DATABASES["default"]["NAME"]):
template_filename = settings.BASE_DIR / "db.template.sqlite3"
shutil.copyfile(template_filename, settings.DATABASES["default"]["NAME"])
print("Database copied from template.")

View File

@ -9,6 +9,7 @@ readme = "README.md"
python = "^3.10"
django = "^5.0.4"
django-jinja = "^2.11.0"
gunicorn = "^21.2.0"
[build-system]