update in the bill and po

This commit is contained in:
ismail 2025-06-12 16:42:53 +03:00
parent 2a397c3a2b
commit 6aa2ed130c
21 changed files with 1543 additions and 403 deletions

View File

@ -1325,9 +1325,9 @@ class BillModelCreateForm(BillModelCreateFormBase):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["cash_account"].widget = forms.HiddenInput()
self.fields["prepaid_account"].widget = forms.HiddenInput()
self.fields["unearned_account"].widget = forms.HiddenInput()
# self.fields["cash_account"].widget = forms.HiddenInput()
# self.fields["prepaid_account"].widget = forms.HiddenInput()
# self.fields["unearned_account"].widget = forms.HiddenInput()
class SaleOrderForm(forms.ModelForm):

View File

@ -380,3 +380,13 @@ def po_item_formset_table(context, po_model, itemtxs_formset):
'po_model': po_model,
'itemtxs_formset': itemtxs_formset,
}
@register.inclusion_tag('bill/tags/bill_item_formset.html', takes_context=True)
def bill_item_formset_table(context, item_formset):
return {
'entity_slug': context['view'].kwargs['entity_slug'],
'bill_pk': context['view'].kwargs['bill_pk'],
'total_amount__sum': context['total_amount__sum'],
'item_formset': item_formset,
}

View File

