django-ledger 0.8.0__py3-none-any.whl → 0.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of django-ledger might be problematic. Click here for more details.

Files changed (51) hide show
  1. django_ledger/__init__.py +1 -1
  2. django_ledger/forms/account.py +45 -46
  3. django_ledger/forms/data_import.py +182 -63
  4. django_ledger/io/io_core.py +507 -374
  5. django_ledger/migrations/0026_stagedtransactionmodel_customer_model_and_more.py +56 -0
  6. django_ledger/models/__init__.py +2 -1
  7. django_ledger/models/bill.py +337 -300
  8. django_ledger/models/customer.py +47 -34
  9. django_ledger/models/data_import.py +770 -289
  10. django_ledger/models/entity.py +882 -637
  11. django_ledger/models/mixins.py +421 -280
  12. django_ledger/models/receipt.py +1083 -0
  13. django_ledger/models/transactions.py +105 -41
  14. django_ledger/models/unit.py +42 -30
  15. django_ledger/models/utils.py +12 -2
  16. django_ledger/models/vendor.py +85 -66
  17. django_ledger/settings.py +1 -0
  18. django_ledger/templates/django_ledger/components/period_navigator.html +5 -3
  19. django_ledger/templates/django_ledger/customer/customer_detail.html +87 -0
  20. django_ledger/templates/django_ledger/customer/customer_list.html +0 -1
  21. django_ledger/templates/django_ledger/customer/tags/customer_table.html +3 -1
  22. django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_imported.html +24 -3
  23. django_ledger/templates/django_ledger/data_import/tags/data_import_job_txs_table.html +26 -10
  24. django_ledger/templates/django_ledger/entity/entity_dashboard.html +2 -2
  25. django_ledger/templates/django_ledger/layouts/base.html +1 -1
  26. django_ledger/templates/django_ledger/layouts/content_layout_1.html +1 -1
  27. django_ledger/templates/django_ledger/receipt/customer_receipt_report.html +115 -0
  28. django_ledger/templates/django_ledger/receipt/receipt_delete.html +30 -0
  29. django_ledger/templates/django_ledger/receipt/receipt_detail.html +89 -0
  30. django_ledger/templates/django_ledger/receipt/receipt_list.html +134 -0
  31. django_ledger/templates/django_ledger/receipt/vendor_receipt_report.html +115 -0
  32. django_ledger/templates/django_ledger/vendor/tags/vendor_table.html +3 -2
  33. django_ledger/templates/django_ledger/vendor/vendor_detail.html +86 -0
  34. django_ledger/templatetags/django_ledger.py +338 -191
  35. django_ledger/urls/__init__.py +1 -0
  36. django_ledger/urls/customer.py +3 -0
  37. django_ledger/urls/data_import.py +3 -0
  38. django_ledger/urls/receipt.py +102 -0
  39. django_ledger/urls/vendor.py +1 -0
  40. django_ledger/views/__init__.py +1 -0
  41. django_ledger/views/customer.py +56 -14
  42. django_ledger/views/data_import.py +119 -66
  43. django_ledger/views/mixins.py +112 -86
  44. django_ledger/views/receipt.py +294 -0
  45. django_ledger/views/vendor.py +53 -14
  46. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/METADATA +1 -1
  47. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/RECORD +51 -40
  48. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/WHEEL +0 -0
  49. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/licenses/AUTHORS.md +0 -0
  50. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/licenses/LICENSE +0 -0
  51. {django_ledger-0.8.0.dist-info → django_ledger-0.8.1.dist-info}/top_level.txt +0 -0
@@ -17,17 +17,20 @@ from django.urls import reverse
17
17
  from django.utils.formats import number_format
18
18
 
19
19
  from django_ledger import __version__
20
- from django_ledger.forms.app_filters import EntityFilterForm, ActivityFilterForm
20
+ from django_ledger.forms.app_filters import ActivityFilterForm, EntityFilterForm
21
21
  from django_ledger.forms.feedback import BugReportForm, RequestNewFeatureForm
22
22
  from django_ledger.io import ROLES_ORDER_ALL
23
- from django_ledger.io.io_core import validate_activity, get_localdate
23
+ from django_ledger.io.io_core import get_localdate, validate_activity
24
24
  from django_ledger.models import BillModel, InvoiceModel, JournalEntryModel
25
25
  from django_ledger.settings import (
26
- DJANGO_LEDGER_FINANCIAL_ANALYSIS,
27
26
  DJANGO_LEDGER_CURRENCY_SYMBOL,
28
- DJANGO_LEDGER_SPACED_CURRENCY_SYMBOL
27
+ DJANGO_LEDGER_FINANCIAL_ANALYSIS,
28
+ DJANGO_LEDGER_SPACED_CURRENCY_SYMBOL,
29
+ )
30
+ from django_ledger.utils import (
31
+ get_default_entity_session_key,
32
+ get_end_date_from_session,
29
33
  )
30
- from django_ledger.utils import get_default_entity_session_key, get_end_date_from_session
31
34
 
32
35
  register = template.Library()
33
36
 
@@ -82,13 +85,13 @@ def last_four(value: str):
82
85
 
83
86
  @register.inclusion_tag('django_ledger/components/icon.html')
84
87
  def icon(icon_name, size):
85
- return {
86
- 'icon': icon_name,
87
- 'size': size
88
- }
88
+ return {'icon': icon_name, 'size': size}
89
89
 
90
90
 
91
- @register.inclusion_tag('django_ledger/financial_statements/tags/balance_sheet_statement.html', takes_context=True)
91
+ @register.inclusion_tag(
92
+ 'django_ledger/financial_statements/tags/balance_sheet_statement.html',
93
+ takes_context=True,
94
+ )
92
95
  def balance_sheet_statement(context, io_model, to_date=None):
93
96
  user_model = context['user']
94
97
  activity = context['request'].GET.get('activity')
@@ -107,7 +110,8 @@ def balance_sheet_statement(context, io_model, to_date=None):
107
110
  to_date=to_date,
108
111
  signs=True,
109
112
  process_groups=True,
110
- balance_sheet_statement=True)
113
+ balance_sheet_statement=True,
114
+ )
111
115
 
