43720482c4
Run Tests / test (pull_request) Successful in 2m3s
實作 openspec change provider-verification-workflow(25/25 tasks): - is_verified 升級為 verification_status 四狀態機(unsubmitted/pending/ approved/rejected),migration 自動轉換既有資料,API 以 accessor 保留 is_verified 相容輸出 - 教練端:證照上傳(≤3 張、複用 CompressesImages)、送審、駁回原因 顯示與重送(/coach/verification 新頁面) - Admin 端:審核佇列、通過/駁回(原因必填)、撤銷 approved;移除 toggle-verified 端點(防繞過狀態機);裁決後 flush 課程快取 - 通知:審核通過/駁回(站內+Email,駁回含原因) - 可見性與預約入口改判 approved(行為等價) - 測試 +18(ProviderVerificationTest 10、AdminVerificationTest 8), 既有 4 個測試檔 helper 遷移;Swagger 同步 - 規格同步:provider-verification 全面改寫、admin-user-management toggle 段落改為移除聲明 容器內全套件 173 passed / 439 assertions。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
84 lines
2.1 KiB
PHP
84 lines
2.1 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class DivingOffer extends Model
|
|
{
|
|
public $timestamps = false;
|
|
|
|
protected $table = 'diving_offers';
|
|
|
|
protected $fillable = [
|
|
'provider_id',
|
|
'title',
|
|
'location',
|
|
'spot',
|
|
'rating',
|
|
'reviews',
|
|
'price',
|
|
'badges',
|
|
'description',
|
|
'tag',
|
|
'region',
|
|
'cover_image',
|
|
];
|
|
|
|
protected $casts = [
|
|
'badges' => 'array',
|
|
'rating' => 'float',
|
|
'price' => 'integer',
|
|
'reviews'=> 'integer',
|
|
];
|
|
|
|
protected static function booted(): void
|
|
{
|
|
static::deleting(function ($offer) {
|
|
Storage::disk('public')->deleteDirectory("offers/{$offer->id}");
|
|
});
|
|
}
|
|
|
|
public function getCoverImageUrlAttribute(): ?string
|
|
{
|
|
return $this->cover_image
|
|
? Storage::disk('public')->url($this->cover_image)
|
|
: null;
|
|
}
|
|
|
|
public function provider(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'provider_id');
|
|
}
|
|
|
|
/**
|
|
* 公開端點可見性:未通過審核(approved)教練的課程不對外曝光。
|
|
* provider_id 為 null 的課程(平台自有資料)不受此限制。
|
|
*/
|
|
public function scopeVisibleToPublic(Builder $query): Builder
|
|
{
|
|
return $query->where(function (Builder $visible) {
|
|
$visible->whereNull('provider_id')
|
|
->orWhereHas('provider.providerProfile', fn (Builder $profile) => $profile->where('verification_status', \App\Enums\VerificationStatus::Approved->value));
|
|
});
|
|
}
|
|
|
|
public function schedules()
|
|
{
|
|
return $this->hasMany(CourseSchedule::class, 'diving_offer_id');
|
|
}
|
|
|
|
public function courseImages()
|
|
{
|
|
return $this->hasMany(CourseImage::class)->orderBy('sort_order');
|
|
}
|
|
|
|
public function reviews()
|
|
{
|
|
return $this->hasMany(Review::class);
|
|
}
|
|
}
|