# 🚀 Guia de Implementação - Controle de Abastecimentos no App Android

## 📋 **Resumo do que foi criado**

### ✅ **Backend Pronto:**
1. **Tabela:** `abastecimentos_rota` - Estrutura completa
2. **API:** `api-abastecimentos.php` - Todas as funcionalidades
3. **Painel Admin:** `abastecimentos-painel.html` - Visualização e relatórios
4. **Testes:** `teste-api-abastecimentos.php` - Verificação de funcionamento

### 🎯 **Funcionalidades Implementadas:**
- ✅ Registro de abastecimentos
- ✅ Busca por viagem, veículo, motorista
- ✅ Relatórios completos
- ✅ Sincronização automática
- ✅ Painel administrativo

---

## 📱 **Implementação no App Android (Forma Segura)**

### **Fase 1: Estrutura de Dados (Não afeta o app atual)**

#### **1.1 Criar Data Classes**
```kotlin
// app/src/main/java/com/example/controledefrotas/data/model/Abastecimento.kt
data class Abastecimento(
    val id: Long? = null,
    val viagemId: Long,
    val veiculoId: Long,
    val motoristaId: Long,
    val dataHora: String,
    val tipoCombustivel: String, // GASOLINA, ETANOL, DIESEL, FLEX
    val quantidadeLitros: Double,
    val valorLitro: Double,
    val valorTotal: Double,
    val odometroKm: Int? = null,
    val postoCombustivel: String? = null,
    val observacoes: String? = null,
    val fotoComprovante: String? = null,
    val sincronizado: Boolean = false,
    val createdAt: String? = null,
    val updatedAt: String? = null
)

// Request para API
data class AbastecimentoRequest(
    val viagem_id: Long,
    val veiculo_id: Long,
    val motorista_id: Long,
    val data_hora: String,
    val tipo_combustivel: String,
    val quantidade_litros: Double,
    val valor_litro: Double,
    val odometro_km: Int? = null,
    val posto_combustivel: String? = null,
    val observacoes: String? = null,
    val foto_comprovante: String? = null
)
```

#### **1.2 Criar DAO (Database)**
```kotlin
// app/src/main/java/com/example/controledefrotas/data/dao/AbastecimentoDao.kt
@Dao
interface AbastecimentoDao {
    @Insert
    suspend fun inserir(abastecimento: AbastecimentoEntity): Long
    
    @Query("SELECT * FROM abastecimentos_rota WHERE viagem_id = :viagemId ORDER BY data_hora DESC")
    suspend fun buscarPorViagem(viagemId: Long): List<AbastecimentoEntity>
    
    @Query("SELECT * FROM abastecimentos_rota WHERE sincronizado = 0")
    suspend fun buscarNaoSincronizados(): List<AbastecimentoEntity>
    
    @Update
    suspend fun atualizar(abastecimento: AbastecimentoEntity)
    
    @Query("UPDATE abastecimentos_rota SET sincronizado = 1 WHERE id IN (:ids)")
    suspend fun marcarComoSincronizado(ids: List<Long>)
}
```

#### **1.3 Criar Entity (Room)**
```kotlin
// app/src/main/java/com/example/controledefrotas/data/entity/AbastecimentoEntity.kt
@Entity(tableName = "abastecimentos_rota")
data class AbastecimentoEntity(
    @PrimaryKey(autoGenerate = true)
    val id: Long = 0,
    val viagem_id: Long,
    val veiculo_id: Long,
    val motorista_id: Long,
    val data_hora: String,
    val tipo_combustivel: String,
    val quantidade_litros: Double,
    val valor_litro: Double,
    val valor_total: Double,
    val odometro_km: Int? = null,
    val posto_combustivel: String? = null,
    val observacoes: String? = null,
    val foto_comprovante: String? = null,
    val sincronizado: Boolean = false,
    val created_at: String? = null,
    val updated_at: String? = null
)
```

### **Fase 2: API Service (Não afeta o app atual)**