112
116
  return {
113
117
  'entity_slug': entity_slug,
@@ -116,7 +120,10 @@ def balance_sheet_statement(context, io_model, to_date=None):
116
120
  }
117
121
 
118
122
 
119
- @register.inclusion_tag('django_ledger/financial_statements/tags/cash_flow_statement.html', takes_context=True)
123
+ @register.inclusion_tag(
124
+ 'django_ledger/financial_statements/tags/cash_flow_statement.html',
125
+ takes_context=True,
126
+ )
120
127
  def cash_flow_statement(context, io_model):
121
128
  user_model = context['user']
122
129
  entity_slug = context['view'].kwargs.get('entity_slug')
@@ -134,16 +141,19 @@ def cash_flow_statement(context, io_model):
134
141
  by_unit=context['by_unit'],
135
142
  from_date=from_date,
136
143
  to_date=to_date,
137
- process_groups=True)
144
+ process_groups=True,
145
+ )
138
146
 
139
147
  return {
140
148
  'entity_slug': entity_slug,
141
149
  'user_model': user_model,
142
- 'tx_digest': io_digest.get_io_data()
150
+ 'tx_digest': io_digest.get_io_data(),
143
151
  }
144
152
 
145
153
 
146
- @register.inclusion_tag('django_ledger/financial_statements/tags/income_statement.html', takes_context=True)
154
+ @register.inclusion_tag(
155
+ 'django_ledger/financial_statements/tags/income_statement.html', takes_context=True
156
+ )
147
157
  def income_statement_table(context, io_model, from_date=None, to_date=None):
148
158
  user_model = context['user']
149
159
  activity = context['request'].GET.get('activity')
@@ -166,78 +176,96 @@ def income_statement_table(context, io_model, from_date=None, to_date=None):
166
176
  equity_only=True,
167
177
  process_groups=True,
168
178
  income_statement=True,
169
- signs=True
179
+ signs=True,
170
180
  )
171
181
 
172
182
  return {
173
183
  'entity_slug': entity_slug,
174
184
  'user_model': user_model,
175
- 'tx_digest': io_digest.get_io_data()
185
+ 'tx_digest': io_digest.get_io_data(),
176
186
  }
177
187
 
178
188
 
179
- @register.inclusion_tag('django_ledger/bank_account/tags/bank_accounts_table.html', takes_context=True)
189
+ @register.inclusion_tag(
190
+ 'django_ledger/bank_account/tags/bank_accounts_table.html', takes_context=True
191
+ )
180
192
  def bank_account_table(context, bank_account_qs):
181
193
  entity_slug = context['view'].kwargs['entity_slug']
182
- return {
183
- 'bank_account_qs': bank_account_qs,
184
- 'entity_slug': entity_slug
185
- }
194
+ return {'bank_account_qs': bank_account_qs, 'entity_slug': entity_slug}
186
195
 
187
196
 
188
- @register.inclusion_tag('django_ledger/data_import/tags/data_import_job_list_table.html', takes_context=True)
197
+ @register.inclusion_tag(
198
+ 'django_ledger/data_import/tags/data_import_job_list_table.html', takes_context=True
199
+ )
189
200
  def data_import_job_list_table(context):
190
201
  return context
191
202
 
192
203
 
193
- @register.inclusion_tag('django_ledger/data_import/tags/data_import_job_txs_table.html', takes_context=True)
204
+ @register.inclusion_tag(
205
+ 'django_ledger/data_import/tags/data_import_job_txs_table.html', takes_context=True
206
+ )
194
207
  def data_import_job_txs_pending(context, staged_txs_formset):
195
208
  return {
196
209
  'entity_slug': staged_txs_formset.IMPORT_JOB_MODEL.entity_slug,
197
210
  'import_job_model': staged_txs_formset.IMPORT_JOB_MODEL,
198
- 'staged_txs_formset': staged_txs_formset
211
+ 'staged_txs_formset': staged_txs_formset,
199
212
  }
200
213
 
201
214
 
202
- @register.inclusion_tag('django_ledger/data_import/tags/data_import_job_txs_imported.html', takes_context=True)
215
+ @register.inclusion_tag(
216
+ 'django_ledger/data_import/tags/data_import_job_txs_imported.html',
217
+ takes_context=True,
218
+ )
203
219
  def data_import_job_txs_imported(context, import_job_model):
204
220
  return {
205
221
  'entity_slug': import_job_model.entity_slug,
206
222
  'import_job_model': import_job_model,
207
- 'imported_txs': import_job_model.stagedtransactionmodel_set.all().is_imported()
223
+ 'imported_txs': import_job_model.stagedtransactionmodel_set.all().is_imported(),
208
224
  }
209
225
 
210
226
 
211
- @register.inclusion_tag('django_ledger/journal_entry/tags/je_table.html', takes_context=True)
227
+ @register.inclusion_tag(
228
+ 'django_ledger/journal_entry/tags/je_table.html', takes_context=True
229
+ )
212
230
  def jes_table(context, journal_entry_qs, next_url=None):
213
231
  entity_slug = context['view'].kwargs['entity_slug']
214
232
  ledger_pk = context['view'].kwargs['ledger_pk']
215
233
  if not next_url:
216
- next_url = reverse('django_ledger:je-list',
217
- kwargs={
218
- 'entity_slug': entity_slug,
219
- 'ledger_pk': ledger_pk
220
- })
234
+ next_url = reverse(
235
+ 'django_ledger:je-list',
236
+ kwargs={'entity_slug': entity_slug, 'ledger_pk': ledger_pk},
237
+ )
221
238
  return {
222
239
  'journal_entry_qs': journal_entry_qs,
223
240
  'entity_slug': entity_slug,
224
241
  'ledger_pk': ledger_pk,
225
- 'next_url': next_url
242
+ 'next_url': next_url,
226
243
  }
227
244
 
228
245
 
229
246
  @register.inclusion_tag('django_ledger/transactions/tags/txs_table.html')
