aa-ledger 0.9.9__py3-none-any.whl → 0.9.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aa_ledger-0.9.9.dist-info → aa_ledger-0.9.9.1.dist-info}/METADATA +1 -1
- {aa_ledger-0.9.9.dist-info → aa_ledger-0.9.9.1.dist-info}/RECORD +77 -77
- ledger/__init__.py +9 -9
- ledger/api/api_helper/billboard_helper.py +277 -277
- ledger/api/ledger/admin.py +289 -289
- ledger/app_settings.py +50 -50
- ledger/constants.py +5 -0
- ledger/decorators.py +92 -11
- ledger/helpers/alliance.py +353 -334
- ledger/helpers/character.py +260 -260
- ledger/helpers/core.py +565 -565
- ledger/helpers/corporation.py +455 -421
- ledger/helpers/etag.py +237 -237
- ledger/helpers/ref_type.py +475 -475
- ledger/locale/cs_CZ/LC_MESSAGES/django.po +942 -942
- ledger/locale/de/LC_MESSAGES/django.po +961 -961
- ledger/locale/django.pot +942 -942
- ledger/locale/es/LC_MESSAGES/django.po +943 -943
- ledger/locale/fr_FR/LC_MESSAGES/django.po +942 -942
- ledger/locale/it_IT/LC_MESSAGES/django.po +942 -942
- ledger/locale/ja/LC_MESSAGES/django.po +943 -943
- ledger/locale/ko_KR/LC_MESSAGES/django.po +942 -942
- ledger/locale/nl_NL/LC_MESSAGES/django.po +942 -942
- ledger/locale/pl_PL/LC_MESSAGES/django.po +942 -942
- ledger/locale/ru/LC_MESSAGES/django.po +945 -945
- ledger/locale/sk/LC_MESSAGES/django.po +944 -944
- ledger/locale/uk/LC_MESSAGES/django.po +946 -946
- ledger/locale/zh_Hans/LC_MESSAGES/django.po +943 -943
- ledger/managers/character_mining_manager.py +239 -239
- ledger/managers/character_planetary_manager.py +1 -1
- ledger/migrations/0016_characterminingledger_price_per_unit.py +21 -21
- ledger/models/characteraudit.py +496 -496
- ledger/static/ledger/css/cards.css +1 -1
- ledger/static/ledger/css/table.css +1 -1
- ledger/static/ledger/js/charts.js +221 -221
- ledger/static/ledger/js/planetary.js +143 -143
- ledger/tasks.py +442 -449
- ledger/templates/ledger/allyledger/admin/alliance_administration.html +46 -46
- ledger/templates/ledger/allyledger/admin/alliance_overview.html +108 -108
- ledger/templates/ledger/allyledger/alliance_ledger.html +86 -86
- ledger/templates/ledger/bundles/ally-administration-bundles.html +59 -59
- ledger/templates/ledger/bundles/char-administration-bundles.html +66 -66
- ledger/templates/ledger/bundles/character-ledger-bundles.html +66 -66
- ledger/templates/ledger/bundles/corp-administration-bundles.html +68 -68
- ledger/templates/ledger/bundles/corporation-ledger-bundles.html +75 -75
- ledger/templates/ledger/charledger/admin/character_administration.html +39 -39
- ledger/templates/ledger/charledger/admin/character_overview.html +106 -106
- ledger/templates/ledger/charledger/character_ledger.html +94 -94
- ledger/templates/ledger/charledger/planetary/planetary_ledger.html +54 -54
- ledger/templates/ledger/corpledger/admin/corporation_administration.html +39 -39
- ledger/templates/ledger/corpledger/admin/corporation_overview.html +108 -108
- ledger/templates/ledger/corpledger/corporation_ledger.html +129 -86
- ledger/templates/ledger/partials/administration/alliance.html +37 -37
- ledger/templates/ledger/partials/administration/alliance_corporations.html +58 -58
- ledger/templates/ledger/partials/administration/corporation_characters.html +34 -34
- ledger/templates/ledger/partials/information/daily.html +56 -56
- ledger/templates/ledger/partials/information/day.html +48 -48
- ledger/templates/ledger/partials/information/hourly.html +53 -53
- ledger/templates/ledger/partials/information/summary.html +88 -88
- ledger/templates/ledger/partials/information/view_character_content.html +35 -35
- ledger/templates/ledger/partials/table/char-ledger.html +85 -85
- ledger/templates/ledger/partials/table/corp-ledger.html +66 -66
- ledger/templates/ledger/partials/view/card.html +160 -160
- ledger/tests/test_decarators.py +102 -17
- ledger/tests/test_helpers/test_etag.py +149 -149
- ledger/tests/test_managers/test_character_mining_manager.py +54 -54
- ledger/tests/test_models/test_characterminingledger.py +107 -106
- ledger/tests/test_tasks.py +282 -282
- ledger/tests/test_templatetags.py +5 -2
- ledger/tests/test_views/test_access.py +852 -852
- ledger/tests/testdata/esi.json +1 -2
- ledger/tests/testdata/eveuniverse.json +391 -391
- ledger/urls.py +66 -21
- ledger/views/alliance/alliance_ledger.py +203 -203
- ledger/views/corporation/corporation_ledger.py +25 -9
- {aa_ledger-0.9.9.dist-info → aa_ledger-0.9.9.1.dist-info}/WHEEL +0 -0
- {aa_ledger-0.9.9.dist-info → aa_ledger-0.9.9.1.dist-info}/licenses/LICENSE +0 -0
ledger/helpers/corporation.py
CHANGED
|
@@ -1,421 +1,455 @@
|
|
|
1
|
-
"""PvE Views"""
|
|
2
|
-
|
|
3
|
-
# Standard Library
|
|
4
|
-
import json
|
|
5
|
-
from decimal import Decimal
|
|
6
|
-
|
|
7
|
-
# Django
|
|
8
|
-
from django.core.cache import cache
|
|
9
|
-
from django.core.handlers.wsgi import WSGIRequest
|
|
10
|
-
from django.db.models import DecimalField, Q, Sum
|
|
11
|
-
from django.utils.translation import gettext as _
|
|
12
|
-
|
|
13
|
-
# Alliance Auth
|
|
14
|
-
from allianceauth.eveonline.models import EveCharacter
|
|
15
|
-
from allianceauth.services.hooks import get_extension_logger
|
|
16
|
-
|
|
17
|
-
# Alliance Auth (External Libs)
|
|
18
|
-
from app_utils.logging import LoggerAddTag
|
|
19
|
-
|
|
20
|
-
# AA Ledger
|
|
21
|
-
from ledger import __title__
|
|
22
|
-
from ledger.app_settings import LEDGER_CACHE_ENABLED, LEDGER_CACHE_STALE
|
|
23
|
-
from ledger.
|
|
24
|
-
from ledger.helpers.
|
|
25
|
-
from ledger.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
month
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
self.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self.filter_date,
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
alts_dict.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
"
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
ledger
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
.
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
self.
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
)
|
|
421
|
-
|
|
1
|
+
"""PvE Views"""
|
|
2
|
+
|
|
3
|
+
# Standard Library
|
|
4
|
+
import json
|
|
5
|
+
from decimal import Decimal
|
|
6
|
+
|
|
7
|
+
# Django
|
|
8
|
+
from django.core.cache import cache
|
|
9
|
+
from django.core.handlers.wsgi import WSGIRequest
|
|
10
|
+
from django.db.models import DecimalField, Q, Sum
|
|
11
|
+
from django.utils.translation import gettext as _
|
|
12
|
+
|
|
13
|
+
# Alliance Auth
|
|
14
|
+
from allianceauth.eveonline.models import EveCharacter
|
|
15
|
+
from allianceauth.services.hooks import get_extension_logger
|
|
16
|
+
|
|
17
|
+
# Alliance Auth (External Libs)
|
|
18
|
+
from app_utils.logging import LoggerAddTag
|
|
19
|
+
|
|
20
|
+
# AA Ledger
|
|
21
|
+
from ledger import __title__
|
|
22
|
+
from ledger.app_settings import LEDGER_CACHE_ENABLED, LEDGER_CACHE_STALE
|
|
23
|
+
from ledger.constants import NPC_ENTITIES
|
|
24
|
+
from ledger.helpers.core import LedgerCore, LedgerEntity
|
|
25
|
+
from ledger.helpers.ref_type import RefTypeManager
|
|
26
|
+
from ledger.models.corporationaudit import (
|
|
27
|
+
CorporationAudit,
|
|
28
|
+
CorporationWalletDivision,
|
|
29
|
+
CorporationWalletJournalEntry,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
logger = LoggerAddTag(get_extension_logger(__name__), __title__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CorporationData(LedgerCore):
|
|
36
|
+
"""Class to hold character data for the ledger."""
|
|
37
|
+
|
|
38
|
+
# pylint: disable=too-many-positional-arguments
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
request: WSGIRequest,
|
|
42
|
+
corporation: CorporationAudit,
|
|
43
|
+
division_id: int = None,
|
|
44
|
+
year: int = None,
|
|
45
|
+
month: int = None,
|
|
46
|
+
day: int = None,
|
|
47
|
+
):
|
|
48
|
+
LedgerCore.__init__(self, year, month, day)
|
|
49
|
+
self.request = request
|
|
50
|
+
self.corporation = corporation
|
|
51
|
+
self.division_id = division_id
|
|
52
|
+
self.auth_char_ids = self.auth_character_ids
|
|
53
|
+
|
|
54
|
+
def setup_ledger(self, entity: LedgerEntity = None):
|
|
55
|
+
"""Setup the Ledger Data for the Corporation."""
|
|
56
|
+
corporation_id = self.corporation.corporation.corporation_id
|
|
57
|
+
|
|
58
|
+
# Base queryset filtered by date and corporation division
|
|
59
|
+
base_qs = self._base_journal_queryset()
|
|
60
|
+
|
|
61
|
+
if entity is None:
|
|
62
|
+
# No entity specified: show all entries for the corporation (except self-transfers)
|
|
63
|
+
self.journal = base_qs.exclude(
|
|
64
|
+
first_party_id=corporation_id, second_party_id=corporation_id
|
|
65
|
+
)
|
|
66
|
+
# Prepare auxiliary data used by the view
|
|
67
|
+
self.existing_years = self._compute_existing_years()
|
|
68
|
+
self.entities = self._compute_entities()
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
# If the entity is the corporation itself and "all" is set, show all entries
|
|
72
|
+
if self.request.GET.get("all", False) and entity.entity_id == corporation_id:
|
|
73
|
+
self.journal = base_qs.exclude(
|
|
74
|
+
first_party_id=corporation_id, second_party_id=corporation_id
|
|
75
|
+
)
|
|
76
|
+
self.entities = self._compute_entities()
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
# Regular entity filtering: include any rows where the entity is a first or second party
|
|
80
|
+
character_ids = entity.get_alts_ids_or_self()
|
|
81
|
+
qs = base_qs.filter(
|
|
82
|
+
Q(first_party_id__in=character_ids) | Q(second_party_id__in=character_ids)
|
|
83
|
+
)
|
|
84
|
+
qs = qs.exclude(first_party_id=corporation_id, second_party_id=corporation_id)
|
|
85
|
+
|
|
86
|
+
# If the entity is the corporation itself, include NPC transactions too
|
|
87
|
+
if entity.entity_id == corporation_id:
|
|
88
|
+
qs = qs.filter(
|
|
89
|
+
Q(first_party_id__in=NPC_ENTITIES) | Q(second_party_id__in=NPC_ENTITIES)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# If entity represents a corporation or alliance, exclude auth account character IDs
|
|
93
|
+
# that are not part of the current entity to avoid double counting
|
|
94
|
+
if entity.type in ["alliance", "corporation"]:
|
|
95
|
+
exclude_ids = self.auth_char_ids - set(character_ids)
|
|
96
|
+
qs = qs.exclude(
|
|
97
|
+
Q(first_party_id__in=exclude_ids) | Q(second_party_id__in=exclude_ids)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
self.journal = qs
|
|
101
|
+
self.entities = self._compute_entities()
|
|
102
|
+
|
|
103
|
+
def _base_journal_queryset(self):
|
|
104
|
+
"""Return the base queryset filtered by the current date range and corporation division."""
|
|
105
|
+
if self.division_id is not None:
|
|
106
|
+
return CorporationWalletJournalEntry.objects.filter(
|
|
107
|
+
self.filter_date,
|
|
108
|
+
division__corporation=self.corporation,
|
|
109
|
+
division=self.division_id,
|
|
110
|
+
)
|
|
111
|
+
return CorporationWalletJournalEntry.objects.filter(
|
|
112
|
+
self.filter_date, division__corporation=self.corporation
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def _compute_entities(self):
|
|
116
|
+
"""Return a set of all entity IDs (first and second parties) present in the current journal."""
|
|
117
|
+
return set(self.journal.values_list("second_party_id", flat=True)) | set(
|
|
118
|
+
self.journal.values_list("first_party_id", flat=True)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
def _compute_existing_years(self):
|
|
122
|
+
"""Return the available years for journal entries for this corporation."""
|
|
123
|
+
return (
|
|
124
|
+
CorporationWalletJournalEntry.objects.filter(
|
|
125
|
+
division__corporation=self.corporation
|
|
126
|
+
)
|
|
127
|
+
.exclude(date__year__isnull=True)
|
|
128
|
+
.values_list("date__year", flat=True)
|
|
129
|
+
.order_by("-date__year")
|
|
130
|
+
.distinct()
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def create_entity_data(
|
|
134
|
+
self,
|
|
135
|
+
entity: LedgerEntity,
|
|
136
|
+
alts: EveCharacter = None,
|
|
137
|
+
) -> dict:
|
|
138
|
+
"""Create the URL for entity details based on the view type."""
|
|
139
|
+
ids = (
|
|
140
|
+
list(alts.values_list("character__character_id", flat=True))
|
|
141
|
+
if alts is not None
|
|
142
|
+
else [entity.entity_id]
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Create Alts Dictionary
|
|
146
|
+
alts_dict = {}
|
|
147
|
+
if alts is not None:
|
|
148
|
+
for alt in alts:
|
|
149
|
+
alts_dict[alt.character.character_id] = alt.character.character_name
|
|
150
|
+
|
|
151
|
+
# Remove the main character from the alts dictionary only one entry
|
|
152
|
+
if len(alts_dict) == 1:
|
|
153
|
+
alts_dict.pop(entity.entity_id, None)
|
|
154
|
+
|
|
155
|
+
used_pks = set()
|
|
156
|
+
bounty = Decimal(0)
|
|
157
|
+
ess = Decimal(0)
|
|
158
|
+
miscellaneous = Decimal(0)
|
|
159
|
+
costs = Decimal(0)
|
|
160
|
+
|
|
161
|
+
for pk, rows in list(self.entries.items()):
|
|
162
|
+
for row in rows:
|
|
163
|
+
if row["first_party_id"] in ids or row["second_party_id"] in ids:
|
|
164
|
+
if RefTypeManager.special_cases(
|
|
165
|
+
row, ids=ids, account_char_ids=self.auth_char_ids
|
|
166
|
+
):
|
|
167
|
+
continue
|
|
168
|
+
bounty += row.get("bounty") or Decimal(0)
|
|
169
|
+
ess += row.get("ess") or Decimal(0)
|
|
170
|
+
miscellaneous += row.get("miscellaneous") or Decimal(0)
|
|
171
|
+
costs += row.get("costs") or Decimal(0)
|
|
172
|
+
used_pks.add(pk)
|
|
173
|
+
|
|
174
|
+
# Remove Used Pks from Entries
|
|
175
|
+
# This is to prevent the entries from being used in the future
|
|
176
|
+
for pk in used_pks:
|
|
177
|
+
self.entries.pop(pk, None)
|
|
178
|
+
|
|
179
|
+
total = sum([bounty, ess, miscellaneous, costs])
|
|
180
|
+
|
|
181
|
+
if total == 0:
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
char_data = {
|
|
185
|
+
"entity": entity,
|
|
186
|
+
"alts": alts_dict,
|
|
187
|
+
"ledger": {
|
|
188
|
+
"bounty": bounty,
|
|
189
|
+
"ess": ess,
|
|
190
|
+
"miscellaneous": miscellaneous,
|
|
191
|
+
"costs": costs,
|
|
192
|
+
"total": total,
|
|
193
|
+
},
|
|
194
|
+
"type": entity.type,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return char_data
|
|
198
|
+
|
|
199
|
+
def generate_ledger_data(self) -> dict:
|
|
200
|
+
"""
|
|
201
|
+
Generate the ledger data for the corporation.
|
|
202
|
+
|
|
203
|
+
This method processes the journal entries, builds the ledger data,
|
|
204
|
+
and prepares the context for rendering the corporation ledger view.
|
|
205
|
+
"""
|
|
206
|
+
ledger = False
|
|
207
|
+
finished_entities = False
|
|
208
|
+
|
|
209
|
+
self.setup_ledger()
|
|
210
|
+
|
|
211
|
+
journal = self.journal.values(
|
|
212
|
+
"first_party_id", "second_party_id", "pk", "ref_type"
|
|
213
|
+
).annotate(
|
|
214
|
+
bounty=Sum(
|
|
215
|
+
"amount",
|
|
216
|
+
filter=Q(ref_type__in=RefTypeManager.BOUNTY_PRIZES),
|
|
217
|
+
output_field=DecimalField(),
|
|
218
|
+
),
|
|
219
|
+
ess=Sum(
|
|
220
|
+
"amount",
|
|
221
|
+
filter=Q(ref_type__in=RefTypeManager.ESS_TRANSFER),
|
|
222
|
+
output_field=DecimalField(),
|
|
223
|
+
),
|
|
224
|
+
costs=Sum(
|
|
225
|
+
"amount",
|
|
226
|
+
filter=Q(ref_type__in=RefTypeManager.all_ref_types(), amount__lt=0),
|
|
227
|
+
output_field=DecimalField(),
|
|
228
|
+
),
|
|
229
|
+
miscellaneous=Sum(
|
|
230
|
+
"amount",
|
|
231
|
+
filter=Q(ref_type__in=RefTypeManager.all_ref_types(), amount__gt=0),
|
|
232
|
+
output_field=DecimalField(),
|
|
233
|
+
),
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# Get the journal hash and cache header
|
|
237
|
+
ledger_hash = self._get_ledger_journal_hash(self.journal.values_list("pk"))
|
|
238
|
+
ledger_header = self._get_ledger_header(
|
|
239
|
+
ledger_args=f"{self.corporation.corporation.corporation_id}_{self.division_id}",
|
|
240
|
+
year=self.year,
|
|
241
|
+
month=self.month,
|
|
242
|
+
day=self.day,
|
|
243
|
+
)
|
|
244
|
+
cache_header = cache.get(
|
|
245
|
+
ledger_header,
|
|
246
|
+
False,
|
|
247
|
+
)
|
|
248
|
+
logger.debug(
|
|
249
|
+
f"Ledger Header: {ledger_header}, Cache Header: {cache_header}, Journal Hash: {ledger_hash}"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# Check if the journal is up to date
|
|
253
|
+
journal_up_to_date = cache_header == ledger_hash
|
|
254
|
+
ledger_key = self._build_ledger_cache_key(ledger_header)
|
|
255
|
+
|
|
256
|
+
# Check if we have newest cached version of the ledger
|
|
257
|
+
if journal_up_to_date and LEDGER_CACHE_ENABLED:
|
|
258
|
+
ledger = cache.get(f"{ledger_key}-data", False)
|
|
259
|
+
finished_entities = cache.get(f"{ledger_key}-finished_entities", False)
|
|
260
|
+
|
|
261
|
+
if finished_entities is False or ledger is False:
|
|
262
|
+
# Build the entries from the journal
|
|
263
|
+
self.entries = {}
|
|
264
|
+
for row in journal:
|
|
265
|
+
self.entries.setdefault(row["pk"], []).append(row)
|
|
266
|
+
|
|
267
|
+
# Process Auth Accounts first
|
|
268
|
+
ledger, finished_entities = self._process_auth_accounts()
|
|
269
|
+
# Process remaining entities
|
|
270
|
+
self._process_remaining_entities(ledger, finished_entities)
|
|
271
|
+
# Process corporation entity last to ensure it's always included
|
|
272
|
+
self._handle_entity(
|
|
273
|
+
ledger=ledger,
|
|
274
|
+
entity_id=self.corporation.corporation.corporation_id,
|
|
275
|
+
corporation_obj=self.corporation.corporation,
|
|
276
|
+
)
|
|
277
|
+
# Finalize the billboard for the ledger.
|
|
278
|
+
self.create_rattingbar(list(finished_entities))
|
|
279
|
+
self.create_chord(ledger)
|
|
280
|
+
|
|
281
|
+
context = self._build_context(ledger=ledger)
|
|
282
|
+
|
|
283
|
+
# Create Cache
|
|
284
|
+
cache.set(key=f"{ledger_key}-data", value=ledger, timeout=LEDGER_CACHE_STALE)
|
|
285
|
+
cache.set(
|
|
286
|
+
key=f"{ledger_key}-finished_entities",
|
|
287
|
+
value=finished_entities,
|
|
288
|
+
timeout=LEDGER_CACHE_STALE,
|
|
289
|
+
)
|
|
290
|
+
cache.set(
|
|
291
|
+
key=self._get_ledger_header(
|
|
292
|
+
ledger_args=f"{self.corporation.corporation.corporation_id}_{self.division_id}",
|
|
293
|
+
year=self.year,
|
|
294
|
+
month=self.month,
|
|
295
|
+
day=self.day,
|
|
296
|
+
),
|
|
297
|
+
value=ledger_hash,
|
|
298
|
+
timeout=None, # Cache forever until the journal changes
|
|
299
|
+
)
|
|
300
|
+
return context
|
|
301
|
+
|
|
302
|
+
def _build_view_data(self, entity_id: int):
|
|
303
|
+
details_kwargs = {
|
|
304
|
+
"viewname": "corporation_details",
|
|
305
|
+
"corporation_id": self.corporation.corporation.corporation_id,
|
|
306
|
+
"entity_id": entity_id,
|
|
307
|
+
}
|
|
308
|
+
if self.division_id is not None:
|
|
309
|
+
details_kwargs["division_id"] = self.division_id
|
|
310
|
+
return details_kwargs
|
|
311
|
+
|
|
312
|
+
def _build_view_url(self, entity_id: int):
|
|
313
|
+
"""Return the full URL for a corporation view for the given entity id.
|
|
314
|
+
|
|
315
|
+
This wraps create_url(**self._build_view_data(...)) so callers can
|
|
316
|
+
request the URL in a single, readable call without losing ordering.
|
|
317
|
+
"""
|
|
318
|
+
return self.create_url(**self._build_view_data(entity_id=entity_id))
|
|
319
|
+
|
|
320
|
+
# pylint: disable=too-many-arguments
|
|
321
|
+
def _handle_entity(
|
|
322
|
+
self,
|
|
323
|
+
ledger: list,
|
|
324
|
+
entity_id: int,
|
|
325
|
+
character_obj=None,
|
|
326
|
+
corporation_obj=None,
|
|
327
|
+
alts=None,
|
|
328
|
+
add_finished: bool = True,
|
|
329
|
+
finished_ids=None,
|
|
330
|
+
) -> set:
|
|
331
|
+
"""Create entity object, add to ledger if it has data and return IDs to mark finished.
|
|
332
|
+
|
|
333
|
+
- ledger: list to append to
|
|
334
|
+
- entity_id: numeric id
|
|
335
|
+
- character_obj / corporation_obj: optional objects to attach to LedgerEntity
|
|
336
|
+
- alts: optional alts queryset passed to create_entity_data
|
|
337
|
+
- add_finished: whether to return ids that should be added to finished_entities
|
|
338
|
+
- finished_ids: explicit IDs (set or iterable) to mark finished (used for accounts)
|
|
339
|
+
"""
|
|
340
|
+
details_url = self._build_view_url(entity_id)
|
|
341
|
+
entity_obj = LedgerEntity(
|
|
342
|
+
entity_id,
|
|
343
|
+
character_obj=character_obj,
|
|
344
|
+
corporation_obj=corporation_obj,
|
|
345
|
+
details_url=details_url,
|
|
346
|
+
)
|
|
347
|
+
char_data = self.create_entity_data(entity=entity_obj, alts=alts)
|
|
348
|
+
if char_data is None:
|
|
349
|
+
return set()
|
|
350
|
+
ledger.append(char_data)
|
|
351
|
+
if not add_finished:
|
|
352
|
+
return set()
|
|
353
|
+
if finished_ids is not None:
|
|
354
|
+
return set(finished_ids)
|
|
355
|
+
return {entity_id}
|
|
356
|
+
|
|
357
|
+
def _process_auth_accounts(self):
|
|
358
|
+
"""Process Auth Account information for the ledger."""
|
|
359
|
+
ledger = []
|
|
360
|
+
finished_entities = set()
|
|
361
|
+
for account in self.auth_accounts:
|
|
362
|
+
alts = account.user.character_ownerships.all()
|
|
363
|
+
existing_alts = set(
|
|
364
|
+
alts.values_list("character__character_id", flat=True)
|
|
365
|
+
).intersection(self.entities)
|
|
366
|
+
alts = alts.filter(character__character_id__in=existing_alts)
|
|
367
|
+
if not existing_alts:
|
|
368
|
+
continue
|
|
369
|
+
finished_entities.update(
|
|
370
|
+
self._handle_entity(
|
|
371
|
+
ledger,
|
|
372
|
+
account.main_character.character_id,
|
|
373
|
+
character_obj=account.main_character,
|
|
374
|
+
alts=alts,
|
|
375
|
+
finished_ids=existing_alts,
|
|
376
|
+
)
|
|
377
|
+
)
|
|
378
|
+
return ledger, finished_entities
|
|
379
|
+
|
|
380
|
+
def _process_remaining_entities(self, ledger, finished_entities: set):
|
|
381
|
+
"""Process remaining entities for the ledger."""
|
|
382
|
+
remaining_entities = self.entities - finished_entities
|
|
383
|
+
if not remaining_entities:
|
|
384
|
+
return
|
|
385
|
+
for entity_id in remaining_entities:
|
|
386
|
+
if entity_id in NPC_ENTITIES:
|
|
387
|
+
continue
|
|
388
|
+
if entity_id == self.corporation.corporation.corporation_id:
|
|
389
|
+
continue
|
|
390
|
+
finished_entities.update(self._handle_entity(ledger, entity_id))
|
|
391
|
+
|
|
392
|
+
def _build_context(self, ledger):
|
|
393
|
+
"""Build the context for the ledger view."""
|
|
394
|
+
view = self._build_view_data(
|
|
395
|
+
entity_id=self.corporation.corporation.corporation_id
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
context = {
|
|
399
|
+
"title": f"Corporation Ledger - {self.corporation.corporation.corporation_name}",
|
|
400
|
+
"corporation_id": self.corporation.corporation.corporation_id,
|
|
401
|
+
"division_id": self.division_id,
|
|
402
|
+
"billboard": json.dumps(self.billboard.dict.asdict()),
|
|
403
|
+
"ledger": ledger,
|
|
404
|
+
"divisions": CorporationWalletDivision.objects.filter(
|
|
405
|
+
corporation=self.corporation
|
|
406
|
+
).order_by("division_id"),
|
|
407
|
+
"years": list(self.existing_years),
|
|
408
|
+
"totals": self._calculate_totals(ledger),
|
|
409
|
+
"view": self.create_view_data(**view),
|
|
410
|
+
}
|
|
411
|
+
return context
|
|
412
|
+
|
|
413
|
+
def create_rattingbar(self, entities_ids: list = None):
|
|
414
|
+
"""Create the ratting bar for the view."""
|
|
415
|
+
if not entities_ids:
|
|
416
|
+
return
|
|
417
|
+
|
|
418
|
+
rattingbar_timeline = self.billboard.create_timeline(self.journal)
|
|
419
|
+
rattingbar = (
|
|
420
|
+
rattingbar_timeline.annotate_bounty_income()
|
|
421
|
+
.annotate_ess_income()
|
|
422
|
+
.annotate_miscellaneous()
|
|
423
|
+
)
|
|
424
|
+
self.billboard.create_or_update_results(rattingbar)
|
|
425
|
+
self._build_xy_chart(title=_("Ratting Bar"))
|
|
426
|
+
|
|
427
|
+
def create_chord(self, ledger_data: list[dict]):
|
|
428
|
+
"""Create the chord chart for the view."""
|
|
429
|
+
if not ledger_data:
|
|
430
|
+
return
|
|
431
|
+
|
|
432
|
+
for entry in ledger_data:
|
|
433
|
+
entity_name = entry["entity"].entity_name
|
|
434
|
+
ledger = entry["ledger"]
|
|
435
|
+
self.billboard.chord_add_data(
|
|
436
|
+
chord_from=entity_name,
|
|
437
|
+
chord_to=_("Bounty (Wallet)"),
|
|
438
|
+
value=ledger.get("bounty", 0),
|
|
439
|
+
)
|
|
440
|
+
self.billboard.chord_add_data(
|
|
441
|
+
chord_from=entity_name,
|
|
442
|
+
chord_to=_("ESS (Wallet)"),
|
|
443
|
+
value=ledger.get("ess", 0),
|
|
444
|
+
)
|
|
445
|
+
self.billboard.chord_add_data(
|
|
446
|
+
chord_from=entity_name,
|
|
447
|
+
chord_to=_("Costs (Wallet)"),
|
|
448
|
+
value=abs(ledger.get("costs", 0)),
|
|
449
|
+
)
|
|
450
|
+
self.billboard.chord_add_data(
|
|
451
|
+
chord_from=entity_name,
|
|
452
|
+
chord_to=_("Miscellaneous (Wallet)"),
|
|
453
|
+
value=abs(ledger.get("miscellaneous", 0)),
|
|
454
|
+
)
|
|
455
|
+
self.billboard.chord_handle_overflow()
|