3da1f5412a
Shop password reset:
- Configured 'shop_customers' password broker on the existing
password_reset_tokens table
- ShopCustomer::sendPasswordResetNotification overrides Laravel default to
send a ShopPasswordResetMail with a tenant-subdomain reset URL
- Routes /shop/password/forgot, /shop/password/email, /shop/password/reset/{token}
+ ShopAuthController showForgotPassword/sendResetLink/showResetPassword/
resetPassword. Forgot view stays generic ("if it exists, we sent…") to avoid
email enumeration. Login view links to "Am uitat parola".
Order confirmation email:
- ShopOrderConfirmationMail + nicely formatted HTML email template
- ShopOrderNotifier::placed now also emails customer_email (best-effort,
warning-only logged on failure) alongside existing Telegram + staff push
Multiple images per Part:
- Part media collection switched from singleFile to multiple (max 8 in form)
- imageUrls() helper for galleries; imageUrl() still returns first for cards
- PartResource form: reorderable multi-upload
- Shop part detail: vertical thumbnails switch the main image via vanilla JS
ShopCustomerResource (tenant Filament, "Magazin" nav group):
- List with name/phone/email/client_id/orders_count/last_login_at
- Edit (no password field exposed)
- "Trimite reset parolă" action uses the new broker
- OrdersRelationManager shows the customer's orders read-only
Tests (7 new):
- forgot sends mail; forgot doesn't disclose unknown email; reset with valid
token changes password; bad token rejected; order email when customer_email
set; email skipped without it; Part has imageUrls() collection
Full suite: 130 passed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
71 lines
2.8 KiB
PHP
71 lines
2.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Notifications;
|
|
|
|
use App\Models\Central\Company;
|
|
use App\Models\Tenant\Client;
|
|
use App\Models\Tenant\OnlineOrder;
|
|
use App\Models\Tenant\User;
|
|
|
|
/**
|
|
* Notifies staff of a new online order (Web Push) and confirms to the customer
|
|
* via Telegram if they have a linked chat. Best-effort — never throws.
|
|
*/
|
|
class ShopOrderNotifier
|
|
{
|
|
public function __construct(
|
|
private WebPushService $push,
|
|
private TelegramService $telegram,
|
|
) {
|
|
}
|
|
|
|
public function placed(OnlineOrder $order): void
|
|
{
|
|
$company = Company::withoutGlobalScopes()->find($order->company_id);
|
|
if (! $company) return;
|
|
|
|
// ── Staff: Web Push to active users of this tenant ──
|
|
$title = 'Comandă nouă #' . $order->number;
|
|
$body = $order->customer_name . ' · ' . number_format((float) $order->total, 2) . ' '
|
|
. ($company->settings['currency'] ?? 'MDL');
|
|
$url = '/app/resources/online-orders/' . $order->id . '/edit';
|
|
|
|
$userIds = User::where('status', 'active')->pluck('id');
|
|
foreach ($userIds as $uid) {
|
|
$this->push->sendToUser((int) $uid, $title, $body, $url, 'shop-order-' . $order->id);
|
|
}
|
|
|
|
// ── Customer: Telegram if their phone is linked ──
|
|
$needle = Client::normalizePhone($order->customer_phone);
|
|
if ($needle) {
|
|
$client = Client::whereNotNull('telegram_chat_id')
|
|
->whereRaw(
|
|
"REPLACE(REPLACE(REPLACE(REPLACE(phone, ' ', ''), '-', ''), '(', ''), ')', '') LIKE ?",
|
|
['%' . substr($needle, -9) . '%']
|
|
)
|
|
->first();
|
|
|
|
if ($client && $client->telegram_chat_id) {
|
|
$brand = htmlspecialchars($company->display_name ?? $company->name);
|
|
$text = "🛒 <b>Comanda #{$order->number} primită</b>\n"
|
|
. "Total: <b>" . number_format((float) $order->total, 2) . " "
|
|
. ($company->settings['currency'] ?? 'MDL') . "</b>\n\n"
|
|
. "Urmărește statusul: " . $order->trackingUrl() . "\n\n{$brand}";
|
|
$this->telegram->sendMessage($company, (string) $client->telegram_chat_id, $text);
|
|
}
|
|
}
|
|
|
|
// ── Customer: email confirmation when address given ──
|
|
if ($order->customer_email) {
|
|
try {
|
|
\Illuminate\Support\Facades\Mail::to($order->customer_email)
|
|
->send(new \App\Mail\ShopOrderConfirmationMail($order, $company));
|
|
} catch (\Throwable $e) {
|
|
\Illuminate\Support\Facades\Log::warning('shop order confirmation mail failed', [
|
|
'order' => $order->id, 'err' => $e->getMessage(),
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|