• File: ATSourceController.php
  • Full Path: /var/www/imaliapi/app/Http/ATSourceController.php
  • Date Modified: 09/26/2024 10:58 PM
  • File size: 23.21 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?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])
        );
    }
}