diff --git a/inventory/__pycache__/apps.cpython-311.pyc b/inventory/__pycache__/apps.cpython-311.pyc index 4fe06dca..352d3144 100644 Binary files a/inventory/__pycache__/apps.cpython-311.pyc and b/inventory/__pycache__/apps.cpython-311.pyc differ diff --git a/inventory/__pycache__/forms.cpython-311.pyc b/inventory/__pycache__/forms.cpython-311.pyc index 5c27f5ba..43d16c6c 100644 Binary files a/inventory/__pycache__/forms.cpython-311.pyc and b/inventory/__pycache__/forms.cpython-311.pyc differ diff --git a/inventory/__pycache__/urls.cpython-311.pyc b/inventory/__pycache__/urls.cpython-311.pyc index 2af2899c..fdd0861b 100644 Binary files a/inventory/__pycache__/urls.cpython-311.pyc and b/inventory/__pycache__/urls.cpython-311.pyc differ diff --git a/inventory/__pycache__/views.cpython-311.pyc b/inventory/__pycache__/views.cpython-311.pyc index b7129e6d..20176a12 100644 Binary files a/inventory/__pycache__/views.cpython-311.pyc and b/inventory/__pycache__/views.cpython-311.pyc differ diff --git a/inventory/apps.py b/inventory/apps.py index 9a82aef1..849693ce 100644 --- a/inventory/apps.py +++ b/inventory/apps.py @@ -5,8 +5,7 @@ class InventoryConfig(AppConfig): name = 'inventory' def ready(self): - import inventory.signals - # from decimal import Decimal - # from inventory.models import VatRate - # VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True) - + import inventory.signals + from decimal import Decimal + from inventory.models import VatRate + VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True) diff --git a/inventory/forms.py b/inventory/forms.py index befa4506..6cd912b5 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -21,7 +21,9 @@ from django_ledger.forms.estimate import ( EstimateModelCreateForm as EstimateModelCreateFormBase, ) +# from django_ledger.forms.ledger import LedgerModelCreateForm as LedgerModelCreateFormBase from django_ledger.forms.bill import BillModelCreateForm as BillModelCreateFormBase +from django_ledger.forms.journal_entry import JournalEntryModelCreateForm as JournalEntryModelCreateFormBase from .models import ( Dealer, @@ -953,3 +955,10 @@ class DealersMakeForm(forms.Form): for car_make in self.cleaned_data["car_makes"]: DealersMake.objects.create(dealer=self.dealer, car_make=car_make) + + +class JournalEntryModelCreateForm(JournalEntryModelCreateFormBase): + pass + +# class LedgerModelCreateForm(LedgerModelCreateFormBase): +# pass \ No newline at end of file diff --git a/inventory/signals.py b/inventory/signals.py index 76094df6..64758555 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -82,11 +82,6 @@ def create_car_location(sender, instance, created, **kwargs): except Exception as e: print(f"Failed to create CarLocation for car {instance.vin}: {e}") -@receiver(post_save, sender=models.Dealer) -def create_dealer_settings(sender, instance, created, **kwargs): - if created: - models.DealerSettings.objects.create(dealer=instance) - # Create Entity @receiver(post_save, sender=models.Dealer) def create_ledger_entity(sender, instance, created, **kwargs): @@ -624,8 +619,7 @@ def create_ledger_entity(sender, instance, created, **kwargs): entity.create_account(coa_model=coa, code="6302", role=roles.EXPENSE_OTHER, name=_("Taxes"), balance_type="debit", active=True) entity.create_account(coa_model=coa, code="6303", role=roles.EXPENSE_OTHER, name=_("Foreign Currency Translation"), balance_type="debit", active=True) entity.create_account(coa_model=coa, code="6304", role=roles.EXPENSE_OTHER, name=_("Interest Expenses"), balance_type="debit", active=True) - - + @receiver(post_save, sender=models.Dealer) def create_dealer_groups(sender, instance, created, **kwargs): @@ -872,6 +866,24 @@ def update_car_status_on_reservation_update(sender, instance, **kwargs): car.status = models.CarStatusChoices.AVAILABLE car.save() +@receiver(post_save, sender=models.Dealer) +def create_dealer_settings(sender, instance, created, **kwargs): + if created: + models.DealerSettings.objects.create( + dealer=instance, + invoice_cash_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH).first(), + invoice_prepaid_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES).first(), + invoice_unearned_account=instance.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_DEFERRED_REVENUE).first(), + bill_cash_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH).first(), + bill_prepaid_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID).first(), + bill_unearned_account=instance.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE).first() + ) + +@receiver(post_save, sender=models.Dealer) +def check_if_vat_exists(sender, instance, created, **kwargs): + if created: + models.VatRate.objects.get_create(is_active=True) + # @receiver(post_save, sender=EstimateModel) # def update_estimate_status(sender, instance,created, **kwargs): diff --git a/inventory/templatetags/tenhal_tag.py b/inventory/templatetags/tenhal_tag.py index c410ef04..14e45fa2 100644 --- a/inventory/templatetags/tenhal_tag.py +++ b/inventory/templatetags/tenhal_tag.py @@ -13,6 +13,7 @@ from django import template from django.db.models import Sum from django.urls import reverse from django.utils.formats import number_format +from decimal import Decimal # from django_ledger import __version__ # from django_ledger.forms.app_filters import EntityFilterForm, ActivityFilterForm @@ -27,7 +28,9 @@ from django_ledger.io.io_core import validate_activity, get_localdate register = template.Library() - +@register.filter() +def to_int(value): + return Decimal(value).quantize(Decimal("0.01")) # @register.simple_tag(name='current_version') # def current_version(): # return __version__ diff --git a/inventory/urls.py b/inventory/urls.py index c73cc237..21765357 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -407,6 +407,33 @@ urlpatterns = [ name="representative_delete", ), # Ledger URLS + # Ledger + path( + "ledgers/", views.LedgerModelListView.as_view(), name="ledger_list" + ), + path( + "ledgers//detail//", views.LedgerModelDetailView.as_view(), name="ledger_detail" + ), + # path( + # "ledgers/create/", views.LedgerModelCreateView.as_view(), name="ledger_create" + # ), + path( + "journalentries//list/", views.JournalEntryListView.as_view(), name="journalentry_list" + ), + path( + "journalentries//create/", views.JournalEntryCreateView.as_view(), name="journalentry_create" + ), + path( + "journalentries//delete/", views.JournalEntryDeleteView, name="journalentry_delete" + ), + path( + "journalentries//transactions/", + views.JournalEntryTransactionsView, + name="journalentry_transactions", + ), + path('journalentries///detail//txs/', + views.JournalEntryModelTXSDetailView.as_view(), + name='journalentry_txs'), # Bank Account path( "bank_accounts/", views.BankAccountListView.as_view(), name="bank_account_list" @@ -597,6 +624,7 @@ urlpatterns = [ name="bill_mark_as_paid", ), + # orders path("orders/", views.OrderListView.as_view(), name="order_list_view"), diff --git a/inventory/views.py b/inventory/views.py index 23f4af1c..4f02f134 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -48,12 +48,15 @@ from django.views.generic import ( UpdateView, DeleteView, TemplateView, + ArchiveIndexView, ) ##################################################################### # Django Ledger from django_ledger.io import roles from django_ledger.utils import accruable_net_summary +from django_ledger.views.invoice import InvoiceModelDetailView as InvoiceModelDetailViewBase +from django_ledger.views import LedgerModelListView as LedgerModelListViewBase,JournalEntryModelTXSDetailView as JournalEntryModelTXSDetailViewBase from django_ledger.forms.account import AccountModelCreateForm, AccountModelUpdateForm from django_ledger.views.entity import EntityModelDetailBaseView,EntityModelDetailHandlerView from django_ledger.forms.item import ( @@ -85,6 +88,7 @@ from django_ledger.models import ( CustomerModel, ItemModel, BillModel, + LedgerModel, VendorModel, ) from django_ledger.views.financial_statement import ( @@ -214,7 +218,7 @@ def dealer_signup(request, *args, **kwargs): user.groups.add(group) for perm in Permission.objects.filter(content_type__app_label__in=["inventory","django_ledger"]): group.permissions.add(perm) - + StaffMember.objects.create(user=user) models.Dealer.objects.create( user=user, @@ -2569,6 +2573,8 @@ def invoice_create(request, pk): invoice.save() messages.success(request, "Invoice created successfully!") return redirect("invoice_detail", pk=invoice.pk) + else: + print(form.errors) form = forms.InvoiceModelCreateForm( entity_slug=entity.slug, user_model=entity.admin ) @@ -3993,7 +3999,7 @@ class CarListViewTable(LoginRequiredMixin, ExportMixin, SingleTableView): @login_required def DealerSettingsView(request,pk): - dealer_setting = get_object_or_404(models.DealerSettings, pk=pk) + dealer_setting = get_object_or_404(models.DealerSettings, dealer__pk=pk) dealer = get_user_type(request) if request.method == 'POST': form = forms.DealerSettingsForm(request.POST, instance=dealer_setting) @@ -4038,4 +4044,122 @@ def assign_car_makes(request): existing_car_makes = models.DealersMake.objects.filter(dealer=dealer).values_list("car_make", flat=True) form = forms.DealersMakeForm(initial={"car_makes": existing_car_makes}, dealer=dealer) - return render(request, "dealers/assign_car_makes.html", {"form": form}) \ No newline at end of file + return render(request, "dealers/assign_car_makes.html", {"form": form}) + + +class LedgerModelListView(LoginRequiredMixin, ListView,ArchiveIndexView): + model = LedgerModel + context_object_name = "ledgers" + template_name = "ledger/ledger/ledger_list.html" + date_field = 'created' + ordering = '-created' + show_all = False + show_current = False + show_visible = False + + + def get_queryset(self): + qs = super().get_queryset() + dealer = get_user_type(self.request) + qs = qs.filter(entity=dealer.entity) + qs = qs.select_related('billmodel', 'invoicemodel') + qs = qs.order_by('-created') + if self.show_all: + return qs + if self.show_current: + qs = qs.current() + if self.show_visible: + qs = qs.visible() + return qs + +class LedgerModelDetailView(InvoiceModelDetailViewBase): + model = LedgerModel + context_object_name = "ledger" + template_name = "ledger/ledger/ledger_detail.html" + +# class LedgerModelCreateView(LoginRequiredMixin,SuccessMessageMixin, CreateView): +# model = LedgerModel +# template_name = "ledger/ledger/ledger_form.html" +# form_class = forms.LedgerModelCreateForm +# success_message = "Ledger created" + +# def get_form(self, form_class=None): +# dealer = get_user_type(self.request) +# form = forms.LedgerModelCreateForm(entity_slug=dealer.entity.slug,user_model=dealer.entity.admin,**self.get_form_kwargs()) +# return form +# def get_success_url(self): +# return reverse('ledger_list') + +# def form_valid(self, form): +# instance = form.save(commit=False) +# dealer = get_user_type(self.request) +# instance.entity = dealer.entity +# instance.save() +# return super().form_valid(form) + +class JournalEntryListView(LoginRequiredMixin, ListView): + model = JournalEntryModel + context_object_name = "journal_entries" + template_name = "ledger/journal_entry/journal_entry_list.html" + + def get_queryset(self): + qs = super().get_queryset() + ledger = LedgerModel.objects.filter(pk=self.kwargs['pk']).first() + qs = qs.filter(ledger=ledger) + return qs + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['ledger'] = LedgerModel.objects.filter(pk=self.kwargs['pk']).first() + return context + +class JournalEntryCreateView(LoginRequiredMixin,SuccessMessageMixin, CreateView): + model = JournalEntryModel + template_name = "ledger/journal_entry/journal_entry_form.html" + form_class = forms.JournalEntryModelCreateForm + ledger_model = None + success_message = "Journal Entry created" + + def get_form(self, form_class=None): + dealer = get_user_type(self.request) + ledger = LedgerModel.objects.filter(pk=self.kwargs['pk']).first() + form = forms.JournalEntryModelCreateForm( + entity_model=dealer.entity, + ledger_model=ledger, + **self.get_form_kwargs() + ) + form.fields.pop('entity_unit') + return form + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["ledger"] = LedgerModel.objects.filter(pk=self.kwargs['pk']).first() + return context + + def get_success_url(self): + ledger = LedgerModel.objects.filter(pk=self.kwargs['pk']).first() + return reverse("journalentry_list", kwargs={"pk": ledger.pk}) + + +def JournalEntryDeleteView(request,pk): + journal_entry = get_object_or_404(JournalEntryModel, pk=pk) + ledger = journal_entry.ledger + journal_entry.delete() + messages.success(request, 'Journal Entry deleted') + return redirect("journalentry_list", pk=ledger.pk) + +def JournalEntryTransactionsView(request, pk): + journal = JournalEntryModel.objects.filter(pk=pk).first() + transactions = ( + TransactionModel.objects.filter(journal_entry=journal) + .order_by("account__code") + .all() + ) + return render( + request, + "ledger/journal_entry/journal_entry_transactions.html", + {"journal_entry": journal, "transactions": transactions}, + ) + + +class JournalEntryModelTXSDetailView(JournalEntryModelTXSDetailViewBase): + template_name = 'ledger/journal_entry/journal_entry_txs.html' \ No newline at end of file diff --git a/templates/header.html b/templates/header.html index 2c65bcbd..05cd65b0 100644 --- a/templates/header.html +++ b/templates/header.html @@ -249,6 +249,14 @@ {% endif %} {% if perms.django_ledger.view_itemmodel %} + + {% endif %} - {% endif %} {% if perms.django_ledger.view_itemmodel %}