230
- def transactions_table(object_type: Union[JournalEntryModel, BillModel, InvoiceModel], style='detail'):
247
+ def transactions_table(
248
+ object_type: Union[JournalEntryModel, BillModel, InvoiceModel], style='detail'
249
+ ):
231
250
  if isinstance(object_type, JournalEntryModel):
232
- transaction_model_qs = object_type.transactionmodel_set.all().with_annotated_details().order_by(
233
- '-timestamp')
251
+ transaction_model_qs = (
252
+ object_type.transactionmodel_set.all()
253
+ .with_annotated_details()
254
+ .order_by('-timestamp')
255
+ )
234
256
  elif isinstance(object_type, BillModel):
235
- transaction_model_qs = object_type.get_transaction_queryset(annotated=True).order_by('-timestamp')
257
+ transaction_model_qs = object_type.get_transaction_queryset(
258
+ annotated=True
259
+ ).order_by('-timestamp')
236
260
  elif isinstance(object_type, InvoiceModel):
237
- transaction_model_qs = object_type.get_transaction_queryset(annotated=True).order_by('-timestamp')
261
+ transaction_model_qs = object_type.get_transaction_queryset(
262
+ annotated=True
263
+ ).order_by('-timestamp')
238
264
  else:
239
265
  raise ValidationError(
240
- 'Cannot handle object of type {} to get transaction model queryset'.format(type(object_type))
266
+ 'Cannot handle object of type {} to get transaction model queryset'.format(
267
+ type(object_type)
268
+ )
241
269
  )
242
270
 
243
271
  total_credits = sum(tx.amount for tx in transaction_model_qs if tx.is_credit())
@@ -248,11 +276,13 @@ def transactions_table(object_type: Union[JournalEntryModel, BillModel, InvoiceM
248
276
  'transaction_model_qs': transaction_model_qs,
249
277
  'total_debits': total_debits,
250
278
  'total_credits': total_credits,
251
- 'object': object_type
279
+ 'object': object_type,
252
280
  }
253
281
 
254
282
 
255
- @register.inclusion_tag('django_ledger/ledger/tags/ledgers_table.html', takes_context=True)
283
+ @register.inclusion_tag(
284
+ 'django_ledger/ledger/tags/ledgers_table.html', takes_context=True
285
+ )
256
286
  def ledgers_table(context, ledger_model_qs):
257
287
  return {
258
288
  'ledger_model_qs': ledger_model_qs,
@@ -260,49 +290,58 @@ def ledgers_table(context, ledger_model_qs):
260
290
  }
261
291
 
262
292
 
263
- @register.inclusion_tag('django_ledger/invoice/tags/invoice_table.html', takes_context=True)
293
+ @register.inclusion_tag(
294
+ 'django_ledger/invoice/tags/invoice_table.html', takes_context=True
295
+ )
264
296
  def invoice_table(context, invoice_qs):
265
297
  return {
266
298
  'invoices': invoice_qs,
267
- 'entity_slug': context['view'].kwargs['entity_slug']
299
+ 'entity_slug': context['view'].kwargs['entity_slug'],
268
300
  }
269
301
 
270
302
 
271
303
  @register.inclusion_tag('django_ledger/bills/tags/bill_table.html', takes_context=True)
272
304
  def bill_table(context, bill_qs):
273
- return {
274
- 'bills': bill_qs,
275
- 'entity_slug': context['view'].kwargs['entity_slug']
276
- }
305
+ return {'bills': bill_qs, 'entity_slug': context['view'].kwargs['entity_slug']}
277
306
 
278
307
 
279
- @register.inclusion_tag('django_ledger/closing_entry/tags/closing_entry_table.html', takes_context=True)
308
+ @register.inclusion_tag(
309
+ 'django_ledger/closing_entry/tags/closing_entry_table.html', takes_context=True
310
+ )
280
311
  def closing_entry_table(context, closing_entry_qs):
281
312
  return {
282
313
  'closing_entry_list': closing_entry_qs,
283
- 'entity_slug': context['view'].kwargs['entity_slug']
314
+ 'entity_slug': context['view'].kwargs['entity_slug'],
284
315
  }
285
316
 
286
317
 
287
- @register.inclusion_tag('django_ledger/closing_entry/tags/closing_entry_txs_table.html', takes_context=True)
318
+ @register.inclusion_tag(
319
+ 'django_ledger/closing_entry/tags/closing_entry_txs_table.html', takes_context=True
320
+ )
288
321
  def closing_entry_txs_table(context, closing_entry_txs_qs):
289
322
  ce_txs_list = list(closing_entry_txs_qs)
290
- ce_txs_list.sort(key=lambda ce_txs: ROLES_ORDER_ALL.index(ce_txs.account_model.role))
323
+ ce_txs_list.sort(
324
+ key=lambda ce_txs: ROLES_ORDER_ALL.index(ce_txs.account_model.role)
325
+ )
291
326
  return {
292
327
  'ce_txs_list': ce_txs_list,
293
- 'entity_slug': context['view'].kwargs['entity_slug']
328
+ 'entity_slug': context['view'].kwargs['entity_slug'],
294
329
  }
295
330
 
296
331
 
297
- @register.inclusion_tag('django_ledger/purchase_order/includes/po_table.html', takes_context=True)
332
+ @register.inclusion_tag(
333
+ 'django_ledger/purchase_order/includes/po_table.html', takes_context=True
334
+ )
298
335
  def po_table(context, purchase_order_qs):
299
336
  return {
300
337
  'po_list': purchase_order_qs,
301
- 'entity_slug': context['view'].kwargs['entity_slug']
338
+ 'entity_slug': context['view'].kwargs['entity_slug'],
302
339
  }
303
340
 
304
341
 
305
- @register.inclusion_tag('django_ledger/account/tags/accounts_table.html', takes_context=True)
342
+ @register.inclusion_tag(
343
+ 'django_ledger/account/tags/accounts_table.html', takes_context=True
344
+ )
306
345
  def accounts_table(context, accounts_qs, title=None):
307
346
  return {
308
347
  'title': title,
@@ -311,24 +350,30 @@ def accounts_table(context, accounts_qs, title=None):
311
350
  }
312
351
 
313
352
 
314
- @register.inclusion_tag('django_ledger/customer/tags/customer_table.html', takes_context=True)
353
+ @register.inclusion_tag(
354
+ 'django_ledger/customer/tags/customer_table.html', takes_context=True
355
+ )
315
356
  def customer_table(context):
316
357
  return context
317
358
 
318
359
 
319
- @register.inclusion_tag('django_ledger/vendor/tags/vendor_table.html', takes_context=True)
360
+ @register.inclusion_tag(
361
+ 'django_ledger/vendor/tags/vendor_table.html', takes_context=True
362
+ )
320
363
  def vendor_table(context):
321
364
  return context
322
365
 
323
366
 
324
- @register.inclusion_tag('django_ledger/account/tags/account_txs_table.html', takes_context=True)
367
+ @register.inclusion_tag(
368
+ 'django_ledger/account/tags/account_txs_table.html', takes_context=True
369
+ )
325
370
  def account_txs_table(context, txs_qs):
326
371
  return {
327
372
  'transactions': txs_qs,
328
373
  'total_credits': sum(tx.amount for tx in txs_qs if tx.tx_type == 'credit'),
329
374
  'total_debits': sum(tx.amount for tx in txs_qs if tx.tx_type == 'debit'),
330
375
  'entity_slug': context['view'].kwargs['entity_slug'],
331
- 'account_pk': context['view'].kwargs['account_pk']
376
+ 'account_pk': context['view'].kwargs['account_pk'],
332
377
  }
333
378
 
334
379
 
@@ -342,11 +387,13 @@ def nav_breadcrumbs(context):
342
387
  'entity_slug': entity_slug,
343
388
  'coa_slug': coa_slug,
344
389
  'ledger_pk': ledger_pk,
345
- 'account_pk': account_pk
390
+ 'account_pk': account_pk,
346
391
  }