#### **2.1 Adicionar endpoints na ApiService**
```kotlin
// app/src/main/java/com/example/controledefrotas/data/service/ApiService.kt
// ADICIONAR NO FINAL DA CLASSE (não mexer no código existente)

@POST("api-abastecimentos.php?acao=registrar_abastecimento")
suspend fun registrarAbastecimento(@Body request: AbastecimentoRequest): Response<ApiResponse<Abastecimento>>

@GET("api-abastecimentos.php?acao=buscar_por_viagem")
suspend fun buscarAbastecimentosPorViagem(@Query("viagemId") viagemId: Long): Response<ApiResponse<List<Abastecimento>>>

@POST("api-abastecimentos.php?acao=atualizar_sincronizacao")
suspend fun atualizarSincronizacao(@Body request: SincronizacaoRequest): Response<ApiResponse<Unit>>
```

### **Fase 3: Repository (Não afeta o app atual)**

#### **3.1 Criar Repository**
```kotlin
// app/src/main/java/com/example/controledefrotas/data/repository/AbastecimentoRepository.kt
@Singleton
class AbastecimentoRepository @Inject constructor(
    private val apiService: ApiService,
    private val abastecimentoDao: AbastecimentoDao,
    @ApplicationContext private val context: Context
) {
    suspend fun registrarAbastecimento(abastecimento: Abastecimento): Result<Abastecimento> {
        return try {
            // Salvar localmente primeiro
            val entity = abastecimento.toEntity()
            val id = abastecimentoDao.inserir(entity)
            
            // Tentar sincronizar
            val request = abastecimento.toRequest()
            val response = apiService.registrarAbastecimento(request)
            
            if (response.isSuccessful && response.body()?.success == true) {
                // Marcar como sincronizado
                abastecimentoDao.marcarComoSincronizado(listOf(id))
                Result.success(abastecimento.copy(id = id))
            } else {
                // Manter como não sincronizado para tentar depois
                Result.success(abastecimento.copy(id = id))
            }
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    suspend fun buscarPorViagem(viagemId: Long): Result<List<Abastecimento>> {
        return try {
            val abastecimentos = abastecimentoDao.buscarPorViagem(viagemId)
            Result.success(abastecimentos.map { it.toModel() })
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
    
    suspend fun sincronizarPendentes() {
        try {
            val naoSincronizados = abastecimentoDao.buscarNaoSincronizados()
            if (naoSincronizados.isNotEmpty()) {
                // Implementar lógica de sincronização em background
                // Similar ao ChecklistSyncService
            }
        } catch (e: Exception) {
            Log.e("AbastecimentoRepository", "Erro na sincronização", e)
        }
    }
}
```

### **Fase 4: ViewModel (Não afeta o app atual)**

#### **4.1 Criar ViewModel**
```kotlin
// app/src/main/java/com/example/controledefrotas/presentation/abastecimento/AbastecimentoViewModel.kt
@HiltViewModel
class AbastecimentoViewModel @Inject constructor(
    private val repository: AbastecimentoRepository
) : ViewModel() {
    
    private val _uiState = MutableStateFlow<AbastecimentoUiState>(AbastecimentoUiState.Loading)
    val uiState: StateFlow<AbastecimentoUiState> = _uiState.asStateFlow()
    
    fun registrarAbastecimento(abastecimento: Abastecimento) {
        viewModelScope.launch {
            _uiState.value = AbastecimentoUiState.Loading
            try {
                val result = repository.registrarAbastecimento(abastecimento)
                result.fold(
                    onSuccess = { _uiState.value = AbastecimentoUiState.Success(it) },
                    onFailure = { _uiState.value = AbastecimentoUiState.Error(it.message ?: "Erro desconhecido") }
                )
            } catch (e: Exception) {
                _uiState.value = AbastecimentoUiState.Error(e.message ?: "Erro desconhecido")
            }
        }
    }
    
    fun buscarPorViagem(viagemId: Long) {
        viewModelScope.launch {
            _uiState.value = AbastecimentoUiState.Loading
            try {
                val result = repository.buscarPorViagem(viagemId)
                result.fold(
                    onSuccess = { _uiState.value = AbastecimentoUiState.ListaSuccess(it) },
                    onFailure = { _uiState.value = AbastecimentoUiState.Error(it.message ?: "Erro desconhecido") }
                )
            } catch (e: Exception) {
                _uiState.value = AbastecimentoUiState.Error(e.message ?: "Erro desconhecido")
            }
        }
    }
}

sealed class AbastecimentoUiState {
    object Loading : AbastecimentoUiState()
    data class Success(val abastecimento: Abastecimento) : AbastecimentoUiState()
    data class ListaSuccess(val abastecimentos: List<Abastecimento>) : AbastecimentoUiState()
    data class Error(val message: String) : AbastecimentoUiState()
}
```

