diff --git a/_base/settings.py b/_base/settings.py
index 8261409..e53a6f1 100644
--- a/_base/settings.py
+++ b/_base/settings.py
@@ -167,7 +167,7 @@ JAZZMIN_SETTINGS = {
# Copyright on the footer
"copyright": "سامانه شفافیت",
# Logo to use for your site, must be present in static files, used for brand on top left
- # "site_logo": "../static/dist/img/iconlogo.png",
+ "site_logo": "../static/dist/img/iconlogo.png",
# Relative paths to custom CSS/JS scripts (must be present in static files)
"custom_css": "../static/admin/css/custom_rtl.css",
"custom_js": None,
diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py
index 7b35fb7..de431d4 100644
--- a/accounts/migrations/0001_initial.py
+++ b/accounts/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 5.2.4 on 2025-09-07 07:35
+# Generated by Django 5.2.4 on 2025-08-14 09:02
import django.core.validators
import django.db.models.deletion
@@ -17,27 +17,6 @@ class Migration(migrations.Migration):
]
operations = [
- migrations.CreateModel(
- name='Company',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created', models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ایجاد')),
- ('updated', models.DateTimeField(auto_now=True, verbose_name='تاریخ بروزرسانی')),
- ('is_active', models.BooleanField(default=True, verbose_name='فعال')),
- ('is_deleted', models.BooleanField(default=False, verbose_name='حذف شده')),
- ('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='تاریخ حذف')),
- ('slug', models.SlugField(max_length=100, unique=True, verbose_name='اسلاگ')),
- ('name', models.CharField(max_length=100, verbose_name='نام')),
- ('logo', models.ImageField(blank=True, null=True, upload_to='companies/logos', verbose_name='لوگوی شرکت')),
- ('signature', models.ImageField(blank=True, null=True, upload_to='companies/signatures', verbose_name='امضای شرکت')),
- ('address', models.TextField(blank=True, null=True, verbose_name='آدرس')),
- ('phone', models.CharField(blank=True, max_length=11, null=True, verbose_name='شماره تماس')),
- ],
- options={
- 'verbose_name': 'شرکت',
- 'verbose_name_plural': 'شرکت\u200cها',
- },
- ),
migrations.CreateModel(
name='HistoricalProfile',
fields=[
@@ -51,7 +30,6 @@ class Migration(migrations.Migration):
('address', models.TextField(blank=True, null=True, verbose_name='آدرس')),
('card_number', models.CharField(blank=True, max_length=16, null=True, validators=[django.core.validators.RegexValidator(code='invalid_card_number', message='شماره کارت باید فقط شامل اعداد باشد.', regex='^\\d+$')], verbose_name='شماره کارت')),
('account_number', models.CharField(blank=True, max_length=20, null=True, validators=[django.core.validators.RegexValidator(code='invalid_account_number', message='شماره حساب باید فقط شامل اعداد باشد.', regex='^\\d+$')], verbose_name='شماره حساب')),
- ('bank_name', models.CharField(blank=True, choices=[('mellat', 'بانک ملت'), ('saman', 'بانک سامان'), ('parsian', 'بانک پارسیان'), ('sina', 'بانک سینا'), ('tejarat', 'بانک تجارت'), ('tosee', 'بانک توسعه'), ('iran_zamin', 'بانک ایران زمین'), ('meli', 'بانک ملی'), ('saderat', 'بانک توسعه صادرات'), ('iran_zamin', 'بانک ایران زمین'), ('refah', 'بانک رفاه'), ('eghtesad_novin', 'بانک اقتصاد نوین'), ('pasargad', 'بانک پاسارگاد'), ('other', 'سایر')], max_length=255, null=True, verbose_name='نام بانک')),
('phone_number_1', models.CharField(blank=True, max_length=11, null=True, verbose_name='شماره تماس ۱')),
('phone_number_2', models.CharField(blank=True, max_length=11, null=True, verbose_name='شماره تماس ۲')),
('pic', models.TextField(default='../static/sample_images/profile.jpg', max_length=100, verbose_name='تصویر')),
@@ -106,7 +84,6 @@ class Migration(migrations.Migration):
('address', models.TextField(blank=True, null=True, verbose_name='آدرس')),
('card_number', models.CharField(blank=True, max_length=16, null=True, validators=[django.core.validators.RegexValidator(code='invalid_card_number', message='شماره کارت باید فقط شامل اعداد باشد.', regex='^\\d+$')], verbose_name='شماره کارت')),
('account_number', models.CharField(blank=True, max_length=20, null=True, validators=[django.core.validators.RegexValidator(code='invalid_account_number', message='شماره حساب باید فقط شامل اعداد باشد.', regex='^\\d+$')], verbose_name='شماره حساب')),
- ('bank_name', models.CharField(blank=True, choices=[('mellat', 'بانک ملت'), ('saman', 'بانک سامان'), ('parsian', 'بانک پارسیان'), ('sina', 'بانک سینا'), ('tejarat', 'بانک تجارت'), ('tosee', 'بانک توسعه'), ('iran_zamin', 'بانک ایران زمین'), ('meli', 'بانک ملی'), ('saderat', 'بانک توسعه صادرات'), ('iran_zamin', 'بانک ایران زمین'), ('refah', 'بانک رفاه'), ('eghtesad_novin', 'بانک اقتصاد نوین'), ('pasargad', 'بانک پاسارگاد'), ('other', 'سایر')], max_length=255, null=True, verbose_name='نام بانک')),
('phone_number_1', models.CharField(blank=True, max_length=11, null=True, verbose_name='شماره تماس ۱')),
('phone_number_2', models.CharField(blank=True, max_length=11, null=True, verbose_name='شماره تماس ۲')),
('pic', models.ImageField(default='../static/sample_images/profile.jpg', upload_to='profile_images', verbose_name='تصویر')),
diff --git a/accounts/migrations/0002_company.py b/accounts/migrations/0002_company.py
new file mode 100644
index 0000000..c944cdf
--- /dev/null
+++ b/accounts/migrations/0002_company.py
@@ -0,0 +1,34 @@
+# Generated by Django 5.2.4 on 2025-08-21 06:33
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('accounts', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Company',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created', models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ایجاد')),
+ ('updated', models.DateTimeField(auto_now=True, verbose_name='تاریخ بروزرسانی')),
+ ('is_active', models.BooleanField(default=True, verbose_name='فعال')),
+ ('is_deleted', models.BooleanField(default=False, verbose_name='حذف شده')),
+ ('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='تاریخ حذف')),
+ ('slug', models.SlugField(max_length=100, unique=True, verbose_name='اسلاگ')),
+ ('name', models.CharField(max_length=100, verbose_name='نام')),
+ ('logo', models.ImageField(blank=True, null=True, upload_to='companies/logos', verbose_name='لوگوی شرکت')),
+ ('signature', models.ImageField(blank=True, null=True, upload_to='companies/signatures', verbose_name='امضای شرکت')),
+ ('address', models.TextField(blank=True, null=True, verbose_name='آدرس')),
+ ('phone', models.CharField(blank=True, max_length=11, null=True, verbose_name='شماره تماس')),
+ ],
+ options={
+ 'verbose_name': 'شرکت',
+ 'verbose_name_plural': 'شرکت\u200cها',
+ },
+ ),
+ ]
diff --git a/accounts/migrations/0003_historicalprofile_bank_name_profile_bank_name.py b/accounts/migrations/0003_historicalprofile_bank_name_profile_bank_name.py
new file mode 100644
index 0000000..6becfec
--- /dev/null
+++ b/accounts/migrations/0003_historicalprofile_bank_name_profile_bank_name.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.2.4 on 2025-08-21 07:06
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('accounts', '0002_company'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='historicalprofile',
+ name='bank_name',
+ field=models.CharField(blank=True, choices=[('mellat', 'بانک ملت'), ('saman', 'بانک سامان'), ('parsian', 'بانک پارسیان'), ('sina', 'بانک سینا'), ('tejarat', 'بانک تجارت'), ('tosee', 'بانک توسعه'), ('iran_zamin', 'بانک ایران زمین'), ('meli', 'بانک ملی'), ('saderat', 'بانک توسعه صادرات'), ('iran_zamin', 'بانک ایران زمین'), ('refah', 'بانک رفاه'), ('eghtesad_novin', 'بانک اقتصاد نوین'), ('pasargad', 'بانک پاسارگاد'), ('other', 'سایر')], max_length=255, null=True, verbose_name='نام بانک'),
+ ),
+ migrations.AddField(
+ model_name='profile',
+ name='bank_name',
+ field=models.CharField(blank=True, choices=[('mellat', 'بانک ملت'), ('saman', 'بانک سامان'), ('parsian', 'بانک پارسیان'), ('sina', 'بانک سینا'), ('tejarat', 'بانک تجارت'), ('tosee', 'بانک توسعه'), ('iran_zamin', 'بانک ایران زمین'), ('meli', 'بانک ملی'), ('saderat', 'بانک توسعه صادرات'), ('iran_zamin', 'بانک ایران زمین'), ('refah', 'بانک رفاه'), ('eghtesad_novin', 'بانک اقتصاد نوین'), ('pasargad', 'بانک پاسارگاد'), ('other', 'سایر')], max_length=255, null=True, verbose_name='نام بانک'),
+ ),
+ ]
diff --git a/accounts/templates/accounts/login.html b/accounts/templates/accounts/login.html
index e5791f3..67f300d 100644
--- a/accounts/templates/accounts/login.html
+++ b/accounts/templates/accounts/login.html
@@ -64,18 +64,21 @@ layout-wide customizer-hide
سامانه شفافیت
+
+
Welcome to Sneat! 👋
+ Please sign-in to your account and start the adventure
+
+ New on our platform?
+
+ Create an account
+
+
+
+
+
+
diff --git a/accounts/urls.py b/accounts/urls.py
index ac5119d..8352a63 100644
--- a/accounts/urls.py
+++ b/accounts/urls.py
@@ -1,11 +1,10 @@
from django.urls import path
-from accounts.views import login_view, dashboard, customer_list, add_customer_ajax, edit_customer_ajax, get_customer_data, logout_view
+from accounts.views import login_view, dashboard, customer_list, add_customer_ajax, edit_customer_ajax, get_customer_data
app_name = "accounts"
urlpatterns = [
path('login/', login_view, name='login'),
- path('logout/', logout_view, name='logout'),
path('dashboard/', dashboard, name='dashboard'),
path('customers/', customer_list, name='customer_list'),
path('customers/add/', add_customer_ajax, name='add_customer_ajax'),
diff --git a/accounts/views.py b/accounts/views.py
index 6a4f23c..b238b5e 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -1,11 +1,11 @@
from django.contrib import messages
-from django.contrib.auth import login, authenticate, logout
+from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse
from django.views.decorators.http import require_POST, require_GET
from django.views.decorators.csrf import csrf_exempt
from django import forms
-from django.contrib.auth.decorators import login_required
+
from accounts.models import Profile
from accounts.forms import CustomerForm
from common.consts import UserRoles
@@ -21,12 +21,15 @@ def login_view(request):
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(request, username=username, password=password)
- if user is not None:
- login(request, user)
- return redirect("processes:request_list")
- else:
- messages.error(request, "کاربری با این مشخصات یافت نشد!")
- return redirect("accounts:login")
+ # if user is not None:
+ # login(request, user)
+ # if user.profile.has_none_of([UserRoles.MANAGER]):
+ # return redirect("dashboard:dashboard")
+ # else:
+ # return redirect("dashboard:admin_dashboard")
+ # else:
+ # messages.error(request, "کاربری با این مشخصات یافت نشد!")
+ # return redirect("accounts:login")
return render(request, "accounts/login.html")
@@ -34,7 +37,7 @@ def dashboard(request):
return render(request, "accounts/dashboard.html")
-@login_required
+
def customer_list(request):
# Get all profiles that have customer role
customers = Profile.objects.filter(roles__slug=UserRoles.CUSTOMER.value, is_deleted=False).select_related('user')
@@ -160,9 +163,3 @@ def get_customer_data(request, customer_id):
},
'form_html': form_html
})
-
-
-def logout_view(request):
- """Log out current user and redirect to login page."""
- logout(request)
- return redirect("accounts:login")
diff --git a/certificates/migrations/0001_initial.py b/certificates/migrations/0001_initial.py
index b5753ec..83533bd 100644
--- a/certificates/migrations/0001_initial.py
+++ b/certificates/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 5.2.4 on 2025-09-07 07:35
+# Generated by Django 5.2.4 on 2025-08-22 09:58
import django.db.models.deletion
from django.db import migrations, models
@@ -9,7 +9,6 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('accounts', '0001_initial'),
('processes', '0001_initial'),
]
@@ -24,8 +23,10 @@ class Migration(migrations.Migration):
('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='تاریخ حذف')),
('title', models.CharField(max_length=200, verbose_name='عنوان')),
('body', models.TextField(verbose_name='متن قالب (با جایگزین\u200cها)')),
+ ('company_logo', models.ImageField(blank=True, null=True, upload_to='certificates/logos/%Y/%m/%d/', verbose_name='لوگو')),
+ ('company_name', models.CharField(blank=True, max_length=200, verbose_name='نام شرکت')),
+ ('company_seal_signature', models.ImageField(blank=True, null=True, upload_to='certificates/seals/%Y/%m/%d/', verbose_name='مهر و امضا')),
('is_active', models.BooleanField(default=True, verbose_name='فعال')),
- ('company', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.company', verbose_name='شرکت صادر کننده')),
],
options={
'verbose_name': 'قالب گواهی',
diff --git a/certificates/migrations/0002_remove_certificatetemplate_company_logo_and_more.py b/certificates/migrations/0002_remove_certificatetemplate_company_logo_and_more.py
new file mode 100644
index 0000000..e929c5a
--- /dev/null
+++ b/certificates/migrations/0002_remove_certificatetemplate_company_logo_and_more.py
@@ -0,0 +1,32 @@
+# Generated by Django 5.2.4 on 2025-08-22 10:05
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('accounts', '0003_historicalprofile_bank_name_profile_bank_name'),
+ ('certificates', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='certificatetemplate',
+ name='company_logo',
+ ),
+ migrations.RemoveField(
+ model_name='certificatetemplate',
+ name='company_name',
+ ),
+ migrations.RemoveField(
+ model_name='certificatetemplate',
+ name='company_seal_signature',
+ ),
+ migrations.AddField(
+ model_name='certificatetemplate',
+ name='company',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.company', verbose_name='شرکت صادر کننده'),
+ ),
+ ]
diff --git a/certificates/templates/certificates/step.html b/certificates/templates/certificates/step.html
index b8923c2..3392f82 100644
--- a/certificates/templates/certificates/step.html
+++ b/certificates/templates/certificates/step.html
@@ -2,7 +2,6 @@
{% load static %}
{% load processes_tags %}
{% load humanize %}
- {% load accounts_tags %}
{% block sidebar %}
{% include 'sidebars/admin.html' %}
@@ -80,11 +79,7 @@
{% else %}{% endif %}
diff --git a/certificates/views.py b/certificates/views.py
index 761ee83..428c5ba 100644
--- a/certificates/views.py
+++ b/certificates/views.py
@@ -9,7 +9,6 @@ from processes.models import ProcessInstance, StepInstance
from invoices.models import Invoice
from installations.models import InstallationReport
from .models import CertificateTemplate, CertificateInstance
-from common.consts import UserRoles
from _helpers.jalali import Gregorian
@@ -79,14 +78,6 @@ def certificate_step(request, instance_id, step_id):
next_step = instance.process.steps.filter(order__gt=instance.current_step.order).first() if instance.current_step else None
if request.method == 'POST':
- # Only broker can approve and finish certificate step
- try:
- if not (hasattr(request.user, 'profile') and request.user.profile.has_role(UserRoles.BROKER)):
- messages.error(request, 'شما مجوز تایید این مرحله را ندارید')
- return redirect('processes:step_detail', instance_id=instance.id, step_id=step.id)
- except Exception:
- messages.error(request, 'شما مجوز تایید این مرحله را ندارید')
- return redirect('processes:step_detail', instance_id=instance.id, step_id=step.id)
cert.approved = True
cert.approved_at = timezone.now()
cert.save()
@@ -98,10 +89,7 @@ def certificate_step(request, instance_id, step_id):
instance.current_step = next_step
instance.save()
return redirect('processes:step_detail', instance_id=instance.id, step_id=next_step.id)
- # Mark the whole process instance as completed on the last step
- instance.status = 'completed'
- instance.save()
- return redirect('processes:instance_summary', instance_id=instance.id)
+ return redirect('processes:request_list')
return render(request, 'certificates/step.html', {
'instance': instance,
diff --git a/contracts/migrations/0001_initial.py b/contracts/migrations/0001_initial.py
index 25acea6..8f9f4b7 100644
--- a/contracts/migrations/0001_initial.py
+++ b/contracts/migrations/0001_initial.py
@@ -1,6 +1,7 @@
-# Generated by Django 5.2.4 on 2025-09-07 07:35
+# Generated by Django 5.2.4 on 2025-08-21 06:00
import django.db.models.deletion
+import simple_history.models
from django.conf import settings
from django.db import migrations, models
@@ -10,7 +11,6 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('accounts', '0001_initial'),
('processes', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
@@ -28,7 +28,8 @@ class Migration(migrations.Migration):
('slug', models.SlugField(max_length=100, unique=True, verbose_name='اسلاگ')),
('name', models.CharField(max_length=100, verbose_name='نام')),
('body', models.TextField(verbose_name='متن قرارداد')),
- ('company', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.company', verbose_name='شرکت')),
+ ('company_logo', models.ImageField(blank=True, null=True, upload_to='contracts/logos/%Y/%m/%d/', verbose_name='لوگوی شرکت')),
+ ('company_signature', models.ImageField(blank=True, null=True, upload_to='contracts/signatures/%Y/%m/%d/', verbose_name='امضای شرکت')),
],
options={
'verbose_name': 'قالب قرارداد',
@@ -57,4 +58,61 @@ class Migration(migrations.Migration):
'ordering': ['-created'],
},
),
+ migrations.CreateModel(
+ name='HistoricalContractInstance',
+ fields=[
+ ('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
+ ('created', models.DateTimeField(blank=True, editable=False, verbose_name='تاریخ ایجاد')),
+ ('updated', models.DateTimeField(blank=True, editable=False, verbose_name='تاریخ بروزرسانی')),
+ ('is_active', models.BooleanField(default=True, verbose_name='فعال')),
+ ('is_deleted', models.BooleanField(default=False, verbose_name='حذف شده')),
+ ('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='تاریخ حذف')),
+ ('rendered_body', models.TextField(verbose_name='متن نهایی قرارداد')),
+ ('approved', models.BooleanField(default=False, verbose_name='تایید شده')),
+ ('approved_at', models.DateTimeField(blank=True, null=True, verbose_name='تاریخ تایید')),
+ ('history_id', models.AutoField(primary_key=True, serialize=False)),
+ ('history_date', models.DateTimeField(db_index=True)),
+ ('history_change_reason', models.CharField(max_length=100, null=True)),
+ ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
+ ('created_by', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='ایجاد کننده')),
+ ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
+ ('process_instance', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='processes.processinstance', verbose_name='نمونه فرآیند')),
+ ('template', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='contracts.contracttemplate', verbose_name='قالب مورد استفاده')),
+ ],
+ options={
+ 'verbose_name': 'historical قرارداد',
+ 'verbose_name_plural': 'historical قراردادها',
+ 'ordering': ('-history_date', '-history_id'),
+ 'get_latest_by': ('history_date', 'history_id'),
+ },
+ bases=(simple_history.models.HistoricalChanges, models.Model),
+ ),
+ migrations.CreateModel(
+ name='HistoricalContractTemplate',
+ fields=[
+ ('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
+ ('created', models.DateTimeField(blank=True, editable=False, verbose_name='تاریخ ایجاد')),
+ ('updated', models.DateTimeField(blank=True, editable=False, verbose_name='تاریخ بروزرسانی')),
+ ('is_active', models.BooleanField(default=True, verbose_name='فعال')),
+ ('is_deleted', models.BooleanField(default=False, verbose_name='حذف شده')),
+ ('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='تاریخ حذف')),
+ ('slug', models.SlugField(max_length=100, verbose_name='اسلاگ')),
+ ('name', models.CharField(max_length=100, verbose_name='نام')),
+ ('body', models.TextField(verbose_name='متن قرارداد')),
+ ('company_logo', models.TextField(blank=True, max_length=100, null=True, verbose_name='لوگوی شرکت')),
+ ('company_signature', models.TextField(blank=True, max_length=100, null=True, verbose_name='امضای شرکت')),
+ ('history_id', models.AutoField(primary_key=True, serialize=False)),
+ ('history_date', models.DateTimeField(db_index=True)),
+ ('history_change_reason', models.CharField(max_length=100, null=True)),
+ ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
+ ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'verbose_name': 'historical قالب قرارداد',
+ 'verbose_name_plural': 'historical قالب\u200cهای قرارداد',
+ 'ordering': ('-history_date', '-history_id'),
+ 'get_latest_by': ('history_date', 'history_id'),
+ },
+ bases=(simple_history.models.HistoricalChanges, models.Model),
+ ),
]
diff --git a/contracts/migrations/0002_remove_historicalcontracttemplate_history_user_and_more.py b/contracts/migrations/0002_remove_historicalcontracttemplate_history_user_and_more.py
new file mode 100644
index 0000000..60d434d
--- /dev/null
+++ b/contracts/migrations/0002_remove_historicalcontracttemplate_history_user_and_more.py
@@ -0,0 +1,38 @@
+# Generated by Django 5.2.4 on 2025-08-21 06:33
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('accounts', '0002_company'),
+ ('contracts', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='historicalcontracttemplate',
+ name='history_user',
+ ),
+ migrations.RemoveField(
+ model_name='contracttemplate',
+ name='company_logo',
+ ),
+ migrations.RemoveField(
+ model_name='contracttemplate',
+ name='company_signature',
+ ),
+ migrations.AddField(
+ model_name='contracttemplate',
+ name='company',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.company', verbose_name='شرکت'),
+ ),
+ migrations.DeleteModel(
+ name='HistoricalContractInstance',
+ ),
+ migrations.DeleteModel(
+ name='HistoricalContractTemplate',
+ ),
+ ]
diff --git a/contracts/templates/contracts/contract_step.html b/contracts/templates/contracts/contract_step.html
index df4fdfc..33ff326 100644
--- a/contracts/templates/contracts/contract_step.html
+++ b/contracts/templates/contracts/contract_step.html
@@ -41,36 +41,32 @@
- {% if can_view_contract_body %}
- {% if template.company.logo %}
-
-

-
{{ contract.template.company.name }}
-
{{ contract.template.name }}
-
- {% endif %}
+ {% if template.company.logo %}
+
+

+
{{ contract.template.company.name }}
+
{{ contract.template.name }}
+
+ {% endif %}
-
تاریخ: {{ contract.jcreated }}
-
-
{{ contract.rendered_body|safe }}
-
-
-
-
-
امضای شرکت
-
- {% if template.company.signature %}
-

- {% endif %}
-
+
تاریخ: {{ contract.jcreated }}
+
+
{{ contract.rendered_body|safe }}
+
+
+
+
+
امضای شرکت
+
+ {% if template.company.signature %}
+

+ {% endif %}
- {% else %}
-
شما دسترسی به مشاهده متن قرارداد را ندارید.
- {% endif %}
+
diff --git a/contracts/views.py b/contracts/views.py
index 1949665..f2d0deb 100644
--- a/contracts/views.py
+++ b/contracts/views.py
@@ -4,7 +4,6 @@ from django.urls import reverse
from django.utils import timezone
from django.template import Template, Context
from processes.models import ProcessInstance, StepInstance
-from common.consts import UserRoles
from .models import ContractTemplate, ContractInstance
from _helpers.utils import jalali_converter2
@@ -35,20 +34,6 @@ def contract_step(request, instance_id, step_id):
step = get_object_or_404(instance.process.steps, id=step_id)
previous_step = instance.process.steps.filter(order__lt=step.order).last()
next_step = instance.process.steps.filter(order__gt=step.order).first()
- # Access control:
- # - INSTALLER: can open step but cannot view contract body (show inline message)
- # - Others: can view
- # - Only BROKER can submit/complete this step
- profile = getattr(request.user, 'profile', None)
- is_broker = False
- can_view_contract_body = True
- try:
- is_broker = bool(profile and profile.has_role(UserRoles.BROKER))
- if profile and profile.has_role(UserRoles.INSTALLER):
- can_view_contract_body = False
- except Exception:
- pass
-
template_obj = ContractTemplate.objects.first()
if not template_obj:
return render(request, 'contracts/contract_missing.html', {'instance': instance})
@@ -69,11 +54,8 @@ def contract_step(request, instance_id, step_id):
contract.rendered_body = rendered
contract.save()
- # If user submits to go next, only broker can complete and go to next
+ # If user submits to go next, mark this step completed and go to next
if request.method == 'POST':
- if not is_broker:
- from django.http import JsonResponse
- return JsonResponse({'success': False, 'message': 'شما مجوز تایید این مرحله را ندارید'}, status=403)
StepInstance.objects.update_or_create(
process_instance=instance,
step=step,
@@ -92,8 +74,6 @@ def contract_step(request, instance_id, step_id):
'template': template_obj,
'previous_step': previous_step,
'next_step': next_step,
- 'is_broker': is_broker,
- 'can_view_contract_body': can_view_contract_body,
})
diff --git a/db.sqlite3 b/db.sqlite3
deleted file mode 100644
index e02ec79..0000000
Binary files a/db.sqlite3 and /dev/null differ
diff --git a/installations/migrations/0001_initial.py b/installations/migrations/0001_initial.py
index 41f02f5..05cedcd 100644
--- a/installations/migrations/0001_initial.py
+++ b/installations/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 5.2.4 on 2025-09-07 07:35
+# Generated by Django 5.2.4 on 2025-08-21 08:25
import django.db.models.deletion
from django.conf import settings
@@ -10,7 +10,7 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('invoices', '0001_initial'),
+ ('invoices', '0002_historicalpayment_receipt_image_and_more'),
('processes', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
@@ -53,8 +53,6 @@ class Migration(migrations.Migration):
('utm_x', models.DecimalField(blank=True, decimal_places=6, max_digits=10, null=True, verbose_name='UTM X')),
('utm_y', models.DecimalField(blank=True, decimal_places=6, max_digits=10, null=True, verbose_name='UTM Y')),
('description', models.TextField(blank=True, verbose_name='توضیحات')),
- ('approved', models.BooleanField(default=False, verbose_name='تایید شده')),
- ('approved_at', models.DateTimeField(blank=True, null=True, verbose_name='تاریخ تایید')),
('assignment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reports', to='installations.installationassignment', verbose_name='اختصاص')),
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='ایجادکننده')),
],
diff --git a/installations/migrations/0002_installationreport_approved_and_more.py b/installations/migrations/0002_installationreport_approved_and_more.py
new file mode 100644
index 0000000..d5df3c8
--- /dev/null
+++ b/installations/migrations/0002_installationreport_approved_and_more.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.2.4 on 2025-08-21 09:04
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('installations', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='installationreport',
+ name='approved',
+ field=models.BooleanField(default=False, verbose_name='تایید شده'),
+ ),
+ migrations.AddField(
+ model_name='installationreport',
+ name='approved_at',
+ field=models.DateTimeField(blank=True, null=True, verbose_name='تاریخ تایید'),
+ ),
+ ]
diff --git a/installations/templates/installations/installation_assign_step.html b/installations/templates/installations/installation_assign_step.html
index 2bdbe4d..c1d6c79 100644
--- a/installations/templates/installations/installation_assign_step.html
+++ b/installations/templates/installations/installation_assign_step.html
@@ -1,7 +1,6 @@
{% extends '_base.html' %}
{% load static %}
{% load processes_tags %}
-{% load common_tags %}
{% load humanize %}
{% block sidebar %}
@@ -42,15 +41,12 @@
- {% if show_denied_msg %}
-
شما اجازه تعیین نصاب را ندارید.
- {% endif %}
diff --git a/installations/templates/installations/installation_report_step.html b/installations/templates/installations/installation_report_step.html
index 6044f53..275f7bc 100644
--- a/installations/templates/installations/installation_report_step.html
+++ b/installations/templates/installations/installation_report_step.html
@@ -2,7 +2,6 @@
{% load static %}
{% load processes_tags %}
{% load common_tags %}
-{% load accounts_tags %}
{% load humanize %}
{% block sidebar %}
@@ -20,18 +19,6 @@
-
-
{% endblock %}
{% block content %}
@@ -54,27 +41,13 @@
{% stepper_header instance step %}
+
{% if report and not edit_mode %}
-