package application import ( "cmp" "context" "encoding/json" "fmt" "io" "net/http" "slices" "sort" "strconv" "strings" "time" mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage" "git.coopgo.io/coopgo-platform/payments/pricing" "git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/proto/gen" "git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/transformers" "git.coopgo.io/coopgo-platform/solidarity-transport/types" "github.com/google/uuid" "github.com/gorilla/mux" "github.com/paulmach/orb/geojson" "github.com/rs/zerolog/log" "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/utils/form-validators" "git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting" filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage" ) type DriversForm struct { FirstName string `json:"first_name" validate:"required"` LastName string `json:"last_name" validate:"required"` Email string `json:"email" validate:"required,email"` Birthdate *time.Time `json:"birthdate" validate:"required"` PhoneNumber string `json:"phone_number" validate:"required,phoneNumber"` Address any `json:"address,omitempty"` Gender string `json:"gender"` } const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Saturday ) func (h *ApplicationHandler) SolidarityTransportOverview(w http.ResponseWriter, r *http.Request) { accounts, err := h.solidarityDrivers(r) if err != nil { log.Error().Err(err).Msg("issue getting solidarity drivers") accounts = []mobilityaccountsstorage.Account{} } accountsMap := map[string]mobilityaccountsstorage.Account{} for _, a := range accounts { accountsMap[a.ID] = a } beneficiariesMap, err := h.services.GetBeneficiariesMap() if err != nil { beneficiariesMap = map[string]mobilityaccountsstorage.Account{} } bookingsproto, err := h.services.GRPC.SolidarityTransport.GetSolidarityTransportBookings(context.Background(), &gen.GetSolidarityTransportBookingsRequest{ StartDate: timestamppb.Now(), EndDate: timestamppb.New(time.Now().Add(24 * 365 * time.Hour)), }) if err != nil { log.Error().Err(err).Msg("issue retreving bookings") } bookings := []*types.Booking{} if err == nil { for _, b := range bookingsproto.Bookings { booking, _ := transformers.BookingProtoToType(b) bookings = append(bookings, booking) } } bookingshistoryproto, err := h.services.GRPC.SolidarityTransport.GetSolidarityTransportBookings(context.Background(), &gen.GetSolidarityTransportBookingsRequest{ EndDate: timestamppb.Now(), StartDate: timestamppb.New(time.Now().Add(-1 * 24 * 365 * time.Hour)), }) if err != nil { log.Error().Err(err).Msg("issue retreving bookings") } bookingshistory := []*types.Booking{} if err == nil { for _, b := range bookingshistoryproto.Bookings { booking, _ := transformers.BookingProtoToType(b) bookingshistory = append(bookingshistory, booking) } } slices.SortFunc(accounts, func(a, b mobilityaccountsstorage.Account) int { return strings.Compare( strings.ToLower(fmt.Sprintf("%s %s", a.Data["first_name"].(string), a.Data["last_name"].(string))), strings.ToLower(fmt.Sprintf("%s %s", b.Data["first_name"].(string), b.Data["last_name"].(string))), ) }) slices.SortFunc(bookings, func(a, b *types.Booking) int { return cmp.Compare(a.Journey.PassengerPickupDate.Unix(), b.Journey.PassengerPickupDate.Unix()) }) slices.SortFunc(bookingshistory, func(a, b *types.Booking) int { return cmp.Compare(a.Journey.PassengerPickupDate.Unix(), b.Journey.PassengerPickupDate.Unix()) }) h.Renderer.SolidarityTransportOverview(w, r, accounts, accountsMap, beneficiariesMap, bookings, bookingshistory) } func (h *ApplicationHandler) SolidarityTransportCreateDriver(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { dataMap, err := parseBeneficiariesForm(r) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusBadRequest) return } data, err := structpb.NewValue(dataMap) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } request := &mobilityaccounts.RegisterRequest{ Account: &mobilityaccounts.Account{ Namespace: "solidarity_drivers", Data: data.GetStructValue(), }, } resp, err := h.services.GRPC.MobilityAccounts.Register(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", resp.Account.Id), http.StatusFound) return } h.Renderer.SolidarityTransportCreateDriver(w, r) } func (h *ApplicationHandler) SolidarityTransportUpdateDriver(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) driverID := vars["driverid"] driver, err := h.services.GetAccount(driverID) if err != nil { log.Error().Err(err).Msg("Issue retrieving driver account") w.WriteHeader(http.StatusInternalServerError) return } if r.Method == "POST" { dataMap, err := parseBeneficiariesForm(r) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusBadRequest) return } data, err := structpb.NewValue(dataMap) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } request := &mobilityaccounts.UpdateDataRequest{ Account: &mobilityaccounts.Account{ Id: driverID, Namespace: "solidarity_drivers", Data: data.GetStructValue(), }, } resp, err := h.services.GRPC.MobilityAccounts.UpdateData(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", resp.Account.Id), http.StatusFound) return } h.Renderer.SolidarityTransportUpdateDriver(w, r, driver) } func (h *ApplicationHandler) SolidarityTransportDriverDisplay(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) driverID := vars["driverid"] documents := h.filestorage.List(filestorage.PREFIX_SOLIDARITY_TRANSPORT_DRIVERS + "/" + driverID) driver, err := h.services.GetAccount(driverID) if err != nil { log.Error().Err(err).Msg("Issue retrieving driver account") w.WriteHeader(http.StatusInternalServerError) return } availabilities := []*gen.DriverRegularAvailability{} resp, err := h.services.GRPC.SolidarityTransport.GetDriverRegularAvailabilities(context.Background(), &gen.GetDriverRegularAvailabilitiesRequest{DriverId: driverID}) if err != nil { log.Error().Err(err).Msg("error calling GetDriverRegularAvailabilities") } else { availabilities = resp.Results } sort.Sort(sorting.SolidarityAvailabilitiesByDay(availabilities)) bookingsresp, err := h.services.GRPC.SolidarityTransport.GetSolidarityTransportBookings(context.Background(), &gen.GetSolidarityTransportBookingsRequest{Driverid: driverID}) if err != nil { log.Error().Err(err).Msg("could not get driver bookings") } log.Debug().Any("bookings", bookingsresp.Bookings).Msg("bookings list") kmnb := int64(0) bookings := slices.Collect(func(yield func(*gen.SolidarityTransportBooking) bool) { for _, b := range bookingsresp.Bookings { log.Debug().Str("bokking status", b.Status).Msg("candidate booking") if b.Status == "VALIDATED" { kmnb = kmnb + b.Journey.DriverDistance if !yield(b) { return } } } }) log.Debug().Any("bookings", bookings).Msg("bookings list") stats := map[string]any{ "bookings": map[string]any{ "count": len(bookings), "km": kmnb, }, } h.Renderer.SolidarityTransportDriverDisplay(w, r, driver, availabilities, documents, bookings, stats) } func (h *ApplicationHandler) SolidarityTransportAddAvailability(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { log.Error().Msg("Wrong method") w.WriteHeader(http.StatusMethodNotAllowed) return } if err := r.ParseForm(); err != nil { log.Error().Err(err).Msg("error parsong availabilities form") w.WriteHeader(http.StatusInternalServerError) return } vars := mux.Vars(r) driverID := vars["driverid"] availabilities := []*gen.DriverRegularAvailability{} starttime := r.PostFormValue("starttime") endtime := r.PostFormValue("endtime") address := r.PostFormValue("address") if r.PostFormValue("days.monday") == "on" { a := &gen.DriverRegularAvailability{ DriverId: driverID, Day: Monday, StartTime: starttime, EndTime: endtime, Address: &gen.GeoJsonFeature{ Serialized: address, }, } availabilities = append(availabilities, a) } if r.PostFormValue("days.tuesday") == "on" { a := &gen.DriverRegularAvailability{ DriverId: driverID, Day: Tuesday, StartTime: starttime, EndTime: endtime, Address: &gen.GeoJsonFeature{ Serialized: address, }, } availabilities = append(availabilities, a) } if r.PostFormValue("days.wednesday") == "on" { a := &gen.DriverRegularAvailability{ DriverId: driverID, Day: Wednesday, StartTime: starttime, EndTime: endtime, Address: &gen.GeoJsonFeature{ Serialized: address, }, } availabilities = append(availabilities, a) } if r.PostFormValue("days.thursday") == "on" { a := &gen.DriverRegularAvailability{ DriverId: driverID, Day: Thursday, StartTime: starttime, EndTime: endtime, Address: &gen.GeoJsonFeature{ Serialized: address, }, } availabilities = append(availabilities, a) } if r.PostFormValue("days.friday") == "on" { a := &gen.DriverRegularAvailability{ DriverId: driverID, Day: Friday, StartTime: starttime, EndTime: endtime, Address: &gen.GeoJsonFeature{ Serialized: address, }, } availabilities = append(availabilities, a) } if r.PostFormValue("days.saturday") == "on" { a := &gen.DriverRegularAvailability{ DriverId: driverID, Day: Saturday, StartTime: starttime, EndTime: endtime, Address: &gen.GeoJsonFeature{ Serialized: address, }, } availabilities = append(availabilities, a) } if r.PostFormValue("days.sunday") == "on" { a := &gen.DriverRegularAvailability{ DriverId: driverID, Day: Sunday, StartTime: starttime, EndTime: endtime, Address: &gen.GeoJsonFeature{ Serialized: address, }, } availabilities = append(availabilities, a) } req := &gen.AddDriverRegularAvailabilitiesRequest{ Availabilities: availabilities, } _, err := h.services.GRPC.SolidarityTransport.AddDriverRegularAvailabilities(context.Background(), req) if err != nil { log.Error().Err(err).Msg("could not add availabilities") w.WriteHeader(http.StatusInternalServerError) return } log.Info().Msg("Finished creating availabilities") http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound) } func (h *ApplicationHandler) SolidarityTransportUnarchiveDriver(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) driverID := vars["driverid"] data, _ := structpb.NewValue(map[string]any{ "archived": false, }) request := &mobilityaccounts.UpdateDataRequest{ Account: &mobilityaccounts.Account{ Id: driverID, Namespace: "solidarity_transport_drivers", Data: data.GetStructValue(), }, } resp, err := h.services.GRPC.MobilityAccounts.UpdateData(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", resp.Account.Id), http.StatusFound) } func (h *ApplicationHandler) SolidarityTransportDriverDocuments(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) driverID := vars["driverid"] // r.ParseForm() r.ParseMultipartForm(100 * 1024 * 1024) document_type := r.FormValue("type") document_name := r.FormValue("name") file, header, err := r.FormFile("file-upload") if err != nil { log.Error().Err(err).Msg("") return } defer file.Close() fileid := uuid.NewString() metadata := map[string]string{ "type": document_type, "name": document_name, } log.Debug().Any("metadata", metadata).Msg("Metadata") if err := h.filestorage.Put(file, filestorage.PREFIX_SOLIDARITY_TRANSPORT_DRIVERS, fmt.Sprintf("%s/%s_%s", driverID, fileid, header.Filename), header.Size, metadata); err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound) } func (h *ApplicationHandler) SolidarityTransportDocumentDownload(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) driverID := vars["driverid"] document := vars["document"] file, info, err := h.filestorage.Get(filestorage.PREFIX_SOLIDARITY_TRANSPORT_DRIVERS, fmt.Sprintf("%s/%s", driverID, document)) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } w.Header().Set("Content-Type", info.ContentType) if _, err = io.Copy(w, file); err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } // http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound) } func (h *ApplicationHandler) SolidarityTransportArchiveDriver(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) driverID := vars["driverid"] data, _ := structpb.NewValue(map[string]any{ "archived": true, }) request := &mobilityaccounts.UpdateDataRequest{ Account: &mobilityaccounts.Account{ Id: driverID, Namespace: "solidarity_transport_drivers", Data: data.GetStructValue(), }, } resp, err := h.services.GRPC.MobilityAccounts.UpdateData(context.TODO(), request) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusInternalServerError) return } http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", resp.Account.Id), http.StatusFound) } func (h *ApplicationHandler) SolidarityTransportDeleteAvailability(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) driverID := vars["driverid"] availabilityID := vars["availabilityid"] req := &gen.DeleteDriverRegularAvailabilityRequest{ DriverId: driverID, AvailabilityId: availabilityID, } if _, err := h.services.GRPC.SolidarityTransport.DeleteDriverRegularAvailability(context.Background(), req); err != nil { log.Error().Err(err).Msg("could not delete availability") w.WriteHeader(http.StatusNotFound) return } http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound) } func (h *ApplicationHandler) SolidarityTransportDriverJourney(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) driverId := vars["driverid"] journeyId := vars["journeyid"] var passenger mobilityaccountsstorage.Account passengerId := r.URL.Query().Get("passengerid") log.Info().Str("journeyid", journeyId).Str("driverid", driverId).Msg("driver journey") journey, err := h.services.GRPC.SolidarityTransport.GetDriverJourney(context.Background(), &gen.GetDriverJourneyRequest{ DriverId: driverId, JourneyId: journeyId, }) if err != nil { log.Error().Err(err).Msg("could not get driver journey") w.WriteHeader(http.StatusNotFound) return } if passengerId != "" { passenger, err = h.services.GetAccount(passengerId) if err != nil { log.Error().Err(err).Msg("could not get account") w.WriteHeader(http.StatusNotFound) return } } j, err := transformers.DriverJourneyProtoToType(journey.DriverJourney) if err != nil { log.Error().Err(err).Msg("could not get driver journey") w.WriteHeader(http.StatusNotFound) return } solidarity, err := h.services.GRPC.SolidarityTransport.GetSolidarityTransportBookings(context.Background(), &gen.GetSolidarityTransportBookingsRequest{ Passengerid: passengerId, StartDate: timestamppb.New(time.Now().Add(-12 * 730 * time.Hour)), EndDate: timestamppb.New(time.Now().Add(12 * 730 * time.Hour)), }) priority := false if a, ok := passenger.Data["other_properties"]; ok { if b, ok := a.(map[string]any); ok { if c, ok := b["status"]; ok { if p, ok := c.(string); ok { priority = (p == "Prioritaire") } } } } history := 0 if op, ok := passenger.Data["other_properties"]; ok { if op_map, ok := op.(map[string]any); ok { if pst, ok := op_map["previous_solidarity_transport"]; ok { if pst_str, ok := pst.(string); ok { if pst_str != "" { if n, err := strconv.Atoi(pst_str); err == nil { history = history + n } else { log.Error().Err(err).Str("n", pst_str).Msg("string to int conversion error") } } } } } } history = history + len(solidarity.Bookings) log.Debug().Any("history", history).Msg("history check") benefParams := pricing.BeneficiaryParams{} if passengerId == "" { benefParams = pricing.BeneficiaryParams{ Address: h.pricingGeography(j.PassengerPickup), History: 99, Priority: false, } } else { log.Debug().Any("passenger data", passenger.Data).Msg("0") var passengerGeo pricing.GeographyParams if pa, ok := passenger.Data["address"]; ok { jsonpa, err := json.Marshal(pa) if err == nil { passGeojson, err := geojson.UnmarshalFeature(jsonpa) if err == nil { passengerGeo = h.pricingGeography(passGeojson) } } } benefParams = pricing.BeneficiaryParams{ Address: passengerGeo, History: history, Priority: priority, } } pricing, err := h.services.Pricing.Prices(pricing.PricingParams{ MobilityType: "solidarity_transport", Beneficiary: benefParams, SharedMobility: pricing.SharedMobilityParams{ DriverDistance: journey.DriverJourney.DriverDistance, PassengerDistance: journey.DriverJourney.PassengerDistance, Departure: h.pricingGeography(j.PassengerPickup), Destination: h.pricingGeography(j.PassengerDrop), OutwardOnly: journey.DriverJourney.Noreturn, }, }) if err != nil { log.Error().Err(err).Msg("error in pricing calculation") } journey.DriverJourney.Price.Amount = pricing["passenger"].Amount journey.DriverJourney.Price.Currency = "EUR" if r.Method == "POST" { if passengerId == "" { log.Error().Err(err).Msg("could not get driver journey") w.WriteHeader(http.StatusNotFound) return } if err := r.ParseForm(); err != nil { log.Error().Err(err).Msg("could not parse form input") w.WriteHeader(http.StatusBadRequest) return } rwt := r.PostFormValue("return_waiting_time") return_waiting_time := int64(0) return_waiting_time, err := strconv.ParseInt(rwt, 10, 64) if err == nil { log.Error().Err(err).Msg("return waiting time error") } motivation := r.PostFormValue("motivation") data, err := structpb.NewStruct(map[string]any{ "motivation": motivation, }) if err != nil { log.Error().Err(err).Msg("issue creating data struct") } bookingRes, err := h.services.GRPC.SolidarityTransport.BookDriverJourney(context.Background(), &gen.BookDriverJourneyRequest{ PassengerId: passengerId, DriverId: driverId, DriverJourneyId: journeyId, ReturnWaitingDuration: return_waiting_time * int64(time.Minute), PriceAmount: journey.DriverJourney.Price.Amount, PriceCurrency: journey.DriverJourney.Price.Currency, Data: data, }) if err != nil { log.Error().Err(err).Msg("cannot create booking") w.WriteHeader(http.StatusInternalServerError) return } message := r.PostFormValue("message") doNotSend := r.PostFormValue("do_not_send") send_message := strings.ReplaceAll(message, "{booking_id}", bookingRes.Booking.Id) log.Debug().Str("message", send_message).Str("do not send", doNotSend).Msg("Driver journey booked : sending message") if doNotSend != "on" { h.GenerateSMS(driverId, send_message) if err := h.creditWallet(passengerId, float64(-1)*journey.DriverJourney.Price.Amount); err != nil { log.Error().Err(err).Msg("could not credit wallet") w.WriteHeader(http.StatusInternalServerError) return } } http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/"), http.StatusFound) return } driver, err := h.services.GetAccount(driverId) if err != nil { log.Error().Err(err).Msg("could not get driver") w.WriteHeader(http.StatusNotFound) return } beneficiaries, err := h.beneficiaries(r) if err != nil { log.Error().Err(err).Msg("") w.WriteHeader(http.StatusBadRequest) return } driverjourney, err := transformers.DriverJourneyProtoToType(journey.DriverJourney) if err != nil { log.Error().Err(err).Msg("could not transform driver journey type") w.WriteHeader(http.StatusBadRequest) return } h.Renderer.SolidarityTransportDriverJourney(w, r, driverjourney, driver, passenger, beneficiaries) } func (h *ApplicationHandler) SolidarityTransportDriverJourneyToggleNoreturn(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) journeyId := vars["journeyid"] _, err := h.services.GRPC.SolidarityTransport.ToggleSolidarityTransportNoreturn(context.Background(), &gen.ToggleSolidarityTransportNoreturnRequest{ JourneyId: journeyId, }) if err != nil { log.Error().Err(err).Msg("could not get driver journey") w.WriteHeader(http.StatusNotFound) return } log.Debug().Msg("here") http.Redirect(w, r, r.Referer(), http.StatusFound) } func (h *ApplicationHandler) SolidarityTransportBookingDisplay(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bookingId := vars["bookingid"] resp, err := h.services.GRPC.SolidarityTransport.GetSolidarityTransportBooking(context.Background(), &gen.GetSolidarityTransportBookingRequest{ Id: bookingId, }) if r.Method == "POST" { if err := r.ParseForm(); err != nil { log.Error().Err(err).Msg("could not parse form") w.WriteHeader(http.StatusBadRequest) return } driverDistanceStr := r.PostFormValue("driver_distance") driverDistance, err := strconv.Atoi(driverDistanceStr) if err != nil { log.Error().Err(err).Msg("could not read distance") w.WriteHeader(http.StatusBadRequest) return } resp.Booking.Journey.DriverDistance = int64(driverDistance) _, err = h.services.GRPC.SolidarityTransport.UpdateSolidarityTransportBooking(context.Background(), &gen.UpdateSolidarityTransportBookingRequest{ Booking: resp.Booking, }) if err != nil { log.Error().Err(err).Msg("could not update booking") w.WriteHeader(http.StatusInternalServerError) return } } booking, err := transformers.BookingProtoToType(resp.Booking) if err != nil { log.Error().Err(err).Msg("could not transform booking type") w.WriteHeader(http.StatusBadRequest) return } driver, err := h.services.GetAccount(booking.DriverId) if err != nil { log.Error().Err(err).Msg("driver retrieval issue") w.WriteHeader(http.StatusInternalServerError) return } passenger, err := h.services.GetAccount(booking.PassengerId) if err != nil { log.Error().Err(err).Msg("passenger retrieval issue") w.WriteHeader(http.StatusInternalServerError) return } h.Renderer.SolidarityTransportBookingDisplay(w, r, booking, driver, passenger) } func (h *ApplicationHandler) SolidarityTransportBookingStatus(action string) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bookingId := vars["bookingid"] reason := "" status := "" if action == "confirm" { status = "VALIDATED" } else if action == "cancel" { status = "CANCELLED" if r.Method == "POST" { r.ParseForm() reason = r.PostFormValue("reason") } } else if action == "waitconfirmation" { status = "WAITING_CONFIRMATION" } if status != "" { if _, err := h.services.GRPC.SolidarityTransport.UpdateSolidarityTransportBookingStatus(context.Background(), &gen.UpdateSolidarityTransportBookingStatusRequest{ BookingId: bookingId, NewStatus: status, Reason: reason, }); err != nil { log.Error().Err(err).Msg("update booking status issue") w.WriteHeader(http.StatusInternalServerError) return } if status == "CANCELLED" { booking, err := h.services.GRPC.SolidarityTransport.GetSolidarityTransportBooking(context.Background(), &gen.GetSolidarityTransportBookingRequest{ Id: bookingId, }) if err == nil { if err := h.creditWallet(booking.Booking.PassengerId, booking.Booking.Journey.Price.Amount); err != nil { log.Error().Err(err).Msg("could not credit wallet") w.WriteHeader(http.StatusInternalServerError) return } } } if status == "WAITING_CONFIRMATION" { booking, err := h.services.GRPC.SolidarityTransport.GetSolidarityTransportBooking(context.Background(), &gen.GetSolidarityTransportBookingRequest{ Id: bookingId, }) if err == nil { if err := h.creditWallet(booking.Booking.PassengerId, float64(-1)*booking.Booking.Journey.Price.Amount); err != nil { log.Error().Err(err).Msg("could not credit wallet") w.WriteHeader(http.StatusInternalServerError) return } } } } http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/bookings/%s", bookingId), http.StatusFound) } } func parseDriversForm(r *http.Request) (map[string]any, error) { if err := r.ParseForm(); err != nil { return nil, err } var date *time.Time if r.PostFormValue("birthdate") != "" { d, err := time.Parse("2006-01-02", r.PostFormValue("birthdate")) if err != nil { return nil, err } date = &d } formData := DriversForm{ FirstName: r.PostFormValue("first_name"), LastName: r.PostFormValue("last_name"), Email: r.PostFormValue("email"), Birthdate: date, PhoneNumber: r.PostFormValue("phone_number"), Gender: r.PostFormValue("gender"), } if r.PostFormValue("address") != "" { var a any json.Unmarshal([]byte(r.PostFormValue("address")), &a) formData.Address = a } validate := formvalidators.New() if err := validate.Struct(formData); err != nil { return nil, err } d, err := json.Marshal(formData) if err != nil { return nil, err } var dataMap map[string]any err = json.Unmarshal(d, &dataMap) if err != nil { return nil, err } return dataMap, nil } func (h *ApplicationHandler) solidarityDrivers(r *http.Request) ([]mobilityaccountsstorage.Account, error) { accounts := []mobilityaccountsstorage.Account{} request := &mobilityaccounts.GetAccountsRequest{ Namespaces: []string{"solidarity_drivers"}, } resp, err := h.services.GRPC.MobilityAccounts.GetAccounts(context.TODO(), request) if err != nil { return accounts, err } for _, account := range resp.Accounts { if filterAccount(r, account) { a := account.ToStorageType() accounts = append(accounts, a) } } return accounts, err } func (h *ApplicationHandler) pricingGeography(loc *geojson.Feature) pricing.GeographyParams { if loc == nil { return pricing.GeographyParams{} } geo, err := h.services.Geography.GeoSearch(loc) if err != nil { log.Error().Err(err).Msg("issue in geosearch") return pricing.GeographyParams{} } return pricing.GeographyParams{ Location: loc, CityCode: geo["communes"].Properties.MustString("code"), IntercommunalityCode: geo["epci"].Properties.MustString("code"), RegionCode: geo["regions"].Properties.MustString("code"), DepartmentCode: geo["departements"].Properties.MustString("code"), } }