### **Fase 5: Telas (Novas telas independentes)**

#### **5.1 Tela de Registro de Abastecimento**
```kotlin
// app/src/main/java/com/example/controledefrotas/presentation/abastecimento/RegistrarAbastecimentoScreen.kt
@Composable
fun RegistrarAbastecimentoScreen(
    viewModel: AbastecimentoViewModel = hiltViewModel(),
    viagemId: Long,
    onNavigateBack: () -> Unit
) {
    var tipoCombustivel by remember { mutableStateOf("FLEX") }
    var quantidadeLitros by remember { mutableStateOf("") }
    var valorLitro by remember { mutableStateOf("") }
    var odometroKm by remember { mutableStateOf("") }
    var postoCombustivel by remember { mutableStateOf("") }
    var observacoes by remember { mutableStateOf("") }
    
    val uiState by viewModel.uiState.collectAsState()
    
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Text(
            text = "Registrar Abastecimento",
            style = MaterialTheme.typography.h4,
            modifier = Modifier.padding(bottom = 16.dp)
        )
        
        // Campos do formulário
        OutlinedTextField(
            value = quantidadeLitros,
            onValueChange = { quantidadeLitros = it },
            label = { Text("Quantidade (Litros)") },
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
            modifier = Modifier.fillMaxWidth()
        )
        
        Spacer(modifier = Modifier.height(8.dp))
        
        OutlinedTextField(
            value = valorLitro,
            onValueChange = { valorLitro = it },
            label = { Text("Valor por Litro (R$)") },
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
            modifier = Modifier.fillMaxWidth()
        )
        
        Spacer(modifier = Modifier.height(8.dp))
        
        OutlinedTextField(
            value = odometroKm,
            onValueChange = { odometroKm = it },
            label = { Text("Odômetro (KM)") },
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
            modifier = Modifier.fillMaxWidth()
        )
        
        Spacer(modifier = Modifier.height(8.dp))
        
        OutlinedTextField(
            value = postoCombustivel,
            onValueChange = { postoCombustivel = it },
            label = { Text("Posto de Combustível") },
            modifier = Modifier.fillMaxWidth()
        )
        
        Spacer(modifier = Modifier.height(16.dp))
        
        Button(
            onClick = {
                // Implementar registro
                val abastecimento = Abastecimento(
                    viagemId = viagemId,
                    veiculoId = 6, // Pegar do contexto atual
                    motoristaId = 1, // Pegar do contexto atual
                    dataHora = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date()),
                    tipoCombustivel = tipoCombustivel,
                    quantidadeLitros = quantidadeLitros.toDoubleOrNull() ?: 0.0,
                    valorLitro = valorLitro.toDoubleOrNull() ?: 0.0,
                    valorTotal = (quantidadeLitros.toDoubleOrNull() ?: 0.0) * (valorLitro.toDoubleOrNull() ?: 0.0),
                    odometroKm = odometroKm.toIntOrNull(),
                    postoCombustivel = postoCombustivel.takeIf { it.isNotEmpty() },
                    observacoes = observacoes.takeIf { it.isNotEmpty() }
                )
                viewModel.registrarAbastecimento(abastecimento)
            },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text("Registrar Abastecimento")
        }
        
        when (uiState) {
            is AbastecimentoUiState.Loading -> {
                CircularProgressIndicator(
                    modifier = Modifier.align(Alignment.CenterHorizontally)
                )
            }
            is AbastecimentoUiState.Success -> {
                LaunchedEffect(Unit) {
                    onNavigateBack()
                }
            }
            is AbastecimentoUiState.Error -> {
                Text(
                    text = uiState.message,
                    color = MaterialTheme.colors.error,
                    modifier = Modifier.padding(top = 8.dp)
                )
            }
            else -> {}
        }
    }
}
```

