netgescon-day0/app/Services/Catalog/TelegramOffersPublisher.php

112 lines
4.7 KiB
PHP
Executable File

<?php
namespace App\Services\Catalog;
use App\Models\ProductOffer;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use RuntimeException;
class TelegramOffersPublisher
{
/** @return array<string, mixed> */
public function publishOffer(ProductOffer $offer, ?string $chatId = null, bool $dryRun = false): array
{
$token = trim((string) config('services.telegram.offers_bot_token', ''));
$chatId = trim((string) ($chatId ?: config('services.telegram.offers_chat_id', '')));
$channelName = trim((string) config('services.telegram.offers_channel_name', ''));
$message = $this->buildMessage($offer);
$imageUrl = $this->resolveImageUrl($offer);
if ($dryRun) {
return [
'ok' => true,
'dry_run' => true,
'chat_id' => $chatId,
'channel_name' => $channelName,
'image_url' => $imageUrl,
'message' => $message,
'offer_id' => (int) $offer->id,
];
}
if ($token === '') {
throw new RuntimeException('TELEGRAM_OFFERS_BOT_TOKEN non configurato.');
}
if ($chatId === '') {
throw new RuntimeException('TELEGRAM_OFFERS_CHAT_ID non configurato.');
}
$baseUrl = 'https://api.telegram.org/bot' . $token;
$response = null;
$usedMethod = 'sendMessage';
if ($imageUrl !== null) {
$response = Http::asForm()->post($baseUrl . '/sendPhoto', [
'chat_id' => $chatId,
'photo' => $imageUrl,
'caption' => Str::limit($message, 1024, ''),
]);
$usedMethod = 'sendPhoto';
}
if (! $response || ! $response->ok()) {
$response = Http::asForm()->post($baseUrl . '/sendMessage', [
'chat_id' => $chatId,
'text' => $message,
'disable_web_page_preview' => false,
]);
$usedMethod = 'sendMessage';
}
return [
'ok' => $response->ok(),
'dry_run' => false,
'chat_id' => $chatId,
'channel_name' => $channelName,
'method' => $usedMethod,
'image_url' => $imageUrl,
'offer_id' => (int) $offer->id,
'status' => $response->status(),
'response' => $response->json(),
'message' => $message,
];
}
private function buildMessage(ProductOffer $offer): string
{
$payload = is_array($offer->meta['payload'] ?? null) ? $offer->meta['payload'] : [];
$product = $offer->product;
$lines = array_values(array_filter([
'Offerta Amazon NetGescon',
trim((string) ($offer->title ?: $product?->name ?: 'Prodotto Amazon')),
trim((string) ($product?->internal_code ?? '')) !== '' ? 'Catalogo: ' . trim((string) $product?->internal_code) : null,
$this->formatMoney($offer->price_amount, (string) ($offer->currency ?: data_get($payload, 'currency', 'EUR')), 'Prezzo'),
$this->formatMoney($offer->price_compare_at, (string) ($offer->currency ?: data_get($payload, 'currency', 'EUR')), 'Listino'),
trim((string) ($offer->availability ?: data_get($payload, 'availability', ''))) !== '' ? 'Disponibilita: ' . trim((string) ($offer->availability ?: data_get($payload, 'availability', ''))): null,
trim((string) data_get($payload, 'asin', $offer->external_product_id)) !== '' ? 'ASIN: ' . trim((string) data_get($payload, 'asin', $offer->external_product_id)) : null,
trim((string) ($offer->referral_url ?: data_get($payload, 'referral_url', ''))) !== '' ? 'Apri offerta: ' . trim((string) ($offer->referral_url ?: data_get($payload, 'referral_url', ''))): null,
], static fn(?string $line): bool => is_string($line) && trim($line) !== ''));
return implode(PHP_EOL, $lines);
}
private function resolveImageUrl(ProductOffer $offer): ?string
{
$payload = is_array($offer->meta['payload'] ?? null) ? $offer->meta['payload'] : [];
$imageUrl = trim((string) data_get($payload, 'image_url', ''));
return $imageUrl !== '' && str_starts_with($imageUrl, 'http') ? $imageUrl : null;
}
private function formatMoney(mixed $amount, string $currency, string $label): ?string
{
if (! is_numeric($amount)) {
return null;
}
return $label . ': ' . number_format((float) $amount, 2, ',', '.') . ' ' . strtoupper(trim($currency) !== '' ? $currency : 'EUR');
}
}