Deploy Ladill Woo Manager / deploy (push) Successful in 1m5s
Surfaces actionable controls in Ladill instead of status-only cards: sync catalogs via the plugin proxy, show channel metrics, and link to orders/labels for fulfillment. Co-authored-by: Cursor <cursoragent@cursor.com>
222 lines
7.4 KiB
PHP
222 lines
7.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Woo;
|
|
|
|
use App\Models\WooStore;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class IntegrationStatusService
|
|
{
|
|
public function __construct(private PluginClient $client) {}
|
|
|
|
/**
|
|
* @return array{
|
|
* store: ?WooStore,
|
|
* reachable: bool,
|
|
* cached: bool,
|
|
* integrations: list<array<string, mixed>>
|
|
* }
|
|
*/
|
|
public function forStore(?WooStore $store, bool $refresh = false): array
|
|
{
|
|
$catalog = config('woo_integrations', []);
|
|
|
|
if (! $store) {
|
|
return [
|
|
'store' => null,
|
|
'reachable' => false,
|
|
'cached' => false,
|
|
'integrations' => $this->catalogOnly($catalog),
|
|
];
|
|
}
|
|
|
|
if ($refresh) {
|
|
$this->forgetCache($store);
|
|
}
|
|
|
|
$ttl = max(0, (int) config('woo.integrations_cache_ttl_seconds', 300));
|
|
$cacheKey = $this->cacheKey($store);
|
|
|
|
if ($ttl === 0) {
|
|
return $this->buildPayload($store, $catalog);
|
|
}
|
|
|
|
$cached = Cache::get($cacheKey);
|
|
if (is_array($cached)) {
|
|
return array_merge($cached, ['cached' => true]);
|
|
}
|
|
|
|
$payload = $this->buildPayload($store, $catalog);
|
|
Cache::put($cacheKey, $payload, $ttl);
|
|
|
|
return array_merge($payload, ['cached' => false]);
|
|
}
|
|
|
|
public function forgetCache(WooStore $store): void
|
|
{
|
|
Cache::forget($this->cacheKey($store));
|
|
}
|
|
|
|
/**
|
|
* @return array{success: bool, message: string}
|
|
*/
|
|
public function syncCatalog(?WooStore $store, string $key): array
|
|
{
|
|
$catalog = config('woo_integrations', []);
|
|
|
|
if (! $store) {
|
|
return [
|
|
'success' => false,
|
|
'message' => 'Connect a store before syncing catalogs.',
|
|
];
|
|
}
|
|
|
|
if (! isset($catalog[$key]) || ! ($catalog[$key]['supports_catalog_sync'] ?? false)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => 'Catalog sync is not available for this integration.',
|
|
];
|
|
}
|
|
|
|
$response = $this->client->postWithDetails($store, 'integrations/'.$key.'/sync');
|
|
|
|
if (! $response['reachable']) {
|
|
return [
|
|
'success' => false,
|
|
'message' => 'Could not reach your store. Check that the Ladill plugin is active.',
|
|
];
|
|
}
|
|
|
|
$body = $response['body'] ?? [];
|
|
|
|
if (! $response['successful']) {
|
|
return [
|
|
'success' => false,
|
|
'message' => (string) ($body['message'] ?? 'Catalog sync could not be started.'),
|
|
];
|
|
}
|
|
|
|
if (! ($body['success'] ?? false)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => (string) ($body['message'] ?? 'Catalog sync could not be started.'),
|
|
];
|
|
}
|
|
|
|
$this->forgetCache($store);
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => (string) ($body['message'] ?? 'Catalog sync started on your store.'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, array<string, mixed>> $catalog
|
|
* @return array{
|
|
* store: WooStore,
|
|
* reachable: bool,
|
|
* integrations: list<array<string, mixed>>
|
|
* }
|
|
*/
|
|
private function buildPayload(WooStore $store, array $catalog): array
|
|
{
|
|
$remote = $this->client->get($store, 'integrations/status');
|
|
$reachable = is_array($remote);
|
|
|
|
if (! $reachable) {
|
|
Log::info('Woo integration status unavailable', ['store_id' => $store->id]);
|
|
}
|
|
|
|
$remoteItems = is_array($remote['integrations'] ?? null) ? $remote['integrations'] : [];
|
|
|
|
$integrations = [];
|
|
foreach ($catalog as $key => $meta) {
|
|
$remoteStatus = is_array($remoteItems[$key] ?? null) ? $remoteItems[$key] : [];
|
|
$integrations[] = $this->mergeIntegration($key, $meta, $remoteStatus, $store, $reachable);
|
|
}
|
|
|
|
return [
|
|
'store' => $store,
|
|
'reachable' => $reachable,
|
|
'integrations' => $integrations,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $meta
|
|
* @param array<string, mixed> $remoteStatus
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function mergeIntegration(string $key, array $meta, array $remoteStatus, WooStore $store, bool $reachable): array
|
|
{
|
|
$state = $reachable
|
|
? (string) ($remoteStatus['state'] ?? 'unknown')
|
|
: 'unavailable';
|
|
|
|
$manageUrl = $remoteStatus['manage_url'] ?? null;
|
|
if (is_string($manageUrl) && $manageUrl !== '' && ! str_starts_with($manageUrl, 'http')) {
|
|
$manageUrl = rtrim((string) $store->site_url, '/').'/'.ltrim($manageUrl, '/');
|
|
}
|
|
|
|
return [
|
|
'key' => $key,
|
|
'name' => (string) ($meta['name'] ?? $key),
|
|
'description' => (string) ($meta['description'] ?? ''),
|
|
'category' => (string) ($meta['category'] ?? 'Integration'),
|
|
'install_url' => $meta['install_url'] ?? null,
|
|
'docs_url' => $meta['docs_url'] ?? null,
|
|
'supports_catalog_sync' => (bool) ($meta['supports_catalog_sync'] ?? false),
|
|
'supports_metrics' => (bool) ($meta['supports_metrics'] ?? false),
|
|
'supports_label_actions' => (bool) ($meta['supports_label_actions'] ?? false),
|
|
'state' => $state,
|
|
'installed' => (bool) ($remoteStatus['installed'] ?? false),
|
|
'connected' => (bool) ($remoteStatus['connected'] ?? false),
|
|
'summary' => $reachable
|
|
? (string) ($remoteStatus['summary'] ?? '')
|
|
: 'Could not reach your store. Check that the Ladill plugin is active.',
|
|
'manage_url' => is_string($manageUrl) && $manageUrl !== '' ? $manageUrl : null,
|
|
'details' => is_array($remoteStatus['details'] ?? null) ? $remoteStatus['details'] : [],
|
|
'metrics' => is_array($remoteStatus['metrics'] ?? null) ? $remoteStatus['metrics'] : [],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, array<string, mixed>> $catalog
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
private function catalogOnly(array $catalog): array
|
|
{
|
|
$integrations = [];
|
|
|
|
foreach ($catalog as $key => $meta) {
|
|
$integrations[] = [
|
|
'key' => $key,
|
|
'name' => (string) ($meta['name'] ?? $key),
|
|
'description' => (string) ($meta['description'] ?? ''),
|
|
'category' => (string) ($meta['category'] ?? 'Integration'),
|
|
'install_url' => $meta['install_url'] ?? null,
|
|
'docs_url' => $meta['docs_url'] ?? null,
|
|
'supports_catalog_sync' => (bool) ($meta['supports_catalog_sync'] ?? false),
|
|
'supports_metrics' => (bool) ($meta['supports_metrics'] ?? false),
|
|
'supports_label_actions' => (bool) ($meta['supports_label_actions'] ?? false),
|
|
'state' => 'no_store',
|
|
'installed' => false,
|
|
'connected' => false,
|
|
'summary' => 'Connect a WooCommerce store to see status.',
|
|
'manage_url' => null,
|
|
'details' => [],
|
|
'metrics' => [],
|
|
];
|
|
}
|
|
|
|
return $integrations;
|
|
}
|
|
|
|
private function cacheKey(WooStore $store): string
|
|
{
|
|
return 'woo.integrations.'.$store->id;
|
|
}
|
|
}
|