|
|
@@ -92,11 +92,15 @@
|
|
|
<div v-if="currentStep === 3" class="space-y-4">
|
|
|
<h3 class="text-lg font-semibold mb-4">Paiement</h3>
|
|
|
|
|
|
+ <!-- Sélection de la méthode de paiement -->
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
<div class="bg-gray-50 p-4 rounded-md">
|
|
|
<h4 class="font-medium mb-2">Récapitulatif du paiement :</h4>
|
|
|
<p><strong>Réservation ID :</strong> {{ createdReservationId }}</p>
|
|
|
<p><strong>Montant :</strong> {{ formatPrice(totalAmount) }} FCFA</p>
|
|
|
- <p><strong>Méthode :</strong> Mobile Money</p>
|
|
|
+ <p><strong>Méthode :</strong> {{ getPaymentMethodText(props.paymentMethod) }}</p>
|
|
|
</div>
|
|
|
|
|
|
<div v-if="step3Error" class="text-red-600 text-sm">
|
|
|
@@ -156,8 +160,11 @@
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
import { ref, computed, watch } from 'vue'
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
import UserService from '@/services/UserService'
|
|
|
import ReservationService from '@/services/ReservationService'
|
|
|
+import CinetPayService from '@/services/CinetPayService'
|
|
|
+import { CinetPayCurrency, CinetPayChannels, CinetPayLanguage } from '@/types/cinetpay'
|
|
|
import TransactionService from '@/services/TransactionService'
|
|
|
import type { User, Reservation } from '@/types'
|
|
|
import { Role } from '@/Enum/Role'
|
|
|
@@ -176,6 +183,7 @@ interface Props {
|
|
|
totalAmount: number
|
|
|
tripId: number
|
|
|
tripDetails: string
|
|
|
+ paymentMethod: string
|
|
|
}
|
|
|
|
|
|
interface Emits {
|
|
|
@@ -185,15 +193,24 @@ interface Emits {
|
|
|
|
|
|
const props = defineProps<Props>()
|
|
|
const emit = defineEmits<Emits>()
|
|
|
+const router = useRouter()
|
|
|
|
|
|
// State
|
|
|
const currentStep = ref(1)
|
|
|
const isLoading = ref(false)
|
|
|
const loadingMessage = ref('')
|
|
|
const selectedMainPassenger = ref(0)
|
|
|
+const paymentSuccess = ref(false)
|
|
|
+// La méthode de paiement est maintenant reçue en prop
|
|
|
+// const selectedPaymentMethod = ref('mobile_money')
|
|
|
+
|
|
|
+// Collected data (not persisted until payment success)
|
|
|
+const collectedUserData = ref<any>(null)
|
|
|
+const collectedReservationData = ref<any[]>([])
|
|
|
+
|
|
|
+// Final created entities (after payment)
|
|
|
const createdUserId = ref<number | null>(null)
|
|
|
const createdReservationId = ref<number | null>(null)
|
|
|
-const paymentSuccess = ref(false)
|
|
|
|
|
|
// Error states
|
|
|
const step1Error = ref('')
|
|
|
@@ -225,10 +242,10 @@ const canProceed = computed(() => {
|
|
|
return mainPassenger.value && mainPassenger.value.name && mainPassenger.value.otherName && mainPassenger.value.phone
|
|
|
}
|
|
|
if (currentStep.value === 2) {
|
|
|
- return createdUserId.value !== null
|
|
|
+ return props.selectedSeats.length > 0 && props.passengers.length > 0
|
|
|
}
|
|
|
if (currentStep.value === 3) {
|
|
|
- return createdReservationId.value !== null
|
|
|
+ return collectedUserData.value !== null && collectedReservationData.value.length > 0 && props.paymentMethod
|
|
|
}
|
|
|
return false
|
|
|
})
|
|
|
@@ -253,9 +270,17 @@ const closeModal = () => {
|
|
|
currentStep.value = 1
|
|
|
isLoading.value = false
|
|
|
selectedMainPassenger.value = 0
|
|
|
+
|
|
|
+ // Reset collected data
|
|
|
+ collectedUserData.value = null
|
|
|
+ collectedReservationData.value = []
|
|
|
+
|
|
|
+ // Reset created entities
|
|
|
createdUserId.value = null
|
|
|
createdReservationId.value = null
|
|
|
paymentSuccess.value = false
|
|
|
+
|
|
|
+ // Reset errors
|
|
|
step1Error.value = ''
|
|
|
step2Error.value = ''
|
|
|
step3Error.value = ''
|
|
|
@@ -273,17 +298,17 @@ const nextStep = async () => {
|
|
|
if (!canProceed.value) return
|
|
|
|
|
|
if (currentStep.value === 1) {
|
|
|
- await createUser()
|
|
|
+ prepareUserData()
|
|
|
+ currentStep.value = 2
|
|
|
} else if (currentStep.value === 2) {
|
|
|
- await createReservation()
|
|
|
+ prepareReservationData()
|
|
|
+ currentStep.value = 3
|
|
|
} else if (currentStep.value === 3) {
|
|
|
await processPayment()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const createUser = async () => {
|
|
|
- isLoading.value = true
|
|
|
- loadingMessage.value = 'Création du compte utilisateur...'
|
|
|
+const prepareUserData = () => {
|
|
|
step1Error.value = ''
|
|
|
|
|
|
try {
|
|
|
@@ -296,124 +321,334 @@ const createUser = async () => {
|
|
|
}
|
|
|
|
|
|
delete userData.role
|
|
|
- const createdUser = await UserService.createUser(userData)
|
|
|
-
|
|
|
- if (createdUser && createdUser.id) {
|
|
|
- createdUserId.value = createdUser.id
|
|
|
- currentStep.value = 2
|
|
|
- } else {
|
|
|
- step1Error.value = 'Erreur lors de la création du compte utilisateur'
|
|
|
- }
|
|
|
+ collectedUserData.value = userData
|
|
|
} catch (error) {
|
|
|
- console.error('Erreur création utilisateur:', error)
|
|
|
- step1Error.value = 'Erreur lors de la création du compte utilisateur'
|
|
|
- } finally {
|
|
|
- isLoading.value = false
|
|
|
+ console.error('Erreur préparation données utilisateur:', error)
|
|
|
+ step1Error.value = 'Erreur lors de la préparation des données utilisateur'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const createReservation = async () => {
|
|
|
- isLoading.value = true
|
|
|
- loadingMessage.value = 'Création de la réservation...'
|
|
|
+const prepareReservationData = () => {
|
|
|
step2Error.value = ''
|
|
|
|
|
|
try {
|
|
|
- // Créer une réservation pour chaque passager/place
|
|
|
+ // Préparer les données de réservation pour chaque passager/place
|
|
|
const reservations = []
|
|
|
|
|
|
for (let i = 0; i < props.passengers.length; i++) {
|
|
|
const reservationData: Omit<Reservation, 'id'> = {
|
|
|
dateAt: new Date().toISOString(),
|
|
|
placeId: props.selectedSeats[i],
|
|
|
- userId: createdUserId.value!,
|
|
|
+ userId: 0, // Sera remplacé par l'ID utilisateur créé après paiement
|
|
|
trajetId: props.tripId
|
|
|
}
|
|
|
|
|
|
- const reservation = await ReservationService.createReservation(reservationData)
|
|
|
- console.log('Réservations créées 1:', reservations)
|
|
|
- if (reservation) {
|
|
|
- reservations.push(reservation)
|
|
|
- }
|
|
|
- }
|
|
|
- console.log('Réservations créées:', reservations) // Ajout de cette ligne pour débogage
|
|
|
- if (reservations.length > 0) {
|
|
|
- // Utiliser la première réservation comme référence principale
|
|
|
- console.log('Je suis dedans', reservations)
|
|
|
- createdReservationId.value = reservations[0].data.id
|
|
|
- currentStep.value = 3
|
|
|
- } else {
|
|
|
- step2Error.value = 'Erreur lors de la création de la réservation'
|
|
|
+ reservations.push(reservationData)
|
|
|
}
|
|
|
+
|
|
|
+ collectedReservationData.value = reservations
|
|
|
} catch (error) {
|
|
|
- console.error('Erreur création réservation:', error)
|
|
|
- step2Error.value = 'Erreur lors de la création de la réservation'
|
|
|
- } finally {
|
|
|
- isLoading.value = false
|
|
|
+ console.error('Erreur préparation données réservation:', error)
|
|
|
+ step2Error.value = 'Erreur lors de la préparation des données de réservation'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const processPayment = async () => {
|
|
|
+ if (!collectedUserData.value || !collectedReservationData.value.length) {
|
|
|
+ step3Error.value = 'Données utilisateur ou réservation manquantes'
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!props.paymentMethod) {
|
|
|
+ step3Error.value = 'Veuillez sélectionner une méthode de paiement'
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
isLoading.value = true
|
|
|
- loadingMessage.value = 'Traitement du paiement...'
|
|
|
+ loadingMessage.value = 'Initialisation du paiement...'
|
|
|
step3Error.value = ''
|
|
|
-
|
|
|
+
|
|
|
try {
|
|
|
- // Vérifier que nous avons un ID de réservation valide
|
|
|
- if (!createdReservationId.value || typeof createdReservationId.value !== 'number') {
|
|
|
- throw new Error('ID de réservation manquant ou invalide')
|
|
|
+ // Traitement selon la méthode de paiement sélectionnée
|
|
|
+ if (props.paymentMethod === 'mobile') {
|
|
|
+ // Utiliser CinetPay uniquement pour Mobile Money
|
|
|
+ await processMobileMoneyPayment()
|
|
|
+ } else if (props.paymentMethod === 'card') {
|
|
|
+ // Traitement pour carte bancaire (sans CinetPay)
|
|
|
+ await processCardPayment()
|
|
|
+ } else if (props.paymentMethod === 'cash') {
|
|
|
+ // Traitement pour paiement en espèces
|
|
|
+ await processCashPayment()
|
|
|
+ } else {
|
|
|
+ throw new Error('Méthode de paiement non supportée')
|
|
|
}
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Erreur paiement:', error)
|
|
|
|
|
|
- // Données pour CinetPay selon la documentation
|
|
|
- const cinetPayData = {
|
|
|
- apikey: "174173934865f8799156f094.97916229", // À remplacer par votre vraie clé API
|
|
|
- site_id: "105897483", // À remplacer par votre site ID
|
|
|
- transaction_id: `TRANSPORT_${createdReservationId.value}_${Date.now()}`, // ID unique de transaction
|
|
|
- amount: props.totalAmount,
|
|
|
- currency: "XOF",
|
|
|
- description: `Réservation transport - ${props.passengers.length} place(s)`,
|
|
|
- customer_id: createdUserId.value?.toString() || "guest",
|
|
|
- customer_name: mainPassenger.value.name || "",
|
|
|
- customer_surname: mainPassenger.value.otherName || "",
|
|
|
- customer_email: mainPassenger.value.email || generatedEmail.value,
|
|
|
- customer_phone_number: mainPassenger.value.phone,
|
|
|
- customer_address: "Côte d'Ivoire",
|
|
|
- customer_city: "Abidjan",
|
|
|
- customer_country: "CI",
|
|
|
- customer_state: "CI",
|
|
|
- customer_zip_code: "00225",
|
|
|
- notify_url: `${window.location.origin}/api/payments/cinetpay/notify`,
|
|
|
- return_url: `${window.location.origin}/payment/success?reservation=${createdReservationId.value}`,
|
|
|
- channels: "MOBILE_MONEY", // Uniquement mobile money
|
|
|
- metadata: JSON.stringify({ reservationId: createdReservationId.value }),
|
|
|
- lang: "FR"
|
|
|
+ if (error instanceof Error) {
|
|
|
+ step3Error.value = `❌ ${error.message}`
|
|
|
+ } else {
|
|
|
+ step3Error.value = '❌ Erreur lors du traitement du paiement'
|
|
|
}
|
|
|
+ } finally {
|
|
|
+ isLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Traitement spécifique pour Mobile Money avec CinetPay
|
|
|
+const processMobileMoneyPayment = async () => {
|
|
|
+ // Préparer les données pour CinetPay selon la documentation officielle
|
|
|
+ const paymentData = {
|
|
|
+ amount: props.totalAmount,
|
|
|
+ currency: CinetPayCurrency.EUR,
|
|
|
+ description: `Réservation transport - ${props.passengers.length} place(s)`,
|
|
|
+ customerData: {
|
|
|
+ id: generatedEmail.value,
|
|
|
+ name: mainPassenger.value.name || "",
|
|
|
+ surname: mainPassenger.value.otherName || "",
|
|
|
+ email: generatedEmail.value,
|
|
|
+ phone: mainPassenger.value.phone,
|
|
|
+ address: "Côte d'Ivoire",
|
|
|
+ city: "Abidjan",
|
|
|
+ country: "CI",
|
|
|
+ state: "CI",
|
|
|
+ zipCode: "00225"
|
|
|
+ },
|
|
|
+ metadata: {
|
|
|
+ userData: collectedUserData.value,
|
|
|
+ reservationData: collectedReservationData.value,
|
|
|
+ tripId: props.tripId
|
|
|
+ },
|
|
|
+ channels: CinetPayChannels.MOBILE_MONEY,
|
|
|
+ lang: CinetPayLanguage.FR
|
|
|
+ }
|
|
|
+
|
|
|
+ loadingMessage.value = 'Génération du lien de paiement Mobile Money...'
|
|
|
+
|
|
|
+ // Utiliser le service CinetPay pour initialiser le paiement
|
|
|
+ const result = await CinetPayService.initializePayment(paymentData)
|
|
|
|
|
|
- // Appel à l'API CinetPay pour générer l'URL de paiement
|
|
|
- const paymentResult = await fetch('https://api-checkout.cinetpay.com/v2/payment', {
|
|
|
- method: 'POST',
|
|
|
- headers: { 'Content-Type': 'application/json' },
|
|
|
- body: JSON.stringify(cinetPayData)
|
|
|
- })
|
|
|
+ // Vérifier la réponse de CinetPay
|
|
|
+ if (result.code === '201' && result.data && result.data.payment_url) {
|
|
|
+ loadingMessage.value = 'Redirection vers le paiement...'
|
|
|
+
|
|
|
+ // Sauvegarder les données CinetPay pour référence future
|
|
|
+ const cinetPayResponseData = {
|
|
|
+ transaction_id: result.data.transaction_id,
|
|
|
+ payment_token: result.data.payment_token,
|
|
|
+ payment_url: result.data.payment_url,
|
|
|
+ amount: result.data.amount,
|
|
|
+ currency: result.data.currency,
|
|
|
+ description: result.data.description,
|
|
|
+ created_at: result.data.created_at,
|
|
|
+ api_response_code: result.code,
|
|
|
+ api_response_message: result.message
|
|
|
+ }
|
|
|
+
|
|
|
+ // En mode test, simuler un paiement réussi
|
|
|
+ // En production, rediriger vers result.data.payment_url
|
|
|
+ if (import.meta.env.DEV) {
|
|
|
+ console.log('Mode développement - Simulation du paiement')
|
|
|
+ console.log('URL de paiement générée:', result.data.payment_url)
|
|
|
+ console.log('Données CinetPay à sauvegarder:', cinetPayResponseData)
|
|
|
+ await simulatePaymentSuccess(cinetPayResponseData)
|
|
|
+ } else {
|
|
|
+ // En production, sauvegarder les données CinetPay dans le localStorage pour les récupérer au retour
|
|
|
+ localStorage.setItem('cinetpay_pending_data', JSON.stringify({
|
|
|
+ cinetPayResponse: cinetPayResponseData,
|
|
|
+ userData: collectedUserData.value,
|
|
|
+ reservationData: collectedReservationData.value,
|
|
|
+ totalAmount: props.totalAmount,
|
|
|
+ tripId: props.tripId
|
|
|
+ }))
|
|
|
+
|
|
|
+ // Rediriger vers l'URL de paiement CinetPay
|
|
|
+ window.location.href = result.data.payment_url
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Erreur spécifique du service de paiement CinetPay
|
|
|
+ const errorMessage = result.message || 'Service de paiement indisponible'
|
|
|
+ throw new Error(`Erreur du service de paiement: ${errorMessage}`)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Traitement pour carte bancaire (sans CinetPay)
|
|
|
+const processCardPayment = async () => {
|
|
|
+ loadingMessage.value = 'Traitement du paiement par carte...'
|
|
|
+
|
|
|
+ // Simulation du paiement par carte bancaire
|
|
|
+ // En production, intégrer avec un autre service de paiement pour les cartes
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 2000))
|
|
|
+
|
|
|
+ // Simuler un paiement réussi
|
|
|
+ const cardPaymentData = {
|
|
|
+ transaction_id: `CARD_${Date.now()}`,
|
|
|
+ payment_method: 'CARD',
|
|
|
+ amount: props.totalAmount,
|
|
|
+ currency: 'XOF',
|
|
|
+ status: 'SUCCESS'
|
|
|
+ }
|
|
|
+
|
|
|
+ await simulatePaymentSuccess(cardPaymentData)
|
|
|
+}
|
|
|
+
|
|
|
+// Traitement pour paiement en espèces
|
|
|
+const processCashPayment = async () => {
|
|
|
+ loadingMessage.value = 'Confirmation de la réservation...'
|
|
|
+
|
|
|
+ // Pour le paiement en espèces, créer directement la réservation
|
|
|
+ // Le paiement sera effectué à bord du véhicule
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 1000))
|
|
|
+
|
|
|
+ const cashPaymentData = {
|
|
|
+ transaction_id: `CASH_${Date.now()}`,
|
|
|
+ payment_method: 'CASH',
|
|
|
+ amount: props.totalAmount,
|
|
|
+ currency: 'XOF',
|
|
|
+ status: 'PENDING' // Le paiement sera effectué plus tard
|
|
|
+ }
|
|
|
+
|
|
|
+ await simulatePaymentSuccess(cashPaymentData)
|
|
|
+}
|
|
|
+
|
|
|
+// Fonction pour simuler un paiement réussi et créer toutes les entités
|
|
|
+const simulatePaymentSuccess = async (cinetPayResponseData = null) => {
|
|
|
+ console.log('je suis ici')
|
|
|
+ try {
|
|
|
+ loadingMessage.value = 'Création du compte utilisateur...'
|
|
|
+
|
|
|
+ // 1. Créer l'utilisateur
|
|
|
+ const createdUser = await UserService.createUser(collectedUserData.value)
|
|
|
|
|
|
- if (!paymentResult.ok) {
|
|
|
- throw new Error(`Erreur HTTP CinetPay: ${paymentResult.status}`)
|
|
|
+ if (!createdUser || !createdUser.id) {
|
|
|
+ throw new Error('Erreur lors de la création du compte utilisateur')
|
|
|
}
|
|
|
|
|
|
- const result = await paymentResult.json()
|
|
|
+ createdUserId.value = createdUser.id
|
|
|
+ loadingMessage.value = 'Création des réservations...'
|
|
|
|
|
|
- // Vérifier la réponse de CinetPay
|
|
|
- if (result.code === '201' && result.data && result.data.payment_url) {
|
|
|
- // Rediriger vers l'URL de paiement CinetPay
|
|
|
- window.location.href = result.data.payment_url
|
|
|
- } else {
|
|
|
- throw new Error(result.message || 'Erreur lors de la génération du lien de paiement')
|
|
|
+ // 2. Créer les réservations avec l'ID utilisateur
|
|
|
+ const reservations = []
|
|
|
+
|
|
|
+ for (const reservationData of collectedReservationData.value) {
|
|
|
+ const updatedReservationData = {
|
|
|
+ ...reservationData,
|
|
|
+ userId: createdUser.id
|
|
|
+ }
|
|
|
+
|
|
|
+ const reservation = await ReservationService.createReservation(updatedReservationData)
|
|
|
+ if (reservation && reservation.data && reservation.data.id) {
|
|
|
+ reservations.push(reservation.data)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (reservations.length === 0) {
|
|
|
+ throw new Error('Erreur lors de la création des réservations')
|
|
|
+ }
|
|
|
+
|
|
|
+ // Utiliser la première réservation comme référence principale
|
|
|
+ createdReservationId.value = reservations[0].id
|
|
|
+
|
|
|
+ // 3. Créer la transaction avec les données CinetPay simulées
|
|
|
+ loadingMessage.value = 'Enregistrement de la transaction...'
|
|
|
+
|
|
|
+ // Utiliser les vraies données de paiement ou simuler une réponse
|
|
|
+ const paymentResponse = cinetPayResponseData ? {
|
|
|
+ code: cinetPayResponseData.api_response_code || '201',
|
|
|
+ message: cinetPayResponseData.api_response_message || 'Payment successful',
|
|
|
+ data: {
|
|
|
+ transaction_id: cinetPayResponseData.transaction_id,
|
|
|
+ payment_token: cinetPayResponseData.payment_token,
|
|
|
+ payment_url: cinetPayResponseData.payment_url,
|
|
|
+ payment_method: cinetPayResponseData.payment_method || props.paymentMethod.toUpperCase(),
|
|
|
+ operator_id: props.paymentMethod === 'mobile' ? 'ORANGE_CI' : null, // Seulement pour mobile money
|
|
|
+ phone_number: collectedUserData.value?.phone || '',
|
|
|
+ amount: cinetPayResponseData.amount || props.totalAmount,
|
|
|
+ currency: cinetPayResponseData.currency || 'EUR',
|
|
|
+ status: 'COMPLETED', // En simulation, toujours réussi
|
|
|
+ created_at: cinetPayResponseData.created_at
|
|
|
+ }
|
|
|
+ } : {
|
|
|
+ // Données simulées selon la méthode de paiement sélectionnée
|
|
|
+ code: '201',
|
|
|
+ message: 'Payment successful',
|
|
|
+ data: {
|
|
|
+ transaction_id: `${props.paymentMethod.toUpperCase()}_${Date.now()}`,
|
|
|
+ payment_token: props.paymentMethod === 'mobile' ? `TOKEN_${Math.random().toString(36).substr(2, 9)}` : null,
|
|
|
+ payment_url: props.paymentMethod === 'mobile' ? 'https://checkout.cinetpay.com/payment/mock' : null,
|
|
|
+ payment_method: props.paymentMethod.toUpperCase(),
|
|
|
+ operator_id: props.paymentMethod === 'mobile' ? 'ORANGE_CI' : null,
|
|
|
+ phone_number: collectedUserData.value?.phone || '',
|
|
|
+ amount: props.totalAmount,
|
|
|
+ currency: 'XOF',
|
|
|
+ status: props.paymentMethod === 'cash' ? 'PENDING' : 'COMPLETED'
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Créer la transaction pour chaque réservation
|
|
|
+ for (const reservation of reservations) {
|
|
|
+ const transactionData = {
|
|
|
+ amount: props.totalAmount / reservations.length, // Répartir le montant
|
|
|
+ currency: 'XOF',
|
|
|
+ status: paymentResponse.data.status,
|
|
|
+ provider: props.paymentMethod === 'mobile' ? 'CinetPay' : getPaymentMethodText(props.paymentMethod),
|
|
|
+ reference: paymentResponse.data.transaction_id,
|
|
|
+ metadata: {
|
|
|
+ payment_response: paymentResponse,
|
|
|
+ payment_method: paymentResponse.data.payment_method,
|
|
|
+ operator_id: paymentResponse.data.operator_id,
|
|
|
+ phone_number: paymentResponse.data.phone_number,
|
|
|
+ reservation_details: {
|
|
|
+ trajet: `${reservation.trajet?.departStation?.name || ''} → ${reservation.trajet?.arriveStation?.name || ''}`,
|
|
|
+ departure_time: reservation.trajet?.departAt,
|
|
|
+ place_number: reservation.place?.number
|
|
|
+ }
|
|
|
+ },
|
|
|
+ userId: createdUser.id,
|
|
|
+ reservationId: reservation.id
|
|
|
+ }
|
|
|
+
|
|
|
+ const transaction = await TransactionService.createTransaction(transactionData)
|
|
|
+ if (transaction) {
|
|
|
+ console.log('Transaction créée:', transaction.id, 'pour la réservation:', reservation.id)
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ // 4. Marquer le paiement comme réussi
|
|
|
+ paymentSuccess.value = true
|
|
|
+ loadingMessage.value = 'Réservation confirmée !'
|
|
|
+
|
|
|
+ // Émettre l'événement de succès
|
|
|
+ emit('success', createdReservationId.value)
|
|
|
+
|
|
|
+ // Rediriger vers l'espace utilisateur après un délai
|
|
|
+ setTimeout(() => {
|
|
|
+ router.push('/user/dashboard')
|
|
|
+ }, 2000)
|
|
|
+
|
|
|
} catch (error) {
|
|
|
- console.error('Erreur paiement CinetPay:', error)
|
|
|
- step3Error.value = error instanceof Error ? error.message : 'Erreur lors du traitement du paiement'
|
|
|
- } finally {
|
|
|
- isLoading.value = false
|
|
|
+ console.error('Erreur lors de la création des entités:', error)
|
|
|
+ step3Error.value = error instanceof Error ? error.message : 'Erreur lors de la finalisation de la réservation'
|
|
|
+
|
|
|
+ // En cas d'erreur, nettoyer les entités partiellement créées si nécessaire
|
|
|
+ if (createdUserId.value) {
|
|
|
+ // Ici on pourrait ajouter une logique de nettoyage si nécessaire
|
|
|
+ console.warn('Utilisateur créé mais réservation échouée, ID:', createdUserId.value)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Fonction pour obtenir le texte de la méthode de paiement
|
|
|
+const getPaymentMethodText = (method: string) => {
|
|
|
+ switch (method) {
|
|
|
+ case 'mobile_money':
|
|
|
+ return 'Mobile Money'
|
|
|
+ case 'card':
|
|
|
+ return 'Carte bancaire'
|
|
|
+ case 'cash':
|
|
|
+ return 'Espèces'
|
|
|
+ default:
|
|
|
+ return 'Non défini'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -422,9 +657,17 @@ watch(() => props.isOpen, (newValue) => {
|
|
|
if (newValue) {
|
|
|
currentStep.value = 1
|
|
|
selectedMainPassenger.value = 0
|
|
|
+
|
|
|
+ // Reset collected data
|
|
|
+ collectedUserData.value = null
|
|
|
+ collectedReservationData.value = []
|
|
|
+
|
|
|
+ // Reset created entities
|
|
|
createdUserId.value = null
|
|
|
createdReservationId.value = null
|
|
|
paymentSuccess.value = false
|
|
|
+
|
|
|
+ // Reset errors
|
|
|
step1Error.value = ''
|
|
|
step2Error.value = ''
|
|
|
step3Error.value = ''
|