- Gửi email theo template cho 1 khách, tab lịch sử email, nhắc gia hạn dịch vụ hàng loạt - Mail lưu from/bcc/sent_by; mẫu MARKETING và mẫu cũ trong TemplateSeeder - Gói hosting: giới hạn, trạng thái, lấy plan Plesk qua CLI gateway - Backfill payment_method và ngày đơn hàng còn thiếu - Bổ sung field CPU/RAM/Disk/Băng thông cho loại sản phẩm vps và cloud Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
134 lines
4.2 KiB
PHP
134 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use App\Models\Template;
|
|
use App\Support\EmailTemplateShell;
|
|
use App\Support\MailPlaceholders;
|
|
use Database\Seeders\EmailTemplates\AccountTemplates;
|
|
use Database\Seeders\EmailTemplates\AdminTemplates;
|
|
use Database\Seeders\EmailTemplates\BillingTemplates;
|
|
use Database\Seeders\EmailTemplates\LegacyTemplates;
|
|
use Database\Seeders\EmailTemplates\MarketingTemplates;
|
|
use Database\Seeders\EmailTemplates\ServiceTemplates;
|
|
use Database\Seeders\EmailTemplates\TemplateVariables;
|
|
use Illuminate\Database\Seeder;
|
|
|
|
class TemplateSeeder extends Seeder
|
|
{
|
|
public function run(): void
|
|
{
|
|
foreach ([...self::templates(), ...self::legacyTemplates()] as $item) {
|
|
$this->upsert($item);
|
|
}
|
|
|
|
foreach (MarketingTemplates::all() as $item) {
|
|
$this->createMarketingIfMissing($item);
|
|
}
|
|
}
|
|
|
|
private function createMarketingIfMissing(array $item): void
|
|
{
|
|
$template = Template::firstOrNew(['name' => $item['name']]);
|
|
if ($template->exists) {
|
|
return;
|
|
}
|
|
|
|
$template->fill([
|
|
'type_id' => 0,
|
|
'format' => 'html',
|
|
'subject' => $item['subject'],
|
|
'message' => EmailTemplateShell::page($item['body']),
|
|
'status' => 1,
|
|
]);
|
|
$template->syncVariables($item['variables']);
|
|
$template->save();
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array{scenario: string, name: string, subject: string, message: string, types?: array<string, string>}>
|
|
*/
|
|
public static function templates(): array
|
|
{
|
|
$layout = [
|
|
'scenario' => 'layout',
|
|
'name' => 'Bố cục Header/Footer (mặc định)',
|
|
'subject' => '',
|
|
'message' => EmailTemplateShell::page('{{$content}}'),
|
|
];
|
|
|
|
$scenarios = array_map(
|
|
fn (array $item) => [...$item, 'message' => EmailTemplateShell::page($item['body'])],
|
|
[
|
|
...AccountTemplates::all(),
|
|
...ServiceTemplates::all(),
|
|
...BillingTemplates::all(),
|
|
...AdminTemplates::all(),
|
|
],
|
|
);
|
|
|
|
return [$layout, ...$scenarios];
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array{scenario: string, name: string, subject: string, message: string}>
|
|
*/
|
|
public static function legacyTemplates(): array
|
|
{
|
|
return array_map(
|
|
fn (array $item) => [...$item, 'message' => EmailTemplateShell::page($item['body'])],
|
|
LegacyTemplates::all(),
|
|
);
|
|
}
|
|
|
|
private function upsert(array $item): void
|
|
{
|
|
$scenario = $item['scenario'];
|
|
|
|
$template = Template::query()
|
|
->where(fn ($q) => $q->where('key', $scenario)->orWhere('scenario', $scenario))
|
|
->orderByRaw('`key` = ? desc', [$scenario])
|
|
->orderBy('id')
|
|
->first() ?? new Template(['type_id' => 0, 'status' => 1]);
|
|
|
|
$template->fill([
|
|
'key' => $scenario,
|
|
'scenario' => $scenario,
|
|
'name' => $item['name'],
|
|
'subject' => $item['subject'],
|
|
'message' => $item['message'],
|
|
'format' => 'html',
|
|
]);
|
|
|
|
$template->metadata = [
|
|
...($template->metadata ?? []),
|
|
'variables' => $this->variables($template, $item['types'] ?? []),
|
|
];
|
|
|
|
$template->save();
|
|
}
|
|
|
|
/**
|
|
* @param array<string, string> $typeOverrides
|
|
* @return array<int, array{key: string, label: string, type: string, example: string}>
|
|
*/
|
|
private function variables(Template $template, array $typeOverrides): array
|
|
{
|
|
$existing = $template->variables();
|
|
|
|
return collect(MailPlaceholders::extract($template->subject, $template->message))
|
|
->map(function (string $key) use ($existing, $typeOverrides) {
|
|
[$label, $type, $example] = TemplateVariables::DEFINITIONS[$key] ?? [$key, 'string', ''];
|
|
|
|
return [
|
|
'key' => $key,
|
|
'label' => $existing[$key]['label'] ?? $label,
|
|
'type' => $typeOverrides[$key] ?? $type,
|
|
'example' => $existing[$key]['example'] ?? $example,
|
|
];
|
|
})
|
|
->values()
|
|
->all();
|
|
}
|
|
}
|