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
@@ -4,22 +4,22 @@ from typing import TYPE_CHECKING
4
4
  # Django
5
5
  from django.db import models, transaction
6
6
  from django.utils import timezone
7
+ from django.utils.dateparse import parse_datetime
7
8
 
8
9
  # Alliance Auth
9
10
  from allianceauth.services.hooks import get_extension_logger
10
11
  from esi.exceptions import HTTPNotModified
11
12
 
12
13
  # Alliance Auth (External Libs)
13
- from app_utils.logging import LoggerAddTag
14
14
  from eveuniverse.models import EvePlanet, EveType
15
15
 
16
16
  # AA Ledger
17
17
  from ledger import __title__
18
18
  from ledger.app_settings import LEDGER_BULK_BATCH_SIZE
19
- from ledger.constants import COMMAND_CENTER, EXTRACTOR_CONTROL_UNIT, SPACEPORTS
20
19
  from ledger.decorators import log_timing
21
- from ledger.models.characteraudit import CharacterAudit
22
- from ledger.providers import esi
20
+ from ledger.models.characteraudit import CharacterOwner
21
+ from ledger.models.helpers.update_manager import CharacterUpdateSection
22
+ from ledger.providers import AppLogger, esi
23
23
 
24
24
  if TYPE_CHECKING: # pragma: no cover
25
25
  # Alliance Auth
@@ -28,9 +28,10 @@ if TYPE_CHECKING: # pragma: no cover
28
28
 
29
29
  # AA Ledger
30
30
  from ledger.models.general import UpdateSectionResult
31
- from ledger.models.planetary import CharacterPlanet, CharacterPlanetDetails
31
+ from ledger.models.planetary import CharacterPlanet as PlanetContext
32
+ from ledger.models.planetary import CharacterPlanetDetails as PlanetDetailsContext
32
33
 
33
- logger = LoggerAddTag(get_extension_logger(__name__), __title__)
34
+ logger = AppLogger(get_extension_logger(__name__), __title__)
34
35
 
35
36
 
36
37
  def to_json_serializable(data):
@@ -45,50 +46,46 @@ def to_json_serializable(data):
45
46
  return data
46
47
 
47
48
 
48
- class PlanetaryQuerySet(models.QuerySet):
49
- pass
50
-
51
-
52
- class PlanetaryManagerBase(models.Manager):
49
+ class CharacterPlanetManager(models.Manager["PlanetContext"]):
53
50
  @log_timing(logger)
54
51
  def update_or_create_esi(
55
- self, character: "CharacterAudit", force_refresh: bool = False
52
+ self, owner: CharacterOwner, force_refresh: bool = False
56
53
  ) -> "UpdateSectionResult":
57
54
  """Update or Create a planets entry from ESI data."""