#### **5.2 Tela de Histórico**
```kotlin
// app/src/main/java/com/example/controledefrotas/presentation/abastecimento/HistoricoAbastecimentosScreen.kt
@Composable
fun HistoricoAbastecimentosScreen(
    viewModel: AbastecimentoViewModel = hiltViewModel(),
    viagemId: Long
) {
    val uiState by viewModel.uiState.collectAsState()
    
    LaunchedEffect(viagemId) {
        viewModel.buscarPorViagem(viagemId)
    }
    
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Text(
            text = "Histórico de Abastecimentos",
            style = MaterialTheme.typography.h4,
            modifier = Modifier.padding(bottom = 16.dp)
        )
        
        when (uiState) {
            is AbastecimentoUiState.Loading -> {
                CircularProgressIndicator(
                    modifier = Modifier.align(Alignment.CenterHorizontally)
                )
            }
            is AbastecimentoUiState.ListaSuccess -> {
                LazyColumn {
                    items(uiState.abastecimentos) { abastecimento ->
                        AbastecimentoItem(abastecimento = abastecimento)
                    }
                }
            }
            is AbastecimentoUiState.Error -> {
                Text(
                    text = uiState.message,
                    color = MaterialTheme.colors.error
                )
            }
            else -> {}
        }
    }
}

@Composable
fun AbastecimentoItem(abastecimento: Abastecimento) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(vertical = 4.dp),
        elevation = 4.dp
    ) {
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            Text(
                text = "R$ ${String.format("%.2f", abastecimento.valorTotal)}",
                style = MaterialTheme.typography.h6,
                color = MaterialTheme.colors.primary
            )
            
            Text(
                text = "${abastecimento.quantidadeLitros} L de ${abastecimento.tipoCombustivel}",
                style = MaterialTheme.typography.body1
            )
            
            Text(
                text = "R$ ${String.format("%.2f", abastecimento.valorLitro)}/L",
                style = MaterialTheme.typography.body2,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
            )
            
            if (abastecimento.postoCombustivel != null) {
                Text(
                    text = "Posto: ${abastecimento.postoCombustivel}",
                    style = MaterialTheme.typography.body2,
                    color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
                )
            }
            
            Text(
                text = SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.getDefault())
                    .format(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
                        .parse(abastecimento.dataHora) ?: Date()),
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
            )
        }
    }
}
```

---

## 🔧 **Passos para Implementação Segura**

### **1. Testar o Backend Primeiro**
```bash
# Acessar no navegador:
https://sistemas.pinheiroempresas.com.br/controlefrotaV1.1/backend-php/teste-api-abastecimentos.php
```

### **2. Implementar no App Android (Ordem Segura)**
1. **Criar data classes** (não afeta nada)
2. **Criar DAO e Entity** (não afeta nada)
3. **Adicionar endpoints na API** (não afeta nada)
4. **Criar Repository** (não afeta nada)
5. **Criar ViewModel** (não afeta nada)
6. **Criar telas** (novas telas independentes)
7. **Adicionar navegação** (apenas adicionar, não modificar)

### **3. Integração com Sistema Existente**
- **Adicionar botão** na tela de viagem: "Abastecimentos"
- **Navegar** para as novas telas
- **Sincronização** em background (similar ao checklist)

---

## 🎯 **Resultado Final**

### **Para o Motorista:**
- ✅ Nova tela para registrar abastecimentos
- ✅ Histórico de abastecimentos da rota
- ✅ Sincronização automática
- ✅ Captura de foto do comprovante (futuro)

### **Para o Administrador:**
- ✅ Painel completo de relatórios
- ✅ Filtros por período, veículo, motorista
- ✅ Estatísticas detalhadas
- ✅ Exportação de dados

### **Segurança:**
- ✅ Não afeta o app atual
- ✅ Código independente
- ✅ Testes completos
- ✅ Implementação gradual

---

## 🚀 **Próximos Passos**

1. **Testar o backend** com o script criado
2. **Implementar data classes** no app
3. **Criar telas** uma por vez
4. **Testar cada funcionalidade**
5. **Integrar com sistema existente**

**Quer que eu comece implementando alguma parte específica no app Android?** 📱
