• File: Kyc.php
  • Full Path: /var/www/imaliapi/app/Classes/Kyc.php
  • Date Modified: 12/19/2025 4:07 PM
  • File size: 45.77 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?php


namespace App\Classes;


use App\Bank\Payment;
use App\Credelec;
use App\GeneralAdvice;
use App\Imali\ImaliAccount;
use App\Imali\Transfer;
use App\PeriodCloseStore;
use App\PurchaseVoucher;
use App\Store;
use App\StoreConfig;
use App\User;
use App\UserClient;
use App\Water;
use DateTime;
use DateTimeZone;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use Laravel\Passport\Token;

class Kyc
{
    private function checkUserCredentials($request)
    {

        if (strlen($request->pin) == 3)
            $request->pin = '0' . $request->pin;

        if (strlen($request->pin) == 2)
            $request->pin = '00' . $request->pin;

        if (strlen($request->pin) == 1)
            $request->pin = '000' . $request->pin;

        if ($this->hasPIN($request)) {

            //if ($this->getPinAttempts($request->user()->id) >= 2){
            //  $user = $this->getUser($request->user()->id);
            // $user->status = 0;
            //$user->is_online = 0;
            //    /$user->update();

            // $pushMsgBloqued = "Caro cliente ". $user->name . ",  errou a SENHA 3 vezes. A tua conta está bloqueada. Pra recuperar a tua conta entre em contacto com a nossa linha de atendimento atraves dos  nossos canais digitais, Facebook, Whatsapp ou pelo tefone 846002000.";
            //$pushBodyBloqued = "Caro cliente ". $user->name . ",  a tua conta está bloqueada.";

            //if($user->firebase_token)
            //$this->sendPush($pushBodyBloqued, $pushMsgBloqued, $user->firebase_token);


            //? Update do dispositivo onde esta ser feito o login
            //$last_login = DB::table('user_login_devices')->where('user_id', $user->id)->first();
            //if($last_login)
            //                $t/his->destroyUserAccessToken($last_login->access_token);

            //              return response()->json(['message' => 'Utilizador bloqueado, excedeu o número de tentativas de PIN'], 400);
            //        }

            if (!$this->validatePIN($request->user()->id, $request->pin, $request->user()->pin)) {

                if ($this->getPinAttempts($request->user()->id) > 2) {
                    $user = $this->getUser($request->user()->id);
                    $user->status = 0;
                    $user->is_online = 0;
                    $user->update();


                    $pushMsgBloqued = "Caro cliente " . $user->name . ",  errou a SENHA 3 vezes. A tua conta está bloqueada. Pra recuperar a tua conta entre em contacto com a nossa linha de atendimento atraves dos  nossos canais digitais, Facebook, Whatsapp ou pelo tefone 846002000.";
                    $pushBodyBloqued = "Caro cliente " . $user->name . ",  a tua conta está bloqueada.";

                    if ($user->firebase_token)
                        $this->sendPush($pushBodyBloqued, $pushMsgBloqued, $user->firebase_token);


                    //? Update do dispositivo onde esta ser feito o login
                    $last_login = DB::table('user_login_devices')->where('user_id', $user->id)->first();
                    if ($last_login)
                        $this->destroyUserAccessToken($last_login->access_token);

                    return response()->json(['message' => 'Utilizador bloqueado, excedeu o número de tentativas de PIN'], 400);
                }


                $user = $this->getUser($request->user()->id);

                $pushMsg = "Caro cliente " . $user->name . ",  restam te somente " . (3 - (int)$user->pin_attempts) . " tentativa(s). Se falhares 3 vezes o tem PIN a tua conta será bloqueada.";

                $pushBody = "Caro cliente " . $user->name . ",  a tua conta será bloqueada se digitares o pin incorrecto 3 vezes. Por favor verifique o teu PIN e tenta novamente.";

                if ($user->firebase_token)
                    $this->sendPush($pushBody, $pushMsg, $user->firebase_token);

                return response()->json(['message' => 'Pin Incorrecto, tente novamente'], 400);
            }
        }

        return false;
    }

    private function destroyUserAccessToken($accessToken)
    {
        $token_parts = explode('.', $accessToken);
        $token_header = $token_parts[1];
        $token_header_json = base64_decode($token_header);
        $token_header_array = json_decode($token_header_json, true);
        $token_id = $token_header_array['jti'];


        DB::table('oauth_refresh_tokens')->where('access_token_id', $token_id)->update(['revoked' => true]);

        $token = Token::find($token_id);

        $token->revoke();
    }

    private function getUser($userID)
    {
        return User::findOrFail($userID);
    }

    private function hasPIN($request)
    {
        if ($request->has("pin") && $request->pin != "") return true;
        return false;
    }

    private function pinAttempts($userID)
    {
        $user = $this->getUser($userID);
        $user->pin_attempts = $user->pin_attempts + 1;
        $user->update();
    }

