"add-code nl-46 ol-46"> 508
+    code_no_mks = models.CharField(max_length=100, null=True, blank=True)
509
+    lot_no = models.CharField(max_length=100, null=True, blank=True)
510
+    drawing = models.ImageField(upload_to='drawings/')
511
+    description = models.TextField(null=True, blank=True)
512
+    created_at = models.DateTimeField(auto_now_add=True)
513
+    updated_at = models.DateTimeField(auto_now=True)
514
+
515
+    created_by = models.ForeignKey(
516
+        User,
517
+        on_delete=models.SET_NULL,
518
+        null=True,
519
+        blank=True, 
520
+    )  # Reference to the user who created the report
521
+    
522
+    def __str__(self):
523
+        return f"{self.code_no} - {self.lot_no}"

+ 14 - 1
app/core/utils.py

@@ -12,6 +12,7 @@ from django.views.generic import (
12 12
 )
13 13
 from django.core.paginator import Paginator
14 14
 from core.models import MgMasterView, VMasterView, BelMasterView, EMasterView
15
+from pprint import pprint
15 16
 
16 17
 class ConfigurableCRUDView:
17 18
     model = None
@@ -44,6 +45,7 @@ class ConfigurableCRUDView:
44 45
         - Respects `config_field_orders` and `config_excludes`.
45 46
         Returns field instances instead of field names.
