update customer and organization & staffmember

This commit is contained in:
gitea 2025-03-02 12:18:32 +00:00
parent 21089f8995
commit a96b1131d3
7 changed files with 253 additions and 221 deletions

View File

@ -1,5 +1,5 @@
from django.core.cache import cache
from django.contrib.auth.models import Permission
from django.contrib.auth.models import Permission
from django.contrib.auth.models import Group
from appointment.models import Appointment, Service, StaffMember
from django.urls import reverse
@ -39,14 +39,14 @@ from .models import (
InteriorColors,
# SaleQuotation,
CarLocation,
Representative,
# SaleQuotationCar,
AdditionalServices,
Staff,
Opportunity,
Lead,
Activity,
Notes,
@ -56,7 +56,7 @@ from .models import (
DealerSettings
)
from django_ledger import models as ledger_models
from django.forms import (
from django.forms import (
DateInput,
DateTimeInput,
)
@ -86,7 +86,7 @@ class StaffForm(forms.ModelForm):
label="Email",
widget=forms.EmailInput(attrs={"class": "form-control form-control-sm"}),
)
service_offered = forms.ModelMultipleChoiceField(
label="Services Offered",
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
@ -130,22 +130,17 @@ class DealerForm(forms.ModelForm):
class CustomerForm(forms.Form):
first_name = forms.CharField()
middle_name = forms.CharField()
last_name = forms.CharField()
national_id = forms.CharField(max_length=10)
email = forms.EmailField()
phone_number = PhoneNumberField(region="SA")
address = forms.CharField()
class OrganizationForm(forms.Form):
name = forms.CharField()
arabic_name = forms.CharField()
email = forms.EmailField()
phone_number = PhoneNumberField(region="SA")
crn = forms.CharField()
vrn = forms.CharField()
national_id = forms.CharField(max_length=10,required=False)
crn = forms.CharField(required=False)
vrn = forms.CharField(required=False)
address = forms.CharField()
class OrganizationForm(CustomerForm):
contact_person = forms.CharField(required=False)
logo = forms.ImageField(required=False)
@ -448,7 +443,7 @@ class CarSelectionTable(tables.Table):
class WizardForm1(forms.Form):
hx_attrs = {
hx_attrs = {
"hx-post":"",
"hx-target": "#wizardValidationForm1",
"hx-select": "#wizardValidationForm1",
@ -516,10 +511,10 @@ class WizardForm1(forms.Form):
),
error_messages={
"required": _("You must accept the terms and privacy policy."),
},
},
)
def clean_email(self):
email = self.cleaned_data.get("email")
if email:
@ -528,7 +523,7 @@ class WizardForm1(forms.Form):
_("An account with this email already exists.")
)
return email
def clean_confirm_password(self):
password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("confirm_password")
@ -569,7 +564,7 @@ class WizardForm2(forms.Form):
phone_number = PhoneNumberField(
label=_("Phone Number"),
widget=forms.TextInput(
attrs={
attrs={
"placeholder": _("Phone"),
}
),
@ -578,7 +573,7 @@ class WizardForm2(forms.Form):
"required": _("This field is required."),
"invalid": _("Phone number must be in the format 05xxxxxxxx"),
},
required=True,
required=True,
)
@ -741,6 +736,8 @@ class LeadForm(forms.ModelForm):
"address",
"id_car_make",
"id_car_model",
"crn",
"vrn",
"year",
"source",
"channel",
@ -761,7 +758,7 @@ class LeadForm(forms.ModelForm):
class ScheduleForm(forms.ModelForm):
scheduled_at = forms.DateTimeField(
widget=DateTimeInput(attrs={"type": "datetime-local"})
)
)
class Meta:
model = Schedule
fields = ["purpose", "scheduled_type", "scheduled_at", "duration", "notes",]
@ -788,7 +785,7 @@ class OpportunityForm(forms.ModelForm):
class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["cash_account"].widget = forms.HiddenInput()
self.fields["prepaid_account"].widget = forms.HiddenInput()
self.fields["unearned_account"].widget = forms.HiddenInput()
@ -806,7 +803,7 @@ class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
class BillModelCreateForm(BillModelCreateFormBase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["cash_account"].widget = forms.HiddenInput()
self.fields["prepaid_account"].widget = forms.HiddenInput()
self.fields["unearned_account"].widget = forms.HiddenInput()
@ -877,8 +874,8 @@ class OpportunityStatusForm(forms.Form):
"hx-select": ".other-information",
"hx-swap": "outerHTML",
"hx-on::after-request": "this.setAttribute('disabled','true')",
"disabled": "disabled",
}
"disabled": "disabled",
}
),
required=True,
)
@ -887,7 +884,7 @@ class OpportunityStatusForm(forms.Form):
choices=Stage.choices,
widget=forms.Select(
attrs={
"class": "form-control form-control-sm",
"class": "form-control form-control-sm",
"hx-target": ".other-information",
"hx-select": ".other-information",
"hx-swap": "outerHTML",
@ -895,9 +892,9 @@ class OpportunityStatusForm(forms.Form):
"disabled": "disabled",
}
),
required=True,
)
required=True,
)
class GroupForm(forms.ModelForm):
class Meta:
model = CustomGroup
@ -912,11 +909,11 @@ class PermissionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
cache.set('permissions_queryset', Permission.objects.filter(content_type__app_label__in=["inventory","django_ledger"]), 60*60)
class Meta:
model = Permission
fields = ["name"]
class UserGroupForm(forms.ModelForm):
name = forms.ModelMultipleChoiceField(
queryset= CustomGroup.objects.all(),
@ -927,10 +924,10 @@ class UserGroupForm(forms.ModelForm):
model = CustomGroup
fields = ["name"]
class DealerSettingsForm(forms.ModelForm):
class DealerSettingsForm(forms.ModelForm):
class Meta:
model = DealerSettings
fields = "__all__"
class LeadTransferForm(forms.Form):
transfer_to = forms.ModelChoiceField(label="to",queryset=Staff.objects.all())
transfer_to = forms.ModelChoiceField(label="to",queryset=Staff.objects.all())

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.17 on 2025-03-01 21:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0052_lead_lead_type'),
]
operations = [
migrations.AddField(
model_name='lead',
name='crn',
field=models.CharField(blank=True, max_length=10, null=True, unique=True, verbose_name='Commercial Registration Number'),
),
migrations.AddField(
model_name='lead',
name='vrn',
field=models.CharField(blank=True, max_length=15, null=True, unique=True, verbose_name='VAT Registration Number'),
),
]

View File

@ -454,14 +454,14 @@ class Car(models.Model):
self.status = CarStatusChoices.SOLD
self.save()
Activity.objects.create(dealer=dealer,content_object=self, notes="Car Sold",created_by=request.user,activity_type=ActionChoices.SALE_CAR)
def cancel_reservation(self):
def cancel_reservation(self):
if self.reservations.exists():
self.reservations.all().delete()
def cancel_transfer(self):
if self.transfer_logs.exists():
self.transfer_logs.all().delete()
def to_dict(self):
return {
"vin": self.vin,
@ -580,9 +580,9 @@ class CarFinance(models.Model):
verbose_name=_("Discount Amount"),
default=Decimal("0.00"),
)
@property
def total(self):
def total(self):
return self.selling_price
@property
@ -947,7 +947,7 @@ class StaffTypes(models.TextChoices):
class Staff(models.Model, LocalizedNameMixin):
staff_member = models.OneToOneField(StaffMember, on_delete=models.CASCADE, related_name="staff")
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="staff")
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="staff")
name = models.CharField(max_length=255, verbose_name=_("Name"))
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
@ -957,23 +957,26 @@ class Staff(models.Model, LocalizedNameMixin):
objects = StaffUserManager()
@property
def email(self):
return self.staff_member.user.email
@property
def user(self):
return self.staff_member.user
@property
def groups(self):
def groups(self):
return [x.customgroup for x in self.user.groups.all()]
def clear_groups(self):
return self.user.groups.clear()
def add_group(self,group):
try:
self.user.groups.add(group)
except Exception as e:
pass
pass
class Meta:
verbose_name = _("Staff")
verbose_name_plural = _("Staff")
@ -1197,6 +1200,12 @@ class Lead(models.Model):
channel = models.CharField(
max_length=50, choices=Channel.choices, verbose_name=_("Channel")
)
crn = models.CharField(
max_length=10, unique=True, verbose_name=_("Commercial Registration Number"), blank=True, null=True
)
vrn = models.CharField(
max_length=15, unique=True, verbose_name=_("VAT Registration Number"), blank=True, null=True
)
address = models.CharField(max_length=50, verbose_name=_("address"))
staff = models.ForeignKey(
Staff,
@ -1251,7 +1260,7 @@ class Lead(models.Model):
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
def convert_to_customer(self,entity):
def convert_to_customer(self,entity,lead):
customer = entity.get_customers().filter(email=self.email).first()
if entity and not customer:
customer = entity.create_customer(
@ -1262,10 +1271,13 @@ class Lead(models.Model):
"phone": self.phone_number,
"email": self.email,
}
)
)
customer.additional_info.update({"info":self.to_dict()})
customer.additional_info.update({"type":"customer"})
if lead.lead_type == "organization":
customer.additional_info.update({"type":"organization"})
else:
customer.additional_info.update({"type":"customer"})
customer.save()
self.customer = customer
self.status = Status.QUALIFIED
@ -1415,7 +1427,7 @@ class Email(models.Model):
from_email = models.TextField(verbose_name=_("From Email"),null=True,blank=True)
to_email = models.TextField(verbose_name=_("To Email"),null=True,blank=True)
subject = models.TextField(verbose_name=_("Subject"),null=True,blank=True)
message = models.TextField(verbose_name=_("Message"),null=True,blank=True)
message = models.TextField(verbose_name=_("Message"),null=True,blank=True)
status = models.CharField(max_length=20, choices=EmailStatus.choices, verbose_name=_("Status"),default=EmailStatus.OPEN)
created_by = models.ForeignKey(
User, on_delete=models.DO_NOTHING, related_name="emails_created"
@ -1749,7 +1761,7 @@ class UserActivityLog(models.Model):
def __str__(self):
return f"{self.user.email} - {self.action} - {self.timestamp}"
class SaleOrder(models.Model):
class SaleOrder(models.Model):
estimate = models.ForeignKey(
EstimateModel,
on_delete=models.CASCADE,
@ -1772,12 +1784,12 @@ class SaleOrder(models.Model):
comments = models.TextField(blank=True, null=True)
formatted_order_id = models.CharField(max_length=10, unique=True, editable=False)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created']
def save(self, *args, **kwargs):
if not self.formatted_order_id:
if not self.formatted_order_id:
last_order = SaleOrder.objects.order_by('-id').first()
if last_order:
next_id = last_order.id + 1
@ -1792,17 +1804,17 @@ class SaleOrder(models.Model):
@property
def full_name(self):
return f"{self.customer.customer_name}"
@property
def price(self):
return self.car.finances.selling_price
@property
def items(self):
if self.estimate.get_itemtxs_data():
return self.estimate.get_itemtxs_data()[0]
return []
@property
def customer(self):
return self.estimate.customer
@ -1811,27 +1823,27 @@ class CustomGroup(models.Model):
name = models.CharField(max_length=100)
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="groups")
group = models.OneToOneField("auth.Group", verbose_name=_(""), on_delete=models.CASCADE)
@property
def users(self):
return self.group.user_set.all()
@property
def permissions(self):
return self.group.permissions.all()
def clear_permissions(self):
self.group.permissions.clear()
def add_permission(self, permission):
try:
self.group.permissions.add(permission)
except Permission.DoesNotExist:
pass
pass
def __str__(self):
return self.name
def set_default_manager_permissions(self):
self.clear_permissions()
try:
@ -1839,7 +1851,7 @@ class CustomGroup(models.Model):
self.add_permission(perm)
except Exception as e:
pass
# def set_default_inventory_permissions(self):
# self.clear_permissions()
# allowed_models = ["car","carequipment","interiorcolors","exteriorcolors","carcolors","carlocation","customcard"]
@ -1849,14 +1861,14 @@ class CustomGroup(models.Model):
# allowed_models = ["car","carfinance","carlocation","customcard"]
# allowed_models_ledger = ["accountmodel","chartofaccountmodel","customcard","billmodel"]
# self.set_permissions(allowed_models=allowed_models,other_perms=['view_carfinance'])
# self.set_permissions(app="django_ledger",allowed_models=allowed_models_ledger)
# self.set_permissions(app="django_ledger",allowed_models=allowed_models_ledger)
def set_default_permissions(self):
self.clear_permissions()
if self.name == "Manager":
self.set_permissions(app="inventory",allowed_models=["car","carfinance","carlocation","customcard"])
self.set_permissions(app="django_ledger",allowed_models=["accountmodel","chartofaccountmodel","customcard","billmodel"])
elif self.name == "Inventory":
elif self.name == "Inventory":
self.set_permissions(allowed_models=["car","carequipment","interiorcolors","exteriorcolors","carcolors","carlocation","customcard"]
,other_perms=['view_carfinance'])
elif self.name == "Sales":
@ -1869,9 +1881,9 @@ class CustomGroup(models.Model):
elif self.name == "Agent":
# Todo : set permissions for agent
pass
def set_permissions(self,app="inventory", allowed_models=[],other_perms=[]):
def set_permissions(self,app="inventory", allowed_models=[],other_perms=[]):
try:
for perm in Permission.objects.filter(content_type__app_label=app,content_type__model__in=allowed_models):
self.add_permission(perm)
@ -1880,19 +1892,19 @@ class CustomGroup(models.Model):
self.add_permission(perm)
except Exception as e:
pass
class DealerSettings(models.Model):
dealer = models.OneToOneField(Dealer, on_delete=models.CASCADE, related_name="settings",null=True, blank=True)
class DealerSettings(models.Model):
dealer = models.OneToOneField(Dealer, on_delete=models.CASCADE, related_name="settings",null=True, blank=True)
invoice_cash_account = models.ForeignKey(AccountModel,related_name="invoice_cash", on_delete=models.SET_NULL, null=True, blank=True)
invoice_prepaid_account = models.ForeignKey(AccountModel,related_name="invoice_prepaid", on_delete=models.SET_NULL, null=True, blank=True)
invoice_unearned_account = models.ForeignKey(AccountModel,related_name="invoice_unearned", on_delete=models.SET_NULL, null=True, blank=True)
bill_cash_account = models.ForeignKey(AccountModel,related_name="bill_cash", on_delete=models.SET_NULL, null=True, blank=True)
bill_prepaid_account = models.ForeignKey(AccountModel,related_name="bill_prepaid", on_delete=models.SET_NULL, null=True, blank=True)
bill_unearned_account = models.ForeignKey(AccountModel,related_name="bill_unearned", on_delete=models.SET_NULL, null=True, blank=True)
additional_info = models.JSONField(default=dict,null=True,blank=True)
def __str__(self):
return f"Settings for {self.dealer}"

View File

@ -10,7 +10,7 @@ from calendar import month_name
from pyzbar.pyzbar import decode
from urllib.parse import urlparse, urlunparse
#####################################################################
from django.db.models.deletion import RestrictedError
from django.db.models.deletion import RestrictedError
# Django
from django.db.models import Q
from django.conf import settings
@ -28,7 +28,7 @@ from django.db.models import Count, F, Value
from django.urls import reverse, reverse_lazy
from django.utils import timezone, translation
from django.db.models.functions import Coalesce
from django.contrib.auth.models import Permission
from django.contrib.auth.models import Permission
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.core.files.storage import default_storage
@ -137,7 +137,7 @@ logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
class Hash(Func):
function = 'get_hash'
function = 'get_hash'
def switch_language(request):
language = request.GET.get("language", "en")
@ -179,12 +179,12 @@ def dealer_signup(request, *args, **kwargs):
form1 = forms.WizardForm1()
form2 = forms.WizardForm2()
form3 = forms.WizardForm3()
if request.method == "POST":
if "Hx-Request" in request.headers:
form1 = forms.WizardForm1(request.POST)
if "Hx-Request" in request.headers:
form1 = forms.WizardForm1(request.POST)
return render(request,"account/signup-wizard.html",{"form1": form1, "form2": form2, "form3": form3})
data = json.loads(request.body)
wf1 = data.get("wizardValidationForm1")
wf2 = data.get("wizardValidationForm2")
@ -207,7 +207,7 @@ def dealer_signup(request, *args, **kwargs):
user = User.objects.create(username=email, email=email)
user.set_password(password)
user.save()
StaffMember.objects.create(user=user)
models.Dealer.objects.create(
user=user,
name=name,
@ -219,7 +219,7 @@ def dealer_signup(request, *args, **kwargs):
)
return JsonResponse(
{"message": "User created successfully."}, status=200
)
)
except Exception as e:
return JsonResponse({"error": str(e)}, status=400)
return render(request,"account/signup-wizard.html",{"form1": form1, "form2": form2, "form3": form3})
@ -309,7 +309,6 @@ class HomeView(TemplateView):
"total_selling_price": 0,
"total_profit": 0,
})
return context
class TestView(TemplateView):
@ -516,7 +515,7 @@ class AjaxHandlerView(LoginRequiredMixin, View):
logger.info(
f"VIN decoded using {decoding_method}: Make={manufacturer_name}, Model={model_name}, Year={year_model}"
)
)
if not car_make:
return JsonResponse(
@ -724,7 +723,7 @@ class CarColorCreate(LoginRequiredMixin, CreateView):
def form_valid(self, form):
car = get_object_or_404(models.Car, pk=self.kwargs["car_pk"])
form.instance.car = car
form.instance.car = car
return super().form_valid(form)
def get_success_url(self):
@ -744,7 +743,7 @@ class CarListView(LoginRequiredMixin, ListView):
context = super().get_context_data(**kwargs)
dealer = get_user_type(self.request)
cars = models.Car.objects.filter(dealer=dealer).order_by("receiving_date")
context["stats"] = {
'all': cars.count(),
'available':cars.filter(status='available').count(),
@ -764,19 +763,19 @@ class CarListView(LoginRequiredMixin, ListView):
if make and model:
make_ = models.CarMake.objects.get(id_car_make=int(make))
model_ = models.CarModel.objects.get(id_car_model=int(model))
context['year'] = models.Car.objects.filter(id_car_make=make_,id_car_model=model_).values_list('year').distinct()
context['year'] = models.Car.objects.filter(id_car_make=make_,id_car_model=model_).values_list('year').distinct()
return context
def get_queryset(self):
dealer = get_user_type(self.request)
qs = super().get_queryset()
qs = super().get_queryset()
qs = qs.filter(dealer=dealer)
status = self.request.GET.get('status')
status = self.request.GET.get('status')
search = self.request.GET.get('search')
make = self.request.GET.get('make',None)
model = self.request.GET.get('model',None)
year = self.request.GET.get('year',None)
car_status = self.request.GET.get('car_status',None)
if status:
qs=qs.filter(status=status)
if search:
@ -791,7 +790,7 @@ class CarListView(LoginRequiredMixin, ListView):
if year:
query &= Q(year=year)
if car_status:
query &= Q(status=car_status)
query &= Q(status=car_status)
qs = qs.filter(query)
return qs
@ -1247,14 +1246,14 @@ class CustomerDetailView(LoginRequiredMixin, DetailView):
dealer = get_user_type(self.request)
entity = dealer.entity
context = super().get_context_data(**kwargs)
estimates = entity.get_estimates().filter(customer=self.object)
invoices = entity.get_invoices().filter(customer=self.object)
# txs = entity. transactions(customer=self.object)
total = estimates.count() + invoices.count()
context["estimates"] = estimates
context["invoices"] = invoices
context["total"] = total
context["total"] = total
return context
def add_note_to_customer(request, customer_id):
@ -1296,14 +1295,13 @@ def CustomerCreateView(request):
form = forms.CustomerForm(request.POST)
dealer = get_user_type(request)
if form.is_valid():
if form.is_valid():
if dealer.entity.get_customers().filter(email=form.cleaned_data["email"]).exists():
messages.error(request, _("Customer with this email already exists."))
else:
# Create customer name
customer_name = (
f"{form.cleaned_data['first_name']} "
f"{form.cleaned_data['middle_name']} "
f"{form.cleaned_data['last_name']}"
)
customer_dict = { x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken"}
@ -1346,8 +1344,6 @@ def CustomerUpdateView(request, pk):
customer_name = (
customer_dict["first_name"]
+ " "
+ customer_dict["middle_name"]
+ " "
+ customer_dict["last_name"]
)
@ -1367,7 +1363,7 @@ def CustomerUpdateView(request, pk):
user.save()
except Exception as e:
raise Exception(e)
instance.save()
messages.success(request, _("Customer updated successfully."))
return redirect("customer_list")
@ -1384,12 +1380,12 @@ def CustomerUpdateView(request, pk):
@login_required
def delete_customer(request, pk):
customer = get_object_or_404(models.CustomerModel, pk=pk)
user = User.objects.get(email=customer.email)
user = User.objects.get(email=customer.email)
customer.active = False
user.is_active = False
customer.save()
user.save()
messages.success(request, _("Customer deleted successfully."))
return redirect("customer_list")
@ -1457,15 +1453,15 @@ class GroupListView(LoginRequiredMixin, ListView):
paginate_by = 10
template_name = "groups/group_list.html"
def get_queryset(self):
def get_queryset(self):
dealer = get_user_type(self.request)
return dealer.groups.all()
class GroupDetailView(LoginRequiredMixin, DetailView):
model = models.CustomGroup
template_name = "groups/group_detail.html"
context_object_name = "group"
context_object_name = "group"
class GroupCreateView(
LoginRequiredMixin,
@ -1501,7 +1497,7 @@ class GroupUpdateView(
def form_valid(self, form):
dealer = get_user_type(self.request)
instance = form.save(commit=False)
instance = form.save(commit=False)
instance.group.name = f"{dealer.pk}_{instance.name}"
instance.save()
return super().form_valid(form)
@ -1521,7 +1517,7 @@ def GroupPermissionView(request, pk):
for i in permissions:
group.add_permission(Permission.objects.get(id=int(i)))
messages.success(request, _("Permission added successfully."))
return redirect("group_detail", pk=group.pk)
return redirect("group_detail", pk=group.pk)
form = forms.PermissionForm(initial={"name": group.permissions})
return render(request,"groups/group_permission_form.html",{"group": group, "form": form})
@ -1529,18 +1525,18 @@ def GroupPermissionView(request, pk):
def UserGroupView(request, pk):
staff = get_object_or_404(models.Staff, pk=pk)
if request.method == "POST":
form = forms.UserGroupForm(request.POST)
groups = request.POST.getlist("name")
form = forms.UserGroupForm(request.POST)
groups = request.POST.getlist("name")
staff.clear_groups()
for i in groups:
for i in groups:
cg = models.CustomGroup.objects.get(id=int(i))
staff.add_group(cg.group)
messages.success(request, _("Group added successfully."))
return redirect("user_detail", pk=staff.pk)
form = forms.UserGroupForm(initial={"name": staff.groups})
form.fields['name'].queryset = models.CustomGroup.objects.filter(dealer=staff.dealer)
return render(request,"users/user_group_form.html",{"staff": staff, "form": form})
@ -1591,7 +1587,7 @@ class UserCreateView(
email = form.cleaned_data["email"]
password = "Tenhal@123"
user = User.objects.create_user(username=form.cleaned_data["name"], email=email, password=password)
user.is_staff = True
user.save()
@ -1606,7 +1602,7 @@ class UserCreateView(
staff.add_group(group)
staff.save()
return super().form_valid(form)
class UserUpdateView(
LoginRequiredMixin,
@ -1629,7 +1625,7 @@ class UserUpdateView(
form.fields['email'].disabled = True
return form
def get_initial(self):
initial = super().get_initial()
initial = super().get_initial()
initial['email'] = self.object.staff_member.user.email
initial['service_offered'] = self.object.staff_member.services_offered.all()
return initial
@ -1639,16 +1635,16 @@ class UserUpdateView(
self.object.staff_member.services_offered.clear()
else:
for service in services:
self.object.staff_member.services_offered.add(service)
self.object.staff_member.services_offered.add(service)
staff = form.save(commit=False)
staff.name = form.cleaned_data["name"]
staff.arabic_name = form.cleaned_data["arabic_name"]
staff.phone_number = form.cleaned_data["phone_number"]
staff.staff_type = form.cleaned_data["staff_type"]
staff.staff_type = form.cleaned_data["staff_type"]
staff.save()
return super().form_valid(form)
def UserDeleteview(request, pk):
staff = get_object_or_404(models.Staff, pk=pk)
staff.staff_member.delete()
@ -1700,15 +1696,16 @@ def OrganizationCreateView(request):
if CustomerModel.objects.filter(email=request.POST["email"]).exists():
messages.error(request, _("An organization with this email already exists."))
return redirect("organization_create")
organization_dict = {
x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken"
}
dealer = get_user_type(request)
instance = dealer.entity.create_customer(
name = organization_dict["first_name"] + " " + organization_dict["last_name"]
customer = dealer.entity.create_customer(
commit=False,
customer_model_kwargs={
"customer_name": organization_dict["name"],
"customer_name": name,
"address_1": organization_dict["address"],
"phone": organization_dict["phone_number"],
"email": organization_dict["email"],
@ -1718,12 +1715,12 @@ def OrganizationCreateView(request):
if image:
file_name = default_storage.save("images/{}".format(image.name), image)
file_url = default_storage.url(file_name)
organization_dict["logo"] = file_url
organization_dict["pk"] = str(instance.pk)
instance.additional_info["organization_info"] = organization_dict
instance.additional_info["type"] = "organization"
instance.save()
organization_dict["pk"] = str(customer.pk)
customer.additional_info.update({"customer_info": organization_dict})
customer.additional_info.update({"type": "organization"})
customer.save()
messages.success(request, _("Organization created successfully."))
return redirect("organization_list")
else:
@ -1732,44 +1729,45 @@ def OrganizationCreateView(request):
def OrganizationUpdateView(request,pk):
organization = get_object_or_404(CustomerModel, pk=pk)
organization = get_object_or_404(CustomerModel, pk=pk)
if request.method == "POST":
form = forms.OrganizationForm(request.POST)
organization_dict = {
x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken"
}
}
dealer = get_user_type(request)
instance = dealer.entity.get_customers().get(
pk=organization.additional_info["organization_info"]["pk"]
pk=organization.additional_info["customer_info"]["pk"]
)
instance.customer_name = organization_dict["name"]
name = organization_dict["first_name"] + " " + organization_dict["last_name"]
instance.customer_name = name
instance.address_1 = organization_dict["address"]
instance.phone = organization_dict["phone_number"]
instance.email = organization_dict["email"]
image = request.FILES.get("logo")
if image:
file_name = default_storage.save("images/{}".format(image.name), image)
file_url = default_storage.url(file_name)
file_url = default_storage.url(file_name)
organization_dict["logo"] = file_url
else:
organization_dict["logo"] = organization.additional_info["organization_info"]["logo"]
organization_dict["logo"] = organization.additional_info["customer_info"]["logo"]
organization_dict["pk"] = str(instance.pk)
instance.additional_info["organization_info"] = organization_dict
instance.additional_info["customer_info"] = organization_dict
instance.additional_info["type"] = "organization"
instance.save()
messages.success(request, _("Organization created successfully."))
return redirect("organization_list")
else:
form = forms.OrganizationForm(
initial=organization.additional_info["organization_info"] or {}
form = forms.OrganizationForm(
initial=organization.additional_info["customer_info"] or {}
)
# form.fields.pop("logo", None)
# form.fields.pop("logo", None)
return render(request, "organizations/organization_form.html", {"form": form})
# class OrganizationDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
# model = models.Organization
@ -2047,7 +2045,7 @@ def create_estimate(request,pk=None):
dealer = get_user_type(request)
entity = dealer.entity
if request.method == "POST":
if request.method == "POST":
# try:
data = json.loads(request.body)
title = data.get("title")
@ -2057,13 +2055,13 @@ def create_estimate(request,pk=None):
items = data.get("item", [])
quantities = data.get("quantity", [])
if not all([items, quantities]):
return JsonResponse(
{"status": "error", "message": "Items and Quantities are required"},
status=400,
)
)
if isinstance(quantities, list):
if "0" in quantities:
return JsonResponse(
@ -2084,7 +2082,7 @@ def create_estimate(request,pk=None):
if int(quantities) > models.Car.objects.filter(hash=items,status='available').count():
return JsonResponse(
{"status": "error", "message": "Quantity must be less than or equal to the number of cars in stock"},
)
)
estimate = entity.create_estimate(
estimate_title=title, customer_model=customer, contract_terms=terms
)
@ -2105,7 +2103,7 @@ def create_estimate(request,pk=None):
items_txs = []
for item in items_list:
car_instance = ItemModel.objects.filter(additional_info__car_info__hash=item.get("item_id")).all()
for i in car_instance[:int(quantities[0])]:
items_txs.append(
{
@ -2148,19 +2146,19 @@ def create_estimate(request,pk=None):
for item in estimate_itemtxs.keys():
item_instance = ItemModel.objects.filter(item_number=item).first()
instance = models.Car.objects.get(vin=item_instance.name)
reserve_car(instance, request)
reserve_car(instance, request)
else:
item_instance = ItemModel.objects.filter(additioinal_info__car_info__hash=items).first()
instance = models.Car.objects.get(hash=item)
response = reserve_car(instance, request)
opportunity_id = data.get("opportunity_id")
if opportunity_id != "None":
opportunity = models.Opportunity.objects.get(pk=int(opportunity_id))
opportunity.estimate = estimate
opportunity.save()
opportunity.save()
url = reverse("estimate_detail", kwargs={"pk": estimate.pk})
return JsonResponse(
{
@ -2174,14 +2172,14 @@ def create_estimate(request,pk=None):
entity_slug=entity.slug, user_model=entity.admin
)
form.fields["customer"].queryset = entity.get_customers().filter(active=True,additional_info__type="customer")
if pk:
opportunity = models.Opportunity.objects.get(pk=pk)
customer = opportunity.customer
form.initial['customer'] = customer
car_list = models.Car.objects.filter(dealer=dealer,colors__isnull=False,finances__isnull=False,status="available").annotate(color=F('colors__exterior__rgb'),color_name=F('colors__exterior__name')).values_list(
'id_car_make__name', 'id_car_model__name','id_car_serie__name','id_car_trim__name','color','color_name','hash').annotate(hash_count=Count('hash')).distinct()
'id_car_make__name', 'id_car_model__name','id_car_serie__name','id_car_trim__name','color','color_name','hash').annotate(hash_count=Count('hash')).distinct()
context = {
"form": form,
"items": [
@ -2200,7 +2198,7 @@ def create_estimate(request,pk=None):
"opportunity_id": pk if pk else None,
"customer_count": entity.get_customers().count()
}
return render(request, "sales/estimates/estimate_form.html", context)
@ -2214,7 +2212,7 @@ class EstimateDetailView(LoginRequiredMixin, DetailView):
if estimate.get_itemtxs_data():
calculator = CarFinanceCalculator(estimate)
finance_data = calculator.get_finance_data()
kwargs["data"] = finance_data
kwargs["invoice"] = (
InvoiceModel.objects.all().filter(ce_model=estimate).first()
@ -2238,10 +2236,10 @@ def create_sale_order(request, pk):
item.item_model.additional_info['car_info']['status'] = 'sold'
item.item_model.save()
except KeyError:
pass
pass
models.Car.objects.get(vin=item.item_model.name).mark_as_sold(request)
messages.success(request, "Sale Order created successfully")
messages.success(request, "Sale Order created successfully")
return redirect("estimate_detail", pk=pk)
form = forms.SaleOrderForm()
@ -2363,7 +2361,7 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView):
if invoice.get_itemtxs_data():
calculator = CarFinanceCalculator(invoice)
finance_data = calculator.get_finance_data()
finance_data = calculator.get_finance_data()
kwargs["data"] = finance_data
kwargs["payments"] = JournalEntryModel.objects.filter(
ledger=invoice.ledger
@ -2464,10 +2462,10 @@ def invoice_create(request, pk):
ledger.save()
invoice.save()
calculator = CarFinanceCalculator(estimate)
finance_data = calculator.get_finance_data()
invoice_itemtxs = {
i.get("item_number"): {
"unit_cost": i.get("total_vat"),
@ -2549,11 +2547,11 @@ def PaymentCreateView(request, pk):
messages.error(request,"fully paid")
return redirect(redirect_url, pk=model.pk)
if model.amount_paid + amount > model.amount_due:
messages.error(request,"Amount exceeds due amount")
messages.error(request,"Amount exceeds due amount")
return redirect(redirect_url, pk=model.pk)
try:
if invoice:
if invoice:
set_invoice_payment(dealer, entity, invoice, amount, payment_method)
elif bill:
set_bill_payment(dealer, entity, bill, amount, payment_method)
@ -2703,9 +2701,9 @@ def lead_create(request):
if form.is_valid():
instance = form.save(commit=False)
dealer = get_user_type(request)
instance.dealer = dealer
instance.dealer = dealer
instance.staff = form.cleaned_data.get("staff")
# creating customer in ledger
customer = dealer.entity.get_customers().filter(email=instance.email).first()
if not customer:
@ -2716,7 +2714,7 @@ def lead_create(request):
"address_1": instance.address,
"phone": instance.phone_number,
"email": instance.email,
"sales_tax_rate": 0.15,
"sales_tax_rate": 0.15,
}
)
customer_info = {
@ -2725,7 +2723,9 @@ def lead_create(request):
"address": instance.address,
"phone_number": str(instance.phone_number),
"email": instance.email,
}
"crn": form.cleaned_data["crn"],
"vrn": form.cleaned_data["vrn"],
}
customer.additional_info.update({"customer_info": customer_info })
customer.additional_info.update({"type":"lead"})
customer.save()
@ -2753,7 +2753,7 @@ class LeadUpdateView(UpdateView):
success_url = reverse_lazy("lead_list")
def get_form(self, form_class=None):
form = super().get_form(form_class)
form = super().get_form(form_class)
form.fields["id_car_model"].queryset = form.instance.id_car_make.carmodel_set.all()
return form
@ -2761,7 +2761,7 @@ class LeadUpdateView(UpdateView):
@login_required
def LeadDeleteView(request,pk):
lead = get_object_or_404(models.Lead, pk=pk)
try:
try:
User.objects.get(email=lead.customer.email).delete()
lead.customer.delete()
except Exception as e:
@ -2791,12 +2791,12 @@ def add_note_to_lead(request, pk):
def add_note_to_opportunity(request, pk):
opportunity = get_object_or_404(models.Opportunity, pk=pk)
if request.method == "POST":
notes = request.POST.get("notes")
notes = request.POST.get("notes")
if not notes:
messages.error(request, "Notes field is required.")
messages.error(request, "Notes field is required.")
else:
models.Notes.objects.create(content_object=opportunity, created_by=request.user,note=notes)
messages.success(request, "Note added successfully!")
messages.success(request, "Note added successfully!")
return redirect("opportunity_detail", pk=opportunity.pk)
@ -2835,8 +2835,8 @@ def lead_convert(request, pk):
dealer = get_user_type(request)
if hasattr(lead, "opportunity"):
messages.error(request, "Lead is already converted to customer.")
else:
customer = lead.convert_to_customer(dealer.entity)
else:
customer = lead.convert_to_customer(dealer.entity,lead)
models.Opportunity.objects.create(dealer=dealer,customer=customer,lead=lead,probability=50,stage=models.Stage.PROSPECT,staff=lead.staff,status=models.Status.QUALIFIED)
messages.success(request, "Lead converted to customer successfully!")
return redirect("lead_list")
@ -2860,7 +2860,7 @@ def schedule_lead(request, pk):
service = Service.objects.filter(name=instance.scheduled_type).first()
if not service:
messages.error(request, "Service not found!")
return redirect("lead_list")
return redirect("lead_list")
try:
appointment_request = AppointmentRequest.objects.create(
@ -2873,7 +2873,7 @@ def schedule_lead(request, pk):
except ValidationError as e:
messages.error(request, str(e))
return redirect("schedule_lead", pk=lead.pk)
client = get_object_or_404(User, email=lead.email)
# Create Appointment
Appointment.objects.create(
@ -2902,7 +2902,7 @@ def lead_transfer(request,pk):
if form.is_valid():
lead.staff = form.cleaned_data["transfer_to"]
lead.save()
messages.success(request, "Lead transferred successfully!")
messages.success(request, "Lead transferred successfully!")
else:
messages.error(request, f"Invalid form data: {str(form.errors)}")
return redirect("lead_list")
@ -2919,12 +2919,12 @@ def send_lead_email(request, pk,email_pk=None):
response = HttpResponse(redirect("lead_detail", pk=lead.pk))
response['HX-Redirect'] = reverse('lead_detail', args=[lead.pk])
return response
lead.status = models.Status.CONTACTED
lead.save()
# lead.convert_to_customer(dealer.entity)
if request.method == "POST":
if request.method == "POST":
email_pk = request.POST.get('email_pk')
if email_pk not in [None,"None",""]:
email = get_object_or_404(models.Email, pk=int(email_pk))
@ -2940,7 +2940,7 @@ def send_lead_email(request, pk,email_pk=None):
)
dealer = get_user_type(request)
models.Activity.objects.create(dealer=dealer,content_object=lead, notes="Email sent",created_by=request.user,activity_type=models.ActionChoices.EMAIL)
messages.success(request, _("Email sent successfully!"))
messages.success(request, _("Email sent successfully!"))
return redirect("lead_list")
msg = f"""
السلام عليكم
@ -2982,7 +2982,7 @@ def add_activity_to_lead(request, pk):
if request.method == "POST":
form = forms.ActivityForm(request.POST)
if form.is_valid():
activity = form.save(commit=False)
activity = form.save(commit=False)
activity.content_object = lead
activity.created_by = request.user
activity.save()
@ -3005,8 +3005,8 @@ class OpportunityCreateView(CreateView, LoginRequiredMixin):
def get_initial(self):
initial = super().get_initial()
if self.kwargs.get('pk',None):
lead = models.Lead.objects.get(pk=self.kwargs.get('pk'))
lead = models.Lead.objects.get(pk=self.kwargs.get('pk'))
initial['customer'] = lead.customer
return initial
@ -3037,11 +3037,11 @@ class OpportunityDetailView(DetailView):
context = super().get_context_data(**kwargs)
form = forms.OpportunityStatusForm()
url = reverse("opportunity_update_status", args=[self.object.pk])
form.fields["status"].widget.attrs["hx-get"] = url
form.fields["status"].widget.attrs["hx-get"] = url
form.fields["stage"].widget.attrs["hx-get"] = url
form.fields["status"].initial = self.object.status
form.fields["status"].initial = self.object.status
form.fields["stage"].initial = self.object.stage
context["status_form"] = form
context["status_form"] = form
context["notes"] = models.Notes.objects.filter(content_type__model="opportunity", object_id=self.object.id)
context["activities"] = models.Activity.objects.filter(content_type__model="opportunity", object_id=self.object.id)
email_qs = models.Email.objects.filter(content_type__model="opportunity", object_id=self.object.id)
@ -3061,7 +3061,7 @@ class OpportunityListView(ListView):
def get_queryset(self):
dealer = get_user_type(self.request)
return models.Opportunity.objects.filter(dealer=dealer).all()
@login_required
def delete_opportunity(request, pk):
opportunity = get_object_or_404(models.Opportunity, pk=pk)
@ -3227,7 +3227,7 @@ class BillDetailView(LoginRequiredMixin, DetailView):
bill = kwargs.get("object")
if bill.get_itemtxs_data():
txs = bill.get_itemtxs_data()[0]
transactions = [
{
"item": x,
@ -3242,7 +3242,7 @@ class BillDetailView(LoginRequiredMixin, DetailView):
kwargs["transactions"] = transactions
kwargs["grand_total"] = grand_total
return super().get_context_data(**kwargs)
@ -3323,7 +3323,7 @@ def bill_mark_as_paid(request, pk):
bill.mark_as_paid(user_model=dealer.entity.admin)
bill.save()
bill.ledger.lock_journal_entries()
bill.ledger.post_journal_entries()
bill.ledger.post_journal_entries()
bill.ledger.post()
bill.ledger.save()
messages.success(request, _("Bill marked as paid successfully."))
@ -3461,7 +3461,7 @@ class OrderListView(ListView):
def get_queryset(self):
dealer = get_user_type(self.request)
qs = super().get_queryset()
qs = super().get_queryset()
return qs.filter(estimate__entity=dealer.entity)
# email
@ -3861,7 +3861,7 @@ def DealerSettingsView(request,pk):
dealer = get_user_type(request)
if request.method == 'POST':
form = forms.DealerSettingsForm(request.POST, instance=dealer_setting)
if form.is_valid():
if form.is_valid():
instance = form.save(commit=False)
instance.dealer = dealer
instance.save()
@ -3873,7 +3873,7 @@ def DealerSettingsView(request,pk):
form.fields['invoice_cash_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH)
form.fields['invoice_prepaid_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES)
form.fields['invoice_unearned_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_DEFERRED_REVENUE)
form.fields['bill_cash_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH)
form.fields['bill_prepaid_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID)
form.fields['bill_unearned_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE)

View File

@ -26,7 +26,7 @@
<table class="table fs-9 mb-0 border-top border-translucent">
<thead>
<tr>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 20%;">{{ _("Lead Name")|capfirst }}</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 20%;">{{ _("Lead Name")|capfirst }}</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 15%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><i class="text-success-dark fas fa-car"></i></div>
@ -109,7 +109,7 @@
</div>
</div>
</div>
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="name align-middle white-space-nowrap ps-0">
<div class="d-flex align-items-center">
<div><a class="fs-8 fw-bold" href="{% url 'lead_detail' lead.pk %}">{{lead.full_name}}</a>
@ -132,12 +132,12 @@
</div>
</div>
</td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.id_car_make.get_local_name }} - {{ lead.id_car_model.get_local_name }} {{ lead.year }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.email }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="tel:{{ lead.phone_number }}">{{ lead.phone_number }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold">
<div class="accordion" id="accordionExample">
<td class="align-middle white-space-nowrap fw-semibold">
<div class="accordion" id="accordionExample">
<div class="accordion-item">
<h2 class="accordion-header" id="headingTwo">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{lead.pk}}" aria-expanded="false" aria-controls="collapseTwo">
@ -148,7 +148,7 @@
<div class="accordion-body pt-0">
<div class="d-flex flex-column gap-2">
<table><tbody>
{% for schedule in lead.get_latest_schedules %}
{% for schedule in lead.get_latest_schedules %}
<tr class="schedule-{{ schedule.pk }}">
<td class="align-middle white-space-nowrap">
{% if schedule.scheduled_type == "Call" %}
@ -163,11 +163,11 @@
<a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span>
{{ schedule.scheduled_at }}</span></a>
{% endif %}
{% endif %}
</td>
<td>
<a style="cursor: pointer;" hx-delete="{% url 'schedule_cancel' schedule.pk %}" hx-target=".schedule-{{ schedule.pk }}" hx-confirm="Are you sure you want to cancel this schedule?"><i class="fa-solid fa-ban text-danger"></i></a>
</td>
</td>
{% endfor %}
</tr>
<tr><td><small><a href="{% url 'appointment:get_user_appointments' %}">View All ...</a></small></td></tr>
@ -176,11 +176,11 @@
</div>
</div>
</div>
</div>
</td>
</div>
</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td>
<td class="align-middle white-space-nowrap fw-semibold text-body-highlight">{{ lead.source|upper }}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.channel|upper }}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.channel|upper }}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
{% if lead.opportunity.stage == "prospect" %}
<span class="badge text-bg-primary">{{ lead.opportunity.stage|upper }}</span>
@ -192,7 +192,7 @@
<span class="badge text-bg-success">{{ lead.opportunity.stage|upper }}</span>
{% elif lead.opportunity.stage == "closed_lost" %}
<span class="badge text-bg-danger">{{ lead.opportunity.stage|upper }}</span>
{% endif %}
{% endif %}
</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
{% if lead.opportunity %}
@ -203,7 +203,7 @@
<span class="badge badge-phoenix badge-phoenix-danger">{{ _("No") }}</span>
{% endif %}
</td>
<td class="align-middle white-space-nowrap text-end">
<td class="align-middle white-space-nowrap text-end">
{% if user == lead.staff.user or request.is_dealer %}
<div class="btn-reveal-trigger position-static">
<button

View File

@ -5,10 +5,10 @@
<div class="row my-4">
<h2>{{ organization.get_local_name }}</h2>
<ul class="list-group mb-4">
<li class="list-group-item"><strong>{% trans "CRN" %}:</strong> {{ organization.additional_info.organization_info.crn }}</li>
<li class="list-group-item"><strong>{% trans "VRN" %}:</strong> {{ organization.additional_info.organization_info.vrn }}</li>
<li class="list-group-item"><strong>{% trans "Phone" %}:</strong> {{ organization.additional_info.organization_info.phone_number }}</li>
<li class="list-group-item"><strong>{% trans "Address" %}:</strong> {{ organization.additional_info.organization_info.address }}</li>
<li class="list-group-item"><strong>{% trans "CRN" %}:</strong> {{ organization.additional_info.customer_info.crn }}</li>
<li class="list-group-item"><strong>{% trans "VRN" %}:</strong> {{ organization.additional_info.customer_info.vrn }}</li>
<li class="list-group-item"><strong>{% trans "Phone" %}:</strong> {{ organization.additional_info.customer_info.phone_number }}</li>
<li class="list-group-item"><strong>{% trans "Address" %}:</strong> {{ organization.additional_info.customer_info.address }}</li>
</ul>
<div class="d-flex">
<a href="{% url 'organization_update' organization.pk %}" class="btn btn-sm btn-warning me-2">{% trans "Edit" %}</a>

View File

@ -107,8 +107,8 @@
</div>
</div>
</td>
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.crn }}</td>
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.vrn }}</td>
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.customer_info.crn }}</td>
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.customer_info.vrn }}</td>
<td class="phone align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">
<a class="text-body-highlight" href="tel:{{ org.phone }}">{{ org.phone }}</a>
</td>