Email digital receipts, add promo settings, and apply tips at charge.
Deploy Ladill POS / deploy (push) Successful in 31s
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:
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Http\Middleware\EnsurePlatformSession;
|
||||
use App\Mail\DigitalReceiptMail;
|
||||
use App\Models\PosCustomerDisplay;
|
||||
use App\Models\PosLocation;
|
||||
use App\Models\PosSale;
|
||||
use App\Models\User;
|
||||
use App\Services\Pos\CustomerDisplayService;
|
||||
use App\Services\Pos\PosSaleService;
|
||||
use App\Services\Pos\ReceiptEmailService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ReceiptTipPromoTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private function owner(): User
|
||||
{
|
||||
return User::create([
|
||||
'public_id' => 'owner-rtp',
|
||||
'name' => 'Owner',
|
||||
'email' => 'owner-rtp@example.com',
|
||||
]);
|
||||
}
|
||||
|
||||
private function location(User $owner): PosLocation
|
||||
{
|
||||
return PosLocation::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'name' => 'Front counter',
|
||||
'currency' => 'GHS',
|
||||
'is_default' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->withoutMiddleware(EnsurePlatformSession::class);
|
||||
$this->withoutVite();
|
||||
}
|
||||
|
||||
public function test_tip_is_applied_to_sale_total_on_create(): void
|
||||
{
|
||||
$owner = $this->owner();
|
||||
$this->location($owner);
|
||||
|
||||
$sale = app(PosSaleService::class)->createSale($owner, [
|
||||
['name' => 'Meal', 'unit_price_minor' => 10000, 'quantity' => 1],
|
||||
], [
|
||||
'tip_minor' => 1500,
|
||||
'currency' => 'GHS',
|
||||
]);
|
||||
|
||||
$this->assertSame(10000, $sale->subtotal_minor);
|
||||
$this->assertSame(1500, $sale->tip_minor);
|
||||
$this->assertSame(11500, $sale->total_minor);
|
||||
}
|
||||
|
||||
public function test_digital_receipt_email_is_sent(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$owner = $this->owner();
|
||||
$location = $this->location($owner);
|
||||
$sale = PosSale::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'location_id' => $location->id,
|
||||
'reference' => 'POS-TESTRECEIPT1',
|
||||
'status' => PosSale::STATUS_PAID,
|
||||
'payment_method' => PosSale::METHOD_CASH,
|
||||
'subtotal_minor' => 500,
|
||||
'total_minor' => 500,
|
||||
'currency' => 'GHS',
|
||||
'paid_at' => now(),
|
||||
]);
|
||||
|
||||
$result = app(ReceiptEmailService::class)->send($sale, 'guest@example.com');
|
||||
|
||||
$this->assertTrue($result['ok']);
|
||||
Mail::assertSent(DigitalReceiptMail::class, function (DigitalReceiptMail $mail) use ($sale) {
|
||||
return $mail->sale->is($sale)
|
||||
&& $mail->hasTo('guest@example.com');
|
||||
});
|
||||
$this->assertSame('guest@example.com', $sale->fresh()->customer_email);
|
||||
}
|
||||
|
||||
public function test_customer_display_receipt_email_action_sends_mail(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$owner = $this->owner();
|
||||
$location = $this->location($owner);
|
||||
$sale = PosSale::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'location_id' => $location->id,
|
||||
'reference' => 'POS-TESTRECEIPT2',
|
||||
'status' => PosSale::STATUS_PAID,
|
||||
'payment_method' => PosSale::METHOD_CASH,
|
||||
'subtotal_minor' => 800,
|
||||
'total_minor' => 800,
|
||||
'currency' => 'GHS',
|
||||
'paid_at' => now(),
|
||||
]);
|
||||
|
||||
$display = app(CustomerDisplayService::class)->pushReceipt($location, $sale);
|
||||
|
||||
$this->postJson(route('pos.customer-display.action', ['token' => $display->token]), [
|
||||
'type' => 'receipt_email',
|
||||
'email' => 'buyer@example.com',
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('email_sent', true);
|
||||
|
||||
Mail::assertSent(DigitalReceiptMail::class);
|
||||
}
|
||||
|
||||
public function test_settings_save_customer_promo_content(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$owner = $this->owner();
|
||||
$this->location($owner);
|
||||
|
||||
$this->actingAs($owner)
|
||||
->put(route('pos.settings.update'), [
|
||||
'name' => 'Front counter',
|
||||
'currency' => 'GHS',
|
||||
'service_style' => 'retail',
|
||||
'receipt_footer' => '',
|
||||
'receipt_header' => 'Demo Shop',
|
||||
'printer_paper_mm' => 80,
|
||||
'customer_promo_headline' => 'Happy hour',
|
||||
'customer_promo_body' => 'Buy one get one free until 6pm.',
|
||||
'customer_promo_image' => UploadedFile::fake()->image('promo.jpg'),
|
||||
'gateway_provider' => '',
|
||||
])
|
||||
->assertRedirect();
|
||||
|
||||
$location = PosLocation::query()->first();
|
||||
$this->assertSame('Happy hour', $location->customer_promo_headline);
|
||||
$this->assertSame('Buy one get one free until 6pm.', $location->customer_promo_body);
|
||||
$this->assertNotNull($location->customer_promo_image_path);
|
||||
|
||||
$promo = $location->customerPromo();
|
||||
$this->assertSame('Happy hour', $promo['headline']);
|
||||
$this->assertNotNull($promo['image_url']);
|
||||
|
||||
$display = app(CustomerDisplayService::class)->ensureForLocation($location);
|
||||
$state = app(CustomerDisplayService::class)->publicState($display);
|
||||
$this->assertSame('Happy hour', $state['promo']['headline']);
|
||||
}
|
||||
|
||||
public function test_operator_can_email_receipt_from_sale_page(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$owner = $this->owner();
|
||||
$location = $this->location($owner);
|
||||
$sale = PosSale::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'location_id' => $location->id,
|
||||
'reference' => 'POS-TESTRECEIPT3',
|
||||
'status' => PosSale::STATUS_PAID,
|
||||
'payment_method' => PosSale::METHOD_CASH,
|
||||
'subtotal_minor' => 300,
|
||||
'total_minor' => 300,
|
||||
'currency' => 'GHS',
|
||||
'paid_at' => now(),
|
||||
]);
|
||||
|
||||
$this->actingAs($owner)
|
||||
->post(route('pos.sales.email-receipt', $sale), ['email' => 'print@example.com'])
|
||||
->assertRedirect();
|
||||
|
||||
Mail::assertSent(DigitalReceiptMail::class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user