feat(tenant): provision Mutual SMEP tenant with branding and menu setup
This commit is contained in:
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
private const CLIENT_CODE = 'mutual_smep';
|
||||
|
||||
private const TENANT_CODE = 'mutual_smep';
|
||||
|
||||
private const EXCLUDED_MENU_CODES = [
|
||||
'account.tickets',
|
||||
'adminapp.tickets',
|
||||
'adminapp.fiesta-futbol-infantil.entradas',
|
||||
'adminapp.fiesta-futbol-infantil.alojamientos',
|
||||
'adminapp.fiesta-futbol-infantil.merchandising',
|
||||
'adminapp.fiesta-futbol-infantil.comida',
|
||||
'adminapp.desfile.entradas',
|
||||
'event.index',
|
||||
'event.category',
|
||||
'event.detail',
|
||||
];
|
||||
|
||||
/** @var list<string> */
|
||||
private array $storedPaths = [];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
if (DB::table('tenants')->where('codigo', self::TENANT_CODE)->exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
! DB::table('admin_website_types')->where('codigo', 'shopit')->exists()
|
||||
|| ! DB::table('storefront_website_types')->where('codigo', 'shopit')->exists()
|
||||
) {
|
||||
// Fresh installations provision website-type reference data separately.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
DB::transaction(function (): void {
|
||||
$clientId = $this->clientId();
|
||||
$headerLogoId = $this->storeImage(
|
||||
'images/tennants/mutual_smep/mutual_smep_header.png',
|
||||
'mutual_smep_header.png',
|
||||
);
|
||||
$footerLogoId = $this->storeImage(
|
||||
'images/tennants/mutual_smep/mutual_smep_footer.png',
|
||||
'mutual_smep_footer.png',
|
||||
);
|
||||
$faviconId = $this->storeImage(
|
||||
'images/tennants/mutual_smep/mutual_smep_favicon.png',
|
||||
'mutual_smep_favicon.png',
|
||||
);
|
||||
$now = now();
|
||||
|
||||
DB::table('tenants')->insert([
|
||||
'client_id' => $clientId,
|
||||
'codigo' => self::TENANT_CODE,
|
||||
'nombre' => 'Mutual SMEP',
|
||||
'timezone' => 'America/Argentina/Buenos_Aires',
|
||||
'dominio' => 'mutual-smep.localhost',
|
||||
'base_path' => '/',
|
||||
'site_title' => 'Tienda Mutual SMEP',
|
||||
'address' => 'San Lorenzo 1543, Rosario, Santa Fe',
|
||||
'phone' => '+54 9 341 247-4530',
|
||||
'primary_color' => '#4A7FF5',
|
||||
'secondary_color' => '#0051A4',
|
||||
'danger_color' => '#FF8888',
|
||||
'success_color' => '#198754',
|
||||
'header_bg_color' => '#FFFFFF',
|
||||
'footer_bg_color' => '#0051A4',
|
||||
'header_logo_id' => $headerLogoId,
|
||||
'footer_logo_id' => $footerLogoId,
|
||||
'favicon_id' => $faviconId,
|
||||
'admin_website_type_code' => 'shopit',
|
||||
'storefront_website_type_code' => 'shopit',
|
||||
'display_categories' => true,
|
||||
'display_seach_bar' => true,
|
||||
'display_cart' => true,
|
||||
'cart_editing_policy' => 'quantity_and_remove',
|
||||
'checkout_editing_policy' => 'disabled',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
$this->assignSocialMedia($now);
|
||||
$this->assignMenus($now);
|
||||
});
|
||||
} catch (Throwable $throwable) {
|
||||
Storage::disk('s3')->delete($this->storedPaths);
|
||||
|
||||
throw $throwable;
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$tenant = DB::table('tenants')
|
||||
->where('codigo', self::TENANT_CODE)
|
||||
->first(['id', 'client_id', 'header_logo_id', 'footer_logo_id', 'favicon_id']);
|
||||
|
||||
if ($tenant === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attachmentIds = collect([
|
||||
$tenant->header_logo_id,
|
||||
$tenant->footer_logo_id,
|
||||
$tenant->favicon_id,
|
||||
])->filter()->unique()->values();
|
||||
$storedPaths = DB::table('attachments')
|
||||
->whereIn('id', $attachmentIds)
|
||||
->pluck('path')
|
||||
->all();
|
||||
|
||||
DB::transaction(function () use ($tenant, $attachmentIds): void {
|
||||
DB::table('tenant_social_media')
|
||||
->where('tenant_code', self::TENANT_CODE)
|
||||
->delete();
|
||||
DB::table('tenants_menues')
|
||||
->where('tenant_code', self::TENANT_CODE)
|
||||
->delete();
|
||||
DB::table('tenants')
|
||||
->where('id', $tenant->id)
|
||||
->delete();
|
||||
DB::table('attachments')
|
||||
->whereIn('id', $attachmentIds)
|
||||
->delete();
|
||||
|
||||
$clientHasTenants = DB::table('tenants')
|
||||
->where('client_id', $tenant->client_id)
|
||||
->exists();
|
||||
|
||||
if (! $clientHasTenants) {
|
||||
DB::table('clients')
|
||||
->where('id', $tenant->client_id)
|
||||
->where('code', self::CLIENT_CODE)
|
||||
->delete();
|
||||
}
|
||||
});
|
||||
|
||||
Storage::disk('s3')->delete($storedPaths);
|
||||
}
|
||||
|
||||
private function clientId(): int
|
||||
{
|
||||
$clientId = DB::table('clients')->where('code', self::CLIENT_CODE)->value('id');
|
||||
|
||||
if ($clientId !== null) {
|
||||
DB::table('clients')->where('id', $clientId)->update([
|
||||
'name' => 'Mutual SMEP',
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
return (int) $clientId;
|
||||
}
|
||||
|
||||
return (int) DB::table('clients')->insertGetId([
|
||||
'code' => self::CLIENT_CODE,
|
||||
'name' => 'Mutual SMEP',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function assignSocialMedia(DateTimeInterface $now): void
|
||||
{
|
||||
$socialMedia = [
|
||||
[
|
||||
'code' => 'instagram',
|
||||
'icon' => 'fa-brands fa-instagram',
|
||||
'name' => 'Instagram',
|
||||
'url' => 'https://www.instagram.com/mutualsmep/',
|
||||
'orden' => 0,
|
||||
],
|
||||
[
|
||||
'code' => 'facebook',
|
||||
'icon' => 'fa-brands fa-facebook',
|
||||
'name' => 'Facebook',
|
||||
'url' => 'https://www.facebook.com/smeprosario',
|
||||
'orden' => 1,
|
||||
],
|
||||
[
|
||||
'code' => 'whatsapp',
|
||||
'icon' => 'fa-brands fa-whatsapp',
|
||||
'name' => 'WhatsApp',
|
||||
'url' => 'https://wa.me/5493412474530',
|
||||
'orden' => 2,
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($socialMedia as $network) {
|
||||
DB::table('social_media')->insertOrIgnore([
|
||||
'code' => $network['code'],
|
||||
'icon' => $network['icon'],
|
||||
'name' => $network['name'],
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
DB::table('tenant_social_media')->insertOrIgnore([
|
||||
'tenant_code' => self::TENANT_CODE,
|
||||
'social_media_code' => $network['code'],
|
||||
'url' => $network['url'],
|
||||
'orden' => $network['orden'],
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function assignMenus(DateTimeInterface $now): void
|
||||
{
|
||||
DB::table('menues')
|
||||
->whereNotIn('code', self::EXCLUDED_MENU_CODES)
|
||||
->pluck('code')
|
||||
->each(function (string $menuCode) use ($now): void {
|
||||
$staticContent = match ($menuCode) {
|
||||
'help.faq' => $this->frequentlyAskedQuestions(),
|
||||
'help.contact' => $this->contactContent(),
|
||||
default => null,
|
||||
};
|
||||
|
||||
DB::table('tenants_menues')->updateOrInsert(
|
||||
[
|
||||
'tenant_code' => self::TENANT_CODE,
|
||||
'menu_code' => $menuCode,
|
||||
],
|
||||
[
|
||||
'static_content' => $staticContent === null
|
||||
? null
|
||||
: json_encode($staticContent, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/** @return list<array{pregunta: string, respuesta: string, is_active: bool}> */
|
||||
private function frequentlyAskedQuestions(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'pregunta' => '¿Hay algún límite de compra?',
|
||||
'respuesta' => 'La cantidad disponible depende del stock de cada producto.',
|
||||
'is_active' => true,
|
||||
],
|
||||
[
|
||||
'pregunta' => '¿Cuáles son los medios de pago disponibles?',
|
||||
'respuesta' => 'Podés consultar y seleccionar los medios de pago habilitados al finalizar tu compra.',
|
||||
'is_active' => false,
|
||||
],
|
||||
[
|
||||
'pregunta' => '¿Cómo puedo recibir asesoramiento antes de comprar?',
|
||||
'respuesta' => 'Podés comunicarte con Mutual SMEP por WhatsApp al +54 9 341 247-4530.',
|
||||
'is_active' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private function contactContent(): array
|
||||
{
|
||||
return [
|
||||
'whatsapp' => [
|
||||
'whatsapp_url' => 'https://wa.me/5493412474530',
|
||||
'whatsapp_label' => 'Chateá con Mutual SMEP',
|
||||
],
|
||||
'phone' => '+54 9 341 247-4530',
|
||||
'locations' => [
|
||||
'rosario' => [
|
||||
'label' => 'Rosario',
|
||||
'addresses' => [
|
||||
[
|
||||
'label' => 'Mutual SMEP',
|
||||
'address' => 'San Lorenzo 1543, Rosario, Santa Fe',
|
||||
'coordinates' => [-32.9431184, -60.6437991],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function storeImage(string $relativePath, string $filename): int
|
||||
{
|
||||
$sourcePath = public_path($relativePath);
|
||||
|
||||
if (! is_file($sourcePath)) {
|
||||
throw new RuntimeException("Image not found at path: {$sourcePath}");
|
||||
}
|
||||
|
||||
$contents = file_get_contents($sourcePath);
|
||||
|
||||
if ($contents === false) {
|
||||
throw new RuntimeException("Could not read image at path: {$sourcePath}");
|
||||
}
|
||||
|
||||
$key = (string) Str::uuid();
|
||||
$storedPath = 'tenants/'.self::TENANT_CODE."/{$key}.png";
|
||||
|
||||
if (! Storage::disk('s3')->put($storedPath, $contents)) {
|
||||
throw new RuntimeException("Could not store image at path: {$storedPath}");
|
||||
}
|
||||
|
||||
$this->storedPaths[] = $storedPath;
|
||||
|
||||
return DB::table('attachments')->insertGetId([
|
||||
'key' => $key,
|
||||
'path' => $storedPath,
|
||||
'filename' => $filename,
|
||||
'type' => 'image',
|
||||
'mime_type' => 'image/png',
|
||||
'extension' => 'png',
|
||||
'size' => strlen($contents),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user