aa-ledger 1.0.4__py3-none-any.whl → 2.0.0__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.
Files changed (280) hide show
  1. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/METADATA +5 -6
  2. aa_ledger-2.0.0.dist-info/RECORD +267 -0
  3. ledger/__init__.py +2 -2
  4. ledger/admin.py +23 -18
  5. ledger/api/__init__.py +23 -7
  6. ledger/api/{ledger/admin.py → admin.py} +25 -31
  7. ledger/api/alliance.py +755 -0
  8. ledger/api/character.py +786 -0
  9. ledger/api/corporation.py +1141 -0
  10. ledger/api/{helpers.py → helpers/core.py} +33 -33
  11. ledger/api/helpers/icons.py +372 -0
  12. ledger/api/helpers/planetary_helper.py +354 -0
  13. ledger/api/planetary.py +354 -0
  14. ledger/api/schema.py +240 -15
  15. ledger/app_settings.py +11 -27
  16. ledger/auth_hooks.py +2 -2
  17. ledger/constants.py +50 -177
  18. ledger/decorators.py +2 -46
  19. ledger/forms.py +133 -39
  20. ledger/helpers/billboard.py +194 -144
  21. ledger/helpers/cache.py +105 -0
  22. ledger/helpers/discord.py +2 -4
  23. ledger/helpers/eveonline.py +160 -0
  24. ledger/helpers/ledger_data.py +23 -0
  25. ledger/helpers/ref_type.py +53 -78
  26. ledger/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  27. ledger/locale/cs_CZ/LC_MESSAGES/django.po +349 -193
  28. ledger/locale/de/LC_MESSAGES/django.mo +0 -0
  29. ledger/locale/de/LC_MESSAGES/django.po +528 -379
  30. ledger/locale/django.pot +721 -546
  31. ledger/locale/es/LC_MESSAGES/django.mo +0 -0
  32. ledger/locale/es/LC_MESSAGES/django.po +349 -194
  33. ledger/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  34. ledger/locale/fr_FR/LC_MESSAGES/django.po +349 -193
  35. ledger/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  36. ledger/locale/it_IT/LC_MESSAGES/django.po +349 -193
  37. ledger/locale/ja/LC_MESSAGES/django.mo +0 -0
  38. ledger/locale/ja/LC_MESSAGES/django.po +348 -193
  39. ledger/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
  40. ledger/locale/ko_KR/LC_MESSAGES/django.po +349 -193
  41. ledger/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  42. ledger/locale/nl_NL/LC_MESSAGES/django.po +349 -193
  43. ledger/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  44. ledger/locale/pl_PL/LC_MESSAGES/django.po +350 -193
  45. ledger/locale/ru/LC_MESSAGES/django.mo +0 -0
  46. ledger/locale/ru/LC_MESSAGES/django.po +348 -193
  47. ledger/locale/sk/LC_MESSAGES/django.mo +0 -0
  48. ledger/locale/sk/LC_MESSAGES/django.po +348 -193
  49. ledger/locale/uk/LC_MESSAGES/django.mo +0 -0
  50. ledger/locale/uk/LC_MESSAGES/django.po +348 -193
  51. ledger/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  52. ledger/locale/zh_Hans/LC_MESSAGES/django.po +348 -193
  53. ledger/managers/character_audit_manager.py +28 -20
  54. ledger/managers/character_journal_manager.py +185 -357
  55. ledger/managers/character_mining_manager.py +52 -26
  56. ledger/managers/character_planetary_manager.py +178 -136
  57. ledger/managers/corporation_audit_manager.py +36 -27
  58. ledger/managers/corporation_journal_manager.py +92 -56
  59. ledger/managers/general_manager.py +8 -7
  60. ledger/migrations/0018_remove_characterplanet_ledger_char_planet__58a5b6_idx_and_more.py +44 -0
  61. ledger/migrations/0019_rename_characteraudit_characterowner_and_more.py +48 -0
  62. ledger/models/__init__.py +5 -11
  63. ledger/models/characteraudit.py +101 -109
  64. ledger/models/corporationaudit.py +94 -49
  65. ledger/models/general.py +105 -211
  66. ledger/models/helpers/update_manager.py +302 -0
  67. ledger/models/planetary.py +60 -205
  68. ledger/providers.py +101 -0
  69. ledger/static/ledger/css/{ledger.css → aa-ledger.css} +54 -28
  70. ledger/static/ledger/js/aa-ledger.js +124 -0
  71. ledger/static/ledger/js/charts.js +25 -1
  72. ledger/static/ledger/js/view-alliance-ledger.js +383 -0
  73. ledger/static/ledger/js/view-character-ledger.js +388 -0
  74. ledger/static/ledger/js/view-corporation-ledger.js +402 -0
  75. ledger/static/ledger/js/view-planetary.js +492 -0
  76. ledger/static/ledger/libs/amCharts/5.14.4/js/flow.js +2 -0
  77. ledger/static/ledger/libs/amCharts/5.14.4/js/index.js +2 -0
  78. ledger/static/ledger/libs/amCharts/5.14.4/js/percent.js +2 -0
  79. ledger/static/ledger/libs/amCharts/5.14.4/js/themes/Animated.js +2 -0
  80. ledger/static/ledger/libs/amCharts/5.14.4/js/themes/Dark.js +2 -0
  81. ledger/static/ledger/libs/amCharts/5.14.4/js/xy.js +2 -0
  82. ledger/static/ledger/libs/datatables/2.3.5/css/dataTables.bootstrap5.css +610 -0
  83. ledger/static/ledger/libs/datatables/2.3.5/js/dataTables.bootstrap5.js +122 -0
  84. ledger/static/ledger/libs/datatables/2.3.5/js/dataTables.js +14127 -0
  85. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/css/columnControl.bootstrap5.css +516 -0
  86. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/css/columnControl.dataTables.css +529 -0
  87. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/js/columnControl.bootstrap5.js +73 -0
  88. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/js/dataTables.columnControl.js +3090 -0
  89. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/css/fixedHeader.bootstrap5.css +20 -0
  90. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/js/dataTables.fixedHeader.js +1203 -0
  91. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/js/fixedHeader.bootstrap5.js +59 -0
  92. ledger/tasks.py +157 -141
  93. ledger/templates/ledger/base.html +59 -21
  94. ledger/templates/ledger/bundles/aa-ledger-css.html +3 -0
  95. ledger/templates/ledger/bundles/aa-ledger-js.html +3 -0
  96. ledger/templates/ledger/bundles/view-alliance-ledger-js.html +14 -0
  97. ledger/templates/ledger/bundles/view-character-ledger-js.html +15 -0
  98. ledger/templates/ledger/bundles/view-character-planetary-css.html +3 -0
  99. ledger/templates/ledger/bundles/view-character-planetary-js.html +4 -0
  100. ledger/templates/ledger/bundles/view-corporation-ledger-js.html +15 -0
  101. ledger/templates/ledger/partials/modal/confirm.html +0 -1
  102. ledger/templates/ledger/partials/modal/request-accept-delete-alliance.html +38 -0
  103. ledger/templates/ledger/partials/modal/request-accept-delete-character.html +38 -0
  104. ledger/templates/ledger/partials/modal/request-accept-delete-corporation.html +38 -0
  105. ledger/templates/ledger/partials/modal/request-accept-switch-notification.html +38 -0
  106. ledger/templates/ledger/partials/modal/request-view-alliance-details.html +26 -0
  107. ledger/templates/ledger/partials/modal/request-view-character-details.html +26 -0
  108. ledger/templates/ledger/partials/modal/request-view-corporation-details.html +26 -0
  109. ledger/templates/ledger/partials/modal/request-view-extractor.html +32 -0
  110. ledger/templates/ledger/partials/modal/request-view-factory.html +31 -0
  111. ledger/templates/ledger/partials/{menu → navigation}/administration.html +8 -0
  112. ledger/templates/ledger/partials/{menu → navigation}/navigation.html +2 -2
  113. ledger/templates/ledger/partials/{administration → view-alliance-administration}/alliance_corporations.html +3 -3
  114. ledger/templates/ledger/partials/view-alliance-administration/dashboard.html +81 -0
  115. ledger/templates/ledger/partials/view-alliance-ledger/alliance-billboard.html +25 -0
  116. ledger/templates/ledger/partials/view-alliance-ledger/alliance-ledger-details.html +21 -0
  117. ledger/templates/ledger/partials/view-alliance-ledger/alliance-table.html +24 -0
  118. ledger/templates/ledger/partials/view-alliance-ledger/information/daily.html +18 -0
  119. ledger/templates/ledger/partials/view-alliance-ledger/information/hourly.html +18 -0
  120. ledger/templates/ledger/partials/view-alliance-ledger/information/summary.html +19 -0
  121. ledger/templates/ledger/partials/{administration → view-character-administration}/character.html +1 -9
  122. ledger/templates/ledger/partials/{administration → view-character-administration}/dashboard.html +0 -34
  123. ledger/templates/ledger/partials/view-character-ledger/character-billboard.html +25 -0
  124. ledger/templates/ledger/partials/view-character-ledger/character-ledger-details.html +21 -0
  125. ledger/templates/ledger/partials/view-character-ledger/character-table.html +25 -0
  126. ledger/templates/ledger/partials/view-character-ledger/information/daily.html +18 -0
  127. ledger/templates/ledger/partials/view-character-ledger/information/hourly.html +18 -0
  128. ledger/templates/ledger/partials/view-character-ledger/information/summary.html +19 -0
  129. ledger/templates/ledger/partials/view-character-planetary/extractor-table.html +24 -0
  130. ledger/templates/ledger/partials/view-character-planetary/factory-table.html +24 -0
  131. ledger/templates/ledger/partials/view-character-planetary/planetary-table.html +22 -0
  132. ledger/templates/ledger/partials/view-character-planetary/storage-table.html +23 -0
  133. ledger/templates/ledger/partials/{administration → view-corporation-administration}/corporation.html +5 -13
  134. ledger/templates/ledger/partials/{administration → view-corporation-administration}/corporation_characters.html +1 -1
  135. ledger/templates/ledger/partials/view-corporation-administration/dashboard.html +81 -0
  136. ledger/templates/ledger/partials/view-corporation-ledger/corporation-billboard.html +25 -0
  137. ledger/templates/ledger/partials/view-corporation-ledger/corporation-ledger-details.html +21 -0
  138. ledger/templates/ledger/partials/view-corporation-ledger/corporation-table.html +26 -0
  139. ledger/templates/ledger/partials/view-corporation-ledger/information/daily.html +18 -0
  140. ledger/templates/ledger/partials/view-corporation-ledger/information/hourly.html +18 -0
  141. ledger/templates/ledger/partials/view-corporation-ledger/information/summary.html +19 -0
  142. ledger/templates/ledger/view-administration.html +62 -0
  143. ledger/templates/ledger/view-alliance-administration.html +49 -0
  144. ledger/templates/ledger/view-alliance-ledger.html +72 -0
  145. ledger/templates/ledger/view-alliance-overview.html +131 -0
  146. ledger/templates/ledger/view-character-administration.html +42 -0
  147. ledger/templates/ledger/view-character-ledger.html +73 -0
  148. ledger/templates/ledger/view-character-overview.html +135 -0
  149. ledger/templates/ledger/view-character-planetary-overview.html +135 -0
  150. ledger/templates/ledger/view-character-planetary.html +73 -0
  151. ledger/templates/ledger/view-corporation-administration.html +42 -0
  152. ledger/templates/ledger/view-corporation-ledger.html +73 -0
  153. ledger/templates/ledger/view-corporation-overview.html +131 -0
  154. ledger/templatetags/ledger.py +3 -5
  155. ledger/tests/__init__.py +187 -0
  156. ledger/tests/test_admin.py +164 -68
  157. ledger/tests/test_auth_hook.py +31 -13
  158. ledger/tests/test_decarators.py +14 -79
  159. ledger/tests/test_discord_installed.py +0 -1
  160. ledger/tests/test_helpers/test_ledger_data.py +19 -0
  161. ledger/tests/test_managers/test_character_audit_manager.py +111 -69
  162. ledger/tests/test_managers/test_character_journal_manager.py +48 -208
  163. ledger/tests/test_managers/test_character_mining_manager.py +37 -16
  164. ledger/tests/test_managers/test_corporation_division_manager.py +66 -28
  165. ledger/tests/test_managers/test_corporation_journal_manager.py +39 -42
  166. ledger/tests/test_managers/test_general_manager.py +78 -18
  167. ledger/tests/test_managers/test_planetary_manager.py +73 -32
  168. ledger/tests/test_models/test_characteraudit.py +58 -74
  169. ledger/tests/test_models/test_characterminingledger.py +20 -26
  170. ledger/tests/test_models/test_characterwalletjournal.py +10 -33
  171. ledger/tests/test_models/test_corporationaudit.py +41 -35
  172. ledger/tests/test_models/test_corporationwalletjournal.py +35 -32
  173. ledger/tests/test_models/test_general.py +44 -11
  174. ledger/tests/test_models/test_planetary.py +14 -80
  175. ledger/tests/test_templatetags.py +2 -7
  176. ledger/tests/test_views/corporation/test_add_corp.py +16 -35
  177. ledger/tests/test_views/corporation/test_delete_corporation.py +66 -42
  178. ledger/tests/test_views/test_access.py +512 -545
  179. ledger/tests/test_views/test_add_ally.py +57 -46
  180. ledger/tests/test_views/test_add_char.py +21 -33
  181. ledger/tests/test_views/test_delete_character.py +24 -21
  182. ledger/tests/testdata/README_ESI_STUB.md +430 -0
  183. ledger/tests/testdata/esi_stub_openapi.py +511 -0
  184. ledger/tests/testdata/integrations/__init__.py +0 -0
  185. ledger/tests/testdata/{load_eveuniverse.py → integrations/eveuniverse.py} +0 -1
  186. ledger/tests/testdata/integrations/planetary.py +13 -0
  187. ledger/tests/testdata/json/factory.json +281 -0
  188. ledger/tests/testdata/json/inactive.json +281 -0
  189. ledger/tests/testdata/json/pins.json +175 -272
  190. ledger/tests/testdata/json/route.json +95 -528
  191. ledger/tests/testdata/test_esi_stub.py +468 -0
  192. ledger/tests/testdata/utils.py +601 -0
  193. ledger/thirdparty/charlink_hook.py +60 -30
  194. ledger/urls.py +0 -135
  195. ledger/views/alliance/add_ally.py +2 -4
  196. ledger/views/alliance/alliance_ledger.py +64 -147
  197. ledger/views/character/add_char.py +8 -10
  198. ledger/views/character/character_ledger.py +60 -126
  199. ledger/views/character/planetary.py +5 -98
  200. ledger/views/corporation/add_corp.py +10 -12
  201. ledger/views/corporation/corporation_ledger.py +65 -327
  202. ledger/views/index.py +92 -30
  203. aa_ledger-1.0.4.dist-info/RECORD +0 -236
  204. ledger/api/api_helper/planetary_helper.py +0 -107
  205. ledger/api/ledger/__init__.py +0 -7
  206. ledger/api/ledger/planetary.py +0 -231
  207. ledger/helpers/alliance.py +0 -317
  208. ledger/helpers/character.py +0 -251
  209. ledger/helpers/core.py +0 -665
  210. ledger/helpers/corporation.py +0 -427
  211. ledger/helpers/data_exporter.py +0 -452
  212. ledger/static/ledger/js/planetary-confirm.js +0 -66
  213. ledger/static/ledger/js/planetary.js +0 -143
  214. ledger/templates/ledger/admin.html +0 -43
  215. ledger/templates/ledger/allyledger/admin/alliance_administration.html +0 -46
  216. ledger/templates/ledger/allyledger/admin/alliance_overview.html +0 -108
  217. ledger/templates/ledger/allyledger/alliance_ledger.html +0 -86
  218. ledger/templates/ledger/bundles/character-ledger-bundles.html +0 -66
  219. ledger/templates/ledger/bundles/corporation-ledger-bundles.html +0 -75
  220. ledger/templates/ledger/bundles/ledger-bundles.html +0 -23
  221. ledger/templates/ledger/bundles/ledger-css.html +0 -3
  222. ledger/templates/ledger/bundles/planetary-bundles.html +0 -50
  223. ledger/templates/ledger/bundles/table-css.html +0 -3
  224. ledger/templates/ledger/charledger/admin/character_administration.html +0 -39
  225. ledger/templates/ledger/charledger/admin/character_overview.html +0 -106
  226. ledger/templates/ledger/charledger/character_ledger.html +0 -94
  227. ledger/templates/ledger/charledger/planetary/admin/planetary_overview.html +0 -123
  228. ledger/templates/ledger/charledger/planetary/planetary_ledger.html +0 -54
  229. ledger/templates/ledger/corpledger/admin/corporation_administration.html +0 -39
  230. ledger/templates/ledger/corpledger/admin/corporation_overview.html +0 -108
  231. ledger/templates/ledger/corpledger/corporation_ledger.html +0 -129
  232. ledger/templates/ledger/data-export.html +0 -78
  233. ledger/templates/ledger/error.html +0 -31
  234. ledger/templates/ledger/partials/form/error-message.html +0 -1
  235. ledger/templates/ledger/partials/information/daily.html +0 -56
  236. ledger/templates/ledger/partials/information/day.html +0 -48
  237. ledger/templates/ledger/partials/information/error.html +0 -8
  238. ledger/templates/ledger/partials/information/hourly.html +0 -53
  239. ledger/templates/ledger/partials/information/summary.html +0 -88
  240. ledger/templates/ledger/partials/information/view_character_content.html +0 -35
  241. ledger/templates/ledger/partials/modal/switchalarm_confirm.html +0 -39
  242. ledger/templates/ledger/partials/modal/view_extractor.html +0 -48
  243. ledger/templates/ledger/partials/modal/view_factory.html +0 -123
  244. ledger/templates/ledger/partials/table/char-ledger.html +0 -85
  245. ledger/templates/ledger/partials/table/corp-ledger.html +0 -66
  246. ledger/templates/ledger/partials/table/planetary.html +0 -18
  247. ledger/templates/ledger/partials/thirdparty/billboard.html +0 -22
  248. ledger/templates/ledger/partials/view/card.html +0 -160
  249. ledger/templates/ledger/permission.html +0 -2
  250. ledger/tests/test_helpers/test_billboard.py +0 -11
  251. ledger/tests/test_helpers/test_data_exporter.py +0 -207
  252. ledger/tests/test_tasks.py +0 -282
  253. ledger/tests/test_view_helpers/test_core.py +0 -47
  254. ledger/tests/test_views/corporation/test_corporation.py +0 -267
  255. ledger/tests/test_views/test_planetary.py +0 -137
  256. ledger/tests/testdata/esi_stub.py +0 -109
  257. ledger/tests/testdata/esi_stub_migration.py +0 -80
  258. ledger/tests/testdata/generate_characteraudit.py +0 -106
  259. ledger/tests/testdata/generate_corporationaudit.py +0 -74
  260. ledger/tests/testdata/generate_events.py +0 -31
  261. ledger/tests/testdata/generate_miningledger.py +0 -13
  262. ledger/tests/testdata/generate_planets.py +0 -48
  263. ledger/tests/testdata/generate_walletjournal.py +0 -42
  264. ledger/tests/testdata/json/czarno-pins.json +0 -240
  265. ledger/tests/testdata/json/czarno-routes.json +0 -165
  266. ledger/tests/testdata/json/pins2.json +0 -538
  267. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/WHEEL +0 -0
  268. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/licenses/LICENSE +0 -0
  269. /ledger/{tests/test_view_helpers → api/helpers}/__init__.py +0 -0
  270. /ledger/templates/ledger/bundles/{ally-administration-bundles.html → view-alliance-administration-js.html} +0 -0
  271. /ledger/templates/ledger/bundles/{char-administration-bundles.html → view-character-administration-js.html} +0 -0
  272. /ledger/templates/ledger/bundles/{corp-administration-bundles.html → view-corporation-administration-js.html} +0 -0
  273. /ledger/templates/ledger/partials/{administration → view-alliance-administration}/alliance.html +0 -0
  274. /ledger/tests/testdata/{esi.json → esi_test_data.json} +0 -0
  275. /ledger/tests/testdata/{allianceauth.json → integrations/allianceauth.json} +0 -0
  276. /ledger/tests/testdata/{load_allianceauth.py → integrations/allianceauth.py} +0 -0
  277. /ledger/tests/testdata/{eveentity.json → integrations/eveentity.json} +0 -0
  278. /ledger/tests/testdata/{load_eveentity.py → integrations/eveentity.py} +0 -0
  279. /ledger/tests/testdata/{eveuniverse.json → integrations/eveuniverse.json} +0 -0
  280. /ledger/tests/testdata/{planetary.json → integrations/planetary.json} +0 -0
