This commit is contained in:
Marwan Alwali 2025-05-05 14:26:06 +03:00
parent e10b5f64ea
commit 2070125e0f
12 changed files with 137 additions and 193 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -1,4 +1,4 @@
# Generated by Django 5.1.5 on 2025-01-30 11:28
# Generated by Django 5.1.7 on 2025-05-04 16:07
from django.db import migrations, models

View File

@ -31,71 +31,7 @@ def run():
"LGJE1EE0XSM333551",
"LGJE1EE02SM333561",
"LGJE1EE0XSM333565",
"LGJE1EE01SM333549",
"LGJE1EE06SM333563",
"LGJE1EE04SM333562",
"LGJE1EE08SM333564",
"LFB1E6078P1Y01338",
"LGJE5EE02PM046815",
"LFB1E6074P1Y01742",
"LGJE5EE07PM132850",
"LGJE1EE08SM311094",
"LFPH4ACP4P2A00123",
"LFB1E6075R1Y00117",
"ZAMPP56F0J1282425",
"LGJE1EE06RM292314",
"LGJE1EE00NM013594",
"LFB1E6075M1Y00272",
"LFB1E6670P1Y00224",
"LFB1E6079N1Y00275",
"LGJE3FE00MM804819",
"LGJE3FE0XMM804844",
"LGJE1EE01RM200767",
"LGJE1EE08RM200703",
"ZAMXS57F7L1341373",
"LGJE5EE06SM330781",
"LFB1E6077P1Y02643",
"LFB1E6074M1Y00151",
"LGJE1EE07RM292323",
"LGJE1EE01RM200171",
"LGJE1EE04SM311545",
"LGJE1EE04RM292859",
"LGJE1EE02RM292861",
"LFB1E607XP1Y01454",
"LFB1E6073P1Y00081",
"LGJE1EE03PM129391",
"LGJE1EE03RM200639",
"LGJE1EE02PM128393",
"LGJE1EE03NM964436",
"LGJE1EE06RM211599",
"LGJE1EE06NM014104",
"LGJE1EE05NM014272",
"LGJE5EE06SM331641",
"LGJE1EE09NM013528",
"LGJE5EE0XPM048196",
"LGJE1EE01RM212935",
"LGJE1EE05RM200433",
"LGJE1EE05SM311909",
"LGJE5EE02SM346914",
"LGJE1EE08SM306753",
"LGJE1EE02SM312001",
"LFPH4ACP6R2A02586",
"LGJE1EE00PM048445",
"LGJE1EE02SM311902",
"LGJE1EE03SM312573",
"LGJE1EE00SM306813",
"LFB1E6674N1Y00577",
"LGJE1EE00SM306875",
"LGJE1EE04SM306863",
"LFB1E6079P1Y00389",
"LGJE1EE04SM311562",
"LGJE1EE01SM312006",
"LGJE1EE08SM312486",
"LFB1E6676P1Y00941",
"LFPH4ACP1M1B00116",
"LGJE1EE02SM312564",
"LFPH4BCPXS2L00051",
"LGJE1EE06SM306864",
]
for vin in vin_list:
try:

View File

@ -1,6 +1,5 @@
# Generated by Django 5.1.7 on 2025-04-28 12:45
# Generated by Django 5.1.7 on 2025-05-04 16:07
import django.db.models.deletion
from django.db import migrations, models
@ -9,7 +8,6 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('inventory', '0006_alter_email_object_id_alter_notes_object_id'),
]
operations = [
@ -20,7 +18,6 @@ class Migration(migrations.Migration):
('user_message', models.TextField()),
('chatbot_response', models.TextField()),
('timestamp', models.DateTimeField(auto_now_add=True)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer')),
],
),
]

View File

@ -0,0 +1,22 @@
# Generated by Django 5.1.7 on 2025-05-04 16:07
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('haikalbot', '0001_initial'),
('inventory', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='chatlog',
name='dealer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer'),
),
]

View File

