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.
Files changed (77) hide show
  1. {aa_ledger-0.9.9.dist-info → aa_ledger-0.9.9.1.dist-info}/METADATA +1 -1
  2. {aa_ledger-0.9.9.dist-info → aa_ledger-0.9.9.1.dist-info}/RECORD +77 -77
  3. ledger/__init__.py +9 -9
  4. ledger/api/api_helper/billboard_helper.py +277 -277
  5. ledger/api/ledger/admin.py +289 -289
  6. ledger/app_settings.py +50 -50
  7. ledger/constants.py +5 -0
  8. ledger/decorators.py +92 -11
  9. ledger/helpers/alliance.py +353 -334
  10. ledger/helpers/character.py +260 -260
  11. ledger/helpers/core.py +565 -565
  12. ledger/helpers/corporation.py +455 -421
  13. ledger/helpers/etag.py +237 -237
  14. ledger/helpers/ref_type.py +475 -475
  15. ledger/locale/cs_CZ/LC_MESSAGES/django.po +942 -942
  16. ledger/locale/de/LC_MESSAGES/django.po +961 -961
  17. ledger/locale/django.pot +942 -942
  18. ledger/locale/es/LC_MESSAGES/django.po +943 -943
  19. ledger/locale/fr_FR/LC_MESSAGES/django.po +942 -942
  20. ledger/locale/it_IT/LC_MESSAGES/django.po +942 -942
  21. ledger/locale/ja/LC_MESSAGES/django.po +943 -943
  22. ledger/locale/ko_KR/LC_MESSAGES/django.po +942 -942
  23. ledger/locale/nl_NL/LC_MESSAGES/django.po +942 -942
  24. ledger/locale/pl_PL/LC_MESSAGES/django.po +942 -942
  25. ledger/locale/ru/LC_MESSAGES/django.po +945 -945
  26. ledger/locale/sk/LC_MESSAGES/django.po +944 -944
  27. ledger/locale/uk/LC_MESSAGES/django.po +946 -946
  28. ledger/locale/zh_Hans/LC_MESSAGES/django.po +943 -943
  29. ledger/managers/character_mining_manager.py +239 -239
  30. ledger/managers/character_planetary_manager.py +1 -1
  31. ledger/migrations/0016_characterminingledger_price_per_unit.py +21 -21
  32. ledger/models/characteraudit.py +496 -496
  33. ledger/static/ledger/css/cards.css +1 -1
  34. ledger/static/ledger/css/table.css +1 -1
  35. ledger/static/ledger/js/charts.js +221 -221
  36. ledger/static/ledger/js/planetary.js +143 -143
  37. ledger/tasks.py +442 -449
  38. ledger/templates/ledger/allyledger/admin/alliance_administration.html +46 -46
  39. ledger/templates/ledger/allyledger/admin/alliance_overview.html +108 -108
  40. ledger/templates/ledger/allyledger/alliance_ledger.html +86 -86
  41. ledger/templates/ledger/bundles/ally-administration-bundles.html +59 -59
  42. ledger/templates/ledger/bundles/char-administration-bundles.html +66 -66
  43. ledger/templates/ledger/bundles/character-ledger-bundles.html +66 -66
  44. ledger/templates/ledger/bundles/corp-administration-bundles.html +68 -68
  45. ledger/templates/ledger/bundles/corporation-ledger-bundles.html +75 -75
  46. ledger/templates/ledger/charledger/admin/character_administration.html +39 -39
  47. ledger/templates/ledger/charledger/admin/character_overview.html +106 -106
  48. ledger/templates/ledger/charledger/character_ledger.html +94 -94
  49. ledger/templates/ledger/charledger/planetary/planetary_ledger.html +54 -54
  50. ledger/templates/ledger/corpledger/admin/corporation_administration.html +39 -39
  51. ledger/templates/ledger/corpledger/admin/corporation_overview.html +108 -108
  52. ledger/templates/ledger/corpledger/corporation_ledger.html +129 -86
  53. ledger/templates/ledger/partials/administration/alliance.html +37 -37
  54. ledger/templates/ledger/partials/administration/alliance_corporations.html +58 -58
  55. ledger/templates/ledger/partials/administration/corporation_characters.html +34 -34
  56. ledger/templates/ledger/partials/information/daily.html +56 -56
  57. ledger/templates/ledger/partials/information/day.html +48 -48
  58. ledger/templates/ledger/partials/information/hourly.html +53 -53
  59. ledger/templates/ledger/partials/information/summary.html +88 -88
  60. ledger/templates/ledger/partials/information/view_character_content.html +35 -35
  61. ledger/templates/ledger/partials/table/char-ledger.html +85 -85
  62. ledger/templates/ledger/partials/table/corp-ledger.html +66 -66
  63. ledger/templates/ledger/partials/view/card.html +160 -160
  64. ledger/tests/test_decarators.py +102 -17
  65. ledger/tests/test_helpers/test_etag.py +149 -149
  66. ledger/tests/test_managers/test_character_mining_manager.py +54 -54
  67. ledger/tests/test_models/test_characterminingledger.py +107 -106
  68. ledger/tests/test_tasks.py +282 -282
  69. ledger/tests/test_templatetags.py +5 -2
  70. ledger/tests/test_views/test_access.py +852 -852
  71. ledger/tests/testdata/esi.json +1 -2
  72. ledger/tests/testdata/eveuniverse.json +391 -391
  73. ledger/urls.py +66 -21
  74. ledger/views/alliance/alliance_ledger.py +203 -203
  75. ledger/views/corporation/corporation_ledger.py +25 -9
  76. {aa_ledger-0.9.9.dist-info → aa_ledger-0.9.9.1.dist-info}/WHEEL +0 -0
  77. {aa_ledger-0.9.9.dist-info → aa_ledger-0.9.9.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,289 +1,289 @@
1
- # Standard Library
2
- from typing import Any
3
-
4
- # Third Party
5
- from ninja import NinjaAPI
6
-
7
- # Django
8
- from django.utils.translation import gettext_lazy as _
9
-
10
- # Alliance Auth
11
- from allianceauth.authentication.models import CharacterOwnership, UserProfile
12
- from allianceauth.eveonline.models import EveCorporationInfo
13
- from allianceauth.services.hooks import get_extension_logger
14
-
15
- # Alliance Auth (External Libs)
16
- from app_utils.logging import LoggerAddTag
17
-
18
- # AA Ledger
19
- from ledger import __title__
20
- from ledger.api import schema
21
- from ledger.api.helpers import (
22
- get_all_corporations_from_alliance,
23
- get_character_or_none,
24
- get_corporation,
25
- )
26
- from ledger.models.characteraudit import CharacterAudit
27
- from ledger.models.corporationaudit import CorporationAudit
28
-
29
- logger = LoggerAddTag(get_extension_logger(__name__), __title__)
30
-
31
-
32
- class LedgerAdminApiEndpoints:
33
- tags = ["LedgerAdmin"]
34
-
35
- # pylint: disable=too-many-statements
36
- def __init__(self, api: NinjaAPI):
37
- @api.get(
38
- "character/overview/",
39
- response={200: list[schema.CharacterAdmin], 403: str},
40
- tags=self.tags,
41
- )
42
- def get_character_overview(request):
43
- chars_visible = CharacterAudit.objects.visible_to(request.user)
44
-
45
- if chars_visible is None:
46
- return 403, "Permission Denied"
47
-
48
- chars_ids = chars_visible.values_list(
49
- "eve_character__character_id", flat=True
50
- )
51
-
52
- users_char_ids = UserProfile.objects.filter(
53
- main_character__isnull=False, main_character__character_id__in=chars_ids
54
- )
55
-
56
- character_dict = {}
57
-
58
- for character in users_char_ids:
59
- # pylint: disable=broad-exception-caught
60
- try:
61
- character_dict[character.main_character.character_id] = {
62
- "character_id": character.main_character.character_id,
63
- "character_name": character.main_character.character_name,
64
- "corporation_id": character.main_character.corporation_id,
65
- "corporation_name": character.main_character.corporation_name,
66
- }
67
- except AttributeError:
68
- continue
69
-
70
- output = []
71
- output.append({"character": character_dict})
72
-
73
- return output
74
-
75
- @api.get(
76
- "planetary/overview/",
77
- response={200: list[schema.CharacterAdmin], 403: str},
78
- tags=self.tags,
79
- )
80
- def get_planetary_overview(request):
81
- chars_ids = CharacterAudit.objects.visible_eve_characters(
82
- request.user
83
- ).values_list("character_id", flat=True)
84
-
85
- users_char_ids = UserProfile.objects.filter(
86
- main_character__isnull=False, main_character__character_id__in=chars_ids
87
- )
88
-
89
- if not chars_ids:
90
- return 403, "Permission Denied"
91
-
92
- character_dict = {}
93
-
94
- for character in users_char_ids:
95
- # pylint: disable=broad-exception-caught
96
- try:
97
- character_dict[character.main_character.character_id] = {
98
- "character_id": character.main_character.character_id,
99
- "character_name": character.main_character.character_name,
100
- "corporation_id": character.main_character.corporation_id,
101
- "corporation_name": character.main_character.corporation_name,
102
- }
103
- except Exception:
104
- continue
105
-
106
- output = []
107
- output.append({"character": character_dict})
108
-
109
- return output
110
-
111
- @api.get(
112
- "corporation/overview/",
113
- response={200: list[schema.CorporationAdmin], 403: str},
114
- tags=self.tags,
115
- )
116
- def get_corporation_overview(request):
117
- corporations = CorporationAudit.objects.visible_to(request.user)
118
-
119
- if corporations is None:
120
- return 403, "Permission Denied"
121
-
122
- corporation_dict = {}
123
-
124
- for corporation in corporations:
125
- # pylint: disable=broad-exception-caught
126
- try:
127
- corporation_dict[corporation.corporation.corporation_id] = {
128
- "corporation_id": corporation.corporation.corporation_id,
129
- "corporation_name": corporation.corporation.corporation_name,
130
- }
131
- except Exception:
132
- continue
133
-
134
- output = []
135
- output.append({"corporation": corporation_dict})
136
-
137
- return output
138
-
139
- @api.get(
140
- "alliance/overview/",
141
- response={200: list[schema.AllianceAdmin], 403: str},
142
- tags=self.tags,
143
- )
144
- def get_alliance_overview(request):
145
- corporations = CorporationAudit.objects.visible_to(request.user)
146
-
147
- if corporations is None:
148
- return 403, "Permission Denied"
149
-
150
- alliance_dict = {}
151
-
152
- for corporation in corporations:
153
- # pylint: disable=broad-exception-caught
154
- try:
155
- alliance_dict[corporation.corporation.alliance.alliance_id] = {
156
- "alliance_id": corporation.corporation.alliance.alliance_id,
157
- "alliance_name": corporation.corporation.alliance.alliance_name,
158
- }
159
- except Exception:
160
- continue
161
- output = []
162
- output.append({"alliance": alliance_dict})
163
-
164
- return output
165
-
166
- @api.get(
167
- "character/{character_id}/view/dashboard/",
168
- response={200: Any, 403: str},
169
- tags=self.tags,
170
- )
171
- def get_character_dashboard(request, character_id: int):
172
- perm, character = get_character_or_none(request, character_id)
173
-
174
- if not perm:
175
- return 403, "Permission Denied"
176
- if perm is None:
177
- return 403, "Character not found"
178
-
179
- linked_characters_ids = character.alts.values_list(
180
- "character_id", flat=True
181
- )
182
-
183
- characters = CharacterAudit.objects.filter(
184
- eve_character__character_id__in=linked_characters_ids
185
- )
186
-
187
- auth_characters = len(linked_characters_ids)
188
- active_characters = characters.filter(active=True).count()
189
- inactive_characters = characters.filter(active=False).count()
190
- missing_characters = (
191
- auth_characters - active_characters - inactive_characters
192
- )
193
-
194
- status_msg = None
195
- status_issues = None
196
- issues = []
197
- for char in characters:
198
- if char.ledger_update_status.filter(is_success=False).exists():
199
- issues.append(char.eve_character.character_name)
200
-
201
- if issues:
202
- status_msg = _("Please re-register characters with issues")
203
- status_issues = ", ".join(issues)
204
-
205
- output = {
206
- "dashboard": "Character Dashboard",
207
- "status": status_msg,
208
- "status_issues": status_issues,
209
- "statistics": "Character Statistics",
210
- "auth_characters": auth_characters,
211
- "active_characters": f"{active_characters} / {auth_characters}",
212
- "inactive_characters": inactive_characters,
213
- "missing_characters": missing_characters,
214
- }
215
-
216
- return output
217
-
218
- @api.get(
219
- "corporation/{corporation_id}/view/dashboard/",
220
- response={200: Any, 403: str},
221
- tags=self.tags,
222
- )
223
- def get_corporation_dashboard(request, corporation_id: int):
224
- perm, corporation = get_corporation(request, corporation_id)
225
-
226
- if not perm:
227
- return 403, "Permission Denied"
228
- if perm is None:
229
- return 403, "Corporation not found"
230
-
231
- auth_corp = EveCorporationInfo.objects.get(
232
- corporation_id=corporation.corporation.corporation_id
233
- )
234
-
235
- corp_characters = CharacterOwnership.objects.filter(
236
- character__corporation_id=corporation_id
237
- )
238
-
239
- auth_characters = auth_corp.member_count
240
- active_characters = corp_characters.count()
241
- missing_characters = auth_characters - active_characters
242
-
243
- output = {
244
- "dashboard": "Corporation Dashboard",
245
- "status": "Missing Characters are not impleted yet",
246
- "statistics": "Corporation Statistics",
247
- "auth_characters": auth_characters,
248
- "active_characters": f"{active_characters} / {auth_characters}",
249
- "missing_characters": missing_characters,
250
- }
251
-
252
- return output
253
-
254
- @api.get(
255
- "alliance/{alliance_id}/view/dashboard/",
256
- response={200: Any, 403: str},
257
- tags=self.tags,
258
- )
259
- def get_alliance_dashboard(request, alliance_id: int):
260
- perm, corporations = get_all_corporations_from_alliance(
261
- request, alliance_id
262
- )
263
-
264
- if not perm:
265
- return 403, "Permission Denied"
266
- if perm is None:
267
- return 403, "Alliance not found."
268
-
269
- all_corporations = EveCorporationInfo.objects.filter(
270
- alliance__alliance_id=alliance_id
271
- )
272
- corp_audit_ids = corporations.values_list(
273
- "corporation__corporation_id", flat=True
274
- )
275
- missing_corporations = all_corporations.exclude(
276
- corporation_id__in=corp_audit_ids
277
- )
278
-
279
- active_corporations = corporations.count()
280
-
281
- output = {
282
- "dashboard": "Alliance Dashboard",
283
- "statistics": "Alliance Statistics",
284
- "auth_corporations": all_corporations.count(),
285
- "active_corporations": f"{active_corporations} / {all_corporations.count()}",
286
- "missing_corporations": missing_corporations.count(),
287
- }
288
-
289
- return output
1
+ # Standard Library
2
+ from typing import Any
3
+
4
+ # Third Party
5
+ from ninja import NinjaAPI
6
+
7
+ # Django
8
+ from django.utils.translation import gettext_lazy as _
9
+
10
+ # Alliance Auth
11
+ from allianceauth.authentication.models import CharacterOwnership, UserProfile
12
+ from allianceauth.eveonline.models import EveCorporationInfo
13
+ from allianceauth.services.hooks import get_extension_logger
14
+
15
+ # Alliance Auth (External Libs)
16
+ from app_utils.logging import LoggerAddTag
17
+
18
+ # AA Ledger
19
+ from ledger import __title__
20
+ from ledger.api import schema
21
+ from ledger.api.helpers import (
22
+ get_all_corporations_from_alliance,
23
+ get_character_or_none,
24
+ get_corporation,
25
+ )
26
+ from ledger.models.characteraudit import CharacterAudit
27
+ from ledger.models.corporationaudit import CorporationAudit
28
+
29
+ logger = LoggerAddTag(get_extension_logger(__name__), __title__)
30
+
31
+
32
+ class LedgerAdminApiEndpoints:
33
+ tags = ["LedgerAdmin"]
34
+
35
+ # pylint: disable=too-many-statements
36
+ def __init__(self, api: NinjaAPI):
37
+ @api.get(
38
+ "character/overview/",
39
+ response={200: list[schema.CharacterAdmin], 403: str},
40
+ tags=self.tags,
41
+ )
42
+ def get_character_overview(request):
43
+ chars_visible = CharacterAudit.objects.visible_to(request.user)
44
+
45
+ if chars_visible is None:
46
+ return 403, "Permission Denied"
47
+
48
+ chars_ids = chars_visible.values_list(
49
+ "eve_character__character_id", flat=True
50
+ )
51
+
52
+ users_char_ids = UserProfile.objects.filter(
53
+ main_character__isnull=False, main_character__character_id__in=chars_ids
54
+ )
55
+
56
+ character_dict = {}
57
+
58
+ for character in users_char_ids:
59
+ # pylint: disable=broad-exception-caught
60
+ try:
61
+ character_dict[character.main_character.character_id] = {
62
+ "character_id": character.main_character.character_id,
63
+ "character_name": character.main_character.character_name,
64
+ "corporation_id": character.main_character.corporation_id,
65
+ "corporation_name": character.main_character.corporation_name,
66
+ }
67
+ except AttributeError:
68
+ continue
69
+
70
+ output = []
71
+ output.append({"character": character_dict})
72
+
73
+ return output
74
+
75
+ @api.get(
76
+ "planetary/overview/",
77
+ response={200: list[schema.CharacterAdmin], 403: str},
78
+ tags=self.tags,
79
+ )
80
+ def get_planetary_overview(request):
81
+ chars_ids = CharacterAudit.objects.visible_eve_characters(
82
+ request.user
83
+ ).values_list("character_id", flat=True)
84
+
85
+ users_char_ids = UserProfile.objects.filter(
86
+ main_character__isnull=False, main_character__character_id__in=chars_ids
87
+ )
88
+
89
+ if not chars_ids:
90
+ return 403, "Permission Denied"
91
+
92
+ character_dict = {}
93
+
94
+ for character in users_char_ids:
95
+ # pylint: disable=broad-exception-caught
96
+ try:
97
+ character_dict[character.main_character.character_id] = {
98
+ "character_id": character.main_character.character_id,
99
+ "character_name": character.main_character.character_name,
100
+ "corporation_id": character.main_character.corporation_id,
101
+ "corporation_name": character.main_character.corporation_name,
102
+ }
103
+ except Exception:
104
+ continue
105
+
106
+ output = []
107
+ output.append({"character": character_dict})
108
+
109
+ return output
110
+
111
+ @api.get(
112
+ "corporation/overview/",
113
+ response={200: list[schema.CorporationAdmin], 403: str},
114
+ tags=self.tags,
115
+ )
116
+ def get_corporation_overview(request):
117
+ corporations = CorporationAudit.objects.visible_to(request.user)
118
+
119
+ if corporations is None:
120
+ return 403, "Permission Denied"
121
+
122
+ corporation_dict = {}
123
+
124
+ for corporation in corporations:
125
+ # pylint: disable=broad-exception-caught
126
+ try:
127
+ corporation_dict[corporation.corporation.corporation_id] = {
128
+ "corporation_id": corporation.corporation.corporation_id,
129
+ "corporation_name": corporation.corporation.corporation_name,
130
+ }
131
+ except Exception:
132
+ continue
133
+
134
+ output = []
135
+ output.append({"corporation": corporation_dict})
136
+
137
+ return output
138
+
139
+ @api.get(
140
+ "alliance/overview/",
141
+ response={200: list[schema.AllianceAdmin], 403: str},
142
+ tags=self.tags,
143
+ )
144
+ def get_alliance_overview(request):
145
+ corporations = CorporationAudit.objects.visible_to(request.user)
146
+
147
+ if corporations is None:
148
+ return 403, "Permission Denied"
149
+
150
+ alliance_dict = {}
151
+
152
+ for corporation in corporations:
153
+ # pylint: disable=broad-exception-caught
154
+ try:
155
+ alliance_dict[corporation.corporation.alliance.alliance_id] = {
156
+ "alliance_id": corporation.corporation.alliance.alliance_id,
157
+ "alliance_name": corporation.corporation.alliance.alliance_name,
158
+ }
159
+ except Exception:
160
+ continue
161
+ output = []
162
+ output.append({"alliance": alliance_dict})
163
+
164
+ return output
165
+
166
+ @api.get(
167
+ "character/{character_id}/view/dashboard/",
168
+ response={200: Any, 403: str},
169
+ tags=self.tags,
170
+ )
171
+ def get_character_dashboard(request, character_id: int):
172
+ perm, character = get_character_or_none(request, character_id)
173
+
174
+ if not perm:
175
+ return 403, "Permission Denied"
176
+ if perm is None:
177
+ return 403, "Character not found"
178
+
179
+ linked_characters_ids = character.alts.values_list(
180
+ "character_id", flat=True
181
+ )
182
+
183
+ characters = CharacterAudit.objects.filter(
184
+ eve_character__character_id__in=linked_characters_ids
185
+ )
186
+
187
+ auth_characters = len(linked_characters_ids)
188
+ active_characters = characters.filter(active=True).count()
189
+ inactive_characters = characters.filter(active=False).count()
190
+ missing_characters = (
191
+ auth_characters - active_characters - inactive_characters
192
+ )
193
+
194
+ status_msg = None
195
+ status_issues = None
196
+ issues = []
197
+ for char in characters:
198
+ if char.ledger_update_status.filter(is_success=False).exists():
199
+ issues.append(char.eve_character.character_name)
200
+
201
+ if issues:
202
+ status_msg = _("Please re-register characters with issues")
203
+ status_issues = ", ".join(issues)
204
+
205
+ output = {
206
+ "dashboard": "Character Dashboard",
207
+ "status": status_msg,
208
+ "status_issues": status_issues,
209
+ "statistics": "Character Statistics",
210
+ "auth_characters": auth_characters,
211
+ "active_characters": f"{active_characters} / {auth_characters}",
212
+ "inactive_characters": inactive_characters,
213
+ "missing_characters": missing_characters,
214
+ }
215
+
216
+ return output
217
+
218
+ @api.get(
219
+ "corporation/{corporation_id}/view/dashboard/",
220
+ response={200: Any, 403: str},
221
+ tags=self.tags,
222
+ )
223
+ def get_corporation_dashboard(request, corporation_id: int):
224
+ perm, corporation = get_corporation(request, corporation_id)
225
+
226
+ if not perm:
227
+ return 403, "Permission Denied"
228
+ if perm is None:
229
+ return 403, "Corporation not found"
230
+
231
+ auth_corp = EveCorporationInfo.objects.get(
232
+ corporation_id=corporation.corporation.corporation_id
233
+ )
234
+
235
+ corp_characters = CharacterOwnership.objects.filter(
236
+ character__corporation_id=corporation_id
237
+ )
238
+
239
+ auth_characters = auth_corp.member_count
240
+ active_characters = corp_characters.count()
241
+ missing_characters = auth_characters - active_characters
242
+
243
+ output = {
244
+ "dashboard": "Corporation Dashboard",
245
+ "status": "Missing Characters are not impleted yet",
246
+ "statistics": "Corporation Statistics",
247
+ "auth_characters": auth_characters,
248
+ "active_characters": f"{active_characters} / {auth_characters}",
249
+ "missing_characters": missing_characters,
250
+ }
251
+
252
+ return output
253
+
254
+ @api.get(
255
+ "alliance/{alliance_id}/view/dashboard/",
256
+ response={200: Any, 403: str},
257
+ tags=self.tags,
258
+ )
259
+ def get_alliance_dashboard(request, alliance_id: int):
260
+ perm, corporations = get_all_corporations_from_alliance(
261
+ request, alliance_id
262
+ )
263
+
264
+ if not perm:
265
+ return 403, "Permission Denied"
266
+ if perm is None:
267
+ return 403, "Alliance not found."
268
+
269
+ all_corporations = EveCorporationInfo.objects.filter(
270
+ alliance__alliance_id=alliance_id
271
+ )
272
+ corp_audit_ids = corporations.values_list(
273
+ "corporation__corporation_id", flat=True
274
+ )
275
+ missing_corporations = all_corporations.exclude(
276
+ corporation_id__in=corp_audit_ids
277
+ )
278
+
279
+ active_corporations = corporations.count()
280
+
281
+ output = {
282
+ "dashboard": "Alliance Dashboard",
283
+ "statistics": "Alliance Statistics",
284
+ "auth_corporations": all_corporations.count(),
285
+ "active_corporations": f"{active_corporations} / {all_corporations.count()}",
286
+ "missing_corporations": missing_corporations.count(),
287
+ }
288
+
289
+ return output