Skip to main content

Overview

The Payment model tracks financial transactions for consultations and services. It records payment amounts, methods, status, and links payments to patients and consultations. Model Location: app/Models/Payment.php Features:
  • Soft deletes enabled
  • Decimal casting for monetary amounts
  • Relationships with patients and consultations
  • Support for multiple payment methods and statuses

Database Schema

id
bigint
required
Primary key, auto-incrementing
patient_id
bigint
required
Foreign key to patients table. Cascades on delete.
consultation_id
bigint
Foreign key to consultations table. Sets to null on delete.
amount
decimal(10,2)
required
Payment amount with 2 decimal precision
payment_method
string
required
Payment method used. Common values:
  • cash - Cash payment
  • card - Credit/debit card
  • transfer - Bank transfer
status
string
required
Payment status. Default: paidPossible values:
  • paid - Payment completed
  • pending - Payment pending
  • cancelled - Payment cancelled
notes
text
Additional payment notes or reference information
created_at
timestamp
Record creation timestamp
updated_at
timestamp
Record last update timestamp
deleted_at
timestamp
Soft delete timestamp (null if not deleted)

Fillable Attributes

The following attributes can be mass-assigned:
patient_id
integer
required
ID of the patient making the payment
consultation_id
integer
ID of the related consultation (optional)
amount
decimal
required
Payment amount (e.g., 500.00)
payment_method
string
required
Payment method: cash, card, or transfer
status
string
Payment status: paid, pending, or cancelled
notes
text
Additional notes or transaction reference

Relationships

Patient

Get the patient who made this payment.
$payment = Payment::find(1);
$patient = $payment->patient;

echo $patient->full_name;
echo $patient->phone;
Relationship Type: belongsTo Related Model: App\Models\Patient Foreign Key: patient_id

Consultation

Get the consultation associated with this payment (if any).
$payment = Payment::find(1);
$consultation = $payment->consultation;

if ($consultation) {
    echo "Service: " . $consultation->diagnosis;
    echo "Doctor: " . $consultation->doctor->name;
}
Relationship Type: belongsTo Related Model: App\Models\Consultation Foreign Key: consultation_id

Type Casting

The model automatically casts the following attributes:
  • amount: Cast to decimal with 2 decimal places

Soft Deletes

The Payment model uses soft deletes. Deleted records are not permanently removed from the database but marked with a deleted_at timestamp.
// Soft delete a payment
$payment->delete();

// Include soft deleted records
$allPayments = Payment::withTrashed()->get();

// Get only soft deleted records
$deletedPayments = Payment::onlyTrashed()->get();

// Restore a soft deleted payment
$payment->restore();

// Permanently delete
$payment->forceDelete();

Usage Examples

Creating a Payment

use App\Models\Payment;

$payment = Payment::create([
    'patient_id' => 1,
    'consultation_id' => 5,
    'amount' => 500.00,
    'payment_method' => 'cash',
    'status' => 'paid',
    'notes' => 'Consulta general - pago completo',
]);

Creating Payment for Consultation

use App\Models\Consultation;

$consultation = Consultation::find(1);

// Create payment directly from consultation
$payment = $consultation->payment()->create([
    'patient_id' => $consultation->patient_id,
    'amount' => 750.00,
    'payment_method' => 'card',
    'status' => 'paid',
]);

Updating Payment Status

$payment = Payment::find(1);

// Mark as paid
$payment->update([
    'status' => 'paid',
    'notes' => 'Pagado vía transferencia - Ref: ABC123',
]);

// Cancel payment
$payment->update([
    'status' => 'cancelled',
    'notes' => 'Cancelado por el paciente',
]);

Querying Payments

// Get all payments for a patient
$patientPayments = Payment::where('patient_id', 1)
    ->with('consultation')
    ->orderBy('created_at', 'desc')
    ->get();

// Get today's payments
$todayPayments = Payment::whereDate('created_at', today())
    ->where('status', 'paid')
    ->with(['patient', 'consultation'])
    ->get();

// Get pending payments
$pendingPayments = Payment::where('status', 'pending')
    ->with('patient')
    ->get();

Financial Calculations

// Calculate total revenue for a period
$totalRevenue = Payment::where('status', 'paid')
    ->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])
    ->sum('amount');

echo "Monthly Revenue: $" . number_format($totalRevenue, 2);