@ -693,7 +693,53 @@ path(
),
# Bills
path("items/bills/", views.BillListView.as_view(), name="bill_list"),
path("items/bills/create/", views.BillModelCreateViewView.as_view(), name="bill_create"),
# path("items/bills/create/", views.BillModelCreateViewView.as_view(), name="bill_create"),
path('items/bills/<slug:entity_slug>/create/',
views.BillModelCreateViewView.as_view(),
name='bill-create'),
path('items/bills/<slug:entity_slug>/create/purchase-order/<uuid:po_pk>/',
views.BillModelCreateViewView.as_view(for_purchase_order=True),
name='bill-create-po'),
path('items/bills/<slug:entity_slug>/create/estimate/<uuid:ce_pk>/',
views.BillModelCreateViewView.as_view(for_estimate=True),
name='bill-create-estimate'),
path('items/bills/<slug:entity_slug>/detail/<uuid:bill_pk>/',
views.BillModelDetailViewView.as_view(),
name='bill-detail'),
path('items/bills/<slug:entity_slug>/update/<uuid:bill_pk>/',
views.BillModelUpdateViewView.as_view(),
name='bill-update'),
path('items/bills/<slug:entity_slug>/update/<uuid:bill_pk>/items/',
views.BillModelUpdateViewView.as_view(action_update_items=True),
name='bill-update-items'),
############################################################
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-draft/',
views.BillModelActionMarkAsDraftView.as_view(),
name='bill-action-mark-as-draft'),
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-review/',
views.BillModelActionMarkAsInReviewView.as_view(),
name='bill-action-mark-as-review'),
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-approved/',
views.BillModelActionMarkAsApprovedView.as_view(),
name='bill-action-mark-as-approved'),
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-paid/',
views.BillModelActionMarkAsPaidView.as_view(),
name='bill-action-mark-as-paid'),
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-void/',
views.BillModelActionVoidView.as_view(),
name='bill-action-mark-as-void'),
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/mark-as-canceled/',
views.BillModelActionCanceledView.as_view(),
name='bill-action-mark-as-canceled'),
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/lock-ledger/',
views.BillModelActionLockLedgerView.as_view(),
name='bill-action-lock-ledger'),
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/unlock-ledger/',
views.BillModelActionUnlockLedgerView.as_view(),
name='bill-action-unlock-ledger'),
path('items/bills/<slug:entity_slug>/actions/<uuid:bill_pk>/force-migration/',
views.BillModelActionForceMigrateView.as_view(),
name='bill-action-force-migrate'),
# path("items/bills/create/", views.bill_create, name="bill_create"),
path(
"items/bills/<uuid:pk>/bill_detail/",
@ -818,8 +864,8 @@ path(
path('purchase_orders/<slug:entity_slug>/update/<uuid:po_pk>/update-items/',
views.PurchaseOrderUpdateView.as_view(action_update_items=True),
name='purchase_order_update_items'),
path('purchase_orders/inventory_item/<uuid:pk>/create/', views.InventoryItemCreateView, name='inventory_item_create'),
path('purchase_orders/<uuid:po_pk>/inventory_items_filter/', views.inventory_items_filter, name='inventory_items_filter'),
path('purchase_orders/inventory_item/create/', views.InventoryItemCreateView, name='inventory_item_create'),
path('purchase_orders/inventory_items_filter/', views.inventory_items_filter, name='inventory_items_filter'),
path('purchase_orders/<slug:entity_slug>/delete/<uuid:po_pk>/',
views.PurchaseOrderModelDeleteView.as_view(),
name='po-delete'),

View File

@ -26,7 +26,7 @@ from django.db.models import Q
from django.conf import settings
from django.db.models import Func
from django.contrib import messages
from django.http import Http404, HttpResponseRedirect, JsonResponse, HttpResponseForbidden
from django.http import Http404, HttpResponseNotFound, HttpResponseRedirect, JsonResponse, HttpResponseForbidden
from django.forms import HiddenInput, ValidationError
from django.shortcuts import HttpResponse
@ -84,12 +84,16 @@ from django_ledger.forms.bank_account import (
BankAccountUpdateForm,
)
from django_ledger.views.bill import (
BillModelCreateView
# BillModelUpdateView as BillModelUpdateViewBase
BillModelCreateView,
BillModelDetailView,
BillModelUpdateView,
BaseBillActionView as BaseBillActionViewBase,
)
from django_ledger.forms.bill import (
ApprovedBillModelUpdateForm,
InReviewBillModelUpdateForm,
get_bill_itemtxs_formset_class,
)
from django_ledger.forms.invoice import (
DraftInvoiceModelUpdateForm,
@ -6067,6 +6071,10 @@ class BillListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
qs = dealer.entity.get_bills()
return qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["entity"] = get_user_type(self.request).entity
return context
class BillDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
"""
@ -6282,139 +6290,216 @@ def bill_mark_as_paid(request, pk):
@login_required
@permission_required("django_ledger.add_billmodel", raise_exception=True)
def bill_create(request):
"""
Handles creation of a bill in the system, including the validation of input data,
creation of transactions associated with the bill, and rendering of the appropriate
response or form. Ensures the user creating the bill has the necessary permissions and
correct input parameters for successful bill creation and itemization.
class BillModelCreateViewView(BillModelCreateView):
template_name = 'bill/bill_create.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["entity"] = get_user_type(self.request).entity
return context
class BillModelDetailViewView(BillModelDetailView):
template_name = 'bill/bill_detail.html'
class BillModelUpdateViewView(BillModelUpdateView):
template_name = 'bill/bill_update.html'
def post(self, request, *args, **kwargs):
if self.action_update_items:
:param request: Django HttpRequest object containing metadata and data of the HTTP request.
:type request: HttpRequest
:return: JsonResponse with success/error information if the request is processed,
or HttpResponse rendering the form for bill creation.
:rtype: JsonResponse or HttpResponse
"""
dealer = get_user_type(request)
entity = dealer.entity
if not request.user.is_authenticated:
return HttpResponseForbidden()
if request.method == "POST":
data = json.loads(request.body)
vendor_id = data.get("vendor")
terms = data.get("terms")
vendor = entity.get_vendors().filter(pk=vendor_id).first()
queryset = self.get_queryset()
entity_model: EntityModel = self.get_authorized_entity_instance()
bill_model: BillModel = self.get_object(queryset=queryset)
bill_pk = bill_model.uuid
items = data.get("item", [])
quantities = data.get("quantity", [])
self.object = bill_model
if not all([items, quantities]):
return JsonResponse(
{"status": "error", "message": _("Items and Quantities are required")},
status=400,
bill_itemtxs_formset_class = get_bill_itemtxs_formset_class(bill_model)
itemtxs_formset = bill_itemtxs_formset_class(
request.POST,
bill_model=bill_model,
entity_model=entity_model
)
if isinstance(quantities, list):
if "0" in quantities:
return JsonResponse(
{
"status": "error",
"message": _("Quantity must be greater than zero"),
}
)
else:
if int(quantities) <= 0:
return JsonResponse(
{
"status": "error",
"message": _("Quantity must be greater than zero"),
}
)
bill = entity.create_bill(vendor_model=vendor, terms=terms)
if isinstance(items, list):
item_quantity_map = {}
for item, quantity in zip(items, quantities):
if item in item_quantity_map:
item_quantity_map[item] += int(quantity)
else:
item_quantity_map[item] = int(quantity)
item_list = list(item_quantity_map.keys())
quantity_list = list(item_quantity_map.values())
if itemtxs_formset.has_changed():
if itemtxs_formset.is_valid():
itemtxs_list = itemtxs_formset.save(commit=False)
items_list = [
{"item_id": item_list[i], "quantity": quantity_list[i]}
for i in range(len(item_list))
]
items_txs = []
for item in items_list:
item_instance = ItemModel.objects.get(pk=item.get("item_id"))
car = models.Car.objects.get(vin=item_instance.name)
quantity = Decimal(item.get("quantity"))
items_txs.append(
{
"item_number": item_instance.item_number,
"quantity": quantity,
"unit_cost": car.finances.cost_price,
"total_amount": car.finances.cost_price * quantity,
}
)
for itemtxs in itemtxs_list:
itemtxs.bill_model_id = bill_model.uuid
itemtxs.clean()
bill_itemtxs = {
item.get("item_number"): {
"unit_cost": item.get("unit_cost"),
"quantity": item.get("quantity"),
"total_amount": item.get("total_amount"),
}
for item in items_txs
}
else:
item = entity.get_items_all().filter(pk=items).first()
instance = models.Car.objects.get(vin=item.name)
bill_itemtxs = {
item.item_number: {
"unit_cost": instance.finances.cost_price,
"quantity": Decimal(quantities),
"total_amount": instance.finances.cost_price * Decimal(quantities),
}
}
itemtxs_formset.save()
itemtxs_qs = bill_model.update_amount_due()
bill_model.get_state(commit=True)
bill_model.clean()
bill_model.save(
update_fields=[
'amount_due',
'amount_receivable',
'amount_unearned',
'amount_earned',
'updated'
])
bill_itemtxs = bill.migrate_itemtxs(
itemtxs=bill_itemtxs,
commit=True,
operation=BillModel.ITEMIZE_APPEND,
)
bill_model.migrate_state(
entity_slug=self.kwargs['entity_slug'],
user_model=self.request.user,
itemtxs_qs=itemtxs_qs,
raise_exception=False
)
url = reverse("bill_detail", kwargs={"pk": bill.pk})
return JsonResponse(
{
"status": "success",
"message": _("Bill created successfully"),
"url": f"{url}",
}
)
messages.add_message(request,
message=f'Items for Invoice {bill_model.bill_number} saved.',
level=messages.SUCCESS,)
form = forms.BillModelCreateForm(entity_model=entity)
form.initial.update(
{
"cash_account": dealer.settings.bill_cash_account,
"prepaid_account": dealer.settings.bill_prepaid_account,
"unearned_account": dealer.settings.bill_unearned_account,
}
)
car_list = models.Car.objects.filter(dealer=dealer)
context = {
"form": form,
"items": [
{
"car": x,
"product": entity.get_items_products().filter(name=x.vin).first(),
}
for x in car_list
],
}
# if valid get saved formset from DB
return HttpResponseRedirect(
redirect_to=reverse('bill-update',
kwargs={
'entity_slug': entity_model.slug,
'bill_pk': bill_pk
})
)
context = self.get_context_data(itemtxs_formset=itemtxs_formset)
return self.render_to_response(context=context)
return super(BillModelUpdateViewView, self).post(request, **kwargs)
return render(request, "ledger/bills/bill_form.html", context)
def get_success_url(self):
return reverse("bill-update", kwargs={"entity_slug": self.kwargs["entity_slug"], "bill_pk": self.kwargs["bill_pk"]})
# @login_required
# @permission_required("django_ledger.add_billmodel", raise_exception=True)
# def bill_create(request):
# """
# Handles creation of a bill in the system, including the validation of input data,
# creation of transactions associated with the bill, and rendering of the appropriate
# response or form. Ensures the user creating the bill has the necessary permissions and
# correct input parameters for successful bill creation and itemization.
# :param request: Django HttpRequest object containing metadata and data of the HTTP request.
# :type request: HttpRequest
# :return: JsonResponse with success/error information if the request is processed,
# or HttpResponse rendering the form for bill creation.
# :rtype: JsonResponse or HttpResponse
# """
# dealer = get_user_type(request)
# entity = dealer.entity
# if request.method == "POST":
# data = json.loads(request.body)
# vendor_id = data.get("vendor")
# terms = data.get("terms")
# vendor = entity.get_vendors().filter(pk=vendor_id).first()
# items = data.get("item", [])
# quantities = data.get("quantity", [])
# if not all([items, quantities]):
# return JsonResponse(
# {"status": "error", "message": _("Items and Quantities are required")},
# status=400,
# )
# if isinstance(quantities, list):
# if "0" in quantities:
# return JsonResponse(
# {
# "status": "error",
# "message": _("Quantity must be greater than zero"),
# }
# )
# else:
# if int(quantities) <= 0:
# return JsonResponse(
# {
# "status": "error",
# "message": _("Quantity must be greater than zero"),
# }
# )
# bill = entity.create_bill(vendor_model=vendor, terms=terms)
# if isinstance(items, list):
# item_quantity_map = {}
# for item, quantity in zip(items, quantities):
# if item in item_quantity_map:
# item_quantity_map[item] += int(quantity)
# else:
# item_quantity_map[item] = int(quantity)
# item_list = list(item_quantity_map.keys())
# quantity_list = list(item_quantity_map.values())
# items_list = [
# {"item_id": item_list[i], "quantity": quantity_list[i]}
# for i in range(len(item_list))
# ]
# items_txs = []
# for item in items_list:
# item_instance = ItemModel.objects.get(pk=item.get("item_id"))
# car = models.Car.objects.get(vin=item_instance.name)
# quantity = Decimal(item.get("quantity"))
# items_txs.append(
# {
# "item_number": item_instance.item_number,
# "quantity": quantity,
# "unit_cost": car.finances.cost_price,
# "total_amount": car.finances.cost_price * quantity,
# }
# )
# bill_itemtxs = {
# item.get("item_number"): {
# "unit_cost": item.get("unit_cost"),
# "quantity": item.get("quantity"),
# "total_amount": item.get("total_amount"),
# }
# for item in items_txs
# }
# else:
# item = entity.get_items_all().filter(pk=items).first()
# instance = models.Car.objects.get(vin=item.name)
# bill_itemtxs = {
# item.item_number: {
# "unit_cost": instance.finances.cost_price,
# "quantity": Decimal(quantities),
# "total_amount": instance.finances.cost_price * Decimal(quantities),
# }
# }
# bill_itemtxs = bill.migrate_itemtxs(
# itemtxs=bill_itemtxs,
# commit=True,
# operation=BillModel.ITEMIZE_APPEND,
# )
# url = reverse("bill_detail", kwargs={"pk": bill.pk})
# return JsonResponse(
# {
# "status": "success",
# "message": _("Bill created successfully"),
# "url": f"{url}",
# }
# )
# form = forms.BillModelCreateForm(entity_model=entity)
# form.initial.update(
# {
# "cash_account": dealer.settings.bill_cash_account,
# "prepaid_account": dealer.settings.bill_prepaid_account,
# "unearned_account": dealer.settings.bill_unearned_account,
# }
# )
# car_list = models.Car.objects.filter(dealer=dealer)
# context = {
# "form": form,
# "items": [
# {
# "car": x,
# "product": entity.get_items_products().filter(name=x.vin).first(),
# }
# for x in car_list
# ],
# }
# return render(request, "ledger/bills/bill_form.html", context)
@login_required
@ -8312,34 +8397,73 @@ def PurchaseOrderCreateView(request):
form = PurchaseOrderModelCreateForm(entity_slug=entity.slug, user_model=entity.admin)
return render(request, "purchase_orders/po_form.html", {"form": form})
def InventoryItemCreateView(request,pk):
po = get_object_or_404(PurchaseOrderModel, pk=pk)
def InventoryItemCreateView(request):
dealer = get_user_type(request)
entity = dealer.entity
coa = entity.get_default_coa()
inventory_accounts = entity.get_coa_all().get(name='ASSET_CA_INVENTORY')
inventory_accounts = entity.get_coa_accounts().filter(role='asset_ca_inv')
cogs_accounts = entity.get_coa_accounts().filter(role='cogs_regular')
if(request.method == "POST"):
make = request.POST.get("make")
model = request.POST.get("model")
serie = request.POST.get("serie")
trim = request.POST.get("trim")
name = request.POST.get("name")
account = request.POST.get("account")
account = inventory_accounts.get(pk=account)
inventory_name = None
if name:
inventory_name = name
else:
make = request.POST.get("make")
model = request.POST.get("model")
serie = request.POST.get("serie")
trim = request.POST.get("trim")
make_name = models.CarMake.objects.get(pk=make)
model_name = models.CarModel.objects.get(pk=model)
serie_name = models.CarSerie.objects.get(pk=serie)
trim_name = models.CarTrim.objects.get(pk=trim)
make_name = models.CarMake.objects.get(pk=make)
model_name = models.CarModel.objects.get(pk=model)
serie_name = models.CarSerie.objects.get(pk=serie)
trim_name = models.CarTrim.objects.get(pk=trim)
inventory_name = f"{make_name.name} - {model_name.name} - {serie_name.name} - {trim_name.name}"
inventory_name = f"{make_name.name} - {model_name.name} - {serie_name.name} - {trim_name.name}"
uom = entity.get_uom_all().get(name='Unit')
entity.create_item_inventory(
name=inventory_name,
uom_model=uom,
item_type=ItemModel.ITEM_TYPE_MATERIAL
item_type=ItemModel.ITEM_TYPE_MATERIAL,
inventory_account=account,
coa_model=coa
)
messages.success(request, _("Inventory item created successfully"))
return redirect('purchase_order_detail', pk=po.pk)
return redirect('purchase_order_list')
return render(request,'purchase_orders/inventory_item_form.html',{"make_data":models.CarMake.objects.all(),"inventory_accounts":inventory_accounts,"cogs_accounts":cogs_accounts})
def inventory_items_filter(request):
dealer = get_user_type(request)
make = request.GET.get('make')
model = request.GET.get('model')
serie = request.GET.get('serie')
model_data = models.CarModel.objects.none()
serie_data = models.CarSerie.objects.none()
trim_data = models.CarTrim.objects.none()
if make:
make = models.CarMake.objects.get(pk=make)
model_data = make.carmodel_set.all()
elif model:
model = models.CarModel.objects.get(pk=model)
serie_data = model.carserie_set.all()
elif serie:
serie = models.CarSerie.objects.get(pk=serie)
trim_data = serie.cartrim_set.all()
context = {
'model_data': model_data,
'serie_data': serie_data,
'trim_data': trim_data,
# 'inventory_items': dealer.entity.get_items_inventory(),
# 'entity_slug': dealer.entity.slug,
}
return render(request, "purchase_orders/car_inventory_item_form.html", context)
class PurchaseOrderDetailView(PurchaseOrderModelDetailViewBase):
template_name = 'purchase_orders/po_detail.html'
context_object_name = 'po_model'
@ -8360,37 +8484,6 @@ class PurchaseOrderDetailView(PurchaseOrderModelDetailViewBase):
return context
def inventory_items_filter(request,po_pk):
dealer = get_user_type(request)
make = request.GET.get('make')
model = request.GET.get('model')
serie = request.GET.get('serie')
make_data = models.CarMake.objects.all()
model_data = models.CarModel.objects.none()
serie_data = models.CarSerie.objects.none()
trim_data = models.CarTrim.objects.none()
if make:
make = models.CarMake.objects.get(pk=make)
model_data = make.carmodel_set.all()
elif model:
model = models.CarModel.objects.get(pk=model)
serie_data = model.carserie_set.all()
elif serie:
serie = models.CarSerie.objects.get(pk=serie)
trim_data = serie.cartrim_set.all()
context = {
'make_data': make_data,
'model_data': model_data,
'serie_data': serie_data,
'trim_data': trim_data,
'inventory_accounts': dealer.entity.get_coa_accounts().filter(role="asset_ca_inv"),
'inventory_items': dealer.entity.get_items_inventory(),
'entity_slug': dealer.entity.slug,
'po_model': get_object_or_404(PurchaseOrderModel, pk=po_pk)
}
return render(request, "purchase_orders/po_detail.html", context)
# def PurchaseOrderDetailView(request, pk):
# po = get_object_or_404(PurchaseOrderModel, pk=pk)
# dealer = get_user_type(request)
@ -8497,7 +8590,7 @@ class PurchaseOrderUpdateView(PurchaseOrderModelUpdateViewBase):
if create_bill_uuids:
item_uuids = ','.join(create_bill_uuids)
redirect_url = reverse(
'django_ledger:bill-create-po',
'bill-create-po',
kwargs={
'entity_slug': self.kwargs['entity_slug'],
'po_pk': po_model.uuid,
@ -8604,8 +8697,50 @@ class PurchaseOrderMarkAsCanceledView(BasePurchaseOrderActionActionView):
class PurchaseOrderMarkAsVoidView(BasePurchaseOrderActionActionView):
action_name = 'mark_as_void'
##############################bil
class BaseBillActionView(BaseBillActionViewBase):
def get_redirect_url(self, entity_slug, bill_pk, *args, **kwargs):
return reverse('bill-update',
kwargs={
'entity_slug': entity_slug,
'bill_pk': bill_pk
})
class BillModelCreateViewView(BillModelCreateView):
template_name = 'ledger/bills/bill_form.html'
class BillModelActionMarkAsDraftView(BaseBillActionView):
action_name = 'mark_as_draft'
class BillModelActionMarkAsInReviewView(BaseBillActionView):
action_name = 'mark_as_review'
class BillModelActionMarkAsApprovedView(BaseBillActionView):
action_name = 'mark_as_approved'
class BillModelActionMarkAsPaidView(BaseBillActionView):
action_name = 'mark_as_paid'
class BillModelActionDeleteView(BaseBillActionView):
action_name = 'mark_as_delete'
class BillModelActionVoidView(BaseBillActionView):
action_name = 'mark_as_void'
class BillModelActionCanceledView(BaseBillActionView):
action_name = 'mark_as_canceled'
class BillModelActionLockLedgerView(BaseBillActionView):
action_name = 'lock_ledger'
class BillModelActionUnlockLedgerView(BaseBillActionView):
action_name = 'unlock_ledger'
class BillModelActionForceMigrateView(BaseBillActionView):
action_name = 'migrate_state'

View File

@ -2,6 +2,7 @@
{% load i18n %}
{% load static %}
{% load django_ledger %}
{% load crispy_forms_filters %}
{% block content %}
<div class="row justify-content-center">
@ -27,7 +28,7 @@
{% endif %}
<div class="mb-4">
{{ form|add_class:"form-control" }}
{{ form|crispy }}
</div>
</div>
@ -37,7 +38,7 @@
id="djl-bill-create-button"
class="btn btn-primary btn-lg">{% trans 'Create' %}
</button>
<a href="{% url 'django_ledger:bill-list' entity_slug=view.kwargs.entity_slug %}"
<a href="{{request.META.HTTP_REFERER}}"
id="djl-bill-create-back-button"
class="btn btn-outline-secondary">{% trans 'Cancel' %}</a>
</div>

View File

@ -0,0 +1,275 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load django_ledger %}
{% block title %}Bill Details - {{ block.super }}{% endblock %}
{% block customCSS %}
<style>
/* Optional custom overrides for Bootstrap 5 */
.table th,
.table td {
vertical-align: middle;
}
.card-header i {
font-size: 1.25rem;
}
.text-xs {
font-size: 0.75rem;
}
.text-xxs {
font-size: 0.6rem;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="row g-4">
<!-- Left Sidebar -->
<div class="col-lg-4">
<div class="card h-100 shadow-sm">
<div class="card-body">
{% include 'bill/includes/card_bill.html' with bill=bill entity_slug=view.kwargs.entity_slug style='bill-detail' %}
<hr class="my-4">
{% include 'django_ledger/vendor/includes/card_vendor.html' with vendor=bill.vendor %}
<div class="d-grid mt-4">
<a href="{% url 'django_ledger:bill-list' entity_slug=view.kwargs.entity_slug %}"
class="btn btn-outline-primary">
<i class="fas fa-arrow-left me-1"></i> {% trans 'Bill List' %}
</a>
</div>
</div>
</div>
</div>
<!-- Main Content -->
<div class="col-lg-8">
{% if bill.is_configured %}
<div class="card mb-4 shadow-sm">
<div class="card-body">
<div class="row text-center g-3">
<div class="col-md-3">
<div class="border rounded p-3">
<h6 class="text-uppercase text-xs text-muted mb-2">
{% trans 'Cash Account' %}:
<a href="{% url 'django_ledger:account-detail' account_pk=bill.cash_account.uuid coa_slug=bill.cash_account.coa_model.slug entity_slug=view.kwargs.entity_slug %}"
class="text-decoration-none ms-1">
{{ bill.cash_account.code }}
</a>
</h6>
<h4 class="mb-0" id="djl-bill-detail-amount-paid">
{% currency_symbol %}{{ bill.get_amount_cash | absolute | currency_format }}
</h4>
</div>
</div>
{% if bill.accrue %}
<div class="col-md-3">
<div class="border rounded p-3">
<h6 class="text-uppercase text-xs text-muted mb-2">
{% trans 'Prepaid Account' %}:
<a href="{% url 'django_ledger:account-detail' account_pk=bill.prepaid_account.uuid coa_slug=bill.prepaid_account.coa_model.slug entity_slug=view.kwargs.entity_slug %}"
class="text-decoration-none ms-1">
{{ bill.prepaid_account.code }}
</a>
</h6>
<h4 class="text-success mb-0" id="djl-bill-detail-amount-prepaid">
{% currency_symbol %}{{ bill.get_amount_prepaid | currency_format }}
</h4>
</div>
</div>
<div class="col-md-3">
<div class="border rounded p-3">
<h6 class="text-uppercase text-xs text-muted mb-2">
{% trans 'Accounts Payable' %}:
<a href="{% url 'django_ledger:account-detail' account_pk=bill.unearned_account.uuid coa_slug=bill.unearned_account.coa_model.slug entity_slug=view.kwargs.entity_slug %}"
class="text-decoration-none ms-1">
{{ bill.unearned_account.code }}
</a>
</h6>
<h4 class="text-danger mb-0" id="djl-bill-detail-amount-unearned">
{% currency_symbol %}{{ bill.get_amount_unearned | currency_format }}
</h4>
</div>
</div>
<div class="col-md-3">
<div class="border rounded p-3">
<h6 class="text-uppercase text-xs text-muted mb-2">
{% trans 'Accrued' %} {{ bill.get_progress | percentage }}
</h6>
<h4 class="mb-0">
{% currency_symbol %}{{ bill.get_amount_earned | currency_format }}
</h4>
</div>
</div>
{% else %}
<div class="col-md-3 offset-md-6">
<div class="border rounded p-3">
<h6 class="text-uppercase text-xs text-muted mb-2">
{% trans 'You Still Owe' %}
</h6>
<h4 class="text-danger mb-0" id="djl-bill-detail-amount-owed">
{% currency_symbol %}{{ bill.get_amount_open | currency_format }}
</h4>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
<!-- Bill Items Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header pb-0">
<div class="d-flex align-items-center">
<i class="fas fa-receipt me-3 text-primary"></i>
<h5 class="mb-0">{% trans 'Bill Items' %}</h5>
</div>
</div>
<div class="card-body px-0 pt-0 pb-2">
<div class="table-responsive">
<table class="table table-hover align-items-center mb-0">
<thead class="table-light">
<tr>
<th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7">{% trans 'Item' %}</th>
<th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7">{% trans 'Entity Unit' %}</th>
<th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7 text-end">{% trans 'Unit Cost' %}</th>
<th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7 text-end">{% trans 'Quantity' %}</th>
<th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7 text-end">{% trans 'Total' %}</th>
<th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7 text-end">{% trans 'PO' %}</th>
</tr>
</thead>
<tbody>
{% for bill_item in itemtxs_qs %}
<tr>
<td>
<div class="d-flex px-2 py-1">
<div class="d-flex flex-column justify-content-center">
<h6 class="mb-0 text-sm">{{ bill_item.item_model }}</h6>
</div>
</div>
</td>
<td>
<span class="text-xs font-weight-bold">
{% if bill_item.entity_unit %}
{{ bill_item.entity_unit }}
{% endif %}
</span>
</td>
<td class="text-end">
<span class="text-xs font-weight-bold">
{% currency_symbol %}{{ bill_item.unit_cost | currency_format }}
</span>
</td>
<td class="text-end">
<span class="text-xs font-weight-bold">{{ bill_item.quantity }}</span>
</td>
<td class="text-end">
<span class="text-xs font-weight-bold">
{% currency_symbol %}{{ bill_item.total_amount | currency_format }}
</span>
</td>
<td class="text-end">
{% if bill_item.po_model_id %}
<a class="btn btn-sm btn-outline-info"
href="{% url 'purchase_order_detail' bill_item.po_model_id %}">
{% trans 'View PO' %}
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="3"></td>
<td class="text-end"><strong>{% trans 'Total' %}</strong></td>
<td class="text-end">
<strong>
{% currency_symbol %}{{ total_amount__sum | currency_format }}
</strong>
</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
{% if bill.is_active %}
<!-- Financial Statements Buttons -->
<div class="row mb-4">
<div class="col-12">
<div class="d-flex justify-content-center gap-2 flex-wrap">
<a href="{% url 'django_ledger:ledger-bs' entity_slug=view.kwargs.entity_slug ledger_pk=bill.ledger_id %}"
class="btn btn-outline-info">
{% trans 'Balance Sheet' %}
</a>
<a href="{% url 'django_ledger:ledger-ic' entity_slug=view.kwargs.entity_slug ledger_pk=bill.ledger_id %}"
class="btn btn-outline-info">
{% trans 'Income Statement' %}
</a>
<a href="{% url 'django_ledger:ledger-cf' entity_slug=view.kwargs.entity_slug ledger_pk=bill.ledger_id %}"
class="btn btn-outline-info">
{% trans 'Cash Flow Statement' %}
</a>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-12">
<div class="d-flex justify-content-center gap-2 flex-wrap">
<a href="{% url 'django_ledger:ledger-bs-year' entity_slug=view.kwargs.entity_slug ledger_pk=bill.ledger_id year=bill.get_status_action_date.year %}?format=pdf&report_subtitle={{ bill.generate_descriptive_title | safe }}"
class="btn btn-outline-success">
{% trans 'Balance Sheet PDF' %} <i class="fas fa-download ms-1"></i>
</a>
<a href="{% url 'django_ledger:ledger-ic-year' entity_slug=view.kwargs.entity_slug ledger_pk=bill.ledger_id year=bill.get_status_action_date.year %}?format=pdf&report_subtitle={{ bill.generate_descriptive_title | safe }}"
class="btn btn-outline-success">
{% trans 'Income Statement PDF' %} <i class="fas fa-download ms-1"></i>
</a>
<a href="{% url 'django_ledger:ledger-cf-year' entity_slug=view.kwargs.entity_slug ledger_pk=bill.ledger_id year=bill.get_status_action_date.year %}?format=pdf&report_subtitle={{ bill.generate_descriptive_title | safe }}"
class="btn btn-outline-success">
{% trans 'Cash Flow Statement PDF' %} <i class="fas fa-download ms-1"></i>
</a>
</div>
</div>
</div>
{% endif %}
<!-- Bill Transactions Card -->
<div class="card mb-4 shadow-sm">
<div class="card-header pb-0">
<div class="d-flex align-items-center">
<i class="fas fa-exchange-alt me-3 text-primary"></i>
<h5 class="mb-0">{% trans 'Bill Transactions' %}</h5>
</div>
</div>
<div class="card-body px-0 pt-0 pb-2">
{% transactions_table bill %}
</div>
</div>
<!-- Bill Notes Card -->
<div class="card shadow-sm">
<div class="card-header pb-0">
<div class="d-flex align-items-center">
<i class="fas fa-sticky-note me-3 text-primary"></i>
<h5 class="mb-0">{% trans 'Bill Notes' %}</h5>
</div>
</div>
<div class="card-body">
{% include 'bill/includes/card_markdown.html' with style='card_1' title='' notes_html=bill.notes_html %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,57 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load django_ledger %}
{% load custom_filters %}
{% load widget_tweaks crispy_forms_filters %}
{% block content %}
<div class="container py-4">
<div class="row g-4">
<!-- Vendor Card -->
<div class="col-12">
{% include 'bill/includes/card_vendor.html' with vendor=bill_model.vendor %}
</div>
<!-- Bill Form -->
<div class="col-12">
<div class="card mb-4">
<div class="card-body">
{% include 'bill/includes/card_bill.html' with bill=bill_model style='bill-detail' entity_slug=view.kwargs.entity_slug %}
<form action="{% url 'bill-update' entity_slug=view.kwargs.entity_slug bill_pk=bill_model.uuid %}" method="post">
{% csrf_token %}
<div class="mb-3">
{{ form|crispy }}
</div>
<button type="submit" class="btn btn-primary w-100 mb-2">
<i class="fas fa-save me-2"></i>{% trans 'Save Bill' %}
</button>
<a href="{% url 'bill-detail' entity_slug=view.kwargs.entity_slug bill_pk=bill_model.uuid %}"
class="btn btn-dark w-100 mb-2">
<i class="fas fa-arrow-left me-2"></i>{% trans 'Back to Bill Detail' %}
</a>
<a href="{% url 'bill_list' %}"
class="btn btn-info w-100 mb-2">
<i class="fas fa-list me-2"></i>{% trans 'Bill List' %}
</a>
</form>
</div>
</div>
</div>
<!-- Bill Item Formset -->
<div class="col-12">
{% bill_item_formset_table itemtxs_formset %}
</div>
</div>
</div>
{% include "bill/includes/mark_as.html" %}
{% endblock %}

View File

@ -0,0 +1,307 @@
{% load django_ledger %}
{% load i18n %}
<div id="djl-bill-card-widget">
{% if not create_bill %}
{% if style == 'dashboard' %}
<!-- Dashboard Style Card -->
<div class="">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="text-uppercase text-secondary mb-0">
<i class="fas fa-file-invoice me-2"></i>{% trans 'Bill' %}
</h6>
<span class="badge bg-{{ bill.get_status_badge_color }}">{{ bill.get_bill_status_display }}</span>
</div>
<h4 class="card-title">{{ bill.vendor.vendor_name }}</h4>
<p class="text-sm text-muted mb-4">{{ bill.vendor.address_1 }}</p>
{% if not bill.is_past_due %}
<p class="text-info mb-2">
<i class="fas fa-clock me-2"></i>{% trans 'Due in' %}: {{ bill.date_due | timeuntil }}
</p>
{% else %}
<p class="text-danger fw-bold mb-2">
<i class="fas fa-exclamation-triangle me-2"></i>{% trans 'Past Due' %}: {{ bill.date_due | timesince }} {% trans 'ago' %}
</p>
{% endif %}
<div class="d-flex align-items-center mb-3">
<span class="me-2">{% trans 'Accrued' %}:</span>
{% if bill.accrue %}
<i class="fas fa-check-circle text-success me-2"></i>
{% else %}
<i class="fas fa-times-circle text-danger me-2"></i>
{% endif %}
</div>
<div class="mb-4">
<p class="text-danger fw-bold mb-1">
{% trans 'Amount Due' %}: {% currency_symbol %}{{ bill.get_amount_open | currency_format }}
</p>
<p class="text-success mb-1">
{% trans 'Amount Paid' %}: {% currency_symbol %}{{ bill.amount_paid | currency_format }}
</p>
<p class="mb-1">
{% trans 'Progress' %}: {{ bill.get_progress | percentage }}
</p>
<div class="progress mt-2">
<div class="progress-bar bg-success"
role="progressbar"
style="width: {{ bill.get_progress_percent }}%"
aria-valuenow="{{ bill.get_progress_percent }}"
aria-valuemin="0"
aria-valuemax="100">
</div>
</div>
</div>
<!-- Modal Action -->
{% modal_action bill 'get' entity_slug %}
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a href="{% url 'django_ledger:bill-detail' entity_slug=entity_slug bill_pk=bill.uuid %}"
class="btn btn-sm btn-outline-primary me-md-2">
{% trans 'View' %}
</a>
<a href="{% url 'django_ledger:bill-update' entity_slug=entity_slug bill_pk=bill.uuid %}"
class="btn btn-sm btn-outline-warning me-md-2">
{% trans 'Update' %}
</a>
{% if bill.can_pay %}
<button onclick="djLedger.toggleModal('{{ bill.get_html_id }}')"
class="btn btn-sm btn-outline-info">
{% trans 'Mark as Paid' %}
</button>
{% endif %}
{% if bill.can_cancel %}
<button onclick="djLedger.toggleModal('{{ bill.get_html_id }}')"
class="btn btn-sm btn-outline-danger">
{% trans 'Cancel' %}
</button>
{% endif %}
</div>
</div>
</div>
{% elif style == 'bill-detail' %}
<!-- Detail Style Card -->
<div class="">
<div class="card-header p-4 bg-{{ bill.get_status_badge_color }}">
<div class="d-flex align-items-center">
<i class="fas fa-file-invoice me-3 text-white"></i>
<h2 class="mb-0 text-white">
{% trans 'Bill' %} {{ bill.bill_number }}
</h2>
</div>
</div>
<div class="card-body p-4 text-center">
{% if bill.is_draft %}
<h3 class="text-warning fw-bold mb-4">{% trans 'This bill is' %} {{ bill.get_bill_status_display }}</h3>
<div class="border-bottom pb-4 mb-4">
<p class="mb-2">
<span class="fw-bold">{% trans 'Amount Due' %}:</span>
{% currency_symbol %}{{ bill.amount_due | currency_format }}
</p>
<p class="mb-2">
<span class="fw-bold">{% trans 'Due Date' %}:</span>
{{ bill.date_due | timeuntil }}
</p>
<p class="mb-0">
<span class="fw-bold">{% trans 'Is Accrued' %}:</span>
{% if bill.accrue %}
<i class="fas fa-check-circle text-success ms-2"></i>
{% else %}
<i class="fas fa-times-circle text-danger ms-2"></i>
{% endif %}
</p>
</div>
{% elif bill.is_review %}
<h3 class="text-warning fw-bold mb-4">{% trans 'This bill is' %} {{ bill.get_bill_status_display }}</h3>
<div class="border-bottom pb-4 mb-4">
<p class="mb-2">
<span class="fw-bold">{% trans 'Amount Due' %}:</span>
{% currency_symbol %}{{ bill.amount_due | currency_format }}
</p>
<p class="mb-2">
<span class="fw-bold">{% trans 'Due Date' %}:</span>
{{ bill.date_due | timeuntil }}
</p>
<p class="mb-0">
<span class="fw-bold">{% trans 'Is Accrued' %}:</span>
{% if bill.accrue %}
<i class="fas fa-check-circle text-success ms-2"></i>
{% else %}
<i class="fas fa-times-circle text-danger ms-2"></i>
{% endif %}
</p>
</div>
{% if bill.xref %}
<p class="text-muted fst-italic">{% trans 'External Ref' %}: {{ bill.xref }}</p>
{% endif %}
{% elif bill.is_approved %}
<h3 class="text-info fw-bold mb-4">{% trans 'This bill is' %} {{ bill.get_bill_status_display }}</h3>
<div class="border-bottom pb-4 mb-4">
<p class="mb-2">
<span class="fw-bold">{% trans 'Amount Due' %}:</span>
{% currency_symbol %}{{ bill.amount_due | currency_format }}
</p>
<p class="mb-2">
<span class="fw-bold">{% trans 'Due Date' %}:</span>
{{ bill.date_due | timeuntil }}
</p>
<p class="mb-2">
<span class="fw-bold">{% trans 'Amount Paid' %}:</span>
{% currency_symbol %}{{ bill.amount_paid | currency_format }}
</p>
<p class="mb-2">
<span class="fw-bold">{% trans 'Progress' %}:</span>
{{ bill.get_progress | percentage }}
</p>
<div class="progress mt-3">
<div class="progress-bar bg-success"
role="progressbar"
style="width: {{ bill.get_progress_percent }}%"
aria-valuenow="{{ bill.get_progress_percent }}"
aria-valuemin="0"
aria-valuemax="100">
</div>
</div>
</div>
{% if bill.xref %}
<p class="text-muted fst-italic">{% trans 'External Ref' %}: {{ bill.xref }}</p>
{% endif %}
{% elif bill.is_paid %}
<h3 class="text-success fw-bold mb-4">{% trans 'This bill is' %} {{ bill.get_bill_status_display }}</h3>
<div class="border-bottom pb-4 mb-4">
<p class="mb-2">
<span class="fw-bold">{% trans 'Amount Paid' %}:</span>
{% currency_symbol %}{{ bill.amount_paid | currency_format }}
</p>
<p class="mb-0">
<span class="fw-bold">{% trans 'Paid Date' %}:</span>
{{ bill.date_paid | date }}
</p>
</div>
{% if bill.xref %}
<p class="text-muted fst-italic">{% trans 'External Ref' %}: {{ bill.xref }}</p>
{% endif %}
{% else %}
<div class="border-bottom pb-4 mb-4">
<p class="mb-2">
<span class="fw-bold">{% trans 'Bill Amount' %}:</span>
{% currency_symbol %}{{ bill.amount_due | currency_format }}
</p>
<p class="text-danger fw-bold">
{{ bill.get_bill_status_display | upper }}
</p>
</div>
{% endif %}
</div>
<div class="card-footer p-0">
<div class="d-flex flex-wrap">
<!-- Update Button -->
<a href="{% url 'bill-update' entity_slug=entity_slug bill_pk=bill.uuid %}"
class="btn btn-link text-primary w-100 w-md-auto border-end">
{% trans 'Update' %}
</a>
<!-- Mark as Draft -->
{% if bill.can_draft %}
<button class="btn btn-outline-success"
onclick="showPOModal('Mark as Draft', '{% url 'bill-action-mark-as-draft' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Draft')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Draft' %}
</button>
{% endif %}
<!-- Mark as Review -->
{% if bill.can_review %}
<button class="btn btn-outline-success"
onclick="showPOModal('Mark as Review', '{% url 'bill-action-mark-as-review' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Review')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Review' %}
</button>
{% endif %}
<!-- Mark as Approved -->
{% if bill.can_approve %}
<button class="btn btn-outline-success"
onclick="showPOModal('Mark as Approved', '{% url 'bill-action-mark-as-approved' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Approved')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Approved' %}
</button>
{% endif %}
<!-- Mark as Paid -->
{% if bill.can_pay %}
<button class="btn btn-outline-success"
onclick="showPOModal('Mark as Paid', '{% url 'bill-action-mark-as-paid' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Paid')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Paid' %}
</button>
{% endif %}
<!-- Void Button -->
{% if bill.can_void %}
<button class="btn btn-outline-success"
onclick="showPOModal('Mark as Void', '{% url 'bill-action-mark-as-void' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Void')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Void' %}
</button>
{% endif %}
<!-- Cancel Button -->
{% if bill.can_cancel %}
<button class="btn btn-outline-success"
onclick="showPOModal('Mark as Canceled', '{% url 'bill-action-mark-as-canceled' entity_slug=entity_slug bill_pk=bill.pk %}', 'Mark as Canceled')">
<i class="fas fa-check-circle me-2"></i>{% trans 'Mark as Canceled' %}
</button>
{% modal_action_v2 bill bill.get_mark_as_canceled_url bill.get_mark_as_canceled_message bill.get_mark_as_canceled_html_id %}
{% endif %}
</div>
</div>
</div>
{% endif %}
{% else %}
<!-- Create Bill Card -->
<div class=" bg-light">
<div class="card-body text-center p-5">
<a href="{% url 'django_ledger:bill-create' entity_slug=entity_slug %}"
class="text-primary">
<i class="fas fa-plus-circle fa-4x mb-3"></i>
<h3 class="h4">{% trans 'New Bill' %}</h3>
</a>
</div>
</div>
{% endif %}
</div>
<style>
.card-footer .btn-link {
padding: 1rem;
text-decoration: none;
transition: all 0.2s ease;
}
.card-footer .btn-link:hover {
background-color: rgba(0,0,0,0.03);
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
window.showPOModal = function(title, actionUrl, buttonText) {
const modalEl = document.getElementById('POModal');
if (!modalEl) {
console.error('Modal element not found');
return;
}
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
document.getElementById('POModalTitle').textContent = title;
document.getElementById('POModalBody').innerHTML = `
<div class="d-flex justify-content-center gap-3 py-3">
<a class="btn btn-primary px-4" href="${actionUrl}">
<i class="fas fa-check-circle me-2"></i>${buttonText}
</a>
<button class="btn btn-outline-secondary" data-bs-dismiss="modal">
<i class="fas fa-times me-2"></i>Cancel
</button>
</div>
`;
modal.show();
};
});
</script>

View File

@ -0,0 +1,25 @@
{% load trans from i18n %}
{% load django_ledger %}
{% if style == 'card_1' %}
<div class="card">
<div class="card-header">
<div class="card-header-title">
<h1 class="is-size-3 has-text-weight-light">{% if title %}{{ title }}{% else %}
{% trans 'Notes' %}
{% endif %}</h1>
</div>
</div>
<div class="card-content">
<div class="content">
{% if notes_html %}
{% autoescape off %}
{{ notes_html | safe }}
{% endautoescape %}
{% else %}
<p>{% trans 'No available notes to display...' %}</p>
{% endif %}
</div>
</div>
</div>
{% endif %}

View File

@ -0,0 +1,30 @@
{% load i18n %}
{% load django_ledger %}
<div class="card" id="djl-vendor-card-widget">
<div class="card-header">
<h2 class="card-title d-flex align-items-center text-primary">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-person-lines-fill me-2" viewBox="0 0 16 16">
<path d="M6 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-5 6s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H1zM11 3.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5zm-1 0a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-5 0a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5zM2 3a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4A.5.5 0 0 1 2 3zm9.854 2.854a.5.5 0 0 1 0-.708l3-3a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0zM2.5 14.5c0-.827.673-1.5 1.5-1.5h7c.827 0 1.5.673 1.5 1.5s-.673 1.5-1.5 1.5h-7c-.827 0-1.5-.673-1.5-1.5z"/>
</svg>
{% trans 'Vendor Info' %}
</h2>
</div>
<div class="card-body">
<h4 class="card-title fw-bold mb-3">{{ vendor.vendor_name }}</h4>
<p class="card-text mb-0">
{% if vendor.address_1 %}<span class="d-block">{{ vendor.address_1 }}</span>{% endif %}
{% if vendor.address_2 %}<span class="d-block">{{ vendor.address_2 }}</span>{% endif %}
{% if vendor.get_cszc %}<span class="d-block">{{ vendor.get_cszc }}</span>{% endif %}
{% if vendor.phone %}<span class="d-block">{{ vendor.phone }}</span>{% endif %}
{% if vendor.email %}<span class="d-block">{{ vendor.email }}</span>{% endif %}
{% if vendor.website %}<span class="d-block">{{ vendor.website }}</span>{% endif %}
</p>
</div>
<div class="card-footer bg-white">
</div>
</div>

View File

@ -0,0 +1,14 @@
<!-- Modal Template (keep this in your base template) -->
<div class="modal fade" id="POModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-md">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="POModalTitle"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="POModalBody">
<!-- Content will be inserted here by JavaScript -->
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,159 @@
{% load i18n %}
{% load static %}
{% load django_ledger %}
{% load widget_tweaks %}
<form action="{% url 'bill-update-items' entity_slug=entity_slug bill_pk=bill_pk %}" method="post">
<div class="container-fluid py-4">
<!-- Page Header -->
<div class="row mb-4">
<div class="col-12">
<h2 class="text-primary mb-0 d-flex align-items-center">
<i class="fas fa-receipt me-2"></i>
{% trans 'Bill Items' %}
</h2>
<hr class="my-3">
</div>
</div>
<!-- Form Content -->
<div class="row">
<div class="col-12">
{% csrf_token %}
{{ item_formset.non_form_errors }}
{{ item_formset.management_form }}
<!-- Card Container -->
<div class="card shadow-sm">
<div class="card-body p-0">
<!-- Responsive Table -->
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th class="text-uppercase text-xxs font-weight-bolder">{% trans 'Item' %}</th>
<th class="text-uppercase text-xxs font-weight-bolder text-center">{% trans 'PO Qty' %}</th>
<th class="text-uppercase text-xxs font-weight-bolder text-center">{% trans 'PO Amount' %}</th>
<th class="text-uppercase text-xxs font-weight-bolder text-center">{% trans 'Quantity' %}</th>
<th class="text-uppercase text-xxs font-weight-bolder text-center">{% trans 'Unit Cost' %}</th>
<th class="text-uppercase text-xxs font-weight-bolder text-center">{% trans 'Unit' %}</th>
<th class="text-uppercase text-xxs font-weight-bolder text-end">{% trans 'Total' %}</th>
<th class="text-uppercase text-xxs font-weight-bolder text-center">{% trans 'Delete' %}</th>
</tr>
</thead>
<tbody>
{% for f in item_formset %}
<tr class="align-middle">
<!-- Item Column -->
<td>
<div class="d-flex flex-column">
{% for hidden_field in f.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{{ f.item_model|add_class:"form-control" }}
{% if f.errors %}
<span class="text-danger text-xs">{{ f.errors }}</span>
{% endif %}
</div>
</td>
<!-- PO Quantity -->
<td class="text-center">
<span class="text-muted text-xs">
{% if f.instance.po_quantity %}{{ f.instance.po_quantity }}{% endif %}
</span>
</td>
<!-- PO Amount -->
<td class="text-center">
{% if f.instance.po_total_amount %}
<div class="d-flex flex-column">
<span class="text-xs font-weight-bold">
{% currency_symbol %}{{ f.instance.po_total_amount | currency_format }}
</span>
<a class="btn btn-sm btn-outline-info mt-1"
href="{% url 'purchase_order_detail' f.instance.po_model_id %}">
{% trans 'View PO' %}
</a>
</div>
{% endif %}
</td>
<!-- Quantity -->
<td class="text-center">
<div class="input-group input-group-sm w-100">
{{ f.quantity|add_class:"form-control" }}
</div>
</td>
<!-- Unit Cost -->
<td class="text-center">
<div class="input-group input-group-sm w-100">
{{ f.unit_cost|add_class:"form-control" }}
</div>
</td>
<!-- Entity Unit -->
<td class="text-center">
{{ f.entity_unit|add_class:"form-control" }}
</td>
<!-- Total Amount -->
<td class="text-end">
<span class="text-xs font-weight-bold">
{% currency_symbol %}{{ f.instance.total_amount | currency_format }}
</span>
</td>
<!-- Delete Checkbox -->
<td class="text-center">
{% if item_formset.can_delete %}
<div class="form-check d-flex justify-content-center">
{{ f.DELETE }}
</div>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
<!-- Footer Total -->
<tfoot class="total-row">
<tr>
<td colspan="5"></td>
<td class="text-end"><strong>{% trans 'Total' %}</strong></td>
<td class="text-end">
<strong>
{% currency_symbol %}{{ total_amount__sum | currency_format }}
</strong>
</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="row mt-4">
<div class="col-12">
<div class="d-flex justify-content-end gap-2">
{% if not item_formset.has_po %}
<a href="{% url 'django_ledger:product-create' entity_slug=entity_slug %}"
class="btn btn-outline-primary">
<i class="fas fa-plus me-1"></i>
{% trans 'New Item' %}
</a>
{% endif %}
<button type="submit" class="btn btn-primary">
<i class="fas fa-save me-1"></i>
{% trans 'Save Changes' %}
</button>
</div>
</div>
</div>
</div>
</form>

View File

@ -0,0 +1,60 @@
{% load django_ledger %}
{% load i18n %}
<div class="table-container">
<table class="table is-fullwidth is-narrow is-striped is-bordered django-ledger-table-bottom-margin-75">
<thead>
<tr>
<th>{% trans 'Number' %}</th>
<th>{% trans 'Status' %}</th>
<th>{% trans 'Status Date' %}</th>
<th>{% trans 'Vendor' %}</th>
<th>{% trans 'Amount Due' %}</th>
<th>{% trans 'Payments' %}</th>
<th>{% trans 'Past Due' %}</th>
<th>{% trans 'Actions' %}</th>
</tr>
</thead>
<tbody>
{% for bill in bills %}
<tr id="{{ bill.get_html_id }}">
<td>{{ bill.bill_number }}</td>
<td>{{ bill.get_bill_status_display }}</td>
<td>{{ bill.get_status_action_date }}</td>
<td>{{ bill.vendor.vendor_name }}</td>
<td id="{{ bill.get_html_amount_due_id }}">
{% currency_symbol %}{{ bill.amount_due | currency_format }}</td>
<td id="{{ bill.get_html_amount_paid_id }}">
{% currency_symbol %}{{ bill.amount_paid | currency_format }}</td>
<td class="has-text-centered">
{% if bill.is_past_due %}
<span class="icon is-small has-text-danger">{% icon 'bi:check-circle-fill' 24 %}</span>
{% endif %}
</td>
<td class="has-text-centered">
<div class="dropdown is-right is-hoverable" id="bill-action-{{ bill.uuid }}">
<div class="dropdown-trigger">
<button class="button is-small is-rounded is-outlined is-dark"
aria-haspopup="true"
aria-controls="dropdown-menu">
<span>Actions</span>
<span class="icon is-small">{% icon 'bi:arrow-down' 24 %}</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu-{{ bill.uuid }}" role="menu">
<div class="dropdown-content">
<a href="{% url 'django_ledger:bill-detail' entity_slug=entity_slug bill_pk=bill.uuid %}"
class="dropdown-item has-text-success">Details</a>
<a href="{% url 'django_ledger:bill-update' entity_slug=entity_slug bill_pk=bill.uuid %}"
class="dropdown-item has-text-warning-dark">Update</a>
</div>
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

View File

@ -0,0 +1,160 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load i18n static %}
{% block title %}{{ _("Create Bill") }}{% endblock title %}
{% block content %}
<div class="row mt-4">
<h3 class="text-center">{% trans "Create Bill" %}</h3>
<form id="mainForm" method="post" class="needs-validation">
{% csrf_token %}
<div class="row g-3">
{{ form|crispy }}
<div class="row mt-5">
<div id="formrow">
<h3 class="text-start">Unit Items</h3>
<div class="form-row row g-3 mb-3 mt-5">
<div class="mb-2 col-sm-4">
<select class="form-control item" name="item[]" required>
{% for item in items %}
<option value="{{ item.product.pk }}">{{item.car.vin}} - {{ item.car }}</option>
{% endfor %}
</select>
</div>
<div class="mb-2 col-sm-2">
<input class="form-control quantity" type="number" placeholder="Quantity" name="quantity[]" required>
</div>
<div class="mb-2 col-sm-1">
<button class="btn btn-danger removeBtn">Remove</button>
</div>
</div>
</div>
<div class="col-12">
<button id="addMoreBtn" class="btn btn-primary">Add More</button>
</div>
</div>
</div>
<!-- Buttons -->
<div class="d-flex mt-5 justify-content-center">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
</div>
{% endblock content %}
{% block customJS %}
<script>
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
// Add new form fields
document.getElementById('addMoreBtn').addEventListener('click', function(e) {
e.preventDefault();
const formrow = document.getElementById('formrow');
const newForm = document.createElement('div');
newForm.className = 'form-row row g-3 mb-3 mt-5';
newForm.innerHTML = `
<div class="mb-2 col-sm-2">
<select class="form-control item" name="item[]" required>
{% for item in items %}
<option value="{{ item.product.pk }}">{{ item.car.id_car_model }}</option>
{% endfor %}
</select>
</div>
<div class="mb-2 col-sm-2">
<input class="form-control quantity" type="number" placeholder="Quantity" name="quantity[]" required>
</div>
<div class="mb-2 col-sm-1">
<button class="btn btn-danger removeBtn">Remove</button>
</div>
`;
formrow.appendChild(newForm);
// Add remove button functionality
newForm.querySelector('.removeBtn').addEventListener('click', function() {
newForm.remove();
});
});
// Add remove button functionality to the initial form
document.querySelectorAll('.form-row').forEach(row => {
row.querySelector('.removeBtn').addEventListener('click', function() {
row.remove();
});
});
// Handle form submission
document.getElementById('mainForm').addEventListener('submit', async function(e) {
e.preventDefault();
/*const titleInput = document.querySelector('[name="title"]');
if (titleInput.value.length < 5) {
notify("error", "Customer billte Title must be at least 5 characters long.");
return; // Stop form submission
}*/
// Collect all form data
const formData = {
csrfmiddlewaretoken: document.querySelector('[name=csrfmiddlewaretoken]').value,
vendor: document.querySelector('[name=vendor]').value,
xref: document.querySelector('[name=xref]').value,
date_draft: document.querySelector('[name=date_draft]').value,
terms: document.querySelector('[name=terms]').value,
item: [],
quantity: []
};
// Collect multi-value fields (e.g., item[], quantity[])
document.querySelectorAll('[name="item[]"]').forEach(input => {
formData.item.push(input.value);
});
document.querySelectorAll('[name="quantity[]"]').forEach(input => {
formData.quantity.push(input.value);
});
try {
// Send data to the server using fetch
const response = await fetch("{% url 'bill_create' %}", {
method: 'POST',
headers: {
'X-CSRFToken': formData.csrfmiddlewaretoken,
'Content-Type': 'application/json',
},
body: JSON.stringify(formData)
});
// Parse the JSON response
const data = await response.json();
// Handle the response
if (data.status === "error") {
notify("error", data.message); // Display an error message
} else if (data.status === "success") {
notify("success","Bill created successfully");
setTimeout(() => {
window.location.assign(data.url); // Redirect to the provided URL
}, 1000);
} else {
notify("error","Unexpected response from the server");
}
} catch (error) {
notify("error", error);
}
});
</script>
{% endblock customJS %}

View File

@ -11,33 +11,8 @@
{% csrf_token %}
<div class="row g-3">
{{ form|crispy }}
<div class="row mt-5">
<div id="formrow">
<h3 class="text-start">Unit Items</h3>
<div class="form-row row g-3 mb-3 mt-5">
<div class="mb-2 col-sm-4">
<select class="form-control item" name="item[]" required>
{% for item in items %}
<option value="{{ item.product.pk }}">{{item.car.vin}} - {{ item.car }}</option>
{% endfor %}
</select>
</div>
<div class="mb-2 col-sm-2">
<input class="form-control quantity" type="number" placeholder="Quantity" name="quantity[]" required>
</div>
<div class="mb-2 col-sm-1">
<button class="btn btn-danger removeBtn">Remove</button>
</div>
</div>
</div>
<div class="col-12">
<button id="addMoreBtn" class="btn btn-primary">Add More</button>
</div>
</div>
</div>
<!-- Buttons -->
<div class="d-flex mt-5 justify-content-center">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
@ -45,116 +20,4 @@
</form>
</div>
{% endblock content %}
{% block customJS %}
<script>
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 2000,
timerProgressBar: false,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
// Add new form fields
document.getElementById('addMoreBtn').addEventListener('click', function(e) {
e.preventDefault();
const formrow = document.getElementById('formrow');
const newForm = document.createElement('div');
newForm.className = 'form-row row g-3 mb-3 mt-5';
newForm.innerHTML = `
<div class="mb-2 col-sm-2">
<select class="form-control item" name="item[]" required>
{% for item in items %}
<option value="{{ item.product.pk }}">{{ item.car.id_car_model }}</option>
{% endfor %}
</select>
</div>
<div class="mb-2 col-sm-2">
<input class="form-control quantity" type="number" placeholder="Quantity" name="quantity[]" required>
</div>
<div class="mb-2 col-sm-1">
<button class="btn btn-danger removeBtn">Remove</button>
</div>
`;
formrow.appendChild(newForm);
// Add remove button functionality
newForm.querySelector('.removeBtn').addEventListener('click', function() {
newForm.remove();
});
});
// Add remove button functionality to the initial form
document.querySelectorAll('.form-row').forEach(row => {
row.querySelector('.removeBtn').addEventListener('click', function() {
row.remove();
});
});
// Handle form submission
document.getElementById('mainForm').addEventListener('submit', async function(e) {
e.preventDefault();
/*const titleInput = document.querySelector('[name="title"]');
if (titleInput.value.length < 5) {
notify("error", "Customer billte Title must be at least 5 characters long.");
return; // Stop form submission
}*/
// Collect all form data
const formData = {
csrfmiddlewaretoken: document.querySelector('[name=csrfmiddlewaretoken]').value,
vendor: document.querySelector('[name=vendor]').value,
xref: document.querySelector('[name=xref]').value,
date_draft: document.querySelector('[name=date_draft]').value,
terms: document.querySelector('[name=terms]').value,
item: [],
quantity: []
};
// Collect multi-value fields (e.g., item[], quantity[])
document.querySelectorAll('[name="item[]"]').forEach(input => {
formData.item.push(input.value);
});
document.querySelectorAll('[name="quantity[]"]').forEach(input => {
formData.quantity.push(input.value);
});
try {
// Send data to the server using fetch
const response = await fetch("{% url 'bill_create' %}", {
method: 'POST',
headers: {
'X-CSRFToken': formData.csrfmiddlewaretoken,
'Content-Type': 'application/json',
},
body: JSON.stringify(formData)
});
// Parse the JSON response
const data = await response.json();
// Handle the response
if (data.status === "error") {
notify("error", data.message); // Display an error message
} else if (data.status === "success") {
notify("success","Bill created successfully");
setTimeout(() => {
window.location.assign(data.url); // Redirect to the provided URL
}, 1000);
} else {
notify("error","Unexpected response from the server");
}
} catch (error) {
notify("error", error);
}
});
</script>
{% endblock customJS %}
{% endblock content %}

View File

@ -14,11 +14,9 @@
<div class="row mt-4">
<div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Bills" %}</h3>
<a href="{% url 'bill_create' %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Bill' %}</a>
<a href="{% url 'bill-create' entity.slug %}" class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Bill' %}</a>
</div>
<div class="col-12">
<form method="get" class=" mb-4">
<div class="input-group input-group-sm">
@ -40,9 +38,9 @@
</form>
</div>
<div class="table-responsive px-1 scrollbar mt-3">
<table class="table align-items-center table-flush">
<thead>
@ -53,9 +51,9 @@
<th class="sort white-space-nowrap align-middle" scope="col">{% trans 'Action'%}</th>
</tr>
</thead>
<tbody class="list">
{% for bill in bills %}
{% for bill in bills %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap">
@ -84,7 +82,7 @@
<a href="{% url 'bill_detail' bill.pk %}" class="dropdown-item text-success-dark">{% trans 'View' %}</a>
</div>
</div>
</tr>
{% empty %}
<tr>
@ -107,5 +105,5 @@
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends "base.html" %}
{% load static i18n crispy_forms_tags %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{% include "purchase_orders/partials/po-select.html" with name="make" target="model" data=make_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="model" target="serie" data=model_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="serie" target="trim" data=serie_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="trim" target="none" data=trim_data pk=po_model.pk %}
<div class="form-group">
<label for="account">Account</label>
<select class="form-control" name="account" id="account">
{% for account in inventory_accounts %}
<option value="{{ account.pk }}">{{ account }}"></option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">Add New Item To Inventory</button>
</form>
{% endblock content %}

View File

@ -1,21 +1,27 @@
{% extends "base.html" %}
{% load static i18n crispy_forms_tags %}
<form action="{% url 'inventory_item_create' po_model.pk %}" method="post">
{% csrf_token %}
{% include "purchase_orders/partials/po-select.html" with name="make" target="model" data=make_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="model" target="serie" data=model_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="serie" target="trim" data=serie_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="trim" target="none" data=trim_data pk=po_model.pk %}
<div class="form-group">
<label for="account">Account</label>
<select class="form-control" name="account" id="account">
{% for account in inventory_accounts %}
<option value="{{ account.pk }}">{{ account }}"></option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="quantity">Quantity</label>
<input type="number" class="form-control" id="quantity" name="quantity" required>
</div>
<button type="submit" class="btn btn-primary">Add New Item To Inventory</button>
</form>
{% block content %}
<form action="{% url 'inventory_item_create' po_model.pk %}" method="post">
{% csrf_token %}
{% include "purchase_orders/partials/po-select.html" with name="make" target="model" data=make_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="model" target="serie" data=model_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="serie" target="trim" data=serie_data pk=po_model.pk %}
{% include "purchase_orders/partials/po-select.html" with name="trim" target="none" data=trim_data pk=po_model.pk %}
<div class="form-group">
<label for="account">Account</label>
<select class="form-control" name="account" id="account">
{% for account in inventory_accounts %}
<option value="{{ account.pk }}">{{ account }}"></option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="quantity">Quantity</label>
<input type="number" class="form-control" id="quantity" name="quantity" required>
</div>
<button type="submit" class="btn btn-primary">Add New Item To Inventory</button>
</form>
{% endblock content %}

View File

@ -58,7 +58,7 @@
{{ f.create_bill|add_class:"form-check-input" }}
{% elif f.instance.bill_model %}
<a class="btn btn-sm btn-outline-secondary"
href="{% url 'django_ledger:bill-detail' entity_slug=entity_slug bill_pk=f.instance.bill_model_id %}">
href="{% url 'bill-detail' entity_slug=entity_slug bill_pk=f.instance.bill_model_id %}">
{% trans 'View Bill' %}
</a>
{% endif %}

View File

@ -1,53 +1,23 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% block title %}
{# Check if an 'object' exists in the context #}
{% if object %}
{% trans 'Update Inventory Item'%}
{% else %}
{% trans 'Add New Inventory Item'%}
{% endif %}
{% endblock %}
{% load static i18n crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="row">
<div class="col-xl-9">
<div class="d-sm-flex justify-content-between">
<h3 class="mb-3">
{% if vendor.created %}
<!--<i class="bi bi-pencil-square"></i>-->
{{ _("Edit Inventory Item") }}
{% else %}
<!--<i class="bi bi-person-plus"></i> -->
{{ _("Add New Inventory Item") }}
{% endif %}
</h3>
</div>
</div>
</div>
<div class="row">
<div class="col-xl-9">
<form class="row g-3 mb-9" method="post" class="form" enctype="multipart/form-data" novalidate >
{% csrf_token %}
{{ redirect_field }}
{{ form|crispy }}
{% for error in form.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
<div class="d-flex justify-content-start">
<button class="btn btn-sm btn-success me-2" type="submit"><i class="fa-solid fa-floppy-disk me-1"></i>
<!--<i class="bi bi-save"></i> -->
{{ _("Save") }}
</button>
<a href="{{request.META.HTTP_REFERER}}" class="btn btn-sm btn-danger"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>
</div>
</div>
<div class="container-fluid m-0">
<form action="" method="post">
{% csrf_token %}
<div class="form-group">
<label for="account">Name</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>
{% endblock %}
<div class="form-group">
<label for="account">Account</label>
<select class="form-control" name="account" id="account">
{% for account in inventory_accounts %}
<option value="{{ account.pk }}">{{ account }}"></option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">Add New Item To Inventory</button>
</form>
</div>
{% endblock content %}

View File

@ -2,10 +2,13 @@
<label for="{{name}}">{{name|capfirst}}</label>
<select class="form-control"
name="{{name}}" id="{{name}}"
hx-get="{% url 'inventory_items_filter' po_pk=po_model.pk %}"
hx-target="#form-{{target}}"
hx-select="#form-{{target}}"
hx-swap="outerHTML">
{% if name != "trim" %}
hx-get="{% url 'inventory_items_filter' %}"
hx-target="#form-{{target}}"
hx-select="#form-{{target}}"
hx-swap="outerHTML"
{% endif %}
>
{% for item in data %}
<option value="{{ item.pk }}">{{ item.name }}</option>
{% endfor %}