improvements
	
		
			
	
		
	
	
		
			
				
	
				Build and Push Docker Image / build_and_push (push) Failing after 3m6s
				
					Details
				
			
		
	
				
					
				
			
				
	
				Build and Push Docker Image / build_and_push (push) Failing after 3m6s
				
					Details
				
			
		
	This commit is contained in:
		
							parent
							
								
									fc5b33e88c
								
							
						
					
					
						commit
						723c12a657
					
				| 
						 | 
				
			
			@ -1 +1,2 @@
 | 
			
		|||
config.yaml
 | 
			
		||||
solidarity-transport
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										8
									
								
								go.mod
								
								
								
								
							| 
						 | 
				
			
			@ -5,16 +5,19 @@ go 1.23.3
 | 
			
		|||
//replace git.coopgo.io/coopgo-platform/routing-service => ../../coopgo-platform/routing-service/
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	git.coopgo.io/coopgo-platform/routing-service v0.0.0-20250304234521-faabcc54f536
 | 
			
		||||
	github.com/google/uuid v1.6.0
 | 
			
		||||
	github.com/paulmach/orb v0.11.1
 | 
			
		||||
	github.com/rs/zerolog v1.33.0
 | 
			
		||||
	github.com/spf13/viper v1.19.0
 | 
			
		||||
	github.com/stretchr/testify v1.9.0
 | 
			
		||||
	go.mongodb.org/mongo-driver/v2 v2.1.0
 | 
			
		||||
	google.golang.org/grpc v1.70.0
 | 
			
		||||
	google.golang.org/protobuf v1.36.6
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	git.coopgo.io/coopgo-platform/routing-service v0.0.0-20250304234521-faabcc54f536 // indirect
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.7.0 // indirect
 | 
			
		||||
	github.com/golang/snappy v0.0.4 // indirect
 | 
			
		||||
	github.com/hashicorp/hcl v1.0.0 // indirect
 | 
			
		||||
