Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions backend/analytics/api/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,14 @@ class Meta:

def get_status(self, obj) -> str:
return 'success'


class AnalyticsMarketInsightSerializer(serializers.Serializer):
data = serializers.ListField(
child=serializers.ListField(
child=serializers.CharField(),
min_length=1,
max_length=3,
help_text='Indices: 0: ticker, 1: production, 2: consumption, 3: delta',
)
)
18 changes: 15 additions & 3 deletions backend/analytics/api/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from datetime import timedelta

from analytics.api.serializer import AnalyticsPlanAggregateSerializer
from analytics.api.serializer import AnalyticsMarketInsightSerializer, AnalyticsPlanAggregateSerializer
from analytics.models import AnalyticsEmpireMaterialSnapshot, AnalyticsPlanAggregate
from analytics.services.analytics_cache_manager import AnalyticsCacheManager
from django.db.models import Sum
from django.http import Http404
from django.utils import timezone
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import OpenApiExample, extend_schema
from gamedata.models.game_planet import GamePlanet
from rest_framework import viewsets
from rest_framework.decorators import action
Expand Down Expand Up @@ -45,7 +45,19 @@ def fetch_data(planet_natural_id: str):


class AnalyticsMarketInsightViewSet(viewsets.ViewSet):
@extend_schema(auth=[], summary='Fetch planning insights for materials')
@extend_schema(
auth=[],
summary='Fetch planning insights for materials',
responses={200: AnalyticsMarketInsightSerializer},
examples=[
OpenApiExample(
'Material Insights Example',
summary='Example for positional array response',
value=[['AAR', 30.3584, 12.8593, 17.4991], ['ABH', 120.7919, 0.0, 120.7919]],
response_only=True,
)
],
)
@action(detail=False, methods=['get'], url_path='get-global-tracker')
def get_global_materials(self, request):

Expand Down
59 changes: 59 additions & 0 deletions backend/gamedata/api/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
from gamedata.models import (
GameBuilding,
GameBuildingCost,
GameBuildingExpertiseChoices,
GameExchangeAnalytics,
GameExchangeCXPC,
GameMaterial,
GamePlanet,
GamePlanetCOGCProgram,
GamePlanetCOGCProgramChoices,
GamePlanetCurrencyCodeChoices,
GamePlanetInfrastructureReport,
GamePlanetResource,
GameRecipe,
Expand All @@ -17,6 +19,9 @@
)
from rest_framework import serializers

WORKFORCE_ORDER = ['PIONEER', 'SETTLER', 'TECHNICIAN', 'ENGINEER', 'SCIENTIST']
WF_INDEX_MAP = {level: i for i, level in enumerate(WORKFORCE_ORDER)}


class GameMaterialSerializer(serializers.ModelSerializer):
class Meta:
Expand Down Expand Up @@ -46,6 +51,11 @@ class Meta:
model = GameRecipe
exclude = ['standard_recipe_name']

@extend_schema_field(
serializers.CharField(
help_text="Composite ID formatted as 'BUILDING_TICKER#RECIPE_NAME'. Example: 'BMP#100xPE 25xPG=>20xOVE'"
)
)
def get_recipe_id(self, obj: GameRecipe):
return f'{obj.building_ticker}#{obj.recipe_name}'

Expand Down Expand Up @@ -100,6 +110,8 @@ class GamePlanetSerializer(serializers.ModelSerializer):

active_cogc_program_type = serializers.CharField(read_only=True)

production_fees = serializers.SerializerMethodField()

class Meta:
model = GamePlanet
fields = [
Expand All @@ -123,8 +135,55 @@ class Meta:
'resources',
'cogc_programs',
'active_cogc_program_type',
'production_fees',
]

@extend_schema_field(
inline_serializer(
name='PlanetProductionFeeSchema',
fields={
'currency': serializers.ChoiceField(choices=GamePlanetCurrencyCodeChoices.choices),
'fees': serializers.DictField(
child=serializers.ListField(
child=serializers.FloatField(),
min_length=5,
max_length=5,
help_text='[PIONEER, SETTLER, TECHNICIAN, ENGINEER, SCIENTIST]',
),
help_text=(
'Dictionary keys are Building Categories (GameBuildingExpertiseChoices). '
'Valid keys include: '
+ ', '.join([choice[0] for choice in GameBuildingExpertiseChoices.choices])
),
),
},
)
)
def get_production_fees(self, obj):

# prefetched
fees = obj.production_fees.all()
if not fees:
return None

currency = fees[0].fee_currency

fee_map = {}
for fee in fees:
cat = fee.category
if cat not in fee_map:
# init with 0.0 for all workforces
fee_map[cat] = [0.0] * len(WORKFORCE_ORDER)

try:
# overwrite with the values from data
idx = WF_INDEX_MAP[fee.workforce_level]
fee_map[cat][idx] = fee.fee_amount
except KeyError:
continue

return {'currency': currency, 'fees': fee_map}


class PlanetIdsSerializer(serializers.ListSerializer):
child = serializers.CharField(min_length=7, max_length=7)
Expand Down
3 changes: 2 additions & 1 deletion backend/gamedata/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .game_building import GameBuilding, GameBuildingCost
from .game_building import GameBuilding, GameBuildingCost, GameBuildingExpertiseChoices
from .game_exchange import GameExchange, GameExchangeAnalytics, GameExchangeCXPC
from .game_material import GameMaterial
from .game_planet import (
Expand All @@ -11,6 +11,7 @@
GamePlanetProductionFee,
GamePlanetResource,
GamePlanetResourceTypeChoices,
GamePlanetCurrencyCodeChoices,
queryset_gameplanet,
)
from .game_playerdata import GameFIOPlayerData
Expand Down
2 changes: 1 addition & 1 deletion backend/gamedata/models/game_planet.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def queryset_gameplanet() -> QuerySet:
.values('program_type')[:1]
)

return GamePlanet.objects.prefetch_related('cogc_programs', 'resources').annotate(
return GamePlanet.objects.prefetch_related('cogc_programs', 'resources', 'production_fees').annotate(
active_cogc_program_type=Subquery(active_program_sub)
)

Expand Down
Loading