<?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])
);
}
}