    private function getPinAttempts($userID)
    {
        $user = $this->getUser($userID);
        return $user->pin_attempts;
    }

    private function validatePIN($userID, $pinFornecido, $pinUsuario)
    {

        if (Hash::check($pinFornecido, $pinUsuario)) {
            $user = $this->getUser($userID);
            $user->pin_attempts = 0;
            $user->update();
            return true;
        }

        $this->pinAttempts($userID);

        return false;
    }


    //? Metodo adicionado
    public function checkUserWithdrawall(Request $request)
    {
        //se tem saldo
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', auth('api')->user()->id)
            ->first();

        // return response()->json(['message' => $sender->max_value_operation], 200);

        $userBalance = $sender->balance;
        //$userBalance = $sender->balance - $sender->captive_balance;

        //saldo
        if ($request->amount > $userBalance) {
            return response()->json(['message' => 'Saldo Insuficiente'], 400);
        }

        //conta status
        if ($request->user()->status != 1) {
            return response()->json(['message' => 'Conta Bloqueada, liga para 846002000'], 400);
        }

        //montante a enviar
        if ($sender->balance <= 0) {
            return response()->json(['message' => 'Saldo Negativo ou Zero não permitido'], 400);
        }

        if (!is_numeric($request->amount)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }

        $transferencias = Transfer::query()->where('sender_id', $request->id)->whereYear('created_at', date('Y'))->sum('amount');
        // $pagamentos = Payment::query()->where('sender_id', $request->id)->whereYear('created_at', date('Y'))->sum('amount');

        // somar todos amounts do transferencia, pagamento, withdrawall, carregamento, water, credelec, purshase

        $total = $transferencias;

        if ($total >= $sender->max_value_year) {
            return response()->json(['message' => 'Atingiu o limite anual de transancções'], 400);
        }
        //limite de transacao
        if ($sender->max_value_operation < $request->amount) {
            return response()->json(['message' => 'Limite por transacção ' . $sender->max_value_operation . 'MT', 'INS-1' => 400], 400);
        }

        //wallet_id

        //account_type | client or store
        if (($request->account_type != 'client') || ($request->account_type != 'store')) {
            return response()->json(['message' => 'Cliente inválido'], 400);
        }
    }


    public function checkSender(Request $request)
    {

        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $request->id)
            ->first();

