feat(admin): star/tags marks, service product-type filter, campaign bulk actions, SMTP test
- Star (is_starred) and colored tags for services, customers, orders, invoices:
Markable trait, tags/taggables tables, PATCH administrator/marks/{type}/{key},
tag CRUD, list filters starred / tag_ids[]
- GET administrator/services accepts product_type (falls back to product type
for legacy rows without services.type)
- Mail campaigns: bulk cancel / retry failed / delete; cancelled campaigns are
skipped by SendMailCampaignRecipient
- POST administrator/settings/test-smtp sends a test email through the saved
mail transport
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
46aa138eec
commit
40bf6b54f9
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use App\Models\Customer;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Order;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
final class Markables
|
||||
{
|
||||
/**
|
||||
* @var array<string, array{model: class-string<Model>, key: string, permission: string}>
|
||||
*/
|
||||
public const TYPES = [
|
||||
'services' => ['model' => Service::class, 'key' => 'id', 'permission' => 'customer.edit'],
|
||||
'customers' => ['model' => Customer::class, 'key' => 'uuid', 'permission' => 'customer.edit'],
|
||||
'orders' => ['model' => Order::class, 'key' => 'id', 'permission' => 'order.edit'],
|
||||
'invoices' => ['model' => Invoice::class, 'key' => 'id', 'permission' => 'invoice.edit'],
|
||||
];
|
||||
|
||||
public static function find(string $type, string $key): Model
|
||||
{
|
||||
$definition = self::TYPES[$type];
|
||||
|
||||
return $definition['model']::query()->where($definition['key'], $key)->firstOrFail();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user