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
ledger/helpers/core.py DELETED
@@ -1,665 +0,0 @@
1
- """
2
- Core View Helper
3
- """
4
-
5
- # Standard Library
6
- from decimal import Decimal
7
- from hashlib import md5
8
- from typing import TYPE_CHECKING, Any
9
-
10
- # Django
11
- from django.core.cache import cache
12
- from django.db.models import Q, QuerySet, Sum
13
- from django.urls import reverse
14
- from django.utils import timezone
15
- from django.utils.safestring import mark_safe
16
- from django.utils.translation import gettext as _
17
-
18
- # Alliance Auth
19
- from allianceauth.authentication.models import CharacterOwnership, UserProfile
20
- from allianceauth.eveonline.models import (
21
- EveAllianceInfo,
22
- EveCharacter,
23
- EveCorporationInfo,
24
- )
25
- from allianceauth.services.hooks import get_extension_logger
26
-
27
- # Alliance Auth (External Libs)
28
- from app_utils.logging import LoggerAddTag
29
-
30
- # AA Ledger
31
- from ledger import __title__
32
- from ledger.app_settings import (
33
- LEDGER_CACHE_ENABLED,
34
- LEDGER_CACHE_KEY,
35
- LEDGER_CACHE_STALE,
36
- )
37
- from ledger.constants import NPC_ENTITIES
38
- from ledger.helpers.ref_type import RefTypeManager
39
- from ledger.models.general import EveEntity
40
-
41
- logger = LoggerAddTag(get_extension_logger(__name__), __title__)
42
-
43
- if TYPE_CHECKING:
44
- # AA Ledger
45
- from ledger.models.characteraudit import (
46
- CharacterMiningLedger,
47
- CharacterWalletJournalEntry,
48
- )
49
-
50
- # pylint: disable=import-outside-toplevel
51
- from ledger.models.corporationaudit import CorporationWalletJournalEntry
52
-
53
-
54
- def add_info_to_context(request, context: dict) -> dict:
55
- """Add additional information to the context for the view."""
56
- # pylint: disable=import-outside-toplevel
57
- # AA Ledger
58
- from ledger.models.characteraudit import CharacterAudit
59
-
60
- total_issues = (
61
- CharacterAudit.objects.annotate_total_update_status_user(user=request.user)
62
- .aggregate(total_failed=Sum("num_sections_failed"))
63
- .get("total_failed", 0)
64
- )
65
-
66
- new_context = {
67
- **{
68
- "issues": total_issues,
69
- },
70
- **context,
71
- }
72
- return new_context
73
-
74
-
75
- class DummyEveEntity:
76
- """Dummy Eve Entity class for fallback when no entity is found."""
77
-
78
- def __init__(self, entity_id, entity_name="Unknown"):
79
- self.entity_id = entity_id
80
- self.entity_name = entity_name
81
- self.type = "character"
82
-
83
-
84
- class LedgerEntity:
85
- """Class to hold character or corporation data for the ledger."""
86
-
87
- # pylint: disable=too-many-positional-arguments
88
- def __init__(
89
- self,
90
- entity_id,
91
- character_obj: EveCharacter = None,
92
- corporation_obj: EveCorporationInfo = None,
93
- alliance_obj: EveAllianceInfo = None,
94
- details_url=None,
95
- ):
96
- self.type = "character"
97
- self.entity = None
98
- self.entity_id = entity_id
99
- self.entity_name = None
100
- self.details_url = details_url
101
- if character_obj and hasattr(character_obj, "character_id"):
102
- self.entity = character_obj
103
- self.entity_id = character_obj.character_id
104
- self.entity_name = character_obj.character_name
105
- elif corporation_obj and hasattr(corporation_obj, "corporation_id"):
106
- self.entity = corporation_obj
107
- self.entity_id = corporation_obj.corporation_id
108
- self.entity_name = corporation_obj.corporation_name
109
- self.type = "corporation"
110
- elif alliance_obj and hasattr(alliance_obj, "alliance_id"):
111
- self.entity = alliance_obj
112
- self.entity_id = alliance_obj.alliance_id
113
- self.entity_name = alliance_obj.alliance_name
114
- self.type = "alliance"
115
- else:
116
- try:
117
- entity_obj = EveEntity.objects.get(eve_id=entity_id)
118
- self.entity = entity_obj
119
- self.entity_id = entity_obj.eve_id
120
- self.entity_name = entity_obj.name
121
- self.type = entity_obj.category
122
- except EveEntity.DoesNotExist:
123
- self.entity = DummyEveEntity(entity_id, "Unknown")
124
- self.entity_id = entity_id
125
- self.entity_name = "Unknown"
126
-
127
- @property
128
- def is_eve_character(self):
129
- """Check if the entity is an Eve Character."""
130
- return isinstance(self.entity, EveCharacter)
131
-
132
- @property
133
- def is_eve_corporation(self):
134
- """Check if the entity is an Eve Corporation."""
135
- return isinstance(self.entity, EveCorporationInfo)
136
-
137
- @property
138
- def is_eve_entity(self):
139
- """Check if the entity is an Eve Entity."""
140
- return isinstance(self.entity, EveEntity)
141
-
142
- @property
143
- def alts(self) -> QuerySet[EveCharacter]:
144
- """Get all alts for this character."""
145
- if not isinstance(self.entity, EveCharacter):
146
- raise ValueError("Entity is not an EveCharacter.")
147
- alts = EveCharacter.objects.filter(
148
- character_ownership__user=self.entity.character_ownership.user
149
- ).select_related(
150
- "character_ownership",
151
- )
152
- return alts
153
-
154
- def portrait_url(self):
155
- """Return the portrait URL for the entity."""
156
- try:
157
- if isinstance(self.entity, EveCorporationInfo):
158
- return self.entity.logo_url_32
159
-
160
- if hasattr(self.entity, "portrait_url"):
161
- return self.entity.portrait_url(size=32)
162
-
163
- if self.entity.category == "faction":
164
- return ""
165
- return self.entity.icon_url(size=32)
166
- except Exception as e: # pylint: disable=broad-except
167
- logger.error(f"Error getting portrait URL for {self.entity_id}: {e}")
168
- return ""
169
-
170
- def add_details_url(self, details_url):
171
- """Set the details URL for the entity."""
172
- self.details_url = details_url
173
-
174
- def get_alts_ids_or_self(self):
175
- """Return the IDs of all alternative characters or the character ID itself."""
176
- try:
177
- character = EveCharacter.objects.get(character_id=self.entity_id)
178
- if hasattr(character, "character_ownership"):
179
- alt_ids = character.character_ownership.user.character_ownerships.all().values_list(
180
- "character__character_id", flat=True
181
- )
182
- return list(alt_ids)
183
- except (
184
- EveCharacter.DoesNotExist,
185
- AttributeError,
186
- CharacterOwnership.DoesNotExist,
187
- ):
188
- pass
189
- return [self.entity_id]
190
-
191
- @property
192
- def create_button(self):
193
- """Generate the URL for character details."""
194
- title = _("View Details")
195
- button_html = f"<button class='btn btn-primary btn-sm btn-square' data-bs-toggle='modal' data-bs-target='#modalViewCharacterContainer' data-ajax_url='{self.details_url}' title='{title}' data-tooltip-toggle='ledger-tooltip'><span class='fas fa-info'></span></button>"
196
- return mark_safe(button_html)
197
-
198
-
199
- class LedgerCore:
200
- """Core View Helper for Ledger."""
201
-
202
- def __init__(self, year=None, month=None, day=None):
203
- self.ledger_type: str = "ledger"
204
- self.queryset: QuerySet = None
205
- self.entity_id: int = None
206
- self.section: str = "single"
207
- self.mining: QuerySet = None
208
- self.auth_char_ids: set = set()
209
- self.date_info: dict = {"year": year, "month": month, "day": day}
210
-
211
- @property
212
- def year(self):
213
- return self.date_info["year"]
214
-
215
- @property
216
- def month(self):
217
- return self.date_info["month"]
218
-
219
- @property
220
- def day(self):
221
- return self.date_info["day"]
222
-
223
- @property
224
- def filter_date(self):
225
- """
226
- Generate a date filter for the ledger based on year, month, and day.
227
- Returns:
228
- Q: A Django Q object representing the date filter.
229
- """
230
- now = timezone.now()
231
- # If all are None, use current year and month
232
- if self.year is None and self.month is None and self.day is None:
233
- filter_date = Q(date__year=now.year) & Q(date__month=now.month)
234
- else:
235
- filter_date = (
236
- Q(date__year=self.year) if self.year else Q(date__year=now.year)
237
- )
238
- if self.month:
239
- filter_date &= Q(date__month=self.month)
240
- if self.day:
241
- filter_date &= Q(date__day=self.day)
242
- return filter_date
243
-
244
- @property
245
- def get_details_title(self):
246
- """
247
- Generate a title for the details view based on the date information.
248
-
249
- Returns:
250
- str: A formatted string representing the date or a default title.
251
- """
252
- if self.year and self.month and self.day:
253
- return f"{self.year:04d}-{self.month:02d}-{self.day:02d}"
254
- if self.year and self.month:
255
- return f"{self.year:04d}-{self.month:02d}"
256
- if self.year:
257
- return f"{self.year:04d}"
258
- return "Ledger Details"
259
-
260
- @property
261
- def auth_accounts(self):
262
- """Get all user accounts with a main character."""
263
- return (
264
- UserProfile.objects.filter(
265
- main_character__isnull=False,
266
- )
267
- .prefetch_related(
268
- "user__profile__main_character",
269
- )
270
- .order_by(
271
- "user__profile__main_character__character_name",
272
- )
273
- )
274
-
275
- @property
276
- def auth_character_ids(self) -> set:
277
- """Get all account Character IDs from Alliance Auth."""
278
- account_character_ids = set()
279
- for account in self.auth_accounts:
280
- alts = account.user.character_ownerships.all()
281
- account_character_ids.update(
282
- alts.values_list("character__character_id", flat=True)
283
- )
284
- return account_character_ids
285
-
286
- def filter_entity_journal(self, entity: LedgerEntity = None):
287
- """Apply additional filters to the journal based on the entity."""
288
- if self.section == "summary":
289
- return self.queryset
290
-
291
- # Get all character IDs associated with the entity (including alts)
292
- character_ids = entity.get_alts_ids_or_self()
293
-
294
- # Filter journal to include only entries where the entity is a first or second party
295
- # Exclude entries where both parties are the corporation itself
296
- journal = self.queryset.filter(
297
- Q(first_party_id__in=character_ids) | Q(second_party_id__in=character_ids)
298
- )
299
-
300
- # If the entity is the corporation itself, include NPC transactions too
301
- if entity.entity_id == self.entity_id:
302
- journal = journal.filter(
303
- Q(first_party_id__in=NPC_ENTITIES) | Q(second_party_id__in=NPC_ENTITIES)
304
- )
305
-
306
- # If entity represents a corporation or alliance, exclude auth account character IDs
307
- # that are not part of the current entity to avoid double counting
308
- if entity.type in ["alliance", "corporation"]:
309
- exclude_ids = self.auth_char_ids - set(character_ids)
310
- journal = journal.exclude(
311
- Q(first_party_id__in=exclude_ids) | Q(second_party_id__in=exclude_ids)
312
- )
313
- return journal
314
-
315
- def get_view_mode(self) -> str:
316
- """Determine the current view mode based on year, month, and day."""
317
- if self.day:
318
- return "day"
319
- if self.month:
320
- return "month"
321
- if self.year:
322
- return "year"
323
- return "month"
324
-
325
- def get_ledger_journal_hash(self, journal: list[str]) -> str:
326
- """Generate a hash for the ledger journal."""
327
- return md5(",".join(str(x) for x in sorted(journal)).encode()).hexdigest()
328
-
329
- def get_ledger_hash(self, header_key: str) -> str:
330
- """Generate a hash for the ledger journal."""
331
- return md5(header_key.encode()).hexdigest()
332
-
333
- def get_ledger_header(
334
- self, ledger_args: str, year: int, month: int, day: int
335
- ) -> str:
336
- """Generate a header string for the ledger."""
337
- return f"{ledger_args}_{year}_{month}_{day}"
338
-
339
- def build_ledger_cache_key(self, header_key: str) -> str:
340
- """Build a cache key for the ledger."""
341
- return f"{LEDGER_CACHE_KEY}-{self.get_ledger_hash(header_key)}"
342
-
343
- def get_cache_ledger(
344
- self, ledger_hash: str, cache_key: str
345
- ) -> tuple[Any, Any] | tuple[False, False]:
346
- """Get the ledger cache.
347
-
348
- Args:
349
- ledger_hash (str): The hash of the current ledger journal.
350
- cache_key (str): The base cache key for the ledger.
351
- Returns:
352
- tuple: A tuple containing the cached ledger and finished entities, or (False, False) if not found or outdated.
353
- """
354
- # Get the journal hash and cache header
355
- ledger_header = self.get_ledger_header(
356
- ledger_args=cache_key,
357
- year=self.year,
358
- month=self.month,
359
- day=self.day,
360
- )
361
- cache_header = cache.get(
362
- ledger_header,
363
- False,
364
- )
365
- logger.debug(
366
- f"Ledger Header: {ledger_header}, Cache Header: {cache_header}, Journal Hash: {ledger_hash}"
367
- )
368
-
369
- # Check if the journal is up to date
370
- journal_up_to_date = cache_header == ledger_hash
371
- ledger_key = self.build_ledger_cache_key(ledger_header)
372
-
373
- # Check if we have newest cached version of the ledger
374
- if journal_up_to_date and LEDGER_CACHE_ENABLED:
375
- ledger = cache.get(f"{ledger_key}-data", False)
376
- finished_entities = cache.get(f"{ledger_key}-finished_entities", False)
377
- return ledger, finished_entities
378
- return False, False
379
-
380
- def set_cache_ledger(
381
- self, ledger_hash: str, cache_key: str, ledger: list, finished_entities: set
382
- ):
383
- """Set the ledger cache."""
384
- ledger_header = self.get_ledger_header(
385
- ledger_args=cache_key,
386
- year=self.year,
387
- month=self.month,
388
- day=self.day,
389
- )
390
- ledger_key = self.build_ledger_cache_key(ledger_header)
391
-
392
- cache.set(key=f"{ledger_key}-data", value=ledger, timeout=LEDGER_CACHE_STALE)
393
- cache.set(
394
- key=f"{ledger_key}-finished_entities",
395
- value=finished_entities,
396
- timeout=LEDGER_CACHE_STALE,
397
- )
398
- cache.set(
399
- key=self.get_ledger_header(
400
- ledger_args=cache_key,
401
- year=self.year,
402
- month=self.month,
403
- day=self.day,
404
- ),
405
- value=ledger_hash,
406
- timeout=None, # Cache forever until the journal changes
407
- )
408
-
409
- def calculate_totals(self, ledger) -> dict:
410
- """
411
- Calculate the total amounts for each category in the ledger.
412
-
413
- Args:
414
- ledger (list or dict): The ledger data to calculate totals from.
415
-
416
- Returns:
417
- dict: A dictionary containing the totals for each category.
418
- """
419
- totals = {
420
- "bounty": Decimal(0),
421
- "ess": Decimal(0),
422
- "costs": Decimal(0),
423
- "mining": Decimal(0),
424
- "miscellaneous": Decimal(0),
425
- "total": Decimal(0),
426
- }
427
-
428
- if not ledger:
429
- return totals
430
-
431
- if isinstance(ledger, dict):
432
- ledger = [ledger]
433
-
434
- for total in ledger:
435
-
436
- if total is None:
437
- continue
438
-
439
- totals["bounty"] += total["ledger"].get("bounty", 0)
440
- totals["ess"] += total["ledger"].get("ess", 0)
441
- totals["costs"] += total["ledger"].get("costs", 0)
442
- totals["mining"] += total["ledger"].get("mining", 0)
443
- totals["miscellaneous"] += total["ledger"].get("miscellaneous", 0)
444
- totals["total"] += total["ledger"].get("total", 0)
445
- return totals
446
-
447
- def create_url(self, viewname: str, **kwargs):
448
- """
449
- Create a URL for the given view and entity using kwargs.
450
- Args:
451
- viewname: The name of the view to create the URL for.
452
- kwargs: All needed parameters for the URL (e.g. character_id, corporation_id, etc.)
453
- Returns:
454
- A URL string for the specified view.
455
- """
456
-
457
- # Remove division_id if None to avoid issues with URL reversing
458
- # pylint: disable=no-member
459
- if hasattr(self, "division_id") and self.division_id is not None:
460
- kwargs["division_id"] = self.division_id
461
-
462
- if self.year is not None:
463
- kwargs["year"] = self.year
464
- if self.month is not None:
465
- kwargs["month"] = self.month
466
- if self.day is not None:
467
- kwargs["day"] = self.day
468
-
469
- return reverse(
470
- f"ledger:{viewname}",
471
- kwargs={**kwargs},
472
- )
473
-
474
- def create_view_data(self, viewname: str, **kwargs) -> dict:
475
- """
476
- Create view data for the ledger using kwargs.
477
- Args:
478
- viewname (str): The name of the view to create the URL for.
479
- kwargs: All needed parameters for the URL (e.g. character_id, corporation_id, etc.)
480
- Returns:
481
- dict: A dictionary containing the type, date, and details URL.
482
- """
483
- if kwargs.get("division_id") is None:
484
- kwargs.pop("division_id", None)
485
-
486
- view_dict = {
487
- "type": self.ledger_type,
488
- "date": {
489
- "current": {
490
- "year": timezone.now().year,
491
- "month": timezone.now().month,
492
- "day": timezone.now().day,
493
- },
494
- "year": self.year,
495
- "month": self.month,
496
- "day": self.day,
497
- },
498
- "details_url": self.create_url(
499
- viewname=viewname,
500
- **kwargs,
501
- ),
502
- }
503
-
504
- return view_dict
505
-
506
- # pylint: disable=too-many-locals, too-many-positional-arguments
507
- def _generate_amounts(
508
- self,
509
- journal: QuerySet,
510
- income_types: list,
511
- entity: LedgerEntity,
512
- mining: QuerySet = None,
513
- is_old_ess: bool = False,
514
- char_ids: list = None,
515
- ) -> dict:
516
- """Generate amounts for the entity based on income types and reference types."""
517
- amounts = {}
518
-
519
- ref_types = RefTypeManager.get_all_categories()
520
-
521
- # Bounty Income
522
- if not entity.entity_id == 1000125: # Remove Concord Bountys
523
- bounty_income = journal.aggregate_bounty()
524
- if bounty_income > 0:
525
- amounts["bounty_income"] = {
526
- "total_amount": bounty_income,
527
- "ref_types": ["bounty_prizes"],
528
- }
529
-
530
- if isinstance(entity.entity, EveCharacter):
531
- # Mining Income
532
- mining_income = mining.aggregate_mining()
533
- if mining_income > 0:
534
- amounts["mining_income"] = {
535
- "total_amount": mining_income,
536
- "ref_types": ["mining"],
537
- }
538
-
539
- # ESS Income (nur wenn bounty_income existiert)
540
- ess_income = (
541
- bounty_income * Decimal(0.667)
542
- if is_old_ess and bounty_income
543
- else journal.aggregate_ess()
544
- )
545
- if ess_income > 0:
546
- amounts["ess_income"] = {
547
- "total_amount": ess_income,
548
- "ref_types": ["ess_escrow_transfer"],
549
- }
550
-
551
- # Income/Cost Ref Types (DRY)
552
- for ref_type, value in ref_types.items():
553
- ref_type_name = ref_type.lower()
554
- for kind, income_flag in (("income", True), ("cost", False)):
555
- kwargs = {"ref_type": value, "income": income_flag}
556
- kwargs = RefTypeManager.special_cases_details(
557
- value, entity, kwargs, journal_type=entity.type, char_ids=char_ids
558
- )
559
- agg = journal.aggregate_ref_type(**kwargs)
560
- if (income_flag and agg > 0) or (not income_flag and agg < 0):
561
- amounts[f"{ref_type_name}_{kind}"] = {
562
- "total_amount": agg,
563
- "ref_types": value,
564
- }
565
-
566
- # Summary (exclude mining_income)
567
- summary = sum(
568
- amount["total_amount"]
569
- for key, amount in amounts.items()
570
- if key != "mining_income"
571
- and isinstance(amount, dict)
572
- and "total_amount" in amount
573
- )
574
-
575
- if summary == 0:
576
- return None
577
-
578
- amounts["summary"] = {
579
- "total_amount": summary,
580
- }
581
-
582
- # Dynamische Income/Cost-Typen für das Template
583
- income_types += [
584
- (f"{ref_type.lower()}_income", _(ref_type.replace("_", " ").title()))
585
- for ref_type in ref_types
586
- ]
587
- cost_types = [
588
- (f"{ref_type.lower()}_cost", _(ref_type.replace("_", " ").title()))
589
- for ref_type in ref_types
590
- ]
591
- amounts["income_types"] = income_types
592
- amounts["cost_types"] = cost_types
593
- return amounts
594
-
595
- def _create_corporation_details(
596
- self, journal: QuerySet["CorporationWalletJournalEntry"], entity: LedgerEntity
597
- ) -> dict:
598
- """Create the corporation amounts for the Information View."""
599
- income_types = [
600
- ("bounty_income", _("Bounty")),
601
- ("ess_income", _("Encounter Surveillance System")),
602
- ]
603
- amounts = self._generate_amounts(
604
- journal=journal, income_types=income_types, entity=entity
605
- )
606
- return amounts
607
-
608
- # pylint: disable=no-member
609
- def _create_character_details(
610
- self,
611
- journal: QuerySet["CharacterWalletJournalEntry"],
612
- mining: QuerySet["CharacterMiningLedger"],
613
- ) -> dict:
614
- """
615
- Create the character amounts for the Information View.
616
- Only work with CharacterData Class
617
- """
618
- if not self.character:
619
- raise ValueError("No Character Data found.")
620
-
621
- entity = LedgerEntity(
622
- entity_id=self.character.eve_character.character_id,
623
- character_obj=self.character.eve_character,
624
- )
625
-
626
- income_types = [
627
- ("bounty_income", _("Bounty")),
628
- ("ess_income", _("Encounter Surveillance System")),
629
- ("mining_income", _("Mining")),
630
- ]
631
- amounts = self._generate_amounts(
632
- journal=journal,
633
- income_types=income_types,
634
- entity=entity,
635
- mining=mining,
636
- is_old_ess=self.is_old_ess,
637
- char_ids=self.alts_ids,
638
- )
639
- return amounts
640
-
641
- def _add_average_details(self, request, amounts, day: int = None):
642
- """Add average details to the amounts dictionary, skipping if no data or total is 0."""
643
- if amounts is None:
644
- return None
645
-
646
- avg = day if day else timezone.now().day
647
- if request.GET.get("all", False):
648
- avg = 365
649
-
650
- for key in amounts:
651
- if (
652
- isinstance(amounts[key], dict)
653
- and "total_amount" in amounts[key]
654
- and amounts[key]["total_amount"] not in (None, 0, 0.0, Decimal(0))
655
- ):
656
- total = amounts[key]["total_amount"]
657
- amounts[key]["average_day"] = total / avg
658
- amounts[key]["average_hour"] = total / avg / 24
659
- amounts[key]["average_tick"] = total / 20
660
- amounts[key]["current_day_tick"] = (
661
- amounts[key].get("total_amount_day", 0) / 20
662
- )
663
- amounts[key]["average_day_tick"] = total / avg / 20
664
- amounts[key]["average_hour_tick"] = total / avg / 24 / 20
665
- return amounts