feat: Attach QR sticker PDF to Trello card on order creation
When a new order is created and a Trello card is made, now automatically generate the A6 QR sticker PDF and attach it to the card using Trello's attachment API. Include error handling and logging.
This commit is contained in:
@@ -3,15 +3,18 @@
|
|||||||
namespace App\Listeners;
|
namespace App\Listeners;
|
||||||
|
|
||||||
use App\Events\OrderCreated;
|
use App\Events\OrderCreated;
|
||||||
|
use App\Services\QrStickerService;
|
||||||
use App\Services\SlackNotifierService;
|
use App\Services\SlackNotifierService;
|
||||||
use App\Services\TrelloService;
|
use App\Services\TrelloService;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class NotifySlackOnOrderCreated
|
class NotifySlackOnOrderCreated
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
protected SlackNotifierService $slack,
|
protected SlackNotifierService $slack,
|
||||||
protected TrelloService $trello,
|
protected TrelloService $trello,
|
||||||
|
protected QrStickerService $qrSticker,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +65,35 @@ class NotifySlackOnOrderCreated
|
|||||||
$this->trello->setTextField($cardId, 'print_size', $printSize);
|
$this->trello->setTextField($cardId, 'print_size', $printSize);
|
||||||
|
|
||||||
Log::info('Trello card created for order', ['order_uuid' => $order->uuid, 'card_id' => $cardId]);
|
Log::info('Trello card created for order', ['order_uuid' => $order->uuid, 'card_id' => $cardId]);
|
||||||
|
|
||||||
|
// Generate QR sticker and attach to Trello card
|
||||||
|
try {
|
||||||
|
$stickerPaths = $this->qrSticker->generateSticker($order);
|
||||||
|
$pdfPath = storage_path('app/public/' . $stickerPaths['pdf_path']);
|
||||||
|
|
||||||
|
if (Storage::disk('public')->exists($stickerPaths['pdf_path'])) {
|
||||||
|
// Generate a public URL for the PDF
|
||||||
|
$stickerUrl = Storage::disk('public')->url($stickerPaths['pdf_path']);
|
||||||
|
|
||||||
|
// Attach to Trello card
|
||||||
|
$this->trello->attachFile(
|
||||||
|
$cardId,
|
||||||
|
"QR-Sticker-{$order->order_number}.pdf",
|
||||||
|
$stickerUrl
|
||||||
|
);
|
||||||
|
|
||||||
|
Log::info('QR sticker attached to Trello card', [
|
||||||
|
'order_uuid' => $order->uuid,
|
||||||
|
'card_id' => $cardId,
|
||||||
|
'pdf_path' => $stickerPaths['pdf_path'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to generate or attach QR sticker to Trello', [
|
||||||
|
'order_uuid' => $order->uuid,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class QrStickerService
|
|||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 3mm;
|
gap: 2mm;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.info-section {
|
.info-section {
|
||||||
@@ -144,7 +144,7 @@ class QrStickerService
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.qr-section {
|
.qr-section {
|
||||||
width: 50mm;
|
width: 100mm;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -164,29 +164,15 @@ class QrStickerService
|
|||||||
letter-spacing: 0.5pt;
|
letter-spacing: 0.5pt;
|
||||||
}
|
}
|
||||||
.order-number {
|
.order-number {
|
||||||
font-size: 9pt;
|
font-size: 16pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-top: 1mm;
|
margin-top: 1mm;
|
||||||
color: #222;
|
color: #222;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
.customer-info {
|
|
||||||
font-size: 8pt;
|
|
||||||
color: #555;
|
|
||||||
line-height: 1.3;
|
|
||||||
}
|
|
||||||
.customer-info .label {
|
|
||||||
font-size: 7pt;
|
|
||||||
color: #999;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.3pt;
|
|
||||||
}
|
|
||||||
.customer-info .name {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #222;
|
|
||||||
}
|
|
||||||
.details {
|
.details {
|
||||||
font-size: 7.5pt;
|
font-size: 10pt;
|
||||||
color: #666;
|
color: #666;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
@@ -197,20 +183,21 @@ class QrStickerService
|
|||||||
margin-bottom: 1mm;
|
margin-bottom: 1mm;
|
||||||
}
|
}
|
||||||
.detail-label {
|
.detail-label {
|
||||||
font-weight: 500;
|
|
||||||
color: #999;
|
color: #999;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 6.5pt;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.detail-value {
|
.detail-value {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
color: #222;
|
color: #222;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
.qr-code {
|
.qr-code {
|
||||||
width: 50mm;
|
width: 95mm;
|
||||||
height: 50mm;
|
height: 95mm;
|
||||||
}
|
}
|
||||||
.qr-code img {
|
.qr-code img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -233,14 +220,14 @@ class QrStickerService
|
|||||||
<span class="order-type">' . htmlspecialchars($orderType) . '</span>
|
<span class="order-type">' . htmlspecialchars($orderType) . '</span>
|
||||||
<div class="order-number">' . htmlspecialchars($order->order_number) . '</div>
|
<div class="order-number">' . htmlspecialchars($order->order_number) . '</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="customer-info">
|
|
||||||
<div class="label">Customer</div>
|
|
||||||
<div class="name">' . htmlspecialchars($customerSurname) . '</div>
|
|
||||||
</div>
|
|
||||||
<div class="details">
|
<div class="details">
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">Customer: </span>
|
||||||
|
<span class="detail-value">' . htmlspecialchars($customerSurname) . '</span>
|
||||||
|
</div>
|
||||||
<div class="detail-row">
|
<div class="detail-row">
|
||||||
<span class="detail-label">Design:</span>
|
<span class="detail-label">Design:</span>
|
||||||
<span class="detail-value" style="font-size: 6.5pt;">' . htmlspecialchars($this->truncate($designName, 12)) . '</span>
|
<span class="detail-value">' . htmlspecialchars($this->truncate($designName, 12)) . '</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-row">
|
<div class="detail-row">
|
||||||
<span class="detail-label">Date:</span>
|
<span class="detail-label">Date:</span>
|
||||||
@@ -251,14 +238,14 @@ class QrStickerService
|
|||||||
<span class="detail-value">' . htmlspecialchars($this->formatStatus($order->status)) . '</span>
|
<span class="detail-value">' . htmlspecialchars($this->formatStatus($order->status)) . '</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
|
||||||
Gen: ' . htmlspecialchars($order->created_at->format('Y-m-d H:i')) . '
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="qr-section">
|
|
||||||
<div class="qr-code">
|
<div class="qr-code">
|
||||||
<img src="' . $qrDataUri . '" alt="QR Code" />
|
<img src="' . $qrDataUri . '" alt="QR Code" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
Gen: ' . htmlspecialchars($order->created_at->format('Y-m-d H:i')) . '
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+7
-11
@@ -116,7 +116,7 @@ Route::match(['get', 'post'], '/test/sticker/{orderNumber}/regenerate', function
|
|||||||
$order = \App\Models\Order::where('order_number', $orderNumber)->first();
|
$order = \App\Models\Order::where('order_number', $orderNumber)->first();
|
||||||
|
|
||||||
if (!$order) {
|
if (!$order) {
|
||||||
return response()->json(['error' => 'Order not found'], 404);
|
return response('Order not found', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -131,18 +131,14 @@ Route::match(['get', 'post'], '/test/sticker/{orderNumber}/regenerate', function
|
|||||||
$service = new \App\Services\QrStickerService();
|
$service = new \App\Services\QrStickerService();
|
||||||
$paths = $service->generateSticker($order);
|
$paths = $service->generateSticker($order);
|
||||||
|
|
||||||
return response()->json([
|
// Return PDF inline for viewing
|
||||||
'success' => true,
|
$pdfPath = storage_path('app/public/' . $paths['pdf_path']);
|
||||||
'message' => 'Sticker PDF generated successfully',
|
return response()->file($pdfPath, [
|
||||||
'svg_path' => $paths['svg_path'],
|
'Content-Type' => 'application/pdf',
|
||||||
'pdf_path' => $paths['pdf_path'],
|
'Content-Disposition' => 'inline; filename="QR-' . $order->order_number . '.pdf"'
|
||||||
'view_url' => route('test.sticker', ['orderNumber' => $orderNumber])
|
|
||||||
]);
|
]);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return response()->json([
|
return response('Failed to generate sticker: ' . $e->getMessage(), 500);
|
||||||
'error' => 'Failed to generate sticker',
|
|
||||||
'message' => $e->getMessage()
|
|
||||||
], 500);
|
|
||||||
}
|
}
|
||||||
})->name('test.sticker.regenerate');
|
})->name('test.sticker.regenerate');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user