From 6c630278348554e0dd9296ae8a01e8129e9adc3c Mon Sep 17 00:00:00 2001 From: Elia Bieri Date: Tue, 17 Sep 2024 15:50:53 +0200 Subject: [PATCH] Rework --- .../src/components/dashboard/composables.ts | 9 ++--- client/src/gql/graphql.ts | 34 +++++++++---------- client/src/gql/schema.graphql | 8 ++--- client/src/gql/typenames.ts | 4 +-- .../pages/dashboard/DashboardPersonsPage.vue | 6 ++-- client/src/services/dashboard.ts | 2 +- scripts/create_berufsbildner_mobi.py | 8 ++--- server/vbv_lernwelt/course/models.py | 8 +++-- .../dashboard/graphql/types/dashboard.py | 21 ++++++------ server/vbv_lernwelt/dashboard/utils.py | 4 ++- .../0020_alter_checkoutinformation_user.py | 4 +-- server/vbv_lernwelt/shop/models.py | 2 +- 12 files changed, 58 insertions(+), 52 deletions(-) diff --git a/client/src/components/dashboard/composables.ts b/client/src/components/dashboard/composables.ts index be16fff2..a1559b5f 100644 --- a/client/src/components/dashboard/composables.ts +++ b/client/src/components/dashboard/composables.ts @@ -1,3 +1,4 @@ +import colors from "@/colors.json"; import { useTranslation } from "i18next-vue"; export function useChosenProfileMapping() { @@ -11,10 +12,10 @@ export function useChosenProfileMapping() { }; const CHOSEN_PROFILE_TO_COLOR: Record = { - all: "#558AED", - leben: "#FE955A", - nichtleben: "#54CE8B", - krankenzusatzversicherung: "#FAC852", + all: colors.blue[500], + leben: colors.orange[500], + nichtleben: colors.green[500], + krankenzusatzversicherung: colors.yellow[400], }; return { diff --git a/client/src/gql/graphql.ts b/client/src/gql/graphql.ts index 0783825d..c3578130 100644 --- a/client/src/gql/graphql.ts +++ b/client/src/gql/graphql.ts @@ -359,13 +359,6 @@ export type CoreUserLanguageChoices = /** Italiano */ | 'IT'; -export type CostForYear = { - __typename?: 'CostForYear'; - _id: Scalars['ID']['output']; - total_cost: Scalars['Int']['output']; - year: Scalars['Int']['output']; -}; - export type CourseConfigurationObjectType = { __typename?: 'CourseConfigurationObjectType'; enable_circle_documents: Scalars['Boolean']['output']; @@ -929,13 +922,6 @@ export type MutationUpsertAssignmentCompletionArgs = { learning_content_page_id?: InputMaybe; }; -export type ParticipantsForYear = { - __typename?: 'ParticipantsForYear'; - _id: Scalars['ID']['output']; - participants: Array>; - year: Scalars['Int']['output']; -}; - export type PerformanceCriteriaObjectType = CoursePageInterface & { __typename?: 'PerformanceCriteriaObjectType'; competence_id: Scalars['String']['output']; @@ -1136,9 +1122,23 @@ export type TopicObjectType = CoursePageInterface & { export type TrainingResponsibleStatisticsType = { __typename?: 'TrainingResponsibleStatisticsType'; _id: Scalars['ID']['output']; - cost_per_year: Array>; + cost_per_year: Array>; course_session_id: Scalars['ID']['output']; - participants_per_year: Array>; + participants_per_year: Array>; +}; + +export type TrainingsResponsibleCostForYear = { + __typename?: 'TrainingsResponsibleCostForYear'; + _id: Scalars['ID']['output']; + total_cost: Scalars['Int']['output']; + year: Scalars['Int']['output']; +}; + +export type TrainingsResponsibleParticipantsForYear = { + __typename?: 'TrainingsResponsibleParticipantsForYear'; + _id: Scalars['ID']['output']; + participants: Array>; + year: Scalars['Int']['output']; }; export type UpdateCourseProfileError = { @@ -1489,7 +1489,7 @@ export type TrainingResponsibleStatisticsQueryVariables = Exact<{ }>; -export type TrainingResponsibleStatisticsQuery = { __typename?: 'Query', training_responsible_statistics?: { __typename?: 'TrainingResponsibleStatisticsType', _id: string, cost_per_year: Array<{ __typename?: 'CostForYear', _id: string, year: number, total_cost: number } | null>, participants_per_year: Array<{ __typename?: 'ParticipantsForYear', _id: string, year: number, participants: Array<{ __typename?: 'CourseSessionUserType', id: string, chosen_profile: string } | null> } | null> } | null }; +export type TrainingResponsibleStatisticsQuery = { __typename?: 'Query', training_responsible_statistics?: { __typename?: 'TrainingResponsibleStatisticsType', _id: string, cost_per_year: Array<{ __typename?: 'TrainingsResponsibleCostForYear', _id: string, year: number, total_cost: number } | null>, participants_per_year: Array<{ __typename?: 'TrainingsResponsibleParticipantsForYear', _id: string, year: number, participants: Array<{ __typename?: 'CourseSessionUserType', id: string, chosen_profile: string } | null> } | null> } | null }; export type SendFeedbackMutationMutationVariables = Exact<{ courseSessionId: Scalars['ID']['input']; diff --git a/client/src/gql/schema.graphql b/client/src/gql/schema.graphql index a68ce255..49bdd135 100644 --- a/client/src/gql/schema.graphql +++ b/client/src/gql/schema.graphql @@ -204,17 +204,17 @@ type BaseStatisticsType { type TrainingResponsibleStatisticsType { _id: ID! course_session_id: ID! - cost_per_year: [CostForYear]! - participants_per_year: [ParticipantsForYear]! + cost_per_year: [TrainingsResponsibleCostForYear]! + participants_per_year: [TrainingsResponsibleParticipantsForYear]! } -type CostForYear { +type TrainingsResponsibleCostForYear { _id: ID! year: Int! total_cost: Int! } -type ParticipantsForYear { +type TrainingsResponsibleParticipantsForYear { _id: ID! year: Int! participants: [CourseSessionUserType]! diff --git a/client/src/gql/typenames.ts b/client/src/gql/typenames.ts index b601f647..382132b8 100644 --- a/client/src/gql/typenames.ts +++ b/client/src/gql/typenames.ts @@ -26,7 +26,6 @@ export const CompetenceRecordStatisticsType = "CompetenceRecordStatisticsType"; export const CompetencesStatisticsType = "CompetencesStatisticsType"; export const ContentDocumentObjectType = "ContentDocumentObjectType"; export const CoreUserLanguageChoices = "CoreUserLanguageChoices"; -export const CostForYear = "CostForYear"; export const CourseConfigurationObjectType = "CourseConfigurationObjectType"; export const CourseObjectType = "CourseObjectType"; export const CoursePageInterface = "CoursePageInterface"; @@ -75,7 +74,6 @@ export const LearningSequenceObjectType = "LearningSequenceObjectType"; export const LearningUnitObjectType = "LearningUnitObjectType"; export const LearnpathLearningContentAssignmentAssignmentTypeChoices = "LearnpathLearningContentAssignmentAssignmentTypeChoices"; export const Mutation = "Mutation"; -export const ParticipantsForYear = "ParticipantsForYear"; export const PerformanceCriteriaObjectType = "PerformanceCriteriaObjectType"; export const PresenceRecordStatisticsType = "PresenceRecordStatisticsType"; export const ProgressDashboardAssignmentType = "ProgressDashboardAssignmentType"; @@ -89,6 +87,8 @@ export const StatisticsCourseSessionsSelectionMetricType = "StatisticsCourseSess export const String = "String"; export const TopicObjectType = "TopicObjectType"; export const TrainingResponsibleStatisticsType = "TrainingResponsibleStatisticsType"; +export const TrainingsResponsibleCostForYear = "TrainingsResponsibleCostForYear"; +export const TrainingsResponsibleParticipantsForYear = "TrainingsResponsibleParticipantsForYear"; export const UUID = "UUID"; export const UpdateCourseProfileError = "UpdateCourseProfileError"; export const UpdateCourseProfileResult = "UpdateCourseProfileResult"; diff --git a/client/src/pages/dashboard/DashboardPersonsPage.vue b/client/src/pages/dashboard/DashboardPersonsPage.vue index fa811e02..ed6a0b90 100644 --- a/client/src/pages/dashboard/DashboardPersonsPage.vue +++ b/client/src/pages/dashboard/DashboardPersonsPage.vue @@ -195,9 +195,9 @@ const selectedChosenProfile = ref(chosenProfiles.value[0]); const paidYears = computed(() => { const values = _(dashboardPersons.value) - .filter((cs) => dayjs(cs.paid_date).isValid()) + .filter((cs) => dayjs(cs.paid_datetime).isValid()) .map((cs) => { - const paidYear = dayjs(cs.paid_date).format("YYYY"); + const paidYear = dayjs(cs.paid_datetime).format("YYYY"); return Object.assign({}, cs, { name: paidYear, id: paidYear, @@ -268,7 +268,7 @@ const filteredPersons = computed(() => { if (selectedPaidYear.value.id === UNFILTERED) { return true; } - const paidYear = dayjs(person.paid_date).format("YYYY"); + const paidYear = dayjs(person.paid_datetime).format("YYYY"); return paidYear == selectedPaidYear.value.id; }), ["last_name", "first_name"] diff --git a/client/src/services/dashboard.ts b/client/src/services/dashboard.ts index 91b9de35..31984192 100644 --- a/client/src/services/dashboard.ts +++ b/client/src/services/dashboard.ts @@ -83,7 +83,7 @@ export type DashboardPersonType = { passed_count: number; failed_count: number; }; - paid_date?: string; + paid_datetime?: string; }; export type DashboardCourseConfigType = { diff --git a/scripts/create_berufsbildner_mobi.py b/scripts/create_berufsbildner_mobi.py index f92d193d..85eaeccd 100644 --- a/scripts/create_berufsbildner_mobi.py +++ b/scripts/create_berufsbildner_mobi.py @@ -22,17 +22,17 @@ def main(): berufsbildner, _ = User.objects.get_or_create( id="5f984be9-3024-4169-9c7b-c9e827c18fd8" ) - berufsbildner.username = "training-responsible-mobi@example.com" - berufsbildner.email = "training-responsible-mobi@example.com" + berufsbildner.username = "berufsbildner-mobi@example.com" + berufsbildner.email = "berufsbildner-mobi@example.com" berufsbildner.language = "de" - berufsbildner.first_name = "Ausbildungsverantwortlicher" + berufsbildner.first_name = "Berufsbildner" berufsbildner.last_name = "Mobi" berufsbildner.password = make_password("test") berufsbildner.save() for csu in ( CourseSessionUser.objects.filter(user__username__contains="@mobi") - .filter(course_session__course__configuration__is_uk=False) + .filter(course_session__course__configuration__is_uk=True) .filter(role=CourseSessionUser.Role.MEMBER.value) .exclude(course_session_id__in=[4, 5, 6]) ): diff --git a/server/vbv_lernwelt/course/models.py b/server/vbv_lernwelt/course/models.py index 9fc55d3a..8493de6f 100644 --- a/server/vbv_lernwelt/course/models.py +++ b/server/vbv_lernwelt/course/models.py @@ -304,11 +304,13 @@ class CourseSessionUser(models.Model): ordering = ["user__last_name", "user__first_name", "user__email"] @property - def paid_date(self) -> datetime | None: + def paid_datetime(self) -> datetime | None: """ - Returns the date when the user paid for the course session + Returns the datetime when the user paid for the course session """ - checkout = self.user.checkout_information.filter(state=CheckoutState.PAID) + checkout = self.user.checkout_informations.filter( + state=CheckoutState.PAID + ).order_by("created_at") if checkout: return checkout.first().created_at return None diff --git a/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py b/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py index 645773df..50eedff1 100644 --- a/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py +++ b/server/vbv_lernwelt/dashboard/graphql/types/dashboard.py @@ -256,14 +256,14 @@ class CourseStatisticsType(BaseStatisticsType): ) -class CostForYear(graphene.ObjectType): +class TrainingsResponsibleCostForYear(graphene.ObjectType): _id = graphene.ID(required=True) year = graphene.Int(required=True) # In centimes CHF total_cost = graphene.Int(required=True) -class ParticipantsForYear(graphene.ObjectType): +class TrainingsResponsibleParticipantsForYear(graphene.ObjectType): _id = graphene.ID(required=True) year = graphene.Int(required=True) participants = graphene.List(CourseSessionUserType, required=True) @@ -273,8 +273,10 @@ class TrainingResponsibleStatisticsType(graphene.ObjectType): _id = graphene.ID(required=True) course_session_id = graphene.ID(required=True) - cost_per_year = graphene.List(CostForYear, required=True) - participants_per_year = graphene.List(ParticipantsForYear, required=True) + cost_per_year = graphene.List(TrainingsResponsibleCostForYear, required=True) + participants_per_year = graphene.List( + TrainingsResponsibleParticipantsForYear, required=True + ) @staticmethod def resolve_cost_per_year(root, info): # noqa @@ -297,7 +299,7 @@ class TrainingResponsibleStatisticsType(graphene.ObjectType): key=lambda x: x.created_at.year, ) return [ - CostForYear( + TrainingsResponsibleCostForYear( _id=f"{root.course_session_id} {year}", year=year, total_cost=sum(c.product_price for c in checkouts), @@ -314,17 +316,16 @@ class TrainingResponsibleStatisticsType(graphene.ObjectType): agentparticipantrelation__participant__course_session=root.course_session_id, ) .annotate( - checkout_year=ExtractYear("user__checkout_information__created_at") + checkout_year=ExtractYear("user__checkout_informations__created_at") ) .select_related("user") ) grouped_course_session_users = defaultdict(list) for csu in course_session_users: - checkout_year = csu.checkout_year - if checkout_year: - grouped_course_session_users[checkout_year].append(csu) + if csu.checkout_year: + grouped_course_session_users[csu.checkout_year].append(csu) return [ - ParticipantsForYear( + TrainingsResponsibleParticipantsForYear( _id=f"{root.course_session_id} {year}", year=year, participants=participants, diff --git a/server/vbv_lernwelt/dashboard/utils.py b/server/vbv_lernwelt/dashboard/utils.py index 8c5e2ffd..90e09754 100644 --- a/server/vbv_lernwelt/dashboard/utils.py +++ b/server/vbv_lernwelt/dashboard/utils.py @@ -109,7 +109,9 @@ def create_person_list_with_roles( "avatar_url": user_object.avatar_url, "course_sessions": [], "chosen_profile": csu.chosen_profile.code if csu.chosen_profile else "all", - "paid_date": csu.paid_date.isoformat() if csu.paid_date else None, + "paid_datetime": csu.paid_datetime.isoformat() + if csu.paid_datetime + else None, } if include_private_data: user_data["phone_number"] = user_object.phone_number diff --git a/server/vbv_lernwelt/shop/migrations/0020_alter_checkoutinformation_user.py b/server/vbv_lernwelt/shop/migrations/0020_alter_checkoutinformation_user.py index ff270db8..5673e3ca 100644 --- a/server/vbv_lernwelt/shop/migrations/0020_alter_checkoutinformation_user.py +++ b/server/vbv_lernwelt/shop/migrations/0020_alter_checkoutinformation_user.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.13 on 2024-09-12 13:40 +# Generated by Django 4.2.13 on 2024-09-17 14:00 import django.db.models.deletion from django.conf import settings @@ -17,7 +17,7 @@ class Migration(migrations.Migration): name="user", field=models.ForeignKey( on_delete=django.db.models.deletion.PROTECT, - related_name="checkout_information", + related_name="checkout_informations", to=settings.AUTH_USER_MODEL, ), ), diff --git a/server/vbv_lernwelt/shop/models.py b/server/vbv_lernwelt/shop/models.py index e6db05ff..b13a1e3d 100644 --- a/server/vbv_lernwelt/shop/models.py +++ b/server/vbv_lernwelt/shop/models.py @@ -44,7 +44,7 @@ class CheckoutInformation(models.Model): ) user = models.ForeignKey( - "core.User", on_delete=models.PROTECT, related_name="checkout_information" + "core.User", on_delete=models.PROTECT, related_name="checkout_informations" ) product_sku = models.CharField(max_length=255)