aa-ledger 0.9.8__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.
Files changed (78) hide show
  1. {aa_ledger-0.9.8.dist-info → aa_ledger-0.9.9.1.dist-info}/METADATA +3 -1
  2. {aa_ledger-0.9.8.dist-info → aa_ledger-0.9.9.1.dist-info}/RECORD +78 -76
  3. ledger/__init__.py +9 -9
  4. ledger/api/api_helper/billboard_helper.py +55 -26
  5. ledger/api/ledger/admin.py +1 -1
  6. ledger/app_settings.py +18 -11
  7. ledger/constants.py +5 -0
  8. ledger/decorators.py +92 -11
  9. ledger/helpers/alliance.py +119 -91
  10. ledger/helpers/character.py +260 -252
  11. ledger/helpers/core.py +565 -565
  12. ledger/helpers/corporation.py +237 -187
  13. ledger/helpers/etag.py +2 -1
  14. ledger/helpers/ref_type.py +475 -475
  15. ledger/locale/cs_CZ/LC_MESSAGES/django.po +942 -932
  16. ledger/locale/de/LC_MESSAGES/django.mo +0 -0
  17. ledger/locale/de/LC_MESSAGES/django.po +961 -945
  18. ledger/locale/django.pot +942 -932
  19. ledger/locale/es/LC_MESSAGES/django.po +943 -933
  20. ledger/locale/fr_FR/LC_MESSAGES/django.po +942 -932
  21. ledger/locale/it_IT/LC_MESSAGES/django.po +942 -932
  22. ledger/locale/ja/LC_MESSAGES/django.po +943 -933
  23. ledger/locale/ko_KR/LC_MESSAGES/django.po +942 -932
  24. ledger/locale/nl_NL/LC_MESSAGES/django.po +942 -932
  25. ledger/locale/pl_PL/LC_MESSAGES/django.po +942 -932
  26. ledger/locale/ru/LC_MESSAGES/django.po +945 -935
  27. ledger/locale/sk/LC_MESSAGES/django.po +944 -934
  28. ledger/locale/uk/LC_MESSAGES/django.po +946 -936
  29. ledger/locale/zh_Hans/LC_MESSAGES/django.po +943 -933
  30. ledger/managers/character_mining_manager.py +66 -19
  31. ledger/managers/character_planetary_manager.py +1 -1
  32. ledger/migrations/0016_characterminingledger_price_per_unit.py +21 -0
  33. ledger/models/characteraudit.py +32 -1
  34. ledger/static/ledger/css/cards.css +1 -1
  35. ledger/static/ledger/css/table.css +1 -1
  36. ledger/static/ledger/js/charts.js +7 -227
  37. ledger/static/ledger/js/planetary.js +1 -0
  38. ledger/tasks.py +1 -8
  39. ledger/templates/ledger/allyledger/admin/alliance_administration.html +17 -8
  40. ledger/templates/ledger/allyledger/admin/alliance_overview.html +75 -89
  41. ledger/templates/ledger/allyledger/alliance_ledger.html +8 -10
  42. ledger/templates/ledger/bundles/ally-administration-bundles.html +2 -0
  43. ledger/templates/ledger/bundles/char-administration-bundles.html +2 -0
  44. ledger/templates/ledger/bundles/character-ledger-bundles.html +66 -64
  45. ledger/templates/ledger/bundles/corp-administration-bundles.html +2 -0
  46. ledger/templates/ledger/bundles/corporation-ledger-bundles.html +75 -73
  47. ledger/templates/ledger/charledger/admin/character_administration.html +10 -8
  48. ledger/templates/ledger/charledger/admin/character_overview.html +69 -86
  49. ledger/templates/ledger/charledger/character_ledger.html +11 -15
  50. ledger/templates/ledger/charledger/planetary/planetary_ledger.html +2 -6
  51. ledger/templates/ledger/corpledger/admin/corporation_administration.html +10 -8
  52. ledger/templates/ledger/corpledger/admin/corporation_overview.html +71 -83
  53. ledger/templates/ledger/corpledger/corporation_ledger.html +55 -14
  54. ledger/templates/ledger/partials/administration/alliance.html +28 -49
  55. ledger/templates/ledger/partials/administration/alliance_corporations.html +58 -0
  56. ledger/templates/ledger/partials/administration/corporation_characters.html +26 -28
  57. ledger/templates/ledger/partials/information/daily.html +1 -1
  58. ledger/templates/ledger/partials/information/day.html +1 -7
  59. ledger/templates/ledger/partials/information/hourly.html +1 -7
  60. ledger/templates/ledger/partials/information/summary.html +88 -84
  61. ledger/templates/ledger/partials/information/view_character_content.html +35 -35
  62. ledger/templates/ledger/partials/table/char-ledger.html +14 -5
  63. ledger/templates/ledger/partials/table/corp-ledger.html +3 -3
  64. ledger/templates/ledger/partials/view/card.html +2 -2
  65. ledger/tests/test_decarators.py +102 -17
  66. ledger/tests/test_helpers/test_etag.py +7 -6
  67. ledger/tests/test_managers/test_character_mining_manager.py +2 -1
  68. ledger/tests/test_models/test_characterminingledger.py +38 -2
  69. ledger/tests/test_tasks.py +4 -4
  70. ledger/tests/test_templatetags.py +5 -2
  71. ledger/tests/test_views/test_access.py +852 -852
  72. ledger/tests/testdata/esi.json +1 -2
  73. ledger/tests/testdata/eveuniverse.json +90 -48
  74. ledger/urls.py +66 -21
  75. ledger/views/alliance/alliance_ledger.py +4 -3
  76. ledger/views/corporation/corporation_ledger.py +25 -9
  77. {aa_ledger-0.9.8.dist-info → aa_ledger-0.9.9.1.dist-info}/WHEEL +0 -0
  78. {aa_ledger-0.9.8.dist-info → aa_ledger-0.9.9.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,252 +1,260 @@
1
- """PvE Views"""
2
-
3
- # Standard Library
4
- import json
5
- from decimal import Decimal
6
-
7
- # Django
8
- from django.core.handlers.wsgi import WSGIRequest
9
- from django.utils.translation import gettext as _
10
-
11
- # Alliance Auth
12
- from allianceauth.services.hooks import get_extension_logger
13
-
14
- # Alliance Auth (External Libs)
15
- from app_utils.logging import LoggerAddTag
16
-
17
- # AA Ledger
18
- from ledger import __title__
19
- from ledger.helpers.core import LedgerCore
20
- from ledger.models.characteraudit import (
21
- CharacterAudit,
22
- CharacterMiningLedger,
23
- CharacterWalletJournalEntry,
24
- )
25
-
26
- logger = LoggerAddTag(get_extension_logger(__name__), __title__)
27
-
28
-
29
- class CharacterData(LedgerCore):
30
- """Class to hold character data for the ledger."""
31
-
32
- # pylint: disable=too-many-positional-arguments
33
- def __init__(
34
- self,
35
- request: WSGIRequest,
36
- character: CharacterAudit,
37
- year=None,
38
- month=None,
39
- day=None,
40
- ):
41
- LedgerCore.__init__(self, year, month, day)
42
- self.request = request
43
- self.character = character
44
- self.alts_ids = self.get_alt_ids
45
-
46
- @property
47
- def get_alt_ids(self):
48
- return self.character.alts.values_list("character_id", flat=True)
49
-
50
- @property
51
- def is_old_ess(self):
52
- """
53
- Compatibility check for old ESS income calculation.
54
- Since Swagger ESI has added ESS Ref Type to the Character Journal Endpoint
55
- """
56
- try:
57
- if self.month is None and self.year is None:
58
- return False
59
- if self.year >= 2025 and self.month >= 6:
60
- return False
61
- except TypeError:
62
- return True
63
- return True
64
-
65
- def setup_ledger(self, character: CharacterAudit):
66
- """Setup the Ledger Data for the Character."""
67
-
68
- # Show Card Template for Character Ledger
69
- if self.request.GET.get("single", False):
70
- self.ledger_type = "single"
71
-
72
- # Get All Journal Entries for the Character and its Alts for Details View
73
- if self.request.GET.get("all", False):
74
- self.journal = CharacterWalletJournalEntry.objects.filter(
75
- self.filter_date,
76
- character__eve_character__character_id__in=self.alts_ids,
77
- )
78
- self.mining = CharacterMiningLedger.objects.filter(
79
- self.filter_date,
80
- character__eve_character__character_id__in=self.alts_ids,
81
- )
82
- else:
83
- # Get Journal Entries for the Character and its Alts
84
- self.journal = character.ledger_character_journal.filter(self.filter_date)
85
- self.mining = character.ledger_character_mining.filter(self.filter_date)
86
-
87
- def generate_ledger_data(self) -> dict:
88
- """Generate the ledger data for the character and its alts."""
89
- # Only show the character if 'single' is set in the request
90
- if self.request.GET.get("single", False):
91
- characters = CharacterAudit.objects.filter(
92
- eve_character__character_id=self.character.eve_character.character_id
93
- )
94
- character = characters.first()
95
- character_data = self._create_character_data(character=character)
96
- ledger = character_data
97
- else:
98
- ledger = []
99
- characters = CharacterAudit.objects.filter(
100
- eve_character__character_id__in=self.alts_ids
101
- ).select_related("eve_character")
102
- for character in characters:
103
- character_data = self._create_character_data(character=character)
104
- if character_data:
105
- ledger.append(character_data)
106
-
107
- # Generate the totals for the ledger
108
- totals = self._calculate_totals(ledger)
109
-
110
- # Evaluate the existing years for the view
111
- existing_years = (
112
- CharacterWalletJournalEntry.objects.filter(character__in=characters)
113
- .exclude(date__year__isnull=True)
114
- .values_list("date__year", flat=True)
115
- .order_by("-date__year")
116
- .distinct()
117
- )
118
-
119
- # Create the ratting bar for the view
120
- self.create_rattingbar(
121
- is_old_ess=self.is_old_ess,
122
- character_ids=characters.values_list(
123
- "eve_character__character_id", flat=True
124
- ),
125
- )
126
-
127
- context = {
128
- "title": f"Character Ledger - {self.character.eve_character.character_name}",
129
- "character_id": self.character.eve_character.character_id,
130
- "billboard": json.dumps(self.billboard.dict.asdict()),
131
- "ledger": ledger,
132
- "years": list(existing_years),
133
- "totals": totals,
134
- "view": self.create_view_data(
135
- viewname="character_details",
136
- character_id=self.character.eve_character.character_id,
137
- ),
138
- "is_old_ess": self.is_old_ess,
139
- }
140
- return context
141
-
142
- def _create_character_data(
143
- self,
144
- character: CharacterAudit,
145
- ):
146
- """Create a dictionary with character data and update billboard/ledger."""
147
- self.setup_ledger(character)
148
-
149
- # If no journal or mining data exists, return None
150
- if not self.journal.exists() and not self.mining.exists():
151
- return None
152
-
153
- bounty = self.journal.aggregate_bounty()
154
- ess = (
155
- self.journal.aggregate_bounty() * Decimal(0.667)
156
- if self.is_old_ess
157
- else self.journal.aggregate_ess()
158
- )
159
- mining_val = self.mining.aggregate_mining()
160
- costs = self.journal.aggregate_costs(second_party=self.alts_ids)
161
- miscellaneous = self.journal.aggregate_miscellaneous(first_party=self.alts_ids)
162
- total = sum(
163
- [
164
- bounty,
165
- ess,
166
- mining_val,
167
- costs,
168
- miscellaneous,
169
- ]
170
- )
171
-
172
- # If total is 0, we do not need to create a character data entry
173
- if int(total) == 0:
174
- return None
175
-
176
- update_states = {}
177
-
178
- for status in character.ledger_update_status.all():
179
- update_states[status.section] = {
180
- "is_success": status.is_success,
181
- "last_update_finished_at": status.last_update_finished_at,
182
- "last_run_finished_at": status.last_run_finished_at,
183
- }
184
-
185
- char_data = {
186
- "character": character,
187
- "ledger": {
188
- "bounty": bounty,
189
- "ess": ess,
190
- "mining": mining_val,
191
- "costs": costs,
192
- "miscellaneous": miscellaneous,
193
- "total": total,
194
- },
195
- "update_states": update_states,
196
- "single_url": self.create_url(
197
- viewname="character_ledger",
198
- character_id=character.eve_character.character_id,
199
- ),
200
- "details_url": self.create_url(
201
- viewname="character_details",
202
- character_id=character.eve_character.character_id,
203
- ),
204
- }
205
-
206
- # Create the chord data for the billboard
207
- self.billboard.chord_add_data(
208
- chord_from=character.eve_character.character_name,
209
- chord_to=_("Ratting"),
210
- value=bounty,
211
- )
212
- self.billboard.chord_add_data(
213
- chord_from=character.eve_character.character_name,
214
- chord_to=_("ESS"),
215
- value=ess,
216
- )
217
- self.billboard.chord_add_data(
218
- chord_from=character.eve_character.character_name,
219
- chord_to=_("Mining"),
220
- value=mining_val,
221
- )
222
- self.billboard.chord_add_data(
223
- chord_from=character.eve_character.character_name,
224
- chord_to=_("Miscellaneous"),
225
- value=miscellaneous,
226
- )
227
- self.billboard.chord_add_data(
228
- chord_from=character.eve_character.character_name,
229
- chord_to=_("Costs"),
230
- value=abs(costs),
231
- )
232
-
233
- return char_data
234
-
235
- def create_rattingbar(self, character_ids: list = None, is_old_ess: bool = False):
236
- """Create the ratting bar for the view."""
237
- if not character_ids:
238
- return
239
-
240
- rattingbar_timeline = self.billboard.create_timeline(
241
- CharacterWalletJournalEntry.objects.filter(
242
- self.filter_date,
243
- character__eve_character__character_id__in=character_ids,
244
- )
245
- )
246
- rattingbar = (
247
- rattingbar_timeline.annotate_bounty_income()
248
- .annotate_ess_income()
249
- .annotate_miscellaneous_with_exclude(exclude=self.alts_ids)
250
- )
251
- self.billboard.create_or_update_results(rattingbar, is_old_ess=is_old_ess)
252
- self.billboard.create_ratting_bar()
1
+ """PvE Views"""
2
+
3
+ # Standard Library
4
+ import json
5
+ from decimal import Decimal
6
+
7
+ # Django
8
+ from django.core.handlers.wsgi import WSGIRequest
9
+ from django.utils.translation import gettext as _
10
+
11
+ # Alliance Auth
12
+ from allianceauth.services.hooks import get_extension_logger
13
+
14
+ # Alliance Auth (External Libs)
15
+ from app_utils.logging import LoggerAddTag
16
+
17
+ # AA Ledger
18
+ from ledger import __title__
19
+ from ledger.helpers.core import LedgerCore
20
+ from ledger.models.characteraudit import (
21
+ CharacterAudit,
22
+ CharacterMiningLedger,
23
+ CharacterWalletJournalEntry,
24
+ )
25
+
26
+ logger = LoggerAddTag(get_extension_logger(__name__), __title__)
27
+
28
+
29
+ class CharacterData(LedgerCore):
30
+ """Class to hold character data for the ledger."""
31
+
32
+ # pylint: disable=too-many-positional-arguments
33
+ def __init__(
34
+ self,
35
+ request: WSGIRequest,
36
+ character: CharacterAudit,
37
+ year=None,
38
+ month=None,
39
+ day=None,
40
+ ):
41
+ LedgerCore.__init__(self, year, month, day)
42
+ self.request = request
43
+ self.character = character
44
+ self.alts_ids = self.get_alt_ids
45
+
46
+ @property
47
+ def get_alt_ids(self):
48
+ return self.character.alts.values_list("character_id", flat=True)
49
+
50
+ @property
51
+ def is_old_ess(self):
52
+ """
53
+ Compatibility check for old ESS income calculation.
54
+ Since Swagger ESI has added ESS Ref Type to the Character Journal Endpoint
55
+ """
56
+ try:
57
+ if self.month is None and self.year is None:
58
+ return False
59
+ if self.year >= 2025 and self.month >= 6:
60
+ return False
61
+ except TypeError:
62
+ return True
63
+ return True
64
+
65
+ def setup_ledger(self, character: CharacterAudit):
66
+ """Setup the Ledger Data for the Character."""
67
+
68
+ # Show Card Template for Character Ledger
69
+ if self.request.GET.get("single", False):
70
+ self.ledger_type = "single"
71
+
72
+ # Get All Journal Entries for the Character and its Alts for Details View
73
+ if self.request.GET.get("all", False):
74
+ self.journal = CharacterWalletJournalEntry.objects.filter(
75
+ self.filter_date,
76
+ character__eve_character__character_id__in=self.alts_ids,
77
+ )
78
+ self.mining = CharacterMiningLedger.objects.filter(
79
+ self.filter_date,
80
+ character__eve_character__character_id__in=self.alts_ids,
81
+ )
82
+ else:
83
+ # Get Journal Entries for the Character and its Alts
84
+ self.journal = character.ledger_character_journal.filter(self.filter_date)
85
+ self.mining = character.ledger_character_mining.filter(self.filter_date)
86
+
87
+ def generate_ledger_data(self) -> dict:
88
+ """Generate the ledger data for the character and its alts."""
89
+ # Only show the character if 'single' is set in the request
90
+ if self.request.GET.get("single", False):
91
+ characters = CharacterAudit.objects.filter(
92
+ eve_character__character_id=self.character.eve_character.character_id
93
+ )
94
+ character = characters.first()
95
+ character_data = self._create_character_data(character=character)
96
+ ledger = character_data
97
+ else:
98
+ ledger = []
99
+ characters = CharacterAudit.objects.filter(
100
+ eve_character__character_id__in=self.alts_ids
101
+ ).select_related("eve_character")
102
+ for character in characters:
103
+ character_data = self._create_character_data(character=character)
104
+ if character_data:
105
+ ledger.append(character_data)
106
+
107
+ # Generate the totals for the ledger
108
+ totals = self._calculate_totals(ledger)
109
+
110
+ # Evaluate the existing years for the view
111
+ existing_years = (
112
+ CharacterWalletJournalEntry.objects.filter(character__in=characters)
113
+ .exclude(date__year__isnull=True)
114
+ .values_list("date__year", flat=True)
115
+ .order_by("-date__year")
116
+ .distinct()
117
+ )
118
+
119
+ # Create the ratting bar for the view
120
+ self.create_rattingbar(
121
+ is_old_ess=self.is_old_ess,
122
+ character_ids=characters.values_list(
123
+ "eve_character__character_id", flat=True
124
+ ),
125
+ )
126
+
127
+ context = {
128
+ "title": f"Character Ledger - {self.character.eve_character.character_name}",
129
+ "character_id": self.character.eve_character.character_id,
130
+ "billboard": json.dumps(self.billboard.dict.asdict()),
131
+ "ledger": ledger,
132
+ "years": list(existing_years),
133
+ "totals": totals,
134
+ "view": self.create_view_data(
135
+ viewname="character_details",
136
+ character_id=self.character.eve_character.character_id,
137
+ ),
138
+ "is_old_ess": self.is_old_ess,
139
+ }
140
+ return context
141
+
142
+ def _create_character_data(
143
+ self,
144
+ character: CharacterAudit,
145
+ ):
146
+ """Create a dictionary with character data and update billboard/ledger."""
147
+ self.setup_ledger(character)
148
+
149
+ # If no journal or mining data exists, return None
150
+ if not self.journal.exists() and not self.mining.exists():
151
+ return None
152
+
153
+ bounty = self.journal.aggregate_bounty()
154
+ ess = (
155
+ self.journal.aggregate_bounty() * Decimal(0.667)
156
+ if self.is_old_ess
157
+ else self.journal.aggregate_ess()
158
+ )
159
+ mining_val = self.mining.aggregate_mining()
160
+ costs = self.journal.aggregate_costs(second_party=self.alts_ids)
161
+ miscellaneous = self.journal.aggregate_miscellaneous(first_party=self.alts_ids)
162
+ total = sum(
163
+ [
164
+ bounty,
165
+ ess,
166
+ costs,
167
+ miscellaneous,
168
+ ]
169
+ )
170
+
171
+ # If total is 0, we do not need to create a character data entry
172
+ if int(total) == 0:
173
+ return None
174
+
175
+ update_states = {}
176
+
177
+ for status in character.ledger_update_status.all():
178
+ update_states[status.section] = {
179
+ "is_success": status.is_success,
180
+ "last_update_finished_at": status.last_update_finished_at,
181
+ "last_run_finished_at": status.last_run_finished_at,
182
+ }
183
+
184
+ char_data = {
185
+ "character": character,
186
+ "ledger": {
187
+ "bounty": bounty,
188
+ "ess": ess,
189
+ "mining": mining_val,
190
+ "costs": costs,
191
+ "miscellaneous": miscellaneous,
192
+ "total": total,
193
+ },
194
+ "update_states": update_states,
195
+ "single_url": self.create_url(
196
+ viewname="character_ledger",
197
+ character_id=character.eve_character.character_id,
198
+ ),
199
+ "details_url": self.create_url(
200
+ viewname="character_details",
201
+ character_id=character.eve_character.character_id,
202
+ ),
203
+ }
204
+
205
+ # Create the chord data for the billboard
206
+ self.billboard.chord_add_data(
207
+ chord_from=character.eve_character.character_name,
208
+ chord_to=_("Bounty"),
209
+ value=bounty,
210
+ )
211
+ self.billboard.chord_add_data(
212
+ chord_from=character.eve_character.character_name,
213
+ chord_to=_("ESS"),
214
+ value=ess,
215
+ )
216
+ self.billboard.chord_add_data(
217
+ chord_from=character.eve_character.character_name,
218
+ chord_to=_("Mining"),
219
+ value=mining_val,
220
+ )
221
+ self.billboard.chord_add_data(
222
+ chord_from=character.eve_character.character_name,
223
+ chord_to=_("Miscellaneous"),
224
+ value=miscellaneous,
225
+ )
226
+ self.billboard.chord_add_data(
227
+ chord_from=character.eve_character.character_name,
228
+ chord_to=_("Costs"),
229
+ value=abs(costs),
230
+ )
231
+
232
+ return char_data
233
+
234
+ def create_rattingbar(self, character_ids: list = None, is_old_ess: bool = False):
235
+ """Create the ratting bar for the view."""
236
+ if not character_ids:
237
+ return
238
+
239
+ rattingbar_timeline = self.billboard.create_timeline(
240
+ CharacterWalletJournalEntry.objects.filter(
241
+ self.filter_date,
242
+ character__eve_character__character_id__in=character_ids,
243
+ )
244
+ )
245
+ rattingbar_mining_timeline = self.billboard.create_timeline(
246
+ CharacterMiningLedger.objects.filter(
247
+ self.filter_date,
248
+ character__eve_character__character_id__in=character_ids,
249
+ )
250
+ )
251
+
252
+ rattingbar = (
253
+ rattingbar_timeline.annotate_bounty_income()
254
+ .annotate_ess_income()
255
+ .annotate_miscellaneous_with_exclude(exclude=self.alts_ids)
256
+ )
257
+ rattingbar_mining = rattingbar_mining_timeline.annotate_mining(with_period=True)
258
+ self.billboard.create_or_update_results(rattingbar, is_old_ess=is_old_ess)
259
+ self.billboard.add_category(rattingbar_mining, category="mining")
260
+ self._build_xy_chart(title=_("Ratting Bar"))