connectionReady($connection)) { throw new RuntimeException('Merchant database connection is not available.'); } $storefronts = DB::connection($connection) ->table('qr_codes') ->join('users', 'users.id', '=', 'qr_codes.user_id') ->where('users.public_id', $ownerRef) ->where('qr_codes.is_active', true) ->whereIn('qr_codes.type', ['shop', 'menu']) ->select('qr_codes.id', 'qr_codes.payload', 'qr_codes.label') ->get(); if ($storefronts->isEmpty()) { throw new RuntimeException('No active Merchant storefronts found for this account.'); } $imported = 0; $updated = 0; foreach ($storefronts as $storefront) { $payload = json_decode((string) $storefront->payload, true); $content = is_array($payload) ? (array) ($payload['content'] ?? []) : []; $sections = (array) ($content['sections'] ?? []); foreach ($sections as $section) { foreach ((array) ($section['items'] ?? []) as $item) { $name = trim((string) ($item['name'] ?? '')); $priceGhs = (float) ($item['price'] ?? 0); if ($name === '' || $priceGhs <= 0) { continue; } $priceMinor = (int) round($priceGhs * 100); $sku = 'm'.$storefront->id.'-'.substr(md5($name), 0, 8); $existing = PosProduct::owned($ownerRef)->where('sku', $sku)->first(); $attrs = [ 'name' => $name, 'sku' => $sku, 'price_minor' => $priceMinor, 'currency' => config('pos.default_currency', 'GHS'), 'is_active' => true, ]; if ($existing) { $existing->update($attrs); $updated++; } else { PosProduct::create([...$attrs, 'owner_ref' => $ownerRef]); $imported++; } } } } if ($imported === 0 && $updated === 0) { throw new RuntimeException('No catalog items found in Merchant storefronts.'); } return [ 'imported' => $imported, 'updated' => $updated, 'storefronts' => $storefronts->count(), ]; } private function connectionReady(string $connection): bool { try { DB::connection($connection)->getPdo(); return true; } catch (\Throwable) { return false; } } }