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