@@ -0,0 +1,786 @@
1
+ # Standard Library
2
+ from decimal import Decimal
3
+
4
+ # Third Party
5
+ from ninja import NinjaAPI, Schema
6
+
7
+ # Django
8
+ from django.contrib.humanize.templatetags.humanize import intcomma
9
+ from django.core.handlers.wsgi import WSGIRequest
10
+ from django.db.models import Q, QuerySet
11
+ from django.utils import timezone
12
+ from django.utils.translation import gettext as _
13
+
14
+ # Alliance Auth
15
+ from allianceauth.services.hooks import get_extension_logger
16
+
17
+ # AA Ledger
18
+ from ledger import __title__
19
+ from ledger.api.helpers.core import (
20
+ get_characterowner_or_none,
21
+ )
22
+ from ledger.api.helpers.icons import (
23
+ get_character_details_info_button,
24
+ get_ref_type_details_popover_button,
25
+ )
26
+ from ledger.api.schema import (
27
+ BillboardSchema,
28
+ CategorySchema,
29
+ CharacterLedgerSchema,
30
+ LedgerDetailsResponse,
31
+ LedgerDetailsSummary,
32
+ LedgerResponse,
33
+ OwnerLedgerRequestInfo,
34
+ OwnerSchema,
35
+ UpdateStatusSchema,
36
+ )
37
+ from ledger.helpers.billboard import BillboardSystem
38
+ from ledger.helpers.cache import CacheManager
39
+ from ledger.helpers.ledger_data import get_footer_text_class
40
+ from ledger.helpers.ref_type import RefTypeManager
41
+ from ledger.models.characteraudit import (
42
+ CharacterMiningLedger,
43
+ CharacterOwner,
44
+ CharacterWalletJournalEntry,
45
+ )
46
+ from ledger.providers import AppLogger
47
+
48
+ logger = AppLogger(get_extension_logger(__name__), __title__)
49
+
50
+
51
+ class LedgerCharacterSchema(Schema):
52
+ character: OwnerSchema
53
+ ledger: CharacterLedgerSchema
54
+ update_status: UpdateStatusSchema
55
+ actions: str = ""
56
+
57
+
58
+ class CharacterLedgerResponse(LedgerResponse):
59
+ """
60
+ Schema for Character Ledger Response.
61
+
62
+ This schema represents the response structure for a character's ledger,
63
+ extending the base :class:`LedgerResponse` to include character-specific information.
64
+
65
+ Attributes:
66
+ information (OwnerLedgerRequestInfo): Information about the ledger request.
67
+ characters (list[LedgerCharacterSchema]): List of character ledger data.
68
+ """
69
+
70
+ information: OwnerLedgerRequestInfo
71
+ characters: list[LedgerCharacterSchema]
72
+
73
+
74
+ class CharacterApiEndpoints:
75
+ tags = ["Character"]
76
+
77
+ # pylint: disable=too-many-statements, function-redefined
78
+ # flake8: noqa: F811
79
+ def __init__(self, api: NinjaAPI):
80
+ self.cache_manager = CacheManager()
81
+ self.billboard = BillboardSystem()
82
+
83
+ @api.get(
84
+ "character/{character_id}/date/{year}/",
85
+ response={200: CharacterLedgerResponse, 403: dict, 404: dict},
86
+ tags=self.tags,
87
+ )
88
+ def get_character_ledger(request: WSGIRequest, character_id: int, year: int):
89
+ """Get the ledger for a character for a specific year. Admin Endpoint."""
90
+ return self._ledger_api_response(
91
+ request=request,
92
+ character_id=character_id,
93
+ year=year,
94
+ )
95
+
96
+ @api.get(
97
+ "character/{character_id}/date/{year}/{month}/",
98
+ response={200: CharacterLedgerResponse, 403: dict, 404: dict},
99
+ tags=self.tags,
100
+ )
101
+ def get_character_ledger(
102
+ request: WSGIRequest, character_id: int, year: int, month: int
103
+ ):
104
+ """Get the ledger for a character for a specific year. Admin Endpoint."""
105
+ return self._ledger_api_response(
106
+ request=request,
107
+ character_id=character_id,
108
+ year=year,
109
+ month=month,
110
+ )
111
+
112
+ @api.get(
113
+ "character/{character_id}/date/{year}/{month}/{day}/",
114
+ response={200: CharacterLedgerResponse, 403: dict, 404: dict},
115
+ tags=self.tags,
116
+ )
117
+ def get_character_ledger(
118
+ request: WSGIRequest,
119
+ character_id: int,
120
+ year: int,
121
+ month: int,
122
+ day: int,
123
+ ):
124
+ """Get the ledger for a character for a specific year. Admin Endpoint."""
125
+ return self._ledger_api_response(
126
+ request=request,
127
+ character_id=character_id,
128
+ year=year,
129
+ month=month,
130
+ day=day,
131
+ )
132
+
133
+ def _create_datatable_footer(
134
+ self,
135
+ characters: list[LedgerCharacterSchema],
136
+ request_info: OwnerLedgerRequestInfo,
137
+ ) -> OwnerLedgerRequestInfo:
138
+ """
139
+ Create the footer HTML for the Ledger datatable.
140
+
141
+ This Helper function creates the footer HTML for the Ledger datatable
142
+ by summing up the respective fields from the list of characters.
143
+
144
+ Args:
145
+ characters (list[LedgerCharacterSchema]): The list of character ledger data.
146
+
147
+ Returns:
148
+ str: The generated footer HTML.
149
+ """
150
+ total_bounty = sum(char.ledger.bounty for char in characters)
151
+ total_ess = sum(char.ledger.ess for char in characters)
152
+ total_mining = sum(char.ledger.mining for char in characters)
153
+ total_costs = sum(char.ledger.costs for char in characters)
154
+ total_miscellaneous = sum(char.ledger.miscellaneous for char in characters)
155
+ total_total = sum(char.ledger.total for char in characters)
156
+
157
+ # Generate Details Link
158
+ url = get_character_details_info_button(
159
+ character_id=request_info.owner_id,
160
+ request_info=request_info,
161
+ )
162
+
163
+ # Skip Footer if no Totals
164
+ if total_total == 0:
165
+ return ""
166
+
167
+ info_title = _("This amount is displayed for information only")
168
+ info_html = f"""
169
+ <i class="fa-regular fa-circle-question"
170
+ data-bs-tooltip="aa-ledger" data-bs-placement="top"
171
+ title="{info_title}"
172
+ >
173
+ </i>
174
+ """
175
+
176
+ footer_html = f"""
177
+ <tr>
178
+ <th class="border-top">{_("Summary")}</th>
179
+ <th class="border-top text-end {get_footer_text_class(total_bounty)}">{intcomma(value=int(total_bounty), use_l10n=True)} ISK</th>
180
+ <th class="border-top text-end {get_footer_text_class(total_ess)}">{intcomma(value=int(total_ess), use_l10n=True)} ISK</th>
181
+ <th class="border-top text-end {get_footer_text_class(total_mining, mining=True)}">{intcomma(value=int(total_mining), use_l10n=True)} ISK {info_html}</th>
182
+ <th class="border-top text-end {get_footer_text_class(total_miscellaneous)}">{intcomma(value=int(total_miscellaneous), use_l10n=True)} ISK</th>
183
+ <th class="border-top text-end {get_footer_text_class(total_costs)}">{intcomma(value=int(total_costs), use_l10n=True)} ISK</th>
184
+ <th class="border-start border-top text-end {get_footer_text_class(total_total)}">{intcomma(value=int(total_total), use_l10n=True)} ISK</th>
185
+ <th class="border-top">{url}</th>
186
+ </tr>
187
+ """
188
+ request_info.footer_html = footer_html
189
+ return request_info
190
+
191
+ # pylint: disable=too-many-locals
192
+ def generate_character_data(
193
+ self, owner: CharacterOwner, request_info: OwnerLedgerRequestInfo
194
+ ) -> list[CharacterLedgerResponse]:
195
+ """
196
+ Generate the ledger data for all alts of a character owner.
197
+
198
+ This Helper function generates the ledger data for all alts of a character owner
199
+ based on the provided date query.
200
+
201
+ Args:
202
+ owner (CharacterOwner): The character owner object.
203
+ request_info (LedgerRequestInfo): The request information containing date and section details.
204
+ Returns:
205
+ list[LedgerCharacterSchema]: A list of ledger responses for each character.
206
+ """
207
+ # Get All Alts for this Owner
208
+ characters = CharacterOwner.objects.filter(
209
+ eve_character__character_id__in=owner.alt_ids
210
+ )
211
+
212
+ # Create Ledger Response for each Character
213
+ character_ledger_list: list[LedgerCharacterSchema] = []
214
+ for character in characters:
215
+ # Get Journal Data
216
+ wallet_journal = (
217
+ character.ledger_character_journal.filter(
218
+ **request_info.to_date_query(),
219
+ )
220
+ # Exclude Zero Amount Entries
221
+ .exclude(amount=Decimal("0.00"))
222
+ # Exclude Internal Donations between Alts
223
+ .exclude(
224
+ Q(ref_type="player_donation")
225
+ & (
226
+ Q(first_party__in=owner.alt_ids)
227
+ & Q(second_party__in=owner.alt_ids)
228
+ )
229
+ ).order_by("-date")
230
+ )
231
+
232
+ mining_journal = character.ledger_character_mining.filter(
233
+ **request_info.to_date_query(),
234
+ ).order_by("-date")
235
+
236
+ # Get IDs for Hashing
237
+ entry_ids = wallet_journal.values_list("entry_id", flat=True)
238
+ mining_pks = mining_journal.values_list("type_id", flat=True)
239
+ header_ids = list(entry_ids) + list(mining_pks)
240
+
241
+ # Skip Character if no Ledger Entries
242
+ if len(header_ids) == 0:
243
+ logger.debug(f"Skipping Character {character} - No Ledger Entries")
244
+ continue
245
+
246
+ # Add Character ID to header ids to ensure uniqueness
247
+ header_ids.append(character.eve_character.character_id)
248
+
249
+ # Create Ledger Hash
250
+ wallet_journal_hash = self.cache_manager.create_ledger_hash(header_ids)
251
+
252
+ # Get Cached Ledger if Available
253
+ response_ledger = self.cache_manager.get_cache_key(
254
+ key="character", ledger_hash=wallet_journal_hash
255
+ )
256
+ if response_ledger is False:
257
+ logger.debug(f"Ledger Cache Miss for Character: {character}")
258
+
259
+ # Aggregate Data
260
+ character_bounty = wallet_journal.aggregate_bounty()
261
+ character_ess = wallet_journal.aggregate_ess()
262
+ character_mining = mining_journal.aggregate_mining()
263
+ character_costs = wallet_journal.aggregate_costs()
264
+ character_miscellaneous = wallet_journal.aggregate_miscellaneous()
265
+
266
+ total = sum(
267
+ [
268
+ character_bounty,
269
+ character_ess,
270
+ character_miscellaneous,
271
+ character_costs,
272
+ ]
273
+ )
274
+
275
+ response_ledger = LedgerCharacterSchema(
276
+ character=OwnerSchema(
277
+ character_id=character.eve_character.character_id,
278
+ character_name=character.eve_character.character_name,
279
+ icon=character.get_portrait(size=32, as_html=True),
280
+ ),
281
+ ledger=CharacterLedgerSchema(
282
+ bounty=character_bounty,
283
+ ess=character_ess,
284
+ mining=character_mining,
285
+ costs=character_costs,
286
+ miscellaneous=character_miscellaneous,
287
+ total=total,
288
+ ),
289
+ update_status=UpdateStatusSchema(
290
+ status=owner.get_status,
291
+ ),
292
+ actions=get_character_details_info_button(
293
+ character_id=character.eve_character.character_id,
294
+ request_info=request_info,
295
+ section="single",
296
+ ),
297
+ )
298
+ # Cache Ledger Response
299
+ self.cache_manager.set_cache_key(
300
+ key="character",
301
+ ledger_hash=wallet_journal_hash,
302
+ ledger_data=response_ledger,
303
+ )
304
+
305
+ # Add Character Ledger to List
306
+ character_ledger_list.append(response_ledger)
307
+ return character_ledger_list
308
+
309
+ # pylint: disable=too-many-locals
310
+ def generate_billboard_data(
311
+ self,
312
+ owner: CharacterOwner,
313
+ character_ledger_list: list[LedgerCharacterSchema],
314
+ request_info: OwnerLedgerRequestInfo,
315
+ ) -> BillboardSchema:
316
+ """
317
+ Generate the billboard data for the given character IDs.
318
+
319
+ This Helper function generates the billboard data for the given character IDs
320
+ based on the provided date query.
321
+
322
+ Args:
323
+ character_ids (list[int]): The list of character IDs.
324
+ character_ledger_list (list[LedgerCharacterSchema]): The list of character ledger data.
325
+ request_info (LedgerRequestInfo): The request information containing date and section details.
326
+ Returns:
327
+ LedgerBillboard: The generated billboard data.
328
+ """
329
+ # Get Wallet and Mining Journal Entries
330
+ wallet_journal = (
331
+ CharacterWalletJournalEntry.objects.filter(
332
+ character__eve_character__character_id__in=owner.alt_ids,
333
+ **request_info.to_date_query(),
334
+ )
335
+ # Exclude Zero Amount Entries
336
+ .exclude(amount=Decimal("0.00"))
337
+ # Exclude Internal Donations between Alts
338
+ .exclude(
339
+ Q(ref_type="player_donation")
340
+ & (Q(first_party__in=owner.alt_ids) & Q(second_party__in=owner.alt_ids))
341
+ ).order_by("-date")
342
+ )
343
+
344
+ mining_journal = CharacterMiningLedger.objects.filter(
345
+ character__eve_character__character_id__in=owner.alt_ids,
346
+ **request_info.to_date_query(),
347
+ ).order_by("-date")
348
+
349
+ # Get IDs for Hashing
350
+ entry_ids = wallet_journal.values_list("entry_id", flat=True)
351
+ mining_pks = mining_journal.values_list("type_id", flat=True)
352
+ header_ids = list(entry_ids) + list(mining_pks)
353
+
354
+ # Skip Character if no Ledger Entries
355
+ if len(header_ids) == 0:
356
+ logger.debug(
357
+ f"No Ledger Entries for Billboard Generation for Character IDs: {owner.alt_ids}"
358
+ )
359
+ return BillboardSchema()
360
+
361
+ # add character ids to header ids to ensure uniqueness
362
+ header_ids.extend(owner.alt_ids)
363
+
364
+ # Create Ledger Hash
365
+ wallet_journal_hash = self.cache_manager.create_ledger_hash(header_ids)
366
+
367
+ # Get Cached Billboard if Available
368
+ response_billboard = self.cache_manager.get_cache_key(
369
+ key="character-billboard", ledger_hash=wallet_journal_hash
370
+ )
371
+ if response_billboard is False:
372
+ logger.debug(f"Billboard Cache Miss for Character IDs: {owner.alt_ids}")
373
+ # Create Timelines
374
+ wallet_timeline = (
375
+ self.billboard.create_timeline(
376
+ journal=wallet_journal, request_info=request_info
377
+ )
378
+ .annotate_bounty_income()
379
+ .annotate_ess_income()
380
+ .annotate_miscellaneous()
381
+ )
382
+ mining_timeline = self.billboard.create_timeline(
383
+ journal=mining_journal, request_info=request_info
384
+ ).annotate_mining(with_period=True)
385
+
386
+ # Generate XY Billboard
387
+ xy_results = self.billboard.create_or_update_results(wallet_timeline)
388
+ xy_results = self.billboard.add_category_to_xy_billboard(
389
+ xy_results, category="mining", queryset=mining_timeline
390
+ )
391
+ xy_billboard = self.billboard.create_xy_billboard(
392
+ results=xy_results, request_info=request_info
393
+ )
394
+ # Initialize Chord Billboard
395
+ chord_billboard = self.billboard.create_chord_billboard(
396
+ character_ledger_list
397
+ )
398
+
399
+ response_billboard = BillboardSchema(
400
+ xy_chart=xy_billboard,
401
+ chord_chart=chord_billboard,
402
+ )
403
+ # Cache Billboard Response
404
+ self.cache_manager.set_cache_key(
405
+ key="character-billboard",
406
+ ledger_hash=wallet_journal_hash,
407
+ ledger_data=response_billboard,
408
+ )
409
+ # Billboard Data Generation Logic Here
410
+ return response_billboard
411
+
412
+ # pylint: disable=too-many-positional-arguments
413
+ def _ledger_api_response(
414
+ self,
415
+ request,
416
+ character_id: int,
417
+ year: int,
418
+ month: int = None,
419
+ day: int = None,
420
+ ) -> CharacterLedgerResponse | tuple[int, dict]:
421
+ """
422
+ Helper function to generate ledger response for various date parameters.
423
+
424
+ This function consolidates the common logic for generating the ledger response
425
+ based on the provided date parameters (year, month, day) and section.
426
+
427
+ Args:
428
+ request (WSGIRequest): The incoming request object.
429
+ character_id (int): The character ID.
430
+ year (int): The year for the ledger data.
431
+ month (int, optional): The month for the ledger data. Defaults to None.
432
+ day (int, optional): The day for the ledger data. Defaults to None.
433
+ section (str): The section type ('single' or 'summary').
434
+
435
+ Returns:
436
+ CharacterLedgerResponse | tuple[int, dict]: The ledger response or error tuple.
437
+ """
438
+
439
+ perms, owner = get_characterowner_or_none(
440
+ request=request, character_id=character_id
441
+ )
442
+
443
+ if owner is None:
444
+ return 404, {"error": _("Character not found in Ledger.")}
445
+
446
+ if perms is False:
447
+ return 403, {
448
+ "error": _("You do not have permission to view this character.")
449
+ }
450
+
451
+ # Build Request Info
452
+ request_info = OwnerLedgerRequestInfo(
453
+ owner_id=owner.eve_character.character_id,
454
+ year=year,
455
+ month=month,
456
+ day=day,
457
+ )
458
+
459
+ # Generate Character Ledger Data
460
+ character_ledger_list = self.generate_character_data(
461
+ owner=owner,
462
+ request_info=request_info,
463
+ )
464
+
465
+ # Generate Billboard Data
466
+ billboard = self.generate_billboard_data(
467
+ owner=owner,
468
+ character_ledger_list=character_ledger_list,
469
+ request_info=request_info,
470
+ )
471
+
472
+ # Update Request Info with Available Data
473
+ self._create_datatable_footer(
474
+ characters=character_ledger_list, request_info=request_info
475
+ )
476
+
477
+ response_ledger = CharacterLedgerResponse(
478
+ owner=OwnerSchema(
479
+ character_id=owner.eve_character.character_id,
480
+ character_name=owner.eve_character.character_name,
481
+ icon=owner.get_portrait(as_html=True),
482
+ ),
483
+ information=request_info,
484
+ characters=character_ledger_list,
485
+ billboard=billboard,
486
+ actions=get_character_details_info_button(
487
+ character_id=owner.eve_character.character_id,
488
+ request_info=request_info,
489
+ ),
490
+ )
491
+
492
+ return response_ledger
493
+
494
+
495
+ class CharacterDetailsApiEndpoints:
496
+ tags = ["Character Details"]
497
+
498
+ # pylint: disable=too-many-statements, function-redefined
499
+ def __init__(self, api: NinjaAPI):
500
+ @api.get(
501
+ "character/{character_id}/date/{year}/section/{section}/view/details/",
502
+ response={200: LedgerDetailsResponse, 403: dict, 404: dict},
503
+ tags=self.tags,
504
+ )
505
+ def get_character_ledger_details(
506
+ request: WSGIRequest, character_id: int, year: int, section: str
507
+ ):
508
+ return self._ledger_details_api_response(
509
+ request=request,
510
+ character_id=character_id,
511
+ year=year,
512
+ section=section,
513
+ )
514
+
515
+ @api.get(
516
+ "character/{character_id}/date/{year}/{month}/section/{section}/view/details/",
517
+ response={200: LedgerDetailsResponse, 403: dict, 404: dict},
518
+ tags=self.tags,
519
+ )
520
+ def get_character_ledger_details(
521
+ request: WSGIRequest, character_id: int, year: int, month: int, section: str
522
+ ):
523
+ return self._ledger_details_api_response(
524
+ request=request,
525
+ character_id=character_id,
526
+ year=year,
527
+ month=month,
528
+ section=section,
529
+ )
530
+
531
+ @api.get(
532
+ "character/{character_id}/date/{year}/{month}/{day}/section/{section}/view/details/",
533
+ response={200: LedgerDetailsResponse, 403: dict, 404: dict},
534
+ tags=self.tags,
535
+ )
536
+ def get_character_ledger_details(
537
+ request: WSGIRequest,
538
+ character_id: int,
539
+ year: int,
540
+ month: int,
541
+ day: int,
542
+ section: str,
543
+ ):
544
+ return self._ledger_details_api_response(
545
+ request=request,
546
+ character_id=character_id,
547
+ year=year,
548
+ month=month,
549
+ day=day,
550
+ section=section,
551
+ )
552
+
553
+ def _create_datatable_footer(self, value: float) -> str:
554
+ """Create the footer HTML for the datatable."""
555
+ footer_html = f"""
556
+ <tr>
557
+ <th>{_('Summary')}</th>
558
+ <th class="text-end {get_footer_text_class(value)}">{intcomma(value=int(value), use_l10n=True)} ISK</th>
559
+ <th></th>
560
+ </tr>
561
+ """
562
+ return footer_html
563
+
564
+ # pylint: disable=too-many-locals
565
+ def _create_ledger_details(
566
+ self,
567
+ journal: QuerySet[CharacterWalletJournalEntry],
568
+ mining: QuerySet[CharacterMiningLedger],
569
+ request_info: OwnerLedgerRequestInfo,
570
+ ) -> LedgerDetailsResponse:
571
+ """
572
+ Generate the detailed ledger data for a character.
573
+ This Helper function generates the detailed ledger data for a character
574
+ based on the provided date query.
575
+
576
+ Args:
577
+ journal (QuerySet): The wallet journal entries.
578
+ mining (QuerySet): The mining ledger entries. Defaults to None.
579
+ request_info (LedgerRequestInfo): The request information containing date and section details.
580
+ Returns:
581
+ LedgerDetailsResponse: The generated ledger details response.
582
+ """
583
+ ref_types = RefTypeManager.get_all_categories()
584
+
585
+ avg = request_info.day if request_info.day else timezone.now().day
586
+ if request_info.section == "summary":
587
+ avg = 365
588
+
589
+ monthly_list = []
590
+ daily_list = []
591
+ hourly_list = []
592
+ summary = 0
593
+ # Income/Cost Ref Types
594
+ for category in RefTypeManager.CategoryChoice:
595
+ category_ref_types = ref_types.get(category.value, [])
596
+ if not category_ref_types:
597
+ continue
598
+ for __, income_flag in (("income", True), ("cost", False)):
599
+ kind_label = _("Income from") if income_flag else _("Cost from")
600
+ name = _("%(kind)s %(category)s") % {
601
+ "category": category.label,
602
+ "kind": kind_label,
603
+ }
604
+ kwargs = {"ref_type": category_ref_types, "income": income_flag}
605
+ amount = journal.aggregate_ref_type(**kwargs)
606
+ if (income_flag and amount > 0) or (not income_flag and amount < 0):
607
+ monthly = CategorySchema(
608
+ name=name,
609
+ amount=amount,
610
+ average=amount / avg / 30,
611
+ average_tick=amount / avg / 30 / 20,
612
+ ref_types=get_ref_type_details_popover_button(
613
+ ref_types=category_ref_types
614
+ ),
615
+ )
616
+
617
+ daily = CategorySchema(
618
+ name=name,
619
+ amount=amount / avg,
620
+ average=amount / avg / 30,
621
+ average_tick=amount / avg / 20,
622
+ ref_types=get_ref_type_details_popover_button(
623
+ ref_types=category_ref_types
624
+ ),
625
+ )
626
+
627
+ hourly = CategorySchema(
628
+ name=name,
629
+ amount=amount / avg / 24,
630
+ average=amount / avg / 24 / 30,
631
+ average_tick=amount / avg / 24 / 20,
632
+ ref_types=get_ref_type_details_popover_button(
633
+ ref_types=category_ref_types
634
+ ),
635
+ )
636
+ # Add Amounts
637
+ summary += amount
638
+ monthly_list.append(monthly)
639
+ daily_list.append(daily)
640
+ hourly_list.append(hourly)
641
+
642
+ # Mining Income from Mining Ledger Journal (Only as Information not counted in Summary)
643
+ mining_income = mining.aggregate_mining()
644
+ if mining_income > 0:
645
+ monthly_mining = CategorySchema(
646
+ name=_("Mining Income"),
647
+ amount=mining_income,
648
+ average=mining_income / avg / 30,
649
+ average_tick=mining_income / avg / 30 / 20,
650
+ ref_types=get_ref_type_details_popover_button(
651
+ ref_types=["mining"],
652
+ ),
653
+ )
654
+
655
+ daily_mining = CategorySchema(
656
+ name=_("Mining Income"),
657
+ amount=mining_income,
658
+ average=mining_income / avg,
659
+ average_tick=mining_income / avg / 20,
660
+ ref_types=get_ref_type_details_popover_button(
661
+ ref_types=["mining"],
662
+ ),
663
+ )
664
+
665
+ hourly_mining = CategorySchema(
666
+ name=_("Mining Income"),
667
+ amount=mining_income,
668
+ average=mining_income / avg / 24,
669
+ average_tick=mining_income / avg / 24 / 20,
670
+ ref_types=get_ref_type_details_popover_button(
671
+ ref_types=["mining"],
672
+ ),
673
+ )
674
+ monthly_list.append(monthly_mining)
675
+ daily_list.append(daily_mining)
676
+ hourly_list.append(hourly_mining)
677
+
678
+ if summary == 0:
679
+ return None
680
+
681
+ return LedgerDetailsResponse(
682
+ summary=monthly_list,
683
+ daily=daily_list,
684
+ hourly=hourly_list,
685
+ total=LedgerDetailsSummary(
686
+ summary=self._create_datatable_footer(summary),
687
+ daily=self._create_datatable_footer(
688
+ summary / avg,
689
+ ),
690
+ hourly=self._create_datatable_footer(
691
+ summary / avg / 24,
692
+ ),
693
+ ),
694
+ )
695
+
696
+ def create_character_details(
697
+ self,
698
+ owner: CharacterOwner,
699
+ request_info: OwnerLedgerRequestInfo,
700
+ ) -> dict:
701
+ """
702
+ Create the character amounts for the Information View.
703
+ """
704
+ # Determine Character IDs based on Section
705
+ char_ids = (
706
+ owner.alt_ids
707
+ if request_info.section == "summary"
708
+ else [owner.eve_character.character_id]
709
+ )
710
+
711
+ wallet_journal = (
712
+ CharacterWalletJournalEntry.objects.filter(
713
+ character__eve_character__character_id__in=char_ids,
714
+ **request_info.to_date_query(),
715
+ )
716
+ # Exclude Zero Amount Entries
717
+ .exclude(amount=Decimal("0.00"))
718
+ # Exclude Internal Donations between Alts
719
+ .exclude(
720
+ Q(ref_type="player_donation")
721
+ & (Q(first_party__in=owner.alt_ids) & Q(second_party__in=owner.alt_ids))
722
+ ).order_by("-date")
723
+ )
724
+
725
+ mining_journal = CharacterMiningLedger.objects.filter(
726
+ character__eve_character__character_id__in=char_ids,
727
+ **request_info.to_date_query(),
728
+ )
729
+
730
+ response_ledger_details: LedgerDetailsResponse = self._create_ledger_details(
731
+ journal=wallet_journal,
732
+ mining=mining_journal,
733
+ request_info=request_info,
734
+ )
735
+ return response_ledger_details
736
+
737
+ # pylint: disable=too-many-positional-arguments
738
+ def _ledger_details_api_response(
739
+ self,
740
+ request: WSGIRequest,
741
+ character_id: int,
742
+ year: int,
743
+ month: int = None,
744
+ day: int = None,
745
+ section: str = "summary",
746
+ ):
747
+ """
748
+ Helper function to generate ledger details response for various date parameters.
749
+
750
+ This function consolidates the common logic for generating the ledger details response
751
+ based on the provided date parameters character_id, (year, month, day) and section.
752
+
753
+ Args:
754
+ request (WSGIRequest): The incoming request object.
755
+ character_id (int): The character ID.
756
+ year (int): The year for the ledger data.
757
+ month (int, optional): The month for the ledger data. Defaults to None.
758
+ day (int, optional): The day for the ledger data. Defaults to None.
759
+ section (str): The section type ('single' or 'summary').
760
+ Returns:
761
+ LedgerDetailsResponse | tuple[int, dict]: The ledger details response or error tuple.
762
+ """
763
+ perms, owner = get_characterowner_or_none(
764
+ request=request, character_id=character_id
765
+ )
766
+
767
+ if owner is None:
768
+ return 404, {"error": _("Character not found in Ledger.")}
769
+
770
+ if perms is False:
771
+ return 403, {
772
+ "error": _("You do not have permission to view this character.")
773
+ }
774
+
775
+ request_info = OwnerLedgerRequestInfo(
776
+ owner_id=owner.eve_character.character_id,
777
+ year=year,
778
+ month=month,
779
+ day=day,
780
+ section=section,
781
+ )
782
+
783
+ return self.create_character_details(
784
+ owner=owner,
785
+ request_info=request_info,
786
+ )