@ -1,4 +1,4 @@
# Generated by Django 5.1.7 on 2025-05-04 10:42
# Generated by Django 5.1.7 on 2025-05-04 16:07
import datetime
import django.core.validators
@ -17,11 +17,17 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('appointment', '0001_initial'),
('appointment', '0002_alter_workinghours_options'),
('auth', '0012_alter_user_first_name_max_length'),
('contenttypes', '0002_remove_content_type_name'),
('django_ledger', '0021_alter_bankaccountmodel_account_model_and_more'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_ACCOUNT_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_ENTITY_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_ESTIMATE_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_INVOICE_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_ITEM_MODEL),
migrations.swappable_dependency(settings.DJANGO_LEDGER_VENDOR_MODEL),
]
operations = [
@ -114,7 +120,7 @@ class Migration(migrations.Migration):
('price', models.DecimalField(decimal_places=2, max_digits=14, verbose_name='Price')),
('taxable', models.BooleanField(default=False, verbose_name='taxable')),
('uom', models.CharField(choices=[('EA', 'Each'), ('PR', 'Pair'), ('SET', 'Set'), ('GAL', 'Gallon'), ('L', 'Liter'), ('M', 'Meter'), ('KG', 'Kilogram'), ('HR', 'Hour'), ('BX', 'Box'), ('RL', 'Roll'), ('PKG', 'Package'), ('DZ', 'Dozen'), ('SQ_M', 'Square Meter'), ('PC', 'Piece'), ('BDL', 'Bundle')], max_length=10, verbose_name='Unit of Measurement')),
('item', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='django_ledger.itemmodel', verbose_name='Item')),
('item', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.DJANGO_LEDGER_ITEM_MODEL, verbose_name='Item')),
],
options={
'verbose_name': 'Additional Services',
@ -134,7 +140,7 @@ class Migration(migrations.Migration):
('mileage', models.IntegerField(blank=True, null=True, verbose_name='Mileage')),
('receiving_date', models.DateTimeField(verbose_name='Receiving Date')),
('hash', models.CharField(blank=True, max_length=64, null=True, verbose_name='Hash')),
('vendor', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to='django_ledger.vendormodel', verbose_name='Vendor')),
('vendor', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='cars', to=settings.DJANGO_LEDGER_VENDOR_MODEL, verbose_name='Vendor')),
('id_car_make', models.ForeignKey(blank=True, db_column='id_car_make', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make')),
],
options={
@ -316,7 +322,7 @@ class Migration(migrations.Migration):
('logo', models.ImageField(blank=True, null=True, upload_to='logos/users', verbose_name='Logo')),
('joined_at', models.DateTimeField(auto_now_add=True, verbose_name='Joined At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated At')),
('entity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='django_ledger.entitymodel')),
('entity', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.DJANGO_LEDGER_ENTITY_MODEL)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dealer', to=settings.AUTH_USER_MODEL)),
],
options={
@ -431,13 +437,13 @@ class Migration(migrations.Migration):
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('additional_info', models.JSONField(blank=True, default=dict, null=True)),
('bill_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_cash', to='django_ledger.accountmodel')),
('bill_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_prepaid', to='django_ledger.accountmodel')),
('bill_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_unearned', to='django_ledger.accountmodel')),
('bill_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_cash', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('bill_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('bill_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bill_unearned', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('dealer', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='settings', to='inventory.dealer')),
('invoice_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_cash', to='django_ledger.accountmodel')),
('invoice_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid', to='django_ledger.accountmodel')),
('invoice_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_unearned', to='django_ledger.accountmodel')),
('invoice_cash_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_cash', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_prepaid_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_prepaid', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
('invoice_unearned_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoice_unearned', to=settings.DJANGO_LEDGER_ACCOUNT_MODEL)),
],
),
migrations.CreateModel(
@ -479,7 +485,7 @@ class Migration(migrations.Migration):
('status', models.CharField(choices=[('new', 'New'), ('pending', 'Pending'), ('in_progress', 'In Progress'), ('qualified', 'Qualified'), ('contacted', 'Contacted'), ('converted', 'Converted'), ('canceled', 'Canceled')], db_index=True, default='new', max_length=50, verbose_name='Status')),
('created', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Created')),
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='django_ledger.customermodel')),
('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='leads', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to='inventory.dealer')),
('id_car_make', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make')),
('id_car_model', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model')),
@ -582,8 +588,8 @@ class Migration(migrations.Migration):
('comments', models.TextField(blank=True, null=True)),
('formatted_order_id', models.CharField(editable=False, max_length=10, unique=True)),
('created', models.DateTimeField(auto_now_add=True)),
('estimate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to='django_ledger.estimatemodel', verbose_name='Estimate')),
('invoice', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to='django_ledger.invoicemodel', verbose_name='Invoice')),
('estimate', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to=settings.DJANGO_LEDGER_ESTIMATE_MODEL, verbose_name='Estimate')),
('invoice', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to=settings.DJANGO_LEDGER_INVOICE_MODEL, verbose_name='Invoice')),
],
options={
'ordering': ['-created'],
@ -601,7 +607,7 @@ class Migration(migrations.Migration):
('status', models.CharField(choices=[('Scheduled', 'Scheduled'), ('Completed', 'Completed'), ('Canceled', 'Canceled')], default='Scheduled', max_length=200)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='django_ledger.customermodel')),
('customer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)),
('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='inventory.lead')),
('scheduled_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
@ -644,9 +650,9 @@ class Migration(migrations.Migration):
('updated', models.DateTimeField(auto_now=True, verbose_name='Updated')),
('closed', models.BooleanField(default=False, verbose_name='Closed')),
('car', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='inventory.car', verbose_name='Car')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='django_ledger.customermodel')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)),
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='opportunities', to='inventory.dealer')),
('estimate', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='opportunity', to='django_ledger.estimatemodel')),
('estimate', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='opportunity', to=settings.DJANGO_LEDGER_ESTIMATE_MODEL)),
('lead', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='opportunity', to='inventory.lead')),
('staff', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='owner', to='inventory.staff', verbose_name='Owner')),
],