347
392
 
348
393
 
349
- @register.inclusion_tag('django_ledger/components/default_entity.html', takes_context=True)
394
+ @register.inclusion_tag(
395
+ 'django_ledger/components/default_entity.html', takes_context=True
396
+ )
350
397
  def default_entity(context):
351
398
  user = context['user']
352
399
  session_key = get_default_entity_session_key()
@@ -356,9 +403,7 @@ def default_entity(context):
356
403
  try:
357
404
  entity_uuid = session_entity_data['entity_uuid']
358
405
  default_entity_form = EntityFilterForm(
359
- user_model=user,
360
- form_id=identity,
361
- current_entity_uuid=entity_uuid
406
+ user_model=user, form_id=identity, current_entity_uuid=entity_uuid
362
407
  )
363
408
  except TypeError or KeyError:
364
409
  default_entity_form = EntityFilterForm(
@@ -390,21 +435,18 @@ def session_entity_name(context, request=None):
390
435
 
391
436
 
392
437
  # todo: rename template to activity_form_filter.
393
- @register.inclusion_tag('django_ledger/components/activity_form.html', takes_context=True)
438
+ @register.inclusion_tag(
439
+ 'django_ledger/components/activity_form.html', takes_context=True
440
+ )
394
441
  def activity_filter(context):
395
442
  request = context['request']
396
443
  activity = request.GET.get('activity')
397
444
  if activity:
398
- activity_form = ActivityFilterForm(initial={
399
- 'activity': activity
400
- })
445
+ activity_form = ActivityFilterForm(initial={'activity': activity})
401
446
  else:
402
447
  activity_form = ActivityFilterForm()
403
448
 
404
- return {
405
- 'activity_form': activity_form,
406
- 'form_path': context['request'].path
407
- }
449
+ return {'activity_form': activity_form, 'form_path': context['request'].path}
408
450
 
409
451
 
410
452
  @register.inclusion_tag('django_ledger/components/date_picker.html', takes_context=True)
@@ -425,7 +467,7 @@ def date_picker(context, nav_url=None, date_picker_id=None):
425
467
  return {
426
468
  'entity_slug': entity_slug,
427
469
  'date_picker_id': date_picker_id,
428
- 'date_navigation_url': date_navigation_url
470
+ 'date_navigation_url': date_navigation_url,
429
471
  }
430
472
 
431
473
 
@@ -437,10 +479,7 @@ def get_current_end_date_filter(context):
437
479
 
438
480
  @register.inclusion_tag('django_ledger/components/chart_container.html')
439
481
  def chart_container(chart_id, endpoint=None):
440
- return {
441
- 'chart_id': chart_id,
442
- 'endpoint': endpoint
443
- }
482
+ return {'chart_id': chart_id, 'endpoint': endpoint}
444
483
 
445
484
 
446
485
  @register.inclusion_tag('django_ledger/components/modals.html', takes_context=True)
@@ -452,18 +491,25 @@ def modal_action(context, model, http_method: str = 'post', entity_slug: str = N
452
491
  'object': model,
453
492
  'action_url': action_url,
454
493
  'http_method': http_method,
455
- 'message': f'Do you want to mark {model.__class__._meta.verbose_name} {model.get_document_id()} as paid?'
494
+ 'message': f'Do you want to mark {model.__class__._meta.verbose_name} {model.get_document_id()} as paid?',
456
495
  }
457
496
 
458
497
 
459
498
  @register.inclusion_tag('django_ledger/components/modals_v2.html', takes_context=True)
460
- def modal_action_v2(context, model, action_url: str, message: str, html_id: str, http_method: str = 'get'):
499
+ def modal_action_v2(
500
+ context,
501
+ model,
502
+ action_url: str,
503
+ message: str,
504
+ html_id: str,
505
+ http_method: str = 'get',
506
+ ):
461
507
  return {
462
508
  'object': model,
463
509
  'action_url': action_url,
464
510
  'http_method': http_method,
465
511
  'message': message,
466
- 'html_id': html_id
512
+ 'html_id': html_id,
467
513
  }
468
514
 
469
515
 
@@ -497,8 +543,15 @@ def fin_ratio_threshold_class(value, ratio):
497
543
  return 'is-success'
498
544
 
499
545
 
500
- @register.inclusion_tag('django_ledger/components/feedback_button.html', takes_context=True)
501
- def feedback_button(context, button_size_class: str = 'is-small', color_class: str = 'is-success', icon_id: str = None):
546
+ @register.inclusion_tag(
547
+ 'django_ledger/components/feedback_button.html', takes_context=True
548
+ )
549
+ def feedback_button(
550
+ context,
551
+ button_size_class: str = 'is-small',
552
+ color_class: str = 'is-success',
553
+ icon_id: str = None,
554
+ ):
502
555
  bug_modal_html_id = f'djl-bug-button-{randint(10000, 99999)}'
503
556
  feature_modal_html_id = f'djl-feature-button-{randint(10000, 99999)}'
504
557
  bug_form = BugReportForm()
@@ -512,11 +565,13 @@ def feedback_button(context, button_size_class: str = 'is-small', color_class: s
512
565
  'color_class': color_class,
513
566
  'bug_form': bug_form,
514
567
  'feature_form': feature_form,
515
- 'next_url': next_url
568
+ 'next_url': next_url,
516
569
  }
517
570
 
518
571
 
519
- @register.inclusion_tag('django_ledger/components/period_navigator.html', takes_context=True)
572
+ @register.inclusion_tag(
573
+ 'django_ledger/components/period_navigator.html', takes_context=True
574
+ )
520
575
  def period_navigation(context, base_url: str):
521
576
  kwargs = dict()
522
577
  entity_slug = context['view'].kwargs['entity_slug']
@@ -557,7 +612,7 @@ def period_navigation(context, base_url: str):
557
612
  KWARGS_CURRENT_MONTH = {
558
613
  'entity_slug': context['view'].kwargs['entity_slug'],
559
614
  'year': dt.year,
560
- 'month': dt.month
615
+ 'month': dt.month,
561
616
  }
562
617
 
563
618
  if 'unit_slug' in kwargs:
@@ -569,18 +624,21 @@ def period_navigation(context, base_url: str):
569
624
  if 'coa_slug' in kwargs:
570
625
  KWARGS_CURRENT_MONTH['coa_slug'] = kwargs['coa_slug']
571
626
 
572
- ctx['current_month_url'] = reverse(f'django_ledger:{base_url}-month',
573
- kwargs=KWARGS_CURRENT_MONTH)
627
+ ctx['current_month_url'] = reverse(
628
+ f'django_ledger:{base_url}-month', kwargs=KWARGS_CURRENT_MONTH
629
+ )
574
630
 
575
631
  quarter_urls = list()
576
632
  ctx['quarter'] = context.get('quarter')
577
633
  for Q in range(1, 5):
578
634
  kwargs['quarter'] = Q
579
- quarter_urls.append({
580
- 'url': reverse(f'django_ledger:{base_url}-quarter', kwargs=kwargs),
581
- 'quarter': Q,
582
- 'quarter_name': f'Q{Q}'
583
- })
635
+ quarter_urls.append(
636
+ {
637
+ 'url': reverse(f'django_ledger:{base_url}-quarter', kwargs=kwargs),
638
+ 'quarter': Q,
639
+ 'quarter_name': f'Q{Q}',
640
+ }
641
+ )
584
642
  del kwargs['quarter']
585
643
  ctx['quarter_urls'] = quarter_urls
586
644
 
@@ -588,11 +646,13 @@ def period_navigation(context, base_url: str):
588
646
  ctx['month'] = context.get('month')
589
647
  for M in range(1, 13):
590
648
  kwargs['month'] = M
591
- month_urls.append({
592
- 'url': reverse(f'django_ledger:{base_url}-month', kwargs=kwargs),
593
- 'month': M,
594
- 'month_abbr': month_abbr[M]
595
- })
649
+ month_urls.append(
650
+ {
651
+ 'url': reverse(f'django_ledger:{base_url}-month', kwargs=kwargs),
652
+ 'month': M,
653
+ 'month_abbr': month_abbr[M],
654
+ }
655
+ )
596
656
  ctx['month_urls'] = month_urls
597
657
  ctx['from_date'] = context['from_date']
598
658
  ctx['to_date'] = context['to_date']
@@ -615,8 +675,11 @@ def navigation_menu(context, style):
615
675
  {
616
676
  'type': 'link',
617
677
  'title': 'Entity Dashboard',
618
- 'url': reverse('django_ledger:entity-dashboard', kwargs={'entity_slug': ENTITY_SLUG}),
619
- 'icon': 'mdi:view-dashboard'
678
+ 'url': reverse(
679
+ 'django_ledger:entity-dashboard',
680
+ kwargs={'entity_slug': ENTITY_SLUG},
681
+ ),
682
+ 'icon': 'mdi:view-dashboard',
620
683
  },
621
684
  {
622
685
  'type': 'links',
@@ -625,58 +688,93 @@ def navigation_menu(context, style):
625
688
  {
626
689
  'type': 'link',
627
690
  'title': 'Vendors',
628
- 'url': reverse('django_ledger:vendor-list', kwargs={'entity_slug': ENTITY_SLUG}),
629
- 'icon': 'mdi:truck'
691
+ 'url': reverse(
692
+ 'django_ledger:vendor-list',
693
+ kwargs={'entity_slug': ENTITY_SLUG},
694
+ ),
695
+ 'icon': 'mdi:truck',
630
696
  },
631
697
  {
632
698
  'type': 'link',
633
699
  'title': 'Customers',
634
- 'url': reverse('django_ledger:customer-list', kwargs={'entity_slug': ENTITY_SLUG}),
635
- 'icon': 'mdi:account-group'
700
+ 'url': reverse(
701
+ 'django_ledger:customer-list',
702
+ kwargs={'entity_slug': ENTITY_SLUG},
703
+ ),
704
+ 'icon': 'mdi:account-group',
636
705
  },
637
706
  {
638
707
  'type': 'link',
639
708
  'title': 'Bank Accounts',
640
- 'url': reverse('django_ledger:bank-account-list', kwargs={'entity_slug': ENTITY_SLUG}),
641
- 'icon': 'mdi:bank'
709
+ 'url': reverse(
710
+ 'django_ledger:bank-account-list',
711
+ kwargs={'entity_slug': ENTITY_SLUG},
712
+ ),
713
+ 'icon': 'mdi:bank',
642
714
  },
643
715
  {
644
716
  'type': 'link',
645
- 'title': 'Estimates & Contracts',
646
- 'url': reverse('django_ledger:customer-estimate-list', kwargs={'entity_slug': ENTITY_SLUG}),
647
- 'icon': 'mdi:clipboard-text'
717
+ 'title': 'Receipts',
718
+ 'url': reverse(
719
+ 'django_ledger:receipt-list',
720
+ kwargs={'entity_slug': ENTITY_SLUG},
721
+ ),
722
+ 'icon': 'mdi:receipt',
648
723
  },
649
724
  {
650
725
  'type': 'link',
651
726
  'title': 'Bills',
652
- 'url': reverse('django_ledger:bill-list', kwargs={'entity_slug': ENTITY_SLUG}),
653
- 'icon': 'uil:bill'
727
+ 'url': reverse(
728
+ 'django_ledger:bill-list',
729
+ kwargs={'entity_slug': ENTITY_SLUG},
730
+ ),
731
+ 'icon': 'uil:bill',
654
732
  },
655
733
  {
656
734
  'type': 'link',
657
735
  'title': 'Invoices',
658
- 'url': reverse('django_ledger:invoice-list', kwargs={'entity_slug': ENTITY_SLUG}),
659
- 'icon': 'mdi:file-document'
736
+ 'url': reverse(
737
+ 'django_ledger:invoice-list',
738
+ kwargs={'entity_slug': ENTITY_SLUG},
739
+ ),
740
+ 'icon': 'mdi:file-document',
660
741
  },
661
742
  {
662
743
  'type': 'link',
663
744
  'title': 'Purchase Orders',
664
- 'url': reverse('django_ledger:po-list', kwargs={'entity_slug': ENTITY_SLUG}),
665
- 'icon': 'mdi:cart'
745
+ 'url': reverse(
746
+ 'django_ledger:po-list', kwargs={'entity_slug': ENTITY_SLUG}
747
+ ),
748
+ 'icon': 'mdi:cart',
749
+ },
750
+ {
751
+ 'type': 'link',
752
+ 'title': 'Estimates & Contracts',
753
+ 'url': reverse(
754
+ 'django_ledger:customer-estimate-list',
755
+ kwargs={'entity_slug': ENTITY_SLUG},
756
+ ),
757
+ 'icon': 'mdi:clipboard-text',
666
758
  },
667
759
  {
668
760
  'type': 'link',
669
761
  'title': 'Inventory',
670
- 'url': reverse('django_ledger:inventory-list', kwargs={'entity_slug': ENTITY_SLUG}),
671
- 'icon': 'mdi:warehouse'
762
+ 'url': reverse(
763
+ 'django_ledger:inventory-list',
764
+ kwargs={'entity_slug': ENTITY_SLUG},
765
+ ),
766
+ 'icon': 'mdi:warehouse',
672
767
  },
673
768
  {
674
769
  'type': 'link',
675
770
  'title': 'Closing Entries',
676
- 'url': reverse('django_ledger:closing-entry-list', kwargs={'entity_slug': ENTITY_SLUG}),
677
- 'icon': 'mdi:book-lock'
678
- }
679
- ]
771
+ 'url': reverse(
772
+ 'django_ledger:closing-entry-list',
773
+ kwargs={'entity_slug': ENTITY_SLUG},
774
+ ),
775
+ 'icon': 'mdi:book-lock',
776
+ },
777
+ ],
680
778
  },
