This commit is contained in:
gitea 2024-12-25 17:28:03 +00:00
parent c6a115576d
commit 71ad0bc9e6
18 changed files with 571 additions and 77 deletions

View File

@ -26,8 +26,15 @@ from django.forms import ModelMultipleChoiceField
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables
from django.forms import formset_factory
from .models import Account
from django_ledger.models import EntityModel, ChartOfAccountModel
from django_ledger.io import roles, DEBIT, CREDIT
class AdditionalServiceForm(forms.ModelForm):
class Meta:
model = AdditionalServices
fields = ['name', 'price','description','vatable', 'uom']
class PaymentForm(forms.ModelForm):
class Meta:
@ -253,3 +260,18 @@ class CarSelectionTable(tables.Table):
model = Car
fields = ['vin', 'year', 'id_car_make', 'id_car_model']
template_name = "django_tables2/bootstrap4.html"
class AccountForm(forms.ModelForm):
role = forms.ChoiceField(choices=roles.ROLE_TUPLES, widget=forms.Select(attrs={'class': 'form-select'}))
balance_type = forms.ChoiceField(choices=[(DEBIT, DEBIT),(CREDIT, CREDIT)], widget=forms.Select(attrs={'class': 'form-select'}))
class Meta:
model = Account
fields = ['code', 'name', 'role', 'balance_type', 'active']
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# # Customize the queryset for entity and coa fields if needed
# self.fields['entity'].queryset = EntityModel.objects.all()
# self.fields['coa'].queryset = ChartOfAccountModel.objects.all()

View File

