Files
portal-api/database/seeders/TemplateSeeder.php
T
baodev0andClaude Opus 5.5 30898ea46f feat: email gửi tay/nhắc gia hạn, gói hosting, sửa dữ liệu sản phẩm
- 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>
2026-10-09 11:32:05 +07:00

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();
}
}