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/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 @@تاریخ مراجعه: {{ report.visited_date|to_jalali|default:'-' }}
@@ -86,9 +67,6 @@