diff --git a/app/Exports/OddsExporter.php b/app/Exports/OddsExporter.php new file mode 100644 index 00000000..b53db184 --- /dev/null +++ b/app/Exports/OddsExporter.php @@ -0,0 +1,51 @@ +data = $data; + } + + // Übergibt die flachen Zeilendaten an Excel + public function array(): array + { + return $this->data; + } + + // Definiert die Kopfzeile im Excel-Sheet + public function headings(): array + { + return [ + 'Match Id', + 'BetsApi Id', + 'Betradar Id', + 'Bet365 Id', + 'Starttime', + 'Sport Id', + 'Group Id', + 'Group', + 'Home Id', + 'Home', + 'Away Id', + 'Away', + 'Book Id', + 'Book', + 'One', + 'X', + 'Two', + 'Book Id To', + 'Book To', + 'Over', + 'Under', + 'Total', + ]; + } +} diff --git a/app/Filament/Exports/MainMarketsExporter.php b/app/Filament/Exports/MainMarketsExporter.php new file mode 100644 index 00000000..fa1f3d4e --- /dev/null +++ b/app/Filament/Exports/MainMarketsExporter.php @@ -0,0 +1,62 @@ +label('TxOdds id'), + ExportColumn::make('betsapi_id'), + ExportColumn::make('betradar_id'), + ExportColumn::make('bet365_id'), + ExportColumn::make('starttime'), + ExportColumn::make('sport_id'), + ExportColumn::make('country_id'), + ExportColumn::make('country.name'), + ExportColumn::make('competition_group_id') + ->label('Group id'), + ExportColumn::make('competition_group.name') + ->label('Group'), + ExportColumn::make('home_id'), + ExportColumn::make('home.name'), + ExportColumn::make('away_id'), + ExportColumn::make('away.name'), + ExportColumn::make('odds_3ways.bookmaker_id'), + ExportColumn::make('odds_3ways.h3w'), + ExportColumn::make('odds_3ways.h3w') + ->label('1'), + ExportColumn::make('odds_3ways.d3w') + ->label('X'), + ExportColumn::make('odds_3ways.a3w') + ->label('2'), + ExportColumn::make('odds_totals.over') + ->label('Over'), + ExportColumn::make('odds_totals.under') + ->label('Under'), + ExportColumn::make('odds_totals.total') + ->label('Total'), + ]; + } + + public static function getCompletedNotificationBody(Export $export): string + { + $body = 'Your event export has completed and '.Number::format($export->successful_rows).' '.str('row')->plural($export->successful_rows).' exported.'; + + if ($failedRowsCount = $export->getFailedRowsCount()) { + $body .= ' '.Number::format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to export.'; + } + + return $body; + } +} diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index 43052b3a..01912d57 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -2,10 +2,12 @@ namespace App\Providers\Filament; +use App\Exports\OddsExporter; use App\Filament\Exports\BetfairExporter; use App\Filament\Pages\PlayerProps; use App\Filament\Pages\Statistic; use App\Http\Middleware\RecordUserActivity; +use App\Models\Event; use Awcodes\LightSwitch\Enums\Alignment; use Awcodes\LightSwitch\LightSwitchPlugin; use BezhanSalleh\FilamentShield\FilamentShieldPlugin; @@ -28,10 +30,12 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\Session\Middleware\StartSession; +use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Auth; use Illuminate\View\Middleware\ShareErrorsFromSession; use Joaopaulolndev\FilamentEditProfile\FilamentEditProfilePlugin; use Joaopaulolndev\FilamentEditProfile\Pages\EditProfilePage; +use Maatwebsite\Excel\Facades\Excel; use Swis\Filament\Backgrounds\FilamentBackgroundsPlugin; use Swis\Filament\Backgrounds\ImageProviders\MyImages; @@ -50,13 +54,74 @@ class AdminPanelProvider extends PanelProvider ExportAction::make('download_betfair') ->columnMapping(false) ->exporter(BetfairExporter::class) - ->label('Download Betfair') + ->label('Betfair Odds') ->visible(fn (): bool => Auth::user()->hasRole('download_betfair')) ->fileName(fn (Export $export): string => 'betfair-odds-'.date('d.m.Y-H.i')."-{$export->getKey()}") ->modifyQueryUsing(fn (Builder $query) => $query->whereHas('odds_3ways_bf') ->whereHas('odds_totals_bf') ->where('sport_id', 1)) ->icon('phosphor-download'), + 'export' => Action::make('bookmaker_odds_download') + ->label('Bookmakers Odds') + ->visible(fn (): bool => Auth::user()->hasRole('download_betfair')) + ->icon('phosphor-download') + ->color('success') + ->action(function () { + $rows = []; + + $events = Event::with(['odds_3ways', 'odds_totals', 'competition_group'])->where('starttime', '>', Carbon::now())->where('starttime', '<', Carbon::now()->addDays(15))->orderBy('starttime', 'ASC')->get(); + + foreach ($events as $event) { + + $event->loadMissing(['odds_3ways', 'odds_totals']); + + $totals = []; + foreach ($event->odds_totals as $item) { + $bkmid = $item->bookmaker_id; + $totals[$bkmid]['bookid'] = $item->bookmaker_id; + $totals[$bkmid]['book'] = $item->bookmaker->name; + $totals[$bkmid]['over'] = $item->over; + $totals[$bkmid]['under'] = $item->under; + $totals[$bkmid]['total'] = $item->total; + } + foreach ($event->odds_3ways as $item) { + $bkmid = $item->bookmaker_id; + $tmp = []; + $tmp['Match Id'] = $event->id; + $tmp['BetsApi Id'] = $event->betsapi_id; + $tmp['Betradar Id'] = $event->betradar_id; + $tmp['Bet365 Id'] = $event->bet365_id; + $tmp['Starttime'] = $event->starttime; + $tmp['Sport Id'] = $event->sport_id; + $tmp['Group Id'] = $event->competition_group_id; + $tmp['Group'] = $event->competition_group->name; + $tmp['Home Id'] = $event->home_id; + $tmp['Home'] = $event->home->name; + $tmp['Away Id'] = $event->away_id; + $tmp['Away'] = $event->away->name; + $tmp['Book Id'] = $item->bookmaker->name; + $tmp['Book'] = $bkmid; + $tmp['One'] = $item->h3w; + $tmp['X'] = $item->d3w; + $tmp['Two'] = $item->a3w; + + if (isset($totals[$bkmid])) { + $tmp['Book Id To'] = $bkmid; + $tmp['Book To'] = $totals[$bkmid]['book']; + $tmp['Over'] = $totals[$bkmid]['over']; + $tmp['Under'] = $totals[$bkmid]['under']; + $tmp['Total'] = $totals[$bkmid]['total']; + } + $rows[] = $tmp; + } + } + + // Triggert den direkten Browser-Download der fertigen Excel-Datei + return Excel::download( + new OddsExporter($rows), + 'major-markets-'.now()->format('Y-m-d-H-i').'.xlsx' + ); + }), ]) ->path('') ->login() diff --git a/composer.json b/composer.json index 8b286e69..d3296b22 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "joaopaulolndev/filament-edit-profile": "^3.0", "laravel/framework": "*", "laravel/tinker": "*", + "maatwebsite/excel": "^4.0", "mongodb/laravel-mongodb": "^5.1", "mongodb/mongodb": "^2.4", "neitanod/forceutf8": "^2.0", diff --git a/composer.lock b/composer.lock index af1050ed..6cff3e19 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8d093dac61786eebf4170291bee0c826", + "content-hash": "5c1a30c60933343a06d5d23fce85a4f5", "packages": [ { "name": "agencetwogether/hookshelper", @@ -1173,6 +1173,83 @@ ], "time": "2026-06-07T11:47:49+00:00" }, + { + "name": "composer/semver", + "version": "3.5.1", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "528948210cc46f967a4b98e83b19e76f2b504993" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/528948210cc46f967a4b98e83b19e76f2b504993", + "reference": "528948210cc46f967a4b98e83b19e76f2b504993", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Version comparison library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.5.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2026-10-05T13:12:12+00:00" + }, { "name": "danharrin/date-format-converter", "version": "v0.3.1", @@ -4242,6 +4319,95 @@ ], "time": "2026-09-28T18:12:51+00:00" }, + { + "name": "maatwebsite/excel", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/SpartnerNL/Laravel-Excel.git", + "reference": "30f17acbb89bf260173387349722eec2cc817016" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/30f17acbb89bf260173387349722eec2cc817016", + "reference": "30f17acbb89bf260173387349722eec2cc817016", + "shasum": "" + }, + "require": { + "composer/semver": "^3.4", + "illuminate/support": "^12.0 || ^13.0", + "php": "^8.3", + "phpoffice/phpspreadsheet": "^5.9", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "brianium/paratest": "^7.20", + "driftingly/rector-laravel": "^2.5", + "ext-sqlite3": "*", + "larastan/larastan": "^3.10", + "laravel/pint": "^1.29", + "laravel/scout": "^10.25 || ^11.2", + "orchestra/testbench": "^10.11 || ^11.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan-mockery": "^2.0", + "phpunit/phpunit": "^12.5 || ~13.1.14", + "predis/predis": "^2.3 || ^3.0", + "rector/rector": "^2.4.2" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Excel": "Maatwebsite\\Excel\\Facades\\Excel" + }, + "providers": [ + "Maatwebsite\\Excel\\ExcelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Maatwebsite\\Excel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Patrick Brouwers", + "email": "patrick@spartner.nl" + } + ], + "description": "Supercharged Excel exports and imports in Laravel", + "keywords": [ + "PHPExcel", + "batch", + "csv", + "excel", + "export", + "import", + "laravel", + "php", + "phpspreadsheet" + ], + "support": { + "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", + "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/4.0.4" + }, + "funding": [ + { + "url": "https://laravel-excel.com/commercial-support", + "type": "custom" + }, + { + "url": "https://github.com/patrickbrouwers", + "type": "github" + } + ], + "time": "2026-10-12T08:40:04+00:00" + }, { "name": "maennchen/zipstream-php", "version": "3.2.2",