@ -0,0 +1,20 @@
# Generated by Django 4.2.17 on 2024-12-25 15:52
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
('inventory', '0024_dealer_email'),
]
operations = [
migrations.AddField(
model_name='dealer',
name='entity',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='django_ledger.entitymodel'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.17 on 2024-12-25 16:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0025_dealer_entity'),
]
operations = [
migrations.AddField(
model_name='additionalservices',
name='vatable',
field=models.BooleanField(default=True, verbose_name='Vatable'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.17 on 2024-12-25 16:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0026_additionalservices_vatable'),
]
operations = [
migrations.AlterField(
model_name='additionalservices',
name='vatable',
field=models.BooleanField(default=False, verbose_name='Vatable'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2.17 on 2024-12-25 16:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0027_alter_additionalservices_vatable'),
]
operations = [
migrations.AddField(
model_name='additionalservices',
name='uom',
field=models.CharField(choices=[('m', 'Meter'), ('cm', 'Centimeter'), ('mm', 'Millimeter'), ('in', 'Inch'), ('ft', 'Foot'), ('kg', 'Kilogram'), ('g', 'Gram'), ('mg', 'Milligram'), ('lb', 'Pound'), ('oz', 'Ounce'), ('L', 'Liter'), ('mL', 'Milliliter'), ('', 'Cubic Meter'), ('ft³', 'Cubic Foot'), ('gal', 'Gallon'), ('s', 'Second'), ('min', 'Minute'), ('h', 'Hour'), ('d', 'Day'), ('wk', 'Week'), ('°C', 'Celsius'), ('°F', 'Fahrenheit'), ('K', 'Kelvin'), ('km/h', 'Kilometer per hour'), ('mph', 'Miles per hour'), ('m/s', 'Meter per second'), ('', 'Square Meter'), ('cm²', 'Square Centimeter'), ('ft²', 'Square Foot'), ('in²', 'Square Inch'), ('J', 'Joule'), ('kJ', 'Kilojoule'), ('kWh', 'Kilowatt-hour'), ('cal', 'Calorie'), ('W', 'Watt'), ('kW', 'Kilowatt'), ('MW', 'Megawatt'), ('hp', 'Horsepower'), ('N', 'Newton'), ('kN', 'Kilonewton'), ('lbf', 'Pound-force'), ('Pa', 'Pascal'), ('kPa', 'Kilopascal'), ('MPa', 'Megapascal'), ('bar', 'Bar'), ('psi', 'Pound per square inch'), ('Nm', 'Newton-meter'), ('lb-ft', 'Pound-foot'), ('Hz', 'Hertz'), ('kHz', 'Kilohertz'), ('MHz', 'Megahertz'), ('A', 'Ampere'), ('mA', 'Milliampere'), ('µA', 'Microampere'), ('unit', 'Unit'), ('dozen', 'Dozen'), ('box', 'Box'), ('pack', 'Pack')], default='KG', max_length=10, verbose_name='Unit of Measurement'),
preserve_default=False,
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 4.2.17 on 2024-12-25 16:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0028_additionalservices_uom'),
]
operations = [
migrations.AddField(
model_name='additionalservices',
name='dealer',
field=models.ForeignKey(default=2, on_delete=django.db.models.deletion.CASCADE, to='inventory.dealer', verbose_name='Dealer'),
preserve_default=False,
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 4.2.17 on 2024-12-25 17:00
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
('inventory', '0029_additionalservices_dealer'),
]
operations = [
migrations.CreateModel(
name='Account',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(max_length=10, unique=True)),
('name', models.CharField(max_length=100)),
('role', models.CharField(max_length=50)),
('balance_type', models.CharField(max_length=10)),
('active', models.BooleanField(default=True)),
('coa', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='django_ledger.chartofaccountmodel')),
('entity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='django_ledger.entitymodel')),
],
),
]

View File

@ -27,7 +27,8 @@ from django.utils.timezone import now
from .utilities.financials import get_financial_value, get_total, get_total_financials
from django.db.models import FloatField
from .mixins import LocalizedNameMixin
from django_ledger.models import EntityModel
from django_ledger.models import EntityModel, ChartOfAccountModel
class CarMake(models.Model, LocalizedNameMixin):
id_car_make = models.AutoField(primary_key=True)
@ -141,13 +142,104 @@ class DEALER_TYPES(models.TextChoices):
Inventory = "Inventory", _("Inventory")
Accountent = "Accountent", _("Accountent")
Sales = "sales", _("Sales")
UNIT_CHOICES = [
# Length
('m', 'Meter'),
('cm', 'Centimeter'),
('mm', 'Millimeter'),
('in', 'Inch'),
('ft', 'Foot'),
# Mass
('kg', 'Kilogram'),
('g', 'Gram'),
('mg', 'Milligram'),
('lb', 'Pound'),
('oz', 'Ounce'),
# Volume
('L', 'Liter'),
('mL', 'Milliliter'),
('', 'Cubic Meter'),
('ft³', 'Cubic Foot'),
('gal', 'Gallon'),
# Time
('s', 'Second'),
('min', 'Minute'),
('h', 'Hour'),
('d', 'Day'),
('wk', 'Week'),
# Temperature
('°C', 'Celsius'),
('°F', 'Fahrenheit'),
('K', 'Kelvin'),
# Speed
('km/h', 'Kilometer per hour'),
('mph', 'Miles per hour'),
('m/s', 'Meter per second'),
# Area
('', 'Square Meter'),
('cm²', 'Square Centimeter'),
('ft²', 'Square Foot'),
('in²', 'Square Inch'),
# Energy
('J', 'Joule'),
('kJ', 'Kilojoule'),
('kWh', 'Kilowatt-hour'),
('cal', 'Calorie'),
# Power
('W', 'Watt'),
('kW', 'Kilowatt'),
('MW', 'Megawatt'),
('hp', 'Horsepower'),
# Force
('N', 'Newton'),
('kN', 'Kilonewton'),
('lbf', 'Pound-force'),
# Pressure
('Pa', 'Pascal'),
('kPa', 'Kilopascal'),
('MPa', 'Megapascal'),
('bar', 'Bar'),
('psi', 'Pound per square inch'),
# Torque
('Nm', 'Newton-meter'),
('lb-ft', 'Pound-foot'),
# Frequency
('Hz', 'Hertz'),
('kHz', 'Kilohertz'),
('MHz', 'Megahertz'),
# Electric Current
('A', 'Ampere'),
('mA', 'Milliampere'),
('µA', 'Microampere'),
# Other
('unit', 'Unit'), # For counting items
('dozen', 'Dozen'), # For counting in dozens
('box', 'Box'), # For counting in boxes
('pack', 'Pack'), # For counting in packs
]
class AdditionalServices(models.Model, LocalizedNameMixin):
name = models.CharField(max_length=255, verbose_name=_("Name"))
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
description = models.TextField(verbose_name=_("Description"))
price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Price"))
vatable = models.BooleanField(default=False, verbose_name=_("Vatable"))
uom = models.CharField(max_length=10, choices=UNIT_CHOICES, verbose_name=_("Unit of Measurement"))
dealer = models.ForeignKey("Dealer", on_delete=models.CASCADE, verbose_name=_("Dealer"))
class Meta:
verbose_name = _("Additional Services")
@ -499,7 +591,7 @@ class Dealer(models.Model, LocalizedNameMixin):
upload_to="logos/users", blank=True, null=True, verbose_name=_("Logo")
)
joined_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Joined At"))
# entity = models.ForeignKey(EntityModel,on_delete=models.CASCADE,null=True,blank=True)
entity = models.ForeignKey(EntityModel,on_delete=models.CASCADE,null=True,blank=True)
email = models.EmailField(unique=True, verbose_name=_("Email"))
parent_dealer = models.ForeignKey(
"self",
@ -562,7 +654,7 @@ class Dealer(models.Model, LocalizedNameMixin):
@receiver(post_save, sender=User)
def create_dealer(instance, created, *args, **kwargs):
if created:
Dealer.objects.create(user=instance)
Dealer.objects.create(user=instance,name=instance.username,email=instance.email)
# Vendor Model
@ -875,4 +967,19 @@ class Refund(models.Model):
verbose_name_plural = _("refunds")
def __str__(self):
return f"Refund of {self.amount} on {self.refund_date}"
return f"Refund of {self.amount} on {self.refund_date}"
# accounts
class Account(models.Model):
entity = models.ForeignKey(EntityModel, on_delete=models.CASCADE)
coa = models.ForeignKey(ChartOfAccountModel, on_delete=models.CASCADE)
code = models.CharField(max_length=10, unique=True)
name = models.CharField(max_length=100)
role = models.CharField(max_length=50)
balance_type = models.CharField(max_length=10)
active = models.BooleanField(default=True)
def __str__(self):
return f"{self.code} - {self.name}"

View File

@ -10,7 +10,6 @@ from django.utils.translation import gettext_lazy as _
from . import models
# @receiver(post_save, sender=models.SaleQuotation)
# def link_quotation_to_entity(sender, instance, created, **kwargs):
# if created:
@ -26,18 +25,20 @@ from . import models
@receiver(post_save, sender=models.Car)
def create_car_location(sender, instance, created, **kwargs):
"""
Signal to create or update the car's location when a car instance is saved.
"""
Signal to create or update the car's location when a car instance is saved.
"""
try:
if created:
if instance.dealer is None:
raise ValueError(f"Cannot create CarLocation for car {instance.vin}: dealer is missing.")
raise ValueError(
f"Cannot create CarLocation for car {instance.vin}: dealer is missing."
)
models.CarLocation.objects.create(
car=instance,
owner=instance.dealer,
showroom=instance.dealer,
description=f"Initial location set for car {instance.vin}."
description=f"Initial location set for car {instance.vin}.",
)
print("Car Location created")
except Exception as e:
@ -63,70 +64,78 @@ def update_car_status_on_reservation_delete(sender, instance, **kwargs):
# Create Entity
@receiver(post_save, sender=models.Dealer)
def create_ledger_entity(sender, instance, created, **kwargs):
if created:
entity, created = EntityModel.objects.get_or_create(
name=instance.get_root_dealer.name,
admin=instance.get_root_dealer.user,
accrual_method=False,
fy_start_month=1,
depth=0,
)
print(entity)
if created:
default_coa = entity.create_chart_of_accounts(assign_as_default=True,
commit=True,
coa_name=_("Chart of Accounts"))
if default_coa:
entity.populate_default_coa(activate_accounts=True, coa_model=default_coa)
print(f"Ledger entity created for Dealer: {instance.name}")
if created:
root_dealer = instance.get_root_dealer
if not root_dealer.entity:
entity_name = f"{root_dealer.name}-{root_dealer.pk}-{root_dealer.joined_at.date()}"
entity = EntityModel.create_entity(
name=entity_name,
admin=root_dealer.user,
use_accrual_method=True,
fy_start_month=1,
)
# entity.create_account(
# coa_model=coa,
# code=1010,
# role='asset_ca_cash',
# name=_('Cash'),
# balance_type="debit",
# )
# entity.create_account(
# coa_model=coa,
# code=1100,
# role='asset_ca_recv',
# name=_('Accounts Receivable'),
# balance_type="debit",
# )
# entity.create_account(
# coa_model=coa,
# code=1200,
# role='asset_ca_inv',
# name=_('Inventory'),
# balance_type="debit",
# active=True)
#
# entity.create_account(
# coa_model=coa,
# code=2010,
# role='lia_cl_acc_payable',
# name=_('Accounts Payable'),
# balance_type="credit",
# active=True)
#
# entity.create_account(
# coa_model=coa,
# code=4010,
# role='in_operational',
# name=_('Sales Income'),
# balance_type="credit",
# active=True)
#
# entity.create_account(
# coa_model=coa,
# code=5010,
# role='cogs_regular',
# name=_('Cost of Goods Sold'),
# balance_type="debit",
# active=True)
if entity:
instance.entity = entity
instance.save()
coa = entity.create_chart_of_accounts(
assign_as_default=True, commit=True, coa_name=_(f"{entity_name}-COA")
)
if coa:
entity.populate_default_coa(activate_accounts=True, coa_model=coa)
print(f"Ledger entity created for Dealer: {instance.name}")
entity.create_account(
coa_model=coa,
code="10100",
role="asset_ca_cash",
name=_("Cash"),
balance_type="debit",
active=True,
)
entity.create_account(
coa_model=coa,
code="11000",
role="asset_ca_recv",
name=_("Accounts Receivable"),
balance_type="debit",
active=True,
)
entity.create_account(
coa_model=coa,
code="12000",
role="asset_ca_inv",
name=_("Inventory"),
balance_type="debit",
active=True,
)
entity.create_account(
coa_model=coa,
code="20100",
role="lia_cl_acc_payable",
name=_("Accounts Payable"),
balance_type="credit",
active=True,
)
entity.create_account(
coa_model=coa,
code="40100",
role="in_operational",
name=_("Sales Income"),
balance_type="credit",
active=True,
)
entity.create_account(
coa_model=coa,
code="50100",
role="cogs_regular",
name=_("Cost of Goods Sold"),
balance_type="debit",
active=True,
)
# uom_name = _("Unit")
# unit_abbr = _("U")
@ -134,11 +143,9 @@ def create_ledger_entity(sender, instance, created, **kwargs):
# entity.create_uom(uom_name, unit_abbr)
# Create Vendor
@receiver(post_save, sender=models.Vendor)
def create_ledger_vendor(sender, instance, created, **kwargs):
if created:
entity = EntityModel.objects.filter(name=instance.dealer.name).first()
@ -153,8 +160,8 @@ def create_ledger_vendor(sender, instance, created, **kwargs):
additional_info={
"arabic_name": instance.arabic_name,
"contact_person": instance.contact_person,
})
},
)
print(f"VendorModel created for Vendor: {instance.name}")
@ -162,7 +169,9 @@ def create_ledger_vendor(sender, instance, created, **kwargs):
@receiver(post_save, sender=models.Customer)
def create_customer(sender, instance, created, **kwargs):
if created:
entity = EntityModel.objects.filter(name=instance.dealer.get_root_dealer.name).first()
entity = EntityModel.objects.filter(
name=instance.dealer.get_root_dealer.name
).first()
name = f"{instance.first_name} {instance.middle_name} {instance.last_name}"
entity.create_customer(
@ -174,7 +183,7 @@ def create_customer(sender, instance, created, **kwargs):
"sales_tax_rate": 0.15,
"active": True,
"hidden": False,
"additional_info": {}
"additional_info": {},
}
)
@ -273,4 +282,3 @@ def create_customer(sender, instance, created, **kwargs):
# else:
# quotation.status = 'pending'
# quotation.save()

View File

@ -105,6 +105,19 @@ urlpatterns = [
path('representatives/create/', views.RepresentativeCreateView.as_view(), name='representative_create'),
path('representatives/<int:pk>/update/', views.RepresentativeUpdateView.as_view(), name='representative_update'),
path('representatives/<int:pk>/delete/', views.RepresentativeDeleteView.as_view(), name='representative_delete'),
#AdditionalServices URLs
path('additionalservices/', views.AdditionalServiceListView.as_view(), name='additional_service_list'),
path('additionalservices/<int:pk>/', views.AdditionalServiceDetailView.as_view(), name='additional_service_detail'),
path('additionalservices/create/', views.AdditionalServiceCreateView.as_view(), name='additional_service_create'),
path('additionalservices/<int:pk>/update/', views.AdditionalServiceUpdateView.as_view(), name='additional_service_update'),
path('additionalservices/<int:pk>/delete/', views.AdditionalServiceDeleteView.as_view(), name='additional_service_delete'),
#ledger accounts
path('accounts/',views.AccountListView.as_view(), name='account_list'),
path('accounts/create/', views.AccountCreateView.as_view(), name='account_create'),
path('accounts/update/<int:pk>/', views.AccountUpdateView.as_view(), name='account_update'),
path('accounts/delete/<int:pk>/', views.AccountDeleteView.as_view(), name='account_delete')
]

View File

@ -54,6 +54,8 @@ from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.models import Group
from django.contrib.auth import get_user_model
from .utils import get_calculations
from .models import Account
from .forms import AccountForm
User = get_user_model()
@ -1445,3 +1447,92 @@ def payment_create(request, pk):
else:
form = forms.PaymentForm()
return render(request, "sales/payments/payment_create.html", {"quotation": quotation,"form": form})
class AdditionalServiceListView(LoginRequiredMixin, ListView):
model = models.AdditionalServices
template_name = "sales/additional_services/additional_service_list.html"
context_object_name = "services"
def get_queryset(self):
dealer = self.request.user.dealer.get_root_dealer
return models.AdditionalServices.objects.filter(dealer=dealer)
class AdditionalServiceDetailView(LoginRequiredMixin, DetailView):
model = models.AdditionalServices
template_name = "sales/additional_services/additional_service_detail.html"
context_object_name = "service"
class AdditionalServiceCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = models.AdditionalServices
form_class = forms.AdditionalServiceForm
template_name = "sales/additional_services/additional_service_form.html"
success_url = reverse_lazy("additional_service_list")
success_message = "Additional Service created successfully."
def form_valid(self, form):
dealer = self.request.user.dealer.get_root_dealer
form.instance.dealer = dealer
for entity in EntityModel.objects.all():
if entity:
uom_name = form.cleaned_data.get('uom')
uom = entity.create_uom(
name=uom_name,
unit_abbr=uom_name)
service_name = form.cleaned_data.get('name')
service_model = entity.create_item_service(
name=service_name,
uom_model=uom)
form.save()
return super().form_valid(form)
class AdditionalServiceUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = models.AdditionalServices
form_class = forms.AdditionalServiceForm
template_name = "sales/additional_services/additional_service_form.html"
success_url = reverse_lazy("additional_service_list")
success_message = "Additional Service updated successfully."
class AdditionalServiceDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = models.AdditionalServices
success_url = reverse_lazy("additional_service_list")
success_message = "Additional Service deleted successfully."
class AccountListView(ListView):
model = Account
template_name = 'ledger_accounts/account_list.html'
context_object_name = 'accounts'
def get_queryset(self):
dealer = self.request.user.dealer.get_root_dealer
return Account.objects.filter(entity=dealer.entity)
class AccountCreateView(CreateView):
model = Account
form_class = AccountForm
template_name = 'ledger_accounts/account_form.html'
success_url = reverse_lazy('account_list')
def form_valid(self, form):
dealer = self.request.user.dealer.get_root_dealer
if dealer.entity:
form.instance.entity = dealer.entity
coa = dealer.entity.get_default_coa()
if coa:
form.instance.coa = coa
return super().form_valid(form)
class AccountUpdateView(UpdateView):
model = Account
form_class = AccountForm
template_name = 'ledger_accounts/account_form.html'
success_url = reverse_lazy('account_list')
class AccountDeleteView(DeleteView):
model = Account
template_name = 'ledger_accounts/account_confirm_delete.html'
success_url = reverse_lazy('account_list')

View File

@ -229,6 +229,19 @@
</a>
<!-- more inner pages-->
</li>
<li class="nav-item"><a class="nav-link" href="{% url 'additional_service_list' %}">
<div class="d-flex align-items-center"><span class="nav-link-text">{% trans "Services"|capfirst %}</span>
</div>
</a>
<!-- more inner pages-->
</li>
</li>
<li class="nav-item"><a class="nav-link" href="{% url 'account_list' %}">
<div class="d-flex align-items-center"><span class="nav-link-text">{% trans "Account"|capfirst %}</span>
</div>
</a>
<!-- more inner pages-->
</li>
</ul>
</div>

View File

@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% block content %}
<h1>Delete Account</h1>
<p>Are you sure you want to delete "{{ object }}"?</p>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn btn-danger">Delete</button>
<a href="{% url 'account_list' %}" class="btn btn-secondary">Cancel</a>
</form>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}{% if object %}Edit{% else %}Create{% endif %} Account{% endblock %}
{% block content %}
<h1>{% if object %}Edit{% else %}Create{% endif %} Account</h1>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends 'base.html' %}
{% block content %}
<h1>Accounts</h1>
<a href="{% url 'account_create' %}" class="btn btn-primary">Create New Account</a>
<table class="table">
<thead>
<tr>
<th>Code</th>
<th>Name</th>
<th>Role</th>
<th>Balance Type</th>
<th>Active</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for account in accounts %}
<tr>
<td>{{ account.code }}</td>
<td>{{ account.name }}</td>
<td>{{ account.role }}</td>
<td>{{ account.balance_type }}</td>
<td>{{ account.active }}</td>
<td>
<a href="{% url 'account_update' account.pk %}" class="btn btn-warning">Edit</a>
<a href="{% url 'account_delete' account.pk %}" class="btn btn-danger">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}{% trans "Additional Services" %}{% endblock title %}
{% block additional_services %}
<a class="nav-link active fw-bold">
{% trans "Additional Services"|capfirst %}
<span class="visually-hidden">(current)</span>
</a>
{% endblock %}
{% block content %}
<form method="post">{% csrf_token %}{{ form|crispy }}<button class="btn btn-primary" type="submit">{% trans "Save" %}</button></form>
{% endblock %}

View File

@ -0,0 +1,47 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans "Additional Services" %}{% endblock title %}
{% block additional_services %}
<a class="nav-link active fw-bold">
{% trans "Additional Services" %}
<span class="visually-hidden">(current)</span>
</a>
{% endblock %}
{% block content %}
<a href="{% url 'additional_service_create' %}" class="btn btn-sm btn-success">{% trans "Create" %}</a>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Arabic Name</th>
<th scope="col">Description</th>
<th scope="col">Price</th>
<th scope="col">Vatable</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{% for service in services %}
<tr>
<th scope="row"></th>
<td>{{service.name}}</td>
<td>{{service.arabic_name}}</td>
<td>{{service.description}}</td>
<td>{{service.price}}</td>
<td>{{service.vatable}}</td>
<td>
<a href="{% url 'additional_service_detail' service.id %}" class="btn btn-sm btn-info">{% trans "Details" %}</a>
<a href="{% url 'additional_service_update' service.id %}" class="btn btn-sm btn-primary">{% trans "Update" %}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}