diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index 7998edf..8bde616 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -27,6 +27,7 @@ jobs: pip install -r requirements.txt - name: Run Tests run: | + python manage.py collectstatic python manage.py test env: diff --git a/.gitignore b/.gitignore index 3bd62a7..af255a8 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ share/python-wheels/ *.egg-info/ .installed.cfg *.egg +/staticfiles MANIFEST media/ *.pyc diff --git a/gds/settings.py b/gds/settings.py index b19b6a6..72cab83 100644 --- a/gds/settings.py +++ b/gds/settings.py @@ -28,6 +28,7 @@ 'django.contrib.messages', 'django.contrib.staticfiles', #apps + 'stock', #3rd part apps 'allauth', @@ -54,7 +55,7 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [os.path.join(BASE_DIR, 'templates/')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/gds/urls.py b/gds/urls.py index 6d5f373..3be965d 100644 --- a/gds/urls.py +++ b/gds/urls.py @@ -6,4 +6,5 @@ path('admin/', admin.site.urls), path('__debug__/', include("debug_toolbar.urls")), path('accounts/', include('allauth.urls')), + path('stock/', include('stock.urls')), ] diff --git a/stock/__init__.py b/stock/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stock/admin.py b/stock/admin.py new file mode 100644 index 0000000..8dbe4bd --- /dev/null +++ b/stock/admin.py @@ -0,0 +1,12 @@ +from django.contrib import admin +from .models import Gas + +@admin.register(Gas) +class GasAdmin(admin.ModelAdmin): + list_display = ('name', 'quantity', 'price', 'supplier', 'created', 'updated') + list_filter = ('supplier', 'created', 'updated') + search_fields = ('name', 'supplier') + date_hierarchy = 'created' + ordering = ('-created',) + fields = ('name', 'quantity', 'price', 'supplier') + readonly_fields = ('created', 'updated') \ No newline at end of file diff --git a/stock/apps.py b/stock/apps.py new file mode 100644 index 0000000..ee74ea8 --- /dev/null +++ b/stock/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class StockConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'stock' diff --git a/stock/migrations/0001_initial.py b/stock/migrations/0001_initial.py new file mode 100644 index 0000000..fb4bd42 --- /dev/null +++ b/stock/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 5.0 on 2023-12-28 20:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Gas', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100)), + ('quantity', models.PositiveIntegerField()), + ('price', models.DecimalField(decimal_places=2, max_digits=8)), + ('supplier', models.CharField(blank=True, max_length=100, null=True)), + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ], + ), + ] diff --git a/stock/migrations/__init__.py b/stock/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stock/models.py b/stock/models.py new file mode 100644 index 0000000..9349e3e --- /dev/null +++ b/stock/models.py @@ -0,0 +1,13 @@ +from django.db import models + + +class Gas(models.Model): + name = models.CharField(max_length=100) + quantity = models.PositiveIntegerField() + price = models.DecimalField(max_digits=8, decimal_places=2) + supplier = models.CharField(max_length=100, null=True, blank=True) + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.name \ No newline at end of file diff --git a/stock/tests.py b/stock/tests.py new file mode 100644 index 0000000..9d5d075 --- /dev/null +++ b/stock/tests.py @@ -0,0 +1,50 @@ +from django.test import TestCase +from django.urls import reverse +from .models import Gas +from .views import GasListView, GasCreateView + +class GasModelTest(TestCase): + def setUp(self): + self.gas = Gas.objects.create( + name='Gas A', + quantity=10, + price=2.50, + supplier='Supplier A' + ) + + def test_gas_model(self): + self.assertEqual(self.gas.name, 'Gas A') + self.assertEqual(self.gas.quantity, 10) + self.assertEqual(self.gas.price, 2.50) + self.assertEqual(self.gas.supplier, 'Supplier A') + self.assertIsNotNone(self.gas.created) + self.assertIsNotNone(self.gas.updated) + +class GasListViewTest(TestCase): + def test_gas_list_view(self): + url = reverse('stock:gas_list') + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + +class GasCreateViewTest(TestCase): + def test_gas_create_view(self): + url = reverse('stock:gas_create') + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + + def test_gas_create_form_submission(self): + url = reverse('stock:gas_create') + data = { + 'name': 'Gas B', + 'quantity': 5, + 'price': 3.00, + 'supplier': 'Supplier B' + } + response = self.client.post(url, data) + self.assertEqual(response.status_code, 302) + self.assertEqual(Gas.objects.count(), 1) + gas = Gas.objects.first() + self.assertEqual(gas.name, 'Gas B') + self.assertEqual(gas.quantity, 5) + self.assertEqual(gas.price, 3.00) + self.assertEqual(gas.supplier, 'Supplier B') diff --git a/stock/urls.py b/stock/urls.py new file mode 100644 index 0000000..d3aa970 --- /dev/null +++ b/stock/urls.py @@ -0,0 +1,12 @@ +from django.urls import path + +from . import views + +app_name = 'stock' + +urlpatterns = [ + path('', views.GasListView.as_view(), name='gas_list'), + path('add/', views.GasCreateView.as_view(), name='gas_create'), + path('/update/', views.GasUpdateView.as_view(), name='gas_update'), + path('/delete/', views.GasDeleteView.as_view(), name='gas_delete'), +] \ No newline at end of file diff --git a/stock/views.py b/stock/views.py new file mode 100644 index 0000000..ecfe1e8 --- /dev/null +++ b/stock/views.py @@ -0,0 +1,28 @@ +from django.shortcuts import render + +# Create your views here. +from django.views.generic import ListView, CreateView, UpdateView, DeleteView +from django.urls import reverse_lazy +from .models import Gas + +class GasListView(ListView): + model = Gas + template_name = 'stock/index.html' + context_object_name = 'gas_items' + +class GasCreateView(CreateView): + model = Gas + template_name = 'stock/create.html' + fields = ['name', 'quantity', 'price', 'supplier'] + success_url = reverse_lazy('stock:gas_list') + +class GasUpdateView(UpdateView): + model = Gas + template_name = 'stock/update.html' + fields = ['name', 'quantity', 'price', 'supplier'] + success_url = reverse_lazy('stock:gas_list') + +class GasDeleteView(DeleteView): + model = Gas + template_name = 'stock/delete.html' + success_url = reverse_lazy('stock:gas_list') \ No newline at end of file diff --git a/templates/stock/create.html b/templates/stock/create.html new file mode 100644 index 0000000..e69de29 diff --git a/templates/stock/index.html b/templates/stock/index.html new file mode 100644 index 0000000..e69de29 diff --git a/templates/stock/update.html b/templates/stock/update.html new file mode 100644 index 0000000..e69de29