package application import ( "context" "encoding/json" "fmt" "sort" "strconv" "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/sorting" agenda "git.coopgo.io/coopgo-platform/agenda/grpcapi" agendastorage "git.coopgo.io/coopgo-platform/agenda/storage" fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi" fleetsstorage "git.coopgo.io/coopgo-platform/fleets/storage" groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" groupsstorage "git.coopgo.io/coopgo-platform/groups-management/storage" accounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" accountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage" "github.com/xuri/excelize/v2" ) type FlatMaps []map[string]any func (maps FlatMaps) GetHeaders() (res []string) { keys := map[string]bool{} for _, m := range maps { for k, _ := range m { if _, ok := keys[k]; !ok { keys[k] = true res = append(res, k) } } } sort.Strings(res) return } func (maps FlatMaps) GetValues() (res [][]string) { headers := maps.GetHeaders() for _, m := range maps { line := []string{} for _, k := range headers { if v, ok := m[k]; ok && v != nil { line = append(line, fmt.Sprint(v)) } else { line = append(line, "") } } res = append(res, line) } return } type ExportCacheResult struct { Headers []string Values [][]string } func (h *ApplicationHandler) ExportCacheAsCSV(cacheID string) (*ExportCacheResult, error) { d, err := h.cache.Get(cacheID) if err != nil { return nil, err } var data []any if dataSlice, ok := d.([]any); ok { data = dataSlice } else { // Convert single item to slice jsonData, err := json.Marshal(d) if err != nil { return nil, err } if err := json.Unmarshal(jsonData, &data); err != nil { return nil, err } } flatmaps := FlatMaps{} for _, v := range data { if vMap, ok := v.(map[string]any); ok { fm := map[string]any{} flatten("", vMap, fm) flatmaps = append(flatmaps, fm) } } return &ExportCacheResult{ Headers: flatmaps.GetHeaders(), Values: flatmaps.GetValues(), }, nil } func flatten(prefix string, src map[string]any, dest map[string]any) { if len(prefix) > 0 { prefix += "." } for k, v := range src { switch child := v.(type) { case map[string]any: flatten(prefix+k, child, dest) case []any: for i := 0; i < len(child); i++ { dest[prefix+k+"."+strconv.Itoa(i)] = child[i] } default: dest[prefix+k] = v } } } type AgendaExportResult struct { ExcelFile *excelize.File } func (h *ApplicationHandler) ExportAllAgendaEvents() (*AgendaExportResult, error) { resp, err := h.services.GRPC.Agenda.GetEvents(context.TODO(), &agenda.GetEventsRequest{ Namespaces: []string{"parcoursmob_dispositifs"}, }) if err != nil { return nil, err } events := []agendastorage.Event{} groupids := []string{} beneficiaries_ids := []string{} for _, e := range resp.Events { groupids = append(groupids, e.Owners...) events = append(events, e.ToStorageType()) for _, subscriptions := range e.Subscriptions { beneficiaries_ids = append(beneficiaries_ids, subscriptions.Subscriber) } } sort.Sort(sorting.EventsByStartdate(events)) groups, beneficiaries_map, err := h.getAgendaMetadata(groupids, beneficiaries_ids) if err != nil { return nil, err } file := h.generateAgendaExcel(events, groups, beneficiaries_map) return &AgendaExportResult{ExcelFile: file}, nil } func (h *ApplicationHandler) ExportSingleAgendaEvent(eventID string) (*AgendaExportResult, error) { resp, err := h.services.GRPC.Agenda.GetEvent(context.TODO(), &agenda.GetEventRequest{ Id: eventID, }) if err != nil { return nil, err } groupids := []string{} beneficiaries_ids := []string{} groupids = append(groupids, resp.Event.Owners...) for _, subscriptions := range resp.Event.Subscriptions { beneficiaries_ids = append(beneficiaries_ids, subscriptions.Subscriber) } groups, beneficiaries_map, err := h.getAgendaMetadata(groupids, beneficiaries_ids) if err != nil { return nil, err } events := []agendastorage.Event{resp.Event.ToStorageType()} file := h.generateAgendaExcel(events, groups, beneficiaries_map) return &AgendaExportResult{ExcelFile: file}, nil } func (h *ApplicationHandler) getAgendaMetadata(groupids, beneficiaries_ids []string) (map[string]groupsstorage.Group, map[string]accountsstorage.Account, error) { groupsresp, err := h.services.GRPC.GroupsManagement.GetGroupsBatch(context.TODO(), &groupsmanagement.GetGroupsBatchRequest{ Groupids: groupids, }) groups := map[string]groupsstorage.Group{} if err == nil { for _, g := range groupsresp.Groups { groups[g.Id] = g.ToStorageType() } } beneficiaries, err := h.services.GRPC.MobilityAccounts.GetAccountsBatch(context.TODO(), &accounts.GetAccountsBatchRequest{ Accountids: beneficiaries_ids, }) if err != nil { return nil, nil, err } beneficiaries_map := map[string]accountsstorage.Account{} for _, ben := range beneficiaries.Accounts { beneficiaries_map[ben.Id] = ben.ToStorageType() } return groups, beneficiaries_map, nil } func (h *ApplicationHandler) generateAgendaExcel(events []agendastorage.Event, groups map[string]groupsstorage.Group, beneficiaries_map map[string]accountsstorage.Account) *excelize.File { f := excelize.NewFile() f.SetCellValue("Sheet1", "A1", "Evénement") f.SetCellValue("Sheet1", "B1", "Date de début") f.SetCellValue("Sheet1", "C1", "Date de fin") f.SetCellValue("Sheet1", "D1", "Nom bénéficiaire") f.SetCellValue("Sheet1", "E1", "Prenom bénéficiaire") f.SetCellValue("Sheet1", "F1", "Numéro allocataire / Pole emploi") f.SetCellValue("Sheet1", "G1", "Prescipteur") f.SetCellValue("Sheet1", "H1", "Prescipteur Nom") f.SetCellValue("Sheet1", "I1", "Prescipteur Email") f.SetCellValue("Sheet1", "J1", "Gestionnaire événement") i := 2 for _, e := range events { if len(e.Owners) == 0 { continue } admin := groups[e.Owners[0]] for _, s := range e.Subscriptions { subscribedbygroup := "" subscribedbyuser := "" subscribedbyemail := "" if v, ok := s.Data["subscribed_by"].(map[string]any); ok { if v2, ok := v["group"].(map[string]any); ok { if v3, ok := v2["name"].(string); ok { subscribedbygroup = v3 } } if v4, ok := v["user"].(map[string]any); ok { if v5, ok := v4["display_name"].(string); ok { subscribedbyuser = v5 } if v6, ok := v4["email"].(string); ok { subscribedbyemail = v6 } } } beneficiary := beneficiaries_map[s.Subscriber] f.SetCellValue("Sheet1", fmt.Sprintf("A%d", i), e.Name) f.SetCellValue("Sheet1", fmt.Sprintf("B%d", i), e.Startdate.Format("2006-01-02")) f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i), e.Enddate.Format("2006-01-02")) f.SetCellValue("Sheet1", fmt.Sprintf("D%d", i), beneficiary.Data["last_name"]) f.SetCellValue("Sheet1", fmt.Sprintf("E%d", i), beneficiary.Data["first_name"]) f.SetCellValue("Sheet1", fmt.Sprintf("F%d", i), beneficiary.Data["file_number"]) f.SetCellValue("Sheet1", fmt.Sprintf("G%d", i), subscribedbygroup) f.SetCellValue("Sheet1", fmt.Sprintf("H%d", i), subscribedbyuser) f.SetCellValue("Sheet1", fmt.Sprintf("I%d", i), subscribedbyemail) f.SetCellValue("Sheet1", fmt.Sprintf("J%d", i), admin.Data["name"]) i = i + 1 } } return f } type FleetBookingsExportResult struct { ExcelFile *excelize.File } func (h *ApplicationHandler) ExportAllFleetBookings() (*FleetBookingsExportResult, error) { vehicles, bookings, err := h.getFleetData() if err != nil { return nil, err } groups, beneficiaries_map, err := h.getFleetMetadata(bookings) if err != nil { return nil, err } file := h.generateFleetExcel(bookings, vehicles, groups, beneficiaries_map, "") return &FleetBookingsExportResult{ExcelFile: file}, nil } func (h *ApplicationHandler) ExportFleetBookingsByGroup(groupID string) (*FleetBookingsExportResult, error) { vehicles, bookings, err := h.getFleetData() if err != nil { return nil, err } groups, beneficiaries_map, err := h.getFleetMetadata(bookings) if err != nil { return nil, err } file := h.generateFleetExcel(bookings, vehicles, groups, beneficiaries_map, groupID) return &FleetBookingsExportResult{ExcelFile: file}, nil } func (h *ApplicationHandler) getFleetData() (map[string]fleetsstorage.Vehicle, []fleetsstorage.Booking, error) { vehicles := map[string]fleetsstorage.Vehicle{} bookings := []fleetsstorage.Booking{} request := &fleets.GetVehiclesRequest{ Namespaces: []string{"parcoursmob"}, } resp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), request) if err != nil { return nil, nil, err } for _, vehicle := range resp.Vehicles { v := vehicle.ToStorageType() for _, b := range v.Bookings { bookings = append(bookings, b) } vehicles[vehicle.Id] = v } return vehicles, bookings, nil } func (h *ApplicationHandler) getFleetMetadata(bookings []fleetsstorage.Booking) (map[string]groupsstorage.Group, map[string]accountsstorage.Account, error) { beneficiaries_ids := []string{} for _, b := range bookings { beneficiaries_ids = append(beneficiaries_ids, b.Driver) } groups := map[string]groupsstorage.Group{} admingroups, err := h.services.GRPC.GroupsManagement.GetGroups(context.TODO(), &groupsmanagement.GetGroupsRequest{ Namespaces: []string{"parcoursmob_organizations"}, }) if err != nil { return nil, nil, err } for _, g := range admingroups.Groups { groups[g.Id] = g.ToStorageType() } beneficiaries, err := h.services.GRPC.MobilityAccounts.GetAccountsBatch(context.TODO(), &accounts.GetAccountsBatchRequest{ Accountids: beneficiaries_ids, }) if err != nil { return nil, nil, err } beneficiaries_map := map[string]accountsstorage.Account{} for _, ben := range beneficiaries.Accounts { beneficiaries_map[ben.Id] = ben.ToStorageType() } return groups, beneficiaries_map, nil } func (h *ApplicationHandler) generateFleetExcel(bookings []fleetsstorage.Booking, vehicles map[string]fleetsstorage.Vehicle, groups map[string]groupsstorage.Group, beneficiaries_map map[string]accountsstorage.Account, filterGroupID string) *excelize.File { f := excelize.NewFile() f.SetCellValue("Sheet1", "A1", "Numéro") f.SetCellValue("Sheet1", "B1", "Type") f.SetCellValue("Sheet1", "C1", "Gestionnaire") f.SetCellValue("Sheet1", "D1", "Prescripteur") f.SetCellValue("Sheet1", "E1", "Bénéficiaire") f.SetCellValue("Sheet1", "F1", "Numéro allocataire / Pole emploi") f.SetCellValue("Sheet1", "G1", "Début de Mise à disposition") f.SetCellValue("Sheet1", "H1", "Fin de mise à disposition") f.SetCellValue("Sheet1", "I1", "Début indisponibilité") f.SetCellValue("Sheet1", "J1", "Fin indisponibilité") f.SetCellValue("Sheet1", "K1", "Véhicule retiré") f.SetCellValue("Sheet1", "L1", "Commentaire - Retrait véhicule") f.SetCellValue("Sheet1", "M1", "Réservation supprimée") f.SetCellValue("Sheet1", "N1", "Motif de la suppression") i := 2 for _, b := range bookings { vehicle := vehicles[b.Vehicleid] if len(vehicle.Administrators) == 0 { continue } admin := groups[vehicle.Administrators[0]] bookedby := "" if v, ok := b.Data["booked_by"].(map[string]any); ok { if v2, ok := v["user"].(map[string]any); ok { if v3, ok := v2["display_name"].(string); ok { bookedby = v3 } } } bookedbygroup := "" if v4, ok := b.Data["booked_by"].(map[string]any); ok { if v5, ok := v4["group"].(map[string]any); ok { if v6, ok := v5["id"].(string); ok { bookedbygroup = v6 } } } // Filter by group if specified if filterGroupID != "" && bookedbygroup != filterGroupID { continue } beneficiary := beneficiaries_map[b.Driver] adminunavailability := false if av, ok := b.Data["administrator_unavailability"].(bool); ok && av { adminunavailability = true } deleted := "" if b.Deleted { deleted = "DELETED" } f.SetCellValue("Sheet1", fmt.Sprintf("A%d", i), vehicle.Data["licence_plate"]) f.SetCellValue("Sheet1", fmt.Sprintf("B%d", i), vehicle.Type) f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i), admin.Data["name"]) f.SetCellValue("Sheet1", fmt.Sprintf("D%d", i), bookedby) f.SetCellValue("Sheet1", fmt.Sprintf("E%d", i), fmt.Sprintf("%v %v", beneficiary.Data["first_name"], beneficiary.Data["last_name"])) f.SetCellValue("Sheet1", fmt.Sprintf("F%d", i), beneficiary.Data["file_number"]) f.SetCellValue("Sheet1", fmt.Sprintf("G%d", i), b.Startdate.Format("2006-01-02")) f.SetCellValue("Sheet1", fmt.Sprintf("H%d", i), b.Enddate.Format("2006-01-02")) f.SetCellValue("Sheet1", fmt.Sprintf("I%d", i), b.Unavailablefrom.Format("2006-01-02")) f.SetCellValue("Sheet1", fmt.Sprintf("J%d", i), b.Unavailableto.Format("2006-01-02")) f.SetCellValue("Sheet1", fmt.Sprintf("K%d", i), adminunavailability) f.SetCellValue("Sheet1", fmt.Sprintf("L%d", i), b.Data["comment"]) f.SetCellValue("Sheet1", fmt.Sprintf("M%d", i), deleted) f.SetCellValue("Sheet1", fmt.Sprintf("N%d", i), b.Data["motif"]) i = i + 1 } return f }