update
This commit is contained in:
parent
266bd54fe3
commit
41e1a7d472
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -3,4 +3,5 @@
|
||||
#
|
||||
# websocket_urlpatterns = [
|
||||
# re_path(r'ws/vin_scan/$', consumers.VINScanConsumer.as_asgi()),
|
||||
# ]
|
||||
# ]
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from rest_framework import serializers
|
||||
from . import models
|
||||
from rest_framework import serializers
|
||||
from inventory import models as inventory_models
|
||||
|
||||
|
||||
class CarVINSerializer(serializers.ModelSerializer):
|
||||
@ -12,3 +13,71 @@ class CarVINSerializer(serializers.ModelSerializer):
|
||||
return models.CarVIN.objects.create(vin=vin, **validated_data)
|
||||
|
||||
|
||||
class CarMakeSerializer(serializers.ModelSerializer):
|
||||
car_models = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='carmodel_set')
|
||||
|
||||
class Meta:
|
||||
model = inventory_models.CarMake
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CarModelSerializer(serializers.ModelSerializer):
|
||||
car_series = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='carserie_set')
|
||||
|
||||
class Meta:
|
||||
model = inventory_models.CarModel
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CarSerieSerializer(serializers.ModelSerializer):
|
||||
car_trims = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='cartrim_set')
|
||||
|
||||
class Meta:
|
||||
model = inventory_models.CarSerie
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CarTrimSerializer(serializers.ModelSerializer):
|
||||
car_equipments = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='carequipment_set')
|
||||
car_specification_values = serializers.PrimaryKeyRelatedField(many=True, read_only=True,
|
||||
source='carspecificationvalue_set')
|
||||
|
||||
class Meta:
|
||||
model = inventory_models.CarTrim
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CarEquipmentSerializer(serializers.ModelSerializer):
|
||||
car_option_values = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='caroptionvalue_set')
|
||||
|
||||
class Meta:
|
||||
model = inventory_models.CarEquipment
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CarSpecificationSerializer(serializers.ModelSerializer):
|
||||
child_specifications = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='carspecification_set')
|
||||
|
||||
class Meta:
|
||||
model = inventory_models.CarSpecification
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CarSpecificationValueSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = inventory_models.CarSpecificationValue
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CarOptionSerializer(serializers.ModelSerializer):
|
||||
child_options = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='caroption_set')
|
||||
|
||||
class Meta:
|
||||
model = inventory_models.CarOption
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CarOptionValueSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = inventory_models.CarOptionValue
|
||||
fields = '__all__'
|
||||
18
api/urls.py
18
api/urls.py
@ -1,8 +1,22 @@
|
||||
from django.urls import path
|
||||
from django.urls import path, include
|
||||
from rest_framework import routers
|
||||
|
||||
from api import views
|
||||
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register(r'car-makes', views.CarMakeViewSet)
|
||||
router.register(r'car-models', views.CarModelViewSet)
|
||||
router.register(r'car-series', views.CarSerieViewSet)
|
||||
router.register(r'car-trims', views.CarTrimViewSet)
|
||||
router.register(r'car-equipments', views.CarEquipmentViewSet)
|
||||
router.register(r'car-specifications', views.CarSpecificationViewSet)
|
||||
router.register(r'car-specification-values', views.CarSpecificationValueViewSet)
|
||||
router.register(r'car-options', views.CarOptionViewSet)
|
||||
router.register(r'car-option-values', views.CarOptionValueViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
path('cars/vin/', views.CarVINViewSet.as_view(), name='car_vin'),
|
||||
path('login/', views.LoginView.as_view(), name='login'),
|
||||
]
|
||||
]
|
||||
|
||||
49
api/views.py
49
api/views.py
@ -1,5 +1,6 @@
|
||||
from django.db.models import Q
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from rest_framework import permissions, status, viewsets
|
||||
from rest_framework import permissions, status, viewsets, generics
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from django.contrib.auth import authenticate
|
||||
@ -7,8 +8,9 @@ from django.shortcuts import render
|
||||
from . import models, serializers
|
||||
from .services import get_car_data, get_from_cardatabase
|
||||
from rest_framework.authtoken.models import Token
|
||||
# from inventory.models import CustomUser
|
||||
from django.utils.decorators import method_decorator
|
||||
from inventory import models as inventory_models
|
||||
|
||||
|
||||
|
||||
class LoginView(APIView):
|
||||
@ -51,3 +53,46 @@ class CarVINViewSet(APIView):
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class CarMakeViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarMake.objects.filter(is_sa_import=True)
|
||||
serializer_class = serializers.CarMakeSerializer
|
||||
|
||||
|
||||
class CarModelViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarModel.objects.filter(id_car_make__is_sa_import=True)
|
||||
serializer_class = serializers.CarModelSerializer
|
||||
|
||||
|
||||
class CarSerieViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarSerie.objects.all()
|
||||
serializer_class = serializers.CarSerieSerializer
|
||||
|
||||
|
||||
class CarTrimViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarTrim.objects.all()
|
||||
serializer_class = serializers.CarTrimSerializer
|
||||
|
||||
|
||||
class CarEquipmentViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarEquipment.objects.all()
|
||||
serializer_class = serializers.CarEquipmentSerializer
|
||||
|
||||
|
||||
class CarSpecificationViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarSpecification.objects.all()
|
||||
serializer_class = serializers.CarSpecificationSerializer
|
||||
|
||||
|
||||
class CarSpecificationValueViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarSpecificationValue.objects.all()
|
||||
serializer_class = serializers.CarSpecificationValueSerializer
|
||||
|
||||
|
||||
class CarOptionViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarOption.objects.all()
|
||||
serializer_class = serializers.CarOptionSerializer
|
||||
|
||||
|
||||
class CarOptionValueViewSet(viewsets.ModelViewSet):
|
||||
queryset = inventory_models.CarOptionValue.objects.all()
|
||||
serializer_class = serializers.CarOptionValueSerializer
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -452,6 +452,10 @@ class Car(models.Model):
|
||||
"id": self.id,
|
||||
}
|
||||
|
||||
def get_specifications(self):
|
||||
specs = CarSpecificationValue.objects.filter(id_car_trim=self.id_car_trim)
|
||||
return specs
|
||||
|
||||
class CarTransfer(models.Model):
|
||||
car = models.ForeignKey(
|
||||
"Car",
|
||||
|
||||
@ -115,6 +115,28 @@ from django.core.files.storage import default_storage
|
||||
from plans.models import Plan,PlanPricing
|
||||
from django_ledger.utils import accruable_net_summary
|
||||
from appointment.views_admin import fetch_user_appointments
|
||||
from django_ledger.views.financial_statement import (
|
||||
FiscalYearBalanceSheetView,
|
||||
BaseIncomeStatementRedirectView,
|
||||
FiscalYearIncomeStatementView,
|
||||
BaseCashFlowStatementRedirectView,
|
||||
FiscalYearCashFlowStatementView,
|
||||
)
|
||||
from django_ledger.views.entity import EntityModelDetailBaseView,EntityModelDetailHandlerView
|
||||
from django.views.generic import DetailView, RedirectView
|
||||
|
||||
from django_ledger.io.io_core import get_localdate
|
||||
from django_ledger.models import EntityModel, EntityUnitModel
|
||||
from django_ledger.views.mixins import (
|
||||
QuarterlyReportMixIn,
|
||||
YearlyReportMixIn,
|
||||
MonthlyReportMixIn,
|
||||
DateReportMixIn,
|
||||
DjangoLedgerSecurityMixIn,
|
||||
EntityUnitMixIn,
|
||||
BaseDateNavigationUrlMixIn,
|
||||
PDFReportMixIn,
|
||||
)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -2649,6 +2671,7 @@ class PaymentRequest(LoginRequiredMixin, DetailView):
|
||||
models.Car.objects.get(vin=car.item_model.name)
|
||||
for car in context["estimate"].get_itemtxs_data()[0].all()
|
||||
]
|
||||
|
||||
return context
|
||||
|
||||
|
||||
@ -2957,7 +2980,7 @@ def PaymentCreateView(request, pk):
|
||||
try:
|
||||
if invoice:
|
||||
set_invoice_payment(dealer, entity, invoice, amount, payment_method)
|
||||
elif bill:
|
||||
elif bill:
|
||||
set_bill_payment(dealer, entity, bill, amount, payment_method)
|
||||
messages.success(request, "Payment created successfully!")
|
||||
return redirect(redirect_url, pk=model.pk)
|
||||
@ -3094,6 +3117,7 @@ def lead_create(request):
|
||||
|
||||
return render(request, "crm/leads/lead_form.html", {"form": form})
|
||||
|
||||
|
||||
class LeadUpdateView(UpdateView):
|
||||
model = models.Lead
|
||||
form_class = forms.LeadForm
|
||||
@ -3105,6 +3129,8 @@ class LeadUpdateView(UpdateView):
|
||||
form.fields["id_car_model"].queryset = form.instance.id_car_make.carmodel_set.all()
|
||||
return form
|
||||
|
||||
|
||||
@login_required
|
||||
def LeadDeleteView(request,pk):
|
||||
lead = get_object_or_404(models.Lead, pk=pk)
|
||||
lead.delete()
|
||||
@ -3278,7 +3304,7 @@ def add_activity_to_lead(request, pk):
|
||||
return render(request, "crm/add_activity.html", {"form": form, "lead": lead})
|
||||
|
||||
|
||||
class OpportunityCreateView(CreateView):
|
||||
class OpportunityCreateView(CreateView, LoginRequiredMixin):
|
||||
model = models.Opportunity
|
||||
form_class = forms.OpportunityForm
|
||||
template_name = "crm/opportunities/opportunity_form.html"
|
||||
@ -3309,7 +3335,7 @@ class OpportunityCreateView(CreateView):
|
||||
return reverse_lazy("opportunity_detail", kwargs={"pk": self.object.pk})
|
||||
|
||||
|
||||
class OpportunityUpdateView(UpdateView):
|
||||
class OpportunityUpdateView(UpdateView, LoginRequiredMixin):
|
||||
model = models.Opportunity
|
||||
form_class = forms.OpportunityForm
|
||||
template_name = "crm/opportunities/opportunity_form.html"
|
||||
@ -3432,7 +3458,8 @@ class ItemServiceCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView)
|
||||
|
||||
def form_valid(self, form):
|
||||
vat = models.VatRate.objects.get(is_active=True)
|
||||
form.instance.dealer = get_user_type(self.request.user.dealer)
|
||||
dealer = get_user_type(self.request)
|
||||
form.instance.dealer = dealer
|
||||
if form.instance.taxable:
|
||||
form.instance.price = (form.instance.price * vat.rate) + form.instance.price
|
||||
return super().form_valid(form)
|
||||
@ -3448,13 +3475,14 @@ class ItemServiceUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView)
|
||||
|
||||
def form_valid(self, form):
|
||||
vat = models.VatRate.objects.get(is_active=True)
|
||||
form.instance.dealer = get_user_type(self.request.user.dealer)
|
||||
dealer = get_user_type(self.request)
|
||||
form.instance.dealer = dealer
|
||||
if form.instance.taxable:
|
||||
form.instance.price = (form.instance.price * vat.rate) + form.instance.price
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class ItemServiceListView(ListView):
|
||||
class ItemServiceListView(ListView, LoginRequiredMixin):
|
||||
model = models.AdditionalServices
|
||||
template_name = "items/service/service_list.html"
|
||||
context_object_name = "services"
|
||||
@ -3465,7 +3493,7 @@ class ItemServiceListView(ListView):
|
||||
return models.AdditionalServices.objects.filter(dealer=dealer).all()
|
||||
|
||||
|
||||
class ItemExpenseCreateView(CreateView):
|
||||
class ItemExpenseCreateView(CreateView, LoginRequiredMixin):
|
||||
model = ItemModel
|
||||
form_class = ExpenseItemCreateForm
|
||||
template_name = "items/expenses/expense_create.html"
|
||||
@ -3484,7 +3512,7 @@ class ItemExpenseCreateView(CreateView):
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class ItemExpenseUpdateView(UpdateView):
|
||||
class ItemExpenseUpdateView(UpdateView, LoginRequiredMixin):
|
||||
model = ItemModel
|
||||
form_class = ExpenseItemUpdateForm
|
||||
template_name = "items/expenses/expense_update.html"
|
||||
@ -3503,7 +3531,7 @@ class ItemExpenseUpdateView(UpdateView):
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class ItemExpenseListView(ListView):
|
||||
class ItemExpenseListView(ListView, LoginRequiredMixin):
|
||||
model = ItemModel
|
||||
template_name = "items/expenses/expenses_list.html"
|
||||
context_object_name = "expenses"
|
||||
@ -3514,7 +3542,7 @@ class ItemExpenseListView(ListView):
|
||||
return dealer.entity.get_items_expenses()
|
||||
|
||||
|
||||
class BillListView(ListView):
|
||||
class BillListView(ListView, LoginRequiredMixin):
|
||||
model = BillModel
|
||||
template_name = "ledger/bills/bill_list.html"
|
||||
context_object_name = "bills"
|
||||
@ -3606,6 +3634,7 @@ class ApprovedBillModelView(LoginRequiredMixin, UpdateView):
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
@login_required
|
||||
def bill_mark_as_approved(request, pk):
|
||||
bill = get_object_or_404(BillModel, pk=pk)
|
||||
if request.method == "POST":
|
||||
@ -3619,6 +3648,7 @@ def bill_mark_as_approved(request, pk):
|
||||
return redirect("bill_detail", pk=bill.pk)
|
||||
|
||||
|
||||
@login_required
|
||||
def bill_mark_as_paid(request, pk):
|
||||
bill = get_object_or_404(BillModel, pk=pk)
|
||||
if request.method == "POST":
|
||||
@ -3668,6 +3698,7 @@ def bill_mark_as_paid(request, pk):
|
||||
# )
|
||||
# form.instance.ledger = ledger
|
||||
# return super().form_valid(form)
|
||||
|
||||
@login_required
|
||||
def bill_create(request):
|
||||
dealer = get_user_type(request)
|
||||
@ -3788,21 +3819,20 @@ def bill_create(request):
|
||||
return render(request, "ledger/bills/bill_form.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
def BillDeleteView(request, pk):
|
||||
bill = get_object_or_404(BillModel, pk=pk)
|
||||
bill.delete()
|
||||
return redirect("bill_list")
|
||||
|
||||
|
||||
class SubscriptionPlans(ListView):
|
||||
class SubscriptionPlans(ListView, LoginRequiredMixin):
|
||||
model = models.SubscriptionPlan
|
||||
template_name = "subscriptions/subscription_plan.html"
|
||||
context_object_name = "plans"
|
||||
|
||||
|
||||
# orders
|
||||
|
||||
|
||||
class OrderListView(ListView):
|
||||
model = models.SaleOrder
|
||||
template_name = "sales/orders/order_list.html"
|
||||
@ -3810,6 +3840,7 @@ class OrderListView(ListView):
|
||||
|
||||
|
||||
# email
|
||||
@login_required
|
||||
def send_email_view(request, pk):
|
||||
estimate = get_object_or_404(EstimateModel, pk=pk)
|
||||
if request.method == "POST":
|
||||
@ -3879,34 +3910,7 @@ def custom_bad_request_view(request, exception=None):
|
||||
return render(request, "errors/400.html", {})
|
||||
|
||||
|
||||
# from django_ledger.io.io_core import get_localdate
|
||||
# from django_ledger.views.mixins import (DjangoLedgerSecurityMixIn)
|
||||
# from django.views.generic import RedirectView
|
||||
from django_ledger.views.financial_statement import (
|
||||
FiscalYearBalanceSheetView,
|
||||
BaseIncomeStatementRedirectView,
|
||||
FiscalYearIncomeStatementView,
|
||||
BaseCashFlowStatementRedirectView,
|
||||
FiscalYearCashFlowStatementView,
|
||||
)
|
||||
from django_ledger.views.entity import EntityModelDetailBaseView,EntityModelDetailHandlerView
|
||||
from django.views.generic import DetailView, RedirectView
|
||||
|
||||
from django_ledger.io.io_core import get_localdate
|
||||
from django_ledger.models import EntityModel, EntityUnitModel
|
||||
from django_ledger.views.mixins import (
|
||||
QuarterlyReportMixIn,
|
||||
YearlyReportMixIn,
|
||||
MonthlyReportMixIn,
|
||||
DateReportMixIn,
|
||||
DjangoLedgerSecurityMixIn,
|
||||
EntityUnitMixIn,
|
||||
BaseDateNavigationUrlMixIn,
|
||||
PDFReportMixIn,
|
||||
)
|
||||
# BALANCE SHEET -----------
|
||||
|
||||
|
||||
# BALANCE SHEET
|
||||
class BaseBalanceSheetRedirectView(DjangoLedgerSecurityMixIn, RedirectView):
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
year = get_localdate().year
|
||||
@ -3916,23 +3920,23 @@ class BaseBalanceSheetRedirectView(DjangoLedgerSecurityMixIn, RedirectView):
|
||||
)
|
||||
|
||||
|
||||
class FiscalYearBalanceSheetViewBase(FiscalYearBalanceSheetView):
|
||||
class FiscalYearBalanceSheetViewBase(FiscalYearBalanceSheetView,DjangoLedgerSecurityMixIn):
|
||||
template_name = "ledger/reports/balance_sheet.html"
|
||||
|
||||
|
||||
class QuarterlyBalanceSheetView(FiscalYearBalanceSheetViewBase, QuarterlyReportMixIn):
|
||||
class QuarterlyBalanceSheetView(FiscalYearBalanceSheetViewBase, QuarterlyReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Quarter Balance Sheet View.
|
||||
"""
|
||||
|
||||
|
||||
class MonthlyBalanceSheetView(FiscalYearBalanceSheetViewBase, MonthlyReportMixIn):
|
||||
class MonthlyBalanceSheetView(FiscalYearBalanceSheetViewBase, MonthlyReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Monthly Balance Sheet View.
|
||||
"""
|
||||
|
||||
|
||||
class DateBalanceSheetView(FiscalYearBalanceSheetViewBase, DateReportMixIn):
|
||||
class DateBalanceSheetView(FiscalYearBalanceSheetViewBase, DateReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Date Balance Sheet View.
|
||||
"""
|
||||
@ -3941,7 +3945,7 @@ class DateBalanceSheetView(FiscalYearBalanceSheetViewBase, DateReportMixIn):
|
||||
# Income Statement -----------
|
||||
|
||||
|
||||
class BaseIncomeStatementRedirectViewBase(BaseIncomeStatementRedirectView):
|
||||
class BaseIncomeStatementRedirectViewBase(BaseIncomeStatementRedirectView, DjangoLedgerSecurityMixIn):
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
year = get_localdate().year
|
||||
dealer = get_user_type(self.request)
|
||||
@ -3950,25 +3954,25 @@ class BaseIncomeStatementRedirectViewBase(BaseIncomeStatementRedirectView):
|
||||
)
|
||||
|
||||
|
||||
class FiscalYearIncomeStatementViewBase(FiscalYearIncomeStatementView):
|
||||
class FiscalYearIncomeStatementViewBase(FiscalYearIncomeStatementView, DjangoLedgerSecurityMixIn):
|
||||
template_name = "ledger/reports/income_statement.html"
|
||||
|
||||
|
||||
class QuarterlyIncomeStatementView(
|
||||
FiscalYearIncomeStatementViewBase, QuarterlyReportMixIn
|
||||
FiscalYearIncomeStatementViewBase, QuarterlyReportMixIn, DjangoLedgerSecurityMixIn
|
||||
):
|
||||
"""
|
||||
Quarter Income Statement View.
|
||||
"""
|
||||
|
||||
|
||||
class MonthlyIncomeStatementView(FiscalYearIncomeStatementViewBase, MonthlyReportMixIn):
|
||||
class MonthlyIncomeStatementView(FiscalYearIncomeStatementViewBase, MonthlyReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Monthly Income Statement View.
|
||||
"""
|
||||
|
||||
|
||||
class DateModelIncomeStatementView(FiscalYearIncomeStatementViewBase, DateReportMixIn):
|
||||
class DateModelIncomeStatementView(FiscalYearIncomeStatementViewBase, DateReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Date Income Statement View.
|
||||
"""
|
||||
@ -3977,7 +3981,7 @@ class DateModelIncomeStatementView(FiscalYearIncomeStatementViewBase, DateReport
|
||||
# Cash Flow -----------
|
||||
|
||||
|
||||
class BaseCashFlowStatementRedirectViewBase(BaseCashFlowStatementRedirectView):
|
||||
class BaseCashFlowStatementRedirectViewBase(BaseCashFlowStatementRedirectView, DjangoLedgerSecurityMixIn):
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
year = get_localdate().year
|
||||
dealer = get_user_type(self.request)
|
||||
@ -3986,12 +3990,12 @@ class BaseCashFlowStatementRedirectViewBase(BaseCashFlowStatementRedirectView):
|
||||
)
|
||||
|
||||
|
||||
class FiscalYearCashFlowStatementViewBase(FiscalYearCashFlowStatementView):
|
||||
class FiscalYearCashFlowStatementViewBase(FiscalYearCashFlowStatementView, DjangoLedgerSecurityMixIn):
|
||||
template_name = "ledger/reports/cash_flow_statement.html"
|
||||
|
||||
|
||||
class QuarterlyCashFlowStatementView(
|
||||
FiscalYearCashFlowStatementViewBase, QuarterlyReportMixIn
|
||||
FiscalYearCashFlowStatementViewBase, QuarterlyReportMixIn, DjangoLedgerSecurityMixIn
|
||||
):
|
||||
"""
|
||||
Quarter Cash Flow Statement View.
|
||||
@ -3999,14 +4003,14 @@ class QuarterlyCashFlowStatementView(
|
||||
|
||||
|
||||
class MonthlyCashFlowStatementView(
|
||||
FiscalYearCashFlowStatementViewBase, MonthlyReportMixIn
|
||||
FiscalYearCashFlowStatementViewBase, MonthlyReportMixIn, DjangoLedgerSecurityMixIn
|
||||
):
|
||||
"""
|
||||
Monthly Cash Flow Statement View.
|
||||
"""
|
||||
|
||||
|
||||
class DateCashFlowStatementView(FiscalYearCashFlowStatementViewBase, DateReportMixIn):
|
||||
class DateCashFlowStatementView(FiscalYearCashFlowStatementViewBase, DateReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Date Cash Flow Statement View.
|
||||
"""
|
||||
@ -4014,7 +4018,7 @@ class DateCashFlowStatementView(FiscalYearCashFlowStatementViewBase, DateReportM
|
||||
|
||||
# Dashboard
|
||||
|
||||
class EntityModelDetailHandlerViewBase(EntityModelDetailHandlerView):
|
||||
class EntityModelDetailHandlerViewBase(EntityModelDetailHandlerView, DjangoLedgerSecurityMixIn):
|
||||
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
loc_date = get_localdate()
|
||||
@ -4036,7 +4040,7 @@ class EntityModelDetailHandlerViewBase(EntityModelDetailHandlerView):
|
||||
})
|
||||
|
||||
|
||||
class EntityModelDetailBaseViewBase(EntityModelDetailBaseView):
|
||||
class EntityModelDetailBaseViewBase(EntityModelDetailBaseView, DjangoLedgerSecurityMixIn):
|
||||
template_name = "ledger/reports/dashboard.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@ -4066,31 +4070,30 @@ class EntityModelDetailBaseViewBase(EntityModelDetailBaseView):
|
||||
return context
|
||||
|
||||
|
||||
class FiscalYearEntityModelDashboardView(EntityModelDetailBaseViewBase):
|
||||
class FiscalYearEntityModelDashboardView(EntityModelDetailBaseViewBase, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Entity Fiscal Year Dashboard View.
|
||||
"""
|
||||
|
||||
|
||||
class QuarterlyEntityDashboardView(FiscalYearEntityModelDashboardView, QuarterlyReportMixIn):
|
||||
class QuarterlyEntityDashboardView(FiscalYearEntityModelDashboardView, QuarterlyReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Entity Quarterly Dashboard View.
|
||||
"""
|
||||
|
||||
|
||||
class MonthlyEntityDashboardView(FiscalYearEntityModelDashboardView, MonthlyReportMixIn):
|
||||
class MonthlyEntityDashboardView(FiscalYearEntityModelDashboardView, MonthlyReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Monthly Entity Dashboard View.
|
||||
"""
|
||||
|
||||
|
||||
class DateEntityDashboardView(FiscalYearEntityModelDashboardView, DateReportMixIn):
|
||||
class DateEntityDashboardView(FiscalYearEntityModelDashboardView, DateReportMixIn, DjangoLedgerSecurityMixIn):
|
||||
"""
|
||||
Date-specific Entity Dashboard View.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
class PayableNetAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
|
||||
http_method_names = ['get']
|
||||
|
||||
@ -4120,6 +4123,7 @@ class PayableNetAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
|
||||
'message': 'Unauthorized'
|
||||
}, status=401)
|
||||
|
||||
|
||||
class ReceivableNetAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
|
||||
http_method_names = ['get']
|
||||
|
||||
@ -4150,6 +4154,7 @@ class ReceivableNetAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
|
||||
'message': 'Unauthorized'
|
||||
}, status=401)
|
||||
|
||||
|
||||
class PnLAPIView(DjangoLedgerSecurityMixIn, EntityUnitMixIn, View):
|
||||
http_method_names = ['get']
|
||||
|
||||
|
||||
@ -1,21 +1,24 @@
|
||||
{% load i18n custom_filters num2words_tags %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="ar" dir="rtl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>عرض سعر السيارة - Tenhall</title>
|
||||
<title>عرض سعر / Quotation</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
font-family: Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
background-color: #f9f9f9;
|
||||
background-color: #f8f9fa;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
.row {
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
margin: auto;
|
||||
background-color: #fff;
|
||||
padding: 30px;
|
||||
border: 1px solid #ddd;
|
||||
@ -25,21 +28,22 @@
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-bottom: 20px;
|
||||
font-size: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
p {
|
||||
margin: 10px 0;
|
||||
p, label {
|
||||
font-size: 14px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px; /* Space between elements */
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.row input {
|
||||
flex: 1; /* Input fields take remaining space */
|
||||
input[type="text"] {
|
||||
border: none;
|
||||
border-bottom: 1px solid #333;
|
||||
text-align: start;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
direction: rtl;
|
||||
background: transparent;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
@ -49,39 +53,24 @@
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
table-layout: fixed;
|
||||
}
|
||||
th, td {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
border: 1px solid #ddd;
|
||||
word-wrap: break-word;
|
||||
font-size: 14px;
|
||||
}
|
||||
th {
|
||||
background-color: #2c3e50;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.footer {
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #777;
|
||||
text-align: center;
|
||||
border-top: 1px solid #ddd;
|
||||
padding-top: 20px;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.header img {
|
||||
width: 100px;
|
||||
height: auto;
|
||||
}
|
||||
.signature-section {
|
||||
margin-top: 30px;
|
||||
padding: 15px;
|
||||
@ -97,137 +86,94 @@
|
||||
font-weight: bold;
|
||||
color: #2c3e50;
|
||||
}
|
||||
.gap {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
border-bottom: 1px solid #333;
|
||||
margin: 0 5px;
|
||||
}
|
||||
input[type="text"] {
|
||||
border: none;
|
||||
border-bottom: 1px solid #333;
|
||||
text-align: start; /* Align text to the start (left for RTL) */
|
||||
width: 100%;
|
||||
margin: 0 5px;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
direction: rtl; /* Ensure RTL direction for input */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="row">
|
||||
<div class="header">
|
||||
<h1>عرض سعر السيارة - Tenhal</h1>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h1>عرض سعر السيارة - Tenhal</h1>
|
||||
|
||||
<div class="row">
|
||||
<p>المكرمين/</p>
|
||||
<input type="text">
|
||||
</div>
|
||||
<p>المكرمين/</p>
|
||||
<input type="text">
|
||||
|
||||
<p>السلام عليكم و رحمة الله و بركاته،</p>
|
||||
<p>السلام عليكم ورحمة الله وبركاته،</p>
|
||||
|
||||
<p>بناء على طلبكم، نورد لكم عرض سعر للسيارة وهو يعد إيجابا منا بالبيع:</p>
|
||||
<p>بناءً على طلبكم، نورد لكم عرض سعر للسيارة وهو يعد إيجابًا منا بالبيع:</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th style="width: 30%;">نوع السيارة</th>
|
||||
<th style="width: 30%;">اللون الخارجي</th>
|
||||
<th style="width: 30%;">اللون الداخلي</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>نوع السيارة</th>
|
||||
<th>اللون الخارجي</th>
|
||||
<th>اللون الداخلي</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for car in cars %}
|
||||
<td><input type="text" style="text-align: center" value="{{ car.vin }}" disabled></td>
|
||||
<td><input type="text" style="background-color: rgb({{ car.colors.first.interior.rgb }})" disabled></td>
|
||||
<td><input type="text" style="background-color: rgb({{ car.colors.first.exterior.rgb }})" disabled></td>
|
||||
<tr>
|
||||
<td>{{ car.year }} - {{ car.id_car_make.arabic_name }} - {{ car.id_car_model.arabic_name }} - {{ car.id_car_trim.arabic_name }}</td>
|
||||
<td>{{ car.colors.first.exterior.arabic_name }}</td>
|
||||
<td>{{ car.colors.first.interior.arabic_name }}</td>
|
||||
<td>{{ car.finances.first.cost_price }}</td>
|
||||
<td>{{ car. }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="row">
|
||||
<p>حمولة المركبة (</p>
|
||||
<input type="text">
|
||||
<p>) سنة الصنع (</p>
|
||||
<input type="text">
|
||||
<p>) (جديد / مستعملة) كلم/ميل</p>
|
||||
</div>
|
||||
<p>حمولة المركبة (<input type="text">) سنة الصنع (<input type="text">) (جديد / مستعملة) كلم/ميل</p>
|
||||
|
||||
<div class="row">
|
||||
<p>مستوى اقتصاد الوقود (</p>
|
||||
<input type="text">
|
||||
<p>) رقم الشاسيه "في حال كانت السيارة مستعملة فقط" (</p>
|
||||
<input type="text">
|
||||
<p>)</p>
|
||||
</div>
|
||||
<p>مستوى اقتصاد الوقود (<input type="text">) رقم الشاسيه (في حال كانت السيارة مستعملة فقط) (<input type="text">)</p>
|
||||
|
||||
<div class="row">
|
||||
<p>مواصفات أخرى:</p>
|
||||
<input type="text">
|
||||
</div>
|
||||
<p>مواصفات أخرى:</p>
|
||||
<input type="text">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>سعر السيارة الأساسي</th>
|
||||
<th>مبلغ ضريبة القيمة المضافة (15% VAT)</th>
|
||||
<th>إجمالي سعر السيارة مع الضريبة</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th style="width: 30%;">سعر السيارة الأساسي</th>
|
||||
<th style="width: 30%;">مبلغ ضريبة القيمة المضافة (15% VAT)</th>
|
||||
<th style="width: 30%;">إجمالي سعر السيارة مع الضريبة</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="text"></td>
|
||||
<td><input type="text"></td>
|
||||
<td><input type="text"></td>
|
||||
<td colspan="3">{{ cars }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ estimate.get_cost_estimate }}</td>
|
||||
<td></td>
|
||||
<td>{{ estimate.get_invoiced_amount.invoice_amount_paid__sum }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>إجمالي سعر السيارة مع الضريبة كتابة: <span class="highlight">ريالا سعوديا فقط لا غير</span></p>
|
||||
<p>الإجمالي مع الضريبة كتابةً: <span class="highlight">{{ estimate.get_invoiced_amount.invoice_amount_paid__sum|num_to_words }} {{ CURRENCY }} فقط لا غير</span></p>
|
||||
|
||||
<div class="row">
|
||||
<p>مدة الضمان:</p>
|
||||
<input type="text">
|
||||
<p>شهرا، أو</p>
|
||||
<input type="text">
|
||||
<p>كيلومترا /ميل (أيهما يأتي أولا)</p>
|
||||
</div>
|
||||
<p>مدة الضمان: <input type="text"> شهراً، أو <input type="text"> كيلومتراً / ميلاً (أيهما يأتي أولاً)</p>
|
||||
|
||||
<div class="row">
|
||||
<p>ملاحظات:</p>
|
||||
<input type="text">
|
||||
</div>
|
||||
<p>ملاحظات:</p>
|
||||
<input type="text">
|
||||
|
||||
<div class="row">
|
||||
<p>اسم الشركة/ الوكالة:</p>
|
||||
<input type="text">
|
||||
</div>
|
||||
<p>اسم الشركة / الوكالة:</p>
|
||||
<input type="text">
|
||||
|
||||
<div class="row">
|
||||
<p>العنوان: المدينة شارع</p>
|
||||
<input type="text">
|
||||
</div>
|
||||
<p>العنوان: المدينة - شارع:</p>
|
||||
<input type="text">
|
||||
|
||||
<div class="row">
|
||||
<p>ص.ب رمز بريدي الهاتف:</p>
|
||||
<input type="text">
|
||||
</div>
|
||||
<p>ص.ب / رمز بريدي / الهاتف:</p>
|
||||
<input type="text">
|
||||
|
||||
<div class="signature-section">
|
||||
<div class="row">
|
||||
<p>الموظف المسؤول التوقيع:</p>
|
||||
<span class="gap"></span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p>التاريخ:</p>
|
||||
<input type="text" style="width: 50px;">
|
||||
<p>/</p>
|
||||
<input type="text" style="width: 50px;">
|
||||
<p>/</p>
|
||||
<input type="text" style="width: 50px;">
|
||||
<p>م الختم</p>
|
||||
</div>
|
||||
<p>الموظف المسؤول:</p>
|
||||
<input type="text" style="width: 60%; display: inline-block; border-bottom: 1px solid #333;">
|
||||
<p>التوقيع:</p>
|
||||
<input type="text" style="width: 60%; display: inline-block; border-bottom: 1px solid #333;">
|
||||
<p>التاريخ: <input type="text" style="width: 50px;"> / <input type="text" style="width: 50px;"> / <input type="text" style="width: 50px;"></p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<!-- Footer content here -->
|
||||
<p>Powered by <a href="https://tenhal.sa">Tenhal | تنحل</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
<div class="spinner-border mx-3 htmx-indicator" role="status"><span class="visually-hidden">Loading...</span></div>
|
||||
<div class="search-box me-3">
|
||||
<form class="position-relative">
|
||||
<input class="form-control search-input search" name='search' type="search" placeholder="Search" aria-label="Search" hx-get="{% url 'car_list' %}" hx-trigger='keyup changed delay:500ms' hx-target='.table-responsive' hx-select='.table-responsive' hx-swap="innerHTML show:window:top" hx-indicator=".htmx-indicator"
|
||||
<input class="form-control search-input search" name='search' type="search" placeholder="{{ _("Search") }}" aria-label="Search" hx-get="{% url 'car_list' %}" hx-trigger='keyup changed delay:500ms' hx-target='.table-responsive' hx-select='.table-responsive' hx-swap="innerHTML show:window:top" hx-indicator=".htmx-indicator"
|
||||
hx-on::before-request="on_before_request()"
|
||||
hx-on::after-request="on_after_request()"
|
||||
/>
|
||||
@ -129,17 +129,18 @@
|
||||
<table class="table fs-9 mb-0 border-top border-translucent">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort white-space-nowrap align-middle ps-0" scope="col" data-sort="projectName" style="width:10%;">Customer Name</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="assignees" style="width:5%;">Customer Address</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="start" style="width:5%;">Customer Phone</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="deadline" style="width:5%;">Make</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:5%;">Model</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:5%;">VIN</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:5%;">Trim</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:5%;">Selling Price</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:7%;">Estimate</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:7%;">Invoice</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:7%;">Sales Staff</th>
|
||||
<th class="sort white-space-nowrap align-middle ps-0" scope="col" data-sort="projectName" style="width:10%;">
|
||||
{{ _("Customer Name")}}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="assignees" style="width:5%;">{{ _("Customer Address")}}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="start" style="width:5%;">{{ _("Customer Phone")}}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="deadline" style="width:5%;">{{ _("Make") }}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:5%;">{{ _("Model") }}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:5%;">{{ _("VIN") }}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:5%;">{{ _("Trim") }}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:5%;">{{ _("Price") }}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:7%;">{{ _("Quotation") }}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:7%;">{{ _("Invoice") }}</th>
|
||||
<th class="sort align-middle ps-3" scope="col" data-sort="task" style="width:7%;">{{ _("Staff Member") }}</th>
|
||||
<th class="sort align-middle text-end" scope="col" style="width:10%;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -205,7 +206,7 @@
|
||||
{% elif tx.invoice.is_canceled %}
|
||||
<span class="badge badge-phoenix badge-phoenix-danger">{{tx.invoice.invoice_status}}</span>
|
||||
{% elif tx.invoice.is_past_due %}
|
||||
<span class="badge badge-phoenix badge-phoenix-danger">Past Due</span>
|
||||
<span class="badge badge-phoenix badge-phoenix-danger">{{ _("Past Due")}}</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
@ -225,8 +226,8 @@
|
||||
<td class="align-middle text-end white-space-nowrap pe-0 action">
|
||||
<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="#!">View</a><a class="dropdown-item" href="#!">Export</a>
|
||||
<div class="dropdown-divider"></div><a class="dropdown-item text-danger" href="#!">Remove</a>
|
||||
<div class="dropdown-menu dropdown-menu-end py-2"><a class="dropdown-item" href="">{{ _("View") }}</a><a class="dropdown-item" href="">{{ _("Export") }}</a>
|
||||
<div class="dropdown-divider"></div><a class="dropdown-item text-danger" href="">{{ _("Remove") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
@ -237,19 +238,9 @@
|
||||
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent">
|
||||
<div class="d-flex">
|
||||
|
||||
</div>
|
||||
<div class="d-flex" hx-boost="true" hx-push-url='false' hx-include=".make,.model,.year,.car_status" hx-target=".table-responsive" hx-select=".table-responsive" hx-swap="innerHTML" hx-indicator=".htmx-indicator"
|
||||
hx-on::before-request="on_before_request()"
|
||||
hx-on::after-request="on_after_request()">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="{% url 'car_list' %}?page={{page_obj.previous_page_number}}" class="page-link" data-list-pagination="prev"><span class="fas fa-chevron-left"></span></a>
|
||||
{% endif %}
|
||||
<ul class="mb-0 pagination">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</ul>
|
||||
{% if page_obj.has_next %}
|
||||
<a href="{% url 'car_list' %}?page={{page_obj.next_page_number}}" class="page-link pe-0" data-list-pagination="next"><span class="fas fa-chevron-right"></span></a>
|
||||
{% endif %}
|
||||
{% include 'partials/pagination.html' %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user