58
- return character.update_section_if_changed(
59
- section=character.UpdateSection.PLANETS,
55
+ return owner.update_manager.update_section_if_changed(
56
+ section=CharacterUpdateSection.PLANETS,
60
57
  fetch_func=self._fetch_esi_data,
61
58
  force_refresh=force_refresh,
62
59
  )
63
60
 
64
61
  def _fetch_esi_data(
65
- self, audit: "CharacterAudit", force_refresh: bool = False
62
+ self, owner: CharacterOwner, force_refresh: bool = False
66
63
  ) -> None:
67
64
  """Fetch planetary entries from ESI data."""
68
65
  req_scopes = ["esi-planets.manage_planets.v1"]
69
- token = audit.get_token(scopes=req_scopes)
66
+ token = owner.get_token(scopes=req_scopes)
70
67
 
71
68
  # Make the ESI request
72
69
  operation = esi.client.Planetary_Interaction.GetCharactersCharacterIdPlanets(
73
- character_id=audit.eve_character.character_id,
70
+ character_id=owner.eve_character.character_id,
74
71
  token=token,
75
72
  )
76
73
 
77
74
  planets_items = operation.results(force_refresh=force_refresh)
78
75
 
79
- self._update_or_create_objs(character=audit, objs=planets_items)
76
+ self._update_or_create_objs(owner=owner, objs=planets_items)
80
77
 
81
78
  @transaction.atomic()
82
79
  def _update_or_create_objs(
83
- self, character: "CharacterAudit", objs: list["PlanetGetItem"]
80
+ self, owner: CharacterOwner, objs: list["PlanetGetItem"]
84
81
  ) -> None:
85
82
  """Update or Create planets entries from objs data."""
86
83
  # pylint: disable=import-outside-toplevel
87
84
  # AA Ledger
88
85
  from ledger.models.planetary import CharacterPlanetDetails
89
86
 
90
- _current_planets = self.filter(character=character).values_list(
91
- "planet_id", flat=True
87
+ _current_planets = self.filter(character=owner).values_list(
88
+ "eve_planet_id", flat=True
92
89
  )
93
90
 
94
91
  _planets_ids = []
@@ -100,16 +97,16 @@ class PlanetaryManagerBase(models.Manager):
100
97
  _planets_ids.append(eve_planet.id)
101
98
 
102
99
  try:
103
- e_planet = self.get(character=character, planet=eve_planet)
100
+ e_planet = self.get(character=owner, eve_planet=eve_planet)
104
101
  prim_key = e_planet.id
105
102
  except self.model.DoesNotExist:
106
103
  prim_key = None
107
104
 
108
105
  planet = self.model(
109
106
  id=prim_key,
110
- character=character,
111
- planet=eve_planet,
112
- planet_name=eve_planet.name,
107
+ name=eve_planet.name,
108
+ character=owner,
109
+ eve_planet=eve_planet,
113
110
  upgrade_level=planet.upgrade_level,
114
111
  num_pins=planet.num_pins,
115
112
  )
@@ -130,39 +127,22 @@ class PlanetaryManagerBase(models.Manager):
130
127
 
131
128
  # Delete Planets that are no longer in the list
132
129
  obsolete_planets = set(_current_planets) - set(_planets_ids)
133
- self.filter(character=character, planet_id__in=obsolete_planets).delete()
130
+ self.filter(character=owner, eve_planet_id__in=obsolete_planets).delete()
134
131
  # Delete Planet Details that are no longer in the list
135
132
  CharacterPlanetDetails.objects.filter(
136
- planet__character=character, planet__planet_id__in=obsolete_planets
133
+ planet__character=owner, planet__eve_planet_id__in=obsolete_planets
137
134
  ).delete()
138
135
 
139
136
 
140
- PlanetaryManager = PlanetaryManagerBase.from_queryset(PlanetaryQuerySet)
141
-
142
-
143
- class PlanetaryDetailsQuerySet(models.QuerySet):
144
- def get_or_create_facilitys(self, planet: "CharacterPlanet"):
145
- """Get or Create Facilitys for a given Planet"""
146
- return self._get_or_create_facilitys(planet=planet)
147
-
148
- def _get_or_create_facilitys(self, planet: "CharacterPlanet"):
149
- try:
150
- facilitys = self.get(planet=planet)
151
- facility = facilitys.facilitys
152
- created = False
153
- return facility, created
154
- except self.model.DoesNotExist:
155
- facility, created = self.update_or_create_facilitys(planet=planet)
156
- return facility, created
157
-
137
+ class PlanetDetailsQuerySet(models.QuerySet):
158
138
  def update_or_create_layout(
159
139
  self,
160
- character: CharacterAudit,
161
- planet: "CharacterPlanetDetails",
140
+ owner: CharacterOwner,
141
+ planet: "PlanetDetailsContext",
162
142
  objs: list["PlanetDetailsItem"],
163
143
  ):
164
144
  """Update or Create Layout for a given Planet"""
165
- return self._update_or_create(character=character, planet=planet, objs=objs)
145
+ return self._update_or_create(owner=owner, planet=planet, objs=objs)
166
146
 
167
147
  def _convert_to_dict(
168
148
  self,
@@ -176,13 +156,14 @@ class PlanetaryDetailsQuerySet(models.QuerySet):
176
156
 
177
157
  def _update_or_create(
178
158
  self,
179
- character: "CharacterAudit",
180
- planet: "CharacterPlanetDetails",
159
+ owner: CharacterOwner,
160
+ planet: "PlanetDetailsContext",
181
161
  objs: list["PlanetDetailsItem"],
182
- ):
162
+ ) -> tuple["PlanetDetailsContext", bool]:
183
163
  """Update or Create Layout for a given Planet"""
184
164
  if not isinstance(objs, list):
185
165
  objs = [objs]
166
+
186
167
  for result in objs:
187
168
  links = self._convert_to_dict(result.links)
188
169
  pins = self._convert_to_dict(result.pins)
@@ -190,66 +171,147 @@ class PlanetaryDetailsQuerySet(models.QuerySet):
190
171
 
191
172
  planetdetails, created = self.update_or_create(
192
173
  planet=planet,
193
- character=character,
174
+ character=owner,
194
175
  defaults={
195
176
  "links": links,
196
177
  "pins": pins,
197
178
  "routes": routes,
198
- "facilitys": None,
179
+ "factories": None,
199
180
  },
200
181
  )
201
182
 
202
- self._update_facility(planetdetails)
183
+ self._update_factory(planetdetails)
203
184
 
204
- logger.debug("Planet %s Facilitys Updated", planetdetails)
185
+ logger.debug("Planet %s Factories Updated", planetdetails)
205
186
 
206
187
  return planetdetails, created
207
188
 
208
- def _update_facility(self, planet: "CharacterPlanetDetails"):
209
- facility_info = self.get_facility_info(planet)
210
- planet.facilitys = facility_info
211
- planet.save()
212
- return planet
189
+ def _update_factory(self, planet: "PlanetDetailsContext"):
213
190
 
214
- # TODO make code easier or split it to peaces for better readable
215
- def get_facility_info(self, planet: "CharacterPlanetDetails"):
216
- facility_info = {}
191
+ factory_dict = {}
217
192
 
218
193
  # Process pins
219
194
  for pin in planet.pins:
220
195
  pin_id = pin["pin_id"]
221
196
  item_type, _ = EveType.objects.get_or_create_esi(id=pin["type_id"])
222
- if (
223
- pin["type_id"] in SPACEPORTS
224
- or pin["type_id"] in EXTRACTOR_CONTROL_UNIT
225
- or pin["type_id"] in COMMAND_CENTER
197
+
198
+ # Skip Command Center
199
+ if pin["type_id"] in EveType.objects.filter(eve_group_id=1027).values_list(
200
+ "id", flat=True
226
201
  ):
227
202
  continue
228
- facility_info[pin_id] = {
203
+
204
+ # Create Facility Pin Entry
205
+ factory_dict[pin_id] = {
229
206
  "facility_id": pin["type_id"],
230
207
  "facility_name": item_type.name,
231
- "resources": [],
232
- "storage": {
233
- content["type_id"]: content["amount"]
234
- for content in pin.get("contents", [])
235
- },
208
+ "facility_type": (
209
+ item_type.eve_group.name if item_type.eve_group else "N/A"
210
+ ),
211
+ "ressources": [],
236
212
  }
237
213
 
238
- self._facility_production_chain(planet, facility_info)
214
+ # Spaceport and Storage Facility
215
+ if pin["type_id"] in EveType.objects.filter(
216
+ eve_group_id__in=[1029, 1030]
217
+ ).values_list("id", flat=True):
218
+ factory_dict[pin_id]["storage"] = {}
219
+ self._storage_info(pin, factory_dict[pin_id])
239
220
 
240
- self._facility_produce_depend(planet, facility_info)
221
+ # Extractor
222
+ if pin["type_id"] in EveType.objects.filter(eve_group_id=1063).values_list(
223
+ "id", flat=True
224
+ ):
225
+ factory_dict[pin_id]["extractor"] = {}
226
+ self._extractor_info(pin, factory_dict[pin_id])
241
227
 
242
- return facility_info
228
+ self._factory_production_chain(planet, factory_dict)
243
229
 
244
- def _facility_production_chain(
245
- self, planet: "CharacterPlanetDetails", facility_info: dict
230
+ planet.factories = factory_dict
231
+ planet.save()
232
+ return planet
233
+
234
+ def _storage_info(self, pin: dict, facility_dict: dict):
235
+ """Update per-facility dict and add all Storage Information."""
236
+ for content in pin.get("contents", []):
237
+ item_type, _ = EveType.objects.get_or_create_esi(id=content["type_id"])
238
+
239
+ item_type_id = content["type_id"]
240
+ item_amount = content["amount"]
241
+
242
+ if item_type_id in facility_dict["storage"]:
243
+ facility_dict["storage"][item_type_id]["amount"] += item_amount
244
+ else:
245
+ facility_dict["storage"][item_type_id] = {
246
+ "item_id": item_type_id,
247
+ "item_name": item_type.name,
248
+ "amount": item_amount,
249
+ }
250
+ return facility_dict
251
+
252
+ def _extractor_info(self, pin: dict, factory_dict: dict):
253
+ """Update dict and add all Extractor Information to the given dict"""
254
+ # Update Extractor Information (ensure None is treated as empty dict)
255
+ extractor_details = pin.get("extractor_details") or {}
256
+ product_type_id = extractor_details.get("product_type_id")
257
+ product_type_name = "N/A"
258
+
259
+ # Get Product Eve Type
260
+ if product_type_id:
261
+ item_type, _ = EveType.objects.get_or_create_esi(id=product_type_id)
262
+ product_type_name = item_type.name
263
+
264
+ # Use timezone-aware datetimes and compute elapsed/total seconds
265
+ current_time = timezone.now()
266
+
267
+ install_time = None
268
+ if pin.get("install_time") is not None:
269
+ install_time = parse_datetime(pin.get("install_time"))
270
+ expiry_time = None
271
+ if pin.get("expiry_time") is not None:
272
+ expiry_time = parse_datetime(pin.get("expiry_time"))
273
+
274
+ # Create Extractor Info Entry on the per-facility dict
275
+ factory_dict["extractor"] = {
276
+ "head_count": extractor_details.get("head_count"),
277
+ "product_type_id": product_type_id,
278
+ "product_type_name": product_type_name,
279
+ "install_time": str(install_time),
280
+ "expiry_time": str(expiry_time),
281
+ "cycle_time": extractor_details.get("cycle_time"),
282
+ "progress_percentage": None,
283
+ }
284
+
285
+ is_running = False
286
+ # Calculate progress as percentage (0-100) based on elapsed time
287
+ if install_time and expiry_time:
288
+ total_seconds = (expiry_time - install_time).total_seconds()
289
+ if total_seconds > 0:
290
+ elapsed_seconds = (current_time - install_time).total_seconds()
291
+ progress = (elapsed_seconds / total_seconds) * 100.0
292
+ progress = max(0.0, min(progress, 100.0))
293
+ factory_dict["extractor"]["progress_percentage"] = round(progress, 2)
294
+
295
+ # Extractor is running
296
+ if progress < 100.0:
297
+ is_running = True
298
+
299
+ # Store is_running status
300
+ factory_dict["extractor"]["is_running"] = is_running
301
+
302
+ # pylint: disable=too-many-locals
303
+ def _factory_production_chain(
304
+ self, planet: "PlanetDetailsContext", factory_dict: dict
246
305
  ):
247
306
  """Update dict and add all Production Information to the given dict"""
307
+ item_ids = set()
308
+ for facility in factory_dict.values():
309
+ for storage_item in facility.get("storage", {}).values():
310
+ item_ids.add(storage_item["item_id"])
248
311
 
249
- extractors = planet.get_extractors_info()
250
- extractors_item_ids = [
251
- extractor["item_id"] for extractor in extractors.values()
252
- ]
312
+ extractor_product = facility.get("extractor", {}).get("product_type_id")
313
+ if extractor_product:
314
+ item_ids.add(extractor_product)
253
315
 
254
316
  for route in planet.routes:
255
317
  destination_pin_id = route["destination_pin_id"]
@@ -258,69 +320,54 @@ class PlanetaryDetailsQuerySet(models.QuerySet):
258
320
  id=route["content_type_id"]
259
321
  )
260
322
 
261
- if destination_pin_id in facility_info:
323
+ if destination_pin_id in factory_dict:
262
324
  req_quantity = route["quantity"]
263
- current_quantity = facility_info[destination_pin_id]["storage"].get(
264
- content_type.id, 0
265
- )
266
- missing_quantity = req_quantity - current_quantity
325
+ storage = factory_dict[destination_pin_id].get("storage", {})
326
+ current_quantity = storage.get(content_type.id, {}).get("amount", 0)
327
+ missing_quantity = max((req_quantity - current_quantity), 0)
328
+
267
329
  still_producing = (
268
- content_type.id in extractors_item_ids
269
- if not planet.is_expired
270
- else False
330
+ content_type.id in item_ids if not planet.is_expired else False
271
331
  )
272
332
 
333
+ is_active = still_producing and missing_quantity > 0
334
+
273
335
  resource = {
274
336
  "item_id": content_type.id,
275
337
  "item_name": content_type.name,
276
338
  "req_quantity": req_quantity,
277
339
  "current_quantity": current_quantity,
278
- "missing_quantity": max(missing_quantity, 0),
279
- "still_producing": still_producing,
340
+ "missing_quantity": missing_quantity,
341
+ "is_active": is_active,
280
342
  }
281
- facility_info[destination_pin_id]["resources"].append(resource)
343
+ factory_dict[destination_pin_id]["ressources"].append(resource)
282
344
 
283
- if source_pin_id in facility_info:
284
- facility_info[source_pin_id]["output_product"] = {
345
+ if source_pin_id in factory_dict:
346
+ factory_dict[source_pin_id]["output_product"] = {
285
347
  "item_id": content_type.id,
286
348
  "item_name": content_type.name,
287
349
  "output_quantity": route["quantity"],
288
350
  }
289
- return facility_info
290
-
291
- def _facility_produce_depend(self, planet, facility_info):
292
- """Check if Facility is Producing"""
293
- for facility in facility_info.values():
294
- for resource in facility["resources"]:
295
- self._facility_still_producing(planet, resource, facility_info)
296
- return facility_info
297
-
298
- def _facility_still_producing(self, planet, resource, facility_info) -> bool:
299
- """Check if ressource exist in Production Chain and change State"""
300
- for other_facility in facility_info.values():
301
- if (
302
- "output_product" in other_facility
303
- and other_facility["output_product"]["item_id"] == resource["item_id"]
304
- and not planet.is_expired
305
- ):
306
- if other_facility["output_product"]["output_quantity"] > 0:
307
- resource["still_producing"] = True
351
+ return factory_dict
308
352
 
309
353
 
310
- class PlanetaryDetailsManagerBase(models.Manager):
354
+ class PlanetDetailsManager(models.Manager["PlanetDetailsContext"]):
355
+ def get_queryset(self):
356
+ return PlanetDetailsQuerySet(self.model, using=self._db)
357
+
311
358
  @log_timing(logger)
312
359
  def update_or_create_esi(
313
- self, character: "CharacterAudit", force_refresh: bool = False
360
+ self, owner: CharacterOwner, force_refresh: bool = False
314
361
  ) -> "UpdateSectionResult":
315
362
  """Update or Create a planets details entry from ESI data."""
316
- return character.update_section_if_changed(
317
- section=character.UpdateSection.PLANETS_DETAILS,
363
+ return owner.update_manager.update_section_if_changed(
364
+ section=CharacterUpdateSection.PLANETS_DETAILS,
318
365
  fetch_func=self._fetch_esi_data,
319
366
  force_refresh=force_refresh,
320
367
  )
321
368
 
322
369
  def _fetch_esi_data(
323
- self, audit: "CharacterAudit", force_refresh: bool = False
370
+ self, owner: CharacterOwner, force_refresh: bool = False
324
371
  ) -> None:
325
372
  """Fetch planets details entries from ESI data."""
326
373
  # pylint: disable=import-outside-toplevel
@@ -329,17 +376,17 @@ class PlanetaryDetailsManagerBase(models.Manager):
329
376
 
330
377
  req_scopes = ["esi-planets.manage_planets.v1"]
331
378
 
332
- token = audit.get_token(scopes=req_scopes)
379
+ token = owner.get_token(scopes=req_scopes)
333
380
 
334
- planets_ids = CharacterPlanet.objects.filter(character=audit).values_list(
335
- "planet_id", flat=True
381
+ planets_ids = CharacterPlanet.objects.filter(character=owner).values_list(
382
+ "eve_planet_id", flat=True
336
383
  )
337
384
  is_updated = False
338
385
 
339
386
  for planet_id in planets_ids:
340
387
  # Make the ESI request
341
388
  operation = esi.client.Planetary_Interaction.GetCharactersCharacterIdPlanetsPlanetId(
342
- character_id=audit.eve_character.character_id,
389
+ character_id=owner.eve_character.character_id,
343
390
  planet_id=planet_id,
344
391
  token=token,
345
392
  )
@@ -351,7 +398,7 @@ class PlanetaryDetailsManagerBase(models.Manager):
351
398
  continue
352
399
 
353
400
  self._update_or_create_objs(
354
- character=audit,
401
+ owner=owner,
355
402
  objs=planets_details_items,
356
403
  planet_id=planet_id,
357
404
  )
@@ -362,7 +409,7 @@ class PlanetaryDetailsManagerBase(models.Manager):
362
409
  @transaction.atomic()
363
410
  def _update_or_create_objs(
364
411
  self,
365
- character: "CharacterAudit",
412
+ owner: CharacterOwner,
366
413
  objs: list["PlanetDetailsItem"],
367
414
  planet_id: int,
368
415
  ) -> None:
@@ -373,18 +420,18 @@ class PlanetaryDetailsManagerBase(models.Manager):
373
420
 
374
421
  try:
375
422
  character_planet = CharacterPlanet.objects.get(
376
- character=character, planet_id=planet_id
423
+ character=owner, eve_planet_id=planet_id
377
424
  )
378
425
  except CharacterPlanet.DoesNotExist:
379
426
  logger.warning(
380
427
  "Planet %s not found for character %s",
381
428
  planet_id,
382
- character.eve_character.character_name,
429
+ owner.eve_character.character_name,
383
430
  )
384
431
  return
385
432
 
386
- planet_details, created = self.update_or_create_layout(
387
- character=character,
433
+ planet_details, created = self.get_queryset().update_or_create_layout(
434
+ owner=owner,
388
435
  planet=character_planet,
389
436
  objs=objs,
390
437
  )
@@ -394,7 +441,7 @@ class PlanetaryDetailsManagerBase(models.Manager):
394
441
  if planet_details.is_expired and planet_details.last_alert is None:
395
442
  logger.debug(
396
443
  "Planet %s Extractor Heads Expired for: %s",
397
- planet_details.planet.planet.name,
444
+ planet_details.planet.eve_planet.name,
398
445
  planet_details.planet.character.eve_character.character_name,
399
446
  )
400
447
  planet_details.last_alert = timezone.now()
@@ -408,14 +455,9 @@ class PlanetaryDetailsManagerBase(models.Manager):
408
455
  logger.debug(
409
456
  "Notification Reseted for %s Planet: %s",
410
457
  planet_details.planet.character.eve_character.character_name,
411
- planet_details.planet.planet.name,
458
+ planet_details.planet.eve_planet.name,
412
459
  )
413
460
  planet_details.last_alert = None
414
461
  planet_details.notification_sent = False
415
462
 
416
463
  planet_details.save()
417
-
418
-
419
- PlanetaryDetailsManager = PlanetaryDetailsManagerBase.from_queryset(
420
- PlanetaryDetailsQuerySet
421
- )