        $receiver = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $request->receiver_id)
            ->select('imali_accounts.*', 'users.name', 'imali_account_configs.*')
            ->first();

        $payments = Transfer::query()
            ->whereDate('created_at', date('Y-m-d'))
            ->where('reciever_id', $request->receiver_id)
            ->count();

        $paymentsUser = Transfer::query()
            ->whereDate('created_at', date('Y-m-d'))
            ->where('reciever_id', '=', $request->id)
            ->count();

        $transferencias = Transfer::query()->where('sender_id', $request->id)->whereYear('created_at', date('Y'))->sum('amount');
        $pagamentos = Payment::query()->where('sender_id', $request->id)->whereYear('created_at', date('Y'))->sum('amount');

        $total = $pagamentos + $transferencias;

        $transferenciasR = Transfer::query()->where('reciever_id', $request->receiver_id)->whereYear('created_at', date('Y'))->sum('amount');
        $pagamentosR = Payment::query()->where('sender_id', $request->receiver_id)->whereYear('created_at', date('Y'))->sum('amount');

        $totalReceiver = $pagamentosR + $transferenciasR;

        if ($request->user()->status != 1) {
            return response()->json(['message' => 'Conta Bloqueada, liga para 846002000'], 400);
        }

        //? Validacao do PIN ****
        $resp = $this->checkUserCredentials($request);
        if ($resp) return $resp;


        if ($request->amount <= 0) {
            return response()->json(['message' => 'Montante Negativo ou Zero não permitido'], 400);
        }

        if (!is_numeric($request->amount)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }

        if ($sender->balance <= 0) {
            return response()->json(['message' => 'Saldo Negativo ou Zero não permitido'], 400);
        }


        if ($totalReceiver >= $receiver->max_value_year) {
            return response()->json(['message' => $receiver->name . ' atingiu o limite anual de transancções'], 400);
        }

        if ($total >= $sender->max_value_year) {
            return response()->json(['message' => 'Atingiu o limite anual de transancções'], 400);
        }

        if ($sender->max_value_operation < $request->amount) {
            //return response()->json(['message' => 'Limite por transacção ' . $sender->max_value_operation .'MT', 'INS-1' => 400], 400);
            return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
        }

        if ($receiver->balance >= $receiver->max_balance) {
            return response()->json(['message' => 'Pagamento Recusado na conta ' . $receiver->name, 'INS-2' => 400], 400);
        }
        if ($payments > $receiver->nr_transaction) {
            return response()->json(['message' => $receiver->name . ' atingiu o limite diário', 'INS-3' => 400], 400);
        }

        if ($paymentsUser > $receiver->nr_transaction) {
            return response()->json(['message' => 'Atingiu o limite diário', 'INS-3' => 400], 400);
        }
    }

    public function checkSenderPayment(Request $request)
    {
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('users.user_id', $request->user()->user_id)
            ->select('imali_accounts.*', 'users.name', 'imali_account_configs.*')
            ->first();


        $getPayment = Payment::query()
            ->where('transaction_id', '=', $request->transaction)
            ->where('status', '=', 'success')
            ->first();

        //if ($request->has("pin") && $request->pin != "") {
        //  if (!Hash::check($request->pin, $request->user()->pin)) {
        //    return response()->json(['message' => 'Pin Incorrecto'], 400);
        // }
        // }

        //? Validacao do PIN ****
        $resp = $this->checkUserCredentials($request);
        if ($resp) return $resp;

        if (!is_numeric($request->amount)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }

        if ($getPayment)
            return response()->json(['message' => trans('transaction_has_been_done')], 400);


        $imali = ImaliAccount::query()->where('user_id', '=', $sender->user_id)->first();

        if ($request->user()->status != 1) {
            return response()->json(['message' => trans('blocked_customer_account')], 400);
        }

        //? Validacao do PIN ****
        // $resp = $this->checkUserCredentials($request);
        // if($resp) return $resp;	

        //if (!is_numeric($request->amount)) {
        //  return response()->json(['message' => 'Montante inválido'], 400);
        //}

        if ($request->amount <= 0) {
            return response()->json(['message' => trans('invalid_amount')], 400);
        }

        if ($imali->balance < $request->amount) {
            return response()->json(['message' => trans('not_enough_funds')], 400);
        }

        $store = Store::query()->where('account_number', $request->account_number)
            ->join('merchant_contracts', 'merchant_contracts.store_id', '=', 'stores.id')
            ->select('merchant_contracts.*')
            ->first();

        if (!$store) return response()->json(['message' => trans('invalid_store')], 400);

        $valorAPagar = $request->amount;

        $taxaDesconto = $valorAPagar * ($store->taxa) / 100;

        $valorMin = $store->min_amount;
        $valorMax = $store->max_amount;

        if ($taxaDesconto < $valorMin) {
            $taxaDesconto = $valorMin;
        }
        if ($taxaDesconto > $valorMax) {
            $taxaDesconto = $valorMax;
        }

        //        if ($taxaDesconto > ($valorAPagar + $sender->taxa)) {
        //            return response()->json(['message' => 'Montante de pagamento, inferior ao recomendado.'], 400);
        //        }

        if ($taxaDesconto > ($valorAPagar - $taxaDesconto)) {
            return response()->json(['message' => 'Montante de pagamento, inferior ao recomendado.'], 400);
        }
        if (0 == ($valorAPagar - $taxaDesconto)) {
            return response()->json(['message' => 'Montante de pagamento, inferior ao recomendado.'], 400);
        }

        if (($valorAPagar - $taxaDesconto) < 0) {
            return response()->json(['message' => 'Montante de pagamento, inferior ao recomendado.'], 400);
        }

        if ($sender->max_value_operation < $request->amount) {
            //return response()->json(['message' => 'Limite por Transacção ' . $sender->max_value_operation .'MT', 'INS-2' => 400], 400);
            return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
        }

        $storeCheck = Store::query()->where('account_number', $request->account_number)->first();

        $payment = Payment::query()
            ->where('sender_id', '=', $request->user()->id)
            ->where('amount', '=', $request->amount)
            ->where('store_id', '=', $storeCheck->id)
            ->get()->last();


        // CHECK STORE CONFIG
        $storeConfig = StoreConfig::query()
            ->where('store_id', '=', $storeCheck->id)
            ->first();

        if ($storeConfig) {
            if ($storeConfig->accept_payment != 1) {
                return response()->json(['message' => 'Neste momento não aceitamos pagamentos'], 400);
            }

            if ($storeConfig->use_period == 1) {

                $lastPeriod = PeriodCloseStore::query()
                    ->leftJoin('stores', 'stores.id', '=', 'period_close_stores.store_id')
                    ->select('period_close_stores.*')
                    ->where('period_close_stores.store_id', '=', $storeCheck->id)
                    ->get()->last();

                if ($lastPeriod) {
                    if ($lastPeriod->status == 'fechado') {
                        return response()->json(['message' => 'Está loja não tem período aberto'], 400);
                    }
                } else {
                    return response()->json(['message' => 'Está loja não tem período aberto'], 400);
                }
            }
        } else {
            return response()->json(['message' => 'Está loja ainda não pode receber pagamentos'], 400);
        }
    }

    public function checkRecharge(Request $request)
    {
        $receiver = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.reference', $request->reference)
            ->select('imali_accounts.*', 'users.name', 'imali_account_configs.*')
            ->first();

        if ($receiver->balance >= $receiver->max_balance) {
            return response()->json(['message' => 'A conta ' . $receiver->account_number . ' referente a ' . $receiver->name . " Atingiu o Saldo Máximo", 'INS-2' => 400], 400);
        }
    }

    public function checkRechargeByBank(array $request) {}

    public function checkSenderKyc() {}

    private function getMinutesFromExpireDateTime($updated_at)
    {
        $now = strtotime("now");
        $timeSmsSent = strtotime($updated_at);
        $pastMinutes = floor(($now - $timeSmsSent) / 60);
        return $pastMinutes;
    }


    public function checkSameTransaction(Request $request, $transaction_type)
    {
        $user =  auth('api')->user();
        $imaliUser = ImaliAccount::query()->where('user_id', auth('api')->user()->id)->first();

        if ($transaction_type === 'vouchers') {

            $voucher = PurchaseVoucher::query()->where('user_id', $imaliUser->user_id)->orderBy('id', 'desc')->first();
            if (!$voucher) return response()->json(['message' => 'Validado com sucesso!'], 200);
            $pastMinutes = $this->getMinutesFromExpireDateTime($voucher->created_at);

            //$message = 'Senhor(a) '. $user->name . ', acaba de efectuar uma compra no valor de ' .$request->amount. ' à '. $pastMinutes . ' minutos. Por favor aguarde 10 minutos para efectuar uma nova transação.';
            $message = 'Olá ' . $user->name . ', acabas de comprar uma recarga no valor de ' . $request->amount . ' à ' . $pastMinutes . ' minutos. Por favor aguarda 10 minutos para fazeres uma nova compra.';

            if (($voucher->vouchervalue == $request->amount) && ($pastMinutes < 10)) return response()->json(['message' => $message], 400);
        }

        if ($transaction_type === 'credelec') {
            $credelec = Credelec::query()->where('user_id', $imaliUser->user_id)->orderBy('id', 'desc')->first();
            if (!$credelec) return response()->json(['message' => 'Validado com sucesso!'], 200);
            $pastMinutes = $this->getMinutesFromExpireDateTime($credelec->created_at);

            if (($credelec->vouchervalue == $request->amount) && ($pastMinutes < 10)) return response()->json(['message' => $message], 400);
        }

        if ($transaction_type === 'water') {

            $water = Water::query()->where('user_id', $imaliUser->user_id)->orderBy('id', 'desc')->first();
            if (!$water) return response()->json(['message' => 'Validado com sucesso!'], 200);
            $pastMinutes = $this->getMinutesFromExpireDateTime($water->created_at);

            if (($water->vouchervalue == $request->amount) && ($pastMinutes < 10)) return response()->json(['message' => $message], 400);
        }

        return response()->json(['message' => 'Validado com sucesso!'], 200);
    }

    public function checkUserForAirTime(Request $request)
    {
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $request->user()->id)
            ->select('imali_accounts.*', 'imali_account_configs.*') // adicionado para controle de Nivel de KYC
            ->first();

        //return $sender;


        if ($request->filled('voucher')) {

            $voucherAmount = intval(preg_replace('/[^0-9]+/', '', $request->voucher), 10);

            //            $amountTotal = $voucherAmount + $sender->taxa;
            //$userBalance = $sender->balance - $sender->captive_balance;
            $userBalance = $sender->balance;

            $totalValor = $voucherAmount + $sender->taxa;

            if (!is_numeric($voucherAmount)) {
                return response()->json(['message' => 'Montante inválido'], 400);
            }

            if ($voucherAmount <= 0) {
                return response()->json(['message' => 'Montante negativo ou zero não permitido'], 400);
            }

            if ($totalValor > $userBalance) {
                return response()->json(['message' => 'Saldo Insuficiente'], 400);
                //                return response()->json(['message' => 'Saldo Insuficiente', 'valorRecarga' => $voucherAmount, 'total' => $totalValor, 'userBalance' => $userBalance, 'balance' => $sender->balance], 400);
            }
        } else {

            $amountTotal = $request->amount + $sender->taxa;
            $userBalance = $sender->balance;
            //$userBalance = $sender->balance - $sender->captive_balance;

            if ($amountTotal > $userBalance) {
                return response()->json(['message' => 'Saldo Insuficiente'], 400);
                //                return response()->json(['message' => 'Saldo Insuficiente', 'userBalance' => $userBalance], 400);
            }
        }


        if ($request->user()->status != 1) {
            return response()->json(['message' => 'Conta Bloqueada, liga para 846002000'], 400);
        }

        //       if ($request->pin != 'vazio') {
        //         if (!Hash::check($request->pin, $sender->pin)) {
        //           return response()->json(['message' => 'Pin Incorrecto do vazio aspas'], 400);
        //     }
        // }
        //return $this->getUser($request->user()->id);

        //? Validacao do PIN ****
        $resp = $this->checkUserCredentials($request);
        if ($resp) return $resp;

        if (!is_numeric($request->amount)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }
        //        if ($sender->balance < 0) {
        //            return response()->json(['message' => 'Saldo inválido'], 400);
        //        }

        if ($sender->max_value_operation < $request->amount) {
            //return response()->json(['message' => 'Limite por Transacção ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
            return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
            //return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation .'MT.' .' Se quiser transacionar valores maiores submete os teus documentos para actualização, clicando no botão ACTUALIZAR DOCUMENTOS disponivel no menu CONTA.', 'INS-2' => 400], 400);
        }

        if ($request->amount <= 0) {
            return response()->json(['message' => 'Montante negativo ou zero não permitido'], 400);
        }

        if ($sender->balance <= 0) {
            return response()->json(['message' => 'Saldo negativo ou zero não permitido'], 400);
        }

        $transacResp = $this->checkSameTransaction($request, 'vouchers');
        if ($transacResp->getStatusCode() == 400) return $transacResp;
    }

    public function checkCredelecAdvice($data)
    {
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $data->user_id)
            ->first();

        $imali = ImaliAccount::query()->where('user_id', $data->user_id)->first();


        $amountTotal = $data->amount + $sender->taxa;
        if ($amountTotal > $sender->balance) {
            return response()->json(['message' => 'Saldo Insuficiente'], 400);
        }
    }

    public function checkUserBuyCredelec(Request $request)
    {
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $request->user()->id)
            ->select('imali_accounts.*', 'imali_account_configs.*') // adicionado para controle de Nivel de KYC
            ->first();

        $amountTotal = $request->amount + $sender->taxa;
        $userBalance = $sender->balance;
        //$userBalance = $sender->balance - $sender->captive_balance;
        //        if ($amountTotal > $sender->balance) {

        if ($request->user()->status != 1) {
            return response()->json(['message' => 'Conta Bloqueada, liga para 846002000'], 400);
        }

        //? Validacao do PIN ****
        $resp = $this->checkUserCredentials($request);
        if ($resp) return $resp;


        if ($request->amount <= 0) {
            return response()->json(['message' => 'Montante Negativo ou Zero não permitido'], 400);
        }

        if ($sender->balance <= 0) {
            return response()->json(['message' => 'Saldo negativo ou zero não permitido'], 400);
        }

        if (!is_numeric($request->amount)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }

        // adicionado para controle de Nivel de KYC
        if ($sender->max_value_operation < $request->amount) {
            //return response()->json(['message' => 'Limite por Transacção ' . $sender->max_value_operation .'MT', 'INS-2' => 400], 400);
            return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
        }

        if ($amountTotal > $userBalance) {
            return response()->json(['message' => 'Saldo Insuficiente'], 400);
        }


        // if ($request->pin != "") {

        //     if (Hash::check($request->pin, $sender->pin)) {
        //     } else {
        //         return response()->json(['message' => 'Pin Incorrecto'], 400);
        //     }
        // }

        // $voucher = Credelec::query()
        //     ->where('user_id', $request->user()->id)
        //     ->whereDate('created_at', '=', 'Y-m-d')
        //     ->where('amount', '=', $request->amount)
        //     ->where('contador', '=', $request->credelec_number)
        //     ->latest()->get()->first();


        // if ($voucher) {

        //    $start_date = new DateTime($voucher->created_at, new DateTimeZone('Africa/Maputo'));
        //    $since_start = $start_date->diff(new DateTime(now(), new DateTimeZone('Africa/Maputo')));
        //    $minutos = 10;

        //    if ($since_start->i <= $minutos) {
        //       return response()->json(['message' => 'Deve esperar ' . $minutos . ' minutos, para voltar a comprar credelec desse montante. Tempo Decorrido ' . $since_start->i . ' minutos'], 400);
        //   }
        // }

        //? Adicionado
        $transacResp = $this->checkSameTransaction($request, 'credelec');
        if ($transacResp->getStatusCode() == 400) return $transacResp;

        //        $credelec = Credelec::query()
        //            ->where('amount', $request->amount)
        //            ->where('contador', $request->credelec_number)
        //            ->where('user_id', $request->user()->id)
        //            ->latest();

        //        $to = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', '2015-5-6 3:30:34');
        //        $from = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', '2015-5-6 3:30:54');


        //        if ($credelec) {
        //            $to = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', $credelec->created_at);
        //            $from = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', now());
        //
        //            $diff_in_minutes = $to->diffInMinutes($from);
        //            if ($diff_in_minutes < $credelec->duration){
        //                return response()->json(['message' => 'Deve esperar 10 minutos, para voltar a comprar credelec de '.$request->amount. ' MT'], 400);
        //            }
        //        }


    }

    public function checkUserBuyZap(Request $request)
    {
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $request->user()->id)
            ->select('imali_accounts.*', 'imali_account_configs.*') // adicionado para controle de Nivel de KYC
            ->first();

        if ($request->user()->status != 1) {
            return response()->json(['message' => 'Conta Bloqueada, liga para 846002000'], 400);
        }

        //? Validacao do PIN ****
        $resp = $this->checkUserCredentials($request);
        if ($resp) return $resp;


        // if ($request->pin != "") {

        //     if (Hash::check($request->pin, $sender->pin)) {
        //     } else {
        //         return response()->json(['message' => 'Pin Incorrecto'], 400);
        //     }
        // }

        $amountTotal = $request->price + $sender->taxa;
        $userBalance = $sender->balance;
        //$userBalance = $sender->balance - $sender->captive_balance;

        if (!is_numeric($request->price)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }

        // adicionado para controle de Nivel de KYC
        if ($sender->max_value_operation < $request->amount) {
            //return response()->json(['message' => 'Limite por Transacção ' . $sender->max_value_operation, 'INS-2' => 400], 400);
            return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
        }

        if ($sender->balance < 0) {
            return response()->json(['message' => 'Saldo inválido'], 400);
        }

        if ($sender->balance <= 0) {
            return response()->json(['message' => 'Saldo negativo ou zero não permitido'], 400);
        }
        if ($request->price <= 0) {
            return response()->json(['message' => 'Montante Negativo ou Zero não Permitido'], 400);
        }


        //        if ($amountTotal > $sender->balance) {
        if ($amountTotal > $userBalance) {
            return response()->json(['message' => 'Saldo Insuficiente'], 400);
        }


        //   $result = GeneralAdvice::query()
        //       ->where('amount', $request->price)
        //       ->where('msno', $request->code)
        //       ->where('user_id', $request->user()->id)
        //       ->where('status', 'open')
        //       ->where('type', 'zap')
        //       ->orderByDesc('created_at')
        //       ->latest()->get()->first();

        ////        $to = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', '2015-5-6 3:30:34');
        ////        $from = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', '2015-5-6 3:30:54');


        //   if ($result) {
        //       $to = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', $result->created_at);
        //       $from = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', now());

        //       $diff_in_minutes = $to->diffInMinutes($from);
        //       if ($diff_in_minutes < $result->duration) {
        //           return response()->json(['message' => 'Deve esperar 5 minutos, para voltar a comprar esse pacote de ' . $request->price . ' MT'], 400);
        //       }
        //   }

        //? Adicionado
        $transacResp = $this->checkSameTransaction($request, 'vouchers');
        if ($transacResp->getStatusCode() == 400) return $transacResp;
    }

    public function checkUserBuyDSTV(Request $request)
    {
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $request->user()->id)
            ->select('imali_accounts.*', 'imali_account_configs.*') // adicionado para controle de Nivel de KYC
            ->first();

        if ($request->user()->status != 1) {
            return response()->json(['message' => 'Conta Bloqueada, liga para 846002000'], 400);
        }

        //? Validacao do PIN ****
        $resp = $this->checkUserCredentials($request);
        if ($resp) return $resp;


        // if ($request->pin != "") {

        //     if (!Hash::check($request->pin, $sender->pin)) {
        //         return response()->json(['message' => 'Pin Incorrecto'], 402);
        //     }
        // }

        $amountTotal = $request->price + $sender->taxa;
        $userBalance = $sender->balance;
        //$userBalance = $sender->balance - $sender->captive_balance;

        if (!is_numeric($request->price)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }
        //        if ($sender->balance < 0) {
        //            return response()->json(['message' => 'Saldo inválido'], 400);
        //        }

        // adicionado para controle de Nivel de KYC
        if ($sender->max_value_operation < $request->amount) {
            //return response()->json(['message' => 'Limite por Transacção ' . $sender->max_value_operation, 'INS-2' => 400], 400);
            return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
        }

        if ($sender->balance <= 0) {
            return response()->json(['message' => 'Saldo negativo ou zero não permitido'], 400);
        }
        if ($request->price <= 0) {
            return response()->json(['message' => 'Montante Negativo ou Zero não Permitido'], 400);
        }


        if ($amountTotal > $userBalance) {
            return response()->json(['message' => 'Saldo Insuficiente'], 400);
        }


        $result = GeneralAdvice::query()
            ->where('amount', $request->price)
            ->where('msno', $request->code)
            ->where('user_id', $request->user()->id)
            ->where('status', 'open')
            ->where('type', 'zap')
            ->orderByDesc('created_at')
            ->latest()->get()->first();


        // $voucher = PurchaseVoucher::query()
        //     ->where('user_id', $request->user()->id)
        ////     ->whereDate('created_at','=' ,'Y-m-d')
        //  ->where('vouchervalue', '=', $request->price)
        //  ->where('vouchername', '=', $request->payment_type . '-' . $request->description)
        //  ->where('vouchercode', '=', $request->customerNumber)
        //  ->latest()->get()->first();


        // if ($voucher) {

        //   $start_date = new DateTime($voucher->created_at, new DateTimeZone('Africa/Maputo'));
        //   $since_start = $start_date->diff(new DateTime(now(), new DateTimeZone('Africa/Maputo')));

        //  $minutos = 10;

        //  if ($since_start->i <= $minutos) {
        //      return response()->json(['message' => 'Deve esperar ' . $minutos . ' minutos, para voltar a comprar esse pacote. Tempo Decorrido ' . $since_start->i . ' minutos'], 400);
        //  }
        // }

        //? Adicionado
        $transacResp = $this->checkSameTransaction($request, 'vouchers');
        if ($transacResp->getStatusCode() == 400) return $transacResp;
    }

    public function checkUserBuyStartimes(Request $request)
    {
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $request->user()->id)
            ->select('imali_accounts.*', 'imali_account_configs.*') // adicionado para controle de Nivel de KYC
            ->first();

        if ($request->user()->status != 1) {
            return response()->json(['message' => 'Conta Bloqueada, liga para 846002000'], 400);
        }

        //? Validacao do PIN ****
        $resp = $this->checkUserCredentials($request);
        if ($resp) return $resp;


        // if ($request->pin != "") {

        //   if (Hash::check($request->pin, $sender->pin)) {
        //   } else {
        //       return response()->json(['message' => 'Pin Incorrecto'], 402);
        //   }
        // }

        $amountTotal = $request->purchaseValue + $sender->taxa;
        $userBalance = $sender->balance;
        // $userBalance = $sender->balance - $sender->captive_balance;

        if (!is_numeric($request->purchaseValue)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }

        // adicionado para controle de Nivel de KYC
        if ($sender->max_value_operation < $request->amount) {
            //return response()->json(['message' => 'Limite por Transacção ' . $sender->max_value_operation, 'INS-2' => 400], 400);
            return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
        }


        if ($sender->balance < 0) {
            return response()->json(['message' => 'Saldo inválido'], 400);
        }

        if ($sender->balance <= 0) {
            return response()->json(['message' => 'Saldo negativo ou zero não permitido'], 400);
        }
        if ($request->purchaseValue <= 0) {
            return response()->json(['message' => 'Montante Negativo ou Zero não Permitido'], 400);
        }


        //        if ($amountTotal > $sender->balance) {
        if ($amountTotal > $userBalance) {
            return response()->json(['message' => 'Saldo Insuficiente'], 400);
        }


        $result = GeneralAdvice::query()
            ->where('amount', $request->purchaseValue)
            ->where('msno', $request->code)
            ->where('user_id', $request->user()->id)
            ->where('status', 'open')
            ->where('type', 'zap')
            ->orderByDesc('created_at')
            ->latest()->get()->first();

        //        $to = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', '2015-5-6 3:30:34');
        //        $from = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', '2015-5-6 3:30:54');


        //  $voucher = PurchaseVoucher::query()
        //    ->where('user_id', $request->user()->id)
        ////      ->whereDate('created_at','=' ,'Y-m-d')
        //    ->where('vouchervalue', '=', $request->purchaseValue)
        //    ->where('vouchername', '=', 'StarTimes-' . $request->productDesc)
        //    ->where('vouchercode', '=', $request->productNumber)
        //    ->latest()->get()->first();


        // if ($voucher) {

        //   $start_date = new DateTime($voucher->created_at, new DateTimeZone('Africa/Maputo'));
        //   $since_start = $start_date->diff(new DateTime(now(), new DateTimeZone('Africa/Maputo')));
        ////        echo $since_start->days.' days total<br>';
        ////         echo $since_start->y.' years<br>';
        ////            echo $since_start->m.' months<br>';
        ////            echo $since_start->d.' days<br>';
        ////            echo $since_start->h.' hours<br>';
        ////            echo $since_start->i.' minutes<br>';
        ////            echo $since_start->s.' seconds<br>';

        //      $minutos = 10;

        //     if ($since_start->i <= $minutos) {
        //         return response()->json(['message' => 'Deve esperar ' . $minutos . ' minutos, para voltar a comprar esse pacote. Tempo Decorrido ' . $since_start->i . ' minutos'], 400);
        //     }
        // }

        //? Adicionado
        $transacResp = $this->checkSameTransaction($request, 'vouchers');
        if ($transacResp->getStatusCode() == 400) return $transacResp;


        //        if ($result) {
        //            $to = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', $result->created_at);
        //            $from = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', now());
        //
        //            $diff_in_minutes = $to->diffInMinutes($from);
        //            if ($diff_in_minutes < $result->duration) {
        //                return response()->json(['message' => 'Deve esperar 5 minutos, para voltar a comprar esse pacote de ' . $request->price . ' MT'], 400);
        //            }
        //        }

    }

    public function checkUserBuyWater(Request $request)
    {
        $sender = ImaliAccount::query()
            ->join('users', 'users.id', '=', 'imali_accounts.user_id')
            ->join('imali_account_configs', 'imali_account_configs.id', '=', 'imali_accounts.imali_account_config')
            ->where('imali_accounts.user_id', $request->user()->id)
            ->select('imali_accounts.*', 'imali_account_configs.*') // adicionado para controle de Nivel de KYC
            ->first();


        if ($request->user()->status != 1) {
            return response()->json(['message' => 'Conta Bloqueada, liga para 846002000'], 400);
        }

        // adicionado para controle de Nivel de KYC
        if ($sender->max_value_operation < $request->amount) {
            //return response()->json(['message' => 'Limite por Transacção ' . $sender->max_value_operation, 'INS-2' => 400], 400);
            return response()->json(['message' => 'Caro cliente só podes transacionar valores até ' . $sender->max_value_operation . 'MT', 'INS-2' => 400], 400);
        }

        //? Validacao do PIN ****
        $resp = $this->checkUserCredentials($request);
        if ($resp) return $resp;


        $amountTotal = $request->purchaseValue + $sender->taxa;
        $userBalance = $sender->balance;
        //$userBalance = $sender->balance - $sender->captive_balance;

        if ($request->purchaseValue <= 0) {
            return response()->json(['message' => 'Montante Negativo ou Zero não permitido'], 400);
        }

        if ($sender->balance <= 0) {
            return response()->json(['message' => 'Montante negativo ou zero não permitido'], 400);
        }

        if (!is_numeric($request->purchaseValue)) {
            return response()->json(['message' => 'Montante inválido'], 400);
        }

        if ($sender->balance < 0) {
            return response()->json(['message' => 'Saldo inválido'], 400);
        }

        if ($amountTotal > $userBalance) {
            return response()->json(['message' => 'Saldo Insuficiente'], 400);
        }

        //? Adicionado
        $transacResp = $this->checkSameTransaction($request, 'water');
        if ($transacResp->getStatusCode() == 400) return $transacResp;
    }

    public function checkEntidadeReferencia(Request $request)
    {
        $amount = ($request->amount) / 100;
        $imali = ImaliAccount::query()
            ->where('reference', '=', $request->reference)
            ->first();
        $userClient = UserClient::query()
            ->where('client_key', '=', $request->apiKey)
            ->first();

        if (!$userClient) {
            return response()->json(['msg' => 'Api key invalida', 'msgtype' => 'E', 'msgid' => 'E003'], 400);
        }
        if (!is_numeric($amount)) {
            return response()->json(['msg' => 'Montante invalido', 'msgtype' => 'E', 'msgid' => 'E007'], 400);
        }

        if ($amount < 10) {
            return response()->json(['msg' => 'Montante invalido', 'msgtype' => 'E', 'msgid' => 'E007'], 400);
        }

        if (!($request->entity === '11900')) {
            return response()->json(['msg' => 'Entidade invalida', 'msgtype' => 'E', 'msgid' => 'E005'], 400);
        }
        if (!$imali) {
            return response()->json(['msg' => 'Referencia invalida', 'msgtype' => 'E', 'msgid' => 'E005'], 400);
        }
        //        if (strlen("" + $request->reference) < 11) {
        //            return response()->json(['msg' => 'A referencia deve ter 11 digitos', 'msgtype' => 'E', 'msgid' => 'E005'], 400);
        //        }
    }


    //? Send Push before PIN error
    private function sendPush($pushBody, $pushMsg, $pushFirebaseToken)
    {

        $notification = array(
            'icon' => 'ic_i_mali_cover',
            'title' => 'PIN incorrecto',
            'body' => $pushBody,
            'click_action' => 'com.imali.payapp.payment_NOTICIA',
            'color' => '#ffffff'
        );

        $data = array(
            'sms' => $pushMsg,
            'route' => 'NOTICIA',
            'terminal' => 'firebase'
        );

        $this->pushNotifification($pushFirebaseToken, $notification, $data);
    }

    public function pushNotifification($token, $notification = array(), $data = array())
    {
        $apiKey = 'AAAA8zVzEPQ:APA91bHl_DXB6UGb_6gZlmFnaLTQoANtX_OBjvl3nOy2bSlnFhxedvk6EhGj7cZoIvmlbKeCnqGxXbuyMH_rEPuhRXvuitXzo6Pfl2TMXLar1PlifXqEhYq6tS55UMrY2Kffzj-P_UH-';
        $fields = array('to' => $token, 'notification' => $notification, 'data' => $data);
        $headers = array('Authorization: key=' . $apiKey, 'Content-Type: application/json');
        $url = 'https://fcm.googleapis.com/fcm/send';

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($fields));
        $result = curl_exec($curl);
        curl_close($curl);

        return json_decode($result, true);
    }
}