Notify instructors on new bookings and enrolments
CI / Coding Standards (pull_request) Successful in 27s
CI / Tests (PHP 8.1) (pull_request) Successful in 37s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.3) (pull_request) Successful in 36s
CI / Tests (PHP 8.5) (pull_request) Successful in 40s
CI / Tests (PHP 8.2) (pull_request) Successful in 42s
CI / Static Analysis (pull_request) Successful in 48s
CI / Build Plugin Zip (pull_request) Skipped
CI / Coding Standards (pull_request) Successful in 27s
CI / Tests (PHP 8.1) (pull_request) Successful in 37s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.3) (pull_request) Successful in 36s
CI / Tests (PHP 8.5) (pull_request) Successful in 40s
CI / Tests (PHP 8.2) (pull_request) Successful in 42s
CI / Static Analysis (pull_request) Successful in 48s
CI / Build Plugin Zip (pull_request) Skipped
Add an opt-in, per-instructor email notice sent when someone books one of their lessons or enrols in one of their group classes. Off by default and set from My Availability → Notifications; covers both the student/guardian REST flows and the studio's wp-admin "book/add for a student" forms. The opt-in check lives in InstructorNotificationMailer so no booking path can drift on who is mailed; lessons fire from LessonBooker::settle (the one step both booking paths reach), enrolments from EnrollmentEndpoint::enroll and GroupClassController::addDirect. The notice is a courtesy and never fails a booking or enrolment that otherwise succeeded. Co-authored-by: anthropic/claude-opus-4-8
This commit is contained in:
co-authored by
anthropic/claude-opus-4-8
parent
56fc0bd57d
commit
12765d8f13
@@ -5,6 +5,7 @@ namespace Unsupervised\Schedular\Tests\Unit\GroupClass;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use Mockery;
|
||||
use Unsupervised\Schedular\Auth\InstructorNotificationMailer;
|
||||
use Unsupervised\Schedular\GroupClass\Enrollment;
|
||||
use Unsupervised\Schedular\GroupClass\EnrollmentEndpoint;
|
||||
use Unsupervised\Schedular\GroupClass\EnrollmentRepository;
|
||||
@@ -26,6 +27,7 @@ class EnrollmentEndpointTest extends TestCase
|
||||
private RegistrationGate $gate;
|
||||
private PaymentService $payments;
|
||||
private GroupAccessRepository $access;
|
||||
private InstructorNotificationMailer&Mockery\MockInterface $instructorMailer;
|
||||
private EnrollmentEndpoint $endpoint;
|
||||
|
||||
protected function setUp(): void
|
||||
@@ -37,6 +39,9 @@ class EnrollmentEndpointTest extends TestCase
|
||||
Functions\when('sanitize_text_field')->returnArg();
|
||||
Functions\when('get_current_user_id')->justReturn(5);
|
||||
Functions\when('current_time')->justReturn('2026-07-24');
|
||||
// The enrolment notice resolves the student's name before handing off to the
|
||||
// (mocked) mailer; a bare false is enough since the name falls back to the id.
|
||||
Functions\when('get_userdata')->justReturn(false);
|
||||
|
||||
$this->enrollments = Mockery::mock(EnrollmentRepository::class);
|
||||
$this->offerings = Mockery::mock(OfferingRepository::class);
|
||||
@@ -44,6 +49,11 @@ class EnrollmentEndpointTest extends TestCase
|
||||
$this->payments = Mockery::mock(PaymentService::class);
|
||||
$this->access = Mockery::mock(GroupAccessRepository::class);
|
||||
|
||||
// The opt-in instructor notice is exercised on its own; here it is a mock
|
||||
// that ignores whatever it is handed, so enrolment tests stay about enrolment.
|
||||
$this->instructorMailer = Mockery::mock(InstructorNotificationMailer::class);
|
||||
$this->instructorMailer->shouldReceive('notifyEnrollment')->andReturn(true)->byDefault();
|
||||
|
||||
$this->guardians = Mockery::mock(GuardianService::class);
|
||||
$this->guardians->shouldReceive('canActFor')
|
||||
->andReturnUsing(static fn (int $actor, int $student): bool => $actor === $student)->byDefault();
|
||||
@@ -57,6 +67,7 @@ class EnrollmentEndpointTest extends TestCase
|
||||
$this->payments,
|
||||
$this->access,
|
||||
$this->guardians,
|
||||
$this->instructorMailer,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,6 +104,19 @@ class EnrollmentEndpointTest extends TestCase
|
||||
self::assertNull($result->get_data()['payment']);
|
||||
}
|
||||
|
||||
public function testASuccessfulEnrolmentNotifiesTheClassInstructor(): void
|
||||
{
|
||||
$this->offerings->shouldReceive('findById')->with(8)->andReturn($this->offering(0.0));
|
||||
$this->expectSuccessfulEnrollment();
|
||||
$this->payments->shouldNotReceive('createForRegistration');
|
||||
|
||||
// The class is taught by instructor 3; the enrolling student falls back to
|
||||
// their id for a name (get_userdata is stubbed false in setUp).
|
||||
$this->instructorMailer->shouldReceive('notifyEnrollment')->once()->with(3, '5', 'Choir')->andReturn(true);
|
||||
|
||||
$this->endpoint->enroll(new \WP_REST_Request(['offering_id' => 8]));
|
||||
}
|
||||
|
||||
public function testEnrollInPricedClassReturnsPaymentSummary(): void
|
||||
{
|
||||
$this->offerings->shouldReceive('findById')->with(8)->andReturn($this->offering(120.0));
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Unsupervised\Schedular\Tests\Unit\GroupClass;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use Mockery;
|
||||
use Unsupervised\Schedular\Auth\InstructorNotificationMailer;
|
||||
use Unsupervised\Schedular\Auth\InviteRepository;
|
||||
use Unsupervised\Schedular\Auth\RegistrationMailer;
|
||||
use Unsupervised\Schedular\Auth\RoleManager;
|
||||
@@ -32,6 +33,7 @@ class GroupClassControllerTest extends TestCase
|
||||
private RegistrationMailer&Mockery\MockInterface $mailer;
|
||||
private IntakeAudit&Mockery\MockInterface $audit;
|
||||
private IntakeRecording&Mockery\MockInterface $intake;
|
||||
private InstructorNotificationMailer&Mockery\MockInterface $instructorMailer;
|
||||
private GroupClassController $controller;
|
||||
|
||||
protected function setUp(): void
|
||||
@@ -47,6 +49,10 @@ class GroupClassControllerTest extends TestCase
|
||||
$this->mailer = Mockery::mock(RegistrationMailer::class);
|
||||
$this->audit = Mockery::mock(IntakeAudit::class);
|
||||
$this->intake = Mockery::mock(IntakeRecording::class);
|
||||
// The opt-in instructor notice is tested on its own; a mock keeps these
|
||||
// tests about enrolment, not about who gets emailed.
|
||||
$this->instructorMailer = Mockery::mock(InstructorNotificationMailer::class);
|
||||
$this->instructorMailer->shouldReceive('notifyEnrollment')->andReturn(true)->byDefault();
|
||||
$this->controller = new GroupClassController(
|
||||
$this->enrollments,
|
||||
$this->offerings,
|
||||
@@ -57,6 +63,7 @@ class GroupClassControllerTest extends TestCase
|
||||
$this->mailer,
|
||||
$this->audit,
|
||||
$this->intake,
|
||||
$this->instructorMailer,
|
||||
);
|
||||
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
|
||||
Reference in New Issue
Block a user