Charge weekly reservations for every claimed occurrence and confirm the whole series
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 2m50s
CI / Tests (PHP 8.1) (pull_request) Successful in 42s
CI / Tests (PHP 8.2) (pull_request) Successful in 39s
CI / PHPStan (pull_request) Successful in 2m49s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m38s
CI / Build Plugin Zip (pull_request) Skipped

A weekly booking on a per-lesson (one_time) priced offering was creating its
single upfront payment for one week's price while reserving up to 12 weeks,
and settling that payment confirmed only the anchor lesson, leaving the rest
of the series pending forever.

- BookingEndpoint now charges price x claimed occurrences for one_time
  billing; a full_term price is still charged once since it covers the term.
- PaymentService::confirmRegistration resolves the anchor lesson's series and
  confirms every non-cancelled row via the new
  BookingRepository::updateStatusForSeries().

Closes #79

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
2026-07-22 10:19:53 -03:00
co-authored by Claude Fable 5
parent 05d1728248
commit ff059909a5
8 changed files with 164 additions and 7 deletions
+8 -1
View File
@@ -249,7 +249,14 @@ class BookingEndpoint {
$status = Lesson::STATUS_PENDING;
if ( $offering->price > 0.0 ) {
$payment = $this->payments->createForRegistration( Payment::REG_LESSON, $anchorId, $studentId, $slot->instructorId, $offering->price, $offering->currency, $offering->etransferEmail );
// A full-term price already covers the whole reservation; a per-lesson
// (one_time) price is owed once per occurrence actually claimed, so a
// weekly reservation cannot hold a term while paying for one week.
$amount = Offering::BILLING_FULL_TERM === $offering->billingMode
? $offering->price
: $offering->price * count( $ids );
$payment = $this->payments->createForRegistration( Payment::REG_LESSON, $anchorId, $studentId, $slot->instructorId, $amount, $offering->currency, $offering->etransferEmail );
if ( null !== $payment && $payment->isPaid() ) {
$status = Lesson::STATUS_CONFIRMED;
+20
View File
@@ -214,6 +214,26 @@ class BookingRepository {
);
}
/**
* Update every non-cancelled lesson in a weekly series at once — e.g.
* confirming the whole reservation when its single upfront payment settles.
*/
public function updateStatusForSeries( int $seriesId, string $status ): bool {
if ( ! in_array( $status, Lesson::VALID_STATUSES, true ) ) {
return false;
}
$sql = $this->db->prepare(
'UPDATE %i SET status = %s WHERE series_id = %d AND status != %s',
$this->table,
$status,
$seriesId,
Lesson::STATUS_CANCELLED
);
return null !== $sql && false !== $this->db->query( $sql );
}
public function updateStatus( int $id, string $status ): bool {
if ( ! in_array( $status, Lesson::VALID_STATUSES, true ) ) {
return false;
+13 -3
View File
@@ -195,10 +195,20 @@ class PaymentService {
}
private function confirmRegistration( string $type, int $registrationId ): void {
if ( Payment::REG_LESSON === $type ) {
$this->bookings->updateStatus( $registrationId, Lesson::STATUS_CONFIRMED );
if ( Payment::REG_LESSON !== $type ) {
// Group enrolments are already `active`; no status change on payment.
return;
}
// Group enrolments are already `active`; no status change on payment.
// A weekly reservation's payment is linked to its anchor lesson but pays
// for the whole series, so settling it confirms every lesson in the series.
$lesson = $this->bookings->findById( $registrationId );
if ( null !== $lesson && null !== $lesson->seriesId ) {
$this->bookings->updateStatusForSeries( $lesson->seriesId, Lesson::STATUS_CONFIRMED );
return;
}
$this->bookings->updateStatus( $registrationId, Lesson::STATUS_CONFIRMED );
}
private function linkPayment( string $type, int $registrationId, int $paymentId ): void {