681
779
  {
682
780
  'type': 'links',
@@ -685,40 +783,58 @@ def navigation_menu(context, style):
685
783
  {
686
784
  'type': 'link',
687
785
  'title': 'Entity Units',
688
- 'url': reverse('django_ledger:unit-list', kwargs={'entity_slug': ENTITY_SLUG}),
689
- 'icon': 'mdi:domain'
786
+ 'url': reverse(
787
+ 'django_ledger:unit-list',
788
+ kwargs={'entity_slug': ENTITY_SLUG},
789
+ ),
790
+ 'icon': 'mdi:domain',
690
791
  },
691
792
  {
692
793
  'type': 'link',
693
794
  'title': 'Products',
694
- 'url': reverse('django_ledger:product-list', kwargs={'entity_slug': ENTITY_SLUG}),
695
- 'icon': 'mdi:package-variant'
795
+ 'url': reverse(
796
+ 'django_ledger:product-list',
797
+ kwargs={'entity_slug': ENTITY_SLUG},
798
+ ),
799
+ 'icon': 'mdi:package-variant',
696
800
  },
697
801
  {
698
802
  'type': 'link',
699
803
  'title': 'Services',
700
- 'url': reverse('django_ledger:service-list', kwargs={'entity_slug': ENTITY_SLUG}),
701
- 'icon': 'mdi:briefcase'
804
+ 'url': reverse(
805
+ 'django_ledger:service-list',
806
+ kwargs={'entity_slug': ENTITY_SLUG},
807
+ ),
808
+ 'icon': 'mdi:briefcase',
702
809
  },
703
810
  {
704
811
  'type': 'link',
705
812
  'title': 'Business Expenses',
706
- 'url': reverse('django_ledger:expense-list', kwargs={'entity_slug': ENTITY_SLUG}),
707
- 'icon': 'mdi:cash-minus'
813
+ 'url': reverse(
814
+ 'django_ledger:expense-list',
815
+ kwargs={'entity_slug': ENTITY_SLUG},
816
+ ),
817
+ 'icon': 'mdi:cash-minus',
708
818
  },
709
819
  {
710
820
  'type': 'link',
711
821
  'title': 'Inventory Items',
712
- 'url': reverse('django_ledger:inventory-item-list', kwargs={'entity_slug': ENTITY_SLUG}),
713
- 'icon': 'mdi:barcode'
822
+ 'url': reverse(
823
+ 'django_ledger:inventory-item-list',
824
+ kwargs={'entity_slug': ENTITY_SLUG},
825
+ ),
826
+ 'icon': 'mdi:barcode',
714
827
  },
715
828
  {
716
829
  'type': 'link',
717
830
  'title': 'Unit of Measures',
718
- 'url': reverse('django_ledger:uom-list', kwargs={'entity_slug': ENTITY_SLUG}),
719
- 'icon': 'mdi:ruler'
831
+ 'url': reverse(
832
+ 'django_ledger:uom-list',
833
+ kwargs={'entity_slug': ENTITY_SLUG},
834
+ ),
835
+ 'icon': 'mdi:ruler',
720
836
  },
721
- ]
837
+ ],
722
838
  },