// Calculate revenue by payment method
$revenueByMethod = Payment::where('status', 'paid')
    ->whereDate('created_at', today())
    ->selectRaw('payment_method, SUM(amount) as total')
    ->groupBy('payment_method')
    ->get();

foreach ($revenueByMethod as $method) {
    echo "{$method->payment_method}: $" . number_format($method->total, 2) . "\n";
}

Working with Decimal Amounts

$payment = Payment::find(1);

// Amount is automatically cast to decimal
echo "Amount: $" . number_format($payment->amount, 2);

// Perform calculations
$tax = $payment->amount * 0.16; // 16% tax
$total = $payment->amount + $tax;

echo "Subtotal: $" . number_format($payment->amount, 2);
echo "Tax: $" . number_format($tax, 2);
echo "Total: $" . number_format($total, 2);

Filtering by Payment Method

// Get cash payments
$cashPayments = Payment::where('payment_method', 'cash')
    ->where('status', 'paid')
    ->get();

// Get card payments
$cardPayments = Payment::where('payment_method', 'card')
    ->where('status', 'paid')
    ->get();

// Get transfer payments
$transferPayments = Payment::where('payment_method', 'transfer')
    ->where('status', 'paid')
    ->get();

Patient Payment History

$patientId = 1;

$paymentHistory = Payment::where('patient_id', $patientId)
    ->with(['consultation.doctor'])
    ->orderBy('created_at', 'desc')
    ->get();

// Calculate total paid by patient
$totalPaid = Payment::where('patient_id', $patientId)
    ->where('status', 'paid')
    ->sum('amount');

// Calculate outstanding balance
$pendingAmount = Payment::where('patient_id', $patientId)
    ->where('status', 'pending')
    ->sum('amount');

echo "Total Paid: $" . number_format($totalPaid, 2);
echo "Outstanding: $" . number_format($pendingAmount, 2);

Daily Revenue Report

$date = today();

$dailyReport = [
    'date' => $date->format('d/m/Y'),
    'total_payments' => Payment::whereDate('created_at', $date)->count(),
    'total_revenue' => Payment::whereDate('created_at', $date)
        ->where('status', 'paid')
        ->sum('amount'),
    'pending_amount' => Payment::whereDate('created_at', $date)
        ->where('status', 'pending')
        ->sum('amount'),
    'by_method' => Payment::whereDate('created_at', $date)
        ->where('status', 'paid')
        ->selectRaw('payment_method, COUNT(*) as count, SUM(amount) as total')
        ->groupBy('payment_method')
        ->get(),
];

Eager Loading Payment Details

// Load payment with all related information
$payment = Payment::with([
    'patient' => function ($query) {
        $query->select('id', 'full_name', 'phone', 'email');
    },
    'consultation' => function ($query) {
        $query->select('id', 'diagnosis', 'doctor_id')
              ->with('doctor:id,name');
    }
])->find(1);

Outstanding Payments Report

// Get all patients with pending payments
$outstandingPayments = Payment::where('status', 'pending')
    ->with(['patient', 'consultation'])
    ->get()
    ->groupBy('patient_id')
    ->map(function ($payments, $patientId) {
        return [
            'patient' => $payments->first()->patient->full_name,
            'total_pending' => $payments->sum('amount'),
            'payment_count' => $payments->count(),
            'oldest_pending' => $payments->min('created_at'),
        ];
    });

Validation Example

// Validate payment data
$validated = $request->validate([
    'patient_id' => 'required|exists:patients,id',
    'consultation_id' => 'nullable|exists:consultations,id',
    'amount' => 'required|numeric|min:0.01|max:999999.99',
    'payment_method' => 'required|in:cash,card,transfer',
    'status' => 'nullable|in:paid,pending,cancelled',
    'notes' => 'nullable|string|max:1000',
]);

$payment = Payment::create($validated);

Refund or Adjustment

$originalPayment = Payment::find(1);

// Create refund payment (negative amount)
$refund = Payment::create([
    'patient_id' => $originalPayment->patient_id,
    'consultation_id' => $originalPayment->consultation_id,
    'amount' => -$originalPayment->amount,
    'payment_method' => $originalPayment->payment_method,
    'status' => 'paid',
    'notes' => "Reembolso de pago #{$originalPayment->id}",
]);

// Or mark original as cancelled
$originalPayment->update([
    'status' => 'cancelled',
    'notes' => 'Cancelado - reembolso procesado',
]);

Build docs developers (and LLMs) love