This commit is contained in:
Elia Bieri 2024-09-17 15:50:53 +02:00
parent 678ea12c73
commit 6c63027834
12 changed files with 58 additions and 52 deletions

View File

@ -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<string, string> = {
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 {

View File

@ -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<Scalars['ID']['input']>;
};
export type ParticipantsForYear = {
__typename?: 'ParticipantsForYear';
_id: Scalars['ID']['output'];
participants: Array<Maybe<CourseSessionUserType>>;
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<Maybe<CostForYear>>;
cost_per_year: Array<Maybe<TrainingsResponsibleCostForYear>>;
course_session_id: Scalars['ID']['output'];
participants_per_year: Array<Maybe<ParticipantsForYear>>;
participants_per_year: Array<Maybe<TrainingsResponsibleParticipantsForYear>>;
};
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<Maybe<CourseSessionUserType>>;
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'];

View File

@ -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]!

View File

@ -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";

View File

@ -195,9 +195,9 @@ const selectedChosenProfile = ref<MenuItem>(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"]

View File

@ -83,7 +83,7 @@ export type DashboardPersonType = {
passed_count: number;
failed_count: number;
};
paid_date?: string;
paid_datetime?: string;
};
export type DashboardCourseConfigType = {

View File

@ -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])
):

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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,
),
),

View File

@ -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)