723
839
  {
724
840
  'type': 'links',
@@ -727,22 +843,31 @@ def navigation_menu(context, style):
727
843
  {
728
844
  'type': 'link',
729
845
  'title': 'Balance Sheet',
730
- 'url': reverse('django_ledger:entity-bs', kwargs={'entity_slug': ENTITY_SLUG}),
731
- 'icon': 'clarity:balance-line'
846
+ 'url': reverse(
847
+ 'django_ledger:entity-bs',
848
+ kwargs={'entity_slug': ENTITY_SLUG},
849
+ ),
850
+ 'icon': 'clarity:balance-line',
732
851
  },
733
852
  {
734
853
  'type': 'link',
735
854
  'title': 'Income Statement',
736
- 'url': reverse('django_ledger:entity-ic', kwargs={'entity_slug': ENTITY_SLUG}),
737
- 'icon': 'mdi:chart-line'
855
+ 'url': reverse(
856
+ 'django_ledger:entity-ic',
857
+ kwargs={'entity_slug': ENTITY_SLUG},
858
+ ),
859
+ 'icon': 'mdi:chart-line',
738
860
  },
739
861
  {
740
862
  'type': 'link',
741
863
  'title': 'Cash Flow Statement',
742
- 'url': reverse('django_ledger:entity-cf', kwargs={'entity_slug': ENTITY_SLUG}),
743
- 'icon': 'hugeicons:money-send-flow-02'
864
+ 'url': reverse(
865
+ 'django_ledger:entity-cf',
866
+ kwargs={'entity_slug': ENTITY_SLUG},
867
+ ),
868
+ 'icon': 'hugeicons:money-send-flow-02',
744
869
  },
745
- ]
870
+ ],
746
871
  },
