Add HST/tax support and payment reporting with HST aggregation
CI / Tests (PHP 8.1) (pull_request) Successful in 51s
CI / Coding Standards (pull_request) Successful in 1m1s
CI / Tests (PHP 8.2) (pull_request) Successful in 58s
CI / No Debug Code (pull_request) Successful in 4s
CI / PHPStan (pull_request) Successful in 1m16s
CI / Tests (PHP 8.3) (pull_request) Successful in 45s
CI / Build Plugin Zip (pull_request) Has been skipped
CI / Tests (PHP 8.1) (pull_request) Successful in 51s
CI / Coding Standards (pull_request) Successful in 1m1s
CI / Tests (PHP 8.2) (pull_request) Successful in 58s
CI / No Debug Code (pull_request) Successful in 4s
CI / PHPStan (pull_request) Successful in 1m16s
CI / Tests (PHP 8.3) (pull_request) Successful in 45s
CI / Build Plugin Zip (pull_request) Has been skipped
Studio Settings gains a default HST rate; the rate is frozen onto each payment at booking and computed against the pre-tax subtotal, with the total billed as subtotal + tax. The rate is overridable per booking on My Lessons while unpaid (recomputing the tax amount), comped registrations are never taxed, and receipts break out subtotal/HST/total. Builds the payments report (roadmap #8) from us_payments: a monthly per-instructor view with subtotal, HST collected, and grand-total aggregation, plus a nonce-protected CSV export via admin-post. Studio admins see all instructors and can filter; instructors are scoped to their own rows. The Payment Report menu is gated on export_payments so instructors (who lack manage_billing) can reach it. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
@@ -23,6 +23,8 @@ class PaymentRepository {
|
||||
'currency' => $payment->currency,
|
||||
'method' => $payment->method,
|
||||
'status' => $payment->status,
|
||||
'tax_rate' => $payment->taxRate,
|
||||
'tax_amount' => $payment->taxAmount,
|
||||
'etransfer_email' => $payment->etransferEmail,
|
||||
'stripe_payment_intent_id' => $payment->stripePaymentIntentId,
|
||||
'receipt_number' => $payment->receiptNumber,
|
||||
@@ -30,7 +32,7 @@ class PaymentRepository {
|
||||
'paid_at' => $payment->paidAt,
|
||||
'created_at' => current_time( 'mysql' ),
|
||||
],
|
||||
[ '%d', '%d', '%s', '%d', '%f', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ]
|
||||
[ '%d', '%d', '%s', '%d', '%f', '%s', '%s', '%s', '%f', '%f', '%s', '%s', '%s', '%s', '%s', '%s' ]
|
||||
);
|
||||
|
||||
return $this->db->insert_id;
|
||||
@@ -46,6 +48,42 @@ class PaymentRepository {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a payment's tax rate and recompute the tax amount from its subtotal.
|
||||
*/
|
||||
public function updateTax( int $id, float $rate ): bool {
|
||||
return false !== $this->db->query(
|
||||
$this->db->prepare(
|
||||
"UPDATE {$this->table} SET tax_rate = %f, tax_amount = ROUND( amount * %f / 100, 2 ) WHERE id = %d",
|
||||
$rate,
|
||||
$rate,
|
||||
$id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paid payments in a month (`Y-m` bounds), optionally for one instructor —
|
||||
* the reporting source.
|
||||
*
|
||||
* @return list<Payment>
|
||||
*/
|
||||
public function findPaidBetween( string $from, string $to, int $instructorId = 0 ): array {
|
||||
$sql = "SELECT * FROM {$this->table} WHERE status = %s AND paid_at >= %s AND paid_at < %s";
|
||||
$params = [ Payment::STATUS_PAID, $from, $to ];
|
||||
|
||||
if ( $instructorId > 0 ) {
|
||||
$sql .= ' AND instructor_id = %d';
|
||||
$params[] = $instructorId;
|
||||
}
|
||||
|
||||
$sql .= ' ORDER BY paid_at ASC';
|
||||
|
||||
$rows = $this->db->get_results( $this->db->prepare( $sql, $params ) );
|
||||
|
||||
return array_map( Payment::fromRow( ... ), $rows ?? [] );
|
||||
}
|
||||
|
||||
public function findById( int $id ): ?Payment {
|
||||
$row = $this->db->get_row(
|
||||
$this->db->prepare( "SELECT * FROM {$this->table} WHERE id = %d", $id )
|
||||
|
||||
Reference in New Issue
Block a user