321 lines
9.9 KiB
Go
321 lines
9.9 KiB
Go
package xlsx
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"git.coopgo.io/coopgo-apps/parcoursmob/core/application"
|
|
"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/gender"
|
|
"github.com/paulmach/orb/geojson"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
func (r *XLSXRenderer) SolidarityTransportBookings(w http.ResponseWriter, result *application.SolidarityTransportBookingsResult) {
|
|
// Create Excel spreadsheet
|
|
spreadsheet := r.NewSpreadsheet("Transport solidaire")
|
|
|
|
// Build headers dynamically based on configuration
|
|
headers := []string{
|
|
"ID Réservation",
|
|
"Statut",
|
|
"Motif de réservation",
|
|
"Raison d'annulation",
|
|
"Date de prise en charge",
|
|
"Heure de prise en charge",
|
|
}
|
|
|
|
// Add driver fields from config
|
|
driverOptionalFields := r.Config.Get("modules.solidarity_transport.profile_optional_fields")
|
|
driverFields := []string{"last_name", "first_name", "email", "phone_number"}
|
|
driverHeaders := []string{"Conducteur - Nom", "Conducteur - Prénom", "Conducteur - Email", "Conducteur - Téléphone"}
|
|
|
|
if driverOptionalFieldsList, ok := driverOptionalFields.([]interface{}); ok {
|
|
for _, field := range driverOptionalFieldsList {
|
|
if fieldMap, ok := field.(map[string]interface{}); ok {
|
|
if name, ok := fieldMap["name"].(string); ok {
|
|
driverFields = append(driverFields, name)
|
|
label := name
|
|
if labelVal, ok := fieldMap["label"].(string); ok {
|
|
label = labelVal
|
|
}
|
|
driverHeaders = append(driverHeaders, fmt.Sprintf("Conducteur - %s", label))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
headers = append(headers, driverHeaders...)
|
|
|
|
// Add beneficiary fields from config
|
|
beneficiaryOptionalFields := r.Config.Get("modules.beneficiaries.profile_optional_fields")
|
|
beneficiaryFields := []string{"last_name", "first_name", "email", "phone_number"}
|
|
beneficiaryHeaders := []string{"Bénéficiaire - Nom", "Bénéficiaire - Prénom", "Bénéficiaire - Email", "Bénéficiaire - Téléphone"}
|
|
|
|
if beneficiaryOptionalFieldsList, ok := beneficiaryOptionalFields.([]interface{}); ok {
|
|
for _, field := range beneficiaryOptionalFieldsList {
|
|
if fieldMap, ok := field.(map[string]interface{}); ok {
|
|
if name, ok := fieldMap["name"].(string); ok {
|
|
beneficiaryFields = append(beneficiaryFields, name)
|
|
label := name
|
|
if labelVal, ok := fieldMap["label"].(string); ok {
|
|
label = labelVal
|
|
}
|
|
beneficiaryHeaders = append(beneficiaryHeaders, fmt.Sprintf("Bénéficiaire - %s", label))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
headers = append(headers, beneficiaryHeaders...)
|
|
|
|
// Add journey information headers
|
|
headers = append(headers,
|
|
"Lieu de départ - Adresse",
|
|
"Lieu de départ - Latitude",
|
|
"Lieu de départ - Longitude",
|
|
"Destination - Adresse",
|
|
"Destination - Latitude",
|
|
"Destination - Longitude",
|
|
"Distance passager (km)",
|
|
"Distance conducteur totale (km)",
|
|
"Durée trajet (minutes)",
|
|
"Prix passager",
|
|
"Devise prix passager",
|
|
"Compensation conducteur",
|
|
"Devise compensation",
|
|
"Temps d'attente retour",
|
|
"Aller simple",
|
|
"Départ conducteur - Adresse",
|
|
"Départ conducteur - Latitude",
|
|
"Départ conducteur - Longitude",
|
|
"Arrivée conducteur - Adresse",
|
|
"Arrivée conducteur - Latitude",
|
|
"Arrivée conducteur - Longitude",
|
|
)
|
|
|
|
spreadsheet.SetHeaders(headers)
|
|
|
|
// Add data rows
|
|
for _, booking := range result.Bookings {
|
|
driver := result.DriversMap[booking.DriverId]
|
|
beneficiary := result.BeneficiariesMap[booking.PassengerId]
|
|
|
|
row := []interface{}{}
|
|
|
|
// Booking information
|
|
row = append(row, booking.Id)
|
|
row = append(row, booking.Status)
|
|
|
|
// Motivation (from booking.Data)
|
|
motivation := ""
|
|
if booking.Data != nil {
|
|
if motivationVal, ok := booking.Data["motivation"]; ok && motivationVal != nil {
|
|
motivation = fmt.Sprint(motivationVal)
|
|
}
|
|
}
|
|
row = append(row, motivation)
|
|
|
|
// Cancellation reason (from booking.Data)
|
|
cancellationReason := ""
|
|
if booking.Data != nil {
|
|
if reasonVal, ok := booking.Data["reason"]; ok && reasonVal != nil {
|
|
cancellationReason = fmt.Sprint(reasonVal)
|
|
}
|
|
}
|
|
row = append(row, cancellationReason)
|
|
|
|
// Journey date and time
|
|
if booking.Journey != nil {
|
|
row = append(row, booking.Journey.PassengerPickupDate.Format("2006-01-02"))
|
|
row = append(row, booking.Journey.PassengerPickupDate.Format("15:04"))
|
|
} else {
|
|
row = append(row, "", "")
|
|
}
|
|
|
|
// Driver data
|
|
for _, field := range driverFields {
|
|
row = append(row, getAccountFieldValue(driver.Data, field))
|
|
}
|
|
|
|
// Beneficiary data
|
|
for _, field := range beneficiaryFields {
|
|
row = append(row, getAccountFieldValue(beneficiary.Data, field))
|
|
}
|
|
|
|
// Journey locations and details
|
|
if booking.Journey != nil {
|
|
// Passenger pickup
|
|
pickupAddr, pickupLat, pickupLon := getLocationData(booking.Journey.PassengerPickup)
|
|
row = append(row, pickupAddr, pickupLat, pickupLon)
|
|
|
|
// Passenger drop
|
|
dropAddr, dropLat, dropLon := getLocationData(booking.Journey.PassengerDrop)
|
|
row = append(row, dropAddr, dropLat, dropLon)
|
|
|
|
// Distances and duration
|
|
row = append(row, booking.Journey.PassengerDistance)
|
|
row = append(row, booking.Journey.DriverDistance)
|
|
row = append(row, int64(booking.Journey.Duration.Minutes()))
|
|
|
|
// Pricing
|
|
row = append(row, fmt.Sprintf("%.2f", booking.Journey.Price.Amount))
|
|
row = append(row, booking.Journey.Price.Currency)
|
|
|
|
// Driver compensation
|
|
if booking.DriverCompensationAmount > 0 {
|
|
row = append(row, fmt.Sprintf("%.2f", booking.DriverCompensationAmount))
|
|
row = append(row, booking.DriverCompensationCurrency)
|
|
} else {
|
|
row = append(row, "", "")
|
|
}
|
|
|
|
// Return wait time
|
|
row = append(row, "")
|
|
|
|
// One way trip (Noreturn field)
|
|
if booking.Journey.Noreturn {
|
|
row = append(row, "Oui")
|
|
} else {
|
|
row = append(row, "Non")
|
|
}
|
|
|
|
// Driver departure
|
|
driverDepartAddr, driverDepartLat, driverDepartLon := getLocationData(booking.Journey.DriverDeparture)
|
|
row = append(row, driverDepartAddr, driverDepartLat, driverDepartLon)
|
|
|
|
// Driver arrival
|
|
driverArrivalAddr, driverArrivalLat, driverArrivalLon := getLocationData(booking.Journey.DriverArrival)
|
|
row = append(row, driverArrivalAddr, driverArrivalLat, driverArrivalLon)
|
|
} else {
|
|
// No journey data - fill with empty values
|
|
for i := 0; i < 21; i++ {
|
|
row = append(row, "")
|
|
}
|
|
}
|
|
|
|
spreadsheet.AddRow(row)
|
|
}
|
|
|
|
// Write Excel to response
|
|
w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
w.Header().Set("Content-Disposition", "attachment; filename=\"export-transport-solidaire.xlsx\"")
|
|
|
|
if err := spreadsheet.GetFile().Write(w); err != nil {
|
|
log.Error().Err(err).Msg("Error generating Excel file")
|
|
http.Error(w, "Error generating Excel file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
func getAccountFieldValue(data map[string]interface{}, field string) string {
|
|
// First check direct field
|
|
if val, ok := data[field]; ok && val != nil {
|
|
return fmt.Sprint(val)
|
|
}
|
|
|
|
// Check in other_properties
|
|
if otherProps, ok := data["other_properties"]; ok {
|
|
if otherPropsMap, ok := otherProps.(map[string]interface{}); ok {
|
|
if val, ok := otherPropsMap[field]; ok && val != nil {
|
|
return fmt.Sprint(val)
|
|
}
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func getLocationData(feature *geojson.Feature) (address string, lat interface{}, lon interface{}) {
|
|
if feature != nil && feature.Properties != nil {
|
|
if label, ok := feature.Properties["label"].(string); ok {
|
|
address = label
|
|
}
|
|
if feature.Geometry != nil {
|
|
coords := feature.Geometry.Bound().Center()
|
|
lat = fmt.Sprintf("%.6f", coords.Lat())
|
|
lon = fmt.Sprintf("%.6f", coords.Lon())
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (r *XLSXRenderer) SolidarityTransportDrivers(w http.ResponseWriter, result *application.SolidarityTransportOverviewResult) {
|
|
// Create Excel spreadsheet
|
|
spreadsheet := r.NewSpreadsheet("Conducteurs solidaires")
|
|
|
|
// Build headers dynamically based on configuration
|
|
driverOptionalFields := r.Config.Get("modules.solidarity_transport.drivers.profile_optional_fields")
|
|
driverFields := []string{"last_name", "first_name", "email", "phone_number", "birthdate", "gender", "file_number"}
|
|
headers := []string{"ID", "Nom", "Prénom", "Email", "Téléphone", "Date de naissance", "Genre", "Numéro de dossier"}
|
|
|
|
if driverOptionalFieldsList, ok := driverOptionalFields.([]interface{}); ok {
|
|
for _, field := range driverOptionalFieldsList {
|
|
if fieldMap, ok := field.(map[string]interface{}); ok {
|
|
if name, ok := fieldMap["name"].(string); ok {
|
|
driverFields = append(driverFields, name)
|
|
label := name
|
|
if labelVal, ok := fieldMap["label"].(string); ok {
|
|
label = labelVal
|
|
}
|
|
headers = append(headers, label)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add address and archived columns
|
|
headers = append(headers, "Adresse", "Archivé")
|
|
|
|
spreadsheet.SetHeaders(headers)
|
|
|
|
// Add data rows
|
|
for _, driver := range result.Accounts {
|
|
row := []interface{}{}
|
|
|
|
// Driver ID
|
|
row = append(row, driver.ID)
|
|
|
|
// Driver data
|
|
for _, field := range driverFields {
|
|
value := getAccountFieldValue(driver.Data, field)
|
|
// Convert gender code to text
|
|
if field == "gender" && value != "" {
|
|
value = gender.ISO5218ToString(value)
|
|
}
|
|
row = append(row, value)
|
|
}
|
|
|
|
// Address
|
|
address := ""
|
|
if addr, ok := driver.Data["address"]; ok {
|
|
if addrMap, ok := addr.(map[string]interface{}); ok {
|
|
if props, ok := addrMap["properties"]; ok {
|
|
if propsMap, ok := props.(map[string]interface{}); ok {
|
|
if label, ok := propsMap["label"].(string); ok {
|
|
address = label
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
row = append(row, address)
|
|
|
|
// Archived status
|
|
archived := "Non"
|
|
if archivedVal, ok := driver.Data["archived"].(bool); ok && archivedVal {
|
|
archived = "Oui"
|
|
}
|
|
row = append(row, archived)
|
|
|
|
spreadsheet.AddRow(row)
|
|
}
|
|
|
|
// Write Excel to response
|
|
w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
w.Header().Set("Content-Disposition", "attachment; filename=\"export-conducteurs-solidaires.xlsx\"")
|
|
|
|
if err := spreadsheet.GetFile().Write(w); err != nil {
|
|
log.Error().Err(err).Msg("Error generating Excel file")
|
|
http.Error(w, "Error generating Excel file", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|