feat: Version 3.3.4 - Nouvelle architecture pages, optimisations widgets Flutter et API

- Mise à jour VERSION vers 3.3.4
- Optimisations et révisions architecture API (deploy-api.sh, scripts de migration)
- Ajout documentation Stripe Tap to Pay complète
- Migration vers polices Inter Variable pour Flutter
- Optimisations build Android et nettoyage fichiers temporaires
- Amélioration système de déploiement avec gestion backups
- Ajout scripts CRON et migrations base de données

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-10-05 20:11:15 +02:00
parent 2786252307
commit 570a1fa1f0
212 changed files with 24275 additions and 11321 deletions

226
bao/lib/helpers.php Normal file
View File

@@ -0,0 +1,226 @@
<?php
declare(strict_types=1);
/**
* Fonctions utilitaires pour BAO
*/
/**
* Affiche un message coloré dans le terminal
*/
function color(string $text, string $color = 'default'): string {
static $colors = [
'default' => "\033[0m",
'black' => "\033[0;30m",
'red' => "\033[0;31m",
'green' => "\033[0;32m",
'yellow' => "\033[0;33m",
'blue' => "\033[0;34m",
'magenta' => "\033[0;35m",
'cyan' => "\033[0;36m",
'white' => "\033[0;37m",
'bold' => "\033[1m",
'underline' => "\033[4m",
];
$config = DatabaseConfig::getInstance();
$colorsEnabled = $config->get('COLORS_ENABLED', 'true') === 'true';
if (!$colorsEnabled || !isset($colors[$color])) {
return $text;
}
return $colors[$color] . $text . $colors['default'];
}
/**
* Affiche un titre encadré
*/
function title(string $text): void {
$length = strlen($text);
$border = str_repeat('═', $length + 4);
echo color("\n{$border}\n", 'cyan');
echo color("{$text}\n", 'cyan');
echo color("{$border}\n\n", 'cyan');
}
/**
* Affiche un message de succès
*/
function success(string $message): void {
echo color("", 'green') . color($message, 'white') . "\n";
}
/**
* Affiche un message d'erreur
*/
function error(string $message): void {
echo color("", 'red') . color($message, 'white') . "\n";
}
/**
* Affiche un message d'avertissement
*/
function warning(string $message): void {
echo color("", 'yellow') . color($message, 'white') . "\n";
}
/**
* Affiche un message d'information
*/
function info(string $message): void {
echo color(" ", 'blue') . color($message, 'white') . "\n";
}
/**
* Affiche un label et sa valeur
*/
function display(string $label, ?string $value, bool $encrypted = false): void {
$labelColored = color($label . ':', 'yellow');
if ($value === null) {
$valueColored = color('(null)', 'magenta');
} elseif ($encrypted && strpos($value, 'base64:') === 0) {
$valueColored = color('[ENCRYPTED]', 'red');
} else {
$valueColored = color($value, 'white');
}
echo " {$labelColored} {$valueColored}\n";
}
/**
* Affiche une ligne de séparation
*/
function separator(int $length = 80): void {
echo color(str_repeat('─', $length), 'cyan') . "\n";
}
/**
* Demande une confirmation à l'utilisateur
*/
function confirm(string $question, bool $default = false): bool {
$suffix = $default ? '[O/n]' : '[o/N]';
echo color("{$question} {$suffix}: ", 'yellow');
$handle = fopen('php://stdin', 'r');
$line = trim(fgets($handle));
fclose($handle);
if (empty($line)) {
return $default;
}
return in_array(strtolower($line), ['o', 'oui', 'y', 'yes']);
}
/**
* Demande un choix parmi plusieurs options
*/
function choice(string $question, array $options, $default = null): string {
echo color("\n{$question}\n", 'yellow');
foreach ($options as $key => $label) {
$prefix = ($key === $default) ? color('*', 'green') : ' ';
echo " {$prefix} " . color((string)$key, 'cyan') . ") {$label}\n";
}
echo color("\nVotre choix: ", 'yellow');
$handle = fopen('php://stdin', 'r');
$line = trim(fgets($handle));
fclose($handle);
if (empty($line) && $default !== null) {
return (string)$default;
}
if (!isset($options[$line])) {
error("Choix invalide");
return choice($question, $options, $default);
}
return $line;
}
/**
* Affiche un tableau formaté
*/
function table(array $headers, array $rows, bool $showIndex = true): void {
if (empty($rows)) {
warning("Aucune donnée à afficher");
return;
}
// Calculer les largeurs de colonnes
$widths = [];
if ($showIndex) {
$widths['#'] = max(strlen((string)count($rows)), 1) + 1;
}
foreach ($headers as $key => $label) {
$widths[$key] = max(
strlen($label),
max(array_map(fn($row) => strlen((string)($row[$key] ?? '')), $rows))
) + 2;
}
// En-tête
separator();
if ($showIndex) {
echo color(str_pad('#', $widths['#']), 'bold');
}
foreach ($headers as $key => $label) {
echo color(str_pad($label, $widths[$key]), 'bold');
}
echo "\n";
separator();
// Lignes
foreach ($rows as $index => $row) {
if ($showIndex) {
echo color(str_pad((string)($index + 1), $widths['#']), 'cyan');
}
foreach ($headers as $key => $label) {
$value = $row[$key] ?? '';
echo str_pad((string)$value, $widths[$key]);
}
echo "\n";
}
separator();
}
/**
* Formate une date MySQL en français
*/
function formatDate(?string $date): string {
if (empty($date) || $date === '0000-00-00' || $date === '0000-00-00 00:00:00') {
return '-';
}
try {
$dt = new DateTime($date);
return $dt->format('d/m/Y H:i');
} catch (Exception $e) {
return $date;
}
}
/**
* Tronque une chaîne si elle est trop longue
*/
function truncate(string $text, int $length = 50): string {
if (strlen($text) <= $length) {
return $text;
}
return substr($text, 0, $length - 3) . '...';
}