46 47
         """
48
+        pprint("get_fields")
47 49
         model_fields = {f.name: f for f in self.model._meta.get_fields()}
48 50
 
49 51
         # Filter based on `config_fields` configuration
@@ -65,7 +67,6 @@ class ConfigurableCRUDView:
65 67
         # Reorder fields to match the order specified in `config_field_orders`
66 68
         ordered_field_names = set(self.config_field_orders)
67 69
         ordered_fields.sort(key=lambda f: self.config_field_orders.index(f.name) if f.name in ordered_field_names else len(ordered_field_names))
68
-
69 70
         return ordered_fields + remaining_fields
70 71
 
71 72
 
@@ -226,3 +227,15 @@ def queryFromMaster(lot_no):
226 227
         results.extend(queryset)
227 228
     return results
228 229
 
230
+SHEET_NAMES = {
231
+    'hardness_out': 'Hardness Out',
232
+    'hardness_out_in': 'Hardness Out/In', 
233
+    'hardness_both_size': 'Hardness Both Size',
234
+    'dimension': 'Dimension',
235
+    'dimension_app': 'Dimension Appearance',
236
+    'dimension_bal_weight': 'Dimension Balance/Weight',
237
+    'dim_bal_app_hard': 'Dimension Balance/Appearance/Hardness',
238
+    'dim_bal_app_rot_hard': 'Dimension Balance/Appearance/Rotation/Hardness',
239
+    'thickness_8_point': 'Thickness 8 Points',
240
+    'centering': 'Centering',
241
+}

+ 104 - 0
app/legacy/migrations/0003_allproductaverageobminmaxview_and_more.py

@@ -0,0 +1,104 @@
1
+# Generated by Django 4.2 on 2025-05-06 04:36
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('legacy', '0002_belmasterview_emasterview_mgmasterview_vmasterview'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.CreateModel(
14
+            name='AllProductAverageObMinMaxView',
15
+            fields=[
16
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17
+                ('ProductCode', models.CharField(max_length=255, null=True)),
18
+                ('out_min', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
19
+                ('out_max', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
20
+                ('in_min', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
21
+                ('in_max', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
22
+            ],
23
+            options={
24
+                'db_table': 'AllProduct_Average_OB_MIN_MAX_view',
25
+                'managed': False,
26
+            },
27
+        ),
28
+        migrations.CreateModel(
29
+            name='AllProductDimensionForInsProcess',
30
+            fields=[
31
+                ('ProdType', models.CharField(max_length=255, null=True)),
32
+                ('ProductCode', models.CharField(max_length=255, primary_key=True, serialize=False)),
33
+                ('Size_Id', models.CharField(max_length=255, null=True)),
34
+                ('Size_Name', models.CharField(max_length=255, null=True)),
35
+                ('Std', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
36
+                ('TolUn', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
37
+                ('TolUp', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
38
+            ],
39
+            options={
40
+                'db_table': 'AllProduct_Dimension_ForInsProcess',
41
+                'managed': False,
42
+            },
43
+        ),
44
+        migrations.CreateModel(
45
+            name='AllProductPressPositionPressWeight',
46
+            fields=[
47
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
48
+                ('ProductCode', models.CharField(max_length=255, null=True)),
49
+                ('Lot_No', models.CharField(max_length=255, null=True)),
50
+                ('PO_Qty', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
51
+                ('UWeight', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
52
+                ('Current_ProNo', models.CharField(max_length=255, null=True)),
53
+                ('Press_Time', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
54
+                ('PressType_1', models.CharField(max_length=255, null=True)),
55
+                ('PressWeight_1', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
56
+                ('PressType_2', models.CharField(max_length=255, null=True)),
57
+                ('PressWeight_2', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
58
+                ('Press_Ton', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
59
+                ('Press_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
60
+                ('Press_T_Tol', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
61
+                ('Mold_D', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
62
+                ('Mold_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
63
+                ('SegMold_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
64
+                ('SegMold_D', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
65
+                ('Center_D', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
66
+                ('Center_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
67
+                ('LowerPlate_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
68
+                ('StudPlate_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
69
+                ('UpperPlate_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
70
+                ('PinPlate_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
71
+                ('TopConcave_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
72
+                ('BottomConcave_T', models.DecimalField(decimal_places=2, max_digits=10, null=True)),
73
+            ],
74
+            options={
75
+                'db_table': 'AllProduct_PressPosition_PressWeight',
76
+                'managed': False,
77
+            },
78
+        ),
79
+        migrations.CreateModel(
80
+            name='RotateBrokenTest',
81
+            fields=[
82
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
83
+                ('row_no', models.IntegerField(blank=True, null=True)),
84
+                ('speed_spec', models.FloatField(blank=True, null=True)),
85
+                ('speed_test', models.FloatField(blank=True, null=True)),
86
+                ('speedOk', models.CharField(blank=True, max_length=4, null=True)),
87
+                ('qty', models.IntegerField()),
88
+                ('station_no', models.IntegerField()),
89
+                ('created_at', models.DateTimeField(blank=True, null=True)),
90
+                ('updated_at', models.DateTimeField(blank=True, null=True)),
91
+                ('lot_no', models.CharField(blank=True, max_length=50, null=True)),
92
+                ('machine_id', models.IntegerField(blank=True, null=True)),
93
+                ('code', models.CharField(blank=True, max_length=50, null=True)),
94
+                ('emp_id', models.IntegerField()),
95
+                ('devid', models.CharField(blank=True, max_length=40, null=True)),
96
+                ('mode', models.CharField(blank=True, max_length=10, null=True)),
97
+                ('cal_mode', models.IntegerField(blank=True, null=True)),
98
+            ],
99
+            options={
100
+                'db_table': 'rotate_broken_test',
101
+                'managed': False,
102
+            },
103
+        ),
104
+    ]

+ 2 - 0
app/legacy/templates/legacy/datacrud_list.html

@@ -46,6 +46,8 @@
46 46
                         </a>
47 47
                     {% elif field.name == 'file' and obj.file %}
48 48
                     <a href="{{ obj.file.url }}" target="_blank">View</a>
49
+                    {% elif field.name == 'drawing' and obj.drawing %}
50
+                    <a href="{{ obj.drawing.url }}" target="_blank">View</a>
49 51
                     {% elif field.get_internal_type == "DateTimeField" %}
50 52
                         {{ obj|attr:field.name|date:"d/m/Y H:i" }}
51 53
                     {% else %}

+ 30 - 1
app/report/filters.py

@@ -1,5 +1,5 @@
1 1
 import django_filters
2
-from core.models import Report
2
+from core.models import Report, CustomerTemplateMapping, ProductDrawing
3 3
 
4 4
 class ReportFilter(django_filters.FilterSet):
5 5
     name = django_filters.CharFilter(
@@ -26,3 +26,32 @@ class ReportFilter(django_filters.FilterSet):
26 26
     class Meta:
27 27
         model = Report
28 28
         fields = ['name', 'created_by', 'created_at']
29
+
30
+
31
+class CustomerTemplateFilter(django_filters.FilterSet):
32
+    customer_name = django_filters.CharFilter(
33
+        field_name='customer_name',
34
+        lookup_expr='icontains',
35
+        label='Customer Name'
36
+    )
37
+
38
+    template_names = django_filters.CharFilter(
39
+        method='filter_template_names',
40
+        label='Template Name Contains'
41
+    )
42
+
43
+    class Meta:
44
+        model = CustomerTemplateMapping
45
+        fields = ['customer_name', 'template_names']
46
+
47
+    def filter_template_names(self, queryset, name, value):
48
+        return queryset.filter(template_names__icontains=value)
49
+
50
+class ProductDrawingFilter(django_filters.FilterSet):
51
+    code_no = django_filters.CharFilter(lookup_expr='icontains', label='Code No')
52
+    code_no_mks = django_filters.CharFilter(lookup_expr='icontains', label='Code No (MKS)')
53
+    lot_no = django_filters.CharFilter(lookup_expr='icontains', label='Lot No')
54
+
55
+    class Meta:
56
+        model = ProductDrawing
57
+        fields = ['code_no', 'code_no_mks', 'lot_no',]

+ 42 - 0
app/report/templates/report/customer_template_form.html

@@ -0,0 +1,42 @@
1
+{% extends "base.html" %}
2
+{% load legacy_filters %}
3
+{% load tailwind_filters %}
4
+
5
+{% block title %}
6
+    {% if view.title %}
7
+        {{ view.title }}
8
+    {% else %}
9
+        {{ view|class_name }}
10
+    {% endif %}
11
+{% endblock %}
12
+
13
+{% block content %}
14
+<div class="container mx-auto px-4 py-6">
15
+    <h1 class="text-2xl font-bold mb-6">
16
+        {% if view.title %}
17
+            {{ view.title }}
18
+        {% elif view|class_name == "CreateViewClass" %}
19
+            Create {{ model_verbose_name }}
20
+        {% else %}
21
+            Update {{ model_verbose_name }}
22
+        {% endif %}
23
+    </h1>
24
+
25
+    <!-- Render the Form -->
26
+    <form method="post" enctype="multipart/form-data" >
27
+        {% csrf_token %}
28
+        <div>
29
+          
30
+        {{ form|crispy }}
31
+        </div>
32
+        <div class='mt-4'>
33
+            <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
34
+                Save
35
+            </button>
36
+            <a href="{% url list_url_name %}" class="bg-gray-300 text-gray-800 px-4 py-2 rounded hover:bg-gray-400">
37
+                Cancel
38
+            </a>
39
+        </div>
40
+    </form>
41
+</div>
42
+{% endblock %}

+ 126 - 0
app/report/templates/report/customer_template_list.html

@@ -0,0 +1,126 @@
1
+{% extends "base.html" %}
2
+{% load legacy_filters %}
3
+{% load tailwind_filters %}
4
+{% block title %}{{ page_title }}{% endblock %}
5
+
6
+{% block content %}
7
+<div class="container mx-auto px-4 py-6">
8
+    <h1 class="text-3xl font-bold text-gray-800 mb-4">{{ page_title }}</h1>
9
+
10
+    <!-- Filter Form -->
11
+    <form method="get" class="flex items-center space-x-4 mb-4">
12
+        {{ filter.form | crispy }}
13
+        <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">Filter</button>
14
+        <a href="?" class="bg-gray-300 text-gray-800 px-4 py-2 rounded hover:bg-gray-400">Reset</a>
15
+    </form>
16
+
17
+    <!-- Create Button -->
18
+    <div class="my-4 flex">
19
+        <p class="text-gray-600 mb-4 mr-auto">
20
+            Total Records: {{ page_obj.paginator.count }}
21
+        </p>
22
+        <a href="{% url create_url %}" class="ml-auto bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">
23
+            Create New Data
24
+        </a>
25
+    </div>
26
+
27
+    <!-- Data Table -->
28
+    <div class="clear-both bg-white shadow rounded-lg overflow-x-auto">
29
+<table class="w-full border-collapse border border-gray-200">
30
+    <thead>
31
+        <tr class="bg-gray-100 text-left text-sm uppercase">
32
+            {% for field in fields %}
33
+            <th class="border border-gray-200 px-4 py-2 text-left">{% firstof field.verbose_name field.name %} </th>
34
+            {% endfor %}
35
+            <th class="py-2 px-4 border-b">Actions</th>
36
+        </tr>
37
+    </thead>
38
+    <tbody>
39
+        {% for obj in page_obj %}
40
+            <tr class="hover:bg-gray-50">
41
+                {% for field in fields %}
42
+                <td class="border border-gray-200 px-4 py-2">
43
+                    {% if field.name == 'id' %}
44
+                        <a href="{% url update_url obj.pk %}" class="text-blue-500 hover:underline">
45
+                            {{ obj|attr:field.name }}
46
+                        </a>
47
+                    {% elif field.name == 'template_names' %}
48
+
49
+                      {% with template_list=obj|attr:field.name %}
50
+                          {% for t in template_list %}
51
+                              {{ sheet_names | get_item:t }}
52
+                              {% if not forloop.last %}, {% endif %}
53
+                          {% endfor %}
54
+                      {% endwith %}
55
+                    {% elif field.name == 'file' and obj.file %}
56
+                    <a href="{{ obj.file.url }}" target="_blank">View</a>
57
+                    {% elif field.get_internal_type == "DateTimeField" %}
58
+                        {{ obj|attr:field.name|date:"d/m/Y H:i" }}
59
+                    {% else %}
60
+                        {{ obj|attr:field.name | safe_floatformat:2 }}
61
+                    {% endif %}
62
+                </td>
63
+                {% endfor %}
64
+                <td class="py-2 px-4 border-b">
65
+                    <a href="{% url update_url obj.pk %}" 
66
+                       class="bg-blue-500 text-white px-3 py-2 rounded hover:bg-blue-600">Edit</a>
67
+                    <a href="{% url delete_url obj.pk %}" 
68
+                       class="bg-red-500 text-white px-3 py-2 rounded hover:bg-red-600">Delete</a>
69
+                </td>
70
+            </tr>
71
+        {% empty %}
72
+            <tr>
73
+                <td colspan="5" class="py-4 px-4 text-center text-gray-600">No data available.</td>
74
+            </tr>
75
+        {% endfor %}
76
+    </tbody>
77
+</table>
78
+    </div>
79
+
80
+    <!-- Pagination -->
81
+    <div class="mt-6 flex justify-between items-center">
82
+        <div>
83
+            <span class="text-sm text-gray-600">
84
+                Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
85
+            </span>
86
+        </div>
87
+        <div class="space-x-2">
88
+            {% if page_obj.has_previous %}
89
+                <a href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value|urlencode }}&{% endif %}{% endfor %}page=1" 
90
+                   class="text-blue-500 hover:underline">First</a>
91
+                <a href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value|urlencode }}&{% endif %}{% endfor %}page={{ page_obj.previous_page_number }}" 
92
+                   class="text-blue-500 hover:underline">Previous</a>
93
+            {% endif %}
94
+            {% for page_num in page_obj.paginator.page_range %}
95
+                {% if page_num == page_obj.number %}
96
+                    <span class="font-bold text-gray-700">{{ page_num }}</span>
97
+                {% elif page_num == 1 or page_num == page_obj.paginator.num_pages or page_num >= page_obj.number|add:"-2" and page_num <= page_obj.number|add:"2" %}
98
+                    <a href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value|urlencode }}&{% endif %}{% endfor %}page={{ page_num }}" 
99
+                       class="text-blue-500 hover:underline">{{ page_num }}</a>
100
+                {% elif page_num == page_obj.number|add:-3 or page_num == page_obj.number|add:3 %}
101
+                    <span class="mx-1">...</span>
102
+                {% endif %}
103
+            {% endfor %}
104
+            {% if page_obj.has_next %}
105
+                <a href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value|urlencode }}&{% endif %}{% endfor %}page={{ page_obj.next_page_number }}" 
106
+                   class="text-blue-500 hover:underline">Next</a>
107
+                <a href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value|urlencode }}&{% endif %}{% endfor %}page={{ page_obj.paginator.num_pages }}" 
108
+                   class="text-blue-500 hover:underline">Last</a>
109
+            {% endif %}
110
+        </div>
111
+    </div>
112
+</div>
113
+<style>
114
+/* Remove fixed layout and allow columns to grow dynamically */
115
+table {
116
+    table-layout: auto; /* Default is auto, can be explicitly set */
117
+    width: 100%; /* Ensures table spans available space */
118
+}
119
+
120
+th, td {
121
+    white-space: nowrap; /* Prevents text wrapping */
122
+    text-overflow: ellipsis; /* Adds ellipsis for overflowed content if combined with max-width */
123
+    vertical-align: top; /* Aligns content to the top */
124
+}
125
+</style>
126
+{% endblock %}

+ 12 - 1
app/report/urls.py

@@ -1,8 +1,10 @@
1 1
 from django.urls import path
2 2
 from . import views
3
-from .views import ReportCRUDView
3
+from .views import ReportCRUDView, CustomerTemplateCRUDView, ProductDrawingCRUDView
4 4
 
5 5
 report_crud = ReportCRUDView()
6
+customer_templates_crud = CustomerTemplateCRUDView()
7
+product_drawings_crud = ProductDrawingCRUDView()
6 8
 
7 9
 app_name = "report"  # Use this namespace for reverse URL lookups
8 10
 
@@ -16,6 +18,15 @@ urlpatterns = [
16 18
     path('coi/', views.coi_view, name='coi-view'),
17 19
     path('report/generate/', views.gen_report_view, name='gen_report'),
18 20
 
21
+    path('customer_templates/', customer_templates_crud.get_list_view().as_view(), name='customer_templates-list'),
22
+    path('customer_templates/create/', customer_templates_crud.get_create_view().as_view(), name='customer_templates-create'),
23
+    path('customer_templates/<str:pk>/update/', customer_templates_crud.get_update_view().as_view(), name='customer_templates-update'),
24
+    path('customer_templates/<str:pk>/delete/', customer_templates_crud.get_delete_view().as_view(), name='customer_templates-delete'),
25
+    
26
+    path('product_drawings/', product_drawings_crud.get_list_view().as_view(), name='product_drawings-list'),
27
+    path('product_drawings/create/', product_drawings_crud.get_create_view().as_view(), name='product_drawings-create'),
28
+    path('product_drawings/<str:pk>/update/', product_drawings_crud.get_update_view().as_view(), name='product_drawings-update'),
29
+    path('product_drawings/<str:pk>/delete/', product_drawings_crud.get_delete_view().as_view(), name='product_drawings-delete'),
19 30
     # path('create/', views.create_report, name='create'),  # Create a new report
20 31
     # path('<int:pk>/', views.detail_report, name='detail'),  # View details of a specific report
21 32
     # path('<int:pk>/update/', views.update_report, name='update'),  # Update a specific report

+ 84 - 16
app/report/views.py

@@ -1,10 +1,11 @@
1 1
 from django.shortcuts import render, redirect, get_object_or_404
2 2
 from django.core.paginator import Paginator
3 3
 from django.contrib import messages
4
-from core.models import Report, AllProductDimensionForInsProcess
5
-from core.forms import ReportForm
6
-from core.utils import ConfigurableCRUDView, queryFromMaster
7
-from .filters import ReportFilter
4
+from core.models import Report, AllProductDimensionForInsProcess, CustomerTemplateMapping, \
5
+                ProductDrawing
6
+from core.forms import ReportForm, CustomerTemplateMappingForm, ProductDrawingForm
7
+from core.utils import ConfigurableCRUDView, queryFromMaster, SHEET_NAMES
8
+from .filters import ReportFilter, CustomerTemplateFilter, ProductDrawingFilter
8 9
 from .forms import ExportOptionsForm
9 10
 from pprint import pprint
10 11
 
@@ -24,6 +25,10 @@ from django.conf import settings
24 25
 
25 26
 from itertools import chain
26 27
 
28
+from django_filters.views import FilterView
29
+
30
+from django.views.generic import (
31
+    ListView,)
27 32
 
28 33
 def index(request):
29 34
     reports = Report.objects.all()
@@ -886,18 +891,6 @@ def create_coi_file(lot_no, sheets, user, md):
886 891
     pprint(f"outputfile = {output_file}")
887 892
     return report
888 893
 
889
-SHEET_NAMES = {
890
-    'hardness_out': 'Hardness Out',
891
-    'hardness_out_in': 'Hardness Out/In', 
892
-    'hardness_both_size': 'Hardness Both Size',
893
-    'dimension': 'Dimension',
894
-    'dimension_app': 'Dimension Appearance',
895
-    'dimension_bal_weight': 'Dimension Balance/Weight',
896
-    'dim_bal_app_hard': 'Dimension Balance/Appearance/Hardness',
897
-    'dim_bal_app_rot_hard': 'Dimension Balance/Appearance/Rotation/Hardness',
898
-    'thickness_8_point': 'Thickness 8 Points',
899
-    'centering': 'Centering',
900
-}
901 894
 def get_fields(model):
902 895
     # model_fields = {f.name: f for f in model._meta.get_fields()}
903 896
     # fields = list(model_fields.values())
@@ -1051,3 +1044,78 @@ def gen_report_view(request):
1051 1044
 
1052 1045
 
1053 1046
 
1047
+class CustomerTemplateCRUDView(ConfigurableCRUDView):
1048
+    model = CustomerTemplateMapping
1049
+    list_template_name = 'report/customer_template_list.html'
1050
+    detail_template_name = 'legacy/datacrud_detail.html'
1051
+    form_template_name = 'report/customer_template_form.html'
1052
+    confirm_delete_template_name = 'legacy/datacrud_confirm_delete.html'
1053
+    filterset_class = CustomerTemplateFilter
1054
+
1055
+    page_title = "Customer Template Mapping"
1056
+
1057
+    # URL name mappings
1058
+    list_url_name = 'report:customer_templates-list'
1059
+    create_url_name = 'report:customer_templates-create'
1060
+    update_url_name = 'report:customer_templates-update'
1061
+    delete_url_name = 'report:customer_templates-delete'
1062
+    config_fields = ["id", "customer_name", "template_names", "created_at"] 
1063
+    config_field_orders = ["id", "customer_name", "template_names", "created_at",  "created_by"]
1064
+    # config_readonly_fields = ["lot_no"]
1065
+    config_edit_fields = None
1066
+    ordering = ["-created_at", "-id",]
1067
+    form_class = CustomerTemplateMappingForm
1068
+
1069
+
1070
+    def get_list_view(self):
1071
+        class ListViewClass(FilterView, ListView):
1072
+            model = self.model
1073
+            template_name = self.list_template_name
1074
+            paginate_by = self.paginate_by
1075
+            filterset_class = self.filterset_class
1076
+            ordering = self.ordering
1077
+
1078
+            def get_context_data(inner_self, **kwargs):
1079
+                context = super().get_context_data(**kwargs)
1080
+                fields = self.get_fields()
1081
+                context.update({
1082
+                    'fields': [f for f in fields],
1083
+                    'sheet_names': SHEET_NAMES,
1084
+
1085
+                    # 'fields': [field for field in self.model._meta.get_fields()],
1086
+                    'page_title': self.page_title,
1087
+                    'list_url': self.list_url_name,
1088
+                    'create_url': self.create_url_name,
1089
+                    'update_url': self.update_url_name,
1090
+                    'delete_url': self.delete_url_name,
1091
+                    'bs': self.get_breadcrumbs('list'),
1092
+                })
1093
+                return context
1094
+
1095
+        return ListViewClass
1096
+
1097
+
1098
+
1099
+class ProductDrawingCRUDView(ConfigurableCRUDView):
1100
+    model = ProductDrawing
1101
+    list_template_name = 'legacy/datacrud_list.html'
1102
+    detail_template_name = 'legacy/datacrud_detail.html'
1103
+    form_template_name = 'legacy/datacrud_form.html'
1104
+    confirm_delete_template_name = 'legacy/datacrud_confirm_delete.html'
1105
+    filterset_class = ProductDrawingFilter
1106
+
1107
+    page_title = "Product Drawing"
1108
+
1109
+    # URL name mappings
1110
+    list_url_name = 'report:product_drawings-list'
1111
+    create_url_name = 'report:product_drawings-create'
1112
+    update_url_name = 'report:product_drawings-update'
1113
+    delete_url_name = 'report:product_drawings-delete'
1114
+    config_fields = ["id", "code_no", "code_no_mks", "lot_no", "drawing", "description", "created_at"] 
1115
+    #config_field_orders = ["id", "customer_name", "template_names", "created_at",  "created_by"]
1116
+    # config_readonly_fields = ["lot_no"]
1117
+    config_edit_fields = None
1118
+    ordering = ["-created_at", "-id",]
1119
+    form_class = ProductDrawingForm
1120
+
1121
+

BIN
app/src.zip


+ 18 - 0
app/sysadmin/migrations/0002_alter_userprofile_position.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 4.2 on 2025-05-06 04:36
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('sysadmin', '0001_initial'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AlterField(
14
+            model_name='userprofile',
15
+            name='position',
16
+            field=models.CharField(blank=True, choices=[('QA_STAFF', 'QA Staff'), ('QA_MANAGER', 'QA. MG.'), ('QA_AST_MANAGER', 'QA. Asst. MG.'), ('QA_ENGINEER', 'QA. Engineer')], max_length=20, null=True),
17
+        ),
18
+    ]

+ 2 - 0
app/templates/base.html

@@ -66,6 +66,8 @@
66 66
                 <li><a href="/dashboard/" class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white"><span class="ml-3">Dashboard</span></a></li>
67 67
                 <li><a href="{% url "report:coi-view" %}" class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white"><span class="ml-3">COI</span></a></li>
68 68
                 <li><a href="{% url "report:report-list" %}" class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white"><span class="ml-3">Reports</span></a></li>
69
+                <li><a href="{% url "report:customer_templates-list" %}" class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white"><span class="ml-3">Customer Templates</span></a></li>
70
+                <li><a href="{% url "report:product_drawings-list" %}" class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white"><span class="ml-3">Drawing</span></a></li>
69 71
                  <li>
70 72
                     <button type="button" class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700" aria-controls="dropdown-example" data-collapse-toggle="dropdown-example">
71 73
                           <svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">

Iniciar sesión - Gogs: Simplico Git Service

Iniciar sesión