grapper betsapi fixtures

This commit is contained in:
salam committed 2026-01-01 16:41:33 +01:00
1 parent cec5a5e2f7
commit e90a6c71f6
18 files changed
+3335 -3054

No files matched your search

@@ -26,6 +26,7 @@ class Bwin
/**
* BWIN ODDS & BETRADAR ID (per page)
* only get BETRADAR ID no storing of data
*/
$base_url = 'https://api.b365api.com/v1/bwin/prematch?token='.config('env.betsapi_token').'&skip_markets=1&page=###page###&sport_id='.$bwin_sport_id;
@@ -5,17 +5,28 @@ namespace App\Console\Commands\Grapper\Betsapi;
use App\Console\Commands\Curl;
use App\Console\Commands\Nuh;
use App\Mapper\FindEvent;
use App\Mapper\LoadElements;
use App\Mapper\LoadGroups;
use App\Models\Sport;
use App\Utilities\Notice;
use Illuminate\Support\Carbon;
class Fixtures
{
public static $elements = [];
public static $groups = [];
public static function grap()
{
$debug = Nuh::$options['d'] ?? 0;
$break = Nuh::$options['b'] ?? 0;
self::$elements = LoadElements::load(Nuh::$options['provider_id']);
self::$groups = LoadGroups::load(Nuh::$options['provider_id']);
$sportmap = Sport::map('bapi');
$now = Carbon::now();
@@ -73,7 +84,7 @@ class Fixtures
'group_cc' => strtoupper($row['league']['cc']) ?? '',
];
FindEvent::search($event);
FindEvent::search($event, self::$groups[$sport_id], self::$elements[$sport_id]);
}
}
}
@@ -4,6 +4,10 @@ namespace App\Console\Commands\Grapper\Betsapi;
use App\Console\Commands\Curl;
use App\Console\Commands\Nuh;
use App\Mapper\LoadElements;
use App\Mapper\LoadGroups;
use App\Mapper\StoreElement;
use App\Mapper\StoreGroup;
use App\Models\Event;
use App\Models\Mapper;
use App\Models\Odds3way;
@@ -15,6 +19,12 @@ class Willhill
{
$debug = Nuh::$options['d'] ?? 0;
$sport_id = 1;
$elements = LoadElements::load(Nuh::$options['provider_id']);
$groups = LoadGroups::load(Nuh::$options['provider_id']);
/**
* williamhill
*/
@@ -23,6 +33,7 @@ class Willhill
$res = Odds3way::join('events', 'odds_3ways.event_id', 'events.id')
->where('odds_3ways.bookmaker_id', $bookmaker_id)
->where('events.betsapi_id', 0)
->where('events.sport_id', $sport_id)
->where('odds_3ways.bmoid', '>', 0)->pluck('odds_3ways.event_id', 'odds_3ways.bmoid');
foreach ($res as $willhill_id => $txodds_id) {
@@ -40,7 +51,36 @@ class Willhill
}
if ($betsapi_id) {
Event::where('id', (int) $txodds_id)->update(['betsapi_id' => $betsapi_id, 'bet365_id' => $bet365_id]);
$match = Event::where('id', (int) $txodds_id)->first();
$ele = [];
$ele['sport_id'] = $sport_id;
$ele['provider_id'] = Nuh::$options['provider_id'];
$ele['element_id'] = $match->home_id ?? 0;
$ele['provider_element_id'] = $data['results'][0]['home']['id'] ?? 0;
$ele['name'] = $data['results'][0]['home']['name'];
StoreElement::store($elements, $ele);
$ele = [];
$ele['sport_id'] = $sport_id;
$ele['provider_id'] = Nuh::$options['provider_id'];
$ele['element_id'] = $match->away_id ?? 0;
$ele['provider_element_id'] = $data['results'][0]['away']['id'] ?? 0;
$ele['name'] = $data['results'][0]['away']['name'];
StoreElement::store($elements, $ele);
$group = [];
$group['sport_id'] = $sport_id;
$group['provider_id'] = Nuh::$options['provider_id'];
$group['competition_group_id'] = $match->competition_group_id;
$group['provider_group_id'] = $data['results'][0]['league']['id'] ?? 0;
$group['name'] = $data['results'][0]['league']['name'];
StoreGroup::store($groups, $group);
$match->betsapi_id = $betsapi_id;
$match->bet365_id = $bet365_id;
$match->save();
Mapper::where('event_id', $betsapi_id)->delete();
}
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1 +1 @@
{"success":1,"pager":{"page":1,"per_page":50,"total":103},"results":[{"id":"11196131","sport_id":"1","time":"1767265200","time_status":"0","league":{"id":"2369","name":"Syria Division 1","cc":"sy"},"home":{"id":"1232083","name":"Omaya SC","image_id":"1311226","cc":"sy"},"away":{"id":"184357","name":"Hutteen","image_id":"189388","cc":"sy"},"ss":null,"round":"3"},{"id":"11196132","sport_id":"1","time":"1767265200","time_status":"0","league":{"id":"2369","name":"Syria Division 1","cc":"sy"},"home":{"id":"177711","name":"Tishreen","image_id":"157792","cc":"sy"},"away":{"id":"1231539","name":"Khan Shaykhun SC","image_id":"1311228","cc":"sy"},"ss":null,"round":"3"},{"id":"11198690","sport_id":"1","time":"1767265200","time_status":"0","league":{"id":"42027","name":"Algeria U20 League","cc":"dz"},"home":{"id":"1194258","name":"ES Ben Aknoun U20","image_id":"1292973","cc":"dz"},"away":{"id":"1206680","name":"Paradou AC U20","image_id":"1300782","cc":"dz"},"ss":null,"bet365_id":"187231851"},{"id":"10173612","sport_id":"1","time":"1767270600","time_status":"0","league":{"id":"880","name":"England Championship","cc":"gb"},"home":{"id":"17201","name":"Blackburn","image_id":"46","cc":"gb"},"away":{"id":"1875","name":"Wrexham","image_id":"64","cc":"gb"},"ss":null,"round":"25","bet365_id":"186496893"},{"id":"10270360","sport_id":"1","time":"1767270600","time_status":"0","league":{"id":"156","name":"Wales Premier League","cc":"gb"},"home":{"id":"60899","name":"Colwyn Bay","image_id":"597088","cc":"gb"},"away":{"id":"8512","name":"Flint Town Utd","image_id":"37090","cc":"gb"},"ss":null,"round":"21","bet365_id":"185889723"},{"id":"10476839","sport_id":"1","time":"1767270900","time_status":"0","league":{"id":"809","name":"Saudi Arabia Division 1","cc":"sa"},"home":{"id":"56220","name":"Al Orubah","image_id":"114259","cc":"sa"},"away":{"id":"682282","name":"Al Jandal","image_id":"522144","cc":"sa"},"ss":null,"round":"14","bet365_id":"185936511"},{"id":"10476859","sport_id":"1","time":"1767270900","time_status":"0","league":{"id":"809","name":"Saudi Arabia Division 1","cc":"sa"},"home":{"id":"56221","name":"Al Taee","image_id":"168072","cc":"sa"},"away":{"id":"583338","name":"Al Zulfi","image_id":"757980","cc":"sa"},"ss":null,"round":"14","bet365_id":"185936514"},{"id":"11133547","sport_id":"1","time":"1767271800","time_status":"0","league":{"id":"1945","name":"Saudi Arabia Division 2","cc":"sa"},"home":{"id":"244281","name":"Weg Taif SC","image_id":"276755","cc":"sa"},"away":{"id":"622080","name":"Al Rayyan Ar Rawdah","image_id":"857289","cc":"sa"},"ss":null,"round":"13"},{"id":"10321213","sport_id":"1","time":"1767272400","time_status":"0","league":{"id":"319","name":"England Northern Premier League","cc":"gb"},"home":{"id":"46501","name":"Morpeth Town","image_id":"47120","cc":"gb"},"away":{"id":"193388","name":"Stockton Town","image_id":"630010","cc":"gb"},"ss":null,"round":"25","bet365_id":"186823577"},{"id":"10874159","sport_id":"1","time":"1767272400","time_status":"0","league":{"id":"854","name":"Iran Pro League","cc":"ir"},"home":{"id":"15854","name":"Sepahan","image_id":"8018","cc":"ir"},"away":{"id":"43979","name":"Esteghlal","image_id":"34316","cc":"ir"},"ss":"3-0","round":"10"},{"id":"11173754","sport_id":"1","time":"1767272400","time_status":"0","league":{"id":"39521","name":"Iraq Stars League","cc":"iq"},"home":{"id":"284537","name":"Al Minaa","image_id":"405353","cc":"iq"},"away":{"id":"594899","name":"Newroz SC","image_id":"845058","cc":"iq"},"ss":null,"round":"9","bet365_id":"187165073"},{"id":"11173872","sport_id":"1","time":"1767272400","time_status":"0","league":{"id":"39521","name":"Iraq Stars League","cc":"iq"},"home":{"id":"284412","name":"Al Najaf","image_id":"508998","cc":"iq"},"away":{"id":"239046","name":"Al Naft SC","image_id":"508988","cc":"iq"},"ss":null,"round":"9","bet365_id":"187149701"},{"id":"11202124","sport_id":"1","time":"1767272400","time_status":"0","league":{"id":"1212","name":"England Northern League Division One","cc":"gb"},"home":{"id":"172842","name":"Grimsby Borough","image_id":"58005","cc":"gb"},"away":{"id":"507428","name":"North Ferriby","image_id":"170","cc":"gb"},"ss":null,"bet365_id":"187149512"},{"id":"11202354","sport_id":"1","time":"1767272400","time_status":"0","league":{"id":"1212","name":"England Northern League Division One","cc":"gb"},"home":{"id":"64562","name":"Bedworth Utd","image_id":"188","cc":"gb"},"away":{"id":"296243","name":"Coventry Sphinx","image_id":"37994","cc":"gb"},"ss":null,"bet365_id":"187149503"},{"id":"11205156","sport_id":"1","time":"1767273600","time_status":"0","league":{"id":"12352","name":"Oman U21 Championship","cc":"om"},"home":{"id":"241665","name":"Dhofar U21","image_id":null,"cc":null},"away":{"id":"1231918","name":"Al Shabab Seeb U21","image_id":null,"cc":null},"ss":null,"bet365_id":"187161283"},{"id":"10205757","sport_id":"1","time":"1767276000","time_status":"0","league":{"id":"18163","name":"Wales Championship North","cc":"gb"},"home":{Line truncated
{"success":1,"pager":{"page":1,"per_page":50,"total":118},"results":[{"id":"11205969","sport_id":"1","time":"1767312000","time_status":"0","league":{"id":"32086","name":"Sierra Leone Premier League","cc":"sl"},"home":{"id":"807038","name":"Luawa FC","image_id":"976023","cc":"sl"},"away":{"id":"1107248","name":"Bullom Stars","image_id":"1227141","cc":"sl"},"ss":null,"bet365_id":"187264995"},{"id":"11204558","sport_id":"1","time":"1767324600","time_status":"0","league":{"id":"3726","name":"India League Women","cc":"in"},"home":{"id":"1232296","name":"Gokulam Kerala FC (W)","image_id":"417727","cc":"in"},"away":{"id":"1233191","name":"Garhwal United (W)","image_id":"1250925","cc":"in"},"ss":null,"bet365_id":"187151600"},{"id":"11204559","sport_id":"1","time":"1767324600","time_status":"0","league":{"id":"3726","name":"India League Women","cc":"in"},"home":{"id":"1176727","name":"Kickstart Karnataka FC (W)","image_id":"678415","cc":"in"},"away":{"id":"1231917","name":"Sribhumi FC (W)","image_id":"676603","cc":"in"},"ss":null,"bet365_id":"187151605"},{"id":"11204534","sport_id":"1","time":"1767331800","time_status":"0","league":{"id":"14959","name":"India Delhi Senior Division","cc":"in"},"home":{"id":"270701","name":"Jaguar FC (India)","image_id":"303564","cc":"in"},"o_home":{"id":"236714","name":"Jaguar FC","image_id":"430845","cc":"au"},"away":{"id":"1128257","name":"M2M FC","image_id":"1245746","cc":"in"},"ss":null,"bet365_id":"187151505"},{"id":"11204544","sport_id":"1","time":"1767339000","time_status":"0","league":{"id":"42582","name":"India Bengal Super League","cc":"in"},"home":{"id":"1234888","name":"Howrah Hooghly Warriors","image_id":"1313608","cc":"in"},"away":{"id":"1235171","name":"JHR Royal City FC","image_id":null,"cc":null},"ss":null,"bet365_id":"187149267"},{"id":"11202121","sport_id":"1","time":"1767340800","time_status":"0","league":{"id":"42027","name":"Algeria U20 League","cc":"dz"},"home":{"id":"1213704","name":"GC Mascara U20","image_id":"1304486","cc":"dz"},"away":{"id":"1235068","name":"MB Ain Hadjar U20","image_id":null,"cc":null},"ss":null,"bet365_id":"187233071"},{"id":"11202156","sport_id":"1","time":"1767340800","time_status":"0","league":{"id":"834","name":"Algeria Division 1","cc":"dz"},"home":{"id":"27180","name":"JS Kabylie","image_id":"42202","cc":"dz"},"away":{"id":"46305","name":"MC Alger","image_id":"42204","cc":"dz"},"ss":null,"bet365_id":"187233073"},{"id":"11204655","sport_id":"1","time":"1767340800","time_status":"0","league":{"id":"42027","name":"Algeria U20 League","cc":"dz"},"home":{"id":"1213704","name":"GC Mascara U20","image_id":"1304486","cc":"dz"},"away":{"id":"1210732","name":"Mb Ain Hdjer U20","image_id":"1302480","cc":"dz"},"ss":null},{"id":"10733545","sport_id":"1","time":"1767342600","time_status":"0","league":{"id":"820","name":"Bangladesh Premier League","cc":"bd"},"home":{"id":"48294","name":"Brothers Union","image_id":"336965","cc":"bd"},"away":{"id":"48560","name":"Mohammedan Dhaka","image_id":"275093","cc":"bd"},"ss":null,"round":"9","bet365_id":"187155183"},{"id":"11204535","sport_id":"1","time":"1767342600","time_status":"0","league":{"id":"14959","name":"India Delhi Senior Division","cc":"in"},"home":{"id":"177885","name":"Ahbab FC","image_id":"396446","cc":"in"},"away":{"id":"270807","name":"Rangers SC","image_id":"561390","cc":"in"},"ss":null,"bet365_id":"187159249"},{"id":"10650729","sport_id":"1","time":"1767342900","time_status":"0","league":{"id":"1727","name":"Australia A-League","cc":"au"},"home":{"id":"50643","name":"Melbourne Victory","image_id":"5970","cc":"au"},"away":{"id":"2463","name":"Perth Glory","image_id":"2945","cc":"au"},"ss":null,"round":"11","bet365_id":"185933007"},{"id":"11202146","sport_id":"1","time":"1767344400","time_status":"0","league":{"id":"36349","name":"Algeria Elite Championship Women","cc":"dz"},"home":{"id":"1203504","name":"Afak Relizane (W)","image_id":"509986","cc":"dz"},"away":{"id":"1213182","name":"CF Akbou (W)","image_id":"388558","cc":"dz"},"ss":null,"bet365_id":"187207243"},{"id":"11202147","sport_id":"1","time":"1767344400","time_status":"0","league":{"id":"36349","name":"Algeria Elite Championship Women","cc":"dz"},"home":{"id":"1216683","name":"CR Belouizdad (W)","image_id":"1084372","cc":"dz"},"away":{"id":"1216682","name":"ALS Batna (W)","image_id":"543765","cc":"dz"},"ss":null,"bet365_id":"187233075"},{"id":"11202148","sport_id":"1","time":"1767344400","time_status":"0","league":{"id":"36349","name":"Algeria Elite Championship Women","cc":"dz"},"home":{"id":"1213181","name":"FC Bejaia (W)","image_id":"388556","cc":"dz"},"away":{"id":"1224160","name":"RS Tissemsilt (W)","image_id":null,"cc":null},"ss":null,"bet365_id":"187233080"},{"id":"11204461","sport_id":"1","time":"1767344400","time_status":"0","league":{"id":"36349","name":"Algeria Elite Championship Women","cc":"dz"},"home":{"id":"1218636","name":"JS Kabylie (W)","image_id":"1099083","cc":"dz"},"away":{"id":"1203506","name":"CEA Setif (W)Line truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"success":1,"results":[{"id":"10119811","sport_id":"1","time":"1767288600","time_status":"0","league":{"id":"94","name":"England Premier League","cc":"gb"},"home":{"id":"17189","name":"Crystal Palace","image_id":"7","cc":"gb"},"away":{"id":"17170","name":"Fulham","image_id":"43","cc":"gb"},"ss":null,"extra":{"away_manager":{"id":"59685","name":"Marco Silva","cc":"pt"},"home_manager":{"id":"3318","name":"Oliver Glasner","cc":"at"},"numberofperiods":"2","periodlength":"45","referee":{"id":"84853","name":"Tony Harrington","cc":"gb"},"stadium_data":{"id":"10","name":"Selhurst Park","city":"London","country":"England","capacity":"25073","googlecoords":"51.398333,-0.085556"},"length":90,"round":"19"},"has_lineup":0,"bet365_id":"186071619","matching_dir":"1"}]}
+84 -7
View File
@@ -4,25 +4,102 @@ namespace App\Mapper;
use App\Models\Event;
use App\Models\Mapper;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Carbon;
class FindEvent
{
public static function search($event)
public static function search($event, &$groups, &$elements)
{
dd($event);
$event_id = $event['event_id'];
$match_id = Event::where('betsapi_id', $event_id)->value('id');
unset($event['event_id']);
switch ($event['provider_id']) {
case 2:
// BETSAPI
$match_id = Event::where('betsapi_id', $event_id)->value('id');
break;
case 3:
// MAGLOO KENIA
$match_id = Event::where('magken_id', $event_id)->value('id');
break;
case 4:
// MAGLOO NIGERIA
$match_id = Event::where('magnig_id', $event_id)->value('id');
break;
case 5:
// LOGIFUTUR NIGERA
$match_id = Event::where('lognig_id', $event_id)->value('id');
break;
case 6:
// LOGIFUTUR COLOMBIA
$match_id = Event::where('logcol_id', $event_id)->value('id');
break;
default:
Notice::note('unknown provider', 'r', 1);
break;
}
if ($match_id) {
Mapper::where('event_id', $event_id)->delete();
} else {
Mapper::updateOrCreate(['event_id' => $event_id], $event);
}
$home_id = $elements[$event['home_id']] ?? 0;
return Mapper::query()->where('sport_id', Auth::user()->sport_id)->where('provider_id', Auth::user()->provider_id);
$away_id = $elements[$event['away_id']] ?? 0;
$cgid = $groups[$event['group_id']] ?? 0;
$startime = $event['starttime'];
if ($home_id && $away_id && $cgid) {
$from = Carbon::createFromDate($startime)->remvoDay();
$to = Carbon::createFromDate($starttime_period['end'])->subDay();
$match_id = Event::query()
->where('home_id', $home_id)
->where('away_id', $away_id)
->where('competition_group_id', $competition_group_id)
->where('starttime', '>', $from)
->where('starttime', '<', $to)
->value('id')
->get();
if ($match_id) {
Event::where('betsapi_id', (int) $betsapi_id)->update(['betradar_id' => $betradar_id, 'bwin_id' => $bwin_id]);
switch ($event['provider_id']) {
case 2:
// BETSAPI
Event::where('id', $match_id)->update(['betsapi_id' => $event_id]);
break;
case 3:
// MAGLOO KENIA
Event::where('id', $match_id)->update(['magken_id' => $event_id]);
break;
case 4:
// MAGLOO NIGERIA
Event::where('id', $match_id)->update(['magnig_id' => $event_id]);
break;
case 5:
// LOGIFUTUR NIGERA
Event::where('id', $match_id)->update(['lognig_id' => $event_id]);
break;
case 6:
// LOGIFUTUR COLOMBIA
Event::where('id', $match_id)->update(['logcol_id' => $event_id]);
break;
default:
}
} else {
Mapper::updateOrCreate(['event_id' => $event_id], $event);
}
} else {
Mapper::updateOrCreate(['event_id' => $event_id], $event);
}
}
}
}
+20
View File
@@ -0,0 +1,20 @@
<?php
namespace App\Mapper;
use App\Models\ElementProvider;
class LoadElements
{
public static function load($provider_id)
{
$res = ElementProvider::where('provider_id', $provider_id)->get();
$r = [];
foreach ($res as $val) {
$r[$val->sport_id][$val->provider_element_id] = $val->element_id;
}
return $r;
}
}
+20
View File
@@ -0,0 +1,20 @@
<?php
namespace App\Mapper;
use App\Models\CompetitionGroupProvider;
class LoadGroups
{
public static function load($provider_id)
{
$res = CompetitionGroupProvider::where('provider_id', $provider_id)->get();
$r = [];
foreach ($res as $val) {
$r[$val->sport_id][$val->provider_group_id] = $val->competition_group_id;
}
return $r;
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\Mapper;
use App\Models\ElementProvider;
class StoreElement
{
public static function store(&$elements, $ele)
{
$provider_element_id = $ele['provider_element_id'] ?? 0;
unset($ele['provider_element_id']);
$sport_id = $ele['sport_id'] ?? 0;
if (! isset($elements[$sport_id][$provider_element_id])) {
ElementProvider::updateOrCreate(['provider_element_id' => (int) $provider_element_id], $ele);
}
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\Mapper;
use App\Models\CompetitionGroupProvider;
class StoreGroup
{
public static function store(&$groups, $group)
{
$provider_group_id = $group['provider_group_id'] ?? 0;
unset($group['provider_group_id']);
$sport_id = $group['sport_id'] ?? 0;
if (! isset($groups[$sport_id][$provider_group_id])) {
CompetitionGroupProvider::updateOrCreate(['provider_group_id' => (int) $provider_group_id], $group);
}
}
}
@@ -4,12 +4,13 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CompetitionGroupFilter extends Model
class CompetitionGroupProvider extends Model
{
protected $fillable = [
'sport_id',
'competition_group_id',
'bkm_competition_group_id',
'bookmaker_id',
'provider_id',
'provider_group_id',
'name',
];
@@ -18,8 +19,8 @@ class CompetitionGroupFilter extends Model
return $this->belongsTo(CompetitionGroup::class);
}
public function bookmaker()
public function provider()
{
return $this->belongsTo(Bookmaker::class);
return $this->belongsTo(Provider::class);
}
}
@@ -4,13 +4,15 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ElementFilter extends Model
class ElementProvider extends Model
{
protected $fillable = [
'name',
'sport_id',
'element_id',
'bkm_element_id',
'bookmaker_id',
'provider_id',
'provider_element_id',
'name',
];
public function element()
@@ -18,8 +20,8 @@ class ElementFilter extends Model
return $this->belongsTo(Element::class);
}
public function bookmaker()
public function provider()
{
return $this->belongsTo(Bookmaker::class);
return $this->belongsTo(Provider::class);
}
}
+5
View File
@@ -27,4 +27,9 @@ class Mapper extends Model
{
return $this->belongsTo(Country::class, 'group_cc', 'iso2')->where('is_country', 1)->where('disabled', 0);
}
public function provider()
{
return $this->belongsTo(Provider::class);
}
}
@@ -14,7 +14,6 @@ return new class extends Migration
Schema::create('element_providers', function (Blueprint $table) {
$table->id();
$table->integer('sport_id')->index();
$table->integer('country_id')->default(0)->nullable()->index();
$table->integer('element_id')->index();
$table->integer('provider_id')->default(0)->nullable()->index();
$table->integer('provider_element_id')->index();
@@ -14,7 +14,6 @@ return new class extends Migration
Schema::create('competition_group_providers', function (Blueprint $table) {
$table->id();
$table->integer('sport_id')->index();
$table->integer('country_id')->default(0)->nullable()->index();
$table->integer('competition_group_id')->default(0)->nullable()->index();
$table->integer('provider_id')->default(0)->nullable()->index();
$table->integer('provider_group_id')->default(0)->nullable()->index();
@@ -15,7 +15,6 @@ return new class extends Migration
$table->id();
$table->integer('event_id')->index();
$table->integer('sport_id')->index();
$table->integer('bookmaker_id')->index();
$table->integer('provider_id')->default(0)->nullable()->index();
$table->dateTime('starttime')->nullable();
$table->string('group')->nullable();