sale order
This commit is contained in:
parent
149c68cfae
commit
7142975004
@ -24,7 +24,7 @@ urlpatterns += i18n_patterns(
|
|||||||
path('ledger/', include('django_ledger.urls', namespace='django_ledger')),
|
path('ledger/', include('django_ledger.urls', namespace='django_ledger')),
|
||||||
path("haikalbot/", include("haikalbot.urls")),
|
path("haikalbot/", include("haikalbot.urls")),
|
||||||
path('appointment/', include('appointment.urls')),
|
path('appointment/', include('appointment.urls')),
|
||||||
path('plans/', include('plans.urls')),
|
# path('plans/', include('plans.urls')),
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|||||||
@ -230,7 +230,7 @@ class CarUpdateForm(forms.ModelForm, AddClassMixin):
|
|||||||
# ]
|
# ]
|
||||||
|
|
||||||
|
|
||||||
class CarFinanceForm(AddClassMixin, forms.ModelForm):
|
class CarFinanceForm(forms.ModelForm):
|
||||||
additional_finances = forms.ModelMultipleChoiceField(
|
additional_finances = forms.ModelMultipleChoiceField(
|
||||||
queryset=AdditionalServices.objects.all(),
|
queryset=AdditionalServices.objects.all(),
|
||||||
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
|
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
|
||||||
@ -689,8 +689,7 @@ class BillModelCreateForm(BillModelCreateFormBase):
|
|||||||
class SaleOrderForm(forms.ModelForm):
|
class SaleOrderForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SaleOrder
|
model = SaleOrder
|
||||||
fields = '__all__'
|
fields = ['estimate','payment_method', 'comments']
|
||||||
widgets = {
|
widgets = {
|
||||||
'address': forms.Textarea(attrs={'rows': 3}),
|
|
||||||
'comments': forms.Textarea(attrs={'rows': 3}),
|
'comments': forms.Textarea(attrs={'rows': 3}),
|
||||||
}
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 4.2.17 on 2025-01-27 08:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||||
|
('inventory', '0007_alter_cartransfer_status'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='saleorder',
|
||||||
|
name='estimate',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to='django_ledger.estimatemodel', verbose_name='Estimate'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='saleorder',
|
||||||
|
name='invoice',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to='django_ledger.invoicemodel', verbose_name='Invoice'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
inventory/migrations/0009_saleorder_formatted_order_id.py
Normal file
19
inventory/migrations/0009_saleorder_formatted_order_id.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.2.17 on 2025-01-27 08:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0008_saleorder_estimate_saleorder_invoice'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='saleorder',
|
||||||
|
name='formatted_order_id',
|
||||||
|
field=models.CharField(default=1, editable=False, max_length=10, unique=True),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 4.2.17 on 2025-01-27 09:02
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0009_saleorder_formatted_order_id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='saleorder',
|
||||||
|
name='car',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='saleorder',
|
||||||
|
name='customer',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='saleorder',
|
||||||
|
name='trade_in',
|
||||||
|
),
|
||||||
|
]
|
||||||
21
inventory/migrations/0011_alter_saleorder_estimate.py
Normal file
21
inventory/migrations/0011_alter_saleorder_estimate.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 4.2.17 on 2025-01-27 11:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
|
||||||
|
('inventory', '0010_remove_saleorder_car_remove_saleorder_customer_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='saleorder',
|
||||||
|
name='estimate',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='sale_orders', to='django_ledger.estimatemodel', verbose_name='Estimate'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -28,7 +28,7 @@ from sqlalchemy.orm.base import object_state
|
|||||||
from .utilities.financials import get_financial_value, get_total, get_total_financials
|
from .utilities.financials import get_financial_value, get_total, get_total_financials
|
||||||
from django.db.models import FloatField
|
from django.db.models import FloatField
|
||||||
from .mixins import LocalizedNameMixin
|
from .mixins import LocalizedNameMixin
|
||||||
from django_ledger.models import EntityModel, ItemModel
|
from django_ledger.models import EntityModel, ItemModel,EstimateModel,InvoiceModel
|
||||||
from django_countries.fields import CountryField
|
from django_countries.fields import CountryField
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
@ -1541,33 +1541,54 @@ class UserActivityLog(models.Model):
|
|||||||
return f"{self.user.email} - {self.action} - {self.timestamp}"
|
return f"{self.user.email} - {self.action} - {self.timestamp}"
|
||||||
|
|
||||||
class SaleOrder(models.Model):
|
class SaleOrder(models.Model):
|
||||||
customer = models.ForeignKey(
|
estimate = models.ForeignKey(
|
||||||
Customer,
|
EstimateModel,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
related_name="sale_orders",
|
related_name="sale_orders",
|
||||||
verbose_name=_("Customer"),
|
verbose_name=_("Estimate")
|
||||||
)
|
)
|
||||||
car = models.ForeignKey(
|
invoice = models.ForeignKey(
|
||||||
Car,
|
InvoiceModel,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
related_name="sale_orders",
|
related_name="sale_orders",
|
||||||
verbose_name=_("Car"),
|
verbose_name=_("Invoice"),
|
||||||
|
null=True,
|
||||||
|
blank=True
|
||||||
)
|
)
|
||||||
payment_method = models.CharField(max_length=20, choices=[
|
payment_method = models.CharField(max_length=20, choices=[
|
||||||
('cash', 'Cash'),
|
('cash', 'Cash'),
|
||||||
('finance', 'Finance'),
|
('finance', 'Finance'),
|
||||||
('lease', 'Lease'),
|
('lease', 'Lease'),
|
||||||
])
|
])
|
||||||
trade_in = models.CharField(max_length=100, blank=True, null=True)
|
|
||||||
comments = models.TextField(blank=True, null=True)
|
comments = models.TextField(blank=True, null=True)
|
||||||
|
formatted_order_id = models.CharField(max_length=10, unique=True, editable=False)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.formatted_order_id:
|
||||||
|
last_order = SaleOrder.objects.order_by('-id').first()
|
||||||
|
if last_order:
|
||||||
|
next_id = last_order.id + 1
|
||||||
|
else:
|
||||||
|
next_id = 1
|
||||||
|
self.formatted_order_id = f"{next_id:05d}"
|
||||||
|
super().save(*args, **kwargs)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Sale Order for {self.full_name} - {self.make} {self.model}"
|
return f"Sale Order for {self.full_name}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_name(self):
|
def full_name(self):
|
||||||
return f"{self.customer.first_name} {self.customer.last_name}"
|
return f"{self.customer.customer_name}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def price(self):
|
def price(self):
|
||||||
return self.car.finances.selling_price
|
return self.car.finances.selling_price
|
||||||
|
|
||||||
|
@property
|
||||||
|
def items(self):
|
||||||
|
if self.estimate.get_itemtxs_data():
|
||||||
|
return self.estimate.get_itemtxs_data()[0]
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def customer(self):
|
||||||
|
return self.estimate.customer
|
||||||
@ -1,8 +1,10 @@
|
|||||||
from django import template
|
from django import template
|
||||||
|
from calendar import month_abbr
|
||||||
|
from django.urls import reverse
|
||||||
|
from django_ledger.io.io_core import get_localdate
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@register.filter(name='percentage')
|
@register.filter(name='percentage')
|
||||||
def percentage(value):
|
def percentage(value):
|
||||||
if value is not None:
|
if value is not None:
|
||||||
@ -31,3 +33,116 @@ def attr(field, args):
|
|||||||
attrs[definition.strip()] = True
|
attrs[definition.strip()] = True
|
||||||
return field.as_widget(attrs=attrs)
|
return field.as_widget(attrs=attrs)
|
||||||
|
|
||||||
|
|
||||||
|
@register.inclusion_tag('ledger/reports/components/period_navigator.html', takes_context=True)
|
||||||
|
def period_navigation(context, base_url: str):
|
||||||
|
kwargs = dict()
|
||||||
|
entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
kwargs['entity_slug'] = entity_slug
|
||||||
|
|
||||||
|
if context['view'].kwargs.get('ledger_pk'):
|
||||||
|
kwargs['ledger_pk'] = context['view'].kwargs.get('ledger_pk')
|
||||||
|
|
||||||
|
if context['view'].kwargs.get('account_pk'):
|
||||||
|
kwargs['account_pk'] = context['view'].kwargs.get('account_pk')
|
||||||
|
|
||||||
|
if context['view'].kwargs.get('unit_slug'):
|
||||||
|
kwargs['unit_slug'] = context['view'].kwargs.get('unit_slug')
|
||||||
|
|
||||||
|
if context['view'].kwargs.get('coa_slug'):
|
||||||
|
kwargs['coa_slug'] = context['view'].kwargs.get('coa_slug')
|
||||||
|
|
||||||
|
ctx = dict()
|
||||||
|
ctx['year'] = context['year']
|
||||||
|
ctx['has_year'] = context.get('has_year')
|
||||||
|
ctx['has_quarter'] = context.get('has_quarter')
|
||||||
|
ctx['has_month'] = context.get('has_month')
|
||||||
|
ctx['has_date'] = context.get('has_date')
|
||||||
|
ctx['previous_year'] = context['previous_year']
|
||||||
|
|
||||||
|
kwargs['year'] = context['previous_year']
|
||||||
|
ctx['previous_year_url'] = reverse(f'{base_url}-year', kwargs=kwargs)
|
||||||
|
ctx['next_year'] = context['next_year']
|
||||||
|
|
||||||
|
kwargs['year'] = context['next_year']
|
||||||
|
ctx['next_year_url'] = reverse(f'{base_url}-year', kwargs=kwargs)
|
||||||
|
|
||||||
|
kwargs['year'] = context['year']
|
||||||
|
ctx['current_year_url'] = reverse(f'{base_url}-year', kwargs=kwargs)
|
||||||
|
|
||||||
|
dt = get_localdate()
|
||||||
|
|
||||||
|
KWARGS_CURRENT_MONTH = {
|
||||||
|
'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
'year': dt.year,
|
||||||
|
'month': dt.month
|
||||||
|
}
|
||||||
|
|
||||||
|
if 'unit_slug' in kwargs:
|
||||||
|
KWARGS_CURRENT_MONTH['unit_slug'] = kwargs['unit_slug']
|
||||||
|
if 'account_pk' in kwargs:
|
||||||
|
KWARGS_CURRENT_MONTH['account_pk'] = kwargs['account_pk']
|
||||||
|
if 'ledger_pk' in kwargs:
|
||||||
|
KWARGS_CURRENT_MONTH['ledger_pk'] = kwargs['ledger_pk']
|
||||||
|
if 'coa_slug' in kwargs:
|
||||||
|
KWARGS_CURRENT_MONTH['coa_slug'] = kwargs['coa_slug']
|
||||||
|
|
||||||
|
ctx['current_month_url'] = reverse(f'{base_url}-month',
|
||||||
|
kwargs=KWARGS_CURRENT_MONTH)
|
||||||
|
|
||||||
|
quarter_urls = list()
|
||||||
|
ctx['quarter'] = context.get('quarter')
|
||||||
|
for Q in range(1, 5):
|
||||||
|
kwargs['quarter'] = Q
|
||||||
|
quarter_urls.append({
|
||||||
|
'url': reverse(f'{base_url}-quarter', kwargs=kwargs),
|
||||||
|
'quarter': Q,
|
||||||
|
'quarter_name': f'Q{Q}'
|
||||||
|
})
|
||||||
|
del kwargs['quarter']
|
||||||
|
ctx['quarter_urls'] = quarter_urls
|
||||||
|
|
||||||
|
month_urls = list()
|
||||||
|
ctx['month'] = context.get('month')
|
||||||
|
for M in range(1, 13):
|
||||||
|
kwargs['month'] = M
|
||||||
|
month_urls.append({
|
||||||
|
'url': reverse(f'{base_url}-month', kwargs=kwargs),
|
||||||
|
'month': M,
|
||||||
|
'month_abbr': month_abbr[M]
|
||||||
|
})
|
||||||
|
ctx['month_urls'] = month_urls
|
||||||
|
ctx['from_date'] = context['from_date']
|
||||||
|
ctx['to_date'] = context['to_date']
|
||||||
|
ctx.update(kwargs)
|
||||||
|
|
||||||
|
ctx['date_navigation_url'] = context.get('date_navigation_url')
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
@register.inclusion_tag('ledger/reports/tags/balance_sheet_statement.html', takes_context=True)
|
||||||
|
def balance_sheet_statement(context, io_model, to_date=None):
|
||||||
|
user_model = context['user']
|
||||||
|
activity = context['request'].GET.get('activity')
|
||||||
|
entity_slug = context['view'].kwargs.get('entity_slug')
|
||||||
|
if not to_date:
|
||||||
|
to_date = context['to_date']
|
||||||
|
|
||||||
|
io_digest = io_model.digest(
|
||||||
|
activity=activity,
|
||||||
|
user_model=user_model,
|
||||||
|
equity_only=False,
|
||||||
|
entity_slug=entity_slug,
|
||||||
|
unit_slug=context['unit_slug'],
|
||||||
|
by_unit=context['by_unit'],
|
||||||
|
to_date=to_date,
|
||||||
|
signs=True,
|
||||||
|
process_groups=True,
|
||||||
|
balance_sheet_statement=True)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'entity_slug': entity_slug,
|
||||||
|
'user_model': user_model,
|
||||||
|
'tx_digest': io_digest.get_io_data(),
|
||||||
|
}
|
||||||
|
|||||||
908
inventory/templatetags/tenhal_tag.py
Normal file
908
inventory/templatetags/tenhal_tag.py
Normal file
@ -0,0 +1,908 @@
|
|||||||
|
# """
|
||||||
|
# Django Ledger created by Miguel Sanda <msanda@arrobalytics.com>.
|
||||||
|
# Copyright© EDMA Group Inc licensed under the GPLv3 Agreement.
|
||||||
|
|
||||||
|
# Contributions to this module:
|
||||||
|
# Miguel Sanda <msanda@arrobalytics.com>
|
||||||
|
# """
|
||||||
|
|
||||||
|
from calendar import month_abbr
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
from django.db.models import Sum
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.formats import number_format
|
||||||
|
|
||||||
|
from django_ledger import __version__
|
||||||
|
from django_ledger.forms.app_filters import EntityFilterForm, ActivityFilterForm
|
||||||
|
from django_ledger.forms.feedback import BugReportForm, RequestNewFeatureForm
|
||||||
|
from django_ledger.io import CREDIT, DEBIT, ROLES_ORDER_ALL
|
||||||
|
from django_ledger.io.io_core import validate_activity, get_localdate
|
||||||
|
from django_ledger.models import TransactionModel, BillModel, InvoiceModel, EntityUnitModel
|
||||||
|
from django_ledger.settings import (
|
||||||
|
DJANGO_LEDGER_FINANCIAL_ANALYSIS, DJANGO_LEDGER_CURRENCY_SYMBOL,
|
||||||
|
DJANGO_LEDGER_SPACED_CURRENCY_SYMBOL)
|
||||||
|
from django_ledger.utils import get_default_entity_session_key, get_end_date_from_session
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
# @register.simple_tag(name='current_version')
|
||||||
|
# def current_version():
|
||||||
|
# return __version__
|
||||||
|
|
||||||
|
|
||||||
|
# @register.simple_tag(name='currency_symbol')
|
||||||
|
# def currency_symbol(spaced: bool = False):
|
||||||
|
# if spaced or DJANGO_LEDGER_SPACED_CURRENCY_SYMBOL:
|
||||||
|
# return f'{DJANGO_LEDGER_CURRENCY_SYMBOL} '
|
||||||
|
# return DJANGO_LEDGER_CURRENCY_SYMBOL
|
||||||
|
|
||||||
|
|
||||||
|
# @register.filter(name='absolute')
|
||||||
|
# def absolute(value):
|
||||||
|
# if value:
|
||||||
|
# if isinstance(value, str):
|
||||||
|
# value = float(value)
|
||||||
|
# return abs(value)
|
||||||
|
|
||||||
|
|
||||||
|
# @register.filter(name='reverse_sign')
|
||||||
|
# def reverse_sign(value):
|
||||||
|
# if value:
|
||||||
|
# if isinstance(value, str):
|
||||||
|
# value = float(value)
|
||||||
|
# return -value
|
||||||
|
|
||||||
|
|
||||||
|
# @register.filter(name='currency_format')
|
||||||
|
# def currency_format(value):
|
||||||
|
# if not value:
|
||||||
|
# value = 0.00
|
||||||
|
# return number_format(value, decimal_pos=2, use_l10n=True, force_grouping=True)
|
||||||
|
|
||||||
|
|
||||||
|
# @register.filter(name='percentage')
|
||||||
|
# def percentage(value):
|
||||||
|
# if value is not None:
|
||||||
|
# return '{0:,.2f}%'.format(value * 100)
|
||||||
|
|
||||||
|
|
||||||
|
# @register.filter(name='last_four')
|
||||||
|
# def last_four(value: str):
|
||||||
|
# if value:
|
||||||
|
# return '*' + value[-4:]
|
||||||
|
# return ''
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/icon.html')
|
||||||
|
# def icon(icon_name, size):
|
||||||
|
# return {
|
||||||
|
# 'icon': icon_name,
|
||||||
|
# 'size': size
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/financial_statements/tags/balance_sheet_statement.html', takes_context=True)
|
||||||
|
# def balance_sheet_statement(context, io_model, to_date=None):
|
||||||
|
# user_model = context['user']
|
||||||
|
# activity = context['request'].GET.get('activity')
|
||||||
|
# entity_slug = context['view'].kwargs.get('entity_slug')
|
||||||
|
|
||||||
|
# if not to_date:
|
||||||
|
# to_date = context['to_date']
|
||||||
|
|
||||||
|
# io_digest = io_model.digest(
|
||||||
|
# activity=activity,
|
||||||
|
# user_model=user_model,
|
||||||
|
# equity_only=False,
|
||||||
|
# entity_slug=entity_slug,
|
||||||
|
# unit_slug=context['unit_slug'],
|
||||||
|
# by_unit=context['by_unit'],
|
||||||
|
# to_date=to_date,
|
||||||
|
# signs=True,
|
||||||
|
# process_groups=True,
|
||||||
|
# balance_sheet_statement=True)
|
||||||
|
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'user_model': user_model,
|
||||||
|
# 'tx_digest': io_digest.get_io_data(),
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/financial_statements/tags/cash_flow_statement.html', takes_context=True)
|
||||||
|
# def cash_flow_statement(context, io_model):
|
||||||
|
# user_model = context['user']
|
||||||
|
# entity_slug = context['view'].kwargs.get('entity_slug')
|
||||||
|
# from_date = context['from_date']
|
||||||
|
# to_date = context['to_date']
|
||||||
|
|
||||||
|
# io_digest = io_model.digest(
|
||||||
|
# cash_flow_statement=True,
|
||||||
|
# by_activity=True,
|
||||||
|
# user_model=user_model,
|
||||||
|
# equity_only=False,
|
||||||
|
# signs=True,
|
||||||
|
# entity_slug=entity_slug,
|
||||||
|
# unit_slug=context['unit_slug'],
|
||||||
|
# by_unit=context['by_unit'],
|
||||||
|
# from_date=from_date,
|
||||||
|
# to_date=to_date,
|
||||||
|
# process_groups=True)
|
||||||
|
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'user_model': user_model,
|
||||||
|
# 'tx_digest': io_digest.get_io_data()
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/financial_statements/tags/income_statement.html', takes_context=True)
|
||||||
|
# def income_statement_table(context, io_model, from_date=None, to_date=None):
|
||||||
|
# user_model = context['user']
|
||||||
|
# activity = context['request'].GET.get('activity')
|
||||||
|
# activity = validate_activity(activity, raise_404=True)
|
||||||
|
# entity_slug = context['view'].kwargs.get('entity_slug')
|
||||||
|
|
||||||
|
# if not from_date:
|
||||||
|
# from_date = context['from_date']
|
||||||
|
# if not to_date:
|
||||||
|
# to_date = context['to_date']
|
||||||
|
|
||||||
|
# io_digest = io_model.digest(
|
||||||
|
# activity=activity,
|
||||||
|
# user_model=user_model,
|
||||||
|
# entity_slug=entity_slug,
|
||||||
|
# unit_slug=context['unit_slug'],
|
||||||
|
# by_unit=context['by_unit'],
|
||||||
|
# from_date=from_date,
|
||||||
|
# to_date=to_date,
|
||||||
|
# equity_only=True,
|
||||||
|
# process_groups=True,
|
||||||
|
# income_statement=True,
|
||||||
|
# signs=True
|
||||||
|
# )
|
||||||
|
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'user_model': user_model,
|
||||||
|
# 'tx_digest': io_digest.get_io_data()
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/bank_account/tags/bank_accounts_table.html', takes_context=True)
|
||||||
|
# def bank_account_table(context, bank_account_qs):
|
||||||
|
# entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
# return {
|
||||||
|
# 'bank_account_qs': bank_account_qs,
|
||||||
|
# 'entity_slug': entity_slug
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/data_import/tags/data_import_job_list_table.html', takes_context=True)
|
||||||
|
# def data_import_job_list_table(context):
|
||||||
|
# return context
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/data_import/tags/data_import_job_txs_table.html', takes_context=True)
|
||||||
|
# def data_import_job_txs_pending(context, staged_txs_formset):
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'job_pk': context['view'].kwargs['job_pk'],
|
||||||
|
# 'staged_txs_formset': staged_txs_formset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/data_import/tags/data_import_job_txs_imported.html', takes_context=True)
|
||||||
|
# def data_import_job_txs_imported(context, staged_txs_qs):
|
||||||
|
# imported_txs = [stx for stx in staged_txs_qs if stx.is_imported()]
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'job_pk': context['view'].kwargs['job_pk'],
|
||||||
|
# 'imported_txs': imported_txs
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/journal_entry/tags/je_table.html', takes_context=True)
|
||||||
|
# def jes_table(context, journal_entry_qs, next_url=None):
|
||||||
|
# entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
# ledger_pk = context['view'].kwargs['ledger_pk']
|
||||||
|
# if not next_url:
|
||||||
|
# next_url = reverse('django_ledger:je-list',
|
||||||
|
# kwargs={
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'ledger_pk': ledger_pk
|
||||||
|
# })
|
||||||
|
# return {
|
||||||
|
# 'jes': journal_entry_qs,
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'ledger_pk': ledger_pk,
|
||||||
|
# 'next_url': next_url
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/journal_entry/tags/je_txs_table.html')
|
||||||
|
# def journal_entry_txs_table(journal_entry_model, style='detail'):
|
||||||
|
# txs_queryset = journal_entry_model.transactionmodel_set.all().select_related('account').order_by('account__code')
|
||||||
|
# total_credits = sum(tx.amount for tx in txs_queryset if tx.tx_type == 'credit')
|
||||||
|
# total_debits = sum(tx.amount for tx in txs_queryset if tx.tx_type == 'debit')
|
||||||
|
# return {
|
||||||
|
# 'txs': txs_queryset,
|
||||||
|
# 'total_debits': total_debits,
|
||||||
|
# 'total_credits': total_credits,
|
||||||
|
# 'style': style
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/journal_entry/tags/je_txs_table.html', takes_context=True)
|
||||||
|
# def bill_txs_table(context, bill_model: BillModel):
|
||||||
|
# # todo: move this to bill model...
|
||||||
|
# txs_queryset = TransactionModel.objects.for_bill(
|
||||||
|
# bill_model=bill_model.uuid,
|
||||||
|
# user_model=context['request'].user,
|
||||||
|
# entity_slug=context['view'].kwargs['entity_slug']
|
||||||
|
# ).select_related('journal_entry', 'journal_entry__entity_unit', 'account').order_by('-journal_entry__timestamp')
|
||||||
|
# total_credits = sum(tx.amount for tx in txs_queryset if tx.tx_type == CREDIT)
|
||||||
|
# total_debits = sum(tx.amount for tx in txs_queryset if tx.tx_type == DEBIT)
|
||||||
|
# return {
|
||||||
|
# 'style': 'detail',
|
||||||
|
# 'txs': txs_queryset,
|
||||||
|
# 'total_debits': total_debits,
|
||||||
|
# 'total_credits': total_credits
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/journal_entry/tags/je_txs_table.html', takes_context=True)
|
||||||
|
# def invoice_txs_table(context, invoice_model: InvoiceModel):
|
||||||
|
# txs_queryset = TransactionModel.objects.for_invoice(
|
||||||
|
# invoice_model=invoice_model,
|
||||||
|
# user_model=context['request'].user,
|
||||||
|
# entity_slug=context['view'].kwargs['entity_slug']
|
||||||
|
# ).select_related('journal_entry', 'journal_entry__entity_unit', 'account').order_by('-journal_entry__timestamp')
|
||||||
|
# total_credits = sum(tx.amount for tx in txs_queryset if tx.tx_type == CREDIT)
|
||||||
|
# total_debits = sum(tx.amount for tx in txs_queryset if tx.tx_type == DEBIT)
|
||||||
|
# return {
|
||||||
|
# 'style': 'detail',
|
||||||
|
# 'txs': txs_queryset,
|
||||||
|
# 'total_debits': total_debits,
|
||||||
|
# 'total_credits': total_credits
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/ledger/tags/ledgers_table.html', takes_context=True)
|
||||||
|
# def ledgers_table(context, ledger_model_qs):
|
||||||
|
# return {
|
||||||
|
# 'ledgers': ledger_model_qs,
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/invoice/tags/invoice_table.html', takes_context=True)
|
||||||
|
# def invoice_table(context, invoice_qs):
|
||||||
|
# return {
|
||||||
|
# 'invoices': invoice_qs,
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug']
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/bills/tags/bill_table.html', takes_context=True)
|
||||||
|
# def bill_table(context, bill_qs):
|
||||||
|
# return {
|
||||||
|
# 'bills': bill_qs,
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug']
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/closing_entry/tags/closing_entry_table.html', takes_context=True)
|
||||||
|
# def closing_entry_table(context, closing_entry_qs):
|
||||||
|
# return {
|
||||||
|
# 'closing_entry_list': closing_entry_qs,
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug']
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/closing_entry/tags/closing_entry_txs_table.html', takes_context=True)
|
||||||
|
# def closing_entry_txs_table(context, closing_entry_txs_qs):
|
||||||
|
# ce_txs_list = list(closing_entry_txs_qs)
|
||||||
|
# ce_txs_list.sort(key=lambda ce_txs: ROLES_ORDER_ALL.index(ce_txs.account_model.role))
|
||||||
|
# return {
|
||||||
|
# 'ce_txs_list': ce_txs_list,
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug']
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/purchase_order/includes/po_table.html', takes_context=True)
|
||||||
|
# def po_table(context, purchase_order_qs):
|
||||||
|
# return {
|
||||||
|
# 'po_list': purchase_order_qs,
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug']
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/account/tags/accounts_table.html', takes_context=True)
|
||||||
|
# def accounts_table(context, accounts_qs, title=None):
|
||||||
|
# return {
|
||||||
|
# 'title': title,
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'accounts_gb': accounts_qs.gb_bs_role(),
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/customer/tags/customer_table.html', takes_context=True)
|
||||||
|
# def customer_table(context):
|
||||||
|
# return context
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/vendor/tags/vendor_table.html', takes_context=True)
|
||||||
|
# def vendor_table(context):
|
||||||
|
# return context
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/account/tags/account_txs_table.html', takes_context=True)
|
||||||
|
# def account_txs_table(context, txs_qs):
|
||||||
|
# return {
|
||||||
|
# 'transactions': txs_qs,
|
||||||
|
# 'total_credits': sum(tx.amount for tx in txs_qs if tx.tx_type == 'credit'),
|
||||||
|
# 'total_debits': sum(tx.amount for tx in txs_qs if tx.tx_type == 'debit'),
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'account_pk': context['view'].kwargs['account_pk']
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/breadcrumbs.html', takes_context=True)
|
||||||
|
# def nav_breadcrumbs(context):
|
||||||
|
# entity_slug = context['view'].kwargs.get('entity_slug')
|
||||||
|
# coa_slug = context['view'].kwargs.get('coa_slug')
|
||||||
|
# ledger_pk = context['view'].kwargs.get('entity_slug')
|
||||||
|
# account_pk = context['view'].kwargs.get('account_pk')
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'coa_slug': coa_slug,
|
||||||
|
# 'ledger_pk': ledger_pk,
|
||||||
|
# 'account_pk': account_pk
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/default_entity.html', takes_context=True)
|
||||||
|
# def default_entity(context):
|
||||||
|
# user = context['user']
|
||||||
|
# session_key = get_default_entity_session_key()
|
||||||
|
# session = context['request'].session
|
||||||
|
# session_entity_data = session.get(session_key)
|
||||||
|
# identity = randint(0, 1000000)
|
||||||
|
# try:
|
||||||
|
# entity_uuid = session_entity_data['entity_uuid']
|
||||||
|
# default_entity_form = EntityFilterForm(
|
||||||
|
# user_model=user,
|
||||||
|
# form_id=identity,
|
||||||
|
# current_entity_uuid=entity_uuid
|
||||||
|
# )
|
||||||
|
# except TypeError or KeyError:
|
||||||
|
# default_entity_form = EntityFilterForm(
|
||||||
|
# user_model=user,
|
||||||
|
# form_id=identity,
|
||||||
|
# )
|
||||||
|
|
||||||
|
# return {
|
||||||
|
# 'default_entity_form': default_entity_form,
|
||||||
|
# 'form_id': identity,
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.simple_tag(takes_context=True)
|
||||||
|
# def session_entity_name(context, request=None):
|
||||||
|
# session_key = get_default_entity_session_key()
|
||||||
|
# if not request:
|
||||||
|
# request = context.get('request')
|
||||||
|
# try:
|
||||||
|
# session = request.session
|
||||||
|
# entity_name = session.get(session_key)['entity_name']
|
||||||
|
# except AttributeError:
|
||||||
|
# entity_name = 'Django Ledger'
|
||||||
|
# except KeyError:
|
||||||
|
# entity_name = 'Django Ledger'
|
||||||
|
# except TypeError:
|
||||||
|
# entity_name = 'Django Ledger'
|
||||||
|
# return entity_name
|
||||||
|
|
||||||
|
|
||||||
|
# # todo: rename template to activity_form_filter.
|
||||||
|
# @register.inclusion_tag('django_ledger/components/activity_form.html', takes_context=True)
|
||||||
|
# def activity_filter(context):
|
||||||
|
# request = context['request']
|
||||||
|
# activity = request.GET.get('activity')
|
||||||
|
# if activity:
|
||||||
|
# activity_form = ActivityFilterForm(initial={
|
||||||
|
# 'activity': activity
|
||||||
|
# })
|
||||||
|
# else:
|
||||||
|
# activity_form = ActivityFilterForm()
|
||||||
|
|
||||||
|
# return {
|
||||||
|
# 'activity_form': activity_form,
|
||||||
|
# 'form_path': context['request'].path
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/date_picker.html', takes_context=True)
|
||||||
|
# def date_picker(context, nav_url=None, date_picker_id=None):
|
||||||
|
# try:
|
||||||
|
# entity_slug = context['view'].kwargs.get('entity_slug')
|
||||||
|
# except KeyError:
|
||||||
|
# entity_slug = context['entity_slug']
|
||||||
|
|
||||||
|
# if not date_picker_id:
|
||||||
|
# date_picker_id = f'djl-datepicker-{randint(10000, 99999)}'
|
||||||
|
|
||||||
|
# if 'date_picker_ids' not in context:
|
||||||
|
# context['date_picker_ids'] = list()
|
||||||
|
# context['date_picker_ids'].append(date_picker_id)
|
||||||
|
|
||||||
|
# date_navigation_url = nav_url if nav_url else context.get('date_navigation_url')
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'date_picker_id': date_picker_id,
|
||||||
|
# 'date_navigation_url': date_navigation_url
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.simple_tag(takes_context=True)
|
||||||
|
# def get_current_end_date_filter(context):
|
||||||
|
# entity_slug = context['view'].kwargs.get('entity_slug')
|
||||||
|
# return get_end_date_from_session(entity_slug, context['request'])
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/chart_container.html')
|
||||||
|
# def chart_container(chart_id, endpoint=None):
|
||||||
|
# return {
|
||||||
|
# 'chart_id': chart_id,
|
||||||
|
# 'endpoint': endpoint
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/modals.html', takes_context=True)
|
||||||
|
# def modal_action(context, model, http_method: str = 'post', entity_slug: str = None):
|
||||||
|
# if not entity_slug:
|
||||||
|
# entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
# action_url = model.get_mark_as_paid_url(entity_slug=entity_slug)
|
||||||
|
# return {
|
||||||
|
# 'object': model,
|
||||||
|
# 'action_url': action_url,
|
||||||
|
# 'http_method': http_method,
|
||||||
|
# 'message': f'Do you want to mark {model.__class__._meta.verbose_name} {model.get_document_id()} as paid?'
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/modals_v2.html', takes_context=True)
|
||||||
|
# def modal_action_v2(context, model, action_url: str, message: str, html_id: str, http_method: str = 'get'):
|
||||||
|
# return {
|
||||||
|
# 'object': model,
|
||||||
|
# 'action_url': action_url,
|
||||||
|
# 'http_method': http_method,
|
||||||
|
# 'message': message,
|
||||||
|
# 'html_id': html_id
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.simple_tag
|
||||||
|
# def fin_ratio_max_value(ratio: str):
|
||||||
|
# params = DJANGO_LEDGER_FINANCIAL_ANALYSIS['ratios'][ratio]['ranges']
|
||||||
|
# return params['healthy']
|
||||||
|
|
||||||
|
|
||||||
|
# @register.filter
|
||||||
|
# def fin_ratio_threshold_class(value, ratio):
|
||||||
|
# if value:
|
||||||
|
# params = DJANGO_LEDGER_FINANCIAL_ANALYSIS['ratios'][ratio]
|
||||||
|
# ranges = params['ranges']
|
||||||
|
|
||||||
|
# if params['good_incremental']:
|
||||||
|
# if value <= ranges['critical']:
|
||||||
|
# return 'is-danger'
|
||||||
|
# elif value <= ranges['warning']:
|
||||||
|
# return 'is-warning'
|
||||||
|
# elif value <= ranges['watch']:
|
||||||
|
# return 'is-primary'
|
||||||
|
# return 'is-success'
|
||||||
|
# else:
|
||||||
|
# if value >= ranges['critical']:
|
||||||
|
# return 'is-danger'
|
||||||
|
# elif value >= ranges['warning']:
|
||||||
|
# return 'is-warning'
|
||||||
|
# elif value >= ranges['watch']:
|
||||||
|
# return 'is-primary'
|
||||||
|
# return 'is-success'
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/feedback_button.html', takes_context=True)
|
||||||
|
# def feedback_button(context, button_size_class: str = 'is-small', color_class: str = 'is-success', icon_id: str = None):
|
||||||
|
# bug_modal_html_id = f'djl-bug-button-{randint(10000, 99999)}'
|
||||||
|
# feature_modal_html_id = f'djl-feature-button-{randint(10000, 99999)}'
|
||||||
|
# bug_form = BugReportForm()
|
||||||
|
# feature_form = RequestNewFeatureForm()
|
||||||
|
# next_url = context['request'].path
|
||||||
|
# return {
|
||||||
|
# 'icon_id': icon_id,
|
||||||
|
# 'bug_modal_html_id': bug_modal_html_id,
|
||||||
|
# 'feature_modal_html_id': feature_modal_html_id,
|
||||||
|
# 'button_size_class': button_size_class,
|
||||||
|
# 'color_class': color_class,
|
||||||
|
# 'bug_form': bug_form,
|
||||||
|
# 'feature_form': feature_form,
|
||||||
|
# 'next_url': next_url
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
@register.inclusion_tag('inventory/ledger/reports/components/period_navigator.html', takes_context=True)
|
||||||
|
def period_navigation(context, base_url: str):
|
||||||
|
kwargs = dict()
|
||||||
|
entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
kwargs['entity_slug'] = entity_slug
|
||||||
|
|
||||||
|
if context['view'].kwargs.get('ledger_pk'):
|
||||||
|
kwargs['ledger_pk'] = context['view'].kwargs.get('ledger_pk')
|
||||||
|
|
||||||
|
if context['view'].kwargs.get('account_pk'):
|
||||||
|
kwargs['account_pk'] = context['view'].kwargs.get('account_pk')
|
||||||
|
|
||||||
|
if context['view'].kwargs.get('unit_slug'):
|
||||||
|
kwargs['unit_slug'] = context['view'].kwargs.get('unit_slug')
|
||||||
|
|
||||||
|
if context['view'].kwargs.get('coa_slug'):
|
||||||
|
kwargs['coa_slug'] = context['view'].kwargs.get('coa_slug')
|
||||||
|
|
||||||
|
ctx = dict()
|
||||||
|
ctx['year'] = context['year']
|
||||||
|
ctx['has_year'] = context.get('has_year')
|
||||||
|
ctx['has_quarter'] = context.get('has_quarter')
|
||||||
|
ctx['has_month'] = context.get('has_month')
|
||||||
|
ctx['has_date'] = context.get('has_date')
|
||||||
|
ctx['previous_year'] = context['previous_year']
|
||||||
|
|
||||||
|
kwargs['year'] = context['previous_year']
|
||||||
|
ctx['previous_year_url'] = reverse(f'django_ledger:{base_url}-year', kwargs=kwargs)
|
||||||
|
ctx['next_year'] = context['next_year']
|
||||||
|
|
||||||
|
kwargs['year'] = context['next_year']
|
||||||
|
ctx['next_year_url'] = reverse(f'django_ledger:{base_url}-year', kwargs=kwargs)
|
||||||
|
|
||||||
|
kwargs['year'] = context['year']
|
||||||
|
ctx['current_year_url'] = reverse(f'django_ledger:{base_url}-year', kwargs=kwargs)
|
||||||
|
|
||||||
|
dt = get_localdate()
|
||||||
|
|
||||||
|
KWARGS_CURRENT_MONTH = {
|
||||||
|
'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
'year': dt.year,
|
||||||
|
'month': dt.month
|
||||||
|
}
|
||||||
|
|
||||||
|
if 'unit_slug' in kwargs:
|
||||||
|
KWARGS_CURRENT_MONTH['unit_slug'] = kwargs['unit_slug']
|
||||||
|
if 'account_pk' in kwargs:
|
||||||
|
KWARGS_CURRENT_MONTH['account_pk'] = kwargs['account_pk']
|
||||||
|
if 'ledger_pk' in kwargs:
|
||||||
|
KWARGS_CURRENT_MONTH['ledger_pk'] = kwargs['ledger_pk']
|
||||||
|
if 'coa_slug' in kwargs:
|
||||||
|
KWARGS_CURRENT_MONTH['coa_slug'] = kwargs['coa_slug']
|
||||||
|
|
||||||
|
ctx['current_month_url'] = reverse(f'django_ledger:{base_url}-month',
|
||||||
|
kwargs=KWARGS_CURRENT_MONTH)
|
||||||
|
|
||||||
|
quarter_urls = list()
|
||||||
|
ctx['quarter'] = context.get('quarter')
|
||||||
|
for Q in range(1, 5):
|
||||||
|
kwargs['quarter'] = Q
|
||||||
|
quarter_urls.append({
|
||||||
|
'url': reverse(f'django_ledger:{base_url}-quarter', kwargs=kwargs),
|
||||||
|
'quarter': Q,
|
||||||
|
'quarter_name': f'Q{Q}'
|
||||||
|
})
|
||||||
|
del kwargs['quarter']
|
||||||
|
ctx['quarter_urls'] = quarter_urls
|
||||||
|
|
||||||
|
month_urls = list()
|
||||||
|
ctx['month'] = context.get('month')
|
||||||
|
for M in range(1, 13):
|
||||||
|
kwargs['month'] = M
|
||||||
|
month_urls.append({
|
||||||
|
'url': reverse(f'django_ledger:{base_url}-month', kwargs=kwargs),
|
||||||
|
'month': M,
|
||||||
|
'month_abbr': month_abbr[M]
|
||||||
|
})
|
||||||
|
ctx['month_urls'] = month_urls
|
||||||
|
ctx['from_date'] = context['from_date']
|
||||||
|
ctx['to_date'] = context['to_date']
|
||||||
|
ctx.update(kwargs)
|
||||||
|
|
||||||
|
ctx['date_navigation_url'] = context.get('date_navigation_url')
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/components/menu.html', takes_context=True)
|
||||||
|
# def navigation_menu(context, style):
|
||||||
|
# ENTITY_SLUG = context['view'].kwargs.get('entity_slug')
|
||||||
|
|
||||||
|
# ctx = dict()
|
||||||
|
# ctx['style'] = style
|
||||||
|
# if ENTITY_SLUG:
|
||||||
|
# ctx['entity_slug'] = ENTITY_SLUG
|
||||||
|
# nav_menu_links = [
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Entity Dashboard',
|
||||||
|
# 'url': reverse('django_ledger:entity-dashboard', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'links',
|
||||||
|
# 'title': 'Management',
|
||||||
|
# 'links': [
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Vendors',
|
||||||
|
# 'url': reverse('django_ledger:vendor-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Customers',
|
||||||
|
# 'url': reverse('django_ledger:customer-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Bank Accounts',
|
||||||
|
# 'url': reverse('django_ledger:bank-account-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Estimates & Contracts',
|
||||||
|
# 'url': reverse('django_ledger:customer-estimate-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Bills',
|
||||||
|
# 'url': reverse('django_ledger:bill-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Invoices',
|
||||||
|
# 'url': reverse('django_ledger:invoice-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Purchase Orders',
|
||||||
|
# 'url': reverse('django_ledger:po-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Inventory',
|
||||||
|
# 'url': reverse('django_ledger:inventory-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Closing Entries',
|
||||||
|
# 'url': reverse('django_ledger:closing-entry-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# }
|
||||||
|
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'links',
|
||||||
|
# 'title': 'Your Lists',
|
||||||
|
# 'links': [
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Entity Units',
|
||||||
|
# 'url': reverse('django_ledger:unit-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Products',
|
||||||
|
# 'url': reverse('django_ledger:product-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Services',
|
||||||
|
# 'url': reverse('django_ledger:service-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Business Expenses',
|
||||||
|
# 'url': reverse('django_ledger:expense-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Inventory Items',
|
||||||
|
# 'url': reverse('django_ledger:inventory-item-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Unit of Measures',
|
||||||
|
# 'url': reverse('django_ledger:uom-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'links',
|
||||||
|
# 'title': 'Reports',
|
||||||
|
# 'links': [
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Balance Sheet',
|
||||||
|
# 'url': reverse('django_ledger:entity-bs', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Income Statement',
|
||||||
|
# 'url': reverse('django_ledger:entity-ic', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Cash Flow Statement',
|
||||||
|
# 'url': reverse('django_ledger:entity-cf', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'links',
|
||||||
|
# 'title': 'Accounting',
|
||||||
|
# 'links': [
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Chart of Accounts',
|
||||||
|
# 'url': reverse('django_ledger:coa-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Ledgers',
|
||||||
|
# 'url': reverse('django_ledger:ledger-list-visible', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Data Import',
|
||||||
|
# 'url': reverse('django_ledger:data-import-jobs-list', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'links',
|
||||||
|
# 'title': 'Administration',
|
||||||
|
# 'links': [
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'My Entities',
|
||||||
|
# 'url': reverse('django_ledger:home')
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# 'type': 'link',
|
||||||
|
# 'title': 'Entity Settings',
|
||||||
|
# 'url': reverse('django_ledger:entity-update', kwargs={'entity_slug': ENTITY_SLUG})
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
# ctx['links'] = nav_menu_links
|
||||||
|
# ctx['request'] = context['request']
|
||||||
|
# return ctx
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/product/tags/product_table.html', takes_context=True)
|
||||||
|
# def product_table(context, queryset):
|
||||||
|
# entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'product_list': queryset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/service/tags/services_table.html', takes_context=True)
|
||||||
|
# def service_table(context, queryset):
|
||||||
|
# entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'service_list': queryset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/expense/tags/expense_item_table.html', takes_context=True)
|
||||||
|
# def expense_item_table(context, queryset):
|
||||||
|
# entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'expense_list': queryset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/inventory/tags/inventory_item_table.html', takes_context=True)
|
||||||
|
# def inventory_item_table(context, queryset):
|
||||||
|
# entity_slug = context['view'].kwargs['entity_slug']
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': entity_slug,
|
||||||
|
# 'inventory_item_list': queryset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/invoice/tags/invoice_item_formset.html', takes_context=True)
|
||||||
|
# def invoice_item_formset_table(context, itemtxs_formset):
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'invoice_model': context['invoice'],
|
||||||
|
# 'total_amount__sum': context['total_amount__sum'],
|
||||||
|
# 'itemtxs_formset': itemtxs_formset,
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/bills/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,
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/purchase_order/includes/po_item_formset.html', takes_context=True)
|
||||||
|
# def po_item_formset_table(context, po_model, itemtxs_formset):
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'po_model': po_model,
|
||||||
|
# 'itemtxs_formset': itemtxs_formset,
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/uom/tags/uom_table.html', takes_context=True)
|
||||||
|
# def uom_table(context, uom_queryset):
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'uom_list': uom_queryset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/inventory/tags/inventory_table.html', takes_context=True)
|
||||||
|
# def inventory_table(context, queryset):
|
||||||
|
# ctx = {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'inventory_list': queryset
|
||||||
|
# }
|
||||||
|
# ctx.update(queryset.aggregate(inventory_total_value=Sum('total_value')))
|
||||||
|
# return ctx
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/estimate/includes/estimate_table.html', takes_context=True)
|
||||||
|
# def customer_estimate_table(context, queryset):
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'ce_list': queryset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/estimate/includes/estimate_item_table.html', takes_context=True)
|
||||||
|
# def estimate_item_table(context, queryset):
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'ce_model': context['estimate_model'],
|
||||||
|
# 'ce_item_list': queryset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/purchase_order/tags/po_item_table.html', takes_context=True)
|
||||||
|
# def po_item_table(context, queryset):
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'po_model': context['po_model'],
|
||||||
|
# 'po_item_list': queryset
|
||||||
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
# @register.inclusion_tag('django_ledger/estimate/tags/ce_item_formset.html', takes_context=True)
|
||||||
|
# def customer_estimate_item_formset(context, item_formset):
|
||||||
|
# return {
|
||||||
|
# 'entity_slug': context['view'].kwargs['entity_slug'],
|
||||||
|
# 'ce_pk': context['view'].kwargs['ce_pk'],
|
||||||
|
# 'ce_revenue_estimate__sum': context['ce_revenue_estimate__sum'],
|
||||||
|
# 'ce_cost_estimate__sum': context['ce_cost_estimate__sum'],
|
||||||
|
# 'item_formset': item_formset,
|
||||||
|
# }
|
||||||
@ -279,6 +279,7 @@ urlpatterns = [
|
|||||||
views.payment_create,
|
views.payment_create,
|
||||||
name="payment_create",
|
name="payment_create",
|
||||||
),
|
),
|
||||||
|
|
||||||
# Users URLs
|
# Users URLs
|
||||||
path("user/create/", views.UserCreateView.as_view(), name="user_create"),
|
path("user/create/", views.UserCreateView.as_view(), name="user_create"),
|
||||||
path("user/<int:pk>/update/", views.UserUpdateView.as_view(), name="user_update"),
|
path("user/<int:pk>/update/", views.UserUpdateView.as_view(), name="user_update"),
|
||||||
@ -403,6 +404,7 @@ urlpatterns = [
|
|||||||
"sales/estimates/<uuid:pk>/send_email", views.send_email_view, name="send_email"
|
"sales/estimates/<uuid:pk>/send_email", views.send_email_view, name="send_email"
|
||||||
),
|
),
|
||||||
path('sales/estimates/<uuid:pk>/sale_order/', views.create_sale_order, name='create_sale_order'),
|
path('sales/estimates/<uuid:pk>/sale_order/', views.create_sale_order, name='create_sale_order'),
|
||||||
|
path('sales/estimates/<uuid:pk>/sale_order/preview/', views.preview_sale_order, name='preview_sale_order'),
|
||||||
|
|
||||||
# Invoice
|
# Invoice
|
||||||
path("sales/invoices/", views.InvoiceListView.as_view(), name="invoice_list"),
|
path("sales/invoices/", views.InvoiceListView.as_view(), name="invoice_list"),
|
||||||
@ -523,6 +525,28 @@ urlpatterns = [
|
|||||||
views.bill_mark_as_paid,
|
views.bill_mark_as_paid,
|
||||||
name="bill_mark_as_paid",
|
name="bill_mark_as_paid",
|
||||||
),
|
),
|
||||||
|
|
||||||
|
# orders
|
||||||
|
path("orders/", views.OrderListView.as_view(), name="order_list"),
|
||||||
|
|
||||||
|
# BALANCE SHEET Reports...
|
||||||
|
# Entities...
|
||||||
|
path('entity/<slug:entity_slug>/balance-sheet/',
|
||||||
|
views.BaseBalanceSheetRedirectView.as_view(),
|
||||||
|
name='entity-bs'),
|
||||||
|
path('entity/<slug:entity_slug>/balance-sheet/year/<int:year>/',
|
||||||
|
views.FiscalYearBalanceSheetViewBase.as_view(),
|
||||||
|
name='entity-bs-year'),
|
||||||
|
path('entity/<slug:entity_slug>/balance-sheet/quarter/<int:year>/<int:quarter>/',
|
||||||
|
views.QuarterlyBalanceSheetView.as_view(),
|
||||||
|
name='entity-bs-quarter'),
|
||||||
|
path('entity/<slug:entity_slug>/balance-sheet/month/<int:year>/<int:month>/',
|
||||||
|
views.MonthlyBalanceSheetView.as_view(),
|
||||||
|
name='entity-bs-month'),
|
||||||
|
path('entity/<slug:entity_slug>/balance-sheet/date/<int:year>/<int:month>/<int:day>/',
|
||||||
|
views.DateBalanceSheetView.as_view(),
|
||||||
|
name='entity-bs-date'),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,13 @@ from django.core.mail import send_mail
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from inventory.utilities.financials import get_financial_value
|
from inventory.utilities.financials import get_financial_value
|
||||||
from django_ledger.models.items import ItemModel
|
from django_ledger.models.items import ItemModel
|
||||||
from django_ledger.models import InvoiceModel, EstimateModel,BillModel,VendorModel,CustomerModel
|
from django_ledger.models import (
|
||||||
|
InvoiceModel,
|
||||||
|
EstimateModel,
|
||||||
|
BillModel,
|
||||||
|
VendorModel,
|
||||||
|
CustomerModel,
|
||||||
|
)
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
|
||||||
@ -123,6 +129,73 @@ def calculate_vat_amount(amount):
|
|||||||
return amount
|
return amount
|
||||||
|
|
||||||
|
|
||||||
|
def get_car_finance_data(model):
|
||||||
|
vat = models.VatRate.objects.filter(is_active=True).first()
|
||||||
|
data = model.get_itemtxs_data()[0].all()
|
||||||
|
total = sum(
|
||||||
|
[
|
||||||
|
Decimal(item.item_model.additional_info["car_finance"]["selling_price"])
|
||||||
|
* Decimal(item.ce_quantity or item.quantity)
|
||||||
|
for item in data
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
additional_services = []
|
||||||
|
|
||||||
|
for i in data:
|
||||||
|
if i.item_model.additional_info["additional_services"]:
|
||||||
|
additional_services.extend(
|
||||||
|
[
|
||||||
|
{"name": x.name, "price": x.price}
|
||||||
|
for x in i.item_model.additional_info["additional_services"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"cars": [
|
||||||
|
{
|
||||||
|
"vin": x.item_model.additional_info["car_info"]["vin"],
|
||||||
|
"make": x.item_model.additional_info["car_info"]["make"],
|
||||||
|
"model": x.item_model.additional_info["car_info"]["model"],
|
||||||
|
"year": x.item_model.additional_info["car_info"]["year"],
|
||||||
|
"trim": x.item_model.additional_info["car_info"]["mileage"],
|
||||||
|
"cost_price": x.item_model.additional_info["car_finance"]["cost_price"],
|
||||||
|
"selling_price": x.item_model.additional_info["car_finance"][
|
||||||
|
"selling_price"
|
||||||
|
],
|
||||||
|
"discount": x.item_model.additional_info["car_finance"][
|
||||||
|
"discount_amount"
|
||||||
|
],
|
||||||
|
"quantity": x.ce_quantity or x.quantity,
|
||||||
|
"unit_price": Decimal(x.item_model.additional_info["car_finance"]["total"]),
|
||||||
|
"total": Decimal(x.item_model.additional_info["car_finance"]["total"]) * Decimal(x.quantity or x.ce_quantity),
|
||||||
|
"total_vat": x.item_model.additional_info["car_finance"]["total_vat"],
|
||||||
|
"additional_services": x.item_model.additional_info[
|
||||||
|
"additional_services"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
for x in data
|
||||||
|
],
|
||||||
|
"quantity": sum((x.quantity or x.ce_quantity) for x in data),
|
||||||
|
"total_price": total,
|
||||||
|
"total_vat": (total * vat.rate) + total,
|
||||||
|
"total_discount": sum(
|
||||||
|
Decimal(x.item_model.additional_info["car_finance"]["discount_amount"])
|
||||||
|
for x in data
|
||||||
|
),
|
||||||
|
"grand_total": Decimal(total * vat.rate)
|
||||||
|
+ total
|
||||||
|
- Decimal(
|
||||||
|
sum(
|
||||||
|
Decimal(x.item_model.additional_info["car_finance"]["discount_amount"])
|
||||||
|
for x in data
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"additionals": additional_services,
|
||||||
|
"vat": vat.rate,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_financial_values(model):
|
def get_financial_values(model):
|
||||||
vat = models.VatRate.objects.filter(is_active=True).first()
|
vat = models.VatRate.objects.filter(is_active=True).first()
|
||||||
|
|
||||||
@ -155,21 +228,27 @@ def get_financial_values(model):
|
|||||||
data = model.ce_model.get_itemtxs_data()[0].all()
|
data = model.ce_model.get_itemtxs_data()[0].all()
|
||||||
else:
|
else:
|
||||||
data = model.get_itemtxs_data()[0].all()
|
data = model.get_itemtxs_data()[0].all()
|
||||||
total = sum([Decimal(item.item_model.additional_info["car_finance"]["selling_price"]) * Decimal(item.ce_quantity or item.quantity) for item in data])
|
total = sum(
|
||||||
|
[
|
||||||
|
Decimal(item.item_model.additional_info["car_finance"]["selling_price"])
|
||||||
|
* Decimal(item.ce_quantity or item.quantity)
|
||||||
|
for item in data
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
discount_amount = sum(
|
discount_amount = sum(
|
||||||
Decimal(i.item_model.additional_info['car_finance']["discount_amount"])
|
Decimal(i.item_model.additional_info["car_finance"]["discount_amount"])
|
||||||
for i in data
|
for i in data
|
||||||
)
|
)
|
||||||
|
|
||||||
additional_services = []
|
additional_services = []
|
||||||
|
|
||||||
for i in data:
|
for i in data:
|
||||||
if i.item_model.additional_info['additional_services']:
|
if i.item_model.additional_info["additional_services"]:
|
||||||
additional_services.extend(
|
additional_services.extend(
|
||||||
[
|
[
|
||||||
{"name": x.name, "price": x.price}
|
{"name": x.name, "price": x.price}
|
||||||
for x in i.item_model.additional_info['additional_services']
|
for x in i.item_model.additional_info["additional_services"]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -178,10 +257,12 @@ def get_financial_values(model):
|
|||||||
|
|
||||||
car_and_item_info = [
|
car_and_item_info = [
|
||||||
{
|
{
|
||||||
"info": x.item_model.additional_info['car_info'],
|
"info": x.item_model.additional_info["car_info"],
|
||||||
"finances": x.item_model.additional_info['car_finance'],
|
"finances": x.item_model.additional_info["car_finance"],
|
||||||
"quantity": x.ce_quantity or x.quantity,
|
"quantity": x.ce_quantity or x.quantity,
|
||||||
"total": Decimal(x.item_model.additional_info['car_finance']['selling_price'])
|
"total": Decimal(
|
||||||
|
x.item_model.additional_info["car_finance"]["selling_price"]
|
||||||
|
)
|
||||||
* Decimal(x.ce_quantity or x.quantity),
|
* Decimal(x.ce_quantity or x.quantity),
|
||||||
}
|
}
|
||||||
for x in data
|
for x in data
|
||||||
@ -288,7 +369,6 @@ def set_bill_payment(dealer, entity, bill, amount, payment_method):
|
|||||||
name="Accounts Payable", active=True
|
name="Accounts Payable", active=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
TransactionModel.objects.create(
|
TransactionModel.objects.create(
|
||||||
journal_entry=journal,
|
journal_entry=journal,
|
||||||
account=cash_account, # Debit Cash
|
account=cash_account, # Debit Cash
|
||||||
@ -309,7 +389,7 @@ def set_bill_payment(dealer, entity, bill, amount, payment_method):
|
|||||||
bill.save()
|
bill.save()
|
||||||
|
|
||||||
|
|
||||||
def transfer_to_dealer(request,cars, to_dealer, remarks=None):
|
def transfer_to_dealer(request, cars, to_dealer, remarks=None):
|
||||||
dealer = get_user_type(request)
|
dealer = get_user_type(request)
|
||||||
|
|
||||||
if not cars:
|
if not cars:
|
||||||
@ -338,29 +418,35 @@ def transfer_to_dealer(request,cars, to_dealer, remarks=None):
|
|||||||
car.dealer = to_dealer
|
car.dealer = to_dealer
|
||||||
car.save()
|
car.save()
|
||||||
|
|
||||||
def transfer_car(car,transfer):
|
|
||||||
|
def transfer_car(car, transfer):
|
||||||
from_dealer = transfer.from_dealer
|
from_dealer = transfer.from_dealer
|
||||||
to_dealer = transfer.to_dealer
|
to_dealer = transfer.to_dealer
|
||||||
# add transfer.to_dealer as customer in transfer.from_dealer entity
|
# add transfer.to_dealer as customer in transfer.from_dealer entity
|
||||||
|
|
||||||
customer = from_dealer.entity.get_customers().filter(
|
customer = (
|
||||||
email=to_dealer.user.email).first()
|
from_dealer.entity.get_customers().filter(email=to_dealer.user.email).first()
|
||||||
|
)
|
||||||
if not customer:
|
if not customer:
|
||||||
customer = from_dealer.entity.create_customer(
|
customer = from_dealer.entity.create_customer(
|
||||||
customer_model_kwargs={
|
customer_model_kwargs={
|
||||||
"customer_name": to_dealer.name,
|
"customer_name": to_dealer.name,
|
||||||
"email": to_dealer.user.email,
|
"email": to_dealer.user.email,
|
||||||
"address_1": to_dealer.address
|
"address_1": to_dealer.address,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
customer.additional_info.update({"type":"organization"})
|
customer.additional_info.update({"type": "organization"})
|
||||||
customer.save()
|
customer.save()
|
||||||
|
|
||||||
invoice = from_dealer.entity.create_invoice(
|
invoice = from_dealer.entity.create_invoice(
|
||||||
customer_model=customer,
|
customer_model=customer,
|
||||||
terms=InvoiceModel.TERMS_NET_30,
|
terms=InvoiceModel.TERMS_NET_30,
|
||||||
cash_account=from_dealer.entity.get_default_coa_accounts().get(name="Cash", active=True),
|
cash_account=from_dealer.entity.get_default_coa_accounts().get(
|
||||||
prepaid_account=from_dealer.entity.get_default_coa_accounts().get(name="Accounts Receivable", active=True),
|
name="Cash", active=True
|
||||||
|
),
|
||||||
|
prepaid_account=from_dealer.entity.get_default_coa_accounts().get(
|
||||||
|
name="Accounts Receivable", active=True
|
||||||
|
),
|
||||||
coa_model=from_dealer.entity.get_default_coa(),
|
coa_model=from_dealer.entity.get_default_coa(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -392,33 +478,41 @@ def transfer_car(car,transfer):
|
|||||||
invoice.mark_as_approved(from_dealer.entity.slug, from_dealer.entity.admin)
|
invoice.mark_as_approved(from_dealer.entity.slug, from_dealer.entity.admin)
|
||||||
# invoice.mark_as_paid(from_dealer.entity.slug, from_dealer.entity.admin)
|
# invoice.mark_as_paid(from_dealer.entity.slug, from_dealer.entity.admin)
|
||||||
invoice.save()
|
invoice.save()
|
||||||
#create car item product in to_dealer entity
|
# create car item product in to_dealer entity
|
||||||
uom = to_dealer.entity.get_uom_all().filter(name=item.uom.name).first()
|
uom = to_dealer.entity.get_uom_all().filter(name=item.uom.name).first()
|
||||||
|
|
||||||
#create item product in the reciever ledger
|
# create item product in the reciever ledger
|
||||||
product = to_dealer.entity.create_item_product(
|
product = to_dealer.entity.create_item_product(
|
||||||
name=item.name,
|
name=item.name,
|
||||||
uom_model=uom,
|
uom_model=uom,
|
||||||
item_type=item.item_type,
|
item_type=item.item_type,
|
||||||
coa_model=to_dealer.entity.get_default_coa(),
|
coa_model=to_dealer.entity.get_default_coa(),
|
||||||
)
|
)
|
||||||
|
|
||||||
product.additional_info.update({'car_info': car.to_dict()})
|
product.additional_info.update({"car_info": car.to_dict()})
|
||||||
product.save()
|
product.save()
|
||||||
|
|
||||||
#add the sender as vendor and create a bill for it
|
# add the sender as vendor and create a bill for it
|
||||||
vendor = None
|
vendor = None
|
||||||
vendor = to_dealer.entity.get_vendors().filter(vendor_name=from_dealer.name).first()
|
vendor = to_dealer.entity.get_vendors().filter(vendor_name=from_dealer.name).first()
|
||||||
if not vendor:
|
if not vendor:
|
||||||
vendor = VendorModel.objects.create(entity_model=to_dealer.entity, vendor_name=from_dealer.name,additional_info={"info":to_dict(from_dealer)})
|
vendor = VendorModel.objects.create(
|
||||||
|
entity_model=to_dealer.entity,
|
||||||
|
vendor_name=from_dealer.name,
|
||||||
|
additional_info={"info": to_dict(from_dealer)},
|
||||||
|
)
|
||||||
|
|
||||||
#transfer the car to to_dealer and create items record
|
# transfer the car to to_dealer and create items record
|
||||||
|
|
||||||
bill = to_dealer.entity.create_bill(
|
bill = to_dealer.entity.create_bill(
|
||||||
vendor_model=vendor,
|
vendor_model=vendor,
|
||||||
terms=BillModel.TERMS_NET_30,
|
terms=BillModel.TERMS_NET_30,
|
||||||
cash_account=to_dealer.entity.get_default_coa_accounts().get(name="Cash", active=True),
|
cash_account=to_dealer.entity.get_default_coa_accounts().get(
|
||||||
prepaid_account=to_dealer.entity.get_default_coa_accounts().get(name="Prepaid Expenses", active=True),
|
name="Cash", active=True
|
||||||
|
),
|
||||||
|
prepaid_account=to_dealer.entity.get_default_coa_accounts().get(
|
||||||
|
name="Prepaid Expenses", active=True
|
||||||
|
),
|
||||||
coa_model=to_dealer.entity.get_default_coa(),
|
coa_model=to_dealer.entity.get_default_coa(),
|
||||||
)
|
)
|
||||||
bill.additional_info = {}
|
bill.additional_info = {}
|
||||||
@ -428,14 +522,14 @@ def transfer_car(car,transfer):
|
|||||||
"quantity": transfer.quantity,
|
"quantity": transfer.quantity,
|
||||||
"total_amount": transfer.total_price,
|
"total_amount": transfer.total_price,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bill_itemtxs = bill.migrate_itemtxs(itemtxs=bill_itemtxs,
|
bill_itemtxs = bill.migrate_itemtxs(
|
||||||
commit=True,
|
itemtxs=bill_itemtxs, commit=True, operation=BillModel.ITEMIZE_APPEND
|
||||||
operation=BillModel.ITEMIZE_APPEND)
|
)
|
||||||
|
|
||||||
bill.additional_info.update({'car_info': car.to_dict()})
|
bill.additional_info.update({"car_info": car.to_dict()})
|
||||||
bill.additional_info.update({'car_finance': car.finances.to_dict()})
|
bill.additional_info.update({"car_finance": car.finances.to_dict()})
|
||||||
|
|
||||||
bill.mark_as_review()
|
bill.mark_as_review()
|
||||||
bill.mark_as_approved(to_dealer.entity.slug, to_dealer.entity.admin)
|
bill.mark_as_approved(to_dealer.entity.slug, to_dealer.entity.admin)
|
||||||
@ -463,18 +557,19 @@ def transfer_car(car,transfer):
|
|||||||
car.save()
|
car.save()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
#pay the pill
|
# pay the pill
|
||||||
# set_bill_payment(to_dealer,to_dealer.entity,bill,transfer.total_price,"credit")
|
# set_bill_payment(to_dealer,to_dealer.entity,bill,transfer.total_price,"credit")
|
||||||
|
|
||||||
|
|
||||||
def to_dict(obj):
|
def to_dict(obj):
|
||||||
obj_dict = vars(obj).copy()
|
obj_dict = vars(obj).copy()
|
||||||
if '_state' in vars(obj):
|
if "_state" in vars(obj):
|
||||||
del obj_dict["_state"]
|
del obj_dict["_state"]
|
||||||
|
|
||||||
for key, value in obj_dict.items():
|
for key, value in obj_dict.items():
|
||||||
if isinstance(value, datetime.datetime):
|
if isinstance(value, datetime.datetime):
|
||||||
obj_dict[key] = value.strftime('%Y-%m-%d %H:%M:%S')
|
obj_dict[key] = value.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
elif hasattr(value,'pk') or hasattr(value,'id'):
|
elif hasattr(value, "pk") or hasattr(value, "id"):
|
||||||
try:
|
try:
|
||||||
obj_dict[key] = value.name
|
obj_dict[key] = value.name
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
|||||||
@ -84,6 +84,7 @@ from django.contrib.auth.models import Group
|
|||||||
from .utils import (
|
from .utils import (
|
||||||
calculate_vat_amount,
|
calculate_vat_amount,
|
||||||
get_calculations,
|
get_calculations,
|
||||||
|
get_car_finance_data,
|
||||||
get_financial_values,
|
get_financial_values,
|
||||||
reserve_car,
|
reserve_car,
|
||||||
send_email,
|
send_email,
|
||||||
@ -2399,15 +2400,26 @@ def create_sale_order(request, pk):
|
|||||||
form = forms.SaleOrderForm(request.POST)
|
form = forms.SaleOrderForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
return redirect("success")
|
if not estimate.is_completed():
|
||||||
else:
|
estimate.mark_as_completed()
|
||||||
form = forms.SaleOrderForm()
|
estimate.save()
|
||||||
|
messages.success(request, "Sale Order created successfully")
|
||||||
|
return redirect("estimate_detail", pk=pk)
|
||||||
|
|
||||||
|
form = forms.SaleOrderForm()
|
||||||
|
form.fields["estimate"].queryset = EstimateModel.objects.filter(pk=pk)
|
||||||
|
form.initial['estimate'] = estimate
|
||||||
|
data = get_car_finance_data(estimate)
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"sales/estimates/sale_order.html",
|
"sales/estimates/sale_order_form.html",
|
||||||
{"form": form, "estimate": estimate, "items": items},
|
{"form": form, "estimate": estimate, "items": items,"data": data},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def preview_sale_order(request,pk):
|
||||||
|
estimate = get_object_or_404(EstimateModel,pk=pk)
|
||||||
|
data = get_car_finance_data(estimate)
|
||||||
|
return render(request,'sales/estimates/sale_order_preview.html',{'order':estimate.sale_orders.first(),"data":data,"estimate":estimate})
|
||||||
|
|
||||||
class PaymentRequest(LoginRequiredMixin, DetailView):
|
class PaymentRequest(LoginRequiredMixin, DetailView):
|
||||||
model = EstimateModel
|
model = EstimateModel
|
||||||
@ -3406,6 +3418,13 @@ class SubscriptionPlans(ListView):
|
|||||||
context_object_name = "plans"
|
context_object_name = "plans"
|
||||||
|
|
||||||
|
|
||||||
|
# orders
|
||||||
|
|
||||||
|
class OrderListView(ListView):
|
||||||
|
model = models.SaleOrder
|
||||||
|
template_name = "sales/orders/order_list.html"
|
||||||
|
context_object_name = "orders"
|
||||||
|
|
||||||
# email
|
# email
|
||||||
def send_email_view(request, pk):
|
def send_email_view(request, pk):
|
||||||
estimate = get_object_or_404(EstimateModel, pk=pk)
|
estimate = get_object_or_404(EstimateModel, pk=pk)
|
||||||
@ -3474,3 +3493,48 @@ def custom_permission_denied_view(request, exception=None):
|
|||||||
|
|
||||||
def custom_bad_request_view(request, exception=None):
|
def custom_bad_request_view(request, exception=None):
|
||||||
return render(request, "errors/400.html", {})
|
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
|
||||||
|
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 -----------
|
||||||
|
|
||||||
|
class BaseBalanceSheetRedirectView(DjangoLedgerSecurityMixIn, RedirectView):
|
||||||
|
|
||||||
|
def get_redirect_url(self, *args, **kwargs):
|
||||||
|
year = get_localdate().year
|
||||||
|
return reverse('entity-bs-year',
|
||||||
|
kwargs={
|
||||||
|
'entity_slug': self.kwargs['entity_slug'],
|
||||||
|
'year': year
|
||||||
|
})
|
||||||
|
class FiscalYearBalanceSheetViewBase(FiscalYearBalanceSheetView):
|
||||||
|
template_name = "ledger/reports/balance_sheet.html"
|
||||||
|
|
||||||
|
class QuarterlyBalanceSheetView(FiscalYearBalanceSheetViewBase, QuarterlyReportMixIn):
|
||||||
|
"""
|
||||||
|
Quarter Balance Sheet View.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class MonthlyBalanceSheetView(FiscalYearBalanceSheetViewBase, MonthlyReportMixIn):
|
||||||
|
"""
|
||||||
|
Monthly Balance Sheet View.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DateBalanceSheetView(FiscalYearBalanceSheetViewBase, DateReportMixIn):
|
||||||
|
"""
|
||||||
|
Date Balance Sheet View.
|
||||||
|
"""
|
||||||
|
|||||||
9
scripts/report.py
Normal file
9
scripts/report.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from django_ledger.report.balance_sheet import BalanceSheetReport
|
||||||
|
from django_ledger.models import EntityModel
|
||||||
|
|
||||||
|
def run():
|
||||||
|
|
||||||
|
entity = EntityModel.objects.first()
|
||||||
|
report = BalanceSheetReport(entity=entity)
|
||||||
|
|
||||||
|
print(report)
|
||||||
70
scripts/run.py
Normal file
70
scripts/run.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
from decimal import Decimal
|
||||||
|
from django_ledger.models import EstimateModel
|
||||||
|
from rich import print
|
||||||
|
|
||||||
|
from inventory.models import VatRate
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
estimate = EstimateModel.objects.first()
|
||||||
|
vat = VatRate.objects.filter(is_active=True).first()
|
||||||
|
data = estimate.get_itemtxs_data()[0].all()
|
||||||
|
total = sum(
|
||||||
|
[
|
||||||
|
Decimal(item.item_model.additional_info["car_finance"]["selling_price"])
|
||||||
|
* Decimal(item.ce_quantity or item.quantity)
|
||||||
|
for item in data
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
additional_services = []
|
||||||
|
|
||||||
|
for i in data:
|
||||||
|
if i.item_model.additional_info["additional_services"]:
|
||||||
|
additional_services.extend(
|
||||||
|
[
|
||||||
|
{"name": x.name, "price": x.price}
|
||||||
|
for x in i.item_model.additional_info["additional_services"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
cars_info = {
|
||||||
|
"cars": [
|
||||||
|
{
|
||||||
|
"vin": x.item_model.additional_info["car_info"]["vin"],
|
||||||
|
"make": x.item_model.additional_info["car_info"]["make"],
|
||||||
|
"model": x.item_model.additional_info["car_info"]["model"],
|
||||||
|
"year": x.item_model.additional_info["car_info"]["year"],
|
||||||
|
"trim": x.item_model.additional_info["car_info"]["mileage"],
|
||||||
|
"cost_price": x.item_model.additional_info["car_finance"]["cost_price"],
|
||||||
|
"selling_price": x.item_model.additional_info["car_finance"][
|
||||||
|
"selling_price"
|
||||||
|
],
|
||||||
|
"discount": x.item_model.additional_info["car_finance"][
|
||||||
|
"discount_amount"
|
||||||
|
],
|
||||||
|
"total": x.item_model.additional_info["car_finance"]["total"],
|
||||||
|
"additional_services": x.item_model.additional_info[
|
||||||
|
"additional_services"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
for x in data
|
||||||
|
],
|
||||||
|
"quantity": data.count(),
|
||||||
|
"total_price": total,
|
||||||
|
"total__vat": (total * vat.rate) + total,
|
||||||
|
"total_discount": sum(
|
||||||
|
Decimal(x.item_model.additional_info["car_finance"]["discount_amount"])
|
||||||
|
for x in data
|
||||||
|
),
|
||||||
|
"grand_total": Decimal(total * vat.rate)
|
||||||
|
+ total
|
||||||
|
- Decimal(
|
||||||
|
sum(
|
||||||
|
Decimal(x.item_model.additional_info["car_finance"]["discount_amount"])
|
||||||
|
for x in data
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"additionals": additional_services,
|
||||||
|
}
|
||||||
|
|
||||||
|
print(cars_info)
|
||||||
@ -56,6 +56,7 @@
|
|||||||
<main class="main" id="top">
|
<main class="main" id="top">
|
||||||
{% include 'header.html' %}
|
{% include 'header.html' %}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
{% block period_navigation %}{% endblock period_navigation %}
|
||||||
<section class="content">
|
<section class="content">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock content%}
|
{% endblock content%}
|
||||||
|
|||||||
@ -105,7 +105,7 @@
|
|||||||
<!-- more inner pages-->
|
<!-- more inner pages-->
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="#">
|
<a class="nav-link" href="{% url 'order_list' %}">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<span class="nav-link-icon"><span class="fas fa-cart-plus"></span></span><span class="nav-link-text">{% trans "orders"|capfirst %}</span>
|
<span class="nav-link-icon"><span class="fas fa-cart-plus"></span></span><span class="nav-link-text">{% trans "orders"|capfirst %}</span>
|
||||||
</div>
|
</div>
|
||||||
@ -236,6 +236,11 @@
|
|||||||
<span class="nav-link-icon"><span data-feather="package"></span></span><span class="nav-link-text">{% trans 'bills'|capfirst %}</span>
|
<span class="nav-link-icon"><span data-feather="package"></span></span><span class="nav-link-text">{% trans 'bills'|capfirst %}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="nav-link" href="{% url 'entity-bs' request.user.dealer.entity.slug %}">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<span class="nav-link-icon"><span data-feather="package"></span></span><span class="nav-link-text">{% trans 'bills'|capfirst %}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
54
templates/ledger/reports/balance_sheet.html
Normal file
54
templates/ledger/reports/balance_sheet.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load static %}
|
||||||
|
{% load custom_filters %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block period_navigation %}
|
||||||
|
{% if entity %}
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">{% period_navigation 'entity-bs' %}</div>
|
||||||
|
</div>
|
||||||
|
{% elif ledger %}
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">{% period_navigation 'ledger-bs' %}</div>
|
||||||
|
</div>
|
||||||
|
{% elif unit_model %}
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">{% period_navigation 'unit-bs' %}</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="card shadow-sm border-0 p-6">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="text-center mb-5">
|
||||||
|
{% if entity %}
|
||||||
|
<h1 class="display-4 fw-light">{{ entity.name }}</h1>
|
||||||
|
{% elif ledger %}
|
||||||
|
<h1 class="display-4 fw-light">{{ ledger.name }}</h1>
|
||||||
|
{% elif unit_model %}
|
||||||
|
<h1 class="display-4 fw-light">{{ ledger.name }}</h1>
|
||||||
|
{% endif %}
|
||||||
|
<h1 class="display-4 fw-bold">{% trans 'Balance Sheet' %}</h1>
|
||||||
|
{% if unit_model %}
|
||||||
|
<h3 class="h2 fw-medium fst-italic">{{ unit_model.name }} {% trans 'Unit' %}</h3>
|
||||||
|
{% endif %}
|
||||||
|
<h2 class="display-6 fw-light">
|
||||||
|
{% if quarter %}{{ year }} | Q{{ quarter }}
|
||||||
|
{% elif month %}{{ from_date | date:'F, Y' }}
|
||||||
|
{% else %}{% trans 'Fiscal Year' %} {{ year }}
|
||||||
|
{% endif %}
|
||||||
|
</h2>
|
||||||
|
<p class="h5 fst-italic fw-light">As of {{ to_date | date:'m/d/Y' }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Balance Sheet Statement -->
|
||||||
|
<div class="table-responsive">
|
||||||
|
{% balance_sheet_statement io_model=object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
73
templates/ledger/reports/components/period_navigator.html
Normal file
73
templates/ledger/reports/components/period_navigator.html
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{% load django_ledger %}
|
||||||
|
{% load trans from i18n %}
|
||||||
|
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-body">
|
||||||
|
<!-- Header Section -->
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h2 class="display-4 fw-medium">
|
||||||
|
{% if has_year %}Fiscal Year {{ to_date.year }}{% endif %}
|
||||||
|
{% if has_month %}{{ to_date | date:"F Y" }}{% endif %}
|
||||||
|
{% if has_quarter %}Q{{ quarter }} {{ year }}{% endif %}
|
||||||
|
{% if has_date %}{{ to_date | date }}{% endif %}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Year Navigation -->
|
||||||
|
<div class="text-center mb-3">
|
||||||
|
<p class="mb-1">
|
||||||
|
<span class="fw-bold">Year:</span>
|
||||||
|
<a href="{{ previous_year_url }}" class="text-decoration-none me-2"><< {{ previous_year }}</a>
|
||||||
|
<a href="{{ current_year_url }}" class="text-decoration-none me-2">{{ year }}</a>
|
||||||
|
<a href="{{ next_year_url }}" class="text-decoration-none">{{ next_year }} >></a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quarter Navigation -->
|
||||||
|
<div class="text-center mb-3">
|
||||||
|
<p class="mb-1">
|
||||||
|
<span class="fw-bold">Quarter:</span>
|
||||||
|
{% for q_url in quarter_urls %}
|
||||||
|
<a href="{{ q_url.url }}" class="text-decoration-none me-2">{{ q_url.quarter_name }}</a>
|
||||||
|
{% if not forloop.last %}|{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Month Navigation -->
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<p class="mb-1">
|
||||||
|
<span class="fw-bold">{% trans 'Month' %}:</span>
|
||||||
|
{% for m_url in month_urls %}
|
||||||
|
<a href="{{ m_url.url }}" class="text-decoration-none me-2">{{ m_url.month_abbr }}</a>
|
||||||
|
{% if not forloop.last %}|{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Date Range -->
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
{% if has_date %}
|
||||||
|
<p class="fw-bold fst-italic">{{ from_date | date:"m/d/Y" }}</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="fw-bold fst-italic">
|
||||||
|
{{ from_date | date:"m/d/Y" }}
|
||||||
|
{% trans 'thru' %}
|
||||||
|
{{ to_date | date:"m/d/Y" }}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Current Month Link -->
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<a href="{{ current_month_url }}" class="btn btn-link text-decoration-none">
|
||||||
|
{% trans 'Go To Current Month' %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Date Picker -->
|
||||||
|
<div class="text-center">
|
||||||
|
{% date_picker date_navigation_url %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
0
templates/ledger/reports/income_statement.html
Normal file
0
templates/ledger/reports/income_statement.html
Normal file
140
templates/ledger/reports/tags/balance_sheet_statement.html
Normal file
140
templates/ledger/reports/tags/balance_sheet_statement.html
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
{% load django_ledger %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<table class="table is-fullwidth is-narrow is-striped">
|
||||||
|
<tbody>
|
||||||
|
{% for bs_role, bs_role_data in tx_digest.balance_sheet.items %}
|
||||||
|
{% if bs_role_data.is_block %}
|
||||||
|
<tr>
|
||||||
|
<td><h2 class="is-size-3">{{ bs_role | upper }}</h2></td>
|
||||||
|
<td></td>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<td></td>
|
||||||
|
{% endif %}
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="has-text-centered">{% trans 'Account Code' %}</th>
|
||||||
|
<th class="has-text-centered">{% trans 'Account Name' %}</th>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<th class="has-text-centered">{% trans 'Unit' %}</th>
|
||||||
|
{% endif %}
|
||||||
|
<th class="has-text-centered">{% trans 'Balance Type' %}</th>
|
||||||
|
<th class="has-text-centered">{% trans 'Balance Through' %} {{ tx_digest.to_date | date }}</th>
|
||||||
|
<th class="has-text-centered">{% trans 'Actions' %}</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% for acc_role, acc_data in bs_role_data.roles.items %}
|
||||||
|
<tr class="has-background-grey-light">
|
||||||
|
<td class="p-3 has-text-weight-bold">{{ acc_data.role_name | upper }}</td>
|
||||||
|
<td></td>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<td></td>
|
||||||
|
{% endif %}
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% for acc in acc_data.accounts %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ acc.code }}</td>
|
||||||
|
<td class="has-text-left">{{ acc.name }}</td>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<td>{% if acc.unit_name %}{{ acc.unit_name }}{% endif %}</td>
|
||||||
|
{% endif %}
|
||||||
|
<td class="has-text-centered">{{ acc.balance_type.0 | upper }}</td>
|
||||||
|
<td class="has-text-right">{% currency_symbol %}{{ acc.balance | currency_format }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="dropdown is-hoverable" id="account-action-{{ account.uuid }}">
|
||||||
|
<div class="dropdown-trigger">
|
||||||
|
<button class="button is-small is-rounded"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-controls="dropdown-menu">
|
||||||
|
<span>{% trans 'Actions' %}</span>
|
||||||
|
<span class="icon is-small">{% icon 'bi:arrow-down' 24 %}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% comment %} <div class="dropdown-menu" id="dropdown-menu-{{ acc.uuid }}" role="menu">
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a href="{% url 'django_ledger:account-detail' entity_slug=entity_slug coa_slug=acc.coa_slug account_pk=acc.account_uuid %}"
|
||||||
|
class="dropdown-item has-text-success">{% trans 'Detail' %}</a>
|
||||||
|
<a href="{% url 'django_ledger:account-update' entity_slug=entity_slug coa_slug=acc.coa_slug account_pk=acc.account_uuid %}"
|
||||||
|
class="dropdown-item has-text-warning">{% trans 'Update' %}</a>
|
||||||
|
</div>
|
||||||
|
</div> {% endcomment %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<tr class="has-text-weight-bold is-selected">
|
||||||
|
<td></td>
|
||||||
|
<td>{{ acc_data.role_name | upper }} {% trans 'Total:' %}</td>
|
||||||
|
<td></td>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<td></td>
|
||||||
|
{% endif %}
|
||||||
|
<td class="has-text-right">
|
||||||
|
{% currency_symbol %}{{ acc_data.total_balance | currency_format }}</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if bs_role != 'equity' %}
|
||||||
|
<tr class="has-text-weight-bold is-size-5">
|
||||||
|
<td>{% trans 'Total' %} {{ bs_role | upper }}</td>
|
||||||
|
<td></td>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<td></td>
|
||||||
|
{% endif %}
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td>{% currency_symbol %}{{ bs_role_data.total_balance | currency_format }}</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
<tr class="has-text-weight-bold is-size-5">
|
||||||
|
<td>{% trans 'Retained Earnings' %}</td>
|
||||||
|
<td></td>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<td></td>
|
||||||
|
{% endif %}
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td>{% currency_symbol %}{{ tx_digest.group_balance.GROUP_EARNINGS | currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="has-text-weight-bold is-size-5">
|
||||||
|
<td>{% trans 'Total EQUITY' %}</td>
|
||||||
|
<td></td>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<td></td>
|
||||||
|
{% endif %}
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td>{% currency_symbol %}{{ tx_digest.group_balance.GROUP_EQUITY | currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="has-text-weight-bold is-size-5">
|
||||||
|
<td>{% trans 'Total Equity + Liabilities' %}</td>
|
||||||
|
<td></td>
|
||||||
|
{% if tx_digest.by_unit %}
|
||||||
|
<td></td>
|
||||||
|
{% endif %}
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td>{% currency_symbol %}{{ tx_digest.group_balance.GROUP_LIABILITIES_EQUITY | currency_format }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@ -45,7 +45,10 @@
|
|||||||
{% elif estimate.status == 'in_review' %}
|
{% elif estimate.status == 'in_review' %}
|
||||||
<button id="accept_estimate" onclick="setFormAction('approved')" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block">{% trans 'Mark As Accept' %}</span></button>
|
<button id="accept_estimate" onclick="setFormAction('approved')" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block">{% trans 'Mark As Accept' %}</span></button>
|
||||||
{% elif estimate.status == 'approved' %}
|
{% elif estimate.status == 'approved' %}
|
||||||
|
<a href="{% url 'create_sale_order' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Create Sale Order' %}</span></a>
|
||||||
|
{% elif estimate.status == 'completed' %}
|
||||||
<a href="{% url 'invoice_create' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Create Invoice' %}</span></a>
|
<a href="{% url 'invoice_create' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Create Invoice' %}</span></a>
|
||||||
|
<a href="{% url 'preview_sale_order' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview Sale Order' %}</span></a>
|
||||||
{% elif estimate.status == 'in_review' %}
|
{% elif estimate.status == 'in_review' %}
|
||||||
<a href="{% url 'estimate_preview' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview' %}</span></a>
|
<a href="{% url 'estimate_preview' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview' %}</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
157
templates/sales/estimates/sale_order_form.html
Normal file
157
templates/sales/estimates/sale_order_form.html
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n static %}
|
||||||
|
{% load crispy_forms_filters %}
|
||||||
|
{% block title %}
|
||||||
|
{% trans 'Sale Order' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<link rel="stylesheet" href="{% static 'flags/sprite.css' %}" />
|
||||||
|
<div class="row">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-6 col-md-8">
|
||||||
|
<div class="d-sm-flex justify-content-between">
|
||||||
|
<h3 class="mb-3">
|
||||||
|
{% if customer.created %}
|
||||||
|
{{ _('Edit Sale Order') }}
|
||||||
|
{% else %}
|
||||||
|
{{ _('Add Sale Order') }}
|
||||||
|
{% endif %}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-5 col-md-6">
|
||||||
|
<form method="post" class="form row g-3 needs-validation" novalidate>
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form|crispy }}
|
||||||
|
<div class="col-12">
|
||||||
|
<button class="btn btn-primary" type="submit">{% trans 'Save' %}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="col-xl-4 col-xxl-4">
|
||||||
|
<div class="px-xl-4 mb-7">
|
||||||
|
<div class="row mx-0 mx-sm-3 mx-lg-0 px-lg-0">
|
||||||
|
<div class="col-sm-12 col-xxl-6 py-3">
|
||||||
|
<table class="w-100 table-stats table-stats">
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="py-2">
|
||||||
|
<div class="d-inline-flex align-items-center">
|
||||||
|
<div class="d-flex bg-success-subtle rounded-circle flex-center me-3" style="width:24px; height:24px">
|
||||||
|
<span class="text-success-dark" data-feather="bar-chart-2" style="width:16px; height:16px"></span>
|
||||||
|
</div>
|
||||||
|
<p class="fw-bold mb-0">Customer Name</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
||||||
|
<td class="py-2">
|
||||||
|
<p class="ps-6 ps-sm-0 fw-semibold mb-0 mb-0 pb-3 pb-sm-0">{{ estimate.customer.customer_name }}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="py-2">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="d-flex bg-info-subtle rounded-circle flex-center me-3" style="width:24px; height:24px">
|
||||||
|
<span class="text-info-dark" data-feather="trending-up" style="width:16px; height:16px"></span>
|
||||||
|
</div>
|
||||||
|
<p class="fw-bold mb-0">Email</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
||||||
|
<td class="py-2">
|
||||||
|
<p class="ps-6 ps-sm-0 fw-semibold mb-0">{{ estimate.customer.email }}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="py-2">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="d-flex bg-info-subtle rounded-circle flex-center me-3" style="width:24px; height:24px">
|
||||||
|
<span class="text-info-dark" data-feather="trending-up" style="width:16px; height:16px"></span>
|
||||||
|
</div>
|
||||||
|
<p class="fw-bold mb-0">Address</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
||||||
|
<td class="py-2">
|
||||||
|
<p class="ps-6 ps-sm-0 fw-semibold mb-0">{{ estimate.customer.address_1 }}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="py-2">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="d-flex bg-info-subtle rounded-circle flex-center me-3" style="width:24px; height:24px">
|
||||||
|
<span class="text-info-dark" data-feather="trending-up" style="width:16px; height:16px"></span>
|
||||||
|
</div>
|
||||||
|
<p class="fw-bold mb-0">Total Amount</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="py-2 d-none d-sm-block pe-sm-2">:</td>
|
||||||
|
<td class="py-2">
|
||||||
|
<p class="ps-6 ps-sm-0 fw-semibold mb-0">${{ data.grand_total }}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border-top border-bottom border-translucent mt-10" id="leadDetailsTable">
|
||||||
|
<div class="table-responsive scrollbar mx-n1 px-1">
|
||||||
|
<table class="table fs-9 mb-0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="white-space-nowrap fs-9 align-middle ps-0" style="width:26px;">
|
||||||
|
<div class="form-check mb-0 fs-8">
|
||||||
|
<input class="form-check-input" type="checkbox" />
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th class="sort white-space-nowrap align-middle pe-3 ps-0 text-uppercase" scope="col" data-sort="name" style="width:20%; min-width:100px">Vin</th>
|
||||||
|
<th class="sort align-middle pe-6 text-uppercase" scope="col" data-sort="description" style="width:20%; max-width:60px">Make</th>
|
||||||
|
<th class="sort align-middle text-start text-uppercase" scope="col" data-sort="create_date" style="width:20%; min-width:115px">Model</th>
|
||||||
|
<th class="sort align-middle text-start text-uppercase" scope="col" data-sort="create_by" style="width:20%; min-width:150px">Year</th>
|
||||||
|
<th class="sort align-middle text-start text-uppercase" scope="col" data-sort="create_by" style="width:20%; min-width:150px">Unit Price</th>
|
||||||
|
<th class="align-middle pe-0 text-end" scope="col" style="width:15%;"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="list" id="lead-details-table-body">
|
||||||
|
{% for car in data.cars %}
|
||||||
|
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||||
|
<td class="fs-9 align-middle px-0 py-3">
|
||||||
|
<div class="form-check mb-0 fs-8">
|
||||||
|
<input class="form-check-input" type="checkbox" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="name align-middle white-space-nowrap py-2 ps-0">
|
||||||
|
<a class="d-flex align-items-center text-body-highlight" href="#!">
|
||||||
|
{% comment %} <div class="avatar avatar-m me-3 status-online">
|
||||||
|
<img class="rounded-circle" src="" alt="" />
|
||||||
|
</div> {% endcomment %}
|
||||||
|
<h6 class="mb-0 text-body-highlight fw-bold">{{car.vin}}</h6>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="description align-middle white-space-nowrap text-start fw-bold text-body-tertiary py-2 pe-6">{{car.make}}</td>
|
||||||
|
<td class="create_by align-middle white-space-nowrap fw-semibold text-body-highlight">{{car.model}}</td>
|
||||||
|
<td class="create_by align-middle white-space-nowrap fw-semibold text-body-highlight">{{car.year}}</td>
|
||||||
|
<td class="last_activity align-middle text-center py-2">
|
||||||
|
<div class="d-flex align-items-center flex-1">
|
||||||
|
<span class="fw-bold fs-9 text-body">${{car.total_vat}}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -123,7 +123,7 @@
|
|||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% if estimate.status != "in_review" %}
|
{% if not estimate.is_completed %}
|
||||||
<main class="main" id="top">
|
<main class="main" id="top">
|
||||||
<div class="px-3">
|
<div class="px-3">
|
||||||
<div class="row min-vh-100 flex-center p-5">
|
<div class="row min-vh-100 flex-center p-5">
|
||||||
@ -208,44 +208,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div> {% endcomment %}
|
</div> {% endcomment %}
|
||||||
|
|
||||||
<!-- Accept Modal -->
|
|
||||||
<div class="modal fade" id="acceptModal" tabindex="-1" aria-labelledby="acceptModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="acceptModalLabel">{% trans 'Accept Estimate' %}</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% trans 'Are you sure you want to accept this estimate?' %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans 'Cancel' %}</button>
|
|
||||||
<a href="{% url 'estimate_mark_as' estimate.pk %}?mark=accepted" type="button" class="btn btn-success" id="confirmAccept">{% trans 'Accept' %}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Reject Modal -->
|
|
||||||
<div class="modal fade" id="rejectModal" tabindex="-1" aria-labelledby="rejectModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="rejectModalLabel">{% trans 'Reject Estimate' %}</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% trans 'Are you sure you want to reject this estimate?' %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans 'Cancel' %}</button>
|
|
||||||
<a href="{% url 'estimate_mark_as' estimate.pk %}?mark=rejected" type="button" class="btn btn-danger" id="confirmReject">{% trans 'Reject' %}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="estimate-row" id="estimate-content">
|
<div class="estimate-row" id="estimate-content">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="estimate-header">
|
<div class="estimate-header">
|
||||||
@ -265,30 +227,31 @@
|
|||||||
<p><strong>{% trans "Terms" %} :</strong> {{estimate.terms|title}}</p>
|
<p><strong>{% trans "Terms" %} :</strong> {{estimate.terms|title}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Items Table -->
|
<!-- Items Table -->
|
||||||
<div class="estimate-table">
|
<div class="estimate-table">
|
||||||
<table class="table table-bordered">
|
<table class="table table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>{% trans "VIN" %}</th>
|
||||||
<th>{% trans "Make" %}</th>
|
<th>{% trans "Make" %}</th>
|
||||||
<th>{% trans "Model" %}</th>
|
<th>{% trans "Model" %}</th>
|
||||||
<th>{% trans "Year" %}</th>
|
<th>{% trans "Year" %}</th>
|
||||||
<th>{% trans "VIN" %}</th>
|
|
||||||
<th class="text-center">{% trans "Quantity" %}</th>
|
<th class="text-center">{% trans "Quantity" %}</th>
|
||||||
<th class="text-center">{% trans "Unit Price" %}</th>
|
<th class="text-center">{% trans "Unit Price" %}</th>
|
||||||
<th class="text-center">{% trans "Total" %}</th>
|
<th class="text-center">{% trans "Total" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for item in items %}
|
{% for car in data.cars %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.item_model.additional_info.car_info.make }}</td>
|
<td>{{ car.vin }}</td>
|
||||||
<td>{{ item.item_model.additional_info.car_info.model }}</td>
|
<td>{{ car.make }}</td>
|
||||||
<td>{{ item.item_model.additional_info.car_info.year }}</td>
|
<td>{{ car.model }}</td>
|
||||||
<td>{{ item.item_model.additional_info.car_info.vin }}</td>
|
<td>{{ car.year }}</td>
|
||||||
<td class="text-center">{{ item.ce_quantity }}</td>
|
<td class="text-center">{{ car.quantity }}</td>
|
||||||
<td class="text-center">{{ item.item_model.additional_info.car_finance.selling_price }}</td>
|
<td class="text-center">{{ car.unit_price }}</td>
|
||||||
<td class="highlight fw-semibold text-center">{{ item.total }}</td>
|
<td class="highlight fw-semibold text-center">{{ car.total }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -297,10 +260,10 @@
|
|||||||
|
|
||||||
<!-- Additional Charges (VAT and Services) -->
|
<!-- Additional Charges (VAT and Services) -->
|
||||||
<div class="additional-charges">
|
<div class="additional-charges">
|
||||||
<p><strong>{% trans "VAT" %} ({{vat}}%):</strong> <span class="highlight">${{vat_amount}}</span></p>
|
<p><strong>{% trans "VAT" %} ({{vat}}%):</strong> <span class="highlight">${{data.vat}}</span></p>
|
||||||
<p><strong>{% trans "Additional Services" %}:</strong>
|
<p><strong>{% trans "Additional Services" %}:</strong>
|
||||||
<br>
|
<br>
|
||||||
{% for service in additional_services %}
|
{% for service in data.additional_services %}
|
||||||
<span class="highlight">{{service.name}} - ${{service.price}}</span><br>
|
<span class="highlight">{{service.name}} - ${{service.price}}</span><br>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
@ -308,7 +271,7 @@
|
|||||||
|
|
||||||
<!-- Total -->
|
<!-- Total -->
|
||||||
<div class="estimate-total">
|
<div class="estimate-total">
|
||||||
<p><strong>{%trans "Total Amount" %}:</strong> <span class="highlight">${{total}}</span></p>
|
<p><strong>{%trans "Total Amount" %}:</strong> <span class="highlight">${{data.grand_total}}</span></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Footer Note -->
|
<!-- Footer Note -->
|
||||||
48
templates/sales/orders/order_list.html
Normal file
48
templates/sales/orders/order_list.html
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n static %}
|
||||||
|
|
||||||
|
{% block title %}{{ _("Orders") }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row mt-4">
|
||||||
|
<h3 class="mb-3">{% trans "Orders" %}</h3>
|
||||||
|
|
||||||
|
<div class="table-responsive px-1 scrollbar">
|
||||||
|
<table class="table fs-9 mb-0 border-top border-translucent">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Order Number" %}</th>
|
||||||
|
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Customer" %}</th>
|
||||||
|
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "For Estimate" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="list">
|
||||||
|
{% for order in orders %}
|
||||||
|
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
|
||||||
|
<td class="align-middle product white-space-nowrap py-0">{{ order.formatted_order_id }}</td>
|
||||||
|
<td class="align-middle product white-space-nowrap py-0">{{ order.estimate.customer.customer_name }}</td>
|
||||||
|
<td class="align-middle product white-space-nowrap">{{ order.estimate }}</td>
|
||||||
|
|
||||||
|
<td class="text-center">
|
||||||
|
{% comment %} <a href="{% url 'estimate_detail' estimate.pk %}"
|
||||||
|
class="btn btn-sm btn-phoenix-success">
|
||||||
|
{% trans "view"|capfirst %}
|
||||||
|
</a> {% endcomment %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center">{% trans "No Quotations Found" %}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
{% if is_paginated %}
|
||||||
|
{% include 'partials/pagination.html' %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
Loading…
x
Reference in New Issue
Block a user