747
872
  {
748
873
  'type': 'links',
@@ -751,22 +876,31 @@ def navigation_menu(context, style):
751
876
  {
752
877
  'type': 'link',
753
878
  'title': 'Chart of Accounts',
754
- 'url': reverse('django_ledger:coa-list', kwargs={'entity_slug': ENTITY_SLUG}),
755
- 'icon': 'system-uicons:hierarchy'
879
+ 'url': reverse(
880
+ 'django_ledger:coa-list',
881
+ kwargs={'entity_slug': ENTITY_SLUG},
882
+ ),
883
+ 'icon': 'system-uicons:hierarchy',
756
884
  },
757
885
  {
758
886
  'type': 'link',
759
887
  'title': 'Ledgers',
760
- 'url': reverse('django_ledger:ledger-list-visible', kwargs={'entity_slug': ENTITY_SLUG}),
761
- 'icon': 'mdi:book-open'
888
+ 'url': reverse(
889
+ 'django_ledger:ledger-list-visible',
890
+ kwargs={'entity_slug': ENTITY_SLUG},
891
+ ),
892
+ 'icon': 'mdi:book-open',
762
893
  },
763
894
  {
764
895
  'type': 'link',
765
896
  'title': 'Data Import',
766
- 'url': reverse('django_ledger:data-import-jobs-list', kwargs={'entity_slug': ENTITY_SLUG}),
767
- 'icon': 'mdi:database-import'
768
- }
769
- ]
897
+ 'url': reverse(
898
+ 'django_ledger:data-import-jobs-list',
899
+ kwargs={'entity_slug': ENTITY_SLUG},
900
+ ),
901
+ 'icon': 'mdi:database-import',
902
+ },
903
+ ],
770
904
  },
771
905
  {
772
906
  'type': 'links',
@@ -776,58 +910,60 @@ def navigation_menu(context, style):
776
910
  'type': 'link',
777
911
  'title': 'My Entities',
778
912
  'url': reverse('django_ledger:home'),
779
- 'icon': 'mdi:home-group'
913
+ 'icon': 'mdi:home-group',
780
914
  },
781
915
  {
782
916
  'type': 'link',
783
917
  'title': 'Entity Settings',
784
- 'url': reverse('django_ledger:entity-update', kwargs={'entity_slug': ENTITY_SLUG}),
785
- 'icon': 'mdi:cog'
786
- }
787
- ]
788
- }
918
+ 'url': reverse(
919
+ 'django_ledger:entity-update',
920
+ kwargs={'entity_slug': ENTITY_SLUG},
921
+ ),
922
+ 'icon': 'mdi:cog',
923
+ },
924
+ ],
925
+ },
789
926
  ]
790
927
  ctx['links'] = nav_menu_links
791
928
  ctx['request'] = context['request']
792
929
  return ctx
793
930
 
794
- @register.inclusion_tag('django_ledger/product/tags/product_table.html', takes_context=True)
931
+
932
+ @register.inclusion_tag(
933
+ 'django_ledger/product/tags/product_table.html', takes_context=True
934
+ )
795
935
  def product_table(context, queryset):
796
936
  entity_slug = context['view'].kwargs['entity_slug']
797
- return {
798
- 'entity_slug': entity_slug,
799
- 'product_list': queryset
800
- }
937
+ return {'entity_slug': entity_slug, 'product_list': queryset}
801
938
 
802
939
 
803
- @register.inclusion_tag('django_ledger/service/tags/services_table.html', takes_context=True)
940
+ @register.inclusion_tag(
941
+ 'django_ledger/service/tags/services_table.html', takes_context=True
942
+ )
804
943
  def service_table(context, queryset):
805
944
  entity_slug = context['view'].kwargs['entity_slug']
806
- return {
807
- 'entity_slug': entity_slug,
808
- 'service_list': queryset
809
- }
945
+ return {'entity_slug': entity_slug, 'service_list': queryset}
810
946
 
