Combining both flows allows for a comprehensive payment confirmation system where users can submit screenshots of payments to vendors, and both vendors and admins have roles in reviewing and approving/rejecting payments. Here’s how to design and implement the system:
Unified Payment Confirmation Flow
Overview
- User submits payment proof: Users upload payment screenshots along with payment details.
- Vendor reviews payments: Vendors review payments made to them and approve/reject the payments.
- Admin oversight (optional): Admins can view all payments and override vendor decisions if necessary.
1. Database Setup
Create a payments
table that associates payments with users, vendors, and tracks the approval status.
Migration for payments
Table:
php artisan make:migration create_payments_table
Migration Code:
Schema::create('payments', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id'); // User who made the payment
$table->unsignedBigInteger('vendor_id'); // Vendor receiving the payment
$table->string('transaction_id')->nullable();
$table->string('payment_method')->nullable();
$table->string('screenshot_path'); // Screenshot of payment
$table->string('status')->default('pending'); // pending, approved, rejected
$table->unsignedBigInteger('approved_by')->nullable(); // Admin or vendor who approved
$table->timestamps();
});
Run the migration:
php artisan migrate
2. Models
Payment Model:
Add relationships for users, vendors, and approvers.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Payment extends Model
{
protected $fillable = [
'user_id',
'vendor_id',
'transaction_id',
'payment_method',
'screenshot_path',
'status',
'approved_by',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function vendor()
{
return $this->belongsTo(User::class, 'vendor_id');
}
public function approver()
{
return $this->belongsTo(User::class, 'approved_by');
}
}
3. User Payment Submission
Payment Form Blade Template (resources/views/payment.blade.php
):
<form method="POST" action="{{ route('payment.store') }}" enctype="multipart/form-data">
@csrf
<div>
<label for="vendor">Select Vendor:</label>
<select id="vendor" name="vendor_id" required>
@foreach($vendors as $vendor)
<option value="{{ $vendor->id }}">{{ $vendor->name }}</option>
@endforeach
</select>
</div>
<div>
<label for="transaction_id">Transaction ID (optional):</label>
<input type="text" id="transaction_id" name="transaction_id">
</div>
<div>
<label for="payment_method">Payment Method:</label>
<select id="payment_method" name="payment_method" required>
<option value="bank_transfer">Bank Transfer</option>
<option value="upi">UPI</option>
<option value="other">Other</option>
</select>
</div>
<div>
<label for="screenshot">Upload Screenshot:</label>
<input type="file" id="screenshot" name="screenshot" accept="image/*" required>
</div>
<button type="submit">Submit Payment</button>
</form>
Payment Submission Controller:
namespace App\Http\Controllers;
use App\Models\Payment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
class PaymentController extends Controller
{
public function store(Request $request)
{
$request->validate([
'vendor_id' => 'required|exists:users,id',
'payment_method' => 'required|string',
'screenshot' => 'required|image|max:2048',
]);
$screenshotPath = $request->file('screenshot')->store('payment_screenshots', 'public');
Payment::create([
'user_id' => Auth::id(),
'vendor_id' => $request->vendor_id,
'transaction_id' => $request->transaction_id,
'payment_method' => $request->payment_method,
'screenshot_path' => $screenshotPath,
'status' => 'pending',
]);
// Notify the vendor
$vendor = User::find($request->vendor_id);
$vendor->notify(new PaymentSubmittedNotification(Auth::user()));
return redirect()->back()->with('success', 'Payment submitted successfully.');
}
}
4. Vendor Dashboard
Vendor Payment List Blade (resources/views/vendor/payments.blade.php
):
<h1>Payments Received</h1>
<table border="1">
<thead>
<tr>
<th>User</th>
<th>Transaction ID</th>
<th>Payment Method</th>
<th>Screenshot</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach($payments as $payment)
<tr>
<td>{{ $payment->user->name }}</td>
<td>{{ $payment->transaction_id }}</td>
<td>{{ $payment->payment_method }}</td>
<td><a href="{{ asset('storage/' . $payment->screenshot_path) }}" target="_blank">View Screenshot</a></td>
<td>{{ $payment->status }}</td>
<td>
<form method="POST" action="{{ route('payment.update', $payment->id) }}">
@csrf
@method('PUT')
<button name="status" value="approved">Approve</button>
<button name="status" value="rejected">Reject</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
Vendor Controller:
namespace App\Http\Controllers;
use App\Models\Payment;
use Illuminate\Support\Facades\Auth;
class VendorController extends Controller
{
public function payments()
{
$payments = Payment::where('vendor_id', Auth::id())->get();
return view('vendor.payments', compact('payments'));
}
public function update(Request $request, Payment $payment)
{
if ($payment->vendor_id !== Auth::id()) {
abort(403, 'Unauthorized action.');
}
$payment->update([
'status' => $request->status,
'approved_by' => Auth::id(),
]);
return redirect()->back()->with('success', 'Payment status updated successfully.');
}
}
5. Admin Oversight
Admins can review all payments and override vendor decisions if necessary.
Admin Dashboard Controller:
public function payments()
{
$payments = Payment::all(); // Retrieve all payments
return view('admin.payments', compact('payments'));
}
public function update(Request $request, Payment $payment)
{
$payment->update([
'status' => $request->status,
'approved_by' => Auth::id(),
]);
return redirect()->back()->with('success', 'Payment status updated successfully.');
}
Final Flow
- User: Submits payment details and screenshot.
- Vendor: Reviews payments made to them and approves/rejects them.
- Admin (Optional): Reviews all payments and overrides decisions if necessary.
- Notifications: Users and vendors are notified of status changes.
This combined flow ensures that both vendors and admins can manage payments efficiently while keeping users informed.