forked from TFMM/silent-auction
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eff3707268 | |||
| 23f944b808 | |||
| 8b80887d91 | |||
| b900a5e34b |
@@ -43,3 +43,6 @@ NORTH_CHECKOUT_ID=
|
|||||||
NORTH_PROFILE_ID=
|
NORTH_PROFILE_ID=
|
||||||
NORTH_PRIVATE_API_KEY=
|
NORTH_PRIVATE_API_KEY=
|
||||||
|
|
||||||
|
AUTO_PRINT_ENABLED=false
|
||||||
|
PRINTER_EMAIL=
|
||||||
|
|
||||||
|
|||||||
@@ -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}}
|
{"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}}
|
||||||
@@ -9,4 +9,14 @@ use Filament\Resources\Pages\CreateRecord;
|
|||||||
class CreateCheckout extends CreateRecord
|
class CreateCheckout extends CreateRecord
|
||||||
{
|
{
|
||||||
protected static string $resource = CheckoutResource::class;
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,6 +197,14 @@ class NorthCheckoutController extends Controller
|
|||||||
GROUP BY winning_bids.winning_bidder_num
|
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', [
|
return view('checkout_complete', [
|
||||||
'checkout_result' => $checkout_id,
|
'checkout_result' => $checkout_id,
|
||||||
'checkout_list_results' => $checkout_list_results,
|
'checkout_list_results' => $checkout_list_results,
|
||||||
|
|||||||
@@ -141,6 +141,15 @@ class PagesController extends Controller
|
|||||||
'cc_amount' => $cc_amount,
|
'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', [
|
return view('checkout_complete', [
|
||||||
'checkout_result' => $checkout_result,
|
'checkout_result' => $checkout_result,
|
||||||
'checkout_list_results' => $checkout_list_results,
|
'checkout_list_results' => $checkout_list_results,
|
||||||
@@ -351,7 +360,11 @@ class PagesController extends Controller
|
|||||||
|
|
||||||
public function winnersbyitem()
|
public function winnersbyitem()
|
||||||
{
|
{
|
||||||
$winnersbyitem_results = WinningBids::with(['items', 'bidders'])->get();
|
$winnersbyitem_results = WinningBids::with(['items', 'bidders'])
|
||||||
|
->join('items', 'winning_bids.winning_item_num', '=', 'items.iditems')
|
||||||
|
->orderByRaw('CAST(items.item_assigned_num AS UNSIGNED) ASC')
|
||||||
|
->select('winning_bids.*')
|
||||||
|
->get();
|
||||||
return view('winnersbyitem', ['winnersbyitem_results' => $winnersbyitem_results]);
|
return view('winnersbyitem', ['winnersbyitem_results' => $winnersbyitem_results]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Attachment;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class PickupSlipMail extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
protected $pdfOutput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct($pdfOutput)
|
||||||
|
{
|
||||||
|
$this->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<int, Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Attachment::fromData(fn () => $this->pdfOutput, 'pickup_slip.pdf')
|
||||||
|
->withMime('application/pdf'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
use Dompdf\Options;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class PrinterService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Print the pickup slip for a given Checkout model.
|
||||||
|
*
|
||||||
|
* @param \App\Models\Checkout $checkout
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function printForCheckout(\App\Models\Checkout $checkout)
|
||||||
|
{
|
||||||
|
$bidder_num = $checkout->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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,4 +48,9 @@ return [
|
|||||||
'private_api_key' => env('NORTH_PRIVATE_API_KEY'),
|
'private_api_key' => env('NORTH_PRIVATE_API_KEY'),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'printer' => [
|
||||||
|
'enabled' => env('AUTO_PRINT_ENABLED', false),
|
||||||
|
'email' => env('PRINTER_EMAIL'),
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Please find the attached item pickup slip.
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Tests\TestCase;
|
||||||
|
use App\Services\PrinterService;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
use Illuminate\Support\Facades\View;
|
||||||
|
|
||||||
|
class PrinterServiceTest extends TestCase
|
||||||
|
{
|
||||||
|
public function test_printForCheckout_calls_printPickupSlip_with_correct_data()
|
||||||
|
{
|
||||||
|
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 Checkout model
|
||||||
|
$checkout = \Mockery::mock(\App\Models\Checkout::class)->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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user