Initial commit
This commit is contained in:
552
app/Http/Controllers/ApiMerchantsController.php
Normal file
552
app/Http/Controllers/ApiMerchantsController.php
Normal file
@@ -0,0 +1,552 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Models\Merchant;
|
||||
use App\Models\Transaction;
|
||||
use App\ActivityLog;
|
||||
use App\Libs\Smsgateway;
|
||||
|
||||
class ApiMerchantsController extends Controller{
|
||||
public function merchant_login(Request $request){
|
||||
$this->validate($request, [
|
||||
'phone_number' => 'required',
|
||||
'pin' => 'required'
|
||||
]);
|
||||
$phone_number = $this->validatePhoneNumber($request->phone_number);
|
||||
|
||||
if ($phone_number === false) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Phone Number/PIN is incorrect!'
|
||||
], 401);
|
||||
}
|
||||
|
||||
$pin = md5($request->input('pin'));
|
||||
|
||||
$merchant = Models\Merchant::where('phone', $phone_number)->where('pin', $pin)->first();
|
||||
|
||||
if ($merchant === null) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Phone Number/PIN incorrect!'
|
||||
], 401);
|
||||
}
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Login successful',
|
||||
'merchant' => [
|
||||
'id' => $merchant->id,
|
||||
'phone' => $merchant->phone,
|
||||
'balance' => $merchant->balance,
|
||||
'status' => $merchant->status,
|
||||
'fullname' => $merchant->fullname,
|
||||
'country' => $merchant->country
|
||||
]
|
||||
], 200);
|
||||
}
|
||||
|
||||
|
||||
public function get_transactions(Request $request)
|
||||
{
|
||||
// POST body params: merchant_id (required), keyword (optional), start_date, end_date, per_page
|
||||
$merchantId = $request->input('merchant_id');
|
||||
|
||||
if (!$merchantId) {
|
||||
return response()->json(['success' => false, 'message' => 'merchant_id is required'], 422);
|
||||
}
|
||||
$merchant = Models\Merchant::find($merchantId);
|
||||
if (!$merchant) {
|
||||
return response()->json(['success' => false, 'message' => 'merchant not found'], 404);
|
||||
}
|
||||
|
||||
$perPage = (int) $request->input('per_page', 20);
|
||||
|
||||
$query = \DB::table('transactions')
|
||||
->join('merchants', 'transactions.merchant_id', '=', 'merchants.id')
|
||||
->select(
|
||||
'merchants.fullname',
|
||||
'transactions.id',
|
||||
'transactions.status',
|
||||
'transactions.msisdn',
|
||||
'transactions.amount',
|
||||
'transactions.created_at'
|
||||
)
|
||||
->where('transactions.merchant_id', $merchantId);
|
||||
|
||||
if ($request->filled('keyword')) {
|
||||
$keyword = $request->input('keyword');
|
||||
$like = "%{$keyword}%";
|
||||
$query->where(function ($q) use ($like) {
|
||||
$q->where('merchants.fullname', 'like', $like)
|
||||
->orWhere('transactions.msisdn', 'like', $like)
|
||||
->orWhere('transactions.status', 'like', $like)
|
||||
->orWhere('transactions.amount', 'like', $like)
|
||||
->orWhere('transactions.created_at', 'like', $like);
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->filled('start_date') || $request->filled('end_date')) {
|
||||
try {
|
||||
$start = $request->filled('start_date') ? \Carbon\Carbon::parse($request->input('start_date'))->startOfDay() : null;
|
||||
$end = $request->filled('end_date') ? \Carbon\Carbon::parse($request->input('end_date'))->endOfDay() : null;
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['success' => false, 'message' => 'Invalid date format'], 422);
|
||||
}
|
||||
|
||||
if ($start && $end) {
|
||||
$query->whereBetween('transactions.created_at', [$start, $end]);
|
||||
} elseif ($start) {
|
||||
$query->where('transactions.created_at', '>=', $start);
|
||||
} else {
|
||||
$query->where('transactions.created_at', '<=', $end);
|
||||
}
|
||||
}
|
||||
|
||||
$query->orderBy('transactions.created_at', 'desc');
|
||||
|
||||
$paginator = $query->paginate($perPage)->appends($request->except('page'));
|
||||
|
||||
return response()->json($paginator);
|
||||
}
|
||||
public function get_dealers(Request $request){
|
||||
$perPage = (int) $request->input('per_page', 20);
|
||||
|
||||
#$dealer_arr = \DB::table('organisations')->orderBy('organisations.created_at', 'DESC')->paginate(20);
|
||||
|
||||
$query = \DB::table('organisations')->select('organisations.id', 'organisations.name', 'organisations.email', 'organisations.phone', 'organisations.status');
|
||||
|
||||
if ($request->filled('keyword')) {
|
||||
$keyword = $request->input('keyword');
|
||||
$like = "%{$keyword}%";
|
||||
$query->where(function ($q) use ($like) {
|
||||
$q->where('organisations.name', 'like', $like)
|
||||
->orWhere('organisations.phone', 'like', $like)
|
||||
->orWhere('organisations.email', 'like', $like)
|
||||
->orWhere('organisations.status', 'like', $like)
|
||||
->orWhere('organisations.created_at', 'like', $like);
|
||||
});
|
||||
}
|
||||
$paginator = $query->paginate($perPage)->appends($request->except('page'));
|
||||
|
||||
return response()->json($paginator);
|
||||
}
|
||||
|
||||
public function getDealerTransactionsJson(Request $request){
|
||||
$merchant_id = session('merchant.id');
|
||||
// dd($merchant_id);
|
||||
$transactions_arr = \DB::table('merchant_top_ups')
|
||||
->join('merchants', 'merchant_top_ups.merchant_id', '=', 'merchants.id')
|
||||
->join('org_users', 'merchant_top_ups.org_user_id', '=', 'org_users.id')
|
||||
->select('merchants.fullname', 'org_users.phone', 'org_users.name', 'merchant_top_ups.id', 'merchant_top_ups.status', 'merchant_top_ups.amount', 'merchant_top_ups.created_at')
|
||||
->whereRaw('merchant_top_ups.merchant_id = '. $merchant_id)
|
||||
->orderBy('merchant_top_ups.created_at', 'DESC')
|
||||
->paginate(20);
|
||||
|
||||
if($request->has('keyword')){
|
||||
$queries = [];
|
||||
$keyword = $request->keyword;
|
||||
$queries['keyword'] = $keyword;
|
||||
$transactions_arr = \DB::table('merchant_top_ups')
|
||||
->join('merchants', 'merchant_top_ups.merchant_id', '=', 'merchants.id')
|
||||
->join('org_users', 'merchant_top_ups.org_user_id', '=', 'org_users.id')
|
||||
->select('merchants.fullname', 'org_users.phone', 'org_users.name', 'merchant_top_ups.id', 'merchant_top_ups.status', 'merchant_top_ups.amount', 'merchant_top_ups.created_at')
|
||||
->whereRaw("org_users.phone LIKE '%$keyword%' OR org_users.name LIKE '%$keyword%' OR merchants.fullname LIKE '%$keyword%' OR merchant_top_ups.status LIKE '%$keyword%' OR merchant_top_ups.amount LIKE '%$keyword%' OR merchant_top_ups.created_at LIKE '%$keyword%'")
|
||||
->whereRaw('merchant_top_ups.merchant_id = '. $merchant_id)
|
||||
->orderBy('merchant_top_ups.created_at', 'DESC')
|
||||
->paginate(20)->appends($queries);
|
||||
}
|
||||
return response()->json($transactions_arr);
|
||||
}
|
||||
|
||||
|
||||
public function merchant_transactions($merchant){
|
||||
|
||||
$transactions = Models\Transaction::where('merchant_id', $merchant->id)
|
||||
->select('id', 'created_at')->get()
|
||||
->groupBy(function($date) {
|
||||
return Carbon::parse($date->created_at)->format('m'); // grouping by months
|
||||
});
|
||||
$transactionmcount = [];
|
||||
$transactionArr = [];
|
||||
|
||||
|
||||
|
||||
$pp = 1;
|
||||
$trans = [];
|
||||
foreach ($transactions as $value) {
|
||||
if ($pp == $value) {
|
||||
$trans[$pp]= $value;
|
||||
}
|
||||
else{
|
||||
$trans[$pp] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
foreach ($transactions as $key => $value) {
|
||||
$transactionmcount[(int)$key] = count($value);
|
||||
}
|
||||
for($i = 1; $i <= 12; $i++){
|
||||
if(!empty($transactionmcount[$i])){
|
||||
$transactionArr[$i] = $transactionmcount[$i];
|
||||
}else{
|
||||
$transactionArr[$i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$transactions = '';
|
||||
foreach ($transactionArr as $tran) {
|
||||
$transactions = $transactions.','.$tran;
|
||||
}
|
||||
return response()->json(['transactions' => $transactions]);
|
||||
}
|
||||
public function customerTopupStoreOld(Request $request){
|
||||
$this->validate($request, [
|
||||
'phone_number'=> 'required|numeric',
|
||||
'amount' => 'required|numeric|min:1',
|
||||
'merchant_id' => 'required|numeric'
|
||||
]);
|
||||
$phone_number = preg_replace('/\s+/', '', $request->phone_number);
|
||||
$check_phone = $this->validatePhoneNumber($phone_number);
|
||||
if ($check_phone == false) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Invalid phone number!'
|
||||
], 401);
|
||||
}
|
||||
$merchant = Models\Merchant::with('orgInfo')->find($request->merchant_id);
|
||||
if ($merchant == false) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'merchant not found!'
|
||||
], 401);
|
||||
}
|
||||
$difference = $merchant->balance - $request->amount;
|
||||
if ($merchant->balance < $request->amount) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Insufficient balance!'
|
||||
], 401);
|
||||
}
|
||||
$prev_balance = $merchant->balance;
|
||||
$extRefId = uniqid() . '-' . date('YmdHis');
|
||||
$transaction_arr = [
|
||||
'msisdn' => $check_phone,
|
||||
'amount' => $request->amount,
|
||||
'merchant_id' => $merchant->id,
|
||||
'session_id' => $extRefId
|
||||
];
|
||||
// dd($transaction_arr);
|
||||
$trans_result = Models\Transaction::create($transaction_arr);
|
||||
$transaction_id = $trans_result->id;
|
||||
|
||||
$click_params = [
|
||||
"msisdn" => $check_phone,
|
||||
"amount" => $request->amount,
|
||||
"extRefId" => $extRefId
|
||||
];
|
||||
\Log::info($click_params);
|
||||
|
||||
$topup_result = $this->ClickADPHttp($click_params);
|
||||
|
||||
\Log::info($topup_result);
|
||||
|
||||
$this->sendNtfy($topup_result);
|
||||
$topup_result_arr = json_decode($topup_result, TRUE);
|
||||
|
||||
\Log::info($topup_result_arr);
|
||||
if ($topup_result == false) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Top Up Could not be processed at this time. Try again later.'
|
||||
], 401);
|
||||
}
|
||||
$log_data = [
|
||||
'msisdn' => $check_phone,
|
||||
'amount' => $request->tamount,
|
||||
'user_id' => $merchant->id,
|
||||
'merchant_balance' => $merchant->balance,
|
||||
'session_id' => $extRefId,
|
||||
'status' => $topup_result_arr,
|
||||
'network' => 'n.a'
|
||||
];
|
||||
$desc = [
|
||||
'title' =>'customer top up by Merchant ID ' . $merchant->id,
|
||||
'data' => $log_data,
|
||||
'type' => 'merchant',
|
||||
];
|
||||
|
||||
$activity = new ActivityLog;
|
||||
$activity->user_id = $merchant->id;
|
||||
$activity->user_type = 'merchant';
|
||||
$activity->description = json_encode($desc);
|
||||
$activity->save();
|
||||
|
||||
|
||||
if ($topup_result_arr['code'] == 1) {
|
||||
|
||||
$merchant_update = Models\Merchant::find($merchant->id);
|
||||
$merchant_update->balance = $prev_balance - $request->amount;
|
||||
$merchant_update->save();
|
||||
$desc = [
|
||||
'title' =>'Successful customer top up by Merchant ID ' . $merchant->id,
|
||||
'data' => ['previous_balance' => $merchant->balance, 'current_balance' => $merchant->balance - $request->amount],
|
||||
'type' => 'merchant',
|
||||
];
|
||||
#update transactions
|
||||
$transaction = Models\Transaction::find($transaction_id);
|
||||
$transaction->status = $topup_result_arr['message'];
|
||||
$transaction->save();
|
||||
|
||||
$activity = new ActivityLog;
|
||||
$activity->user_id = $merchant->id;
|
||||
$activity->user_type = 'merchant';
|
||||
$activity->description = json_encode($desc);
|
||||
$activity->save();
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Top Up Successfully processed!'
|
||||
], 200);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function customerTopupStore(Request $request){
|
||||
$request->validate([
|
||||
'phone_number' => 'required|string',
|
||||
'amount' => 'required|numeric|min:1',
|
||||
'merchant_id' => 'required|integer|exists:merchants,id'
|
||||
]);
|
||||
|
||||
|
||||
$phone_number = preg_replace('/\s+/', '', $request->phone_number);
|
||||
$check_phone = $this->validatePhoneNumber($phone_number);
|
||||
|
||||
|
||||
if (!$check_phone) {
|
||||
return response()->json(['success' => false, 'message' => 'Invalid phone number!'], 422);
|
||||
}
|
||||
|
||||
$merchant = Models\Merchant::find($request->merchant_id);
|
||||
$country_prefix = substr($check_phone, 0, 3);
|
||||
$country = '';
|
||||
switch ($country_prefix) {
|
||||
case '265':
|
||||
$country = 'MALAWI';
|
||||
break;
|
||||
case '260':
|
||||
$country = 'ZAMBIA';
|
||||
break;
|
||||
|
||||
default:
|
||||
$country = '';
|
||||
break;
|
||||
}
|
||||
if ($merchant->country !== $country) {
|
||||
// find out from team
|
||||
return response()->json(['success' => false, 'message' => 'Country not allowed!'], 400);
|
||||
}
|
||||
$extRefId = uniqid() . '-' . date('YmdHis');
|
||||
$topup_result_arr = null;
|
||||
|
||||
try {
|
||||
$topup_result = DB::transaction(function () use ($request, $check_phone, $extRefId, &$topup_result_arr) {
|
||||
|
||||
|
||||
$merchant = Merchant::lockForUpdate()->find($request->merchant_id);
|
||||
|
||||
if ($merchant->balance < $request->amount) {
|
||||
throw new \Exception('Insufficient balance!', 400);
|
||||
}
|
||||
|
||||
|
||||
$prev_balance = $merchant->balance;
|
||||
$merchant->balance -= $request->amount;
|
||||
$merchant->save();
|
||||
|
||||
|
||||
$transaction = Transaction::create([
|
||||
'msisdn' => $check_phone,
|
||||
'amount' => $request->amount,
|
||||
'merchant_id' => $merchant->id,
|
||||
'session_id' => $extRefId,
|
||||
'status' => 'PENDING'
|
||||
]);
|
||||
|
||||
|
||||
$click_params = [
|
||||
"msisdn" => $check_phone,
|
||||
"amount" => $request->amount,
|
||||
"extRefId" => $extRefId
|
||||
];
|
||||
Log::info('ClickADP Request:', $click_params);
|
||||
|
||||
$api_response = $this->ClickADPHttp($click_params);
|
||||
Log::info('ClickADP Response: ' . $api_response);
|
||||
|
||||
$this->sendNtfy($api_response);
|
||||
$topup_result_arr = json_decode($api_response, true);
|
||||
|
||||
if (!$api_response || !isset($topup_result_arr['code'])) {
|
||||
throw new \Exception('Top Up Could not be processed at this time. Try again later.', 502);
|
||||
}
|
||||
|
||||
if ($topup_result_arr['code'] != 1) {
|
||||
throw new \Exception($topup_result_arr['message'] ?? 'Provider failed to process topup.', 422);
|
||||
}
|
||||
|
||||
$transaction->update(['status' => $topup_result_arr['message'] ?? 'SUCCESS']);
|
||||
|
||||
ActivityLog::create([
|
||||
'user_id' => $merchant->id,
|
||||
'user_type' => 'merchant',
|
||||
'description' => json_encode([
|
||||
'title' => 'Successful customer top up by Merchant ID ' . $merchant->id,
|
||||
'data' => [
|
||||
'msisdn' => $check_phone,
|
||||
'amount' => $request->amount,
|
||||
'previous_balance' => $prev_balance,
|
||||
'current_balance' => $merchant->balance,
|
||||
'session_id' => $extRefId,
|
||||
'status' => $topup_result_arr,
|
||||
'network' => 'n.a'
|
||||
],
|
||||
'type' => 'merchant',
|
||||
])
|
||||
]);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Top Up Successfully processed!'
|
||||
], 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
Log::error('Topup Failed: ' . $e->getMessage());
|
||||
try {
|
||||
ActivityLog::create([
|
||||
'user_id' => $request->merchant_id,
|
||||
'user_type' => 'merchant',
|
||||
'description' => json_encode([
|
||||
'title' => 'Failed customer top up attempt',
|
||||
'error' => $e->getMessage(),
|
||||
'data' => ['msisdn' => $check_phone, 'amount' => $request->amount]
|
||||
])
|
||||
]);
|
||||
|
||||
// $activity = new ActivityLog;
|
||||
// $activity->user_id = $merchant->id;
|
||||
// $activity->user_type = 'merchant';
|
||||
// $activity->description = json_encode($desc);
|
||||
// $activity->save();
|
||||
|
||||
} catch (\Exception $logEx) {
|
||||
Log::error('Failed to write failure activity log: ' . $logEx->getMessage());
|
||||
}
|
||||
|
||||
$code = ($e->getCode() >= 400 && $e->getCode() <= 505) ? $e->getCode() : 500;
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
], $code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Make sure to import your Models and Smsgateway at the top of the file
|
||||
|
||||
public function merchantToDealerRefund(Request $request){
|
||||
$this->validate($request, [
|
||||
'transaction_id' => 'required|string',
|
||||
'reason' => 'required|string',
|
||||
]);
|
||||
$transaction = Models\MerchantTopUp::with('merchantInfo', 'orgInfo')->where('status', 'success')->where('transaction_id', $request->transaction_id)->first();
|
||||
if ($transaction == null) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Transaction not found.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
$dealer = $transaction->orgInfo;
|
||||
|
||||
if ($transaction->merchantInfo->balance < $request->amount) {
|
||||
//ask team to confirm if merchant can have a negative balance
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Insufficient merchant balance to process this refund.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$merchant_name = $transaction->merchantInfo->fullname;
|
||||
$dealer_name = $transaction->orgInfo->name;
|
||||
$merchant = Models\Merchant::find($transaction->merchantInfo->id);
|
||||
$organisation = Models\Organisation::find($transaction->orgInfo->id);
|
||||
try {
|
||||
//todo : remove one of organisation or dealer
|
||||
DB::transaction(function () use ($request, $merchant, $organisation, $dealer, $transaction) {
|
||||
Models\MerchantToDealerRefund::create([
|
||||
'dealer_id' => $transaction->org_user_id,
|
||||
'transaction_id'=> $request->transaction_id,
|
||||
'merchant_id' => $transaction->merchant_id,
|
||||
'amount' => $transaction->amount,
|
||||
'dealer_msisdn' => $transaction->orgInfo->phone,
|
||||
'reason' => $request->reason,
|
||||
]);
|
||||
$merchant->decrement('balance', $transaction->amount);
|
||||
$organisation->increment('balance', $transaction->amount);
|
||||
|
||||
$desc = [
|
||||
'title' => 'Dealer Refund',
|
||||
'data' => "Refunded a dealer with an amount of " . $transaction->amount, // Typo fixed
|
||||
'type' => 'merchant',
|
||||
];
|
||||
|
||||
$activity = new ActivityLog;
|
||||
$activity->user_id = $transaction->merchant_id;
|
||||
$activity->user_type = 'merchant';
|
||||
$activity->description = json_encode($desc);
|
||||
$activity->save();
|
||||
|
||||
$transaction->status = 'refunded';
|
||||
$transaction->save();
|
||||
});
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("API : Refund Transaction Failed: " . $e->getMessage());
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => "API XX Refund Transaction Failed: " . $e->getMessage()
|
||||
], 400);
|
||||
}
|
||||
$msg = "You have successfully refunded a dealer ($dealer_name) with an amount of $transaction->amount.";
|
||||
$dealer_msg = "You have received a refund amount of $transaction->amount from Airtime Merchant ($merchant_name).";
|
||||
|
||||
if (env('APP_ENV') !== 'local') {
|
||||
try {
|
||||
$smsgateway = new Smsgateway;
|
||||
$smsgateway->sendSmsNew($merchant->phone, $msg);
|
||||
$smsgateway->sendSmsNew($organisation->phone, $dealer_msg);
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("API: Failed to send SMS for refund: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
\Log::info("API :" . $msg);
|
||||
\Log::info("API :" . $dealer_msg);
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => "Dealer Refund successfully processed! "
|
||||
], 200);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user