feat(tenant): separate admin and storefront website types
This commit is contained in:
@@ -2,21 +2,21 @@
|
|||||||
|
|
||||||
namespace App\Domains\Bootstrap\Resources;
|
namespace App\Domains\Bootstrap\Resources;
|
||||||
|
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
/** @mixin array{website_type: WebsiteType} */
|
/** @mixin array{website_type: AdminWebsiteType} */
|
||||||
class AdminAppBootstrapResource extends JsonResource
|
class AdminAppBootstrapResource extends JsonResource
|
||||||
{
|
{
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
/** @var WebsiteType $websiteType */
|
/** @var AdminWebsiteType $websiteType */
|
||||||
$websiteType = $this->resource['website_type'];
|
$websiteType = $this->resource['website_type'];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'website_type_code' => $websiteType->codigo,
|
'admin_website_type_code' => $websiteType->codigo,
|
||||||
'site_title' => $websiteType->site_title,
|
'site_title' => $websiteType->site_title,
|
||||||
'primary_color' => $websiteType->primary_color,
|
'primary_color' => $websiteType->primary_color,
|
||||||
'secondary_color' => $websiteType->secondary_color,
|
'secondary_color' => $websiteType->secondary_color,
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Domains\Bootstrap\Services;
|
namespace App\Domains\Bootstrap\Services;
|
||||||
|
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
|
|
||||||
class AdminAppBootstrapService
|
class AdminAppBootstrapService
|
||||||
{
|
{
|
||||||
/** @return array{website_type: WebsiteType} */
|
/** @return array{website_type: AdminWebsiteType} */
|
||||||
public function get(string $domain): array
|
public function get(string $domain): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'website_type' => WebsiteType::query()
|
'website_type' => AdminWebsiteType::query()
|
||||||
->with(['siteLogo', 'footerLogo', 'favicon'])
|
->with(['siteLogo', 'footerLogo', 'favicon'])
|
||||||
->where('dominio', $domain)
|
->where('dominio', $domain)
|
||||||
->firstOrFail(),
|
->firstOrFail(),
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
namespace App\Domains\Bootstrap\Services;
|
namespace App\Domains\Bootstrap\Services;
|
||||||
|
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
|
|
||||||
class ScannerBootstrapService
|
class ScannerBootstrapService
|
||||||
{
|
{
|
||||||
/** @return array{website_type: WebsiteType} */
|
/** @return array{website_type: AdminWebsiteType} */
|
||||||
public function get(string $domain): array
|
public function get(string $domain): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'website_type' => WebsiteType::query()
|
'website_type' => AdminWebsiteType::query()
|
||||||
->with(['siteLogo', 'footerLogo', 'favicon'])
|
->with(['siteLogo', 'footerLogo', 'favicon'])
|
||||||
->where('scanner_domain', $domain)
|
->where('scanner_domain', $domain)
|
||||||
->firstOrFail(),
|
->firstOrFail(),
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class OnTicketFeaturedGroupController extends Controller
|
|||||||
{
|
{
|
||||||
$tenant = $request->user()->tenant()->firstOrFail();
|
$tenant = $request->user()->tenant()->firstOrFail();
|
||||||
|
|
||||||
abort_unless($tenant->website_type_code === 'onticket', 404);
|
abort_unless($tenant->storefront_website_type_code === 'onticket', 404);
|
||||||
|
|
||||||
return $tenant;
|
return $tenant;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,37 +6,37 @@ use App\Domains\Integration\Models\Integration;
|
|||||||
use App\Domains\Integration\Requests\ConfigureIntegrationRequest;
|
use App\Domains\Integration\Requests\ConfigureIntegrationRequest;
|
||||||
use App\Domains\Integration\Resources\IntegrationAssociationResource;
|
use App\Domains\Integration\Resources\IntegrationAssociationResource;
|
||||||
use App\Domains\Integration\Services\IntegrationAssociationService;
|
use App\Domains\Integration\Services\IntegrationAssociationService;
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
|
||||||
class WebsiteTypeIntegrationController extends Controller
|
class AdminWebsiteTypeIntegrationController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct(private readonly IntegrationAssociationService $service) {}
|
public function __construct(private readonly IntegrationAssociationService $service) {}
|
||||||
|
|
||||||
public function index(WebsiteType $websiteType)
|
public function index(AdminWebsiteType $adminWebsiteType)
|
||||||
{
|
{
|
||||||
return IntegrationAssociationResource::collection($websiteType->integrations()->with('integrationInstance')->get());
|
return IntegrationAssociationResource::collection($adminWebsiteType->integrations()->with('integrationInstance')->get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show(WebsiteType $websiteType, string $integrationCode)
|
public function show(AdminWebsiteType $adminWebsiteType, string $integrationCode)
|
||||||
{
|
{
|
||||||
return new IntegrationAssociationResource($websiteType->integrations()->with('integrationInstance')->where('integration_code', $integrationCode)->firstOrFail());
|
return new IntegrationAssociationResource($adminWebsiteType->integrations()->with('integrationInstance')->where('integration_code', $integrationCode)->firstOrFail());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(ConfigureIntegrationRequest $request, WebsiteType $websiteType, string $integrationCode)
|
public function store(ConfigureIntegrationRequest $request, AdminWebsiteType $adminWebsiteType, string $integrationCode)
|
||||||
{
|
{
|
||||||
$integration = Integration::query()->where('integration_code', $integrationCode)->firstOrFail();
|
$integration = Integration::query()->where('integration_code', $integrationCode)->firstOrFail();
|
||||||
|
|
||||||
return new IntegrationAssociationResource($this->service->configure(
|
return new IntegrationAssociationResource($this->service->configure(
|
||||||
$websiteType,
|
$adminWebsiteType,
|
||||||
$integration,
|
$integration,
|
||||||
$request->validated('integration_data'),
|
$request->validated('integration_data'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function destroy(WebsiteType $websiteType, string $integrationCode)
|
public function destroy(AdminWebsiteType $adminWebsiteType, string $integrationCode)
|
||||||
{
|
{
|
||||||
$this->service->detach($websiteType, $integrationCode);
|
$this->service->detach($adminWebsiteType, $integrationCode);
|
||||||
|
|
||||||
return response()->noContent();
|
return response()->noContent();
|
||||||
}
|
}
|
||||||
@@ -2,18 +2,19 @@
|
|||||||
|
|
||||||
namespace App\Domains\Integration\Models;
|
namespace App\Domains\Integration\Models;
|
||||||
|
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
|
||||||
class WebsiteTypeIntegration extends Model
|
class AdminWebsiteTypeIntegration extends Model
|
||||||
{
|
{
|
||||||
protected $fillable = ['website_type_code', 'integration_code', 'integration_instance_id'];
|
protected $table = 'admin_website_type_integrations';
|
||||||
|
protected $fillable = ['admin_website_type_code', 'integration_code', 'integration_instance_id'];
|
||||||
|
|
||||||
/** @return BelongsTo<WebsiteType, $this> */
|
/** @return BelongsTo<AdminWebsiteType, $this> */
|
||||||
public function websiteType(): BelongsTo
|
public function adminWebsiteType(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(WebsiteType::class, 'website_type_code', 'codigo');
|
return $this->belongsTo(AdminWebsiteType::class, 'admin_website_type_code', 'codigo');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return BelongsTo<Integration, $this> */
|
/** @return BelongsTo<Integration, $this> */
|
||||||
@@ -34,9 +34,9 @@ class Integration extends Model
|
|||||||
return $this->hasMany(ClientIntegration::class, 'integration_code', 'integration_code');
|
return $this->hasMany(ClientIntegration::class, 'integration_code', 'integration_code');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return HasMany<WebsiteTypeIntegration, $this> */
|
/** @return HasMany<AdminWebsiteTypeIntegration, $this> */
|
||||||
public function websiteTypeIntegrations(): HasMany
|
public function websiteTypeIntegrations(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(WebsiteTypeIntegration::class, 'integration_code', 'integration_code');
|
return $this->hasMany(AdminWebsiteTypeIntegration::class, 'integration_code', 'integration_code');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ class IntegrationInstance extends Model
|
|||||||
return $this->hasMany(ClientIntegration::class);
|
return $this->hasMany(ClientIntegration::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return HasMany<WebsiteTypeIntegration, $this> */
|
/** @return HasMany<AdminWebsiteTypeIntegration, $this> */
|
||||||
public function websiteTypeIntegrations(): HasMany
|
public function websiteTypeIntegrations(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(WebsiteTypeIntegration::class);
|
return $this->hasMany(AdminWebsiteTypeIntegration::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class IntegrationAssociationResource extends JsonResource
|
|||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
'client_id' => $this->when(isset($this->client_id), $this->client_id),
|
'client_id' => $this->when(isset($this->client_id), $this->client_id),
|
||||||
'website_type_code' => $this->when(isset($this->website_type_code), $this->website_type_code),
|
'admin_website_type_code' => $this->when(isset($this->admin_website_type_code), $this->admin_website_type_code),
|
||||||
'integration_code' => $this->integration_code,
|
'integration_code' => $this->integration_code,
|
||||||
'integration_instance_id' => $this->integration_instance_id,
|
'integration_instance_id' => $this->integration_instance_id,
|
||||||
'integration_instance' => new IntegrationInstanceResource($this->whenLoaded('integrationInstance')),
|
'integration_instance' => new IntegrationInstanceResource($this->whenLoaded('integrationInstance')),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use App\Domains\Client\Models\Client;
|
|||||||
use App\Domains\Integration\Models\ClientIntegration;
|
use App\Domains\Integration\Models\ClientIntegration;
|
||||||
use App\Domains\Integration\Models\Integration;
|
use App\Domains\Integration\Models\Integration;
|
||||||
use App\Domains\Integration\Models\IntegrationInstance;
|
use App\Domains\Integration\Models\IntegrationInstance;
|
||||||
use App\Domains\Integration\Models\WebsiteTypeIntegration;
|
use App\Domains\Integration\Models\AdminWebsiteTypeIntegration;
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Http\Client\PendingRequest;
|
use Illuminate\Http\Client\PendingRequest;
|
||||||
@@ -111,9 +111,9 @@ abstract class BaseIntegrationService
|
|||||||
->where('integration_code', $this->integrationCode)
|
->where('integration_code', $this->integrationCode)
|
||||||
->first()?->integrationInstance;
|
->first()?->integrationInstance;
|
||||||
|
|
||||||
if (! $this->integrationInstance && $this->tenant?->website_type_code) {
|
if (! $this->integrationInstance && $this->tenant?->admin_website_type_code) {
|
||||||
$this->integrationInstance = WebsiteTypeIntegration::with('integrationInstance')
|
$this->integrationInstance = AdminWebsiteTypeIntegration::with('integrationInstance')
|
||||||
->where('website_type_code', $this->tenant->website_type_code)
|
->where('admin_website_type_code', $this->tenant->admin_website_type_code)
|
||||||
->where('integration_code', $this->integrationCode)
|
->where('integration_code', $this->integrationCode)
|
||||||
->first()?->integrationInstance;
|
->first()?->integrationInstance;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ use App\Domains\Client\Models\Client;
|
|||||||
use App\Domains\Integration\Models\ClientIntegration;
|
use App\Domains\Integration\Models\ClientIntegration;
|
||||||
use App\Domains\Integration\Models\Integration;
|
use App\Domains\Integration\Models\Integration;
|
||||||
use App\Domains\Integration\Models\IntegrationInstance;
|
use App\Domains\Integration\Models\IntegrationInstance;
|
||||||
use App\Domains\Integration\Models\WebsiteTypeIntegration;
|
use App\Domains\Integration\Models\AdminWebsiteTypeIntegration;
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class IntegrationAssociationService
|
class IntegrationAssociationService
|
||||||
{
|
{
|
||||||
public function configure(Client|WebsiteType $owner, Integration $integration, array $integrationData): ClientIntegration|WebsiteTypeIntegration
|
public function configure(Client|AdminWebsiteType $owner, Integration $integration, array $integrationData): ClientIntegration|AdminWebsiteTypeIntegration
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($owner, $integration, $integrationData): ClientIntegration|WebsiteTypeIntegration {
|
return DB::transaction(function () use ($owner, $integration, $integrationData): ClientIntegration|AdminWebsiteTypeIntegration {
|
||||||
$instance = IntegrationInstance::create([
|
$instance = IntegrationInstance::create([
|
||||||
'integration_code' => $integration->integration_code,
|
'integration_code' => $integration->integration_code,
|
||||||
'name' => $integration->name.' / '.$this->ownerName($owner),
|
'name' => $integration->name.' / '.$this->ownerName($owner),
|
||||||
@@ -25,9 +25,9 @@ class IntegrationAssociationService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function associate(Client|WebsiteType $owner, string $code, IntegrationInstance $instance): ClientIntegration|WebsiteTypeIntegration
|
public function associate(Client|AdminWebsiteType $owner, string $code, IntegrationInstance $instance): ClientIntegration|AdminWebsiteTypeIntegration
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($owner, $code, $instance): ClientIntegration|WebsiteTypeIntegration {
|
return DB::transaction(function () use ($owner, $code, $instance): ClientIntegration|AdminWebsiteTypeIntegration {
|
||||||
$association = $owner->integrations()
|
$association = $owner->integrations()
|
||||||
->where('integration_code', $code)
|
->where('integration_code', $code)
|
||||||
->lockForUpdate()
|
->lockForUpdate()
|
||||||
@@ -62,7 +62,7 @@ class IntegrationAssociationService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function detach(Client|WebsiteType $owner, string $code): void
|
public function detach(Client|AdminWebsiteType $owner, string $code): void
|
||||||
{
|
{
|
||||||
DB::transaction(function () use ($owner, $code): void {
|
DB::transaction(function () use ($owner, $code): void {
|
||||||
$association = $owner->integrations()
|
$association = $owner->integrations()
|
||||||
@@ -91,7 +91,7 @@ class IntegrationAssociationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ownerName(Client|WebsiteType $owner): string
|
private function ownerName(Client|AdminWebsiteType $owner): string
|
||||||
{
|
{
|
||||||
return $owner instanceof Client ? $owner->name : $owner->nombre;
|
return $owner instanceof Client ? $owner->name : $owner->nombre;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Domains\Integration\Services;
|
|||||||
|
|
||||||
use App\Domains\Client\Models\Client;
|
use App\Domains\Client\Models\Client;
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Mail\Factory as MailFactory;
|
use Illuminate\Contracts\Mail\Factory as MailFactory;
|
||||||
use Illuminate\Contracts\Mail\Mailer;
|
use Illuminate\Contracts\Mail\Mailer;
|
||||||
@@ -79,7 +79,7 @@ class MailService extends BaseIntegrationService
|
|||||||
string|array $recipient,
|
string|array $recipient,
|
||||||
string $subject,
|
string $subject,
|
||||||
string $content,
|
string $content,
|
||||||
Tenant|WebsiteType|null $brand = null,
|
Tenant|AdminWebsiteType|null $brand = null,
|
||||||
array $attachments = [],
|
array $attachments = [],
|
||||||
): void {
|
): void {
|
||||||
if (! $this->mailer || ! $this->tenant) {
|
if (! $this->mailer || ! $this->tenant) {
|
||||||
@@ -97,7 +97,7 @@ class MailService extends BaseIntegrationService
|
|||||||
BLADE,
|
BLADE,
|
||||||
[
|
[
|
||||||
'branding' => $branding,
|
'branding' => $branding,
|
||||||
'headerLogoUrl' => $brand instanceof WebsiteType
|
'headerLogoUrl' => $brand instanceof AdminWebsiteType
|
||||||
? $brand->siteLogo?->getTemporaryUrl(1440)
|
? $brand->siteLogo?->getTemporaryUrl(1440)
|
||||||
: $brand->headerLogo?->getTemporaryUrl(1440),
|
: $brand->headerLogo?->getTemporaryUrl(1440),
|
||||||
'footerLogoUrl' => $brand->footerLogo?->getTemporaryUrl(1440),
|
'footerLogoUrl' => $brand->footerLogo?->getTemporaryUrl(1440),
|
||||||
@@ -128,9 +128,9 @@ class MailService extends BaseIntegrationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @return array{name: string, primary_color: string, body_color: string, background_color: string, surface_color: string, header_bg_color: string, footer_bg_color: string} */
|
/** @return array{name: string, primary_color: string, body_color: string, background_color: string, surface_color: string, header_bg_color: string, footer_bg_color: string} */
|
||||||
private function brandingFor(Tenant|WebsiteType $brand): array
|
private function brandingFor(Tenant|AdminWebsiteType $brand): array
|
||||||
{
|
{
|
||||||
if ($brand instanceof WebsiteType) {
|
if ($brand instanceof AdminWebsiteType) {
|
||||||
$brand->loadMissing(['siteLogo', 'footerLogo']);
|
$brand->loadMissing(['siteLogo', 'footerLogo']);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
use App\Domains\Integration\Controllers\ClientIntegrationController;
|
use App\Domains\Integration\Controllers\ClientIntegrationController;
|
||||||
use App\Domains\Integration\Controllers\TelepagosWebhookController;
|
use App\Domains\Integration\Controllers\TelepagosWebhookController;
|
||||||
use App\Domains\Integration\Controllers\WebsiteTypeIntegrationController;
|
use App\Domains\Integration\Controllers\AdminWebsiteTypeIntegrationController;
|
||||||
use App\Domains\Integration\Models\Integration;
|
use App\Domains\Integration\Models\Integration;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
Route::middleware(['auth:sanctum', 'can:manage,'.Integration::class])->group(function (): void {
|
Route::middleware(['auth:sanctum', 'can:manage,'.Integration::class])->group(function (): void {
|
||||||
Route::prefix('website-types/{websiteType:codigo}/integrations')->group(function (): void {
|
Route::prefix('admin-website-types/{adminWebsiteType:codigo}/integrations')->group(function (): void {
|
||||||
Route::get('/', [WebsiteTypeIntegrationController::class, 'index']);
|
Route::get('/', [AdminWebsiteTypeIntegrationController::class, 'index']);
|
||||||
Route::get('/{integration_code}', [WebsiteTypeIntegrationController::class, 'show']);
|
Route::get('/{integration_code}', [AdminWebsiteTypeIntegrationController::class, 'show']);
|
||||||
Route::put('/{integration_code}', [WebsiteTypeIntegrationController::class, 'store']);
|
Route::put('/{integration_code}', [AdminWebsiteTypeIntegrationController::class, 'store']);
|
||||||
Route::delete('/{integration_code}', [WebsiteTypeIntegrationController::class, 'destroy']);
|
Route::delete('/{integration_code}', [AdminWebsiteTypeIntegrationController::class, 'destroy']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['prefix' => 'clients/{client}/integrations'], function () {
|
Route::group(['prefix' => 'clients/{client}/integrations'], function () {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class NotificationMailService
|
|||||||
'user_id' => $userId,
|
'user_id' => $userId,
|
||||||
'tenant_code' => $tenantCode,
|
'tenant_code' => $tenantCode,
|
||||||
];
|
];
|
||||||
$tenant = Tenant::query()->with('websiteType')->where('codigo', $tenantCode)->firstOrFail();
|
$tenant = Tenant::query()->where('codigo', $tenantCode)->firstOrFail();
|
||||||
$user = User::query()->findOrFail($userId);
|
$user = User::query()->findOrFail($userId);
|
||||||
|
|
||||||
$this->sendIdempotently(
|
$this->sendIdempotently(
|
||||||
@@ -41,7 +41,7 @@ class NotificationMailService
|
|||||||
$context,
|
$context,
|
||||||
$user->email,
|
$user->email,
|
||||||
function () use ($user, $tenant, $tenantCode): array {
|
function () use ($user, $tenant, $tenantCode): array {
|
||||||
$brand = $tenant->websiteType ?? $tenant;
|
$brand = $tenant;
|
||||||
$tenantUrl = 'https://'.$tenant->dominio.$tenant->base_path;
|
$tenantUrl = 'https://'.$tenant->dominio.$tenant->base_path;
|
||||||
|
|
||||||
$this->mailService
|
$this->mailService
|
||||||
@@ -54,7 +54,7 @@ class NotificationMailService
|
|||||||
);
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'brand_type' => $tenant->websiteType === null ? 'tenant' : 'website_type',
|
'brand_type' => 'tenant',
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -72,7 +72,7 @@ class NotificationMailService
|
|||||||
];
|
];
|
||||||
|
|
||||||
$tenant = Tenant::query()
|
$tenant = Tenant::query()
|
||||||
->with('websiteType')
|
->with('adminWebsiteType')
|
||||||
->where('codigo', $tenantCode)
|
->where('codigo', $tenantCode)
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
$attempt = ResetPasswordAttempt::query()
|
$attempt = ResetPasswordAttempt::query()
|
||||||
@@ -97,8 +97,8 @@ class NotificationMailService
|
|||||||
$attempt->user->email,
|
$attempt->user->email,
|
||||||
function () use ($attempt, $tenant, $tenantCode, $channel): array {
|
function () use ($attempt, $tenant, $tenantCode, $channel): array {
|
||||||
$recoveryDomain = match ($channel) {
|
$recoveryDomain = match ($channel) {
|
||||||
PasswordResetRequested::CHANNEL_ADMINAPP => $tenant->websiteType?->dominio,
|
PasswordResetRequested::CHANNEL_ADMINAPP => $tenant->adminWebsiteType?->dominio,
|
||||||
PasswordResetRequested::CHANNEL_SCANNER => $tenant->websiteType?->scanner_domain,
|
PasswordResetRequested::CHANNEL_SCANNER => $tenant->adminWebsiteType?->scanner_domain,
|
||||||
default => $tenant->dominio,
|
default => $tenant->dominio,
|
||||||
};
|
};
|
||||||
$recoveryBasePath = $channel === PasswordResetRequested::CHANNEL_STOREFRONT
|
$recoveryBasePath = $channel === PasswordResetRequested::CHANNEL_STOREFRONT
|
||||||
@@ -115,7 +115,9 @@ class NotificationMailService
|
|||||||
$recoveryUrl = $recoveryDomain === null
|
$recoveryUrl = $recoveryDomain === null
|
||||||
? null
|
? null
|
||||||
: 'https://'.$recoveryDomain.$recoveryBasePath.'/recuperar-contrasena/codigo?'.http_build_query($recoveryQuery);
|
: 'https://'.$recoveryDomain.$recoveryBasePath.'/recuperar-contrasena/codigo?'.http_build_query($recoveryQuery);
|
||||||
$brand = $tenant->websiteType ?? $tenant;
|
$brand = $channel === PasswordResetRequested::CHANNEL_STOREFRONT
|
||||||
|
? $tenant
|
||||||
|
: ($tenant->adminWebsiteType ?? $tenant);
|
||||||
|
|
||||||
[$subject, $template] = match ($attempt->reason) {
|
[$subject, $template] = match ($attempt->reason) {
|
||||||
ResetPasswordAttempt::REASON_STAFF_CREATED => [
|
ResetPasswordAttempt::REASON_STAFF_CREATED => [
|
||||||
@@ -291,7 +293,7 @@ class NotificationMailService
|
|||||||
$newDate,
|
$newDate,
|
||||||
$tickets,
|
$tickets,
|
||||||
): array {
|
): array {
|
||||||
$brand = $purchase->tenant->websiteType ?? $purchase->tenant;
|
$brand = $purchase->tenant;
|
||||||
|
|
||||||
$this->mailService
|
$this->mailService
|
||||||
->forTenant($tenantCode)
|
->forTenant($tenantCode)
|
||||||
@@ -392,7 +394,7 @@ class NotificationMailService
|
|||||||
$disabledTickets,
|
$disabledTickets,
|
||||||
$activeTickets,
|
$activeTickets,
|
||||||
): array {
|
): array {
|
||||||
$brand = $purchase->tenant->websiteType ?? $purchase->tenant;
|
$brand = $purchase->tenant;
|
||||||
|
|
||||||
$this->mailService
|
$this->mailService
|
||||||
->forTenant($tenantCode)
|
->forTenant($tenantCode)
|
||||||
@@ -419,7 +421,7 @@ class NotificationMailService
|
|||||||
{
|
{
|
||||||
return Purchase::query()
|
return Purchase::query()
|
||||||
->where('tenant_codigo', $tenantCode)
|
->where('tenant_codigo', $tenantCode)
|
||||||
->with(['tenant.websiteType', 'user'])
|
->with(['tenant', 'user'])
|
||||||
->find($purchaseId);
|
->find($purchaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class WebsiteExtraController extends Controller
|
|||||||
$tenant = $user->tenant()->firstOrFail();
|
$tenant = $user->tenant()->firstOrFail();
|
||||||
|
|
||||||
return $this->tenantInformationService->load($tenant, [
|
return $this->tenantInformationService->load($tenant, [
|
||||||
'websiteType.extras',
|
'storefrontWebsiteType.extras',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace App\Domains\Tenant\Models;
|
namespace App\Domains\Tenant\Models;
|
||||||
|
|
||||||
use App\Domains\Attachable\Models\Attachment;
|
use App\Domains\Attachable\Models\Attachment;
|
||||||
use App\Domains\Integration\Models\WebsiteTypeIntegration;
|
use App\Domains\Integration\Models\AdminWebsiteTypeIntegration;
|
||||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
@@ -31,16 +31,16 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
|||||||
'footer_logo',
|
'footer_logo',
|
||||||
'favicon_id',
|
'favicon_id',
|
||||||
])]
|
])]
|
||||||
class WebsiteType extends Model
|
class AdminWebsiteType extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $table = 'website_type';
|
protected $table = 'admin_website_types';
|
||||||
|
|
||||||
/** @return HasMany<WebsiteTypeIntegration, $this> */
|
/** @return HasMany<AdminWebsiteTypeIntegration, $this> */
|
||||||
public function integrations(): HasMany
|
public function integrations(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(WebsiteTypeIntegration::class, 'website_type_code', 'codigo');
|
return $this->hasMany(AdminWebsiteTypeIntegration::class, 'admin_website_type_code', 'codigo');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,19 +67,11 @@ class WebsiteType extends Model
|
|||||||
return $this->belongsTo(Attachment::class, 'favicon_id');
|
return $this->belongsTo(Attachment::class, 'favicon_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return HasMany<WebsiteTypeExtra, $this>
|
|
||||||
*/
|
|
||||||
public function extras(): HasMany
|
|
||||||
{
|
|
||||||
return $this->hasMany(WebsiteTypeExtra::class, 'website_type_code', 'codigo');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return HasMany<Tenant, $this>
|
* @return HasMany<Tenant, $this>
|
||||||
*/
|
*/
|
||||||
public function tenants(): HasMany
|
public function tenants(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Tenant::class, 'website_type_code', 'codigo');
|
return $this->hasMany(Tenant::class, 'admin_website_type_code', 'codigo');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
28
app/Domains/Tenant/Models/StorefrontWebsiteType.php
Normal file
28
app/Domains/Tenant/Models/StorefrontWebsiteType.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Tenant\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
|
#[Fillable(['codigo', 'nombre'])]
|
||||||
|
class StorefrontWebsiteType extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $table = 'storefront_website_types';
|
||||||
|
|
||||||
|
/** @return HasMany<StorefrontWebsiteTypeExtra, $this> */
|
||||||
|
public function extras(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(StorefrontWebsiteTypeExtra::class, 'storefront_website_type_code', 'codigo');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return HasMany<Tenant, $this> */
|
||||||
|
public function tenants(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Tenant::class, 'storefront_website_type_code', 'codigo');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,18 +9,18 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
#[Fillable([
|
#[Fillable([
|
||||||
'website_type_code',
|
'storefront_website_type_code',
|
||||||
'codigo',
|
'codigo',
|
||||||
'nombre',
|
'nombre',
|
||||||
'descripcion',
|
'descripcion',
|
||||||
'is_required',
|
'is_required',
|
||||||
'config_schema',
|
'config_schema',
|
||||||
])]
|
])]
|
||||||
class WebsiteTypeExtra extends Model
|
class StorefrontWebsiteTypeExtra extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $table = 'website_type_extras';
|
protected $table = 'storefront_website_type_extras';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string, string>
|
* @return array<string, string>
|
||||||
@@ -34,11 +34,11 @@ class WebsiteTypeExtra extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<WebsiteType, $this>
|
* @return BelongsTo<StorefrontWebsiteType, $this>
|
||||||
*/
|
*/
|
||||||
public function websiteType(): BelongsTo
|
public function storefrontWebsiteType(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(WebsiteType::class, 'website_type_code', 'codigo');
|
return $this->belongsTo(StorefrontWebsiteType::class, 'storefront_website_type_code', 'codigo');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +42,8 @@ use Illuminate\Support\Facades\Schema;
|
|||||||
'favicon_id',
|
'favicon_id',
|
||||||
'header_bg_image_id',
|
'header_bg_image_id',
|
||||||
'footer_bg_image_id',
|
'footer_bg_image_id',
|
||||||
'website_type_code',
|
'admin_website_type_code',
|
||||||
|
'storefront_website_type_code',
|
||||||
'search_product_layout',
|
'search_product_layout',
|
||||||
'search_group_layout',
|
'search_group_layout',
|
||||||
'search_items_per_page',
|
'search_items_per_page',
|
||||||
@@ -210,11 +211,17 @@ class Tenant extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<WebsiteType, $this>
|
* @return BelongsTo<AdminWebsiteType, $this>
|
||||||
*/
|
*/
|
||||||
public function websiteType(): BelongsTo
|
public function adminWebsiteType(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(WebsiteType::class, 'website_type_code', 'codigo');
|
return $this->belongsTo(AdminWebsiteType::class, 'admin_website_type_code', 'codigo');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return BelongsTo<StorefrontWebsiteType, $this> */
|
||||||
|
public function storefrontWebsiteType(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(StorefrontWebsiteType::class, 'storefront_website_type_code', 'codigo');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function catalogItems(): HasMany
|
public function catalogItems(): HasMany
|
||||||
|
|||||||
@@ -48,11 +48,11 @@ class WebsiteExtra extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return BelongsTo<WebsiteTypeExtra, $this>
|
* @return BelongsTo<StorefrontWebsiteTypeExtra, $this>
|
||||||
*/
|
*/
|
||||||
public function websiteTypeExtra(): BelongsTo
|
public function websiteTypeExtra(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(WebsiteTypeExtra::class, 'website_type_extra_id');
|
return $this->belongsTo(StorefrontWebsiteTypeExtra::class, 'website_type_extra_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setResolvedConfig(mixed $config): self
|
public function setResolvedConfig(mixed $config): self
|
||||||
|
|||||||
@@ -127,12 +127,13 @@ class StoreTenantRequest extends FormRequest
|
|||||||
'min:0',
|
'min:0',
|
||||||
'max:99.99',
|
'max:99.99',
|
||||||
],
|
],
|
||||||
'website_type_code' => [
|
'storefront_website_type_code' => [
|
||||||
'required_with:extras',
|
'required_with:extras',
|
||||||
'sometimes',
|
'sometimes',
|
||||||
'string',
|
'string',
|
||||||
Rule::exists('website_type', 'codigo'),
|
Rule::exists('storefront_website_types', 'codigo'),
|
||||||
],
|
],
|
||||||
], app(WebsiteExtraService::class)->requestRules($this->input('website_type_code')));
|
'admin_website_type_code' => ['sometimes', 'nullable', 'string', Rule::exists('admin_website_types', 'codigo')],
|
||||||
|
], app(WebsiteExtraService::class)->requestRules($this->input('storefront_website_type_code')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,6 +148,18 @@ class UpdateTenantRequest extends FormRequest
|
|||||||
'min:0',
|
'min:0',
|
||||||
'max:99.99',
|
'max:99.99',
|
||||||
],
|
],
|
||||||
|
'admin_website_type_code' => ['sometimes', 'nullable', 'string', Rule::exists('admin_website_types', 'codigo')],
|
||||||
|
'storefront_website_type_code' => [
|
||||||
|
'sometimes',
|
||||||
|
'nullable',
|
||||||
|
'string',
|
||||||
|
Rule::exists('storefront_website_types', 'codigo'),
|
||||||
|
function (string $attribute, mixed $value, Closure $fail) use ($tenant): void {
|
||||||
|
if ($tenant && $value !== $tenant->storefront_website_type_code && $tenant->websiteExtras()->exists()) {
|
||||||
|
$fail('The storefront website type cannot be changed while the tenant has extras.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ class WebsiteExtrasResource extends JsonResource
|
|||||||
);
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'website_type' => $this->websiteType ? [
|
'storefront_website_type' => $this->storefrontWebsiteType ? [
|
||||||
'codigo' => $this->websiteType->codigo,
|
'codigo' => $this->storefrontWebsiteType->codigo,
|
||||||
'nombre' => $this->websiteType->nombre,
|
'nombre' => $this->storefrontWebsiteType->nombre,
|
||||||
] : null,
|
] : null,
|
||||||
'definitions' => $this->websiteType?->extras
|
'definitions' => $this->storefrontWebsiteType?->extras
|
||||||
->mapWithKeys(fn ($definition) => [
|
->mapWithKeys(fn ($definition) => [
|
||||||
$definition->codigo => [
|
$definition->codigo => [
|
||||||
'codigo' => $definition->codigo,
|
'codigo' => $definition->codigo,
|
||||||
|
|||||||
@@ -35,21 +35,19 @@ class TenantResource extends JsonResource
|
|||||||
'nombre' => $this->nombre,
|
'nombre' => $this->nombre,
|
||||||
'dominio' => $this->dominio,
|
'dominio' => $this->dominio,
|
||||||
'base_path' => $this->base_path,
|
'base_path' => $this->base_path,
|
||||||
'site_title' => $this->site_title
|
'site_title' => $this->site_title ?? 'ShopitFront',
|
||||||
?? $this->websiteType?->site_title
|
|
||||||
?? 'ShopitFront',
|
|
||||||
'asset_url' => config('filesystems.disks.s3.url'),
|
'asset_url' => config('filesystems.disks.s3.url'),
|
||||||
'address' => $this->address,
|
'address' => $this->address,
|
||||||
'phone' => $this->phone,
|
'phone' => $this->phone,
|
||||||
'favicon' => ($this->favicon ?? $this->websiteType?->favicon)
|
'favicon' => $this->favicon?->getTemporaryUrl(1440),
|
||||||
?->getTemporaryUrl(1440),
|
|
||||||
'primary_color' => $this->primary_color,
|
'primary_color' => $this->primary_color,
|
||||||
'secondary_color' => $this->secondary_color,
|
'secondary_color' => $this->secondary_color,
|
||||||
'danger_color' => $this->danger_color,
|
'danger_color' => $this->danger_color,
|
||||||
'success_color' => $this->success_color,
|
'success_color' => $this->success_color,
|
||||||
'header_bg_color' => $this->header_bg_color,
|
'header_bg_color' => $this->header_bg_color,
|
||||||
'footer_bg_color' => $this->footer_bg_color,
|
'footer_bg_color' => $this->footer_bg_color,
|
||||||
'website_type_code' => $this->website_type_code,
|
'admin_website_type_code' => $this->admin_website_type_code,
|
||||||
|
'storefront_website_type_code' => $this->storefront_website_type_code,
|
||||||
'event_date_text' => $this->event_date_text,
|
'event_date_text' => $this->event_date_text,
|
||||||
'event' => $this->whenLoaded('eventDates', fn () => $this->event_title === null
|
'event' => $this->whenLoaded('eventDates', fn () => $this->event_title === null
|
||||||
? null
|
? null
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ namespace App\Domains\Tenant\Services;
|
|||||||
|
|
||||||
use App\Domains\Attachable\Models\Attachment;
|
use App\Domains\Attachable\Models\Attachment;
|
||||||
use App\Domains\Attachable\Services\AttachmentService;
|
use App\Domains\Attachable\Services\AttachmentService;
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class WebsiteTypeService
|
class AdminWebsiteTypeService
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected AttachmentService $attachmentService,
|
protected AttachmentService $attachmentService,
|
||||||
@@ -19,9 +19,9 @@ class WebsiteTypeService
|
|||||||
*
|
*
|
||||||
* @param array<string, mixed> $data
|
* @param array<string, mixed> $data
|
||||||
*/
|
*/
|
||||||
public function create(array $data): WebsiteType
|
public function create(array $data): AdminWebsiteType
|
||||||
{
|
{
|
||||||
return $this->save(new WebsiteType, $data);
|
return $this->save(new AdminWebsiteType, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,10 +30,10 @@ class WebsiteTypeService
|
|||||||
* @param array<string, mixed> $attributes
|
* @param array<string, mixed> $attributes
|
||||||
* @param array<string, mixed> $values
|
* @param array<string, mixed> $values
|
||||||
*/
|
*/
|
||||||
public function updateOrCreate(array $attributes, array $values = []): WebsiteType
|
public function updateOrCreate(array $attributes, array $values = []): AdminWebsiteType
|
||||||
{
|
{
|
||||||
/** @var WebsiteType $websiteType */
|
/** @var AdminWebsiteType $websiteType */
|
||||||
$websiteType = WebsiteType::query()->firstOrNew($attributes);
|
$websiteType = AdminWebsiteType::query()->firstOrNew($attributes);
|
||||||
|
|
||||||
return $this->save($websiteType, [...$attributes, ...$values]);
|
return $this->save($websiteType, [...$attributes, ...$values]);
|
||||||
}
|
}
|
||||||
@@ -41,9 +41,9 @@ class WebsiteTypeService
|
|||||||
/**
|
/**
|
||||||
* @param array<string, mixed> $data
|
* @param array<string, mixed> $data
|
||||||
*/
|
*/
|
||||||
private function save(WebsiteType $websiteType, array $data): WebsiteType
|
private function save(AdminWebsiteType $websiteType, array $data): AdminWebsiteType
|
||||||
{
|
{
|
||||||
return DB::transaction(function () use ($websiteType, $data): WebsiteType {
|
return DB::transaction(function () use ($websiteType, $data): AdminWebsiteType {
|
||||||
$previousLogos = [];
|
$previousLogos = [];
|
||||||
|
|
||||||
$attachmentFields = [
|
$attachmentFields = [
|
||||||
@@ -68,7 +68,7 @@ class WebsiteTypeService
|
|||||||
if ($logo) {
|
if ($logo) {
|
||||||
$attachment = is_string($logo) && Str::isUuid($logo)
|
$attachment = is_string($logo) && Str::isUuid($logo)
|
||||||
? Attachment::query()->where('key', $logo)->first()
|
? Attachment::query()->where('key', $logo)->first()
|
||||||
: $this->attachmentService->store($logo, 'website-types');
|
: $this->attachmentService->store($logo, 'admin-website-types');
|
||||||
}
|
}
|
||||||
|
|
||||||
$data[$attachmentField['column']] = $attachment?->id;
|
$data[$attachmentField['column']] = $attachment?->id;
|
||||||
@@ -82,7 +82,7 @@ class WebsiteTypeService
|
|||||||
&& $previousLogo->id !== $websiteType->site_logo
|
&& $previousLogo->id !== $websiteType->site_logo
|
||||||
&& $previousLogo->id !== $websiteType->footer_logo
|
&& $previousLogo->id !== $websiteType->footer_logo
|
||||||
&& $previousLogo->id !== $websiteType->favicon_id
|
&& $previousLogo->id !== $websiteType->favicon_id
|
||||||
&& ! $this->isReferencedByWebsiteType($previousLogo)
|
&& ! $this->isReferencedByBrand($previousLogo)
|
||||||
) {
|
) {
|
||||||
$this->attachmentService->delete($previousLogo);
|
$this->attachmentService->delete($previousLogo);
|
||||||
}
|
}
|
||||||
@@ -92,9 +92,10 @@ class WebsiteTypeService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isReferencedByWebsiteType(Attachment $attachment): bool
|
private function isReferencedByBrand(Attachment $attachment): bool
|
||||||
{
|
{
|
||||||
return WebsiteType::query()
|
return Tenant::query()->where('favicon_id', $attachment->id)->exists()
|
||||||
|
|| AdminWebsiteType::query()
|
||||||
->where(function ($query) use ($attachment): void {
|
->where(function ($query) use ($attachment): void {
|
||||||
$query
|
$query
|
||||||
->where('site_logo', $attachment->id)
|
->where('site_logo', $attachment->id)
|
||||||
@@ -14,7 +14,6 @@ class TenantInformationService
|
|||||||
'headerLogo',
|
'headerLogo',
|
||||||
'footerLogo',
|
'footerLogo',
|
||||||
'favicon',
|
'favicon',
|
||||||
'websiteType.favicon',
|
|
||||||
'headerBackgroundImage',
|
'headerBackgroundImage',
|
||||||
'footerBackgroundImage',
|
'footerBackgroundImage',
|
||||||
'socialMedia',
|
'socialMedia',
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use App\Domains\Shared\Rules\CroppedImageOrBase64Rule;
|
|||||||
use App\Domains\Shared\Rules\ImageOrBase64Rule;
|
use App\Domains\Shared\Rules\ImageOrBase64Rule;
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use App\Domains\Tenant\Models\WebsiteExtra;
|
use App\Domains\Tenant\Models\WebsiteExtra;
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\StorefrontWebsiteType;
|
||||||
use App\Domains\Tenant\Models\WebsiteTypeExtra;
|
use App\Domains\Tenant\Models\StorefrontWebsiteTypeExtra;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
@@ -37,7 +37,7 @@ class WebsiteExtraService
|
|||||||
$definitions = $this->definitionsFor($websiteTypeCode);
|
$definitions = $this->definitionsFor($websiteTypeCode);
|
||||||
$allowedCodes = $definitions->pluck('codigo')->all();
|
$allowedCodes = $definitions->pluck('codigo')->all();
|
||||||
$hasRequiredExtras = $definitions->contains(
|
$hasRequiredExtras = $definitions->contains(
|
||||||
fn (WebsiteTypeExtra $definition): bool => $definition->is_required
|
fn (StorefrontWebsiteTypeExtra $definition): bool => $definition->is_required
|
||||||
);
|
);
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
@@ -95,11 +95,11 @@ class WebsiteExtraService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$definitions = $this->definitionsFor((string) $tenant->website_type_code)
|
$definitions = $this->definitionsFor((string) $tenant->storefront_website_type_code)
|
||||||
->keyBy('codigo');
|
->keyBy('codigo');
|
||||||
|
|
||||||
foreach ($extras as $name => $config) {
|
foreach ($extras as $name => $config) {
|
||||||
/** @var WebsiteTypeExtra|null $definition */
|
/** @var StorefrontWebsiteTypeExtra|null $definition */
|
||||||
$definition = $definitions->get($name);
|
$definition = $definitions->get($name);
|
||||||
|
|
||||||
if (! $definition) {
|
if (! $definition) {
|
||||||
@@ -193,20 +193,20 @@ class WebsiteExtraService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function definitionForTenant(Tenant $tenant, string $extraCode): WebsiteTypeExtra
|
public function definitionForTenant(Tenant $tenant, string $extraCode): StorefrontWebsiteTypeExtra
|
||||||
{
|
{
|
||||||
return WebsiteTypeExtra::query()
|
return StorefrontWebsiteTypeExtra::query()
|
||||||
->where('website_type_code', $tenant->website_type_code)
|
->where('storefront_website_type_code', $tenant->storefront_website_type_code)
|
||||||
->where('codigo', $extraCode)
|
->where('codigo', $extraCode)
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection<int, WebsiteTypeExtra>
|
* @return Collection<int, StorefrontWebsiteTypeExtra>
|
||||||
*/
|
*/
|
||||||
private function definitionsFor(string $websiteTypeCode): Collection
|
private function definitionsFor(string $websiteTypeCode): Collection
|
||||||
{
|
{
|
||||||
$websiteType = WebsiteType::query()
|
$websiteType = StorefrontWebsiteType::query()
|
||||||
->where('codigo', $websiteTypeCode)
|
->where('codigo', $websiteTypeCode)
|
||||||
->with('extras')
|
->with('extras')
|
||||||
->first();
|
->first();
|
||||||
@@ -252,7 +252,7 @@ class WebsiteExtraService
|
|||||||
|
|
||||||
private function applyTransforms(
|
private function applyTransforms(
|
||||||
Tenant $tenant,
|
Tenant $tenant,
|
||||||
WebsiteTypeExtra $definition,
|
StorefrontWebsiteTypeExtra $definition,
|
||||||
mixed $config,
|
mixed $config,
|
||||||
string $requestRoot
|
string $requestRoot
|
||||||
): mixed {
|
): mixed {
|
||||||
@@ -318,7 +318,7 @@ class WebsiteExtraService
|
|||||||
*/
|
*/
|
||||||
private function transformValue(
|
private function transformValue(
|
||||||
Tenant $tenant,
|
Tenant $tenant,
|
||||||
WebsiteTypeExtra $definition,
|
StorefrontWebsiteTypeExtra $definition,
|
||||||
string $path,
|
string $path,
|
||||||
mixed $value,
|
mixed $value,
|
||||||
array $transform,
|
array $transform,
|
||||||
|
|||||||
132
database/migrations/2026_09_17_000000_split_website_types.php
Normal file
132
database/migrations/2026_09_17_000000_split_website_types.php
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('storefront_website_types', function (Blueprint $table): void {
|
||||||
|
$table->id();
|
||||||
|
$table->string('codigo')->unique();
|
||||||
|
$table->string('nombre');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
DB::table('website_type')->orderBy('id')->chunk(100, function ($types): void {
|
||||||
|
foreach ($types as $type) {
|
||||||
|
DB::table('storefront_website_types')->insert([
|
||||||
|
'id' => $type->id,
|
||||||
|
'codigo' => $type->codigo,
|
||||||
|
'nombre' => $type->nombre,
|
||||||
|
'created_at' => $type->created_at,
|
||||||
|
'updated_at' => $type->updated_at,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('tenants', function (Blueprint $table): void {
|
||||||
|
$table->string('storefront_website_type_code')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
DB::table('tenants')->orderBy('id')->chunk(100, function ($tenants): void {
|
||||||
|
foreach ($tenants as $tenant) {
|
||||||
|
$type = $tenant->website_type_code
|
||||||
|
? DB::table('website_type')->where('codigo', $tenant->website_type_code)->first()
|
||||||
|
: null;
|
||||||
|
|
||||||
|
DB::table('tenants')->where('id', $tenant->id)->update([
|
||||||
|
'storefront_website_type_code' => $tenant->website_type_code,
|
||||||
|
'site_title' => $tenant->site_title ?? $type?->site_title,
|
||||||
|
'favicon_id' => $tenant->favicon_id ?? $type?->favicon_id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (DB::getDriverName() !== 'sqlite') {
|
||||||
|
Schema::table('tenants', fn (Blueprint $table) => $table->dropForeign(['website_type_code']));
|
||||||
|
Schema::table('website_type_extras', fn (Blueprint $table) => $table->dropForeign(['website_type_code']));
|
||||||
|
Schema::table('website_type_integrations', fn (Blueprint $table) => $table->dropForeign(['website_type_code']));
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::rename('website_type', 'admin_website_types');
|
||||||
|
Schema::rename('website_type_extras', 'storefront_website_type_extras');
|
||||||
|
Schema::rename('website_type_integrations', 'admin_website_type_integrations');
|
||||||
|
|
||||||
|
Schema::table('tenants', fn (Blueprint $table) => $table->renameColumn('website_type_code', 'admin_website_type_code'));
|
||||||
|
Schema::table('storefront_website_type_extras', fn (Blueprint $table) => $table->renameColumn('website_type_code', 'storefront_website_type_code'));
|
||||||
|
Schema::table('admin_website_type_integrations', fn (Blueprint $table) => $table->renameColumn('website_type_code', 'admin_website_type_code'));
|
||||||
|
|
||||||
|
if (DB::getDriverName() === 'sqlite') {
|
||||||
|
Schema::disableForeignKeyConstraints();
|
||||||
|
Schema::create('storefront_website_type_extras_rebuilt', function (Blueprint $table): void {
|
||||||
|
$table->id();
|
||||||
|
$table->string('storefront_website_type_code');
|
||||||
|
$table->foreign('storefront_website_type_code')->references('codigo')->on('storefront_website_types')->cascadeOnUpdate()->cascadeOnDelete();
|
||||||
|
$table->string('codigo')->nullable();
|
||||||
|
$table->string('nombre');
|
||||||
|
$table->text('descripcion');
|
||||||
|
$table->boolean('is_required')->default(false);
|
||||||
|
$table->json('config_schema');
|
||||||
|
$table->timestamps();
|
||||||
|
$table->unique(['storefront_website_type_code', 'codigo']);
|
||||||
|
});
|
||||||
|
DB::table('storefront_website_type_extras')->orderBy('id')->chunk(100, function ($extras): void {
|
||||||
|
foreach ($extras as $extra) {
|
||||||
|
DB::table('storefront_website_type_extras_rebuilt')->insert((array) $extra);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Schema::drop('storefront_website_type_extras');
|
||||||
|
Schema::rename('storefront_website_type_extras_rebuilt', 'storefront_website_type_extras');
|
||||||
|
Schema::enableForeignKeyConstraints();
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('tenants', function (Blueprint $table): void {
|
||||||
|
if (DB::getDriverName() !== 'sqlite') {
|
||||||
|
$table->foreign('admin_website_type_code')->references('codigo')->on('admin_website_types')->cascadeOnUpdate()->nullOnDelete();
|
||||||
|
}
|
||||||
|
$table->foreign('storefront_website_type_code')->references('codigo')->on('storefront_website_types')->cascadeOnUpdate()->nullOnDelete();
|
||||||
|
});
|
||||||
|
if (DB::getDriverName() !== 'sqlite') {
|
||||||
|
Schema::table('storefront_website_type_extras', function (Blueprint $table): void {
|
||||||
|
$table->foreign('storefront_website_type_code')->references('codigo')->on('storefront_website_types')->cascadeOnUpdate()->cascadeOnDelete();
|
||||||
|
});
|
||||||
|
Schema::table('admin_website_type_integrations', function (Blueprint $table): void {
|
||||||
|
$table->foreign('admin_website_type_code')->references('codigo')->on('admin_website_types')->cascadeOnDelete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
if (DB::getDriverName() === 'sqlite') {
|
||||||
|
throw new RuntimeException('SQLite rollback is unsupported for this foreign-key refactor. Recreate the test database instead.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('tenants', function (Blueprint $table): void {
|
||||||
|
$table->dropForeign(['admin_website_type_code']);
|
||||||
|
$table->dropForeign(['storefront_website_type_code']);
|
||||||
|
});
|
||||||
|
Schema::table('storefront_website_type_extras', fn (Blueprint $table) => $table->dropForeign(['storefront_website_type_code']));
|
||||||
|
Schema::table('admin_website_type_integrations', fn (Blueprint $table) => $table->dropForeign(['admin_website_type_code']));
|
||||||
|
|
||||||
|
Schema::table('tenants', fn (Blueprint $table) => $table->renameColumn('admin_website_type_code', 'website_type_code'));
|
||||||
|
Schema::table('storefront_website_type_extras', fn (Blueprint $table) => $table->renameColumn('storefront_website_type_code', 'website_type_code'));
|
||||||
|
Schema::table('admin_website_type_integrations', fn (Blueprint $table) => $table->renameColumn('admin_website_type_code', 'website_type_code'));
|
||||||
|
|
||||||
|
Schema::rename('admin_website_types', 'website_type');
|
||||||
|
Schema::rename('storefront_website_type_extras', 'website_type_extras');
|
||||||
|
Schema::rename('admin_website_type_integrations', 'website_type_integrations');
|
||||||
|
|
||||||
|
Schema::table('tenants', function (Blueprint $table): void {
|
||||||
|
$table->foreign('website_type_code')->references('codigo')->on('website_type')->cascadeOnUpdate()->nullOnDelete();
|
||||||
|
$table->dropColumn('storefront_website_type_code');
|
||||||
|
});
|
||||||
|
Schema::table('website_type_extras', fn (Blueprint $table) => $table->foreign('website_type_code')->references('codigo')->on('website_type')->cascadeOnUpdate()->cascadeOnDelete());
|
||||||
|
Schema::table('website_type_integrations', fn (Blueprint $table) => $table->foreign('website_type_code')->references('codigo')->on('website_type')->cascadeOnDelete());
|
||||||
|
Schema::dropIfExists('storefront_website_types');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -78,7 +78,8 @@ class DesfilePuraTendenciaSeeder extends Seeder
|
|||||||
'checkout_editing_policy' => 'disabled',
|
'checkout_editing_policy' => 'disabled',
|
||||||
'display_cart_item_images' => false,
|
'display_cart_item_images' => false,
|
||||||
'scanner_category_validation_enabled' => false,
|
'scanner_category_validation_enabled' => false,
|
||||||
'website_type_code' => 'onticket',
|
'admin_website_type_code' => 'onticket',
|
||||||
|
'storefront_website_type_code' => 'onticket',
|
||||||
'header_logo' => $this->uploadedImage(
|
'header_logo' => $this->uploadedImage(
|
||||||
'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_header.png',
|
'images/tennants/desfile_pura_tendencia/desfile_pura_tendencia_header.png',
|
||||||
'desfile_pura_tendencia_header.png',
|
'desfile_pura_tendencia_header.png',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use App\Domains\Attachable\Models\Attachment;
|
|||||||
use App\Domains\Attachable\Services\AttachmentService;
|
use App\Domains\Attachable\Services\AttachmentService;
|
||||||
use App\Domains\Client\Models\Client;
|
use App\Domains\Client\Models\Client;
|
||||||
use App\Domains\Tenant\Models\Tenant;
|
use App\Domains\Tenant\Models\Tenant;
|
||||||
use App\Domains\Tenant\Models\WebsiteType;
|
use App\Domains\Tenant\Models\AdminWebsiteType;
|
||||||
use App\Domains\Tenant\Services\TenantService;
|
use App\Domains\Tenant\Services\TenantService;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
@@ -56,7 +56,7 @@ class TenantSeeder extends Seeder
|
|||||||
['name' => 'OnTicket'],
|
['name' => 'OnTicket'],
|
||||||
);
|
);
|
||||||
|
|
||||||
$onTicketType = WebsiteType::query()->where('codigo', 'onticket')->firstOrFail();
|
$onTicketType = AdminWebsiteType::query()->where('codigo', 'onticket')->firstOrFail();
|
||||||
|
|
||||||
$onTicketTenant = Tenant::query()->where('codigo', 'onticket')->first();
|
$onTicketTenant = Tenant::query()->where('codigo', 'onticket')->first();
|
||||||
|
|
||||||
@@ -75,7 +75,8 @@ class TenantSeeder extends Seeder
|
|||||||
'footer_bg_color' => $onTicketType->surface_color,
|
'footer_bg_color' => $onTicketType->surface_color,
|
||||||
'display_categories' => false,
|
'display_categories' => false,
|
||||||
'display_seach_bar' => false,
|
'display_seach_bar' => false,
|
||||||
'website_type_code' => $onTicketType->codigo,
|
'admin_website_type_code' => $onTicketType->codigo,
|
||||||
|
'storefront_website_type_code' => $onTicketType->codigo,
|
||||||
'header_logo' => $this->uploadedImage(
|
'header_logo' => $this->uploadedImage(
|
||||||
'images/tennants/onticket/onticket_logo.png',
|
'images/tennants/onticket/onticket_logo.png',
|
||||||
'onticket_logo.png',
|
'onticket_logo.png',
|
||||||
@@ -127,7 +128,8 @@ class TenantSeeder extends Seeder
|
|||||||
'header_logo' => $this->uploadedImage('images/tennants/sonder/sonder_header.png', 'sonder_header.png'),
|
'header_logo' => $this->uploadedImage('images/tennants/sonder/sonder_header.png', 'sonder_header.png'),
|
||||||
'footer_logo' => $this->uploadedImage('images/tennants/sonder/sonder_footer.png', 'sonder_footer.png'),
|
'footer_logo' => $this->uploadedImage('images/tennants/sonder/sonder_footer.png', 'sonder_footer.png'),
|
||||||
'social_media' => self::SOCIAL_MEDIA,
|
'social_media' => self::SOCIAL_MEDIA,
|
||||||
'website_type_code' => 'shopit',
|
'admin_website_type_code' => 'shopit',
|
||||||
|
'storefront_website_type_code' => 'shopit',
|
||||||
'extras' => [
|
'extras' => [
|
||||||
'carousel' => [
|
'carousel' => [
|
||||||
$this->uploadedImage(
|
$this->uploadedImage(
|
||||||
@@ -195,7 +197,8 @@ class TenantSeeder extends Seeder
|
|||||||
'futbol_infantil_favicon.png',
|
'futbol_infantil_favicon.png',
|
||||||
),
|
),
|
||||||
'social_media' => self::SOCIAL_MEDIA,
|
'social_media' => self::SOCIAL_MEDIA,
|
||||||
'website_type_code' => 'onticket',
|
'admin_website_type_code' => 'onticket',
|
||||||
|
'storefront_website_type_code' => 'onticket',
|
||||||
'extras' => [
|
'extras' => [
|
||||||
'heroConfig' => [
|
'heroConfig' => [
|
||||||
'title_html' => '<h1>Fiesta Fútbol Infantil</h1>',
|
'title_html' => '<h1>Fiesta Fútbol Infantil</h1>',
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
namespace Database\Seeders;
|
namespace Database\Seeders;
|
||||||
|
|
||||||
use App\Domains\Tenant\Services\WebsiteTypeService;
|
use App\Domains\Tenant\Services\AdminWebsiteTypeService;
|
||||||
|
use App\Domains\Tenant\Models\StorefrontWebsiteType;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
@@ -22,7 +23,7 @@ class WebsiteTypeSeeder extends Seeder
|
|||||||
'border_color' => '#EAEAEA',
|
'border_color' => '#EAEAEA',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(private readonly WebsiteTypeService $websiteTypeService) {}
|
public function __construct(private readonly AdminWebsiteTypeService $websiteTypeService) {}
|
||||||
|
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
@@ -40,7 +41,9 @@ class WebsiteTypeSeeder extends Seeder
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
$shopIt->extras()->updateOrCreate(
|
$shopItStorefront = StorefrontWebsiteType::query()->updateOrCreate(['codigo' => 'shopit'], ['nombre' => 'ShopIt']);
|
||||||
|
|
||||||
|
$shopItStorefront->extras()->updateOrCreate(
|
||||||
['codigo' => 'carousel'],
|
['codigo' => 'carousel'],
|
||||||
[
|
[
|
||||||
'nombre' => 'Carrusel principal',
|
'nombre' => 'Carrusel principal',
|
||||||
@@ -75,7 +78,9 @@ class WebsiteTypeSeeder extends Seeder
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
$onTicket->extras()->updateOrCreate(
|
$onTicketStorefront = StorefrontWebsiteType::query()->updateOrCreate(['codigo' => 'onticket'], ['nombre' => 'OnTicket']);
|
||||||
|
|
||||||
|
$onTicketStorefront->extras()->updateOrCreate(
|
||||||
['codigo' => 'heroConfig'],
|
['codigo' => 'heroConfig'],
|
||||||
[
|
[
|
||||||
'nombre' => 'Configuración del hero',
|
'nombre' => 'Configuración del hero',
|
||||||
@@ -100,7 +105,7 @@ class WebsiteTypeSeeder extends Seeder
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
$onTicket->extras()->updateOrCreate(
|
$onTicketStorefront->extras()->updateOrCreate(
|
||||||
['codigo' => 'eventConfig'],
|
['codigo' => 'eventConfig'],
|
||||||
[
|
[
|
||||||
'nombre' => 'Información del evento',
|
'nombre' => 'Información del evento',
|
||||||
@@ -127,7 +132,7 @@ class WebsiteTypeSeeder extends Seeder
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
$onTicket->extras()->updateOrCreate(
|
$onTicketStorefront->extras()->updateOrCreate(
|
||||||
['codigo' => 'additionalInfoConfig'],
|
['codigo' => 'additionalInfoConfig'],
|
||||||
[
|
[
|
||||||
'nombre' => 'Información adicional',
|
'nombre' => 'Información adicional',
|
||||||
|
|||||||
Reference in New Issue
Block a user