| 
						 | 
				
			
			@ -23,14 +26,15 @@ require (
 | 
			
		|||
	github.com/mattn/go-colorable v0.1.13 // indirect
 | 
			
		||||
	github.com/mattn/go-isatty v0.0.19 // indirect
 | 
			
		||||
	github.com/mitchellh/mapstructure v1.5.0 // indirect
 | 
			
		||||
	github.com/paulmach/orb v0.11.1 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 | 
			
		||||
	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 | 
			
		||||
	github.com/sagikazarmark/locafero v0.4.0 // indirect
 | 
			
		||||
	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
 | 
			
		||||
	github.com/sourcegraph/conc v0.3.0 // indirect
 | 
			
		||||
	github.com/spf13/afero v1.11.0 // indirect
 | 
			
		||||
	github.com/spf13/cast v1.6.0 // indirect
 | 
			
		||||
	github.com/spf13/pflag v1.0.5 // indirect
 | 
			
		||||
	github.com/stretchr/objx v0.5.2 // indirect
 | 
			
		||||
	github.com/subosito/gotenv v1.6.0 // indirect
 | 
			
		||||
	github.com/twpayne/go-polyline v1.1.1 // indirect
 | 
			
		||||
	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										6
									
								
								go.sum
								
								
								
								
							| 
						 | 
				
			
			@ -1,5 +1,3 @@
 | 
			
		|||
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20240919052617-d03cd410081c h1:I0pJtlpW7Eloiro+VXVRzdQYJW9AMmjNIczBlROCX9Y=
 | 
			
		||||
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20240919052617-d03cd410081c/go.mod h1:Nh7o15LlV0OuO9zxvJIs9FlelpeAaLYkXtFdgIkFrgg=
 | 
			
		||||
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20250304234521-faabcc54f536 h1:SllXX1VJXulfhNi+Pd0R9chksm8zO6gkWcTQ/uSMsdc=
 | 
			
		||||
git.coopgo.io/coopgo-platform/routing-service v0.0.0-20250304234521-faabcc54f536/go.mod h1:Nh7o15LlV0OuO9zxvJIs9FlelpeAaLYkXtFdgIkFrgg=
 | 
			
		||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +84,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 | 
			
		|||
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 | 
			
		||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 | 
			
		||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 | 
			
		||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
 | 
			
		||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 | 
			
		||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 | 
			
		||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +96,7 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
 | 
			
		|||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 | 
			
		||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 | 
			
		||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 | 
			
		||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
 | 
			
		||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 | 
			
		||||
github.com/twpayne/go-polyline v1.1.1 h1:/tSF1BR7rN4HWj4XKqvRUNrCiYVMCvywxTFVofvDV0w=
 | 
			
		||||
github.com/twpayne/go-polyline v1.1.1/go.mod h1:ybd9IWWivW/rlXPXuuckeKUyF3yrIim+iqA7kSl4NFY=
 | 
			
		||||
| 
						 | 
				
			
			@ -197,8 +197,6 @@ google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
 | 
			
		|||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
 | 
			
		||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 | 
			
		||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 | 
			
		||||
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
 | 
			
		||||
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 | 
			
		||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
 | 
			
		||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
 | 
			
		||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import (
 | 
			
		|||
	"github.com/rs/zerolog/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (h Handler) BookDriverJourney(passengerid string, driverid string, journeyid string, returnWaitingDuration time.Duration, priceAmount float64, priceCurrency string, data map[string]any) (*types.Booking, error) {
 | 
			
		||||
func (h Handler) BookDriverJourney(passengerid string, driverid string, journeyid string, returnWaitingDuration time.Duration, priceAmount float64, priceCurrency string, driverCompensationAmount float64, driverCompensationCurrency string, data map[string]any) (*types.Booking, error) {
 | 
			
		||||
	journey, err := h.Storage.GetDriverJourney(journeyid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error().Err(err).Msg("could not find driver journey")
 | 
			
		||||
| 
						 | 
				
			
			@ -26,14 +26,16 @@ func (h Handler) BookDriverJourney(passengerid string, driverid string, journeyi
 | 
			
		|||
	log.Debug().Float64("Price", priceAmount).Any("journey", journey.Price).Msg("store booking")
 | 
			
		||||
 | 
			
		||||
	booking := types.Booking{
 | 
			
		||||
		Id:                    uuid.NewString(),
 | 
			
		||||
		GroupId:               uuid.NewString(),
 | 
			
		||||
		Status:                "WAITING_CONFIRMATION",
 | 
			
		||||
		PassengerId:           passengerid,
 | 
			
		||||
		DriverId:              driverid,
 | 
			
		||||
		Journey:               journey,
 | 
			
		||||
		ReturnWaitingDuration: returnWaitingDuration,
 | 
			
		||||
		Data:                  data,
 | 
			
		||||
		Id:                       uuid.NewString(),
 | 
			
		||||
		GroupId:                  uuid.NewString(),
 | 
			
		||||
		Status:                   "WAITING_CONFIRMATION",
 | 
			
		||||
		PassengerId:              passengerid,
 | 
			
		||||
		DriverId:                 driverid,
 | 
			
		||||
		Journey:                  journey,
 | 
			
		||||
		ReturnWaitingDuration:    returnWaitingDuration,
 | 
			
		||||
		Data:                     data,
 | 
			
		||||
		DriverCompensationAmount:   driverCompensationAmount,
 | 
			
		||||
		DriverCompensationCurrency: driverCompensationCurrency,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := h.Storage.CreateBooking(booking); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,335 @@
 | 
			
		|||
package handler
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"git.coopgo.io/coopgo-platform/routing-service"
 | 
			
		||||
	"git.coopgo.io/coopgo-platform/solidarity-transport/storage"
 | 
			
		||||
	"git.coopgo.io/coopgo-platform/solidarity-transport/types"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"github.com/paulmach/orb"
 | 
			
		||||
	"github.com/paulmach/orb/geojson"
 | 
			
		||||
	"github.com/spf13/viper"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"github.com/stretchr/testify/mock"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type MockRoutingService struct {
 | 
			
		||||
	mock.Mock
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockRoutingService) Route(points []orb.Point) (*routing.Route, error) {
 | 
			
		||||
	args := m.Called(points)
 | 
			
		||||
	return args.Get(0).(*routing.Route), args.Error(1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createTestConfig() *viper.Viper {
 | 
			
		||||
	cfg := viper.New()
 | 
			
		||||
	cfg.Set("storage.db.type", "mock")
 | 
			
		||||
	cfg.Set("parameters.limits.distance.min", 1000)
 | 
			
		||||
	cfg.Set("parameters.limits.distance.max", 50000)
 | 
			
		||||
	return cfg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createTestGeoJSONFeature(lat, lng float64, label string) *geojson.Feature {
 | 
			
		||||
	feature := geojson.NewFeature(orb.Point{lng, lat})
 | 
			
		||||
	feature.Properties = make(map[string]interface{})
 | 
			
		||||
	feature.Properties["label"] = label
 | 
			
		||||
	return feature
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createTestRoute() *routing.Route {
 | 
			
		||||
	return createTestRouteWithDistance(6000) // Default route with 6km passenger distance
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createTestRouteNoReturn(passengerDistance float64) *routing.Route {
 | 
			
		||||
	// No-return: 3 legs (driver→pickup, pickup→dropoff, dropoff→driver)
 | 
			
		||||
	return &routing.Route{
 | 
			
		||||
		Summary: routing.Summary{
 | 
			
		||||
			Distance: 4000 + passengerDistance,
 | 
			
		||||
			Duration: 15 * time.Minute,
 | 
			
		||||
			Polyline: "test_polyline",
 | 
			
		||||
		},
 | 
			
		||||
		Legs: []routing.RouteLeg{
 | 
			
		||||
			{Summary: routing.Summary{Distance: 2000, Duration: 5 * time.Minute}}, // driver to pickup
 | 
			
		||||
			{Summary: routing.Summary{Distance: passengerDistance, Duration: 8 * time.Minute}}, // pickup to dropoff
 | 
			
		||||
			{Summary: routing.Summary{Distance: 2000, Duration: 5 * time.Minute}}, // dropoff to driver destination
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createTestRouteReturn(passengerDistance float64) *routing.Route {
 | 
			
		||||
	// Return: 4+ legs (driver→pickup, pickup→dropoff, dropoff→pickup, pickup→driver)
 | 
			
		||||
	// For return journeys: passenger distance = legs[1] + legs[2]
 | 
			
		||||
	singleLegDistance := passengerDistance / 2
 | 
			
		||||
 | 
			
		||||
	return &routing.Route{
 | 
			
		||||
		Summary: routing.Summary{
 | 
			
		||||
			Distance: 4000 + passengerDistance,
 | 
			
		||||
			Duration: 18 * time.Minute,
 | 
			
		||||
			Polyline: "test_polyline",
 | 
			
		||||
		},
 | 
			
		||||
		Legs: []routing.RouteLeg{
 | 
			
		||||
			{Summary: routing.Summary{Distance: 2000, Duration: 5 * time.Minute}}, // driver to pickup
 | 
			
		||||
			{Summary: routing.Summary{Distance: singleLegDistance, Duration: 8 * time.Minute}}, // pickup to dropoff
 | 
			
		||||
			{Summary: routing.Summary{Distance: singleLegDistance, Duration: 2 * time.Minute}}, // dropoff to pickup (return)
 | 
			
		||||
			{Summary: routing.Summary{Distance: 2000, Duration: 3 * time.Minute}}, // pickup to driver destination
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createTestRouteWithDistance(passengerDistance float64) *routing.Route {
 | 
			
		||||
	// Default to return journey for backward compatibility
 | 
			
		||||
	return createTestRouteReturn(passengerDistance)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createTestAvailability(driverID string, day int, startTime, endTime string) *types.DriverRegularAvailability {
 | 
			
		||||
	address := createTestGeoJSONFeature(45.7640, 4.8357, "Driver Address")
 | 
			
		||||
	return &types.DriverRegularAvailability{
 | 
			
		||||
		ID:        uuid.New().String(),
 | 
			
		||||
		DriverId:  driverID,
 | 
			
		||||
		Day:       day,
 | 
			
		||||
		StartTime: startTime,
 | 
			
		||||
		EndTime:   endTime,
 | 
			
		||||
		Address:   address,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHandler_GetDriverJourneys(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name               string
 | 
			
		||||
		departureDate      time.Time
 | 
			
		||||
		noreturn           bool
 | 
			
		||||
		availabilities     []*types.DriverRegularAvailability
 | 
			
		||||
		routingResponse    *routing.Route
 | 
			
		||||
		expectedJourneys   int
 | 
			
		||||
		expectedDriverIDs  []string
 | 
			
		||||
		description        string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name:          "journey within distance limits",
 | 
			
		||||
			departureDate: time.Date(2024, 1, 15, 8, 0, 0, 0, time.UTC),
 | 
			
		||||
			noreturn:      false,
 | 
			
		||||
			availabilities: []*types.DriverRegularAvailability{
 | 
			
		||||
				createTestAvailability("driver-1", 1, "07:00", "09:00"),
 | 
			
		||||
			},
 | 
			
		||||
			routingResponse:   createTestRouteWithDistance(6000), // 6km - within limits (1km to 50km)
 | 
			
		||||
			expectedJourneys:  1,
 | 
			
		||||
			expectedDriverIDs: []string{"driver-1"},
 | 
			
		||||
			description:       "6km journey should be within distance limits",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:          "journey too short - below minimum distance",
 | 
			
		||||
			departureDate: time.Date(2024, 1, 15, 8, 0, 0, 0, time.UTC),
 | 
			
		||||
			noreturn:      false,
 | 
			
		||||
			availabilities: []*types.DriverRegularAvailability{
 | 
			
		||||
				createTestAvailability("driver-1", 1, "07:00", "09:00"),
 | 
			
		||||
			},
 | 
			
		||||
			routingResponse:   createTestRouteWithDistance(500), // 500m - below 1km minimum
 | 
			
		||||
			expectedJourneys:  0,
 | 
			
		||||
			expectedDriverIDs: []string{},
 | 
			
		||||
			description:       "500m journey should be rejected (below minimum distance)",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:          "journey too long - above maximum distance",
 | 
			
		||||
			departureDate: time.Date(2024, 1, 15, 8, 0, 0, 0, time.UTC),
 | 
			
		||||
			noreturn:      false,
 | 
			
		||||
			availabilities: []*types.DriverRegularAvailability{
 | 
			
		||||
				createTestAvailability("driver-1", 1, "07:00", "09:00"),
 | 
			
		||||
			},
 | 
			
		||||
			routingResponse:   createTestRouteWithDistance(60000), // 60km - above 50km maximum
 | 
			
		||||
			expectedJourneys:  0,
 | 
			
		||||
			expectedDriverIDs: []string{},
 | 
			
		||||
			description:       "60km journey should be rejected (above maximum distance)",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:          "journey at minimum distance boundary",
 | 
			
		||||
			departureDate: time.Date(2024, 1, 15, 8, 0, 0, 0, time.UTC),
 | 
			
		||||
			noreturn:      false,
 | 
			
		||||
			availabilities: []*types.DriverRegularAvailability{
 | 
			
		||||
				createTestAvailability("driver-1", 1, "07:00", "09:00"),
 | 
			
		||||
			},
 | 
			
		||||
			routingResponse:   createTestRouteWithDistance(1000), // Exactly 1km minimum
 | 
			
		||||
			expectedJourneys:  1,
 | 
			
		||||
			expectedDriverIDs: []string{"driver-1"},
 | 
			
		||||
			description:       "1km journey should be accepted (at minimum boundary)",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:          "journey at maximum distance boundary",
 | 
			
		||||
			departureDate: time.Date(2024, 1, 15, 8, 0, 0, 0, time.UTC),
 | 
			
		||||
			noreturn:      false,
 | 
			
		||||
			availabilities: []*types.DriverRegularAvailability{
 | 
			
		||||
				createTestAvailability("driver-1", 1, "07:00", "09:00"),
 | 
			
		||||
			},
 | 
			
		||||
			routingResponse:   createTestRouteWithDistance(50000), // Exactly 50km maximum
 | 
			
		||||
			expectedJourneys:  1,
 | 
			
		||||
			expectedDriverIDs: []string{"driver-1"},
 | 
			
		||||
			description:       "50km journey should be accepted (at maximum boundary)",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:          "wrong day no availabilities",
 | 
			
		||||
			departureDate: time.Date(2024, 1, 16, 9, 0, 0, 0, time.UTC),
 | 
			
		||||
			noreturn:      false,
 | 
			
		||||
			availabilities: []*types.DriverRegularAvailability{
 | 
			
		||||
				createTestAvailability("driver-1", 1, "08:00", "10:00"),
 | 
			
		||||
			},
 | 
			
		||||
			expectedJourneys:  0,
 | 
			
		||||
			expectedDriverIDs: []string{},
 | 
			
		||||
			description:       "Tuesday departure should not match Monday availability",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	departure := createTestGeoJSONFeature(45.7578, 4.8320, "Departure")
 | 
			
		||||
	arrival := createTestGeoJSONFeature(45.7485, 4.8467, "Arrival")
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			cfg := createTestConfig()
 | 
			
		||||
			mockStorage := storage.NewMockStorage(cfg)
 | 
			
		||||
			mockRouting := &MockRoutingService{}
 | 
			
		||||
 | 
			
		||||
			for _, availability := range tt.availabilities {
 | 
			
		||||
				err := mockStorage.CreateDriverRegularAvailability(*availability)
 | 
			
		||||
				require.NoError(t, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			routeResponse := tt.routingResponse
 | 
			
		||||
			if routeResponse == nil {
 | 
			
		||||
				routeResponse = createTestRoute() // Default route
 | 
			
		||||
			}
 | 
			
		||||
			mockRouting.On("Route", mock.AnythingOfType("[]orb.Point")).Return(routeResponse, nil)
 | 
			
		||||
 | 
			
		||||
			handler := &Handler{
 | 
			
		||||
				Config:  cfg,
 | 
			
		||||
				Storage: mockStorage,
 | 
			
		||||
				Routing: mockRouting,
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			journeys, err := handler.GetDriverJourneys(departure, arrival, tt.departureDate, tt.noreturn)
 | 
			
		||||
 | 
			
		||||
			assert.NoError(t, err, tt.description)
 | 
			
		||||
			assert.Len(t, journeys, tt.expectedJourneys, tt.description)
 | 
			
		||||
 | 
			
		||||
			if tt.expectedJourneys > 0 {
 | 
			
		||||
				actualDriverIDs := make([]string, len(journeys))
 | 
			
		||||
				for i, journey := range journeys {
 | 
			
		||||
					assert.NotEmpty(t, journey.Id)
 | 
			
		||||
					actualDriverIDs[i] = journey.DriverId
 | 
			
		||||
				}
 | 
			
		||||
				assert.ElementsMatch(t, tt.expectedDriverIDs, actualDriverIDs, tt.description)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHandler_GetDriverJourney(t *testing.T) {
 | 
			
		||||
	cfg := createTestConfig()
 | 
			
		||||
	mockStorage := storage.NewMockStorage(cfg)
 | 
			
		||||
 | 
			
		||||
	testJourney := &types.DriverJourney{
 | 
			
		||||
		Id:       uuid.New().String(),
 | 
			
		||||
		DriverId: "driver-1",
 | 
			
		||||
	}
 | 
			
		||||
	err := mockStorage.PushDriverJourneys([]*types.DriverJourney{testJourney})
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	handler := &Handler{
 | 
			
		||||
		Config:  cfg,
 | 
			
		||||
		Storage: mockStorage,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name          string
 | 
			
		||||
		driverID      string
 | 
			
		||||
		journeyID     string
 | 
			
		||||
		expectedError bool
 | 
			
		||||
		errorMessage  string
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name:          "successful retrieval",
 | 
			
		||||
			driverID:      "driver-1",
 | 
			
		||||
			journeyID:     testJourney.Id,
 | 
			
		||||
			expectedError: false,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:          "driver mismatch",
 | 
			
		||||
			driverID:      "driver-2",
 | 
			
		||||
			journeyID:     testJourney.Id,
 | 
			
		||||
			expectedError: true,
 | 
			
		||||
			errorMessage:  "not allowed, driver id mismatch",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:          "journey not found",
 | 
			
		||||
			driverID:      "driver-1",
 | 
			
		||||
			journeyID:     "non-existent",
 | 
			
		||||
			expectedError: true,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			journey, err := handler.GetDriverJourney(tt.driverID, tt.journeyID)
 | 
			
		||||
 | 
			
		||||
			if tt.expectedError {
 | 
			
		||||
				assert.Error(t, err)
 | 
			
		||||
				if tt.errorMessage != "" {
 | 
			
		||||
					assert.Contains(t, err.Error(), tt.errorMessage)
 | 
			
		||||
				}
 | 
			
		||||
				assert.Nil(t, journey)
 | 
			
		||||
			} else {
 | 
			
		||||
				assert.NoError(t, err)
 | 
			
		||||
				assert.NotNil(t, journey)
 | 
			
		||||
				assert.Equal(t, tt.journeyID, journey.Id)
 | 
			
		||||
				assert.Equal(t, tt.driverID, journey.DriverId)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestHandler_ToggleDriverJourneyNoreturn(t *testing.T) {
 | 
			
		||||
	cfg := createTestConfig()
 | 
			
		||||
	mockStorage := storage.NewMockStorage(cfg)
 | 
			
		||||
	mockRouting := &MockRoutingService{}
 | 
			
		||||
 | 
			
		||||
	departure := createTestGeoJSONFeature(45.7578, 4.8320, "Departure")
 | 
			
		||||
	arrival := createTestGeoJSONFeature(45.7485, 4.8467, "Arrival")
 | 
			
		||||
	driverAddress := createTestGeoJSONFeature(45.7640, 4.8357, "Driver Address")
 | 
			
		||||
 | 
			
		||||
	testJourney := &types.DriverJourney{
 | 
			
		||||
		Id:              uuid.New().String(),
 | 
			
		||||
		DriverId:        "driver-1",
 | 
			
		||||
		PassengerPickup: departure,
 | 
			
		||||
		PassengerDrop:   arrival,
 | 
			
		||||
		DriverDeparture: driverAddress,
 | 
			
		||||
		Noreturn:        false,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := mockStorage.PushDriverJourneys([]*types.DriverJourney{testJourney})
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	mockRouting.On("Route", mock.AnythingOfType("[]orb.Point")).Return(createTestRoute(), nil)
 | 
			
		||||
 | 
			
		||||
	handler := &Handler{
 | 
			
		||||
		Config:  cfg,
 | 
			
		||||
		Storage: mockStorage,
 | 
			
		||||
		Routing: mockRouting,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = handler.ToggleDriverJourneyNoreturn(testJourney.Id)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	updatedJourney, err := mockStorage.GetDriverJourney(testJourney.Id)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, updatedJourney.Noreturn)
 | 
			
		||||
 | 
			
		||||
	err = handler.ToggleDriverJourneyNoreturn(testJourney.Id)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	updatedJourney, err = mockStorage.GetDriverJourney(testJourney.Id)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.False(t, updatedJourney.Noreturn)
 | 
			
		||||
 | 
			
		||||
	mockRouting.AssertExpectations(t)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -396,17 +396,19 @@ func (x *SolidarityTransportPrice) GetCurrency() string {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type SolidarityTransportBooking struct {
 | 
			
		||||
	state                 protoimpl.MessageState            `protogen:"open.v1"`
 | 
			
		||||
	Id                    string                            `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
 | 
			
		||||
	GroupId               string                            `protobuf:"bytes,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"`
 | 
			
		||||
	DriverId              string                            `protobuf:"bytes,3,opt,name=driver_id,json=driverId,proto3" json:"driver_id,omitempty"`
 | 
			
		||||
	PassengerId           string                            `protobuf:"bytes,4,opt,name=passenger_id,json=passengerId,proto3" json:"passenger_id,omitempty"`
 | 
			
		||||
	Status                string                            `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"`
 | 
			
		||||
	ReturnWaitingDuration int64                             `protobuf:"varint,6,opt,name=return_waiting_duration,json=returnWaitingDuration,proto3" json:"return_waiting_duration,omitempty"`
 | 
			
		||||
	Data                  *structpb.Struct                  `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
 | 
			
		||||
	Journey               *SolidarityTransportDriverJourney `protobuf:"bytes,10,opt,name=journey,proto3" json:"journey,omitempty"`
 | 
			
		||||
	unknownFields         protoimpl.UnknownFields
 | 
			
		||||
	sizeCache             protoimpl.SizeCache
 | 
			
		||||
	state                      protoimpl.MessageState            `protogen:"open.v1"`
 | 
			
		||||
	Id                         string                            `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
 | 
			
		||||
	GroupId                    string                            `protobuf:"bytes,2,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"`
 | 
			
		||||
	DriverId                   string                            `protobuf:"bytes,3,opt,name=driver_id,json=driverId,proto3" json:"driver_id,omitempty"`
 | 
			
		||||
	PassengerId                string                            `protobuf:"bytes,4,opt,name=passenger_id,json=passengerId,proto3" json:"passenger_id,omitempty"`
 | 
			
		||||
	Status                     string                            `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"`
 | 
			
		||||
	ReturnWaitingDuration      int64                             `protobuf:"varint,6,opt,name=return_waiting_duration,json=returnWaitingDuration,proto3" json:"return_waiting_duration,omitempty"`
 | 
			
		||||
	Data                       *structpb.Struct                  `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
 | 
			
		||||
	DriverCompensationAmount   float64                           `protobuf:"fixed64,8,opt,name=driver_compensation_amount,json=driverCompensationAmount,proto3" json:"driver_compensation_amount,omitempty"`
 | 
			
		||||
	DriverCompensationCurrency string                            `protobuf:"bytes,9,opt,name=driver_compensation_currency,json=driverCompensationCurrency,proto3" json:"driver_compensation_currency,omitempty"`
 | 
			
		||||
	Journey                    *SolidarityTransportDriverJourney `protobuf:"bytes,10,opt,name=journey,proto3" json:"journey,omitempty"`
 | 
			
		||||
	unknownFields              protoimpl.UnknownFields
 | 
			
		||||
	sizeCache                  protoimpl.SizeCache
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *SolidarityTransportBooking) Reset() {
 | 
			
		||||
| 
						 | 
				
			
			@ -488,6 +490,20 @@ func (x *SolidarityTransportBooking) GetData() *structpb.Struct {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *SolidarityTransportBooking) GetDriverCompensationAmount() float64 {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.DriverCompensationAmount
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *SolidarityTransportBooking) GetDriverCompensationCurrency() string {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.DriverCompensationCurrency
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *SolidarityTransportBooking) GetJourney() *SolidarityTransportDriverJourney {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.Journey
 | 
			
		||||
| 
						 | 
				
			
			@ -537,7 +553,7 @@ const file_solidarity_transport_types_proto_rawDesc = "" +
 | 
			
		|||
	"\x06_price\"N\n" +
 | 
			
		||||
	"\x18SolidarityTransportPrice\x12\x16\n" +
 | 
			
		||||
	"\x06amount\x18\x01 \x01(\x01R\x06amount\x12\x1a\n" +
 | 
			
		||||
	"\bcurrency\x18\x02 \x01(\tR\bcurrency\"\xc1\x02\n" +
 | 
			
		||||
	"\bcurrency\x18\x02 \x01(\tR\bcurrency\"\xc1\x03\n" +
 | 
			
		||||
	"\x1aSolidarityTransportBooking\x12\x0e\n" +
 | 
			
		||||
	"\x02id\x18\x01 \x01(\tR\x02id\x12\x19\n" +
 | 
			
		||||
	"\bgroup_id\x18\x02 \x01(\tR\agroupId\x12\x1b\n" +
 | 
			
		||||
| 
						 | 
				
			
			@ -545,7 +561,9 @@ const file_solidarity_transport_types_proto_rawDesc = "" +
 | 
			
		|||
	"\fpassenger_id\x18\x04 \x01(\tR\vpassengerId\x12\x16\n" +
 | 
			
		||||
	"\x06status\x18\x05 \x01(\tR\x06status\x126\n" +
 | 
			
		||||
	"\x17return_waiting_duration\x18\x06 \x01(\x03R\x15returnWaitingDuration\x12+\n" +
 | 
			
		||||
	"\x04data\x18\a \x01(\v2\x17.google.protobuf.StructR\x04data\x12;\n" +
 | 
			
		||||
	"\x04data\x18\a \x01(\v2\x17.google.protobuf.StructR\x04data\x12<\n" +
 | 
			
		||||
	"\x1adriver_compensation_amount\x18\b \x01(\x01R\x18driverCompensationAmount\x12@\n" +
 | 
			
		||||
	"\x1cdriver_compensation_currency\x18\t \x01(\tR\x1adriverCompensationCurrency\x12;\n" +
 | 
			
		||||
	"\ajourney\x18\n" +
 | 
			
		||||
	" \x01(\v2!.SolidarityTransportDriverJourneyR\ajourneyBKZIgit.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/proto/genb\x06proto3"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -608,16 +608,18 @@ func (x *GetDriverJourneyResponse) GetDriverJourney() *SolidarityTransportDriver
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type BookDriverJourneyRequest struct {
 | 
			
		||||
	state                 protoimpl.MessageState `protogen:"open.v1"`
 | 
			
		||||
	PassengerId           string                 `protobuf:"bytes,1,opt,name=passenger_id,json=passengerId,proto3" json:"passenger_id,omitempty"`
 | 
			
		||||
	DriverId              string                 `protobuf:"bytes,2,opt,name=driver_id,json=driverId,proto3" json:"driver_id,omitempty"`
 | 
			
		||||
	DriverJourneyId       string                 `protobuf:"bytes,3,opt,name=driver_journey_id,json=driverJourneyId,proto3" json:"driver_journey_id,omitempty"`
 | 
			
		||||
	ReturnWaitingDuration int64                  `protobuf:"varint,4,opt,name=return_waiting_duration,json=returnWaitingDuration,proto3" json:"return_waiting_duration,omitempty"`
 | 
			
		||||
	PriceAmount           float64                `protobuf:"fixed64,5,opt,name=price_amount,json=priceAmount,proto3" json:"price_amount,omitempty"`
 | 
			
		||||
	PriceCurrency         string                 `protobuf:"bytes,6,opt,name=price_currency,json=priceCurrency,proto3" json:"price_currency,omitempty"`
 | 
			
		||||
	Data                  *structpb.Struct       `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
 | 
			
		||||
	unknownFields         protoimpl.UnknownFields
 | 
			
		||||
	sizeCache             protoimpl.SizeCache
 | 
			
		||||
	state                      protoimpl.MessageState `protogen:"open.v1"`
 | 
			
		||||
	PassengerId                string                 `protobuf:"bytes,1,opt,name=passenger_id,json=passengerId,proto3" json:"passenger_id,omitempty"`
 | 
			
		||||
	DriverId                   string                 `protobuf:"bytes,2,opt,name=driver_id,json=driverId,proto3" json:"driver_id,omitempty"`
 | 
			
		||||
	DriverJourneyId            string                 `protobuf:"bytes,3,opt,name=driver_journey_id,json=driverJourneyId,proto3" json:"driver_journey_id,omitempty"`
 | 
			
		||||
	ReturnWaitingDuration      int64                  `protobuf:"varint,4,opt,name=return_waiting_duration,json=returnWaitingDuration,proto3" json:"return_waiting_duration,omitempty"`
 | 
			
		||||
	PriceAmount                float64                `protobuf:"fixed64,5,opt,name=price_amount,json=priceAmount,proto3" json:"price_amount,omitempty"`
 | 
			
		||||
	PriceCurrency              string                 `protobuf:"bytes,6,opt,name=price_currency,json=priceCurrency,proto3" json:"price_currency,omitempty"`
 | 
			
		||||
	Data                       *structpb.Struct       `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"`
 | 
			
		||||
	DriverCompensationAmount   float64                `protobuf:"fixed64,8,opt,name=driver_compensation_amount,json=driverCompensationAmount,proto3" json:"driver_compensation_amount,omitempty"`
 | 
			
		||||
	DriverCompensationCurrency string                 `protobuf:"bytes,9,opt,name=driver_compensation_currency,json=driverCompensationCurrency,proto3" json:"driver_compensation_currency,omitempty"`
 | 
			
		||||
	unknownFields              protoimpl.UnknownFields
 | 
			
		||||
	sizeCache                  protoimpl.SizeCache
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *BookDriverJourneyRequest) Reset() {
 | 
			
		||||
| 
						 | 
				
			
			@ -699,6 +701,20 @@ func (x *BookDriverJourneyRequest) GetData() *structpb.Struct {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *BookDriverJourneyRequest) GetDriverCompensationAmount() float64 {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.DriverCompensationAmount
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *BookDriverJourneyRequest) GetDriverCompensationCurrency() string {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.DriverCompensationCurrency
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BookDriverJourneyResponse struct {
 | 
			
		||||
	state         protoimpl.MessageState      `protogen:"open.v1"`
 | 
			
		||||
	Booking       *SolidarityTransportBooking `protobuf:"bytes,1,opt,name=booking,proto3" json:"booking,omitempty"`
 | 
			
		||||
| 
						 | 
				
			
			@ -1246,7 +1262,7 @@ const file_solidarity_transport_proto_rawDesc = "" +
 | 
			
		|||
	"\n" +
 | 
			
		||||
	"journey_id\x18\x02 \x01(\tR\tjourneyId\"d\n" +
 | 
			
		||||
	"\x18GetDriverJourneyResponse\x12H\n" +
 | 
			
		||||
	"\x0edriver_journey\x18\x01 \x01(\v2!.SolidarityTransportDriverJourneyR\rdriverJourney\"\xb5\x02\n" +
 | 
			
		||||
	"\x0edriver_journey\x18\x01 \x01(\v2!.SolidarityTransportDriverJourneyR\rdriverJourney\"\xb5\x03\n" +
 | 
			
		||||
	"\x18BookDriverJourneyRequest\x12!\n" +
 | 
			
		||||
	"\fpassenger_id\x18\x01 \x01(\tR\vpassengerId\x12\x1b\n" +
 | 
			
		||||
	"\tdriver_id\x18\x02 \x01(\tR\bdriverId\x12*\n" +
 | 
			
		||||
| 
						 | 
				
			
			@ -1254,7 +1270,9 @@ const file_solidarity_transport_proto_rawDesc = "" +
 | 
			
		|||
	"\x17return_waiting_duration\x18\x04 \x01(\x03R\x15returnWaitingDuration\x12!\n" +
 | 
			
		||||
	"\fprice_amount\x18\x05 \x01(\x01R\vpriceAmount\x12%\n" +
 | 
			
		||||
	"\x0eprice_currency\x18\x06 \x01(\tR\rpriceCurrency\x12+\n" +
 | 
			
		||||
	"\x04data\x18\a \x01(\v2\x17.google.protobuf.StructR\x04data\"R\n" +
 | 
			
		||||
	"\x04data\x18\a \x01(\v2\x17.google.protobuf.StructR\x04data\x12<\n" +
 | 
			
		||||
	"\x1adriver_compensation_amount\x18\b \x01(\x01R\x18driverCompensationAmount\x12@\n" +
 | 
			
		||||
	"\x1cdriver_compensation_currency\x18\t \x01(\tR\x1adriverCompensationCurrency\"R\n" +
 | 
			
		||||
	"\x19BookDriverJourneyResponse\x125\n" +
 | 
			
		||||
	"\abooking\x18\x01 \x01(\v2\x1b.SolidarityTransportBookingR\abooking\"\xef\x01\n" +
 | 
			
		||||
	"%GetSolidarityTransportBookingsRequest\x129\n" +
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,6 +51,8 @@ message SolidarityTransportBooking {
 | 
			
		|||
    string status = 5;
 | 
			
		||||
    int64 return_waiting_duration = 6;
 | 
			
		||||
    google.protobuf.Struct data = 7;
 | 
			
		||||
    double driver_compensation_amount = 8;
 | 
			
		||||
    string driver_compensation_currency = 9;
 | 
			
		||||
 | 
			
		||||
    SolidarityTransportDriverJourney journey = 10;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,6 +88,8 @@ message BookDriverJourneyRequest {
 | 
			
		|||
    double price_amount = 5;
 | 
			
		||||
    string price_currency = 6;
 | 
			
		||||
    google.protobuf.Struct data = 7;
 | 
			
		||||
    double driver_compensation_amount = 8;
 | 
			
		||||
    string driver_compensation_currency = 9;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
message BookDriverJourneyResponse {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,10 +17,12 @@ func (s SolidarityTransportServerImpl) BookDriverJourney(ctx context.Context, re
 | 
			
		|||
	journeyId := req.DriverJourneyId
 | 
			
		||||
	priceAmount := req.PriceAmount
 | 
			
		||||
	priceCurrency := req.PriceCurrency
 | 
			
		||||
	driverCompensationAmount := req.DriverCompensationAmount
 | 
			
		||||
	driverCompensationCurrency := req.DriverCompensationCurrency
 | 
			
		||||
	returnWaitingDuration := time.Duration(req.ReturnWaitingDuration)
 | 
			
		||||
	data := req.Data.AsMap()
 | 
			
		||||
 | 
			
		||||
	booking, err := s.Handler.BookDriverJourney(passengerId, driverId, journeyId, returnWaitingDuration, priceAmount, priceCurrency, data)
 | 
			
		||||
	booking, err := s.Handler.BookDriverJourney(passengerId, driverId, journeyId, returnWaitingDuration, priceAmount, priceCurrency, driverCompensationAmount, driverCompensationCurrency, data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error().Err(err).Msg("issue in BookDriverJourney handler")
 | 
			
		||||
		return nil, status.Errorf(codes.Internal, "could not create booking : %v", err)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,14 +20,16 @@ func BookingTypeToProto(booking *types.Booking) (*gen.SolidarityTransportBooking
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	return &gen.SolidarityTransportBooking{
 | 
			
		||||
		Id:                    booking.Id,
 | 
			
		||||
		GroupId:               booking.GroupId,
 | 
			
		||||
		DriverId:              booking.DriverId,
 | 
			
		||||
		PassengerId:           booking.PassengerId,
 | 
			
		||||
		Status:                booking.Status,
 | 
			
		||||
		ReturnWaitingDuration: int64(booking.ReturnWaitingDuration),
 | 
			
		||||
		Journey:               journey,
 | 
			
		||||
		Data:                  data,
 | 
			
		||||
		Id:                       booking.Id,
 | 
			
		||||
		GroupId:                  booking.GroupId,
 | 
			
		||||
		DriverId:                 booking.DriverId,
 | 
			
		||||
		PassengerId:              booking.PassengerId,
 | 
			
		||||
		Status:                   booking.Status,
 | 
			
		||||
		ReturnWaitingDuration:    int64(booking.ReturnWaitingDuration),
 | 
			
		||||
		Journey:                  journey,
 | 
			
		||||
		Data:                     data,
 | 
			
		||||
		DriverCompensationAmount:   booking.DriverCompensationAmount,
 | 
			
		||||
		DriverCompensationCurrency: booking.DriverCompensationCurrency,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -37,13 +39,15 @@ func BookingProtoToType(booking *gen.SolidarityTransportBooking) (*types.Booking
 | 
			
		|||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &types.Booking{
 | 
			
		||||
		Id:                    booking.Id,
 | 
			
		||||
		GroupId:               booking.GroupId,
 | 
			
		||||
		DriverId:              booking.DriverId,
 | 
			
		||||
		PassengerId:           booking.PassengerId,
 | 
			
		||||
		Status:                booking.Status,
 | 
			
		||||
		ReturnWaitingDuration: time.Duration(booking.ReturnWaitingDuration),
 | 
			
		||||
		Journey:               journey,
 | 
			
		||||
		Data:                  booking.Data.AsMap(),
 | 
			
		||||
		Id:                       booking.Id,
 | 
			
		||||
		GroupId:                  booking.GroupId,
 | 
			
		||||
		DriverId:                 booking.DriverId,
 | 
			
		||||
		PassengerId:              booking.PassengerId,
 | 
			
		||||
		Status:                   booking.Status,
 | 
			
		||||
		ReturnWaitingDuration:    time.Duration(booking.ReturnWaitingDuration),
 | 
			
		||||
		Journey:                  journey,
 | 
			
		||||
		Data:                     booking.Data.AsMap(),
 | 
			
		||||
		DriverCompensationAmount:   booking.DriverCompensationAmount,
 | 
			
		||||
		DriverCompensationCurrency: booking.DriverCompensationCurrency,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,279 @@
 | 
			
		|||
package storage
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"git.coopgo.io/coopgo-platform/solidarity-transport/types"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"github.com/spf13/viper"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MockStorage implements the Storage interface for testing purposes
 | 
			
		||||
type MockStorage struct {
 | 
			
		||||
	config                *viper.Viper
 | 
			
		||||
	mu                    sync.RWMutex
 | 
			
		||||
	availabilities        map[string]*types.DriverRegularAvailability
 | 
			
		||||
	journeys              map[string]*types.DriverJourney
 | 
			
		||||
	bookings              map[string]*types.Booking
 | 
			
		||||
	availabilitiesByDriver map[string][]*types.DriverRegularAvailability
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewMockStorage creates a new mock storage instance
 | 
			
		||||
func NewMockStorage(cfg *viper.Viper) Storage {
 | 
			
		||||
	return &MockStorage{
 | 
			
		||||
		config:                 cfg,
 | 
			
		||||
		availabilities:         make(map[string]*types.DriverRegularAvailability),
 | 
			
		||||
		journeys:               make(map[string]*types.DriverJourney),
 | 
			
		||||
		bookings:               make(map[string]*types.Booking),
 | 
			
		||||
		availabilitiesByDriver: make(map[string][]*types.DriverRegularAvailability),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Driver Regular Availability methods
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) CreateDriverRegularAvailability(availability types.DriverRegularAvailability) error {
 | 
			
		||||
	m.mu.Lock()
 | 
			
		||||
	defer m.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	if availability.ID == "" {
 | 
			
		||||
		availability.ID = uuid.New().String()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.availabilities[availability.ID] = &availability
 | 
			
		||||
 | 
			
		||||
	// Update driver index
 | 
			
		||||
	m.availabilitiesByDriver[availability.DriverId] = append(
 | 
			
		||||
		m.availabilitiesByDriver[availability.DriverId],
 | 
			
		||||
		&availability,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) CreateDriverRegularAvailabilities(availabilities []*types.DriverRegularAvailability) error {
 | 
			
		||||
	for _, availability := range availabilities {
 | 
			
		||||
		if err := m.CreateDriverRegularAvailability(*availability); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) DeleteDriverRegularAvailability(driverid string, availabilityid string) error {
 | 
			
		||||
	m.mu.Lock()
 | 
			
		||||
	defer m.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	availability, exists := m.availabilities[availabilityid]
 | 
			
		||||
	if !exists {
 | 
			
		||||
		return fmt.Errorf("availability %s not found", availabilityid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if availability.DriverId != driverid {
 | 
			
		||||
		return fmt.Errorf("availability %s does not belong to driver %s", availabilityid, driverid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete(m.availabilities, availabilityid)
 | 
			
		||||
 | 
			
		||||
	// Update driver index
 | 
			
		||||
	driverAvailabilities := m.availabilitiesByDriver[driverid]
 | 
			
		||||
	for i, a := range driverAvailabilities {
 | 
			
		||||
		if a.ID == availabilityid {
 | 
			
		||||
			m.availabilitiesByDriver[driverid] = append(driverAvailabilities[:i], driverAvailabilities[i+1:]...)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) GetDriverRegularAvailability(driverid string, availabilityid string) (*types.DriverRegularAvailability, error) {
 | 
			
		||||
	m.mu.RLock()
 | 
			
		||||
	defer m.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	availability, exists := m.availabilities[availabilityid]
 | 
			
		||||
	if !exists {
 | 
			
		||||
		return nil, fmt.Errorf("availability %s not found", availabilityid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if availability.DriverId != driverid {
 | 
			
		||||
		return nil, fmt.Errorf("availability %s does not belong to driver %s", availabilityid, driverid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return availability, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) GetDriverRegularAvailabilities(driverid string) ([]*types.DriverRegularAvailability, error) {
 | 
			
		||||
	m.mu.RLock()
 | 
			
		||||
	defer m.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return m.availabilitiesByDriver[driverid], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) GetRegularAvailabilities(day int, timeInDay string) ([]*types.DriverRegularAvailability, error) {
 | 
			
		||||
	m.mu.RLock()
 | 
			
		||||
	defer m.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	var result []*types.DriverRegularAvailability
 | 
			
		||||
 | 
			
		||||
	for _, availability := range m.availabilities {
 | 
			
		||||
		// Match day
 | 
			
		||||
		if availability.Day != day {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// For testing, just return all availabilities for the day
 | 
			
		||||
		// Let the handler do the time filtering logic
 | 
			
		||||
		result = append(result, availability)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// timeMatches is a simple time matching function for testing
 | 
			
		||||
func (m *MockStorage) timeMatches(availabilityTime, requestedTime string) bool {
 | 
			
		||||
	// Simple string matching for testing - real implementation would parse times
 | 
			
		||||
	return strings.HasPrefix(availabilityTime, requestedTime[:2]) // Match hour
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Driver Journey methods
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) PushDriverJourneys(journeys []*types.DriverJourney) error {
 | 
			
		||||
	m.mu.Lock()
 | 
			
		||||
	defer m.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	for _, journey := range journeys {
 | 
			
		||||
		if journey.Id == "" {
 | 
			
		||||
			journey.Id = uuid.New().String()
 | 
			
		||||
		}
 | 
			
		||||
		m.journeys[journey.Id] = journey
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) GetDriverJourney(id string) (*types.DriverJourney, error) {
 | 
			
		||||
	m.mu.RLock()
 | 
			
		||||
	defer m.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	journey, exists := m.journeys[id]
 | 
			
		||||
	if !exists {
 | 
			
		||||
		return nil, fmt.Errorf("journey %s not found", id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return journey, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) UpdateDriverJourney(journey types.DriverJourney) error {
 | 
			
		||||
	m.mu.Lock()
 | 
			
		||||
	defer m.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	if _, exists := m.journeys[journey.Id]; !exists {
 | 
			
		||||
		return fmt.Errorf("journey %s not found", journey.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.journeys[journey.Id] = &journey
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Booking methods
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) CreateBooking(booking types.Booking) error {
 | 
			
		||||
	m.mu.Lock()
 | 
			
		||||
	defer m.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	if booking.Id == "" {
 | 
			
		||||
		booking.Id = uuid.New().String()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.bookings[booking.Id] = &booking
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) GetAllBookings() ([]*types.Booking, error) {
 | 
			
		||||
	m.mu.RLock()
 | 
			
		||||
	defer m.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	var result []*types.Booking
 | 
			
		||||
	for _, booking := range m.bookings {
 | 
			
		||||
		result = append(result, booking)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) GetBooking(id string) (*types.Booking, error) {
 | 
			
		||||
	m.mu.RLock()
 | 
			
		||||
	defer m.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	booking, exists := m.bookings[id]
 | 
			
		||||
	if !exists {
 | 
			
		||||
		return nil, fmt.Errorf("booking %s not found", id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return booking, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) UpdateBooking(booking types.Booking) error {
 | 
			
		||||
	m.mu.Lock()
 | 
			
		||||
	defer m.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	if _, exists := m.bookings[booking.Id]; !exists {
 | 
			
		||||
		return fmt.Errorf("booking %s not found", booking.Id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m.bookings[booking.Id] = &booking
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockStorage) UpdateBookingStatus(bookingid string, newStatus string, reason string) error {
 | 
			
		||||
	m.mu.Lock()
 | 
			
		||||
	defer m.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	booking, exists := m.bookings[bookingid]
 | 
			
		||||
	if !exists {
 | 
			
		||||
		return fmt.Errorf("booking %s not found", bookingid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	booking.Status = newStatus
 | 
			
		||||
	// In a real implementation, we might store the reason in a separate field
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper methods for testing
 | 
			
		||||
 | 
			
		||||
// Reset clears all data - useful for test setup
 | 
			
		||||
func (m *MockStorage) Reset() {
 | 
			
		||||
	m.mu.Lock()
 | 
			
		||||
	defer m.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	m.availabilities = make(map[string]*types.DriverRegularAvailability)
 | 
			
		||||
	m.journeys = make(map[string]*types.DriverJourney)
 | 
			
		||||
	m.bookings = make(map[string]*types.Booking)
 | 
			
		||||
	m.availabilitiesByDriver = make(map[string][]*types.DriverRegularAvailability)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetAllJourneys returns all stored journeys - useful for testing
 | 
			
		||||
func (m *MockStorage) GetAllJourneys() []*types.DriverJourney {
 | 
			
		||||
	m.mu.RLock()
 | 
			
		||||
	defer m.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	var result []*types.DriverJourney
 | 
			
		||||
	for _, journey := range m.journeys {
 | 
			
		||||
		result = append(result, journey)
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetAllAvailabilities returns all stored availabilities - useful for testing
 | 
			
		||||
func (m *MockStorage) GetAllAvailabilities() []*types.DriverRegularAvailability {
 | 
			
		||||
	m.mu.RLock()
 | 
			
		||||
	defer m.mu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	var result []*types.DriverRegularAvailability
 | 
			
		||||
	for _, availability := range m.availabilities {
 | 
			
		||||
		result = append(result, availability)
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +35,8 @@ func NewStorage(cfg *viper.Viper) (Storage, error) {
 | 
			
		|||
		return NewMongoDBStorage(cfg)
 | 
			
		||||
	case "memory":
 | 
			
		||||
		return NewMemoryStorage(cfg)
 | 
			
		||||
	case "mock":
 | 
			
		||||
		return NewMockStorage(cfg), nil
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, fmt.Errorf("storage type %v is not supported", storage_type)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,13 +3,15 @@ package types
 | 
			
		|||
import "time"
 | 
			
		||||
 | 
			
		||||
type Booking struct {
 | 
			
		||||
	Id                    string         `json:"id" bson:"_id"`
 | 
			
		||||
	GroupId               string         `json:"group_id" bson:"group_id"`
 | 
			
		||||
	DriverId              string         `json:"driver_id" bson:"driver_id"`
 | 
			
		||||
	PassengerId           string         `json:"passenger_id" bson:"passenger_id"`
 | 
			
		||||
	Status                string         `json:"status" bson:"status"`
 | 
			
		||||
	ReturnWaitingDuration time.Duration  `json:"return_waiting_duration" bson:"return_waiting_duration"`
 | 
			
		||||
	Data                  map[string]any `json:"data" bson:"data"`
 | 
			
		||||
	Id                       string         `json:"id" bson:"_id"`
 | 
			
		||||
	GroupId                  string         `json:"group_id" bson:"group_id"`
 | 
			
		||||
	DriverId                 string         `json:"driver_id" bson:"driver_id"`
 | 
			
		||||
	PassengerId              string         `json:"passenger_id" bson:"passenger_id"`
 | 
			
		||||
	Status                   string         `json:"status" bson:"status"`
 | 
			
		||||
	ReturnWaitingDuration    time.Duration  `json:"return_waiting_duration" bson:"return_waiting_duration"`
 | 
			
		||||
	Data                     map[string]any `json:"data" bson:"data"`
 | 
			
		||||
	DriverCompensationAmount float64        `json:"driver_compensation_amount" bson:"driver_compensation_amount"`
 | 
			
		||||
	DriverCompensationCurrency string      `json:"driver_compensation_currency" bson:"driver_compensation_currency"`
 | 
			
		||||
 | 
			
		||||
	Journey *DriverJourney `json:"journey,omitempty" bson:"journey,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue