Merge pull request 'Message in the header' (#194) from frontend into main

Reviewed-on: #194
This commit is contained in:
ismail 2025-08-25 11:51:43 +03:00
commit 2c6249d74c
18 changed files with 126 additions and 59 deletions

View File

@ -177,7 +177,7 @@ class DealerForm(forms.ModelForm):
"""
phone_number = SaudiPhoneNumberField(label=_("Phone Number"))
# phone_number = SaudiPhoneNumberField(label=_("Phone Number"))
class Meta:
model = Dealer
@ -193,7 +193,7 @@ class DealerForm(forms.ModelForm):
class CustomerForm(forms.ModelForm):
phone_number = SaudiPhoneNumberField(label=_("Phone Number"))
# phone_number = SaudiPhoneNumberField(label=_("Phone Number"))
class Meta:
model = Customer
@ -563,7 +563,7 @@ class VendorForm(forms.ModelForm):
:type Meta: Type[VendorForm.Meta]
"""
phone_number = SaudiPhoneNumberField(label=_("Phone Number"))
# phone_number = SaudiPhoneNumberField(label=_("Phone Number"))
contact_person = forms.CharField(label=_("Contact Person"))
class Meta:
@ -652,7 +652,7 @@ class RepresentativeForm(forms.ModelForm):
:type Meta.fields: list of str
"""
phone_number = SaudiPhoneNumberField(label=_("Phone Number"))
# phone_number = SaudiPhoneNumberField(label=_("Phone Number"))
class Meta:
model = Representative

View File

@ -443,7 +443,7 @@ urlpatterns = [
path(
"<slug:dealer_slug>/inventory/<slug:entity_slug>/list/",
views.InventoryListView.as_view(),
name="inventort_list",
name="inventory_list",
),
# Sales URLs quotation_create
# path(

View File

@ -1588,7 +1588,7 @@ def _post_sale_and_cogs(invoice, dealer):
net_car_price = Decimal(data['discounted_price'])
net_additionals_price = Decimal(data['additional_services']['total'])
vat_amount = Decimal(data['vat_amount'])
grand_total = net_car_price + net_additionals_price + vat_amount
grand_total = net_car_price + car.get_additional_services_amount_ + vat_amount
cost_total = Decimal(car.cost_price)
discount_amount =Decimal(data['discount_amount'])
@ -1608,7 +1608,8 @@ def _post_sale_and_cogs(invoice, dealer):
journal_entry=je_sale,
account=cash_acc,
amount=grand_total,
tx_type='debit'
tx_type='debit',
description='Debit to Cash on Hand'
)
# # Cr A/R (clear the receivable)
@ -1624,7 +1625,8 @@ def _post_sale_and_cogs(invoice, dealer):
journal_entry=je_sale,
account=vat_acc,
amount=vat_amount,
tx_type='credit'
tx_type='credit',
description="Credit to Tax Payable"
)
# Cr Sales Car
@ -1633,7 +1635,7 @@ def _post_sale_and_cogs(invoice, dealer):
account=car_rev,
amount=net_car_price,
tx_type='credit',
description="Car Sale"
description=" Credit to Car Sales"
)
if car.get_additional_services_amount > 0:
@ -1642,14 +1644,16 @@ def _post_sale_and_cogs(invoice, dealer):
journal_entry=je_sale,
account=add_rev,
amount=car.get_additional_services_amount,
tx_type='credit'
tx_type='credit',
description="Credit to After-Sales Services"
)
TransactionModel.objects.create(
journal_entry=je_sale,
account=vat_acc,
amount=car.get_additional_services_vat,
tx_type='credit',
description="Additional Services VAT"
description="Credit to Tax Payable (Additional Services)"
)
# ------------------------------------------------------------------
@ -1668,7 +1672,7 @@ def _post_sale_and_cogs(invoice, dealer):
journal_entry=je_cogs,
account=cogs_acc,
amount=cost_total,
tx_type='debit'
tx_type='debit',
)
# Cr Inventory

View File

@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _
import re
class SaudiPhoneNumberValidator(RegexValidator):
def __init__(self):
def __init__(self, *args, **kwargs):
super().__init__(
regex=r"^(\+9665|05)[0-9]{8}$",
message=_("Enter a valid Saudi phone number (05XXXXXXXX or +9665XXXXXXXX)"),

View File

@ -10617,10 +10617,12 @@ class PurchaseOrderListView(LoginRequiredMixin, PermissionRequiredMixin, ListVie
query = self.request.GET.get("q")
qs = self.model.objects.filter(entity=dealer.entity)
if query:
qs = apply_search_filters(qs, query)
qs=qs.filter(Q(po_number__icontains=query)|Q(po_status__icontains=query)|Q(po_title__icontains=query))
return qs
return qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
dealer = get_user_type(self.request)
vendors=models.Vendor.objects.filter(dealer=dealer)
context = super().get_context_data(**kwargs)

View File

@ -4,6 +4,13 @@ from decimal import Decimal
def run():
# Create quotas first
free_quota = Quota.objects.create(
codename="free_quota",
name="Free Features",
description="Free plan features",
is_boolean=True,
url="pricing",
)
basic_quota = Quota.objects.create(
codename="basic_quota",
name="Basic Features",
@ -27,7 +34,19 @@ def run():
is_boolean=True,
url="pricing",
)
# Create the plans
free_plan = Plan.objects.create(
name="Free",
description="Free plan with limited features",
price=Decimal("0.00"), # 0
period=7, # 1 week
default=True,
available=True,
visible=True,
order=1,
)
free_plan.quotas.add(free_quota)
# Create the plans
basic_plan = Plan.objects.create(
name="Basic",
@ -39,7 +58,7 @@ def run():
visible=True,
order=1,
)
basic_plan.quotas.add(basic_quota)
basic_plan.quotas.add(basic_quota,free_quota)
pro_plan = Plan.objects.create(
name="Professional",
@ -50,7 +69,7 @@ def run():
visible=True,
# order=2
)
pro_plan.quotas.add(basic_quota, pro_quota)
pro_plan.quotas.add(free_quota,basic_quota, pro_quota)
premium_plan = Plan.objects.create(
name="Premium",
@ -61,4 +80,4 @@ def run():
visible=True,
order=3,
)
premium_plan.quotas.add(basic_quota, pro_quota, premium_quota)
premium_plan.quotas.add(free_quota,basic_quota, pro_quota, premium_quota)

View File

@ -138,7 +138,8 @@ html[dir="rtl"] .form-icon-container .form-control {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
z-index: 9999;
pointer-events: none;
}
#spinner-bg {
@ -150,11 +151,14 @@ html[dir="rtl"] .form-icon-container .form-control {
background-color: rgba(255, 255, 255, 0.7);
opacity: 0;
transition: opacity 500ms ease-in;
z-index: 5;
visibility: hidden;
z-index: 10000;
pointer-events: none;
}
#spinner-bg.htmx-request {
opacity: .8;
visibility: visible;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

View File

@ -8,7 +8,7 @@
{% trans "Aging Inventory" %}
<i class="fas fa-box-open text-danger ms-2"></i>
</h2>
<h4 class="text-muted mb-3 ">{% trans "Aging Inventory Total" %} :: <span class=" text-danger">{{total_aging_inventory_value}}<span class="icon-saudi_riyal"></span></span></h4>
<h4 class="text-muted mb-3 ">{% trans "Aging Inventory Total" %} :: <span class=" text-danger">{{total_aging_inventory_value|default:0.00}}<span class="icon-saudi_riyal"></span></span></h4>
<p class="text-muted mb-0">{% trans "Cars in inventory for more than 60 days." %}</p>
</div>

View File

@ -138,11 +138,11 @@
</div> {% endcomment %}
<div class="d-flex justify-content-end gap-2">
{% if not dealer.user.userplan %}
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-success"><span class="fas fa-cart-plus me-2"></span>{{ _("Subscribe Now") }}</a>
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-outline-primary"><span class="fas fa-cart-plus me-2"></span>{{ _("Subscribe Now") }}</a>
{% elif dealer.user.userplan.is_expired %}
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-warning"><span class="fas fa-redo-alt me-2"></span>{{ _("Renew") }}</a>
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-outline-warning"><span class="fas fa-redo-alt me-2"></span>{{ _("Renew") }}</a>
{% elif dealer.user.userplan.plan.name != "Enterprise" %}
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-primary"><span class="fas fa-rocket me-2"></span>{{ _("Upgrade Plan") }}</a>
<a href="{% url 'pricing_page' request.dealer.slug %}" class="btn btn-outline-primary"><span class="fas fa-rocket me-2"></span>{{ _("Upgrade Plan") }}</a>
{% endif %}
</div>
</div>

View File

@ -6,7 +6,7 @@
<ul class="navbar-nav flex-column" id="navbarVerticalNav" hx-boost="true" hx-target="#main_content" hx-select="#main_content" hx-swap="outerHTML" hx-select-oob="#toast-container" hx-indicator="#spinner">
<li class="nav-item">
<p class="navbar-vertical-label text-primary fs-8 text-truncate">{{request.dealer|default:"Apps"}}</p>
<hr class="navbar-vertical-line" />
<hr class="navbar-vertical-line">
{% if perms.inventory.can_view_inventory %}
<div class="nav-item-wrapper">
<a id="inventory-nav" class="nav-link dropdown-indicator label-1 inventory-nav" href="#nv-inventory" role="button" data-bs-toggle="collapse" aria-expanded="false" aria-controls="nv-inventory">
@ -20,13 +20,13 @@
<li class="collapsed-nav-item-title d-none">{% trans "Inventory"|capfirst %}</li>
{% if perms.inventory.add_car %}
<li class="nav-item">
<a hx-boost="false" id="btn-add-car" class="nav-link btn-add-car" href="{% url 'car_add' request.dealer.slug %}">
<div class="d-flex align-items-center">
<a hx-boost="false" id="btn-add-car" class="nav-link btn-add-car" href="{% url 'car_add' request.dealer.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-plus-circle"></span></span><span class="nav-link-text">{% trans "add car"|capfirst %}</span>
</div>
</a>
</li>
</a>
</li>
{% endif %}
{% if perms.inventory.view_car%}
@ -64,7 +64,7 @@
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'inventort_list' request.dealer.slug request.dealer.entity.slug %}">
<a class="nav-link" href="{% url 'inventory_list' request.dealer.slug request.dealer.entity.slug %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-boxes"></span></span><span class="nav-link-text">{% trans "Inventory List"|capfirst %}</span>
</div>
@ -129,7 +129,6 @@
<span class="nav-link-icon"><span class="fas fa-city"></span></span><span class="nav-link-text">{% trans "Organizations"|capfirst %}</span>
</div>
</a>
</li>
{% endif %}
{% comment %} <li class="nav-item">
@ -425,7 +424,7 @@
aria-label="Toggle Navigation">
<span class="navbar-toggle-icon"><span class="toggle-line"></span></span>
</button>
<a class="navbar-brand me-1 me-sm-3" href="{% url 'home' %}">
<a class="navbar-brand me-1 me-sm-3" href="{% url 'home'%}">
<div class="d-flex align-items-center">
<img class="logo-img d-dark-none" src="{% static 'images/logos/logo-d.png' %}" alt="haikal" width="27" />
<img class="logo-img d-light-none" src="{% static 'images/logos/logo.png' %}" alt="haikal" width="27" />
@ -434,13 +433,19 @@
</a>
</div>
{% if request.user.is_authenticated%}
<div class="d-flex mx-4 px-4">
<div class="navbar-logo">
<div class="d-flex align-items-center">
<h5 class="text-warning ms-2 d-none d-sm-block">{% trans 'Hello, ' %}{{ request.user.first_name|default:request.dealer.name }} {{ request.user.last_name }}</h5>
<div class="navbar-logo">
<div class="d-flex align-items-center">
{% with name_to_display=request.user.first_name|default:request.dealer.name %}
<h6 class="text-info ms-2 d-none d-sm-block fs-7"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
title="{% trans 'Logged in as ' %}{{request.user.username }}">
{% trans 'Hello, ' %}{{ name_to_display }}
</h6>
{% endwith %}
</div>
</div>
</a>
</div>
{% endif %}
<ul class="navbar-nav navbar-nav-icons flex-row gap-2" hx-boost="false">

View File

@ -15,7 +15,7 @@
}
.moving-car {
.moving-tenhal {
position: absolute;
font-size: 3rem;
font-weight: bold;
@ -39,14 +39,10 @@
{% if inventory.total_cars > 0 %}
<div class="row justify-content-between">
<div class="col-sm-12 ">
<div class="card border h-100 w-100 p-lg-10">
{% comment %} <div class="road-container">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSY0ESBb8625a12EguCyY8j4eL93sY3ibEAuQ&s" alt="Car" id="car" class="img-fluid" style="height:30px; width:30px;">
</div> {% endcomment %}
<div class="card border h-100 w-100 p-lg-10" style="">
<div class="road">
<p class="moving-car ">Powered By Tenhal&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p class="moving-tenhal ">&nbsp;&nbsp;&nbsp;&nbsp;{% trans "Powered By Tenhal" %}&nbsp;&nbsp;&nbsp;&nbsp;</p>
</div>
<div class="bg-holder bg-card"

View File

@ -35,9 +35,27 @@
<td class="align-middle product white-space-nowrap">{{ expense.uom }}</td>
<td class="align-middle product white-space-nowrap">
{% if perms.django_ledger.change_itemmodel %}
<a href="{% url 'item_expense_update' request.dealer.slug expense.pk %}"
class="btn btn-sm btn-phoenix-primary"><li class="fa fa-edit me-1"></li>{% trans "Update" %}</a>
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item" href="{% url 'item_expense_update' request.dealer.slug expense.pk %}" >
<i class="fa fa-edit me-2"></i>{% trans "Update" %}
</a>
<a class="text-danger dropdown-item" href="#" >
<i class="fa fa-trash me-2"></i>{% trans "Delete" %}
</a>
</div>
</div>
{% endif %}
</td>

View File

@ -38,8 +38,28 @@
<td class="align-middle product white-space-nowrap">{{ service.item.co }}</td>
<td class="align-middle white-space-nowrap text-start">
{% if perms.inventory.add_additionalservices %}
<a href="{% url 'item_service_update' request.dealer.slug service.pk %}"
class="btn btn-sm btn-phoenix-primary"><li class="fa fa-edit me-1"></li>{% trans "Update" %}</a>
<div class="btn-reveal-trigger position-static">
<button class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item" href="{% url 'item_service_update' request.dealer.slug service.pk %}" >
<i class="fa fa-edit me-2"></i>{% trans "Update" %}
</a>
<a class="text-danger dropdown-item" href="#" >
<i class="fa fa-trash me-2"></i>{% trans "Delete" %}
</a>
</div>
</div>
{% endif %}
</td>
</tr>

View File

@ -10,7 +10,7 @@
{% endblock %}
{% block content %}
<main class="d-flex align-items-center justify-content-center min-vh-100 py-5">
<main class="d-flex align-items-center justify-content-center min-vh-50 py-5">
<div class="col-12 col-lg-8 col-xl-7">
<div class="card shadow-lg border-0 rounded-4 overflow-hidden animate__animated animate__fadeInUp">
<div class="card-header bg-gradient py-4 border-0 rounded-top-4">

View File

@ -11,18 +11,17 @@
{% if messages %}
{% for message in messages %}<div class="alert alert-success">{{ message }}</div>{% endfor %}
{% endif %}
<h2 class="">
{{ _("Purchase Orders") |capfirst }} <li class="fas fa-cart-plus text-primary ms-2"></li>
</h2>
<div class="row g-3 justify-content-between mb-4">
<div class="col-auto">
<div class="d-md-flex justify-content-between">
{% if perms.django_ledger.add_purchaseordermodel %}
<div class="d-flex justify-content-between mb-2">
<h2 class="">
{{ _("Purchase Orders") |capfirst }} <li class="fas fa-cart-plus text-primary ms-2"></li>
</h2>
{% if perms.django_ledger.add_purchaseordermodel %}
<a href="{% url 'purchase_order_create' request.dealer.slug request.dealer.entity.slug %}"
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New PO") }}</a>
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{{ _("Create New Purchase") }}</a>
{% endif %}
</div>
</div>
<div class="col-auto">
<div class="d-flex">