<?php namespace App\Http\Controllers; use App\Bank\MasterAccount; use App\Bank\Payment; use App\Classes\GenerateToken; use App\Classes\PushNotification; use App\Classes\SendResponse; use App\Classes\SmsManager; use App\Classes\TransactionGeneration; use App\Classes\UserKyc; use App\Imali\RechargeImaliAccount; use App\ImaliSubAccount; use App\PhoneValidation; use App\SubAccountType; use App\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; class ATSourceController extends Controller { protected SmsManager $smsManager; public function __construct() { $this->smsManager = new SmsManager(); } // Validate ImaliAccount - KRB public function validateImaliAccount(Request $request) { $this->validate( $request, [ 'account_number' => 'required' ], [ 'account_number.required' => [ 'messagePT' => 'Número de conta obrigatorio', 'messageEN' => 'Account number required' ] ] ); $userAccount = User::getAccount($request->account_number); if (!$userAccount) return SendResponse::errorResp404notfound( 'Conta invalida', 'Invalid Account not found' ); $user = User::getUserDetails($userAccount->user_id); if (!($request->has('token') && $request->token)) { $convert = strtotime(date('Y-m-d H:i:s')) + (60 * 5); $duration = date("Y-m-d H:i:s", $convert); $token = new GenerateToken(); $data = ['phone' => $user->phone, 'signature' => $request->signature || '#', 'codigo' => $token->generatePhoneNumberCode()]; $this->smsManager->smsVerifyUser($data); $phone_validation = PhoneValidation::query()->where('phone', $user->phone)->first(); $phone_validation->update(['codigo' => $data['codigo'], 'expire_at' => $duration]); return SendResponse::successResp200( 'Foi enviado um código de validação para o número de telefone usado na criação da conta iMali', 'A validation code has been sent to the phone number used to create the iMali account' ); } else { $convert = strtotime(date('Y-m-d H:i:s')) - (60 * 2); $duration = date("Y-m-d H:i:s", $convert); $phone_validation = PhoneValidation::query() ->where('phone', $user->phone) ->where('codigo', $request->token) ->first(); if (!$phone_validation) return SendResponse::errorResp400( 'Token inválido', 'Invalid Token' ); $is_expired = strtotime($phone_validation->expire_at) - strtotime(date('Y-m-d H:i:s')); if ($is_expired < 0) return SendResponse::errorResp400( 'Token expirado', 'Expired Token' ); $phone_validation->update(['expire_at' => $duration]); return SendResponse::successResp200( 'Número de conta validado com sucesso', 'Account number validated successfully' ); } } // Validate CheckImaliAccount Balance - KRB public function checkImaliSubAccounBalance($sub_account_number) { $is_subAccount = User::is_subAccount($sub_account_number); if (!$is_subAccount) return SendResponse::errorResp400( 'Número de Conta inválido', 'Invalid Account Number' ); $sub_account = ImaliSubAccount::query()->where('account_number', $sub_account_number)->first(); if (!$sub_account) return SendResponse::errorResp404notfound( 'Conta não encontrada', 'Account Not Found' ); $sub_account_type = SubAccountType::query()->where('id', $sub_account->sub_account_types_id)->first(); if ($sub_account_type === null) return SendResponse::errorResp400( 'Tipo de conta inválido', 'Invalid Account Type' ); if ($sub_account_type->type_id != 'BNPL') return SendResponse::errorResp400( 'Tipo de conta inválido', 'Invalid Account Type' ); return SendResponse::successResp200( 'Consulta de saldo efectuado com sucesso', 'Balance successfully consulted', array("balance" => $sub_account->balance) ); } // Get Account Transactions - KRB public function getSubAccountPayments(Request $request, $sub_account_number) { // Definir o tamanho padrão da página se não especificado $size = $request->per_page ?? 5; // Verificar se a subconta fornecida existe $subConta = ImaliSubAccount::where('account_number', $sub_account_number)->first(); if (!$subConta) return SendResponse::errorResp404notfound( 'Número de conta inválido', 'Invalid Account Number' ); $sub_account_type = SubAccountType::query()->where('id', $subConta->sub_account_types_id)->first(); if ($sub_account_type === null) return SendResponse::errorResp400( 'Tipo de conta inválido', 'Invalid Account Type' ); if ($sub_account_type->type_id != 'BNPL') return SendResponse::errorResp400( 'Tipo de conta inválido', 'Invalid Account Type' ); // Obter transações normais $payments = Payment::join('stores', 'stores.id', 'payments.store_id') ->where('sender_account_number', $sub_account_number) ->where('payments.created_at', '>=', $subConta->created_at) ->orderByDesc('payments.created_at') ->select([ 'payments.id', 'transaction_id', 'amount', 'transaction_type', 'transaction_name', // 'estado', // 'payment_type', 'sender_name', 'sender_account_number', // 'sender_card_number', // 'store_id', // 'stores.name as store_name', DB::raw( "CASE WHEN payments.status = 'success' THEN 'Sucesso' WHEN payments.status = 'pending' THEN 'Pendente' WHEN payments.status = 'completed' THEN 'Concluído' WHEN payments.status = 'failed' THEN 'Falhou' ELSE payments.status END as status" ), 'payments.created_at', 'payments.updated_at' ]); // todo -----------------01/05/24 $recharge = RechargeImaliAccount::query() ->join('users', 'users.id', 'recharge_imali_accounts.user_id') ->where('account_reference', $sub_account_number) ->where('recharge_imali_accounts.created_at', '>=', $subConta->created_at) ->select([ 'recharge_imali_accounts.id', 'transaction_id', 'amount', // 'transaction_type', // 'transaction_name', 'recharge_way', 'description', // DB::raw("'TRF. iMali' as description"), // DB::raw("'TRF. iMali' as description"), // 'estado', // 'description as payment_type', 'users.name as sender_name', 'account_reference as sender_account_number', // 'sender_card_number', // 'store_id', // 'stores.name as store_name', // DB::raw("'NULL' as description"), // DB::raw("'NULL' as description"), // DB::raw("'NULL' as description"), 'recharge_imali_accounts.estado as status', 'recharge_imali_accounts.created_at', 'recharge_imali_accounts.updated_at' ]); // todo -----------------01/05/24 $allData = $payments->union($recharge)->orderByDesc('created_at')->paginate($size); // $allData = $payments->union($transfers)->orderByDesc('created_at')->paginate($size); return SendResponse::successResp200( array("data" => $allData) ); } private function validateDepositParams(Request $request) { $this->validate( $request, [ 'account_number' => 'required', 'amount' => 'required|numeric', 'bank_date' => 'required|max:20', 'bank_reference' => 'required|max:12|unique:recharge_imali_accounts', 'lending_type' => 'required|in:BNPL,MICREDIT', 'description' => 'required|max:50', ], [ 'account_number.required' => [ 'messagePT' => 'Número de conta obrigatorio', 'messageEN' => 'Account number required' ], 'amount.required' => [ 'messagePT' => 'Montante obrigatorio', 'messageEN' => 'Amount required' ], 'lending_type.required' => [ 'messagePT' => 'Tipo de empréstimo obrigatorio', 'messageEN' => 'Lending Type required' ], 'lending_type.in' => [ 'messagePT' => 'O Tipo de empréstimo deve ser somente BNPL ou MICREDIT', 'messageEN' => 'The lending_type must be BNPL or MICREDIT only' ], 'bank_date.required' => [ 'messagePT' => 'Data da transacao obrigatorio', 'messageEN' => 'Transaction Date required' ], 'bank_date.max' => [ 'messagePT' => 'A data do Banco so permite ate 20 caracteres', 'messageEN' => 'The Bank date only allows up to 20 characters' ], 'bank_reference.required' => [ 'messagePT' => 'Referencia do Banco obrigatorio', 'messageEN' => 'Bank Reference required' ], 'bank_reference.max' => [ 'messagePT' => 'A Referencia do Banco so permite ate 12 caracteres', 'messageEN' => 'The Bank Reference only allows up to 12 characters' ], 'bank_reference.unique' => [ 'messagePT' => 'A Referencia ja existe', 'messageEN' => 'Dublicate Bank Reference' ], 'description.required' => [ 'messagePT' => 'Descricao obrigatorio', 'messageEN' => 'Description required' ], 'description.max' => [ 'messagePT' => 'A Descricao so permite ate 50 caracteres', 'messageEN' => 'Description only allows up to 50 characters' ], ] ); } private function validateAmount($amount) { if (!is_numeric($amount)) return true; if ($amount <= 0) return true; return false; } // Union Bank Methods public function accountDeposit(Request $request) { $this->validateDepositParams($request); $is_validated = $this->validateAmount($request->amount); if ($is_validated) return SendResponse::errorResp400( 'Montante inválido', 'Invalid Amount' ); $amount = (float)str_replace(',', '.', $request->amount); $real_amount = ($amount / 100); if ($real_amount < 1000) return SendResponse::errorResp400( 'Depósito mínimo da conta e 1000MT', 'Minimum account deposit is 1000MT' ); // recharge_imali_accounts --- table | BNPL,MICREDIT', if ($request->lending_type == 'MICREDIT') { // Deposito na conta iMali return $this->microCreditDeposit($request, $real_amount); } else if ($request->lending_type == 'BNPL') { // Deposito na subconta iMali return $this->buyNowPayLaterDeposit($request, $real_amount); } } private function dataPush($recharge, $request, $user, $account) { return array( 'transaction' => $recharge->transaction_id, 'bank_reference' => $request->bank_reference, 'account_reference' => $account->reference, 'bank_date' => $request->bank_date, 'transaction_id' => $recharge->transaction_id, 'description' => $request->description, 'name' => $user->name, 'amount' => (float)$recharge->amount, 'phone' => $user->phone, 'reference' => (User::is_subAccount($account->account_number) ? $account->account_number : $account->reference), 'data' => date('d-m-Y H:i:s', strtotime($recharge->created_at)), 'created_at' => date('d-m-Y H:i:s', strtotime($recharge->created_at)), 'estado' => $recharge->estado, 'route' => 'RECHARGE_DETAILS', 'recharge_way' => $recharge->recharge_way, 'account_number' => $user->account_number, 'terminal' => 'firebase' ); } private function sendPushAndMessage($recharge, $account, $user, $request) { $push = new PushNotification( 'Empréstimo de ' . $recharge->amount . ' MT', 'Parabéns, recebeste um ' . (User::is_subAccount($account->account_number) ? 'empréstimo' : 'micro-empréstimo') . ' no valor de ' . $recharge->amount . ' MT na tua conta ' . $account->account_number, $user->firebase_token, ); $data = $this->dataPush($recharge, $request, $user, $account); $push->sendPush($data); $this->smsManager->sendSMSForUserRecharge($data); } private function microCreditDeposit(Request $request, $real_amount) { try { //code... DB::beginTransaction(); $is_subAccount = User::is_subAccount($request->account_number); if ($is_subAccount) return SendResponse::errorResp400( 'Número de Conta inválido', 'Invalid Account Number' ); $accountOld = User::getAccount($request->account_number); $account = User::getAccount($request->account_number); if (!$account) return SendResponse::errorResp404notfound( 'Conta não encontrada', 'Account Not Found' ); $user = User::getUserDetails($account->user_id); $total_amount = $real_amount + $user->balance; $resp_kyc = $this->validateMaxBalanceKYC($total_amount, $user->max_balance); if ($resp_kyc && $resp_kyc->getStatusCode() != 200) return $resp_kyc; $transactionString = new TransactionGeneration(); $masterAccount = MasterAccount::find(2); $recharge = RechargeImaliAccount::create([ 'imali_account_id' => $account->id, 'transaction_id' => $transactionString->generateTransaction(), 'bank_reference' => $request->bank_reference, 'bank_date' => $request->bank_date, 'account_reference' => $account->reference, 'description' => $request->description, 'amount' => $real_amount, 'last_balance' => $accountOld->balance, 'balance' => $account->balance + $real_amount, 'recharge_way' => 'BANK', 'estado' => 'sucesso', 'estado_color' => '#388E3C', 'master_account_id' => $masterAccount->id, 'user_id' => $user->id ]); $masterBalance = $masterAccount->balance + $real_amount; $masterAccount->update(['balance' => $masterBalance]); $account->update(['balance' => $account->balance + $real_amount]); $this->sendPushAndMessage($recharge, $account, $user, $request); DB::commit(); return SendResponse::successResp200( 'Depósito do empréstimo efectuado com sucesso', 'Lending deposit made successfully', array("transactionID" => $recharge->transaction_id) ); } catch (\Throwable $th) { DB::rollBack(); Log::info('Error Account Deposit - MICREDIT Union Bank', [ 'content' => $th ]); return SendResponse::warningResp500serverError( 'Erro interno do servidor', 'Internal server error' ); } } private function validateMaxBalanceKYC($total_amount, $user_max_balance) { if ($total_amount > $user_max_balance) return SendResponse::errorResp400( 'Utilizador sem permissão para Depósito', 'User without deposit permission' ); } private function buyNowPayLaterDeposit($request, $real_amount) { try { //code... DB::beginTransaction(); $is_subAccount = User::is_subAccount($request->account_number); if (!$is_subAccount) return SendResponse::errorResp400( 'Número de Conta inválido', 'Invalid Account Number' ); $accountOld = User::getAccount($request->account_number); $account = User::getAccount($request->account_number); if (!$account) return SendResponse::errorResp404notfound( 'Conta não encontrada', 'Account Not Found' ); $sub_account_type = SubAccountType::where('id', $account->sub_account_types_id)->first(); if ($sub_account_type && $sub_account_type->type_id != 'BNPL') return SendResponse::errorResp400( 'A conta informada nao suporta empréstimo', 'The account provided does not support lendings' ); $user = User::getUserDetails($account->user_id, $request->account_number); $total_amount = $real_amount + $user->balance; $resp_kyc = $this->validateMaxBalanceKYC($total_amount, $user->max_balance); if ($resp_kyc && $resp_kyc->getStatusCode() != 200) return $resp_kyc; $transactionString = new TransactionGeneration(); $masterAccount = MasterAccount::find(2); $recharge = RechargeImaliAccount::create([ 'imali_account_id' => $account->id, 'transaction_id' => $transactionString->generateTransaction(), 'bank_reference' => $request->bank_reference, 'bank_date' => $request->bank_date, 'account_reference' => $account->account_number, 'description' => $request->description, 'amount' => $real_amount, 'last_balance' => $accountOld->balance, 'balance' => $account->balance + $real_amount, 'recharge_way' => 'BANK', 'estado' => 'sucesso', 'estado_color' => '#388E3C', 'master_account_id' => $masterAccount->id, 'user_id' => $user->id ]); $masterBalance = $masterAccount->balance + $real_amount; $masterAccount->update(['balance' => $masterBalance]); $account->update(['balance' => $account->balance + $real_amount]); $this->sendPushAndMessage($recharge, $account, $user, $request); DB::commit(); return SendResponse::successResp200( 'Depósito do empréstimo efectuado com sucesso', 'Lending deposit made successfully', array("transactionID" => $recharge->transaction_id) ); } catch (\Throwable $th) { DB::rollBack(); Log::info('Error Account Deposit - BNPL Union Bank', [ 'content' => $th ]); return SendResponse::warningResp500serverError( 'Erro interno do servidor', 'Internal server error', ); } } public function checkClient(Request $request) { $this->validate( $request, [ 'amount' => 'required', 'account_number' => 'required', ], [ 'amount.required' => [ 'messagePT' => 'Montante obrigatorio', 'messageEN' => 'Amount required' ], 'account_number.required' => [ 'messagePT' => 'Número de conta obrigatorio', 'messageEN' => 'account_number required' ], ] ); $is_invalid_amount = $this->validateAmount($request->amount); if ($is_invalid_amount) return SendResponse::errorResp400( 'Montante inválido', 'Invalid Amount' ); $amount = (float)str_replace(',', '.', $request->amount); $real_amount = ($amount / 100); if ($real_amount < 1000) return SendResponse::errorResp400( 'Depósito mínimo da conta e 1000MT', 'Minimum account deposit is 1000MT' ); if (User::is_subAccount($request->account_number)) { $account = User::getAccount($request->account_number); if (!$account) return SendResponse::errorResp404notfound( 'Conta não encontrada', 'Account Not Found', array('data' => null) ); $sub_account_type = SubAccountType::where('id', $account->sub_account_types_id)->first(); if (!$sub_account_type) return SendResponse::errorResp400( 'A conta informada não suporta empréstimo', 'The account provided does not support lendings' ); if ($sub_account_type && $sub_account_type->type_id != 'BNPL') return SendResponse::errorResp400( 'A conta informada não suporta empréstimo', 'The account provided does not support lendings' ); $user = User::getUserDetails($account->user_id, $request->account_number); $total_amount = $real_amount + $user->balance; $resp_kyc = $this->validateMaxBalanceKYC($total_amount, $user->max_balance); if ($resp_kyc && $resp_kyc->getStatusCode() != 200) return $resp_kyc; } else { $account = User::getAccount($request->account_number); if (!$account) return SendResponse::errorResp404notfound( 'Conta não encontrada', 'Account Not Found', array('data' => null) ); $user = User::getUserDetails($account->user_id); $total_amount = $real_amount + $user->balance; $resp_kyc = $this->validateMaxBalanceKYC($total_amount, $user->max_balance); if ($resp_kyc && $resp_kyc->getStatusCode() != 200) return $resp_kyc; } return SendResponse::successResp200( 'Validação efectuada com sucesso', 'Validation completed successfully', array("data" => ['name' => $user->name, 'surname' => $user->last_name, 'account_number' => $user->account_number]) ); } }