From eff37072680ec8015c3d2a877b9a98cfd370a968 Mon Sep 17 00:00:00 2001 From: Russ Long Date: Tue, 12 May 2026 15:44:40 -0400 Subject: [PATCH] feat: add automatic item pickup slip printing via HP ePrint --- .env.example | 3 + .phpunit.result.cache | 2 +- .../CheckoutResource/Pages/CreateCheckout.php | 10 ++ .../Controllers/NorthCheckoutController.php | 8 ++ app/Http/Controllers/PagesController.php | 9 ++ app/Mail/PickupSlipMail.php | 58 +++++++++ app/Services/PrinterService.php | 86 ++++++++++++++ config/services.php | 5 + resources/views/emails/pickup_slip.blade.php | 1 + tests/Unit/PrinterServiceTest.php | 110 ++++++++++++++++++ 10 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 app/Mail/PickupSlipMail.php create mode 100644 app/Services/PrinterService.php create mode 100644 resources/views/emails/pickup_slip.blade.php create mode 100644 tests/Unit/PrinterServiceTest.php diff --git a/.env.example b/.env.example index 07e08d4..e740a33 100644 --- a/.env.example +++ b/.env.example @@ -43,3 +43,6 @@ NORTH_CHECKOUT_ID= NORTH_PROFILE_ID= NORTH_PRIVATE_API_KEY= +AUTO_PRINT_ENABLED=false +PRINTER_EMAIL= + diff --git a/.phpunit.result.cache b/.phpunit.result.cache index da9cd8d..2e8930d 100644 --- a/.phpunit.result.cache +++ b/.phpunit.result.cache @@ -1 +1 @@ -{"version":2,"defects":{"Tests\\Feature\\MyWinningsTest::test_mywinnings_form_is_accessible":8,"Tests\\Feature\\MyWinningsTest::test_mywinnings_results_show_correct_data":8,"Tests\\Feature\\MyWinningsTest::test_mywinnings_invalid_bidder_shows_error":8},"times":{"Tests\\Unit\\PhoneFormattingTest::it_formats_a_10_digit_phone_number":0.018,"Tests\\Unit\\PhoneFormattingTest::it_strips_non_numeric_characters_before_formatting":0,"Tests\\Unit\\PhoneFormattingTest::it_returns_original_value_if_not_10_digits":0,"Tests\\Unit\\PhoneFormattingTest::bidder_model_accessor_formats_phone_number":0.003}} \ No newline at end of file +{"version":2,"defects":{"Tests\\Feature\\MyWinningsTest::test_mywinnings_form_is_accessible":8,"Tests\\Feature\\MyWinningsTest::test_mywinnings_results_show_correct_data":8,"Tests\\Feature\\MyWinningsTest::test_mywinnings_invalid_bidder_shows_error":8,"Tests\\Unit\\PrinterServiceTest::test_printPickupSlip_sends_email_when_enabled":7},"times":{"Tests\\Unit\\PhoneFormattingTest::it_formats_a_10_digit_phone_number":0.018,"Tests\\Unit\\PhoneFormattingTest::it_strips_non_numeric_characters_before_formatting":0,"Tests\\Unit\\PhoneFormattingTest::it_returns_original_value_if_not_10_digits":0,"Tests\\Unit\\PhoneFormattingTest::bidder_model_accessor_formats_phone_number":0.003,"Tests\\Unit\\PrinterServiceTest::test_printPickupSlip_sends_email_when_enabled":0.019,"Tests\\Unit\\PrinterServiceTest::test_printPickupSlip_does_not_send_email_when_disabled":0.001,"Tests\\Unit\\PrinterServiceTest::test_printForCheckout_calls_printPickupSlip_with_correct_data":0.09}} \ No newline at end of file diff --git a/app/Filament/Resources/CheckoutResource/Pages/CreateCheckout.php b/app/Filament/Resources/CheckoutResource/Pages/CreateCheckout.php index 913bf24..82c5cd4 100644 --- a/app/Filament/Resources/CheckoutResource/Pages/CreateCheckout.php +++ b/app/Filament/Resources/CheckoutResource/Pages/CreateCheckout.php @@ -9,4 +9,14 @@ use Filament\Resources\Pages\CreateRecord; class CreateCheckout extends CreateRecord { protected static string $resource = CheckoutResource::class; + + protected function afterCreate(): void + { + try { + $printerService = app(\App\Services\PrinterService::class); + $printerService->printForCheckout($this->record); + } catch (\Exception $e) { + \Illuminate\Support\Facades\Log::error('Auto-print failed from Filament: ' . $e->getMessage()); + } + } } diff --git a/app/Http/Controllers/NorthCheckoutController.php b/app/Http/Controllers/NorthCheckoutController.php index 71e83a1..95e22ef 100644 --- a/app/Http/Controllers/NorthCheckoutController.php +++ b/app/Http/Controllers/NorthCheckoutController.php @@ -197,6 +197,14 @@ class NorthCheckoutController extends Controller GROUP BY winning_bids.winning_bidder_num "); + // Automatically print item pickup slips + try { + $printerService = app(\App\Services\PrinterService::class); + $printerService->printForCheckout(\App\Models\Checkout::find($checkout_id)); + } catch (\Exception $e) { + \Illuminate\Support\Facades\Log::error('Auto-print failed: ' . $e->getMessage()); + } + return view('checkout_complete', [ 'checkout_result' => $checkout_id, 'checkout_list_results' => $checkout_list_results, diff --git a/app/Http/Controllers/PagesController.php b/app/Http/Controllers/PagesController.php index 197c7e4..e9627ac 100644 --- a/app/Http/Controllers/PagesController.php +++ b/app/Http/Controllers/PagesController.php @@ -141,6 +141,15 @@ class PagesController extends Controller 'cc_amount' => $cc_amount, ] ); + + // Automatically print item pickup slips + try { + $printerService = app(\App\Services\PrinterService::class); + $printerService->printForCheckout(\App\Models\Checkout::find($checkout_result)); + } catch (\Exception $e) { + \Illuminate\Support\Facades\Log::error('Auto-print failed: ' . $e->getMessage()); + } + return view('checkout_complete', [ 'checkout_result' => $checkout_result, 'checkout_list_results' => $checkout_list_results, diff --git a/app/Mail/PickupSlipMail.php b/app/Mail/PickupSlipMail.php new file mode 100644 index 0000000..2c33e30 --- /dev/null +++ b/app/Mail/PickupSlipMail.php @@ -0,0 +1,58 @@ +pdfOutput = $pdfOutput; + } + + /** + * Get the message envelope. + */ + public function envelope(): Envelope + { + return new Envelope( + subject: 'Item Pickup Slip', + ); + } + + /** + * Get the message content definition. + */ + public function content(): Content + { + return new Content( + view: 'emails.pickup_slip', + ); + } + + /** + * Get the attachments for the message. + * + * @return array + */ + public function attachments(): array + { + return [ + Attachment::fromData(fn () => $this->pdfOutput, 'pickup_slip.pdf') + ->withMime('application/pdf'), + ]; + } +} diff --git a/app/Services/PrinterService.php b/app/Services/PrinterService.php new file mode 100644 index 0000000..d1650b1 --- /dev/null +++ b/app/Services/PrinterService.php @@ -0,0 +1,86 @@ +bidder_num; + + $checkout_list_results = \Illuminate\Support\Facades\DB::select("SELECT + *, items.item_assigned_num, items.item_desc + FROM winning_bids + INNER JOIN items AS items + ON winning_bids.winning_item_num=items.iditems + WHERE winning_bidder_num = $bidder_num + "); + + $checkout_info_results = \Illuminate\Support\Facades\DB::select("SELECT + winning_bids.*, + bidders.*, + sum(winning_cost) AS total_cost + FROM winning_bids + INNER JOIN bidders AS bidders + ON winning_bids.winning_bidder_num=bidders.idbidders + WHERE winning_bidder_num = $bidder_num + GROUP BY winning_bids.winning_bidder_num + "); + + $this->printPickupSlip([ + 'checkout_final_results' => $checkout, + 'checkout_list_results' => $checkout_list_results, + 'checkout_info_results' => $checkout_info_results + ]); + } + + /** + * Print the pickup slip by sending it to the HP ePrint email address. + * + * @param array $checkoutData + * @return void + */ + public function printPickupSlip($checkoutData) + { + if (!config('services.printer.enabled')) { + Log::info('Auto-print is disabled.'); + return; + } + + $printerEmail = config('services.printer.email'); + if (empty($printerEmail)) { + Log::error('Printer email is not configured.'); + return; + } + + try { + $options = new Options(); + $options->set('isHtml5ParserEnabled', true); + $options->set('isRemoteEnabled', true); + $dompdf = new Dompdf($options); + + $html = view('receiptpdf', $checkoutData)->render(); + $dompdf->loadHtml($html); + $dompdf->setPaper('letter', 'portrait'); + $dompdf->render(); + $pdfOutput = $dompdf->output(); + + Mail::to($printerEmail)->send(new \App\Mail\PickupSlipMail($pdfOutput)); + + Log::info('Pickup slip sent to printer: ' . $printerEmail); + } catch (\Exception $e) { + Log::error('Failed to print pickup slip: ' . $e->getMessage()); + } + } +} diff --git a/config/services.php b/config/services.php index 230389e..b948dc0 100644 --- a/config/services.php +++ b/config/services.php @@ -48,4 +48,9 @@ return [ 'private_api_key' => env('NORTH_PRIVATE_API_KEY'), ], + 'printer' => [ + 'enabled' => env('AUTO_PRINT_ENABLED', false), + 'email' => env('PRINTER_EMAIL'), + ], + ]; diff --git a/resources/views/emails/pickup_slip.blade.php b/resources/views/emails/pickup_slip.blade.php new file mode 100644 index 0000000..64384d3 --- /dev/null +++ b/resources/views/emails/pickup_slip.blade.php @@ -0,0 +1 @@ +Please find the attached item pickup slip. diff --git a/tests/Unit/PrinterServiceTest.php b/tests/Unit/PrinterServiceTest.php new file mode 100644 index 0000000..9acc371 --- /dev/null +++ b/tests/Unit/PrinterServiceTest.php @@ -0,0 +1,110 @@ +makePartial(); + $checkout->bidder_num = 1; + $checkout->checkout_id = 1; + $checkout->payment_method = 1; + $checkout->check_number = null; + $checkout->cc_transaction = null; + + // Mock DB calls + \Illuminate\Support\Facades\DB::shouldReceive('select') + ->twice() + ->andReturn([ + (object)['item_assigned_num' => 'A1', 'item_desc' => 'Test', 'winning_cost' => 50] + ], [ + (object)[ + 'bidder_assigned_number' => '123', + 'total_cost' => '50', + 'bidder_fname' => 'John', + 'bidder_lname' => 'Doe', + 'bidder_phone' => '1234567890', + 'bidder_addr' => '123 St', + 'bidder_city' => 'Troy', + 'bidder_state' => 'MI', + 'bidder_zip' => '48083' + ] + ]); + + $service = new PrinterService(); + $service->printForCheckout($checkout); + + Mail::assertSent(\App\Mail\PickupSlipMail::class); + } + + public function test_printPickupSlip_sends_email_when_enabled() + { + Mail::fake(); + Config::set('services.printer.enabled', true); + Config::set('services.printer.email', 'printer@example.com'); + Config::set('mail.from.address', 'hello@example.com'); + Config::set('mail.from.name', 'Example'); + + // Mock data matching what receiptpdf expects + $checkoutData = [ + 'checkout_final_results' => (object)[ + 'payment_method' => 1, + 'check_number' => null, + 'cc_transaction' => null, + 'checkout_id' => 1 + ], + 'checkout_list_results' => [ + (object)[ + 'item_assigned_num' => 'A1', + 'item_desc' => 'Test Item', + 'winning_cost' => '50' + ] + ], + 'checkout_info_results' => [ + (object)[ + 'bidder_assigned_number' => '123', + 'total_cost' => '50', + 'bidder_fname' => 'John', + 'bidder_lname' => 'Doe', + 'bidder_phone' => '1234567890', + 'bidder_addr' => '123 St', + 'bidder_city' => 'Troy', + 'bidder_state' => 'MI', + 'bidder_zip' => '48083' + ] + ] + ]; + + $service = new PrinterService(); + $service->printPickupSlip($checkoutData); + + Mail::assertSent(\App\Mail\PickupSlipMail::class, function ($mail) { + return $mail->hasTo('printer@example.com'); + }); + } + + public function test_printPickupSlip_does_not_send_email_when_disabled() + { + Mail::fake(); + Config::set('services.printer.enabled', false); + + $service = new PrinterService(); + $service->printPickupSlip([]); + + Mail::assertNothingSent(); + } +}