Email digital receipts, add promo settings, and apply tips at charge.
Deploy Ladill POS / deploy (push) Successful in 31s

Send real receipt emails from the customer display and sale page, store
branch promo content for the idle screen, and fold selected tips into totals.
This commit is contained in:
isaacclad
2026-07-15 16:10:20 +00:00
parent 468346b183
commit 600aedb59d
20 changed files with 675 additions and 19 deletions
+72
View File
@@ -0,0 +1,72 @@
<?php
namespace App\Services\Pos;
use App\Mail\DigitalReceiptMail;
use App\Models\PosSale;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use RuntimeException;
class ReceiptEmailService
{
/**
* Email a digital receipt for a sale. Updates customer_email when empty.
*
* @return array{ok: bool, message: string}
*/
public function send(PosSale $sale, string $email): array
{
$email = strtolower(trim($email));
if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new RuntimeException('A valid email address is required.');
}
$sale->loadMissing(['lines', 'location']);
if (! $sale->customer_email) {
$sale->forceFill(['customer_email' => $email])->save();
}
try {
Mail::to($email)->send(new DigitalReceiptMail($sale));
} catch (\Throwable $e) {
Log::warning('pos.receipt_email_failed', [
'sale_id' => $sale->id,
'email' => $email,
'error' => $e->getMessage(),
]);
throw new RuntimeException('Could not send the receipt email. Please try again.');
}
return [
'ok' => true,
'message' => 'Receipt sent to '.$email,
];
}
/**
* Best-effort send after a paid sale when an email is already on the sale.
*/
public function sendIfPresent(PosSale $sale): bool
{
$email = trim((string) ($sale->customer_email ?? ''));
if ($email === '') {
return false;
}
try {
$this->send($sale, $email);
return true;
} catch (\Throwable $e) {
Log::info('pos.receipt_email_skipped', [
'sale_id' => $sale->id,
'error' => $e->getMessage(),
]);
return false;
}
}
}