View File

@ -935,17 +935,6 @@ class Dealer(models.Model, LocalizedNameMixin):
if staff_count >= quota:
return True
return False
#
# @property
# def get_plan(self):
# active_plan = self.get_active_plan
# if active_plan:
# subscription_plan = SubscriptionPlan.objects.filter(
# pk=active_plan.pk
# ).first()
# if subscription_plan:
# return subscription_plan
# return None
class Meta:
verbose_name = _("Dealer")
@ -971,17 +960,6 @@ class Dealer(models.Model, LocalizedNameMixin):
# return self.parent_dealer if self.parent_dealer else self
class DealersMake(models.Model):
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="dealer_makes")
car_make = models.ForeignKey(CarMake, on_delete=models.CASCADE, related_name="car_dealers")
added_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ("dealer", "car_make") # Prevents duplicate entries
def __str__(self):
return f"{self.dealer.name} - {self.car_make.name}"
##############################
# Additional staff types for later

View File

@ -7649,7 +7649,7 @@ def ledger_unpost_all_journals(request, entity_slug, pk):
def pricing_page(request):
plan_list = PlanPricing.objects.all()
form = forms.PaymentPlanForm()
return render(request, "pricing_page.html", {"plan_list": plan_list, "CURRENCY": "$","form":form})
return render(request, "pricing_page.html", {"plan_list": plan_list, "form":form})
# @require_POST
def submit_plan(request):
@ -7661,7 +7661,7 @@ def submit_plan(request):
plan=pp.plan,
pricing=pp.pricing,
amount=pp.price,
currency="SAR",
currency=settings.DEFAULT_CURRENCY,
tax=15,
status=AbstractOrder.STATUS.NEW
)
@ -7669,20 +7669,21 @@ def submit_plan(request):
return redirect(transaction_url)
def payment_callback(request):
dealer = get_user_type(request)
payment_id = request.GET.get("id")
history = models.PaymentHistory.objects.filter(transaction_id=payment_id).first()
payment_status = request.GET.get("status")
order = Order.objects.filter(user=request.user,status=AbstractOrder.STATUS.NEW).first()
order = Order.objects.filter(user=dealer,status=AbstractOrder.STATUS.NEW).first()
if payment_status == "paid":
billing_info,created = BillingInfo.objects.get_or_create(
user=request.user,
tax_number='123456789',
name='',
street='',
zipcode='12345',
city='Riyadh',
country='KSA',
user=dealer.user,
tax_number=dealer.vrn,
name=dealer.arabic_name,
street=dealer.entity.address,
zipcode=dealer.entity.zip_code,
city=dealer.entity.city,
country=dealer.entity.country,
)
if created:
userplan =UserPlan.objects.create(

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -5,22 +5,26 @@
<img src="{{ logo_url }}" alt="Company Logo" class="img-fluid" style="max-height: 80px; max-width: 200px;">
{% endif %}
<div class="text-end">
<div class="d-inline-block p-3 bg-light rounded-3">
<div class="d-inline-block p-3 rounded-3">
<h1 class="h4 mb-1">
<span class="text-muted small">
{% if invoice.type == invoice.INVOICE_TYPES.INVOICE %}Invoice{% endif %}
{% if invoice.type == invoice.INVOICE_TYPES.PROFORMA %}Order Confirmation{% endif %}
{% if invoice.type == invoice.INVOICE_TYPES.DUPLICATE %}Invoice (Duplicate){% endif %}
{% if invoice.type == invoice.INVOICE_TYPES.INVOICE %}{{ _("Invoice") }}{% endif %}
{% if invoice.type == invoice.INVOICE_TYPES.PROFORMA %}{{ _("Order Confirmation")}}{% endif %}
{% if invoice.type == invoice.INVOICE_TYPES.DUPLICATE %}{{ _("Invoice (Duplicate)")}}{% endif %}
</span>
<div id="full_number" class="fw-bold fs-3">{{ invoice.full_number }}</div>
</h1>
<div class="badge bg-{% if copy %}warning{% else %}primary{% endif %} bg-opacity-10 text-{% if copy %}warning{% else %}primary{% endif %} mb-2">
{{ copy|yesno:"COPY,ORIGINAL" }}
{% if copy %}
{{ _("COPY") }}
{% else %}
{{ _("ORIGINAL") }}
{% endif %}
</div>
<div class="d-flex flex-column text-start">
<div class="mb-1"><span class="text-muted">Issued:</span> <strong>{{ invoice.issued|date:"F j, Y" }}</strong></div>
<div class="mb-1"><span class="text-muted">{{ _("Issued") }}:</span> <strong>{{ invoice.issued|date:"F j, Y" }}</strong></div>
{% if invoice.type != invoice.INVOICE_TYPES.PROFORMA %}
<div><span class="text-muted">Order Date:</span> <strong>{{ invoice.selling_date|date:"F j, Y" }}</strong></div>
<div><span class="text-muted">{{ _("Order Date")}}:</span> <strong>{{ invoice.selling_date|date:"F j, Y" }}</strong></div>
{% endif %}
</div>
</div>
@ -31,8 +35,8 @@
<div class="row mb-5 g-4">
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-light">
<h5 class="mb-0 fw-semibold">Seller</h5>
<div class="card-header">
<h5 class="mb-0 fw-semibold">{{ _("Seller") }}</h5>
</div>
<div class="card-body">
<address class="mb-0">
@ -40,7 +44,7 @@
{{ invoice.issuer_street }}<br>
{{ invoice.issuer_zipcode }} {{ invoice.issuer_city }}<br>
{{ invoice.issuer_country.name }}<br>
<span class="text-muted">VAT ID:</span> {{ invoice.issuer_tax_number }}
<span class="text-muted">{{ _("VAT ID")}}:</span> {{ invoice.issuer_tax_number }}
</address>
</div>
</div>
@ -48,8 +52,8 @@
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-light">
<h5 class="mb-0 fw-semibold">Buyer</h5>
<div class="card-header">
<h5 class="mb-0 fw-semibold">{{ _("Buyer") }}</h5>
</div>
<div class="card-body">
<address class="mb-0">
@ -58,7 +62,7 @@
{{ invoice.buyer_zipcode }} {{ invoice.buyer_city }}<br>
{{ invoice.buyer_country.name }}<br>
{% if invoice.buyer_tax_number %}
<span class="text-muted">VAT ID:</span> {{ invoice.buyer_tax_number }}
<span class="text-muted">{{ _("VAT ID")}}:</span> {{ invoice.buyer_tax_number }}
{% endif %}
</address>
</div>
@ -69,8 +73,8 @@
<!-- Shipping Address (unchanged) -->
{% if invoice.shipping_name %}
<div class="card border-0 shadow-sm mb-5">
<div class="card-header bg-light">
<h5 class="mb-0 fw-semibold">Shipping Address</h5>
<div class="card-header">
<h5 class="mb-0 fw-semibold">{{ _("Shipping Address")}}</h5>
</div>
<div class="card-body">
<address class="mb-0">
@ -85,52 +89,52 @@
<!-- Items Table - Now with horizontal scrolling -->
<div class="card border-0 shadow-sm mb-5">
<div class="card-header bg-light">
<h5 class="mb-0 fw-semibold">Invoice Items</h5>
<div class="card-header">
<h5 class="mb-0 fw-semibold">{{ _("Invoice Items")}}</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive" style="overflow-x: auto;">
<div style="min-width: 800px;"> <!-- Minimum width to ensure scrolling on smaller screens -->
<table class="table table-hover mb-0">
<thead class="table-light">
<thead class="">
<tr>
<th class="text-center sticky-col" style="width: 5%; left: 0; background-color: #f8f9fa; z-index: 1;">#</th>
<th style="width: 25%; min-width: 200px;">Description</th>
<th class="text-end" style="width: 10%; min-width: 100px;">Unit Price</th>
<th class="text-center" style="width: 8%; min-width: 80px;">Qty.</th>
<th class="text-center" style="width: 8%; min-width: 80px;">Unit</th>
<th class="text-center sticky-col" style="width: 5%; z-index: 1;">#</th>
<th style="width: 25%; min-width: 200px;">{{ _("Description") }}</th>
<th class="text-end" style="width: 10%; min-width: 100px;">{{ _("Unit Price")}}</th>
<th class="text-center" style="width: 8%; min-width: 80px;">{{ _("Quantity") }}</th>
<th class="text-center" style="width: 8%; min-width: 80px;">{{ _("Unit") }}</th>
{% if invoice.rebate %}
<th class="text-center" style="width: 8%; min-width: 80px;">Rebate</th>
<th class="text-center" style="width: 8%; min-width: 80px;">{{ _("Rebate") }}</th>
{% endif %}
<th class="text-end" style="width: 10%; min-width: 100px;">Subtotal</th>
<th class="text-center" style="width: 8%; min-width: 80px;">VAT</th>
<th class="text-end" style="width: 10%; min-width: 100px;">VAT Amount</th>
<th class="text-end" style="width: 10%; min-width: 100px;">Total</th>
<th class="text-end" style="width: 10%; min-width: 100px;">{{ _("Subtotal") }}</th>
<th class="text-center" style="width: 8%; min-width: 80px;">{{ _("VAT") }}</th>
<th class="text-end" style="width: 10%; min-width: 100px;">{{ _("VAT Amount")}}</th>
<th class="text-end" style="width: 10%; min-width: 100px;">{{ _("Total") }}</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-center sticky-col" style="left: 0; background-color: white; z-index: 1;">1</td>
<td class="text-center sticky-col" style=" z-index: 1;">1</td>
<td>{{ invoice.item_description }}</td>
<td class="text-end">{{ invoice.unit_price_net|floatformat:2 }} {{ invoice.currency }}</td>
<td class="text-end">{{ invoice.unit_price_net|floatformat:2 }} <span class="currency">{{ CURRENCY }}</span></td>
<td class="text-center">{{ invoice.quantity }}</td>
<td class="text-center">units</td>
<td class="text-center">{{ _("units") }}</td>
{% if invoice.rebate %}
<td class="text-center">{{ invoice.rebate|floatformat:2 }}%</td>
{% endif %}
<td class="text-end">{{ invoice.total_net|floatformat:2 }} {{ invoice.currency }}</td>
<td class="text-center">{% if invoice.tax != None %}{{ invoice.tax|floatformat:2 }}%{% else %}n/a{% endif %}</td>
<td class="text-end">{% if invoice.tax_total != None %}{{ invoice.tax_total|floatformat:2 }} {{ invoice.currency }}{% else %}n/a{% endif %}</td>
<td class="text-end fw-bold">{{ invoice.total|floatformat:2 }} {{ invoice.currency }}</td>
<td class="text-end">{{ invoice.total_net|floatformat:2 }} <span class="currency">{{ CURRENCY }}</span></td>
<td class="text-center">{% if invoice.tax != None %}{{ invoice.tax|floatformat }}%{% else %}n/a{% endif %}</td>
<td class="text-end">{% if invoice.tax_total != None %}{{ invoice.tax_total|floatformat:2 }} <span class="currency">{{ CURRENCY }}</span>{% else %}{{ _("n/a")}}{% endif %}</td>
<td class="text-end fw-bold">{{ invoice.total|floatformat:2 }} <span class="currency">{{ CURRENCY }}</span></td>
</tr>
</tbody>
<tfoot class="table-light">
<tfoot class="">
<tr>
<td colspan="{% if invoice.rebate %}6{% else %}5{% endif %}" class="text-end fw-bold sticky-col" style="left: 0; background-color: #f8f9fa; z-index: 1;">Total</td>
<td class="text-end fw-bold">{{ invoice.total_net|floatformat:2 }} {{ invoice.currency }}</td>
<td class="text-center fw-bold">{% if invoice.tax != None %}{{ invoice.tax|floatformat:2 }}%{% else %}n/a{% endif %}</td>
<td class="text-end fw-bold">{% if invoice.tax_total != None %}{{ invoice.tax_total|floatformat:2 }} {{ invoice.currency }}{% else %}n/a{% endif %}</td>
<td class="text-end fw-bold text-primary">{{ invoice.total|floatformat:2 }} {{ invoice.currency }}</td>
<td colspan="{% if invoice.rebate %}6{% else %}5{% endif %}" class="text-end fw-bold sticky-col" style="left: 0; z-index: 1;">{{ _("Total") }}</td>
<td class="text-end fw-bold">{{ invoice.total_net|floatformat:2 }} <span class="currency">{{ CURRENCY }}</span></td>
<td class="text-center fw-bold">{% if invoice.tax != None %}{{ invoice.tax|floatformat }}%{% else %}{{ _("n/a")}}{% endif %}</td>
<td class="text-end fw-bold">{% if invoice.tax_total != None %}{{ invoice.tax_total|floatformat:2 }} <span class="currency">{{ CURRENCY }}</span>{% else %}{{ _("n/a")}}{% endif %}</td>
<td class="text-end fw-bold text-primary">{{ invoice.total|floatformat:2 }} <span class="currency">{{ CURRENCY }}</span></td>
</tr>
</tfoot>
</table>
@ -143,23 +147,23 @@
<div class="row">
<div class="col-md-6">
<div class="card border-0 shadow-sm">
<div class="card-header bg-light">
<h5 class="mb-0 fw-semibold">Payment Information</h5>
<div class="card-header">
<h5 class="mb-0 fw-semibold">{{ _("Payment Information")}}</h5>
</div>
<div class="card-body">
{% if invoice.type != invoice.INVOICE_TYPES.PROFORMA %}
<div class="mb-2">
<span class="text-muted">Method:</span>
<strong>Electronic Payment</strong>
<span class="text-muted">{{ _("Method") }}:</span>
<strong>{{ _("Electronic Payment")}}</strong>
</div>
{% endif %}
<div class="mb-2">
<span class="text-muted">Due Date:</span>
<span class="text-muted">{{ _("Due Date")}}:</span>
<strong>{{ invoice.payment_date|date:"F j, Y" }}</strong>
</div>
{% if invoice.type != invoice.INVOICE_TYPES.PROFORMA %}
<div class="alert alert-success p-2 mb-0">
<i class="fas fa-check-circle me-2"></i> Payment Received
<i class="fas fa-check-circle me-2"></i> {{ _("Payment Received")}}
</div>
{% endif %}
</div>
@ -167,18 +171,18 @@
</div>
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-light">
<h5 class="mb-0 fw-semibold">Notes</h5>
<div class="card-header">
<h5 class="mb-0 fw-semibold">{{ _("Notes") }}</h5>
</div>
<div class="card-body">
{% if invoice.type == invoice.INVOICE_TYPES.PROFORMA %}
<div class="alert alert-warning p-2 mb-2">
<i class="fas fa-exclamation-triangle me-2"></i> This document is not an invoice.
<i class="fas fa-exclamation-triangle me-2"></i> {{ _("This document is not an invoice")}}
</div>
{% endif %}
{% if invoice.tax == None and invoice.is_UE_customer %}
<div class="alert alert-info p-2 mb-0">
<i class="fas fa-info-circle me-2"></i> Reverse charge applied.
<i class="fas fa-info-circle me-2"></i> {{ _("Reverse charge applied")}}
</div>
{% endif %}
</div>
@ -188,8 +192,8 @@
<!-- Footer (unchanged) -->
<div class="mt-5 pt-4 border-top text-center text-muted small">
<p class="mb-1">Thank you for your business!</p>
<p class="mb-0">If you have any questions about this invoice, please contact us.</p>
<p class="mb-1">{{ _("Thank you for your business")}}!</p>
<p class="mb-0">{{ _("If you have any questions about this invoice, please contact us")}}.</p>
</div>
</div>

View File

@ -59,7 +59,7 @@
<!-- Step 1: Plan Selection -->
<div class="step" id="step1">
<h4 class="mb-4">1. Select a Plan</h4>
<h4 class="mb-4">1. {{ _("Select a Plan")}}</h4>
<div class="row g-4">
{% for pp in plan_list %}
<div class="col-md-6 col-lg-3">
@ -69,7 +69,7 @@
<div class="card h-100 border border-2 rounded-4">
<div class="card-body p-4">
<h4 class="mb-3">{{ pp.plan.name }}</h4>
<h5 class="mb-4">{{ pp.price }} <span class="currency">{{ CURRENCY }}</span><span class="fs-6 fw-normal">/ {{ _("Per month") }}</span></h5>
<h5 class="mb-4">{{ pp.price }} <span class="currency">{{ CURRENCY }}</span><span class="fs-6 fw-normal">/ {{ pp.pricing.period }}</span> {% trans "days" %}</h5>
<h6>{{ _("Included") }}</h6>
<ul class="fa-ul ps-3">
{% if pp.plan.description %}
@ -91,38 +91,38 @@
<!-- Step 2: User Info -->
<div class="step d-none" id="step2">
<h4 class="mb-4">2. Enter Your Information</h4>
<h4 class="mb-4">2. {{ _("Enter Your Information")}}</h4>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">First Name</label>
<label class="form-label">{{ _("First Name")}}</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-user"></i></span>
<input type="text" name="first_name" id="first_name" class="form-control" required placeholder="John" value="{{ request.user.first_name }}">
</div>
</div>
<div class="col-md-6">
<label class="form-label">Last Name</label>
<label class="form-label">{{ _("Last Name")}}</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-user"></i></span>
<input type="text" name="last_name" id="last_name" class="form-control" required placeholder="Doe" value="{{ request.user.last_name }}">
</div>
</div>
<div class="col-md-6">
<label class="form-label">Email Address</label>
<label class="form-label">{{ _("Email Address")}}</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-envelope"></i></span>
<input type="email" name="email" id="email" class="form-control" required placeholder="email@example.com" value="{{ request.user.email }}">
</div>
</div>
<div class="col-md-6">
<label class="form-label">Phone Number</label>
<label class="form-label">{{ _("Phone Number")}}</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-phone"></i></span>
<input type="text" name="phone" id="phone" class="form-control" required placeholder="056XXXXXXX" value="{{ request.user.dealer.phone_number.raw_input }}">
</div>
</div>
<div class="col-md-6">
<label class="form-label">Company</label>
<label class="form-label">{{ _("Company") }}</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-building"></i></span>
<input type="text" name="company" id="company" class="form-control" placeholder="ABC Company">
@ -133,10 +133,10 @@
<!-- Step 3: Payment -->
<div class="step d-none" id="step3">
<h4 class="mb-4">3. Payment Information</h4>
<h4 class="mb-4">3. {{ _("Payment Information")}}</h4>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Cardholder Name</label>
<label class="form-label">{{ _("Cardholder Name<")}}/label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-user"></i></span>
<input type="text" name="card_name" id="card_name" class="form-control" placeholder="John Doe" required>
@ -144,7 +144,7 @@
</div>
<div class="col-md-6">
<label class="form-label">Card Number</label>
<label class="form-label">{{ _("Card Number")}}</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-credit-card"></i></span>
<input type="text" name="card_number" id="card_number" class="form-control" placeholder="1234 5678 9012 3456"
@ -154,7 +154,7 @@
</div>
<div class="col-md-4">
<label class="form-label">Expiry Date (MM/YY)</label>
<label class="form-label">{{ _("Expiry Date")}} (MM/YY)</label>
<div class="input-group">
<span class="input-group-text"><i class="far fa-calendar-alt"></i></span>
<input type="text" name="card_expiry" id="card_expiry" class="form-control" placeholder="08/28"
@ -164,7 +164,7 @@
</div>
<div class="col-md-2">
<label class="form-label">CVV</label>
<label class="form-label">{{ _("CVV") }}</label>
<div class="input-group">
<span class="input-group-text"><i class="fas fa-lock"></i></span>
<input type="text" name="card_cvv" id="card_cvv" class="form-control" placeholder="123"
@ -184,7 +184,7 @@
<div class="summary-item"><i class="fas fa-tag"></i><strong>Price:</strong> <span id="summary_price"></span></div>
<div class="summary-item"><i class="fas fa-receipt"></i><strong>Tax (15%):</strong> <span id="summary-tax">0.00</span> <span class="currency">{{ CURRENCY }}</span></div>
<hr>
<div class="summary-item"><i class="fas fa-hand-holding-usd"></i><strong>Total:</strong> <span id="summary-total">0.00</span> {{ CURRENCY }}</div>
<div class="summary-item"><i class="fas fa-hand-holding-usd"></i><strong>Total:</strong> <span id="summary-total">0.00</span> <span class="currency">{{ CURRENCY }}</span></div>
<h5 class="mt-4"><i class="fas fa-user me-2"></i>User Information</h5>
<div class="summary-item"><i class="fas fa-signature"></i><strong>Name:</strong> <span id="summary_name"></span></div>
@ -201,9 +201,9 @@
<!-- Navigation -->
<div class="d-flex justify-content-between mt-4">
<button type="button" class="btn btn-outline-secondary" id="prevBtn" disabled>Previous</button>
<button type="button" class="btn btn-primary" id="nextBtn">Next</button>
<button type="submit" class="btn btn-success d-none" id="submitBtn">Confirm</button>
<button type="button" class="btn btn-outline-secondary" id="prevBtn" disabled>{{ _("Previous") }}</button>
<button type="button" class="btn btn-primary" id="nextBtn">{{ _("Next") }}</button>
<button type="submit" class="btn btn-success d-none" id="submitBtn">{{ _("Confirm") }}</button>
</div>
</form>
</div>
@ -337,9 +337,9 @@
const tax = price * 0.15;
const total = price + tax;
document.getElementById("summary_price").textContent = price.toFixed(2) + " {{ CURRENCY }}";
document.getElementById("summary-tax").textContent = tax.toFixed(2) + " {{ CURRENCY }}";
document.getElementById("summary-total").textContent = total.toFixed(2) + " {{ CURRENCY }}";
document.getElementById("summary_price").textContent = price.toFixed(2);
document.getElementById("summary-tax").textContent = tax.toFixed(2);
document.getElementById("summary-total").textContent = total.toFixed(2);
}
}