811
947
 
812
- @register.inclusion_tag('django_ledger/expense/tags/expense_item_table.html', takes_context=True)
948
+ @register.inclusion_tag(
949
+ 'django_ledger/expense/tags/expense_item_table.html', takes_context=True
950
+ )
813
951
  def expense_item_table(context, queryset):
814
952
  entity_slug = context['view'].kwargs['entity_slug']
815
- return {
816
- 'entity_slug': entity_slug,
817
- 'expense_list': queryset
818
- }
953
+ return {'entity_slug': entity_slug, 'expense_list': queryset}
819
954
 
820
955
 
821
- @register.inclusion_tag('django_ledger/inventory/tags/inventory_item_table.html', takes_context=True)
956
+ @register.inclusion_tag(
957
+ 'django_ledger/inventory/tags/inventory_item_table.html', takes_context=True
958
+ )
822
959
  def inventory_item_table(context, queryset):
823
960
  entity_slug = context['view'].kwargs['entity_slug']
824
- return {
825
- 'entity_slug': entity_slug,
826
- 'inventory_item_list': queryset
827
- }
961
+ return {'entity_slug': entity_slug, 'inventory_item_list': queryset}
828
962
 
829
963
 
830
- @register.inclusion_tag('django_ledger/invoice/tags/invoice_item_formset.html', takes_context=True)
964
+ @register.inclusion_tag(
965
+ 'django_ledger/invoice/tags/invoice_item_formset.html', takes_context=True
966
+ )
831
967
  def invoice_item_formset_table(context, itemtxs_formset):
832
968
  return {
833
969
  'entity_slug': context['view'].kwargs['entity_slug'],
@@ -837,7 +973,9 @@ def invoice_item_formset_table(context, itemtxs_formset):
837
973
  }
838
974
 
839
975
 
840
- @register.inclusion_tag('django_ledger/bills/tags/bill_item_formset.html', takes_context=True)
976
+ @register.inclusion_tag(
977
+ 'django_ledger/bills/tags/bill_item_formset.html', takes_context=True
978
+ )
841
979
  def bill_item_formset_table(context, item_formset):
842
980
  return {
843
981
  'entity_slug': context['view'].kwargs['entity_slug'],
@@ -847,7 +985,9 @@ def bill_item_formset_table(context, item_formset):
847
985
  }
848
986
 
849
987
 
850
- @register.inclusion_tag('django_ledger/purchase_order/includes/po_item_formset.html', takes_context=True)
988
+ @register.inclusion_tag(
989
+ 'django_ledger/purchase_order/includes/po_item_formset.html', takes_context=True
990
+ )
851
991
  def po_item_formset_table(context, po_model, itemtxs_formset):
852
992
  return {
853
993
  'entity_slug': context['view'].kwargs['entity_slug'],
@@ -860,47 +1000,54 @@ def po_item_formset_table(context, po_model, itemtxs_formset):
860
1000
  def uom_table(context, uom_queryset):
861
1001
  return {
862
1002
  'entity_slug': context['view'].kwargs['entity_slug'],
863
- 'uom_list': uom_queryset
1003
+ 'uom_list': uom_queryset,
864
1004
  }
865
1005
 
866
1006
 
867
- @register.inclusion_tag('django_ledger/inventory/tags/inventory_table.html', takes_context=True)
1007
+ @register.inclusion_tag(
1008
+ 'django_ledger/inventory/tags/inventory_table.html', takes_context=True
1009
+ )
868
1010
  def inventory_table(context, queryset):
869
1011
  ctx = {
870
1012
  'entity_slug': context['view'].kwargs['entity_slug'],
871
- 'inventory_list': queryset
1013
+ 'inventory_list': queryset,
872
1014
  }
873
1015
  ctx.update(queryset.aggregate(inventory_total_value=Sum('total_value')))
874
1016
  return ctx
875
1017
 
876
1018
 
877
- @register.inclusion_tag('django_ledger/estimate/includes/estimate_table.html', takes_context=True)
1019
+ @register.inclusion_tag(
1020
+ 'django_ledger/estimate/includes/estimate_table.html', takes_context=True
1021
+ )
878
1022
  def customer_estimate_table(context, queryset):
879
- return {
880
- 'entity_slug': context['view'].kwargs['entity_slug'],
881
- 'ce_list': queryset
882
- }
1023
+ return {'entity_slug': context['view'].kwargs['entity_slug'], 'ce_list': queryset}
883
1024
 
884
1025
 
885
- @register.inclusion_tag('django_ledger/estimate/includes/estimate_item_table.html', takes_context=True)
1026
+ @register.inclusion_tag(
1027
+ 'django_ledger/estimate/includes/estimate_item_table.html', takes_context=True
1028
+ )
886
1029
  def estimate_item_table(context, queryset):
887
1030
  return {
888
1031
  'entity_slug': context['view'].kwargs['entity_slug'],
889
1032
  'ce_model': context['estimate_model'],
890
- 'ce_item_list': queryset
1033
+ 'ce_item_list': queryset,
891
1034
  }
892
1035
 
893
1036
 
894
- @register.inclusion_tag('django_ledger/purchase_order/tags/po_item_table.html', takes_context=True)
1037
+ @register.inclusion_tag(
1038
+ 'django_ledger/purchase_order/tags/po_item_table.html', takes_context=True
1039
+ )
895
1040
  def po_item_table(context, queryset):
896
1041
  return {
897
1042
  'entity_slug': context['view'].kwargs['entity_slug'],
898
1043
  'po_model': context['po_model'],
899
- 'po_item_list': queryset
1044
+ 'po_item_list': queryset,
900
1045
  }
901
1046
 
902
1047
 
903
- @register.inclusion_tag('django_ledger/estimate/tags/ce_item_formset.html', takes_context=True)
1048
+ @register.inclusion_tag(
1049
+ 'django_ledger/estimate/tags/ce_item_formset.html', takes_context=True
1050
+ )
904
1051
  def customer_estimate_item_formset(context, item_formset):
905
1052
  return {
906
1053
  'entity_slug': context['view'].kwargs['entity_slug'],