solidarity transport updates
This commit is contained in:
@@ -25,7 +25,7 @@ type ApplicationHandler struct {
|
||||
|
||||
func NewApplicationHandler(cfg *viper.Viper, svc *services.ServicesHandler, cache cache.CacheHandler, filestorage cache.FileStorage, emailing *emailing.Mailer) (*ApplicationHandler, error) {
|
||||
templates_root := cfg.GetString("templates.root")
|
||||
renderer := renderer.NewRenderer(cfg, templates_root)
|
||||
renderer := renderer.NewRenderer(cfg, templates_root, filestorage)
|
||||
return &ApplicationHandler{
|
||||
config: cfg,
|
||||
Renderer: renderer,
|
||||
|
||||
@@ -28,21 +28,25 @@ import (
|
||||
"git.coopgo.io/coopgo-platform/groups-management/storage"
|
||||
mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
|
||||
mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
|
||||
"git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/proto/gen"
|
||||
"git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/transformers"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type BeneficiariesForm 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"`
|
||||
FileNumber string `json:"file_number"`
|
||||
Address any `json:"address,omitempty"`
|
||||
Gender string `json:"gender"`
|
||||
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"`
|
||||
FileNumber string `json:"file_number"`
|
||||
Address any `json:"address,omitempty"`
|
||||
Gender string `json:"gender"`
|
||||
OtherProperties any `json:"other_properties,omitempty"`
|
||||
}
|
||||
|
||||
type Event_Beneficiary interface {
|
||||
@@ -192,7 +196,7 @@ func (h *ApplicationHandler) BeneficiaryDisplay(w http.ResponseWriter, r *http.R
|
||||
|
||||
resp, err := h.services.GRPC.MobilityAccounts.GetAccount(context.TODO(), request)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
log.Error().Err(err).Msg("cannot retrieve account")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -305,6 +309,34 @@ func (h *ApplicationHandler) BeneficiaryDisplay(w http.ResponseWriter, r *http.R
|
||||
events_list = append(events_list, event)
|
||||
}
|
||||
}
|
||||
solidarity, err := h.services.GRPC.SolidarityTransport.GetSolidarityTransportBookings(context.Background(), &gen.GetSolidarityTransportBookingsRequest{
|
||||
Passengerid: beneficiaryID,
|
||||
StartDate: timestamppb.New(time.Now().Add(-36 * 730 * time.Hour)),
|
||||
EndDate: timestamppb.New(time.Now().Add(12 * 730 * time.Hour)),
|
||||
})
|
||||
solidarityTransportStats := map[string]int64{
|
||||
"count": 0,
|
||||
"km": 0,
|
||||
}
|
||||
for _, s := range solidarity.Bookings {
|
||||
b, _ := transformers.BookingProtoToType(s)
|
||||
event := Event{
|
||||
NameVal: fmt.Sprintf("%s (%d km)", b.Journey.PassengerDrop.Properties.MustString("label", ""), b.Journey.PassengerDistance),
|
||||
DateVal: b.Journey.PassengerPickupDate,
|
||||
DateEndVal: b.Journey.PassengerPickupDate,
|
||||
TypeVal: "Transport solidaire",
|
||||
IDVal: b.Id,
|
||||
DbVal: "/app/solidarity-transport/bookings/",
|
||||
IconSet: "vehicle",
|
||||
StatusVal: 1,
|
||||
}
|
||||
|
||||
events_list = append(events_list, event)
|
||||
|
||||
solidarityTransportStats["count"] = solidarityTransportStats["count"] + 1
|
||||
solidarityTransportStats["km"] = solidarityTransportStats["km"] + b.Journey.PassengerDistance
|
||||
|
||||
}
|
||||
sortByDate(events_list)
|
||||
|
||||
diag := []diagsstorage.Diag{}
|
||||
@@ -349,7 +381,7 @@ func (h *ApplicationHandler) BeneficiaryDisplay(w http.ResponseWriter, r *http.R
|
||||
for i, d := range diag {
|
||||
diagsAny[i] = d
|
||||
}
|
||||
h.Renderer.BeneficiaryDisplay(w, r, resp.Account.ToStorageType(), bookings, organizations, beneficiaries_file_types, file_types_map, documents, events_list, diagsAny)
|
||||
h.Renderer.BeneficiaryDisplay(w, r, resp.Account.ToStorageType(), bookings, organizations, beneficiaries_file_types, file_types_map, documents, events_list, diagsAny, solidarityTransportStats)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) BeneficiaryUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -409,6 +441,58 @@ func (h *ApplicationHandler) BeneficiaryUpdate(w http.ResponseWriter, r *http.Re
|
||||
h.Renderer.BeneficiaryUpdate(w, r, resp.Account.ToStorageType())
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) BeneficiaryArchive(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
beneficiaryID := vars["beneficiaryid"]
|
||||
|
||||
data, err := structpb.NewValue(map[string]any{
|
||||
"archived": true,
|
||||
})
|
||||
|
||||
request := &mobilityaccounts.UpdateDataRequest{
|
||||
Account: &mobilityaccounts.Account{
|
||||
Id: beneficiaryID,
|
||||
Namespace: "parcoursmob_beneficiaries",
|
||||
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/beneficiaries/%s", resp.Account.Id), http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) BeneficiaryUnarchive(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
beneficiaryID := vars["beneficiaryid"]
|
||||
|
||||
data, err := structpb.NewValue(map[string]any{
|
||||
"archived": false,
|
||||
})
|
||||
|
||||
request := &mobilityaccounts.UpdateDataRequest{
|
||||
Account: &mobilityaccounts.Account{
|
||||
Id: beneficiaryID,
|
||||
Namespace: "parcoursmob_beneficiaries",
|
||||
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/beneficiaries/%s", resp.Account.Id), http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) BeneficiaryPicture(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
beneficiaryID := vars["beneficiaryid"]
|
||||
@@ -496,7 +580,7 @@ func (h *ApplicationHandler) BeneficiaryDocumentDownload(w http.ResponseWriter,
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound)
|
||||
// http.Redirect(w, r, fmt.Sprintf("/app/beneficiaries/%s", beneficiaryID), http.StatusFound)
|
||||
}
|
||||
|
||||
func filterAccount(r *http.Request, a *mobilityaccounts.Account) bool {
|
||||
@@ -509,6 +593,18 @@ func filterAccount(r *http.Request, a *mobilityaccounts.Account) bool {
|
||||
}
|
||||
}
|
||||
|
||||
archivedFilter, ok := r.URL.Query()["archived"]
|
||||
if ok && archivedFilter[0] == "true" {
|
||||
if archived, ok := a.Data.AsMap()["archived"].(bool); ok && archived {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
if archived, ok := a.Data.AsMap()["archived"].(bool); ok && archived {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -529,6 +625,7 @@ func (h *ApplicationHandler) beneficiaries(r *http.Request) ([]mobilityaccountss
|
||||
|
||||
resp, err := h.services.GRPC.MobilityAccounts.GetAccountsBatch(context.TODO(), request)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("issue in mobilityaccounts call")
|
||||
return accounts, err
|
||||
}
|
||||
|
||||
@@ -566,6 +663,7 @@ func parseBeneficiariesForm(r *http.Request) (map[string]any, error) {
|
||||
FileNumber: r.PostFormValue("file_number"),
|
||||
Gender: r.PostFormValue("gender"),
|
||||
}
|
||||
log.Trace().Any("address", r.PostFormValue("address")).Msg("address")
|
||||
|
||||
if r.PostFormValue("address") != "" {
|
||||
var a any
|
||||
@@ -574,6 +672,15 @@ func parseBeneficiariesForm(r *http.Request) (map[string]any, error) {
|
||||
formData.Address = a
|
||||
}
|
||||
|
||||
log.Trace().Any("otther properties", r.PostFormValue("other_properties")).Msg("other propperties ?")
|
||||
|
||||
if r.PostFormValue("other_properties") != "" {
|
||||
var a any
|
||||
json.Unmarshal([]byte(r.PostFormValue("other_properties")), &a)
|
||||
|
||||
formData.OtherProperties = a
|
||||
}
|
||||
|
||||
validate := formvalidators.New()
|
||||
if err := validate.Struct(formData); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/identification"
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting"
|
||||
@@ -87,7 +88,9 @@ func (h *ApplicationHandler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if err == nil {
|
||||
for _, b := range bookingsresp.Bookings {
|
||||
bookings = append(bookings, b.ToStorageType())
|
||||
if b.Enddate.AsTime().After(time.Now()) {
|
||||
bookings = append(bookings, b.ToStorageType())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,23 +5,33 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting"
|
||||
carpoolproto "git.coopgo.io/coopgo-platform/carpool-service/servers/grpc/proto"
|
||||
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"
|
||||
groupstorage "git.coopgo.io/coopgo-platform/groups-management/storage"
|
||||
mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
|
||||
mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
|
||||
"git.coopgo.io/coopgo-platform/multimodal-routing/libs/transit/motis"
|
||||
"git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/proto/gen"
|
||||
"git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/transformers"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
geojson "github.com/paulmach/go.geojson"
|
||||
"github.com/paulmach/orb/geojson"
|
||||
"github.com/rs/zerolog/log"
|
||||
"gitlab.scity.coop/maas/navitia-golang"
|
||||
"gitlab.scity.coop/maas/navitia-golang/types"
|
||||
|
||||
//"gitlab.scity.coop/maas/navitia-golang"
|
||||
//"gitlab.scity.coop/maas/navitia-golang/types"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -32,14 +42,16 @@ var (
|
||||
func (h *ApplicationHandler) JourneysSearch(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
var (
|
||||
journeys_results *navitia.JourneyResults
|
||||
carpool_results any
|
||||
vehicle_results []any
|
||||
transit_results []*motis.Itinerary
|
||||
carpool_results []*geojson.FeatureCollection
|
||||
vehicle_results []fleetsstorage.Vehicle
|
||||
)
|
||||
availableDrivers := []mobilityaccountsstorage.Account{}
|
||||
vehiclech := make(chan []any, 1)
|
||||
navitiaCh := make(chan *navitia.JourneyResults, 1)
|
||||
carpoolCh := make(chan any, 1)
|
||||
// availableDrivers := []mobilityaccountsstorage.Account{}
|
||||
drivers := map[string]mobilityaccountsstorage.Account{}
|
||||
driverJourneys := []*gen.SolidarityTransportDriverJourney{}
|
||||
var organizedCarpools []*carpoolproto.CarpoolServiceDriverJourney
|
||||
// navitiaCh := make(chan *navitia.JourneyResults, 1)
|
||||
// carpoolCh := make(chan []any, 1)
|
||||
locTime, errTime := time.LoadLocation("Europe/Paris")
|
||||
if errTime != nil {
|
||||
log.Panic().Err(errTime).Msg("Tried to load timezone location Europe/Paris. Error. Missing zones in container ?")
|
||||
@@ -51,15 +63,15 @@ func (h *ApplicationHandler) JourneysSearch(w http.ResponseWriter, r *http.Reque
|
||||
|
||||
departure := r.FormValue("departure")
|
||||
destination := r.FormValue("destination")
|
||||
kb_results := []any{}
|
||||
|
||||
searched := false
|
||||
|
||||
var (
|
||||
departuregeo *geojson.Feature
|
||||
destinationgeo *geojson.Feature
|
||||
journeys *navitia.JourneyResults
|
||||
carpoolresults any
|
||||
vehicles = []any{}
|
||||
// journeys *navitia.JourneyResults
|
||||
// carpoolresults []any
|
||||
)
|
||||
|
||||
if departuredate != "" && departuretime != "" && departure != "" && destination != "" {
|
||||
@@ -69,132 +81,191 @@ func (h *ApplicationHandler) JourneysSearch(w http.ResponseWriter, r *http.Reque
|
||||
|
||||
departuregeo, err = geojson.UnmarshalFeature([]byte(departure))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
log.Error().Err(err).Msg("error unmarshalling departure")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
destinationgeo, err = geojson.UnmarshalFeature([]byte(destination))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
log.Error().Err(err).Msg("error unmarshalling destination")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
journeysRequest := func() {
|
||||
// TODO make it a library
|
||||
session, _ := navitia.NewCustom(
|
||||
h.config.GetString("services.navitia.api_key"),
|
||||
"https://api.navitia.io/v1",
|
||||
&http.Client{})
|
||||
|
||||
// SOLIDARITY TRANSPORT
|
||||
drivers, err = h.services.GetAccountsInNamespacesMap([]string{"solidarity_drivers", "organized_carpool_drivers"})
|
||||
if err != nil {
|
||||
drivers = map[string]mobilityaccountsstorage.Account{}
|
||||
}
|
||||
|
||||
protodep, _ := transformers.GeoJsonToProto(departuregeo)
|
||||
protodest, _ := transformers.GeoJsonToProto(destinationgeo)
|
||||
|
||||
log.Debug().Time("departure time", departuredatetime).Msg("calling driver journeys with ...")
|
||||
|
||||
res, err := h.services.GRPC.SolidarityTransport.GetDriverJourneys(context.Background(), &gen.GetDriverJourneysRequest{
|
||||
Departure: protodep,
|
||||
Arrival: protodest,
|
||||
DepartureDate: timestamppb.New(departuredatetime),
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error in grpc call to GetDriverJourneys")
|
||||
} else {
|
||||
driverJourneys = slices.Collect(func(yield func(*gen.SolidarityTransportDriverJourney) bool) {
|
||||
for _, dj := range res.DriverJourneys {
|
||||
if a, ok := drivers[dj.DriverId].Data["archived"]; ok {
|
||||
if archived, ok := a.(bool); ok {
|
||||
if archived {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
if !yield(dj) {
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
// res.DriverJourneys
|
||||
sort.Slice(driverJourneys, func(i, j int) bool {
|
||||
return driverJourneys[i].DriverDistance < driverJourneys[j].DriverDistance
|
||||
})
|
||||
}
|
||||
|
||||
// ORGANIZED CARPOOL
|
||||
organizedCarpoolsRes, err := h.services.GRPC.CarpoolService.DriverJourneys(context.Background(), &carpoolproto.DriverJourneysRequest{
|
||||
DepartureLat: departuregeo.Point().Lat(),
|
||||
DepartureLng: departuregeo.Point().Lon(),
|
||||
ArrivalLat: destinationgeo.Point().Lat(),
|
||||
ArrivalLng: destinationgeo.Point().Lon(),
|
||||
DepartureDate: timestamppb.New(departuredatetime),
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error retrieving organized carpools")
|
||||
} else {
|
||||
organizedCarpools = organizedCarpoolsRes.DriverJourneys
|
||||
sort.Slice(organizedCarpools, func(i, j int) bool {
|
||||
return *organizedCarpools[i].Distance < *organizedCarpools[j].Distance
|
||||
})
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
// CARPOOL OPERATORS
|
||||
carpools := make(chan *geojson.FeatureCollection)
|
||||
go h.services.InteropCarpool.Search(carpools, *departuregeo, *destinationgeo, departuredatetime)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for c := range carpools {
|
||||
carpool_results = append(carpool_results, c)
|
||||
}
|
||||
}()
|
||||
|
||||
// TRANSIT
|
||||
transitch := make(chan *motis.Itinerary)
|
||||
go func(transitch chan *motis.Itinerary, departure *geojson.Feature, destination *geojson.Feature, datetime *time.Time) {
|
||||
defer close(transitch)
|
||||
// timetableView := false
|
||||
searchWindows := 1800
|
||||
response, err := h.services.TransitRouting.PlanWithResponse(context.Background(), &motis.PlanParams{
|
||||
FromPlace: fmt.Sprintf("%f,%f", departure.Point().Lat(), departure.Point().Lon()),
|
||||
ToPlace: fmt.Sprintf("%f,%f", destination.Point().Lat(), destination.Point().Lon()),
|
||||
Time: datetime,
|
||||
// TimetableView: &timetableView,
|
||||
SearchWindow: &searchWindows,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
navitiaCh <- nil
|
||||
log.Error().Err(err).Msg("error retrieving transit data from MOTIS server")
|
||||
return
|
||||
}
|
||||
|
||||
request := navitia.JourneyRequest{
|
||||
From: types.ID(fmt.Sprintf("%f", departuregeo.Geometry.Point[0]) + ";" + fmt.Sprintf("%f", departuregeo.Geometry.Point[1])),
|
||||
To: types.ID(fmt.Sprintf("%f", destinationgeo.Geometry.Point[0]) + ";" + fmt.Sprintf("%f", destinationgeo.Geometry.Point[1])),
|
||||
Date: departuredatetime.Add(-2 * time.Hour),
|
||||
DateIsArrival: false, // TODO
|
||||
for _, i := range response.JSON200.Itineraries {
|
||||
transitch <- &i
|
||||
}
|
||||
|
||||
journeys, err = session.Journeys(context.Background(), request)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
// w.WriteHeader(http.StatusBadRequest)
|
||||
// return
|
||||
}(transitch, departuregeo, destinationgeo, &departuredatetime)
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for itinerary := range transitch {
|
||||
transit_results = append(transit_results, itinerary)
|
||||
}
|
||||
navitiaCh <- journeys
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SOLIDARITY TRANSPORT
|
||||
drivers, err := h.services.GetAccountsInNamespace("solidarity_drivers")
|
||||
if err != nil {
|
||||
drivers = []mobilityaccountsstorage.Account{}
|
||||
}
|
||||
for _, a := range drivers {
|
||||
if availabilities, ok := a.Data["solidarity_transport_availabilities"].([]any); ok {
|
||||
for _, availability := range availabilities {
|
||||
if av, ok := availability.(map[string]any); ok {
|
||||
day := av["day"].(float64)
|
||||
starttime := av["start_time"].(string)
|
||||
endtime := av["end_time"].(string)
|
||||
if departuretime >= starttime && departuretime <= endtime && departuredatetime.Weekday() == time.Weekday(int(day)) {
|
||||
availableDrivers = append(availableDrivers, a)
|
||||
break
|
||||
}()
|
||||
|
||||
// VEHICLES
|
||||
vehiclech := make(chan fleetsstorage.Vehicle)
|
||||
go h.vehicleRequest(vehiclech, departuredatetime.Add(-24*time.Hour), departuredatetime.Add(168*time.Hour))
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for vehicle := range vehiclech {
|
||||
vehicle_results = append(vehicle_results, vehicle)
|
||||
}
|
||||
slices.SortFunc(vehicle_results, sorting.VehiclesByDistanceFrom(*departuregeo))
|
||||
}()
|
||||
// journeys_results = <-navitiaCh
|
||||
wg.Wait()
|
||||
// KNOWLEDGE BASE
|
||||
departureGeo, _ := h.services.Geography.GeoSearch(departuregeo)
|
||||
kbData := h.config.Get("knowledge_base")
|
||||
if kb, ok := kbData.([]any); ok {
|
||||
log.Debug().Msg("1")
|
||||
for _, sol := range kb {
|
||||
log.Debug().Msg("2")
|
||||
if solution, ok := sol.(map[string]any); ok {
|
||||
log.Debug().Msg("3")
|
||||
if g, ok := solution["geography"]; ok {
|
||||
log.Debug().Msg("4")
|
||||
if geography, ok := g.([]any); ok {
|
||||
log.Debug().Msg("5")
|
||||
for _, gg := range geography {
|
||||
log.Debug().Msg("6")
|
||||
if geog, ok := gg.(map[string]any); ok {
|
||||
log.Debug().Msg("7")
|
||||
if layer, ok := geog["layer"].(string); ok {
|
||||
log.Debug().Msg("8")
|
||||
code := geog["code"]
|
||||
log.Debug().Any("code", fmt.Sprintf("%s", code)).Any("departure geo", departureGeo[layer].Properties.MustString("code")).Msg("9")
|
||||
if strings.Compare(fmt.Sprintf("%v", code), departureGeo[layer].Properties.MustString("code")) == 0 {
|
||||
log.Debug().Msg("10")
|
||||
kb_results = append(kb_results, solution)
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//CARPOOL
|
||||
carpoolRequest := func() {
|
||||
carpoolrequest := "https://api.rdex.ridygo.fr/journeys.json"
|
||||
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", carpoolrequest, nil)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
}
|
||||
|
||||
req.URL.RawQuery = fmt.Sprintf(
|
||||
"p[driver][state]=1&frequency=punctual&p[passenger][state]=0&p[from][latitude]=%f&p[from][longitude]=%f&p[to][latitude]=%f&p[to][longitude]=%f&p[outward][mindate]=%s&p[outward][maxdate]=%s",
|
||||
departuregeo.Geometry.Point[1], departuregeo.Geometry.Point[0],
|
||||
destinationgeo.Geometry.Point[1], destinationgeo.Geometry.Point[0],
|
||||
departuredatetime.Format("2006-01-02"), departuredatetime.Format("2006-01-02"))
|
||||
|
||||
req.Header.Set("X-API-KEY", "123456")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
}
|
||||
|
||||
if err == nil && resp.StatusCode == http.StatusOK {
|
||||
err = json.NewDecoder(resp.Body).Decode(&carpoolresults)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
}
|
||||
|
||||
if carpoolresults == nil {
|
||||
carpoolresults = []any{}
|
||||
}
|
||||
} else {
|
||||
carpoolresults = []any{}
|
||||
}
|
||||
carpoolCh <- carpoolresults
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Vehicles
|
||||
vehicleRequest := func() {
|
||||
vehiclerequest := &fleets.GetVehiclesRequest{
|
||||
Namespaces: []string{"parcoursmob"},
|
||||
}
|
||||
vehicleresp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), vehiclerequest)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
for _, vehicle := range vehicleresp.Vehicles {
|
||||
v := vehicle.ToStorageType()
|
||||
if v.Free(departuredatetime.Add(-24*time.Hour), departuredatetime.Add(168*time.Hour)) {
|
||||
vehicles = append(vehicles, v)
|
||||
}
|
||||
}
|
||||
vehiclech <- vehicles
|
||||
}
|
||||
go journeysRequest()
|
||||
go carpoolRequest()
|
||||
go vehicleRequest()
|
||||
carpool_results = <-carpoolCh
|
||||
journeys_results = <-navitiaCh
|
||||
vehicle_results = <-vehiclech
|
||||
}
|
||||
|
||||
h.Renderer.JourneysSearch(w, r, carpool_results, journeys_results, vehicle_results, searched, departuregeo, destinationgeo, departuredate, departuretime, availableDrivers)
|
||||
beneficiaries, err := h.beneficiaries(r)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("issue retrieving beneficiaries")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
h.Renderer.JourneysSearch(w, r, carpool_results, transit_results, vehicle_results, searched, departuregeo, destinationgeo, departuredate, departuretime, driverJourneys, drivers, organizedCarpools, beneficiaries, kb_results)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) vehicleRequest(vehiclech chan fleetsstorage.Vehicle, start time.Time, end time.Time) {
|
||||
defer close(vehiclech)
|
||||
vehiclerequest := &fleets.GetVehiclesRequest{
|
||||
Namespaces: []string{"parcoursmob"},
|
||||
}
|
||||
vehicleresp, err := h.services.GRPC.Fleets.GetVehicles(context.TODO(), vehiclerequest)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
return
|
||||
}
|
||||
for _, vehicle := range vehicleresp.Vehicles {
|
||||
v := vehicle.ToStorageType()
|
||||
if v.Free(start, end) {
|
||||
vehiclech <- v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type GroupsModule []groupstorage.Group
|
||||
|
||||
639
handlers/application/organized-carpool.go
Normal file
639
handlers/application/organized-carpool.go
Normal file
@@ -0,0 +1,639 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/utils/form-validators"
|
||||
filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage"
|
||||
"git.coopgo.io/coopgo-platform/carpool-service/servers/grpc/proto"
|
||||
mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
|
||||
mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/paulmach/orb"
|
||||
"github.com/paulmach/orb/geojson"
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type OrganizedCarpoolDriversForm 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"`
|
||||
FileNumber string `json:"file_number"`
|
||||
Address any `json:"address,omitempty"`
|
||||
AddressDestination any `json:"address_destination,omitempty"`
|
||||
Gender string `json:"gender"`
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) OrganizedCarpoolOverview(w http.ResponseWriter, r *http.Request) {
|
||||
accounts, err := h.organizedCarpoolDrivers(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.CarpoolService.GetCarpoolBookings(context.Background(), &proto.GetCarpoolBookingsRequest{
|
||||
MinDate: timestamppb.Now(),
|
||||
MaxDate: timestamppb.New(time.Now().Add(24 * 365 * time.Hour)),
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("issue retreving bookings")
|
||||
}
|
||||
|
||||
bookings := []*proto.CarpoolServiceBooking{}
|
||||
|
||||
if err == nil {
|
||||
for _, b := range bookingsproto.Bookings {
|
||||
// booking, _ := transformers.BookingProtoToType(b)
|
||||
bookings = append(bookings, b)
|
||||
}
|
||||
}
|
||||
|
||||
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 *proto.CarpoolServiceBooking) int {
|
||||
return cmp.Compare(a.PassengerPickupDate.AsTime().Unix(), b.PassengerPickupDate.AsTime().Unix())
|
||||
})
|
||||
|
||||
h.Renderer.OrganizedCarpoolOverview(w, r, accounts, accountsMap, beneficiariesMap, bookings)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) organizedCarpoolDrivers(r *http.Request) ([]mobilityaccountsstorage.Account, error) {
|
||||
accounts := []mobilityaccountsstorage.Account{}
|
||||
|
||||
request := &mobilityaccounts.GetAccountsRequest{
|
||||
Namespaces: []string{"organized_carpool_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) OrganizedCarpoolCreateDriver(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "POST" {
|
||||
dataMap, err := parseOrganizedCarpoolDriversForm(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: "organized_carpool_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/organized-carpool/drivers/%s", resp.Account.Id), http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
h.Renderer.OrganizedCarpoolCreateDriver(w, r)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) OrganizedCarpoolDriverDisplay(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
driverID := vars["driverid"]
|
||||
|
||||
documents := h.filestorage.List(filestorage.PREFIX_ORGANIZED_CARPOOL_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
|
||||
}
|
||||
|
||||
log.Info().Any("driver data", driver.Data).Msg("driver retrieved")
|
||||
|
||||
trips := []*geojson.FeatureCollection{}
|
||||
|
||||
resp, err := h.services.GRPC.CarpoolService.GetRegularRoutes(context.Background(), &proto.GetRegularRoutesRequest{
|
||||
UserId: driverID,
|
||||
})
|
||||
|
||||
for _, r := range resp.Routes {
|
||||
t, err := geojson.UnmarshalFeatureCollection([]byte(r.Serialized))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not unmarshall feature collection")
|
||||
continue
|
||||
}
|
||||
|
||||
trips = append(trips, t)
|
||||
}
|
||||
|
||||
h.Renderer.OrganizedCarpoolDriverDisplay(w, r, driver, trips, documents)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) OrganizedCarpoolArchiveDriver(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: "organized_carpool_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/organized-carpool/drivers/%s", resp.Account.Id), http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) OrganizedCarpoolUnarchiveDriver(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: "organized_carpool_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/organized-carpool/drivers/%s", resp.Account.Id), http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) OrganizedCarpoolDriverDocuments(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_ORGANIZED_CARPOOL_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/organized-carpool/drivers/%s", driverID), http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) OrganizedCarpoolDocumentDownload(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
driverID := vars["driverid"]
|
||||
document := vars["document"]
|
||||
|
||||
file, info, err := h.filestorage.Get(filestorage.PREFIX_ORGANIZED_CARPOOL_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) OrganizedCarpoolAddTrip(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"]
|
||||
|
||||
trips := []*proto.CarpoolFeatureCollection{}
|
||||
|
||||
outwardtime := r.PostFormValue("outwardtime")
|
||||
returntime := r.PostFormValue("returntime")
|
||||
dep := r.PostFormValue("address_departure")
|
||||
dest := r.PostFormValue("address_destination")
|
||||
|
||||
departure, err := geojson.UnmarshalFeature([]byte(dep))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed parsong departure geojson")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
destination, err := geojson.UnmarshalFeature([]byte(dest))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed parsong departure geojson")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
outwardroute, err := h.services.Routing.Route([]orb.Point{departure.Point(), destination.Point()})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed calling route search")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
returnroute, err := h.services.Routing.Route([]orb.Point{destination.Point(), departure.Point()})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed calling route search")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
outwardschedules := []map[string]any{}
|
||||
returnschedules := []map[string]any{}
|
||||
|
||||
if r.PostFormValue("days.monday") == "on" {
|
||||
outwardschedules = append(outwardschedules, map[string]any{
|
||||
"day": "MON",
|
||||
"time_of_day": outwardtime,
|
||||
})
|
||||
returnschedules = append(returnschedules, map[string]any{
|
||||
"day": "MON",
|
||||
"time_of_day": returntime,
|
||||
})
|
||||
}
|
||||
if r.PostFormValue("days.tuesday") == "on" {
|
||||
outwardschedules = append(outwardschedules, map[string]any{
|
||||
"day": "TUE",
|
||||
"time_of_day": outwardtime,
|
||||
})
|
||||
returnschedules = append(returnschedules, map[string]any{
|
||||
"day": "TUE",
|
||||
"time_of_day": returntime,
|
||||
})
|
||||
}
|
||||
if r.PostFormValue("days.wednesday") == "on" {
|
||||
outwardschedules = append(outwardschedules, map[string]any{
|
||||
"day": "WED",
|
||||
"time_of_day": outwardtime,
|
||||
})
|
||||
returnschedules = append(returnschedules, map[string]any{
|
||||
"day": "WED",
|
||||
"time_of_day": returntime,
|
||||
})
|
||||
}
|
||||
if r.PostFormValue("days.thursday") == "on" {
|
||||
outwardschedules = append(outwardschedules, map[string]any{
|
||||
"day": "THU",
|
||||
"time_of_day": outwardtime,
|
||||
})
|
||||
returnschedules = append(returnschedules, map[string]any{
|
||||
"day": "THU",
|
||||
"time_of_day": returntime,
|
||||
})
|
||||
}
|
||||
if r.PostFormValue("days.friday") == "on" {
|
||||
outwardschedules = append(outwardschedules, map[string]any{
|
||||
"day": "FRI",
|
||||
"time_of_day": outwardtime,
|
||||
})
|
||||
returnschedules = append(returnschedules, map[string]any{
|
||||
"day": "FRI",
|
||||
"time_of_day": returntime,
|
||||
})
|
||||
}
|
||||
if r.PostFormValue("days.saturday") == "on" {
|
||||
outwardschedules = append(outwardschedules, map[string]any{
|
||||
"day": "SAT",
|
||||
"time_of_day": outwardtime,
|
||||
})
|
||||
returnschedules = append(returnschedules, map[string]any{
|
||||
"day": "SAT",
|
||||
"time_of_day": returntime,
|
||||
})
|
||||
}
|
||||
if r.PostFormValue("days.sunday") == "on" {
|
||||
outwardschedules = append(outwardschedules, map[string]any{
|
||||
"day": "SUN",
|
||||
"time_of_day": outwardtime,
|
||||
})
|
||||
returnschedules = append(returnschedules, map[string]any{
|
||||
"day": "SUN",
|
||||
"time_of_day": returntime,
|
||||
})
|
||||
}
|
||||
|
||||
outward_fc := geojson.NewFeatureCollection()
|
||||
outward_fc.Append(departure)
|
||||
outward_fc.Append(destination)
|
||||
outward_fc.ExtraMembers = geojson.Properties{}
|
||||
outward_fc.ExtraMembers["properties"] = map[string]any{
|
||||
"is_driver": true,
|
||||
"is_passenger": false,
|
||||
"user": mobilityaccountsstorage.Account{
|
||||
ID: driverID,
|
||||
},
|
||||
"polyline": outwardroute.Summary.Polyline,
|
||||
"schedules": outwardschedules,
|
||||
"driver_options": map[string]any{},
|
||||
"passenger_options": map[string]any{},
|
||||
}
|
||||
outwardtrip, err := outward_fc.MarshalJSON()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed parsong return geojson")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
return_fc := geojson.NewFeatureCollection()
|
||||
return_fc.Append(destination)
|
||||
return_fc.Append(departure)
|
||||
return_fc.ExtraMembers = geojson.Properties{}
|
||||
return_fc.ExtraMembers["properties"] = map[string]any{
|
||||
"is_driver": true,
|
||||
"is_passenger": false,
|
||||
"user": mobilityaccountsstorage.Account{
|
||||
ID: driverID,
|
||||
},
|
||||
"polyline": returnroute.Summary.Polyline,
|
||||
"schedules": returnschedules,
|
||||
"driver_options": map[string]any{},
|
||||
"passenger_options": map[string]any{},
|
||||
}
|
||||
returntrip, err := return_fc.MarshalJSON()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed parsong return geojson")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
trips = append(trips, &proto.CarpoolFeatureCollection{
|
||||
Serialized: string(outwardtrip),
|
||||
})
|
||||
trips = append(trips, &proto.CarpoolFeatureCollection{
|
||||
Serialized: string(returntrip),
|
||||
})
|
||||
|
||||
req := &proto.CreateRegularRoutesRequest{
|
||||
Routes: trips,
|
||||
}
|
||||
_, err = h.services.GRPC.CarpoolService.CreateRegularRoutes(context.Background(), req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not create regular routes")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
log.Info().Msg("Finished creating carpool routes")
|
||||
http.Redirect(w, r, fmt.Sprintf("/app/organized-carpool/drivers/%s", driverID), http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) OrganizedCarpoolDeleteTrip(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
driverID := vars["driverid"]
|
||||
tripID := vars["tripid"]
|
||||
|
||||
req := &proto.DeleteRegularRoutesRequest{
|
||||
Ids: []string{tripID},
|
||||
}
|
||||
|
||||
_, err := h.services.GRPC.CarpoolService.DeleteRegularRoutes(context.Background(), req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not delete regular routes")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, fmt.Sprintf("/app/organized-carpool/drivers/%s", driverID), http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) OrganizedCarpoolJourney(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).Str("passengerid", passengerId).Msg("driver journey")
|
||||
|
||||
journeyResp, err := h.services.GRPC.CarpoolService.GetPlannedTrip(context.Background(), &proto.GetPlannedTripRequest{
|
||||
Id: journeyId,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not get driver journey")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
journey, err := geojson.UnmarshalFeatureCollection([]byte(journeyResp.PlannedTrip.Serialized))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not unmarshal driver journey")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == "POST" {
|
||||
if passengerId == "" {
|
||||
log.Error().Err(err).Msg("could not get driver journey")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
/*if _, err := h.services.GRPC.CarpoolService.CreateBooking(context.Background(), &proto.CreateCarpoolBookingRequest{
|
||||
Booking: &proto.CarpoolServiceBooking{
|
||||
Passenger: &proto.CarpoolServiceUser{
|
||||
Id: passengerId,
|
||||
},
|
||||
Driver: &proto.CarpoolServiceUser{
|
||||
Id: driverId,
|
||||
},
|
||||
}
|
||||
PassengerId: passengerId,
|
||||
DriverId: driverId,
|
||||
DriverJourneyId: journeyId,
|
||||
}); err != nil {
|
||||
log.Error().Err(err).Msg("cannot create booking")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}*/
|
||||
http.Redirect(w, r, fmt.Sprintf("/app/organized_carpool/"), 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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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.OrganizedCarpoolJourney(w, r, journey, driver, passenger, beneficiaries)
|
||||
}
|
||||
|
||||
func parseOrganizedCarpoolDriversForm(r *http.Request) (map[string]any, error) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Info().Any("form content", r.Form).Msg("parsing form")
|
||||
|
||||
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 := OrganizedCarpoolDriversForm{
|
||||
FirstName: r.PostFormValue("first_name"),
|
||||
LastName: r.PostFormValue("last_name"),
|
||||
Email: r.PostFormValue("email"),
|
||||
Birthdate: date,
|
||||
PhoneNumber: r.PostFormValue("phone_number"),
|
||||
FileNumber: r.PostFormValue("file_number"),
|
||||
Gender: r.PostFormValue("gender"),
|
||||
}
|
||||
|
||||
if r.PostFormValue("address") != "" {
|
||||
var a any
|
||||
json.Unmarshal([]byte(r.PostFormValue("address")), &a)
|
||||
|
||||
formData.Address = a
|
||||
}
|
||||
|
||||
if r.PostFormValue("address_destination") != "" {
|
||||
var a any
|
||||
json.Unmarshal([]byte(r.PostFormValue("address_destination")), &a)
|
||||
|
||||
formData.AddressDestination = 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
|
||||
}
|
||||
58
handlers/application/sms.go
Normal file
58
handlers/application/sms.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (h *ApplicationHandler) SendSMS(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
referer := r.Referer()
|
||||
|
||||
if err := r.ParseForm(); err != nil {
|
||||
log.Error().Err(err).Msg("Bad request")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
message := r.PostFormValue("message")
|
||||
beneficiaryid := r.PostFormValue("beneficiaryid")
|
||||
|
||||
h.GenerateSMS(beneficiaryid, message)
|
||||
|
||||
http.Redirect(w, r, referer, http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) GenerateSMS(recipientid string, message string) error {
|
||||
recipient, err := h.services.GetAccount(recipientid)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("user not found")
|
||||
return err
|
||||
}
|
||||
|
||||
pn, ok := recipient.Data["phone_number"]
|
||||
if !ok {
|
||||
log.Error().Msg("Beneficiary doesn't have a phone number")
|
||||
return errors.New("missing phone number")
|
||||
}
|
||||
phoneNumber, ok := pn.(string)
|
||||
if !ok {
|
||||
log.Error().Msg("phone number type error")
|
||||
return errors.New("phone number type error")
|
||||
}
|
||||
|
||||
sender := h.config.GetString("service_name")
|
||||
|
||||
err = h.services.SMS.Send(phoneNumber, message, sender)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("cannot send SMS")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
80
handlers/application/solidarity-transport-ext.go
Normal file
80
handlers/application/solidarity-transport-ext.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/proto/gen"
|
||||
"git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/transformers"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (h *ApplicationHandler) SolidarityTransportExternalBookingProposal(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,
|
||||
})
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if r.Method == "POST" {
|
||||
if err = r.ParseForm(); err != nil {
|
||||
log.Error().Err(err).Msg("error parsing form data")
|
||||
}
|
||||
message := r.FormValue("message")
|
||||
action := r.FormValue("action")
|
||||
var status string
|
||||
if action == "confirm" {
|
||||
status = "VALIDATED"
|
||||
} else if action == "cancel" {
|
||||
status = "CANCELLED"
|
||||
} 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: "Refusé par le bénévole",
|
||||
}); err != nil {
|
||||
log.Error().Err(err).Msg("update booking status issue")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
booking.Status = status
|
||||
if status == "VALIDATED" {
|
||||
h.GenerateSMS(passenger.ID, message)
|
||||
} else if status == "CANCELLED" {
|
||||
if err := h.creditWallet(passenger.ID, booking.Journey.Price.Amount); err != nil {
|
||||
log.Error().Err(err).Msg("could not credit wallet")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h.Renderer.SolidarityTransportExternalBookingDisplay(w, r, booking, driver, passenger)
|
||||
}
|
||||
@@ -1,23 +1,34 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"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"
|
||||
mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
|
||||
mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage"
|
||||
)
|
||||
|
||||
type DriversForm struct {
|
||||
@@ -43,16 +54,68 @@ const (
|
||||
func (h *ApplicationHandler) SolidarityTransportOverview(w http.ResponseWriter, r *http.Request) {
|
||||
accounts, err := h.solidarityDrivers(r)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
log.Error().Err(err).Msg("issue getting solidarity drivers")
|
||||
accounts = []mobilityaccountsstorage.Account{}
|
||||
}
|
||||
|
||||
sort.Sort(sorting.SolidarityDriversByName(accounts))
|
||||
accountsMap := map[string]mobilityaccountsstorage.Account{}
|
||||
|
||||
// cacheid := uuid.NewString()
|
||||
// h.cache.PutWithTTL(cacheid, accounts, 1*time.Hour)
|
||||
h.Renderer.SolidarityTransportOverview(w, r, accounts)
|
||||
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) {
|
||||
@@ -92,7 +155,7 @@ func (h *ApplicationHandler) SolidarityTransportCreateDriver(w http.ResponseWrit
|
||||
h.Renderer.SolidarityTransportCreateDriver(w, r)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) SolidarityTransportDriverDisplay(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *ApplicationHandler) SolidarityTransportUpdateDriver(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
driverID := vars["driverid"]
|
||||
|
||||
@@ -102,7 +165,94 @@ func (h *ApplicationHandler) SolidarityTransportDriverDisplay(w http.ResponseWri
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
h.Renderer.SolidarityTransportDriverDisplay(w, r, driver)
|
||||
|
||||
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) {
|
||||
@@ -121,105 +271,164 @@ func (h *ApplicationHandler) SolidarityTransportAddAvailability(w http.ResponseW
|
||||
vars := mux.Vars(r)
|
||||
driverID := vars["driverid"]
|
||||
|
||||
availabilities := []any{}
|
||||
availabilities := []*gen.DriverRegularAvailability{}
|
||||
|
||||
starttime := r.PostFormValue("starttime")
|
||||
endtime := r.PostFormValue("endtime")
|
||||
address := r.PostFormValue("address")
|
||||
|
||||
if r.PostFormValue("days.monday") == "on" {
|
||||
a := map[string]any{
|
||||
"id": uuid.NewString(),
|
||||
"day": Monday,
|
||||
"start_time": r.PostFormValue("starttime"),
|
||||
"end_time": r.PostFormValue("endtime"),
|
||||
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 := map[string]any{
|
||||
"id": uuid.NewString(),
|
||||
"day": Tuesday,
|
||||
"start_time": r.PostFormValue("starttime"),
|
||||
"end_time": r.PostFormValue("endtime"),
|
||||
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 := map[string]any{
|
||||
"id": uuid.NewString(),
|
||||
"day": Wednesday,
|
||||
"start_time": r.PostFormValue("starttime"),
|
||||
"end_time": r.PostFormValue("endtime"),
|
||||
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 := map[string]any{
|
||||
"id": uuid.NewString(),
|
||||
"day": Thursday,
|
||||
"start_time": r.PostFormValue("starttime"),
|
||||
"end_time": r.PostFormValue("endtime"),
|
||||
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 := map[string]any{
|
||||
"id": uuid.NewString(),
|
||||
"day": Friday,
|
||||
"start_time": r.PostFormValue("starttime"),
|
||||
"end_time": r.PostFormValue("endtime"),
|
||||
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 := map[string]any{
|
||||
"id": uuid.NewString(),
|
||||
"day": Saturday,
|
||||
"start_time": r.PostFormValue("starttime"),
|
||||
"end_time": r.PostFormValue("endtime"),
|
||||
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 := map[string]any{
|
||||
"id": uuid.NewString(),
|
||||
"day": Sunday,
|
||||
"start_time": r.PostFormValue("starttime"),
|
||||
"end_time": r.PostFormValue("endtime"),
|
||||
a := &gen.DriverRegularAvailability{
|
||||
DriverId: driverID,
|
||||
Day: Sunday,
|
||||
StartTime: starttime,
|
||||
EndTime: endtime,
|
||||
Address: &gen.GeoJsonFeature{
|
||||
Serialized: address,
|
||||
},
|
||||
}
|
||||
availabilities = append(availabilities, a)
|
||||
}
|
||||
|
||||
account, err := h.services.GetAccount(driverID)
|
||||
req := &gen.AddDriverRegularAvailabilitiesRequest{
|
||||
Availabilities: availabilities,
|
||||
}
|
||||
_, err := h.services.GRPC.SolidarityTransport.AddDriverRegularAvailabilities(context.Background(), req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("driver not found")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
log.Error().Err(err).Msg("could not add availabilities")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
existing_availabilities, ok := account.Data["solidarity_transport_availabilities"].([]any)
|
||||
if !ok {
|
||||
existing_availabilities = []any{}
|
||||
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(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, av := range availabilities {
|
||||
existing_availabilities = append(existing_availabilities, av)
|
||||
}
|
||||
|
||||
account.Data["solidarity_transport_availabilities"] = existing_availabilities
|
||||
data, err := structpb.NewValue(account.Data)
|
||||
resp, err := h.services.GRPC.MobilityAccounts.UpdateData(context.TODO(), request)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
request := &mobilityaccounts.UpdateDataRequest{
|
||||
Account: &mobilityaccounts.Account{
|
||||
Id: account.ID,
|
||||
Namespace: account.Namespace,
|
||||
Data: data.GetStructValue(),
|
||||
},
|
||||
}
|
||||
_, err = h.services.GRPC.MobilityAccounts.UpdateData(context.TODO(), request)
|
||||
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
|
||||
@@ -228,61 +437,402 @@ func (h *ApplicationHandler) SolidarityTransportAddAvailability(w http.ResponseW
|
||||
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"]
|
||||
|
||||
account, err := h.services.GetAccount(driverID)
|
||||
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("driver not found")
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
existing_availabilities, ok := account.Data["solidarity_transport_availabilities"].([]any)
|
||||
if !ok {
|
||||
log.Error().Err(errors.New("no availability found")).Msg("no availability")
|
||||
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)),
|
||||
})
|
||||
|
||||
new_availabilities := []any{}
|
||||
|
||||
for _, av := range existing_availabilities {
|
||||
log.Info().Str("type", reflect.TypeOf(av).Name()).Msg("info on type")
|
||||
if m, ok := av.(map[string]any); ok {
|
||||
if id, ok2 := m["id"].(string); ok2 {
|
||||
if id != availabilityID {
|
||||
new_availabilities = append(new_availabilities, av)
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
account.Data["solidarity_transport_availabilities"] = new_availabilities
|
||||
data, err := structpb.NewValue(account.Data)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request := &mobilityaccounts.UpdateDataRequest{
|
||||
Account: &mobilityaccounts.Account{
|
||||
Id: account.ID,
|
||||
Namespace: account.Namespace,
|
||||
Data: data.GetStructValue(),
|
||||
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")
|
||||
}
|
||||
_, err = h.services.GRPC.MobilityAccounts.UpdateData(context.TODO(), request)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound)
|
||||
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) {
|
||||
@@ -356,3 +906,22 @@ func (h *ApplicationHandler) solidarityDrivers(r *http.Request) ([]mobilityaccou
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/identification"
|
||||
"git.coopgo.io/coopgo-platform/emailing"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
@@ -13,7 +12,6 @@ type Message struct {
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) SupportSend(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
c := r.Context().Value(identification.ClaimsKey)
|
||||
if c == nil {
|
||||
log.Error().Msg("no current user claims")
|
||||
@@ -23,11 +21,10 @@ func (h *ApplicationHandler) SupportSend(w http.ResponseWriter, r *http.Request)
|
||||
current_user_claims := c.(map[string]any)
|
||||
|
||||
comment := r.PostFormValue(("comment"))
|
||||
|
||||
|
||||
if r.Method == "POST" {
|
||||
user_email := current_user_claims["email"].(string)
|
||||
|
||||
|
||||
data := map[string]any{
|
||||
"key": comment,
|
||||
"user": user_email,
|
||||
@@ -35,10 +32,10 @@ func (h *ApplicationHandler) SupportSend(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
log.Debug().Str("user_email", user_email).Msg("Sending message")
|
||||
|
||||
if err := h.emailing.Send("support.request", "support@parcoursmob.fr", data, emailing.WithReplyTo(user_email), emailing.WithTLSOpportunistic()); err != nil {
|
||||
if err := h.emailing.Send("support.request", "support@parcoursmob.fr", data); err != nil {
|
||||
log.Error().Err(err).Msg("error sending email")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/app/", http.StatusFound)
|
||||
return
|
||||
|
||||
@@ -11,8 +11,6 @@ import (
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/identification"
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting"
|
||||
filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage"
|
||||
diags "git.coopgo.io/coopgo-platform/diags/grpcapi"
|
||||
diagsstorage "git.coopgo.io/coopgo-platform/diags/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"
|
||||
@@ -205,30 +203,30 @@ func (h *ApplicationHandler) VehiclesFleetDisplay(w http.ResponseWriter, r *http
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
diag := []diagsstorage.Diag{}
|
||||
/*diag := []diagsstorage.Diag{}
|
||||
|
||||
diagsrequest := &diags.GetDiagsRequest{
|
||||
Namespaces: []string{"parcoursmob_vehicles"},
|
||||
}
|
||||
|
||||
diagsresp, err := h.services.GRPC.Diags.GetDiags(context.TODO(), diagsrequest)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("did not retrieve diags")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for _, d := range diagsresp.Diags {
|
||||
diagData := d.Data.AsMap()
|
||||
if vehicle, ok := diagData["vehicle"].(string); ok && vehicle == vehicleid {
|
||||
diag = append(diag, d.ToStorageType())
|
||||
diagsresp, err := h.services.GRPC.Diags.GetDiags(context.TODO(), diagsrequest)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("did not retrieve diags")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
diagsAny := make([]any, len(diag))
|
||||
for i, d := range diag {
|
||||
for _, d := range diagsresp.Diags {
|
||||
diagData := d.Data.AsMap()
|
||||
if vehicle, ok := diagData["vehicle"].(string); ok && vehicle == vehicleid {
|
||||
diag = append(diag, d.ToStorageType())
|
||||
}
|
||||
} */
|
||||
|
||||
diagsAny := []any{}
|
||||
/*for i, d := range diag {
|
||||
diagsAny[i] = d
|
||||
}
|
||||
}*/
|
||||
|
||||
h.Renderer.VehiclesFleetDisplay(w, r, resp.Vehicle.ToStorageType(), beneficiaries, diagsAny)
|
||||
}
|
||||
@@ -362,30 +360,30 @@ func (h ApplicationHandler) VehicleManagementBookingDisplay(w http.ResponseWrite
|
||||
documents := h.filestorage.List(filestorage.PREFIX_BOOKINGS + "/" + bookingid)
|
||||
file_types_map := h.config.GetStringMapString("storage.files.file_types")
|
||||
|
||||
diag := []diagsstorage.Diag{}
|
||||
/* diag := []diagsstorage.Diag{}
|
||||
|
||||
diagsrequest := &diags.GetDiagsRequest{
|
||||
Namespaces: []string{"parcoursmob_bookings"},
|
||||
}
|
||||
|
||||
diagsresp, err := h.services.GRPC.Diags.GetDiags(context.TODO(), diagsrequest)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for _, d := range diagsresp.Diags {
|
||||
diagData := d.Data.AsMap()
|
||||
if booking, ok := diagData["booking"].(string); ok && booking == bookingid {
|
||||
diag = append(diag, d.ToStorageType())
|
||||
diagsrequest := &diags.GetDiagsRequest{
|
||||
Namespaces: []string{"parcoursmob_bookings"},
|
||||
}
|
||||
}
|
||||
|
||||
diagsAny := make([]any, len(diag))
|
||||
for i, d := range diag {
|
||||
diagsresp, err := h.services.GRPC.Diags.GetDiags(context.TODO(), diagsrequest)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for _, d := range diagsresp.Diags {
|
||||
diagData := d.Data.AsMap()
|
||||
if booking, ok := diagData["booking"].(string); ok && booking == bookingid {
|
||||
diag = append(diag, d.ToStorageType())
|
||||
}
|
||||
}*/
|
||||
|
||||
diagsAny := []any{}
|
||||
/*for i, d := range diag {
|
||||
diagsAny[i] = d
|
||||
}
|
||||
}*/
|
||||
|
||||
h.Renderer.VehicleManagementBookingDisplay(w, r, booking, booking.Vehicle, beneficiary, groupresp.Group.ToStorageType(), documents, file_types_map, alternatives, diagsAny)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -12,8 +14,6 @@ import (
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/identification"
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/sorting"
|
||||
filestorage "git.coopgo.io/coopgo-apps/parcoursmob/utils/storage"
|
||||
diags "git.coopgo.io/coopgo-platform/diags/grpcapi"
|
||||
diagsstorage "git.coopgo.io/coopgo-platform/diags/storage"
|
||||
fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi"
|
||||
"git.coopgo.io/coopgo-platform/fleets/storage"
|
||||
groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi"
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
|
||||
"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"
|
||||
@@ -33,7 +34,7 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques
|
||||
|
||||
beneficiarydocuments := []filestorage.FileInfo{}
|
||||
|
||||
vehicles := []any{}
|
||||
vehicles := []storage.Vehicle{}
|
||||
searched := false
|
||||
start := r.FormValue("startdate")
|
||||
end := r.FormValue("enddate")
|
||||
@@ -100,6 +101,21 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques
|
||||
vehicles = append(vehicles, v)
|
||||
}
|
||||
|
||||
// Sort vehicles if beneficiary address is set
|
||||
if beneficiaryAddress, ok := beneficiary.Data["address"]; ok {
|
||||
beneficiaryAddressJson, err := json.Marshal(beneficiaryAddress)
|
||||
if err == nil {
|
||||
beneficiaryAddressGeojson, err := geojson.UnmarshalFeature(beneficiaryAddressJson)
|
||||
if err == nil {
|
||||
slices.SortFunc(vehicles, sorting.VehiclesByDistanceFrom(*beneficiaryAddressGeojson))
|
||||
} else {
|
||||
log.Error().Err(err).Msg("error transforming beneficiary address to GeoJSON")
|
||||
}
|
||||
} else {
|
||||
log.Error().Err(err).Msg("error transforming beneficiary address to JSON")
|
||||
}
|
||||
}
|
||||
|
||||
beneficiarydocuments = h.filestorage.List(filestorage.PREFIX_BENEFICIARIES + "/" + beneficiary.ID)
|
||||
}
|
||||
|
||||
@@ -307,7 +323,7 @@ func (h ApplicationHandler) VehicleBookingDisplay(w http.ResponseWriter, r *http
|
||||
documents := h.filestorage.List(filestorage.PREFIX_BOOKINGS + "/" + bookingid)
|
||||
file_types_map := h.config.GetStringMapString("storage.files.file_types")
|
||||
|
||||
diag := []diagsstorage.Diag{}
|
||||
/*diag := []diagsstorage.Diag{}
|
||||
|
||||
diagsrequest := &diags.GetDiagsRequest{
|
||||
Namespaces: []string{"parcoursmob_bookings"},
|
||||
@@ -325,12 +341,12 @@ func (h ApplicationHandler) VehicleBookingDisplay(w http.ResponseWriter, r *http
|
||||
if booking, ok := diagData["booking"].(string); ok && booking == bookingid {
|
||||
diag = append(diag, d.ToStorageType())
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
diagsAny := make([]any, len(diag))
|
||||
for i, d := range diag {
|
||||
diagsAny := []any{}
|
||||
/*for i, d := range diag {
|
||||
diagsAny[i] = d
|
||||
}
|
||||
}*/
|
||||
|
||||
h.Renderer.VehicleBookingDisplay(w, r, booking, booking.Vehicle, beneficiaryresp.Account.ToStorageType(), groupresp.Group.ToStorageType(), documents, file_types_map, diagsAny)
|
||||
}
|
||||
|
||||
69
handlers/application/wallets.go
Normal file
69
handlers/application/wallets.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (h ApplicationHandler) CreditWallet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
userid := vars["userid"]
|
||||
|
||||
if r.Method != "POST" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
r.ParseForm()
|
||||
|
||||
amountStr := r.FormValue("amount")
|
||||
|
||||
amount, err := strconv.ParseFloat(amountStr, 64)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not read amount")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.creditWallet(userid, amount); err != nil {
|
||||
log.Error().Err(err).Msg("could not credit wallet")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, r.Referer(), http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *ApplicationHandler) creditWallet(userid string, amount float64) error {
|
||||
account, err := h.services.GetAccount(userid)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not retrieve account")
|
||||
return err
|
||||
}
|
||||
|
||||
if account.Data["wallet"] == nil {
|
||||
account.Data["wallet"] = float64(0)
|
||||
}
|
||||
|
||||
account.Data["wallet"] = account.Data["wallet"].(float64) + amount
|
||||
accountproto, err := grpcapi.AccountFromStorageType(&account)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("account type transformation issue")
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = h.services.GRPC.MobilityAccounts.UpdateData(context.Background(), &grpcapi.UpdateDataRequest{
|
||||
Account: accountproto,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("account type transformation issue")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user