Add customer contact inquiry system, automated receipt emails, admin communication inbox, and customer profile management
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Mail\ContactInquiryConfirmationMail;
|
||||
use App\Mail\ContactInquiryReceivedMail;
|
||||
use App\Mail\ContactInquiryReplyMail;
|
||||
use App\Models\Communication;
|
||||
use App\Models\Order;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CustomerCommunicationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private User $admin;
|
||||
|
||||
private User $customer;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->admin = User::factory()->create([
|
||||
'name' => 'Admin Beheerder',
|
||||
'email' => 'admin@jouwdriedee.nl',
|
||||
'is_admin' => true,
|
||||
]);
|
||||
|
||||
$this->customer = User::factory()->create([
|
||||
'name' => 'Kees de Vries',
|
||||
'email' => 'kees@example.com',
|
||||
'is_admin' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_contact_page_loads_successfully(): void
|
||||
{
|
||||
$response = $this->get(route('contact.index'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertSee('Stel een vraag');
|
||||
$response->assertSee('Directe Contactgegevens');
|
||||
}
|
||||
|
||||
public function test_customer_can_submit_question_and_both_emails_are_dispatched(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$response = $this->post(route('contact.store'), [
|
||||
'name' => 'Lisa Jansen',
|
||||
'email' => 'lisa@example.com',
|
||||
'phone' => '06-87654321',
|
||||
'subject' => 'Vraag over levertijd van Pokémon model',
|
||||
'message' => 'Goedemiddag, hoe lang duurt het printen van het Charizard model in PETG?',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('contact.index'));
|
||||
$response->assertSessionHas('success');
|
||||
|
||||
// Check database
|
||||
$this->assertDatabaseHas('communications', [
|
||||
'name' => 'Lisa Jansen',
|
||||
'email' => 'lisa@example.com',
|
||||
'subject' => 'Vraag over levertijd van Pokémon model',
|
||||
'status' => 'new',
|
||||
]);
|
||||
|
||||
$communication = Communication::where('email', 'lisa@example.com')->first();
|
||||
$this->assertNotNull($communication);
|
||||
|
||||
// 1. Mail to webshop management (info@jouwdrieedee.nl / info@jouwdriedee.nl)
|
||||
Mail::assertSent(ContactInquiryReceivedMail::class, function ($mail) use ($communication) {
|
||||
return $mail->communication->id === $communication->id;
|
||||
});
|
||||
|
||||
// 2. Afschrift to customer from (noreply@jouwdriedee.nl)
|
||||
Mail::assertSent(ContactInquiryConfirmationMail::class, function ($mail) use ($communication) {
|
||||
$hasCorrectRecipient = $mail->hasTo('lisa@example.com');
|
||||
$hasCorrectFrom = $mail->hasFrom('noreply@jouwdriedee.nl');
|
||||
|
||||
return $hasCorrectRecipient && $hasCorrectFrom && $mail->communication->id === $communication->id;
|
||||
});
|
||||
}
|
||||
|
||||
public function test_logged_in_customer_inquiry_is_linked_and_visible_in_account(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$response = $this->actingAs($this->customer)->post(route('contact.store'), [
|
||||
'name' => $this->customer->name,
|
||||
'email' => $this->customer->email,
|
||||
'subject' => 'Speciale kleur vraag',
|
||||
'message' => 'Kan het model ook in glow-in-the-dark filament worden geprint?',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('contact.index'));
|
||||
|
||||
$this->assertDatabaseHas('communications', [
|
||||
'user_id' => $this->customer->id,
|
||||
'email' => 'kees@example.com',
|
||||
'subject' => 'Speciale kleur vraag',
|
||||
]);
|
||||
|
||||
// Customer dashboard in /mijn-account shows their question
|
||||
$accountResponse = $this->actingAs($this->customer)->get(route('account.index'));
|
||||
$accountResponse->assertStatus(200);
|
||||
$accountResponse->assertSee('Speciale kleur vraag');
|
||||
$accountResponse->assertSee('Mijn Vragen');
|
||||
}
|
||||
|
||||
public function test_admin_can_view_communications_in_dedicated_admin_section(): void
|
||||
{
|
||||
$comm = Communication::create([
|
||||
'name' => 'Peter Bakker',
|
||||
'email' => 'peter@example.com',
|
||||
'subject' => 'Garantie op 3D prints',
|
||||
'message' => 'Wat voor garantie zit er op technische 3D prints?',
|
||||
'status' => 'new',
|
||||
]);
|
||||
|
||||
// Admin list
|
||||
$indexResponse = $this->actingAs($this->admin)->get(route('admin.communications.index'));
|
||||
$indexResponse->assertStatus(200);
|
||||
$indexResponse->assertSee('Communicatie');
|
||||
$indexResponse->assertSee('Garantie op 3D prints');
|
||||
$indexResponse->assertSee('Peter Bakker');
|
||||
|
||||
// Admin detail
|
||||
$showResponse = $this->actingAs($this->admin)->get(route('admin.communications.show', $comm));
|
||||
$showResponse->assertStatus(200);
|
||||
$showResponse->assertSee('Garantie op 3D prints');
|
||||
$showResponse->assertSee('Wat voor garantie zit er op technische 3D prints?');
|
||||
|
||||
// Status is automatically transitioned from new to in_progress upon opening
|
||||
$this->assertEquals('in_progress', $comm->fresh()->status);
|
||||
}
|
||||
|
||||
public function test_admin_can_reply_to_customer_from_admin_section(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$comm = Communication::create([
|
||||
'name' => 'Sophie Visser',
|
||||
'email' => 'sophie@example.com',
|
||||
'subject' => 'Custom formaat mogelijk?',
|
||||
'message' => 'Kan de plantenbak ook 30cm hoog geprint worden?',
|
||||
'status' => 'in_progress',
|
||||
]);
|
||||
|
||||
$replyResponse = $this->actingAs($this->admin)->post(route('admin.communications.reply', $comm), [
|
||||
'message' => 'Beste Sophie, ja zeker! We kunnen dit model opschalen naar 30cm. De levertijd is 3 dagen.',
|
||||
]);
|
||||
|
||||
$replyResponse->assertRedirect();
|
||||
$replyResponse->assertSessionHas('success');
|
||||
|
||||
// Verify status and reply in database
|
||||
$this->assertEquals('resolved', $comm->fresh()->status);
|
||||
$this->assertNotNull($comm->fresh()->last_replied_at);
|
||||
$this->assertDatabaseHas('communication_replies', [
|
||||
'communication_id' => $comm->id,
|
||||
'is_admin_reply' => true,
|
||||
]);
|
||||
|
||||
// Verify email was sent to customer from info@jouwdriedee.nl
|
||||
Mail::assertSent(ContactInquiryReplyMail::class, function ($mail) {
|
||||
return $mail->hasTo('sophie@example.com') && $mail->hasFrom('info@jouwdriedee.nl');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_admin_can_view_communication_inside_customer_profile(): void
|
||||
{
|
||||
// Link inquiry to customer
|
||||
$comm = Communication::create([
|
||||
'user_id' => $this->customer->id,
|
||||
'name' => $this->customer->name,
|
||||
'email' => $this->customer->email,
|
||||
'subject' => 'Vraag binnen profiel',
|
||||
'message' => 'Dit is een vraag die in het klantprofiel zichtbaar moet zijn.',
|
||||
'status' => 'new',
|
||||
]);
|
||||
|
||||
// Also create an order for this customer
|
||||
Order::create([
|
||||
'user_id' => $this->customer->id,
|
||||
'order_number' => 'ORD-TEST-999',
|
||||
'customer_name' => $this->customer->name,
|
||||
'customer_email' => $this->customer->email,
|
||||
'shipping_street' => 'Dorpsstraat',
|
||||
'shipping_number' => '1',
|
||||
'shipping_postal_code' => '1234 AB',
|
||||
'shipping_city' => 'Utrecht',
|
||||
'subtotal' => 45.00,
|
||||
'shipping_cost' => 0.00,
|
||||
'total' => 45.00,
|
||||
'status' => 'pending',
|
||||
'payment_status' => 'paid',
|
||||
]);
|
||||
|
||||
// 1. Customers overview in admin
|
||||
$indexResponse = $this->actingAs($this->admin)->get(route('admin.customers.index'));
|
||||
$indexResponse->assertStatus(200);
|
||||
$indexResponse->assertSee($this->customer->name);
|
||||
$indexResponse->assertSee($this->customer->email);
|
||||
|
||||
// 2. Customer profile in admin (by user ID)
|
||||
$profileResponse = $this->actingAs($this->admin)->get(route('admin.customers.show', $this->customer->id));
|
||||
$profileResponse->assertStatus(200);
|
||||
$profileResponse->assertSee('Klantprofiel: '.$this->customer->name);
|
||||
$profileResponse->assertSee('Communicatie & Vragen', false);
|
||||
$profileResponse->assertSee('Vraag binnen profiel');
|
||||
$profileResponse->assertSee('ORD-TEST-999');
|
||||
|
||||
// 3. Customer profile in admin by email
|
||||
$profileByEmail = $this->actingAs($this->admin)->get(route('admin.customers.show', $this->customer->email));
|
||||
$profileByEmail->assertStatus(200);
|
||||
$profileByEmail->assertSee('Vraag binnen profiel');
|
||||
}
|
||||
|
||||
public function test_guest_and_non_admin_cannot_access_admin_communications_or_customers(): void
|
||||
{
|
||||
// Guests redirected to login
|
||||
$this->get(route('admin.communications.index'))->assertRedirect(route('login'));
|
||||
$this->get(route('admin.customers.index'))->assertRedirect(route('login'));
|
||||
|
||||
// Normal customer is redirected to home with error flash
|
||||
$this->actingAs($this->customer)->get(route('admin.communications.index'))->assertRedirect(route('home'));
|
||||
$this->actingAs($this->customer)->get(route('admin.customers.index'))->assertRedirect(route('home'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user