The Deposit History feature provides insights into user deposits. Key components include:
On page load, the /api:BVaDN9hl/deposit/list?page=1&per_page=15 endpoint is called to retrieve the deposit transactions data. It runs App\Http\Controllers\Admin\DepositController@deposits.
{
"data": [
{
"name": "Sam Uzima",
"email": "u******il.com",
"phone_number": "+2547*****66",
"type": "WITHDRAWAL",
"date": "Mar 09, 2025",
"time": "06:01PM",
"amount": "-7,770.00",
"tid": 1234,
"users_id": 5678,
"payment_method": null,
"fulfillment": false,
"bg_color": "/docs/1.0/financial-admin/deposit#7C022533",
"color": "/docs/1.0/financial-admin/deposit#7C0225"
},
---
{
---
}
],
"links": {
"first": "http://127.0.0.1:8080/api:BVaDN9hl/deposit/list?page=1",
"last": "http://127.0.0.1:8080/api:BVaDN9hl/deposit/list?page=401",
"prev": null,
"next": "http://127.0.0.1:8080/api:BVaDN9hl/deposit/list?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 401,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": null,
"label": "...",
"active": false
},
{
"url": "http://127.0.0.1:8080/api:BVaDN9hl/deposit/list?page=2",
"label": "Next »",
"active": false
}
],
"path": "http://127.0.0.1:8080/api:BVaDN9hl/deposit/list",
"per_page": 15,
"to": 15,
"total": 6004
}
}
The Deposit History section displays all deposit transactions. The table includes the following columns:
public function deposits(Request $request)
{
$validator = Validator::make($request->all(), [
'search' => 'nullable|string',
'page' => 'required|numeric',
'per_page' => 'required|numeric',
'status' => 'nullable|string',
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$data = $validator->validated();
$per_page = $data['per_page'];
$deposits = GetTransactionsAction::run($per_page, $data['search'] ?? null);
return TransactionsResource::collection($deposits);
}
The GetTransactionsAction class is used to retrieve the deposit transactions data. The TransactionsResource class is used to format the data for the API response.
{
"name": "Sam Uzima",
"email": "u******il.com",
"phone_number": "+2547*****66",
"type": "WITHDRAWAL",
"date": "Mar 08, 2025",
"time": "09:00PM",
"amount": "-5,000.00",
"tid": 1234,
"users_id": 5678,
"payment_method": "manual",
"fulfillment": true,
"bg_color": "/docs/1.0/financial-admin/deposit#7BBF7433",
"color": "/docs/1.0/financial-admin/deposit#7bbf74"
}
The Deposit Information section allows financial admins to view detailed information about a specific deposit transaction. Clicking on a deposit transaction in the table will display the deposit information, including the user's name, email address, phone number, transaction status, failure reason, and deposit details.
Deposit details include the payment method, transaction reference, customer reference, transaction date, and amount.
This is achieved by hitting the /api:BVaDN9hl/deposit/single?transactionid=6441 endpoint, which runs App\Http\Controllers\Admin\DepositController@single_deposit to retrieve the deposit transaction details.
{
"full_name": "Sam Uzima",
"email": "u******il.com",
"goals": [
{
"goal_title": "Happiness",
"goal_amount": "50,000.00"
}
],
"total": "50,000.00",
"transaction_created_at": "Mar 05, 2025 at 16:33",
"status": "Successful",
"via": "mpesa",
"reason": "-",
"phone_number": "+254721665300",
"meta": {
"joining_fee": 0,
"subscription_fee": 0,
"investment_amount": 50000,
"transaction_fee": 0
},
"transaction": {
"id": 6441,
"uuid": "ec7fe1bb-a6d6-4fbc-ab88-636e6caad97c",
"is_fulfilled": true,
"processed_by": "Mpesa Callback",
"comments": null,
"users_id": 4890,
"created_at": "2025-03-05 16:33:26",
"meta": "{\"joining_fee\":0,\"subscription_fee\":0,\"investment_amount\":50000,\"transaction_fee\":0}",
"firstname": "Sam",
"lastname": "Uzima",
"email": "u******il.com",
"via": "mpesa",
"bank_reference": "\"TZSQ63S\"",
"customer_reference": "6441",
"status": "Successful",
"reason": "-"
}
}
The Add Manual Deposit feature allows financial admins to add a manual deposit for a user. Key steps are as follows:
/api:BVaDN9hl/deposit/check which runs App\Http\Controllers\Admin\DepositController@check to validate the user's email address.public function check(Request $request)
{
$validator = Validator::make($request->all(), [
'email' => ['sometimes',],
'transaction_id' => ['sometimes', 'numeric']
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$data = $validator->validated();
$email = $data['email'] ?? "";
if (isset($data['transaction_id'])) {
$userTransaction = DB::table('user_transactions')
->where('user_transactions.id', '=', $data['transaction_id'])
->where('user_transactions.type', '=', TransactionActionEnum::DEPOSIT->value)
->where('user_transactions.is_fulfilled', false)
->orderBy('user_transactions.id', 'desc')
->first();
if (!$userTransaction) {
return RespondWithError::make()->handle(
code: RespondWithError::$ERROR_CODE_NOT_FOUND,
message: "Transaction not found",
payload: ['email' => $email],
);
}
$users = DB::table('users')->where('id', $userTransaction->users_id)->first();
} else {
$users = DB::table('users')->where('email', $email)
->orWhere('membership_number', $email)->first();
if (!$users) {
return RespondWithError::make()->handle(
code: RespondWithError::$ERROR_CODE_NOT_FOUND,
message: "User not found",
payload: ['email' => $email],
);
}
$userTransaction = DB::table('user_transactions')
->where('user_transactions.users_id', '=', $users->id)
->where('user_transactions.type', '=', TransactionActionEnum::DEPOSIT->value)
->where('user_transactions.is_fulfilled', false)
->orderBy('user_transactions.id', 'desc')
->first();
}
$slider_array = DB::table('goals')->where('users_id', '=', $users->id)->get()->map(function ($item) {
return [
'id' => $item->id,
'name' => $item->title,
'allocation' => number_format($item->target, 2),
'target' => $item->target,
];
});
$exists = 'no';
$goalTransactionDetails = [];
$uid = $users->id;
$tid = $userTransaction?->id;
if ($userTransaction) {
$gt_transactions = DB::table('goal_transactions')
->where('goal_transactions.user_transactions_id', $tid)
->join('goals', 'goals.id', 'goal_transactions.goals_id')
->get();
$gt_transactions_count = DB::table('goal_transactions')
->where('goal_transactions.user_transactions_id', $tid)
->count();
$detail = json_decode($userTransaction->meta);
if (User::find($uid)->hasActiveSubscription()) {
$subscription_amount = 0;
} else {
$subscription_amount = $detail->subscription_fee;
}
$transactionDetails = [
'id' => $tid,
'amount' => number_format($userTransaction->amount, 2),
'transaction_details' => [
'joining_fee' => !empty($detail->joining_fee) ? $detail->joining_fee : 0.0,
'transaction_fee' => !empty($detail->transaction_fee) ? $detail->transaction_fee : 0.0,
'subscription_fee' => $subscription_amount,
'investment_amount' => $detail->investment_amount,
'subscription_id' => Subscription::query()->where('amount', $subscription_amount)->first()?->id,
'transaction_date' => Carbon::parse($userTransaction->created_at)->format('d/m/Y'),
],
'transactions_gts' => $gt_transactions_count
];
$exists = $gt_transactions_count ? 'yes' : 'no';
} else {
$transactionDetails = [
'id' => null,
'transaction_details' => null,
'transactions_gts' => 0,
];
}
if (!empty($transactionDetails['transaction_details']) && isset($gt_transactions) && $transactionDetails['transactions_gts'] > 0) {
foreach ($gt_transactions as $item) {
$var_result = [
'id' => $item->id,
'goal_id' => $item->goals_id,
'allocation_amount' => number_format($item->amount, 2),
'goal_title' => $item->title,
'goal_target' => $item->target,
];
$goalTransactionDetails[] = $var_result;
}
}
return RespondWithSuccess::run(...[
'body' => [
'user_id' => $users->id,
'slider_array' => $slider_array,
't_d' => $transactionDetails,
'g_t_d' => $goalTransactionDetails,
'transaction' => $exists,
]
]);
}
The code snippet above validates the user's email address and retrieves the user's transaction details. The response is formatted using the RespondWithSuccess class.
{
"user_id": 1234,
"slider_array": [
{
"id": 7113,
"name": "Work Station",
"allocation": "285,000.00",
"target": 285000
}
],
"t_d": {
"id": 6329,
"amount": "11,000.00",
"transaction_details": {
"joining_fee": 0,
"transaction_fee": 0,
"subscription_fee": 10000,
"investment_amount": 1000,
"subscription_id": 2,
"transaction_date": "24/02/2025"
},
"transactions_gts": 1
},
"g_t_d": [
{
"id": 7113,
"goal_id": 7113,
"allocation_amount": "1,000.00",
"goal_title": "Work Station",
"goal_target": 285000
}
],
"transaction": "yes"
}
The response includes the user's ID, slider array, transaction details, goal transaction details, and transaction status.
Enter the deposit amount. The admin can add a manual deposit by entering the deposit amount for each goal, then clicking the Next button.
Select Transaction Date and upload proof of payment. The admin can select the transaction date and upload proof of payment for the manual deposit, then click the Next button.
Review and confirm the manual transaction.
The admin can review the manual transaction details and confirm the transaction by clicking the Confirm button, which hits /api:BVaDN9hl/deposit/fulfill and runs App\Http\Controllers\Admin\DepositController@fulfill.
public function fulfill(Request $request)
{
$validator = Validator::make($request->all(), [
'user_id' => 'required|numeric|integer',
'subscription_id' => 'nullable|numeric|integer',
'allocations' => 'required',
'joining_fee' => 'nullable|numeric|integer',
'timestamp' => 'required|numeric',
'tid' => 'nullable|numeric|integer',
'ta' => 'nullable|numeric|integer',
'link' => 'required',
'comment' => ['nullable', 'string'],
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$data = $validator->validated();
$data['approved_by'] = Auth::id();
$users_1 = User::query()->find($data['user_id']);
if (!$users_1) {
return RespondWithError::make()->handle(
code: RespondWithError::$ERROR_CODE_NOT_FOUND,
message: "User not found",
);
}
$subscription_fee_details = null;
$joining_fee_details = null;
$joining_fee = 0.0;
if (!is_null($data['subscription_id'])) {
$subscription_fee_details = new UserTransactionSubscriptionData($data['subscription_id']);
}
if (!is_null($data['joining_fee'])) {
$joining_fee = $data['joining_fee'];
$joining_fee_details = new UserTransactionJoiningFeeData(0);
}
$allocations = json_decode($data['allocations'], true);
$allocations = array_map(fn($item) => UserTransactionAllocationData::fromArray($item), $allocations);
if (isset($data['tid'])) {
$transaction = UserTransaction::findOrFail($data['tid']);
$userTransaction = UpdateTransactionRecord::make()->handle(
transaction: $transaction,
joining_fee: $joining_fee,
allocations: $allocations,
subscriptionData: $subscription_fee_details
);
} else {
$userTransaction = AddTransactionRecordAction::make()->handle(
user_id: $users_1->id,
allocations: $allocations,
subscription: $subscription_fee_details,
joining_fee_details: $joining_fee_details
);
}
if ($data['comment']) {
$userTransaction->addComment($data['comment']);
}
$func_1 = AdminFulfillAction::run(...[
'transaction_id' => $userTransaction->id,
'link' => $data['link'],
'timestamp' => $data['timestamp']
]);
return RespondWithSuccess::run(...[
'body' => ['response' => $func_1]
]);
}
The code snippet above fulfills the manual deposit transaction by updating the transaction record and adding a comment. The response is formatted using the RespondWithSuccess class.