feat(injector-protocols): full module — resource + PDF export via Browsershot
Implements the injector diagnostic protocol module per spec:
- Migration: injector_protocols + injector_protocol_rows with company_id
(multi-tenant), vehicle_id (not car_id — this CRM uses Vehicle),
master_id FK to users, snapshot fields (car_model/plate/vin/mileage/year/
injector_brand) captured at protocol time.
- Models with BelongsToTenant; auto-generate protocol_number as
PS-{tenantId}-{year}-{seq6}; auto-seed 8 empty rows on create.
- Permissions: injector_protocols.view + injector_protocols.conclude.
Default roles: owner/admin (both), manager (both), receptionist (view
only), mechanic (both). Test permission count updated 52→54.
- InjectorProtocolResource under Service nav group with 4 sections:
data auto+client (with client_id/vehicle_id lookups auto-filling
snapshot fields), reason checkboxes, 8-row repeater for measurements
(Repeater with position hidden; fixed 8, non-addable/deletable),
conclusion + comment + master signature.
- Table with columns, badge filters, PDF action.
- Blade PDF template: pixel-close to reference (graphite/gold/blue
brand tokens, striped rows, rotated 'ФОРСУНКИ' header).
- Route /app/injector-protocols/{id}/pdf with permission gate,
streams PDF via new InjectorProtocolPdfService (Browsershot).
- Dockerfile: install nodejs 22 + chromium + noto fonts + puppeteer-core
in /opt/browsershot; env vars for Browsershot binary paths.
- +71 RU/EN translations covering resource + PDF template.
All 306 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Tenant\InjectorProtocol;
|
||||
use Spatie\Browsershot\Browsershot;
|
||||
|
||||
class InjectorProtocolPdfService
|
||||
{
|
||||
public function render(InjectorProtocol $protocol): string
|
||||
{
|
||||
$html = view('pdf.injector-protocol', ['protocol' => $protocol->load('rows', 'master')])->render();
|
||||
|
||||
$shot = Browsershot::html($html)
|
||||
->format('A4')
|
||||
->margins(12, 14, 12, 14)
|
||||
->showBackground()
|
||||
->waitUntilNetworkIdle();
|
||||
|
||||
if ($node = env('BROWSERSHOT_NODE_BINARY')) {
|
||||
$shot->setNodeBinary($node);
|
||||
}
|
||||
if ($npm = env('BROWSERSHOT_NPM_BINARY')) {
|
||||
$shot->setNpmBinary($npm);
|
||||
}
|
||||
if ($modules = env('BROWSERSHOT_NODE_MODULE_PATH')) {
|
||||
$shot->setNodeModulePath($modules);
|
||||
}
|
||||
if ($chrome = env('BROWSERSHOT_CHROME_PATH')) {
|
||||
$shot->setChromePath($chrome);
|
||||
}
|
||||
|
||||
// Docker sandbox — chromium refuses to run as root without --no-sandbox
|
||||
$shot->noSandbox();
|
||||
|
||||
return $shot->pdf();
|
||||
}
|
||||
|
||||
public function filename(InjectorProtocol $protocol): string
|
||||
{
|
||||
$num = $protocol->protocol_number ?: ('protocol-' . $protocol->id);
|
||||
return $num . '.pdf';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user