feat(124): sms templates CRUD + order picker
- Nowa tabela sms_templates (name + body + is_active) + minimalny CRUD.
- /settings/sms-templates: lista + formularz z paleta zmiennych (pill chips).
- Wydzielono Sms\SmsVariableResolver ze wspolna logika placeholderow;
Email\VariableResolver staje sie cienka fasada — EmailSendingService bez zmian.
- Dropdown "Wybierz szablon" w zakladce SMS na /orders/{id} z fetch
GET /orders/{id}/sms/template + OrderProAlerts.confirm przy nadpisaniu.
- Stopka SMSPLANET dalej doklejana wylacznie przez SmsConversationService
(Phase 122 contract preserved).
- Sidebar Ustawien: nowy link "Szablony SMS".
Migration: 20260512_000112_create_sms_templates.sql (CREATE TABLE).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,11 @@ use App\Modules\Automation\AutomationService;
|
||||
use App\Modules\Settings\ShopproApiClient;
|
||||
use App\Modules\Settings\ShopproIntegrationsRepository;
|
||||
use App\Modules\Shipments\ShipmentPackageRepository;
|
||||
use App\Modules\Settings\CompanySettingsRepository;
|
||||
use App\Modules\Sms\SmsConversationService;
|
||||
use App\Modules\Sms\SmsMessageRepository;
|
||||
use App\Modules\Sms\SmsTemplateRepository;
|
||||
use App\Modules\Sms\SmsVariableResolver;
|
||||
use Throwable;
|
||||
|
||||
final class OrdersController
|
||||
@@ -46,7 +49,10 @@ final class OrdersController
|
||||
private readonly ?InvoiceRepository $invoiceRepo = null,
|
||||
private readonly ?InvoiceConfigRepository $invoiceConfigRepo = null,
|
||||
private readonly ?SmsMessageRepository $smsMessages = null,
|
||||
private readonly ?SmsConversationService $smsConversation = null
|
||||
private readonly ?SmsConversationService $smsConversation = null,
|
||||
private readonly ?SmsTemplateRepository $smsTemplates = null,
|
||||
private readonly ?SmsVariableResolver $smsVariableResolver = null,
|
||||
private readonly ?CompanySettingsRepository $companySettingsRepo = null
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -255,6 +261,7 @@ final class OrdersController
|
||||
$smsMessages = $this->smsMessages !== null ? $this->smsMessages->findByOrderId($orderId) : [];
|
||||
$smsPhone = $this->resolveSmsPhone($order, $addresses);
|
||||
$smsDefaultFooterConfigured = $this->smsConversation !== null && $this->smsConversation->hasDefaultFooter();
|
||||
$smsTemplates = $this->smsTemplates !== null ? $this->smsTemplates->listActive() : [];
|
||||
|
||||
$html = $this->template->render('orders/show', [
|
||||
'title' => $this->translator->get('orders.details.title') . ' #' . $orderId,
|
||||
@@ -290,6 +297,7 @@ final class OrdersController
|
||||
'smsMessages' => $smsMessages,
|
||||
'smsPhone' => $smsPhone,
|
||||
'smsDefaultFooterConfigured' => $smsDefaultFooterConfigured,
|
||||
'smsTemplates' => $smsTemplates,
|
||||
], 'layouts/app');
|
||||
|
||||
return Response::html($html);
|
||||
@@ -331,6 +339,44 @@ final class OrdersController
|
||||
return Response::redirect($redirectTo);
|
||||
}
|
||||
|
||||
public function smsTemplate(Request $request): Response
|
||||
{
|
||||
$orderId = max(0, (int) $request->input('id', 0));
|
||||
$templateId = max(0, (int) $request->input('template_id', 0));
|
||||
|
||||
if ($orderId <= 0 || $templateId <= 0) {
|
||||
return Response::json(['ok' => false, 'error' => 'Nieprawidlowe parametry.'], 400);
|
||||
}
|
||||
if ($this->smsTemplates === null || $this->smsVariableResolver === null) {
|
||||
return Response::json(['ok' => false, 'error' => 'Modul szablonow SMS nie jest dostepny.'], 500);
|
||||
}
|
||||
|
||||
$template = $this->smsTemplates->findById($templateId);
|
||||
if ($template === null || (int) ($template['is_active'] ?? 0) !== 1) {
|
||||
return Response::json(['ok' => false, 'error' => 'Szablon nie istnieje albo jest nieaktywny.'], 404);
|
||||
}
|
||||
|
||||
$details = $this->orders->findDetails($orderId);
|
||||
if ($details === null) {
|
||||
return Response::json(['ok' => false, 'error' => 'Zamowienie nie znalezione.'], 404);
|
||||
}
|
||||
|
||||
$order = is_array($details['order'] ?? null) ? $details['order'] : [];
|
||||
$addresses = is_array($details['addresses'] ?? null) ? $details['addresses'] : [];
|
||||
$companySettings = $this->companySettingsRepo !== null
|
||||
? $this->companySettingsRepo->getSettings()
|
||||
: [];
|
||||
|
||||
$variableMap = $this->smsVariableResolver->buildVariableMap($order, $addresses, $companySettings);
|
||||
$resolvedBody = $this->smsVariableResolver->resolve((string) ($template['body'] ?? ''), $variableMap);
|
||||
|
||||
return Response::json([
|
||||
'ok' => true,
|
||||
'body' => $resolvedBody,
|
||||
'name' => (string) ($template['name'] ?? ''),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sklada informacje o historii zwrotow klienta biezacego zamowienia.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user