canBeApprovedByCashier()) { return ['success' => false, 'message' => '此付款無法在此階段由出納審核。']; } $payment->update([ 'status' => MembershipPayment::STATUS_APPROVED_CASHIER, 'verified_by_cashier_id' => $user->id, 'cashier_verified_at' => now(), 'notes' => $notes ?? $payment->notes, ]); AuditLogger::log('payment.approved_by_cashier', $payment, [ 'member_id' => $payment->member_id, 'amount' => $payment->amount, 'verified_by' => $user->id, ]); // Notify member $this->notifyMember($payment, PaymentApprovedByCashierMail::class); // Notify accountants $this->notifyRole($payment, 'verify_payments_accountant', PaymentApprovedByCashierMail::class); return [ 'success' => true, 'message' => '出納已審核。已送交會計審核。', ]; } /** * Approve by Accountant (second tier) */ public function approveByAccountant(MembershipPayment $payment, User $user, ?string $notes = null): array { if (! $payment->canBeApprovedByAccountant()) { return ['success' => false, 'message' => '此付款無法在此階段由會計審核。']; } $payment->update([ 'status' => MembershipPayment::STATUS_APPROVED_ACCOUNTANT, 'verified_by_accountant_id' => $user->id, 'accountant_verified_at' => now(), 'notes' => $notes ?? $payment->notes, ]); AuditLogger::log('payment.approved_by_accountant', $payment, [ 'member_id' => $payment->member_id, 'amount' => $payment->amount, 'verified_by' => $user->id, ]); // Notify member $this->notifyMember($payment, PaymentApprovedByAccountantMail::class); // Notify chairs $this->notifyRole($payment, 'verify_payments_chair', PaymentApprovedByAccountantMail::class); return [ 'success' => true, 'message' => '會計已審核。已送交主席審核。', ]; } /** * Approve by Chair (final tier) */ public function approveByChair(MembershipPayment $payment, User $user, ?string $notes = null): array { if (! $payment->canBeApprovedByChair()) { return ['success' => false, 'message' => '此付款無法在此階段由主席審核。']; } $payment->update([ 'status' => MembershipPayment::STATUS_APPROVED_CHAIR, 'verified_by_chair_id' => $user->id, 'chair_verified_at' => now(), 'notes' => $notes ?? $payment->notes, ]); AuditLogger::log('payment.approved_by_chair', $payment, [ 'member_id' => $payment->member_id, 'amount' => $payment->amount, 'verified_by' => $user->id, ]); // Activate membership $activationResult = $this->activateMembership($payment); // Notify member of full approval $this->notifyMember($payment, PaymentFullyApprovedMail::class); if ($activationResult) { $this->notifyMember($payment, MembershipActivatedMail::class); } return [ 'success' => true, 'message' => '主席已審核。付款驗證完成,會員資格已啟用。', 'membershipActivated' => $activationResult, ]; } /** * Reject payment at any stage */ public function reject(MembershipPayment $payment, User $user, string $reason): array { if ($payment->isRejected()) { return ['success' => false, 'message' => '此付款已被拒絕。']; } $payment->update([ 'status' => MembershipPayment::STATUS_REJECTED, 'rejected_by_user_id' => $user->id, 'rejected_at' => now(), 'rejection_reason' => $reason, ]); AuditLogger::log('payment.rejected', $payment, [ 'member_id' => $payment->member_id, 'amount' => $payment->amount, 'rejected_by' => $user->id, 'reason' => $reason, ]); // Notify member $this->notifyMember($payment, PaymentRejectedMail::class); return [ 'success' => true, 'message' => '付款已拒絕。', ]; } /** * Activate membership after payment is fully approved */ protected function activateMembership(MembershipPayment $payment): bool { $member = $payment->member; if (! $member) { return false; } // Only activate if member is pending if ($member->membership_status !== Member::STATUS_PENDING) { return false; } // Calculate membership dates $startDate = now(); $expiryDate = now()->addYear(); $member->update([ 'membership_status' => Member::STATUS_ACTIVE, 'membership_started_at' => $startDate, 'membership_expires_at' => $expiryDate, ]); AuditLogger::log('member.activated_via_payment', $member, [ 'payment_id' => $payment->id, 'started_at' => $startDate, 'expires_at' => $expiryDate, ]); return true; } /** * Notify member with given mail class */ protected function notifyMember(MembershipPayment $payment, string $mailClass): void { if ($payment->member && $payment->member->email) { Mail::to($payment->member->email)->queue(new $mailClass($payment)); } } /** * Notify users with given permission */ protected function notifyRole(MembershipPayment $payment, string $permission, string $mailClass): void { $users = User::permission($permission)->get(); foreach ($users as $user) { Mail::to($user->email)->queue(new $mailClass($payment)); } } }