fix print and preview quote and add broker to req and complete company model.
This commit is contained in:
parent
5ce94214d5
commit
246a2c0759
19 changed files with 872 additions and 260 deletions
|
@ -54,6 +54,7 @@ class ProcessInstanceAdmin(SimpleHistoryAdmin):
|
|||
'well_display',
|
||||
'representative',
|
||||
'requester',
|
||||
'broker',
|
||||
'process',
|
||||
'status_display',
|
||||
'priority_display',
|
||||
|
@ -65,7 +66,8 @@ class ProcessInstanceAdmin(SimpleHistoryAdmin):
|
|||
'status',
|
||||
'priority',
|
||||
'created',
|
||||
'well__representative'
|
||||
'well__representative',
|
||||
'broker'
|
||||
]
|
||||
search_fields = [
|
||||
'code',
|
||||
|
@ -86,6 +88,7 @@ class ProcessInstanceAdmin(SimpleHistoryAdmin):
|
|||
'well',
|
||||
'representative',
|
||||
'requester',
|
||||
'broker',
|
||||
'process',
|
||||
'current_step'
|
||||
]
|
||||
|
@ -99,7 +102,7 @@ class ProcessInstanceAdmin(SimpleHistoryAdmin):
|
|||
'fields': ('well', 'representative')
|
||||
}),
|
||||
('اطلاعات درخواست', {
|
||||
'fields': ('requester', 'priority')
|
||||
'fields': ('requester', 'broker', 'priority')
|
||||
}),
|
||||
('وضعیت و پیشرفت', {
|
||||
'fields': ('status', 'current_step')
|
||||
|
|
20
processes/migrations/0002_processinstance_broker.py
Normal file
20
processes/migrations/0002_processinstance_broker.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 5.2.4 on 2025-09-07 13:43
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('locations', '0003_remove_broker_company'),
|
||||
('processes', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='processinstance',
|
||||
name='broker',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='process_instances', to='locations.broker', verbose_name='کارگزار'),
|
||||
),
|
||||
]
|
|
@ -5,7 +5,7 @@ from simple_history.models import HistoricalRecords
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
from accounts.models import Role
|
||||
from accounts.models import Role, Broker
|
||||
from _helpers.utils import generate_unique_slug
|
||||
import random
|
||||
|
||||
|
@ -174,7 +174,7 @@ class ProcessInstance(SluggedModel):
|
|||
blank=True,
|
||||
verbose_name="مرحله فعلی",
|
||||
)
|
||||
|
||||
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=STATUS_CHOICES,
|
||||
|
@ -188,6 +188,15 @@ class ProcessInstance(SluggedModel):
|
|||
default='medium',
|
||||
verbose_name="اولویت"
|
||||
)
|
||||
|
||||
broker = models.ForeignKey(
|
||||
Broker,
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name="کارگزار",
|
||||
blank=True,
|
||||
null=True,
|
||||
related_name='process_instances'
|
||||
)
|
||||
|
||||
completed_at = models.DateTimeField(
|
||||
null=True,
|
||||
|
@ -205,13 +214,6 @@ class ProcessInstance(SluggedModel):
|
|||
return f"{self.process.name} - {self.well.water_subscription_number}"
|
||||
return f"{self.process.name} - {self.requester.get_full_name()}"
|
||||
|
||||
def clean(self):
|
||||
"""اعتبارسنجی مدل"""
|
||||
if self.well and self.representative and self.well.representative != self.representative:
|
||||
raise ValidationError("نماینده درخواست باید همان نماینده ثبت شده در چاه باشد")
|
||||
|
||||
if self.well and self.representative and self.requester == self.representative:
|
||||
raise ValidationError("درخواست کننده نمیتواند نماینده چاه باشد")
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Generate unique 5-digit numeric code if missing
|
||||
|
@ -233,6 +235,13 @@ class ProcessInstance(SluggedModel):
|
|||
if self.status == 'completed' and not self.completed_at:
|
||||
self.completed_at = timezone.now()
|
||||
|
||||
# Auto-set broker if not already set
|
||||
if not self.broker:
|
||||
if self.well and hasattr(self.well, 'broker') and self.well.broker:
|
||||
self.broker = self.well.broker
|
||||
elif self.requester and hasattr(self.requester, 'profile') and self.requester.profile and hasattr(self.requester.profile, 'broker') and self.requester.profile.broker:
|
||||
self.broker = self.requester.profile.broker
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_status_display_with_color(self):
|
||||
|
|
275
processes/templates/processes/includes/instance_info_modal.html
Normal file
275
processes/templates/processes/includes/instance_info_modal.html
Normal file
|
@ -0,0 +1,275 @@
|
|||
{% load common_tags %}
|
||||
|
||||
<!-- Modal for Instance Info -->
|
||||
<div class="modal fade" id="{{ modal_id }}" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">اطلاعات درخواست {{ instance.code }}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row g-4">
|
||||
|
||||
<!-- Well Information -->
|
||||
{% if well %}
|
||||
<div class="col-12">
|
||||
<div class="card border-0 bg-light">
|
||||
<div class="card-header bg-label-primary text-white py-2">
|
||||
<h6 class="mb-0">
|
||||
<i class="bx bx-water me-2"></i>اطلاعات چاه
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-droplet text-primary me-2"></i>
|
||||
<strong>شماره اشتراک آب:</strong>
|
||||
<span class="ms-2">{{ well.water_subscription_number|default:"-" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-bolt text-warning me-2"></i>
|
||||
<strong>شماره اشتراک برق:</strong>
|
||||
<span class="ms-2">{{ well.electricity_subscription_number|default:"-" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-barcode text-info me-2"></i>
|
||||
<strong>سریال کنتور:</strong>
|
||||
<span class="ms-2">{{ well.water_meter_serial_number|default:"-" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-barcode-reader text-secondary me-2"></i>
|
||||
<strong>سریال قدیمی:</strong>
|
||||
<span class="ms-2">{{ well.water_meter_old_serial_number|default:"-" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if well.water_meter_manufacturer %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-factory text-success me-2"></i>
|
||||
<strong>سازنده کنتور:</strong>
|
||||
<span class="ms-2">{{ well.water_meter_manufacturer.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-tachometer text-danger me-2"></i>
|
||||
<strong>قدرت چاه:</strong>
|
||||
<span class="ms-2">{{ well.well_power|default:"-" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if well.utm_x and well.utm_y %}
|
||||
<div class="col-12">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-map text-info me-2"></i>
|
||||
<strong>مختصات:</strong>
|
||||
<span class="ms-2">X: {{ well.utm_x }}, Y: {{ well.utm_y }}</span>
|
||||
{% if well.utm_zone %}<span class="text-muted ms-2">(Zone: {{ well.utm_zone }})</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if well.county %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-map-pin text-warning me-2"></i>
|
||||
<strong>شهرستان:</strong>
|
||||
<span class="ms-2">{{ well.county }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if well.affairs %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-building text-primary me-2"></i>
|
||||
<strong>امور:</strong>
|
||||
<span class="ms-2">{{ well.affairs }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if well.reference_letter_number %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-file text-secondary me-2"></i>
|
||||
<strong>شماره معرفی نامه:</strong>
|
||||
<span class="ms-2">{{ well.reference_letter_number }}</span>
|
||||
{% if well.reference_letter_date %}
|
||||
<span class="text-muted ms-2">({{ well.reference_letter_date|to_jalali }})</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if well.representative_letter_file %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-file text-secondary me-2"></i>
|
||||
<strong>فایل نامه نمایندگی:</strong>
|
||||
<a href="{{ well.representative_letter_file.url }}" class="ms-2">دانلود</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Representative Information -->
|
||||
{% if representative %}
|
||||
<div class="col-12">
|
||||
<div class="card border-0 bg-light">
|
||||
<div class="card-header bg-label-success text-white py-2">
|
||||
<h6 class="mb-0">
|
||||
<i class="bx bx-user me-2"></i>اطلاعات نماینده
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-user-circle text-primary me-2"></i>
|
||||
<strong>نام و نام خانوادگی:</strong>
|
||||
<span class="ms-2">{{ representative.get_full_name|default:representative.username }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if representative.profile.national_code %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-id-card text-info me-2"></i>
|
||||
<strong>کد ملی:</strong>
|
||||
<span class="ms-2">{{ representative.profile.national_code }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if representative.profile.phone_number_1 %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-phone text-success me-2"></i>
|
||||
<strong>تلفن اول:</strong>
|
||||
<span class="ms-2">{{ representative.profile.phone_number_1 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if representative.profile.phone_number_2 %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-phone text-success me-2"></i>
|
||||
<strong>تلفن دوم:</strong>
|
||||
<span class="ms-2">{{ representative.profile.phone_number_2 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if representative.profile.bank_name %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-credit-card text-warning me-2"></i>
|
||||
<strong>بانک:</strong>
|
||||
<span class="ms-2">{{ representative.profile.get_bank_name_display }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if representative.profile.card_number %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-credit-card-alt text-secondary me-2"></i>
|
||||
<strong>شماره کارت:</strong>
|
||||
<span class="ms-2">{{ representative.profile.card_number }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if representative.profile.account_number %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-wallet text-info me-2"></i>
|
||||
<strong>شماره حساب:</strong>
|
||||
<span class="ms-2">{{ representative.profile.account_number }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if representative.profile.address %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-start mb-2">
|
||||
<i class="bx bx-map text-danger me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>آدرس:</strong>
|
||||
<p class="mb-0 ms-2 text-wrap">{{ representative.profile.address }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Process Information -->
|
||||
<div class="col-12">
|
||||
<div class="card border-0 bg-light">
|
||||
<div class="card-header bg-label-info text-white py-2">
|
||||
<h6 class="mb-0">
|
||||
<i class="bx bx-cog me-2"></i>اطلاعات فرآیند
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-list-ul text-primary me-2"></i>
|
||||
<strong>نوع فرآیند:</strong>
|
||||
<span class="ms-2">{{ instance.process.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-calendar text-success me-2"></i>
|
||||
<strong>تاریخ ایجاد:</strong>
|
||||
<span class="ms-2">{{ instance.jcreated }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-check-circle text-info me-2"></i>
|
||||
<strong>وضعیت:</strong>
|
||||
<span class="ms-2 badge bg-label-primary">{{ instance.get_status_display }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if instance.current_step %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bx bx-step-forward text-primary me-2"></i>
|
||||
<strong>مرحله فعلی:</strong>
|
||||
<span class="ms-2 badge bg-label-success">{{ instance.current_step.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if instance.description %}
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-start mb-2">
|
||||
<i class="bx bx-note text-secondary me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>توضیحات:</strong>
|
||||
<p class="mb-0 ms-2 text-wrap">{{ instance.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">بستن</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -50,3 +50,57 @@ def stepper_header(instance, current_step=None):
|
|||
}
|
||||
|
||||
# moved to _base/common/templatetags/common_tags.py
|
||||
|
||||
@register.inclusion_tag('processes/includes/instance_info_modal.html')
|
||||
def instance_info_modal(instance, modal_id=None):
|
||||
"""
|
||||
نمایش مدال اطلاعات کامل چاه و نماینده
|
||||
|
||||
استفاده:
|
||||
{% load processes_tags %}
|
||||
{% instance_info_modal instance %}
|
||||
|
||||
یا با modal_id سفارشی:
|
||||
{% instance_info_modal instance "myCustomModal" %}
|
||||
"""
|
||||
if not isinstance(instance, ProcessInstance):
|
||||
return {}
|
||||
|
||||
if not modal_id:
|
||||
modal_id = f"instanceInfoModal_{instance.id}"
|
||||
|
||||
return {
|
||||
'instance': instance,
|
||||
'modal_id': modal_id,
|
||||
'well': instance.well,
|
||||
'representative': instance.representative,
|
||||
}
|
||||
|
||||
@register.simple_tag
|
||||
def instance_info(instance, modal_id=None):
|
||||
"""
|
||||
آیکون info برای نمایش مدال اطلاعات
|
||||
|
||||
استفاده:
|
||||
{% load processes_tags %}
|
||||
نام کاربر: {{ user.name }} {% instance_info_icon instance %}
|
||||
|
||||
یا با modal_id سفارشی:
|
||||
{% instance_info_icon instance "myCustomModal" %}
|
||||
"""
|
||||
if not isinstance(instance, ProcessInstance):
|
||||
return ""
|
||||
|
||||
if not modal_id:
|
||||
modal_id = f"instanceInfoModal_{instance.id}"
|
||||
|
||||
html = f'''
|
||||
اشتراک آب: {instance.well.water_subscription_number }
|
||||
| نماینده: {instance.representative.profile.national_code }
|
||||
<i class="bx bx-info-circle text-muted ms-1"
|
||||
style="cursor: pointer; font-size: 14px;"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#{modal_id}"
|
||||
title="اطلاعات کامل چاه و نماینده"></i>
|
||||
'''
|
||||
return mark_safe(html)
|
||||
|
|
|
@ -237,6 +237,7 @@ def create_request_with_entities(request):
|
|||
well=well,
|
||||
representative=representative_user,
|
||||
requester=request.user,
|
||||
broker=request.user.profile.broker if request.user.profile else None,
|
||||
status='pending',
|
||||
priority='medium',
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue