• File: UserClientController.php
  • Full Path: /var/www/imaliapi/app/Http/Controllers/UserClientController.php
  • Date Modified: 11/04/2025 5:25 PM
  • File size: 174.98 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\GenerateImaliAccount;
use App\Classes\GenerateToken;
use App\Classes\GenerateUserId;
use App\Classes\Kyc;
use App\Classes\PartnerKyc;
use App\Classes\PushNotification;
use App\Classes\Record;
use App\Classes\SendResponse;
use App\Classes\SendSMS;
use App\Classes\SendSMSSislog;
use App\Classes\SmsManager;
use App\Classes\TransactionGeneration;
use App\Classes\UserKyc;
use App\Credelec;
use App\GeneralAdvice;
use App\Imali\ImaliAccount;
use App\Imali\ImaliAccountConfig;
use App\Imali\MerchantAccount;
use App\Imali\MerchantContract;
use App\Imali\RamoActivity;
use App\Imali\RechargeImaliAccount;
use App\Imali\Transfer;
use App\ImaliSubAccount;
use App\PaymentGeneration;
use App\PhoneValidation;
use App\PurchaseVoucher;
use App\Refund;
use App\Store;
use App\StoreAmountGeneration;
use App\User;
use App\UserClient;
use App\UserMobilePhone;
use App\VoucherType;
use App\Water;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
//use DB;
use SoapClient;
use SoapFault;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Spatie\ArrayToXml\ArrayToXml;
use Spatie\Crypto\Rsa\KeyPair;

class UserClientController extends Controller
{

    protected $username;
    protected $password;
    protected $topUpUrl;

    protected $client;
    protected $msid;

    protected $request;
    protected $requestRefund;
    protected $requestRefundConfirm;
    protected $token;
    protected $generatedPayment;

    protected SmsManager $smsManager;


    public function __construct()
    {
        //        TESTE
        $this->username = "TEST_PAYTEK";
        $this->password = "TESTpassPAYtek";
        $this->topUpUrl = 'https://topupretail.com:18880/Service.asmx?wsdl';

        //         PRODUCTION
        //        $this->username = "PAYTEK_PROD";
        //        $this->password = "fs.S}nf4:IGXT|R";
        //        $this->topUpUrl = 'https://topupretail.com:18873/Service.asmx?wsdl';

        $options = array(
            //            'cache_wsdl' => 0,
            //            'trace' => 1,
            'exceptions' => 1,
            'trace' => true,
            'keep_alive' => false,
            'connection_timeout' => 5000,
            'cache_wsdl' => WSDL_CACHE_NONE,
            'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP | SOAP_COMPRESSION_DEFLATE,
            'stream_context' => stream_context_create(array(
                'ssl' => array(
                    'verify_peer' => true,
                    'verify_peer_name' => true,
                    'allow_self_signed' => true,
                    //                    'ciphers'=>'RC4-SHA'
                )
            ))
        );

        // $this->client = new SoapClient($this->topUpUrl, $options);
        // $this->msid = new TransactionGeneration();

        $this->smsManager = new SmsManager();
    }

    public function getLang()
    {
        return response()->json(['message' => trans('not_found_transaction')]);
    }

    public function checkTransactionStatus(Request $request, $transaction)
    {
        return "Chamou método checkTransactionStatus da Pinguim Store";

        $token = str_replace('Bearer ', '', $request->header('authorization'));

        $userClient = UserClient::query()
            ->where('client_key', '=', $token)
            ->first();

        //if(!$userClient){
        //   return response()->json([
        //        'cody' => trans('error')[1]['cody'],
        //        'error' => trans('error')[1]['error'],
        //        'type' => trans('error')[1]['type'],
        //        'message' => "Invalid Client Key",
        //    ], trans('error')[1]['http_code']);
        // }

        $pay = Payment::query()
            ->with(['store', 'customer', 'account'])
            ->where('partner_transaction_id', '=', $transaction)
            ->first();


        if (!$pay) {

            $pay = Payment::query()
                ->with(['store', 'customer', 'account'])
                ->where('transaction_id', '=', $transaction)
                ->first();

            if ($pay) {

                $pay->makeHidden([
                    'id',
                    'qrcode',
                    'firebase_token',
                    'device_name',
                    'store_id',
                    'user_client_id',
                    'updated_at',
                    'imali_account_id',
                    'merchant_id',
                    'sender_id',
                    'store_amount_generation_id',
                    'category_id',
                    'estado',
                    'estado_color',
                    'transaction_id',
                    'token',
                    'token_sent',
                    'used_points',
                    'received_points',
                    'client_id',
                    'payment_type',
                    'amount_debited',
                    'comissao',
                    'payment_id'
                ]);

                if ($pay->customer) {
                    $pay->customer->makeHidden([
                        'id',
                        'status',
                        'profile',
                        'email',
                        'birthday',
                        'balance_visibility',
                        'country_code',
                        'email_verified_at',
                        'session_status',
                        'firebase_token',
                        'user_client_id',
                        'phone_reference',
                        'terminalCompanyName',
                        'terminalChannel',
                        'terminalID',
                        'client_id',
                        'created_at',
                        'updated_at',
                        'info_status',
                        'last_name',
                        'phone',
                        'bi',
                        'update_info_status',
                        'user_update_info_status',
                        'document_id',
                        'photo',
                        'user_id'
                    ]);
                }

                if ($pay->account) {
                    $pay->account->makeHidden([
                        'id',
                        'status',
                        'profile',
                        'email',
                        'birthday',
                        'balance_visibility',
                        'country_code',
                        'email_verified_at',
                        'session_status',
                        'firebase_token',
                        'user_client_id',
                        'phone_reference',
                        'terminalCompanyName',
                        'terminalChannel',
                        'terminalID',
                        'client_id',
                        'created_at',
                        'updated_at',
                        'info_status',
                        'bi',
                        'update_info_status',
                        'user_update_info_status',
                        'document_id',
                        'photo',
                        'user_id',
                        'imali_account_config',
                        'captive_balance',
                        'balance',
                        'points',
                        'reference'
                    ]);
                }

                $pay->store->makeHidden([
                    'id',
                    'qrcode',
                    'firebase_token',
                    'device_name',
                    'store_id',
                    'user_client_id',
                    'created_at',
                    'updated_at',
                    'updated_at',
                    'user_id',
                    'industry_activity',
                    'merchant_contract_id',
                    'merchant_account_id',
                    'longitude',
                    'latitude',
                    'balance',
                    'session_status',
                    'photo',
                    'logo',
                    'status',
                    'email',
                    'qrcode'
                ]);

                if ($userClient->id != $pay->client_id) {
                    return response()->json(['message' => trans('not_allowed_on_store')], 400);

                    //	return response()->json([
                    //        'cody' => trans('error')[3]['cody'],
                    //       'error' => trans('error')[3]['error'],
                    //      'type' => trans('error')[3]['type'],
                    //      'message' => "Not allowed to transact in this store",
                    //  ], trans('error')[3]['http_code']);

                } else {
                    return response()->json($pay);

                    // return response()->json([
                    //     'cody' => trans('success')[0]['cody'],
                    //     'success' => trans('success')[0]['success'],
                    //     'type' => trans('success')[0]['type'],
                    //     'data' => $pay,
                    // ], trans('success')[0]['http_code']);
                }
            } else {

                return response()->json(['message' => trans('not_found_transaction')], 400);

                //return response()->json([
                //    'cody' => trans('error')[3]['cody'],
                //    'error' => trans('error')[3]['error'],
                //    'type' => trans('error')[3]['type'],
                //    'message' => "Transaction not found",
                // ], trans('error')[3]['http_code']);
            }
        } else {

            $pay->makeHidden([
                'id',
                'qrcode',
                'firebase_token',
                'device_name',
                'store_id',
                'user_client_id',
                'updated_at',
                'imali_account_id',
                'merchant_id',
                'sender_id',
                'store_amount_generation_id',
                'category_id',
                'estado',
                'estado_color',
                'transaction_id',
                'token',
                'token_sent',
                'used_points',
                'received_points',
                'client_id',
                'payment_type',
                'amount_debited',
                'comissao',
                'payment_id'
            ]);

            if ($pay->customer) {
                $pay->customer->makeHidden([
                    'id',
                    'status',
                    'profile',
                    'email',
                    'birthday',
                    'balance_visibility',
                    'country_code',
                    'email_verified_at',
                    'session_status',
                    'firebase_token',
                    'user_client_id',
                    'phone_reference',
                    'terminalCompanyName',
                    'terminalChannel',
                    'terminalID',
                    'client_id',
                    'created_at',
                    'updated_at',
                    'info_status',
                    'phone',
                    'last_name',
                    'bi',
                    'update_info_status',
                    'user_update_info_status',
                    'document_id',
                    'photo',
                    'user_id'
                ]);
            }

            if ($pay->account) {
                $pay->account->makeHidden([
                    'id',
                    'status',
                    'profile',
                    'email',
                    'birthday',
                    'balance_visibility',
                    'country_code',
                    'email_verified_at',
                    'session_status',
                    'firebase_token',
                    'user_client_id',
                    'phone_reference',
                    'terminalCompanyName',
                    'terminalChannel',
                    'terminalID',
                    'client_id',
                    'created_at',
                    'updated_at',
                    'info_status',
                    'bi',
                    'update_info_status',
                    'user_update_info_status',
                    'document_id',
                    'photo',
                    'user_id',
                    'imali_account_config',
                    'captive_balance',
                    'balance',
                    'points',
                    'reference'
                ]);
            }

            $pay->store->makeHidden([
                'id',
                'qrcode',
                'firebase_token',
                'device_name',
                'store_id',
                'user_client_id',
                'created_at',
                'updated_at',
                'updated_at',
                'user_id',
                'industry_activity',
                'merchant_contract_id',
                'merchant_account_id',
                'longitude',
                'latitude',
                'balance',
                'session_status',
                'photo',
                'logo',
                'status',
                'email',
                'qrcode'
            ]);

            if ($userClient->id != $pay->client_id) {
                return response()->json(['message' => trans('not_allowed_on_store')], 400);

                //	return response()->json([
                //            'cody' => trans('error')[3]['cody'],
                //            'error' => trans('error')[3]['error'],
                //            'type' => trans('error')[3]['type'],
                //            'message' => "Not allowed to transact in this store.",
                //        ], trans('error')[3]['http_code']);

            } else {
                return response()->json($pay);

                //	return response()->json([
                //            'cody' => trans('success')[0]['cody'],
                //            'success' => trans('success')[0]['success'],
                //            'type' => trans('success')[0]['type'],
                //            'message' => "Transaction found",
                //            'data' => $pay,
                //        ], trans('success')[0]['http_code']);

            }
        }
    }

    public function getTransaction(Request $request, $transaction)
    {
        $token = str_replace('Bearer ', '', $request->header('authorization'));

        $userClient = UserClient::query()
            ->where('client_key', '=', $token)
            ->first();

        $pay = PaymentGeneration::query()
            ->where('payment_generations.partner_transaction_id', '=', $transaction)
            ->first();

        if (!$pay) {
            return response()->json(['message' => trans('not_found_transaction')], 400);
        } else {

            if ($userClient->id != $pay->user_client_id) {
                return response()->json(['message' => trans('not_allowed_on_store')], 400);
            } else {

                $payment = PaymentGeneration::query()
                    ->with(['store', 'customer'])
                    ->where('payment_generations.partner_transaction_id', '=', $transaction)
                    ->get();

                if ($payment) {

                    $payment->makeHidden([
                        'merchant_id',
                        'imali_account_id',
                        'user_id',
                        'token',
                        'user_client_id',
                        'token_sent',
                        'id',
                        'estado_color',
                        'sender_id',
                        'store_id',
                        'client_id',
                        'updated_at',
                        'category_id',
                        'stores.id',
                        'store.status',
                        'store.session_status',
                        'store.firebase_token',
                        'store.user_client_id',
                        'store.merchant_account_id',
                        'store.merchant_contract_id',
                        'store.industry_activity',
                        'store.user_id',
                        'store.created_at',
                        'store.updated_at',
                        'customer.id',
                        'customer.profile',
                        'customer.status',
                        'customer.email',
                        'customer.birthday',
                        'customer.balance_visibility',
                        'customer.country_code',
                        'customer.email_verified_at',
                        'customer.firebase_token',
                        'customer.phone_reference',
                        'customer.terminalCompanyName',
                        'customer.terminalChannel',
                        'customer.terminalID',
                        'customer.client_id',
                        'customer.info_status',
                        'customer.update_info_status',
                        'customer.user_update_info_status',
                        'customer.document_id',
                        'customer.created_at',
                        'customer.updated_at',
                    ]);

                    foreach ($payment as $store) {
                        $store->store->makeHidden(['id', 'status', 'session_status', 'firebase_token', 'user_client_id', 'merchant_account_id', 'merchant_contract_id', 'industry_activity', 'user_id', 'created_at', 'updated_at', 'latitude', 'longitude', 'balance']);
                        $store->customer->makeHidden([
                            'id',
                            'status',
                            'profile',
                            'email',
                            'birthday',
                            'balance_visibility',
                            'country_code',
                            'email_verified_at',
                            'session_status',
                            'firebase_token',
                            'user_client_id',
                            'phone_reference',
                            'terminalCompanyName',
                            'terminalChannel',
                            'terminalID',
                            'client_id',
                            'created_at',
                            'updated_at',
                            'info_status',
                            'update_info_status',
                            'user_update_info_status',
                            'document_id',
                            'photo',
                            'user_id'
                        ]);

                        $store->account->makeHidden(['id', 'points', 'balance', 'captive_balance', 'user_id', 'imali_account_config', 'created_at', 'updated_at']);
                    }

                    return response()->json($payment);
                } else {
                    return response()->json(['message' => trans('not_found_transaction')], 400);
                }
            }
        }
    }



    //? Metodos pagamentos de servico em real-time com BIM


    public function ckeckKYC(Request $request, $user, $paramName)
    {

        //? Validacao do KYC
        $kyc = ImaliAccountConfig::query()->where('id', '=', $user->imali_account_config)->first();

        $amount = $request->get($paramName);
        $amount = (float)str_replace(',', '.', $amount);

        $real_amount = ($amount / 100);
        $total_amount = $real_amount + $user->balance;

        $payments = Payment::query()
            ->join('users', 'users.id', 'payments.sender_id')
            ->join('imali_accounts', 'imali_accounts.user_id', 'users.id')
            ->where('imali_accounts.reference', $request->referenciaDoc)
            ->select('payments.*')
            ->whereDate('payments.created_at', 'LIKE', "%" . date('Y-m-d') . "%")
            ->orderByDesc('created_at')
            ->get();

        $payMent = count($payments);

        $credelec = Credelec::query()
            ->join('users', 'users.id', 'credelecs.user_id')
            ->join('imali_accounts', 'imali_accounts.user_id', 'users.id')
            ->where('imali_accounts.reference', $request->referenciaDoc)
            ->whereDate('credelecs.created_at', 'LIKE', "%" . date('Y-m-d') . "%")
            ->select('credelecs.*')
            ->orderByDesc('created_at')
            ->get();

        $credeleCT = count($credelec);

        $transferenc = Transfer::query()
            ->join('users', 'users.id', 'transfers.sender_id')
            ->join('imali_accounts', 'imali_accounts.user_id', 'users.id')
            ->where('imali_accounts.reference', $request->referenciaDoc)
            ->whereDate('transfers.created_at', 'LIKE', "%" . date('Y-m-d') . "%")
            ->select('transfers.*')
            ->orderByDesc('created_at')
            ->get();

        $transferT = count($transferenc);


        $water = Water::query()
            ->join('users', 'users.id', 'waters.user_id')
            ->join('imali_accounts', 'imali_accounts.user_id', 'users.id')
            ->where('imali_accounts.reference', $request->referenciaDoc)
            ->whereDate('waters.created_at', 'LIKE', "%" . date('Y-m-d') . "%")
            ->select('waters.*')
            ->orderByDesc('created_at')
            ->get();

        $waterT = count($water);


        $voucher = PurchaseVoucher::query()
            ->join('users', 'users.id', 'purchase_vouchers.user_id')
            ->join('imali_accounts', 'imali_accounts.user_id', 'users.id')
            ->where('imali_accounts.reference', $request->referenciaDoc)
            ->whereDate('purchase_vouchers.created_at', 'LIKE', "%" . date('Y-m-d') . "%")
            ->select('purchase_vouchers.*')
            ->orderByDesc('created_at')
            ->get();

        $voucherT = count($voucher);


        $rechargeImali = ImaliAccount::query()
            ->join('users', 'users.id', 'imali_accounts.user_id')
            ->join('recharge_imali_accounts', 'recharge_imali_accounts.imali_account_id', 'imali_accounts.id')
            ->where('imali_accounts.reference', $request->referenciaDoc)
            ->whereDate('recharge_imali_accounts.created_at', 'LIKE', "%" . date('Y-m-d') . "%")
            ->select('imali_accounts.*')
            ->orderByDesc('created_at')
            ->get();

        $rechargeT = count($rechargeImali);


        $carrementosAnuais = RechargeImaliAccount::query()
            ->join('imali_accounts', 'imali_accounts.id', 'recharge_imali_accounts.imali_account_id')
            ->where('imali_accounts.reference', $request->referenciaDoc)
            ->whereYear('recharge_imali_accounts.created_at', 'LIKE', "%" . date('Y') . "%")
            ->select('recharge_imali_accounts.*')
            ->sum('amount');

        $carrementosAnuais += $real_amount;


        $total_transacoes = $payMent + $waterT + $credeleCT + $transferT + $voucherT + $rechargeT;

        //? Validacao do valor maximo por operacao
        if ($kyc->max_value_operation < $real_amount) {
            Log::info('[Error Test Max Operation]', [
                'message' => 'Utilizador sem permissão para pagamento',
            ]);
            return response()->json(['msgid' => 'E002', 'msgtype' => 'E', 'msg' => 'Utilizador sem permissão para pagamento', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado' => 'P002']);
        }

        if ($kyc->min_value_operation > $real_amount) {
            Log::info('[Error Test Min Operation]', [
                'message' => 'Montante Indicado Invalido',
            ]);
            return response()->json(['msgid' => 'E007', 'msgtype' => 'E', 'msg' => 'Montante Indicado Invalido', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado' => 'P002']);
        }

        if ($total_amount > $kyc->max_balance) {
            Log::info('[Error Test Max Balance]', [
                'message' => 'Utilizador sem permissão para pagamento',
            ]);
            return response()->json(['msgid' => 'E002', 'msgtype' => 'E', 'msg' => 'Utilizador sem permissão para pagamento', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado' => 'P002']);
        }

        if ($kyc->nr_transaction <= $total_transacoes) {
            Log::info('[Error Test Total de Transacoes]', [
                'message' => 'Utilizador sem permissão para pagamento',
            ]);
            return response()->json(['msgid' => 'E002', 'msgtype' => 'E', 'msg' => 'Utilizador sem permissão para pagamento', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado' => 'P002']);
        }

        //? Validacao do valor maximo do carregamento Anuais
        if ($kyc->max_value_year < $carrementosAnuais) {
            Log::info('[Error Test Max Valor Anual]', [
                'message' => 'Utilizador sem permissão para pagamento',
            ]);
            return response()->json(['msgid' => 'E002', 'msgtype' => 'E', 'msg' => 'Utilizador sem permissão para pagamento', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado' => 'P002']);
        }


        //? Validacao do valor maximo por operacao
        //if($kyc->max_value_operation < $real_amount) return response()->json(['msgid'=> 'E002', 'msgtype'=> 'E', 'msg'=> 'Utilizador sem permissão para pagamento', 'datadoc'=> date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado'=> 'P002']);

        // if($kyc->min_value_operation > $real_amount) return response()->json(['msgid'=> 'E007', 'msgtype'=> 'E', 'msg'=> 'Montante Indicado Invalido', 'datadoc'=> date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado'=> 'P002']);

        // if($total_amount > $kyc->max_balance) return response()->json(['msgid'=> 'E002', 'msgtype'=> 'E', 'msg'=> 'Utilizador sem permissão para pagamento', 'datadoc'=> date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado'=> 'P002']);

        // if($kyc->nr_transaction <= $total_transacoes) return response()->json(['msgid'=> 'E002', 'msgtype'=> 'E', 'msg'=> 'Utilizador sem permissão para pagamento', 'datadoc'=> date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado'=> 'P002']);

        //? Validacao do valor maximo do carregamento Anuais
        // if($kyc->max_value_year < $carrementosAnuais) return response()->json(['msgid'=> 'E002', 'msgtype'=> 'E', 'msg'=> 'Utilizador sem permissão para pagamento', 'datadoc'=> date('Y-m-d H:i:s'), 'valorTotal' => $request->get($paramName), 'estado'=> 'P002']);

        return false;
    }





    public function checkReference(Request $request)
    {

        try {
            $this->validate($request, [
                'apiKey' => 'required',
                'codigoEntidade' => 'required',
                'referenciaDoc' => 'required',
                'montanteTran' => 'required'
            ]);
        } catch (\Throwable $th) {
            return response()->json(['msgid' => 'E005', 'msgtype' => 'E', 'msg' => 'Parâmetro de entrada invalido', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->montanteTran, 'estado' => 'P002'], 400);
        }

        $amount = $request->montanteTran;
        $amount = (float)str_replace(',', '.', $amount);
        // return $amount;

        $token = str_replace('Bearer ', '', $request->header('authorization'));

        if (!$token && $request->apiKey) {
            $token = $request->apiKey;
        }

        try {
            $partner = UserClient::query()
                ->where('client_key', '=', $token)
                ->first();
        } catch (\Throwable $th) {

            Log::info('[Error Check API Key]', [
                'content' => $th->getMessage(),
            ]);

            return response()->json(['msgid' => 'E002', 'msgtype' => 'E', 'msg' => 'Erro interno de processamento', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $amount, 'estado' => 'P002']);
        }


        if (!$partner) return response()->json(['msgid' => 'E003', 'msgtype' => 'E', 'msg' => 'API Key invalida', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $amount, 'estado' => 'P002']);

        if ($amount < 20) return response()->json(['msgid' => 'E007', 'msgtype' => 'E', 'msg' => 'Montante Indicado Invalido', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $amount, 'estado' => 'P002']);

        //Verificar tamanho da referencia
        if (!is_numeric($request->referenciaDoc) || strlen($request->referenciaDoc) != 11) return response()->json(['msgid' => 'E004', 'msgtype' => 'E', 'msg' => 'A Guia não foi encontrada', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $amount, 'estado' => 'P002']);


        try {
            $user = User::query()
                ->join('imali_accounts', 'imali_accounts.user_id', '=', 'users.id')
                ->where('imali_accounts.reference', $request->referenciaDoc)
                ->select('users.*', 'imali_accounts.imali_account_config', 'imali_accounts.balance')
                ->first();
        } catch (\Throwable $th) {

            Log::info('[Error Getting User]', [
                'content' => $th->getMessage(),
            ]);

            return response()->json(['msgid' => 'E002', 'msgtype' => 'E', 'msg' => 'Erro interno de processamento', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $amount, 'estado' => 'P002']);
        }

        if (!$user) return response()->json(['msgid' => 'E004', 'msgtype' => 'E', 'msg' => 'A Guia não foi encontrada', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $amount, 'estado' => 'P002']);

        //? Validacao do KYC
        //if($this->ckeckKYC($request, $user,'montanteTran')) return $this->ckeckKYC($request, $user,'montanteTran');

        //? Validacao do KYC
        $checked_kyc = $this->ckeckKYC($request, $user, 'montanteTran');
        if ($checked_kyc) return $checked_kyc;

        return response()->json(['msgid' => 'S001', 'msgtype' => 'S', 'msg' => 'Validacao efectuada com sucesso', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $amount, 'estado' => 'P002']);
    }


    //? Metodo para registar o pagamento real-time com BIM
    public function paymentRegister(Request $request)
    {

        try {
            $this->validate($request, [
                'apiKey' => 'required',
                'codigoEntidade' => 'required|integer',
                'referenciaDoc' => 'required',
                'refbancariatran' => 'required',
                'datatransaccao' => 'required',
                'valor' => 'required'
            ]);
        } catch (\Throwable $th) {
            return response()->json(['msgid' => 'E005', 'msgtype' => 'E', 'msg' => 'Parâmetro de entrada invalido', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->valor, 'estado' => 'P002']);
        }

        $token = str_replace('Bearer ', '', $request->header('authorization'));

        if (!$token && $request->apiKey) {
            $token = $request->apiKey;
        }

        try {
            $partner = UserClient::query()
                ->where('client_key', '=', $token)
                ->first();
        } catch (\Throwable $th) {

            Log::info('[Error Check API Key Payment]', [
                'content' => $th->getMessage(),
            ]);

            return response()->json(['msgid' => 'E002', 'msgtype' => 'E', 'msg' => 'Erro interno de processamento', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->valor, 'estado' => 'P002']);
        }

        if (!$partner) return response()->json(['msgid' => 'E003', 'msgtype' => 'E', 'msg' => 'API Key invalida', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->valor, 'estado' => 'P002']);


        //Verificar tamanho da referencia
        if (!is_numeric($request->referenciaDoc) || strlen($request->referenciaDoc) != 11) return response()->json(['msgid' => 'E004', 'msgtype' => 'E', 'msg' => 'A Guia não foi encontrada', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->valor, 'estado' => 'P002']);

        try {
            $user = User::query()
                ->join('imali_accounts', 'imali_accounts.user_id', '=', 'users.id')
                ->where('imali_accounts.reference', $request->referenciaDoc)
                ->select('users.*', 'imali_accounts.imali_account_config', 'imali_accounts.balance', 'imali_accounts.account_number')
                ->first();
        } catch (\Throwable $th) {
            return response()->json(['msgid' => 'E002', 'msgtype' => 'E', 'msg' => 'Erro interno de processamento', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->valor, 'estado' => 'P002']);
        }

        if (!$user) return response()->json(['msgid' => 'E004', 'msgtype' => 'E', 'msg' => 'A Guia não foi encontrada', 'datadoc' => date('Y-m-d H:i:s'), 'valorTotal' => $request->valor, 'estado' => 'P002']);


        //? Validacao do KYC
        //if($this->ckeckKYC($request, $user,'valor')) return $this->ckeckKYC($request, $user,'valor');

        //? Validacao do KYC
        $checked_kyc = $this->ckeckKYC($request, $user, 'valor');
        if ($checked_kyc) return $checked_kyc;

        $amount = $request->valor;
        $amount = (float)str_replace(',', '.', $amount);

        $real_amount = ($amount / 100);

        //?Processo de carregamento

        $imaliAccount = ImaliAccount::query()->where('reference', $request->referenciaDoc)->first();
        $transactionString = new TransactionGeneration();

        if ($imaliAccount) {
            $balanceActual = $imaliAccount->balance + $real_amount;

            $masterAccount = MasterAccount::find(2);
            $recharge = RechargeImaliAccount::create([
                'imali_account_id' => $imaliAccount->id,
                'transaction_id' => $transactionString->generateTransaction(),
                'bank_reference' => $request->refbancariatran,
                'bank_date' => $request->datatransaccao,
                'account_reference' => $request->referenciaDoc,
                'description' => 'Carregamento realtime via BIM',
                'amount' => $real_amount,
                'last_balance' => $imaliAccount->balance,
                'balance' => $balanceActual,
                'recharge_way' => 'MOBILE/INTERNET',
                'estado' => 'sucesso',
                'estado_color' => '#388E3C',
                'master_account_id' => $masterAccount->id
            ]);

            $masterBalance = $masterAccount->balance + $real_amount;

            $masterAccount->update(['balance' => $masterBalance]);

            if ($recharge) {

                $imaliAccount->update(['balance' => $balanceActual]);

                $notification = array(
                    //'icon' => 'ic_i_mali_cover',
                    'icon' => 'ic_imali_logo_verde_01',
                    'title' => 'Carregamento ' . $recharge->amount . ' MT',
                    'body' => 'Parabéns, ' . ' carregaste com ' . $recharge->amount . ' MT ' . ' na sua conta ' . $imaliAccount->account_number,
                    'click_action' => 'com.imali.payapp.payment_RECHARGE_DETAILS',
                    'color' => '#ffffff'
                );

                $data = array(
                    'transaction' => $recharge->transaction_id,
                    'bank_reference' => $request->refbancariatran,
                    'account_reference' => $request->account_reference,
                    'bank_date' => $request->datatransaccao,
                    'description' => $request->description,
                    'name' => $user->name,
                    'amount' => (float)$recharge->amount,
                    'phone' => $user->phone,
                    'reference' => $imaliAccount->reference,
                    'data' => $recharge->created_at,
                    'estado' => $recharge->estado,
                    'route' => 'RECHARGE_DETAILS',
                    'recharge_way' => $recharge->recharge_way,
                    'account_number' => $user->account_number,
                    'terminal' => 'firebase'
                );

                $this->pushNotifification($user->firebase_token, $notification, $data);
                $this->smsManager->sendSMSForUserRecharge($recharge);
            }

            $log = new Record();
            $log->createLog([
                'description' => $imaliAccount->account_number,
                'details' => $user->name . ' ' . $user->last_name,
                'operation' => 'Recharge by Reference',
                'status' => 'success',
                'user_id' => $user->id
            ]);

            if ($recharge) {
                return response()->json(['msgid' => 'S011', 'msgtype' => 'S', 'msg' => 'Pedido processado com sucesso', 'referenciarecibo' => $request->refbancariatran, 'data' => date('Y-m-d H:i:s')]);
            }
        }
    }



    //? Metodos pagamentos de servico em real-time com BIM





    public function getAccount(Request $request)
    {

        return response()->json($request->user()->makeHidden([
            'id',
            'created_at',
            'updated_at',
            'email_verified_at',
            'session_status',
            'url',
            'user_type',
            'client_key',
            'status'
        ]));
    }

    public function getVoucherType()
    {
        $data = VoucherType::query()
            ->where('status', 'disponivel')
            ->where('type', 'recarga')
            ->select('name', 'code', 'type', 'logo', 'created_at', 'updated_at')
            ->get();
        return response()->json(['data' => $data], 200);
    }

    public function getUserVoucher(Request $request)
    {

        $this->validate($request, [
            'accountNumber' => 'required|min:9|max:9'
        ]);

        $token = str_replace('Bearer ', '', $request->header('authorization'));
        $clientStore = UserClient::query()->where('client_key', $token)->first();

        $kyc = new PartnerKyc();

        $result = $kyc->checkImaliAccount($request);

        if ($result) {
            return $result;
        } else {
            $user = User::query()
                ->join('imali_accounts', 'imali_accounts.user_id', '=', 'users.id')
                ->where('imali_accounts.account_number', $request->accountNumber)
                ->select('users.*')
                ->first();

            $data = PurchaseVoucher::query()
                ->where('user_id', $user->id)
                ->where('client_id', $clientStore->id)
                ->orderByDesc('created_at')
                ->get();

            $data->makeHidden(['id', 'user_id', 'client_id', 'voucher_list_id', 'comissao', 'transaction', 'price', 'voucherinfo']);

            return response()->json(['data' => $data], 200);
        }
    }

    public function getVoucherList()
    {
        try {
            $msid = new TransactionGeneration();
            $params = array(
                'req' => array(
                    'authCred' => array(
                        'opName' => $this->username,
                        'password' => $this->password
                    ),
                    'msgID' => $msid->generateMSID(),
                    'terminalID' => 'APP',
                    'terminalMsgID' => '202001070006'
                )
            );
            $data = json_decode(json_encode($params), true);
            $client = new SoapClient($this->topUpUrl, ['trace' => true]);
            $response = $client->VoucherList($data);

            return response()->json(['data' => $response->VoucherListResult->voucherlist->VoucherInfo]);
        } catch (SoapFault $fault) {
            echo '<br>' . $fault;
        }
    }

    public function buyVoucher(Request $request)
    {
        $this->validate($request, [
            'pin' => 'required|min:4|max:4',
            'accountNumber' => 'required',
            'voucher' => 'required',
            'transactionID' => 'required',
            //            'amount' => 'required',
            'terminalID' => 'required',
            'terminalChannel' => 'required',
            'terminalCompanyName' => 'required'
        ], [
            'pin.required' => 'O Pin é Obrigatório',
            'accountNumber.required' => 'O accountNumber é Obrigatório',
            'voucher.required' => 'O voucher é Obrigatório',
            'terminalCompanyName.required' => 'O campo terminalCompanyName é Obrigatório',
            'terminalID.required' => 'terminalID é Obrigatório',
            'terminalChannel.required' => 'terminalChannel é Obrigatório',
        ]);
        $user = User::query()
            ->join('imali_accounts', 'imali_accounts.user_id', '=', 'users.id')
            ->where('imali_accounts.account_number', $request->accountNumber)
            ->first();

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

        try {

            $kyc = new PartnerKyc();

            $result = $kyc->checkPaymentVoucher($request);

            if ($result) {
                return $result;
            } else {
                $msid = new TransactionGeneration();
                //                $transaction = $msid->generateMSID();
                $transaction = $this->msid->generateMSID();

                $params = array(
                    'req' => array(
                        'authCred' => array(
                            'opName' => $this->username,
                            'password' => $this->password
                        ),
                        'terminalMsgID' => '202001070006',
                        //                        'msgID' => $request->transactionID,
                        'msgID' => $transaction,
                        'test' => true,
                        'order' => array(
                            'VoucherOrder' => array(
                                'vouchercode' => $request->voucher,
                                //                                    'vouchercode' => 'VOM000010',
                                'qty' => 1
                            )
                        ),
                        'receiptFormat' => 'POR_FORMATED_50',
                        'terminalChannel' => $request->terminalChannel,
                        'terminalCompanyName' => $request->terminalCompanyName,
                        'terminalID' => $request->terminalID,
                        'terminalOperator' => 'Operator'
                    )
                );
                $data = json_decode(json_encode($params), true);

                $response = $this->client->PurchaseVoucher($data);


                $res = $response->PurchaseVoucherResult;
                $token = str_replace('Bearer ', '', $request->header('authorization'));
                $clientStore = UserClient::query()->where('client_key', $token)->first();

                if ($response->PurchaseVoucherResult->hasFault === false) {
                    $voucher = $response->PurchaseVoucherResult->vouchers->Voucher;
                    $voucherInfo = $response->PurchaseVoucherResult->vouchers->Voucher->voucherinfo;

                    $recarga = PurchaseVoucher::create([
                        //                        'transaction' => $response->transaction,
                        'vouchername' => $voucherInfo->vouchername,
                        'vouchercode' => $voucherInfo->vouchercode,
                        'vouchervalue' => $voucherInfo->vouchervalue,
                        'barcode' => $voucherInfo->barcode,
                        //                            'price' => $voucherInfo->price,
                        'price' => $voucherInfo->vouchervalue,
                        'comissao' => $voucherInfo->vouchervalue - $voucherInfo->price,
                        'reqterminalMsgID' => $res->reqterminalMsgID,
                        'reqterminalID' => $res->reqterminalID,
                        'reqMsgID' => $res->reqMsgID,
                        'respDateTime' => $res->respDateTime,
                        //                        'voucherinfo' => $voucherInfo,
                        'serial' => $voucher->serial,
                        'pin' => $voucher->pin,
                        'datepurchased' => $voucher->datepurchased,
                        'receiptFormat' => $voucher->receiptFormat,
                        'receipt' => $voucher->receipt,
                        'smsreceipt' => $voucher->smsreceipt,
                        'user_id' => $user->id,
                        'voucher_list_id' => null,
                        'type' => 'recarga',
                        'client_id' => $clientStore->id,
                        'terminalChannel' => $request->terminalChannel,
                        'terminalCompanyName' => $request->terminalCompanyName,
                        'terminalID' => $request->terminalID,
                    ]);

                    $imaliUser = ImaliAccount::query()->where('account_number', $request->accountNumber)->first();

                    $totalAmount = $recarga->vouchervalue + $imaliUser->taxa;

                    DB::table('imali_accounts')->where('user_id', $user->id)->decrement('balance', $totalAmount);

                    //                        $sms = new SendSMS();
                    //
                    //                        $sms->sendSMSPurchaseVoucher($response->PurchaseVoucherResult->vouchers->Voucher, $response->PurchaseVoucherResult->vouchers->Voucher->voucherinfo->vouchername, auth()->user()->phone);

                    $notification = array(
                        //'icon' => 'ic_i_mali_cover',
                        'icon' => 'ic_imali_logo_verde_01',
                        'title' => 'iMali recargas',
                        'body' => 'Parabéns, ' . ' comprou recarga ' . $recarga->vouchername . '.' . ' i.Mali é o Futuro',
                        'click_action' => 'com.imali.payapp.payment_RECARGA_NOTIFICATION',
                        'color' => '#ffffff'
                    );

                    $data = array(
                        'reqMsgID' => $recarga->reqMsgID,
                        'vouchername' => $recarga->vouchername,
                        'vouchercode' => (float)$recarga->vouchercode,
                        'data' => $recarga->created_at,
                        'pin' => $recarga->pin,
                        'serial' => $recarga->serial,
                        'price' => $recarga->price,
                        'vouchervalue' => $recarga->vouchervalue,
                        'sms' => $recarga->receipt,
                        'route' => 'RECARGA_NOTIFICATION',
                        'terminal' => 'firebase'
                    );
                    $this->pushNotifification($user->firebase_token, $notification, $data);

                    return response()->json([
                        'message' => 'Compra Feita com Sucesso!',
                        'transaction' => $request->transactionID,
                        //                        'data' => $response->PurchaseVoucherResult,
                        'vouchername' => $voucherInfo->vouchername,
                        'vouchercode' => $voucherInfo->vouchercode,
                        'vouchervalue' => $voucherInfo->vouchervalue,
                        'barcode' => $voucherInfo->barcode,
                        'serial' => $voucher->serial,
                        'pin' => $voucher->pin,
                    ], 200);
                } else {

                    if ($response->PurchaseVoucherResult->fault->mustALR === true) {

                        $imaliUser = ImaliAccount::query()->where('user_id', $user->id)->first();
                        $totalAmount = $request->amount + $imaliUser->taxa;
                        DB::table('imali_accounts')->where('user_id', $user->id)->increment('captive_balance', $totalAmount);

                        //                        return response()->json(['message' => $response->PurchaseVoucherResult], 405);

                        GeneralAdvice::create([
                            'reqMsgID' => $response->PurchaseVoucherResult->reqMsgID,
                            'reqterminalID' => $response->PurchaseVoucherResult->reqterminalID,
                            //                            'receiptFormat' => $response->PurchaseVoucherResult->receiptFormat,
                            'receiptFormat' => 'POR_FORMATED_50',
                            'respDateTime' => $response->PurchaseVoucherResult->respDateTime,
                            'faultNumber' => $response->PurchaseVoucherResult->fault->faultnumber,
                            'user_id' => $user->id,
                            'type' => 'direct',
                            //                            'amount' => $request->voucher . substr(4, 4),
                            'amount' => $request->amount,
                            'message' => $response->PurchaseVoucherResult->fault->POR_operatorMsg,
                            'msno' => $request->voucher,
                            'description' => $request->voucher,
                            'client_id' => $clientStore->id,
                            'terminalChannel' => $request->terminalChannel,
                            'terminalCompanyName' => $request->terminalCompanyName,
                            'terminalID' => $request->terminalID,
                        ]);
                        return response()->json(['message' => $response->PurchaseVoucherResult->fault->POR_operatorMsg], 405);
                    } else {
                        return response()->json(['message' => $response->PurchaseVoucherResult->fault->POR_operatorMsg], 400);
                    }
                }
            }
        } catch (SoapFault $fault) {
            echo '<br>' . $fault;
        }
    }

    public function getUserInfo($accountNumber, Request $request)
    {
        $user = User::query()
            ->join('imali_accounts', 'users.id', '=', 'imali_accounts.user_id')
            ->where('account_number', $accountNumber)
            ->first();

        $user->makeHidden([
            'id',
            'user_id',
            'client_id',
            'profile',
            'status',
            'birthday',
            'bi',
            'terminalID',
            'terminalChannel',
            'terminalCompanyName',
            'email_verified_at',
            'firebase_token',
            'phone_reference',
            'created_at',
            'updated_at',
            'imali_account_config',
            'captive_balance',
            'country_code',
            'photo',
            'email',
            'points',
            'phone',
            'balance_visibility',
            'update_info_status',
            'user_update_info_status',
            'document_id',
            'info_status'
        ]);
        //        $token = str_replace('Bearer ', '', $request->header('authorization'));
        //        $clientStore = UserClient::query()->where('client_key', $token)->first();

        $kyc = new PartnerKyc();

        $result = $kyc->checkImaliAccount($request);

        if ($result) {
            return $result;
        } else {
            return response()->json($user);
        }
    }

    public function IntegrateImaliAccount(Request $request)
    {
        $this->validate($request, [
            'accountNumber' => 'required|min:9|max:9',
            'pin' => 'required|min:4|max:4',
        ]);

        $user = User::query()
            ->join('imali_accounts', 'users.id', '=', 'imali_accounts.user_id')
            ->where('account_number', $request->accountNumber)
            ->first();

        if ($user) {
            if (Hash::check($request->pin, $user->pin)) {
                return response()->json(['message' => 'Conta verificada']);
            } else {
                return response()->json(['message' => 'Pin incorrecto'], 405);
            }
        } else {
            return response()->json(['message' => 'Conta inválida'], 400);
        }
    }

    function saveClientIntegrator(Request $request)
    {
        $this->validate($request, [
            'name' => 'required|min:3|max:50',
            'institution' => 'required|unique:user_clients|min:3',
            'phone' => 'required|unique:user_clients|min:9|integer',
            'email' => 'required|email|unique:user_clients,email',
            'nuit' => 'required|min:9|integer',
            'description' => 'required',
        ], [
            'email.required' => 'O Campo Email é de carácter Obrigatório',
            'email.unique' => 'Este Email já está em uso',
            'phone.required' => 'O Número do celular é obrigatório',
            'phone.unique' => 'O Número do celular já está em uso',
            'phone.min' => 'O Campo Celular deve ter 9 dígitos',
            'name.required' => 'O Campo Nome é obrigatório',
            'institution.required' => 'O Campo Institution é obrigatório',
            'nuit.required' => 'O campo Nuit é Obrigatório',
            'nuit.min' => 'O campo nuit ter 9 dígitos',
            'description.required' => 'O campo descricao é obrigatório',
        ]);

        // NEW 04-September-2024
        [$privateKey, $publicKey] = (new KeyPair())->generate();

        $trasactionGeneration = new TransactionGeneration();

        $client = UserClient::create([
            'name' => $request->name,
            'email' => $request->email,
            'phone' => $request->phone,
            'description' => $request->description,
            'institution' => $request->institution,
            'password' => Hash::make('12345678'),
            'nuit' => $request->nuit,
            'user_type' => $request->user_type,
            'client_id' => $trasactionGeneration->generateCode(),
            'public_key' => $publicKey, // NEW 2024-September-2024
            'private_key' => $privateKey, // NEW 2024-September-2024
        ]);


        $token = $client->createToken('api_token')->plainTextToken;

        $client->update(['client_key' => $token]);

        //        Mail::to($client->email)->send(new ImaliIntegration($client));

        return response()->json(['message' => 'Cliente Integrador Adicionado com Sucesso', 'api_token' => $token]);
    }

    public function saveToken(Request $request)
    {

        $this->validate($request, [
            'client_id' => 'required'
        ]);
        $client = UserClient::find($request->client_id);

        if ($client) {

            $token = $client->createToken('api_token')->plainTextToken;

            UserClient::query()
                ->where('id', '=', $request->client_id)
                ->update(['client_key' => $token]);

            return response()->json(['api_token' => $token]);
        } else {
            return response()->json(['message' => 'Client Not Found'], 400);
        }
    }

    public function getClients()
    {
        $users = UserClient::query()->with(['stores' => function ($query) {
            return $query->leftJoin('admins', 'admins.id', '=', 'stores.user_id')
                ->leftJoin('ramo_activities', 'ramo_activities.id', '=', 'stores.industry_activity')
                ->leftJoin('merchant_contracts', 'stores.merchant_contract_id', '=', 'merchant_contracts.id')
                ->leftJoin('merchant_accounts', 'stores.merchant_account_id', '=', 'merchant_accounts.id')
                ->select(
                    'stores.*',
                    'admins.name as username',
                    'ramo_activities.nome as industry',
                    'merchant_contracts.*',
                    'merchant_accounts.name as merchant_name',
                    'stores.name as store_name',
                    'stores.id as id_store'
                );
        }])->select('user_clients.*', 'user_clients.Institution as institution')->get();

        return response()->json($users);
    }

    public function getStoreQrcode(Request $request, $accountNumber)
    {
        $kyc = new PartnerKyc();
        $checkKyc = $kyc->checkGetTransactions($request, $accountNumber);

        if ($checkKyc) {
            return $checkKyc;
        } else {
            $store = Store::query()
                ->where('account_number', $accountNumber)
                ->select('qrcode', 'public_id')
                ->first();
            return response()->json(['qrcode_url' => $store->qrcode, 'store_reference' => $store->public_id], 200);
        }
    }

    public function QrcodeTransaction(Request $request)
    {
        $this->validate($request, [
            'amount' => 'required',
            'accountNumber' => 'required',
            'transactionID' => 'required|min:12',
            'terminalID' => 'required',
            'terminalChannel' => 'required',
            'terminalCompanyName' => 'required'
        ], [
            'accountNumber.required' => 'O Campo accountNumber é Obrigatório',
            'transactionID.required' => 'O Campo transactionId é Obrigatório',
            'amount.required' => 'O Campo amount é Obrigatório',
            'terminalCompanyName.required' => 'O campo terminalCompanyName é Obrigatório',
            'terminalID.required' => 'terminalID é Obrigatório',
            'terminalChannel.required' => 'terminalChannel é Obrigatório',
        ]);

        $kyc = new PartnerKyc();

        $result = $kyc->checkIntegrador($request);

        if ($result) {
            $log = new Record();
            $log->createLog([
                'description' => 'Gerar Qrcode Partner',
                'details' => $request,
                'operation' => 'Falha',
                'properties' => json_encode($request->all()),
                'origin_request' => $request->url(),
                'origin_ip' => $request->ip(),
                'status' => 'error',
                'user_id' => $request->user()->id
            ]);
            return $result;
        } else {
            $checkStore = Store::query()
                ->join('merchant_accounts', 'merchant_accounts.id', '=', 'stores.merchant_account_id')
                ->where('stores.account_number', $request->accountNumber)
                ->select('stores.*', 'merchant_accounts.institution')
                ->first();
            $token = str_replace('Bearer ', '', $request->header('authorization'));
            $userClient = UserClient::query()->where('client_key', $token)->first();

            if ($checkStore) {
                if (is_numeric($request->amount)) {
                    $res = StoreAmountGeneration::create([
                        'transaction' => \Ramsey\Uuid\Uuid::uuid4(),
                        'partner_transaction_id' => $request->transactionID,
                        'amount' => $request->amount,
                        'store_id' => $checkStore->id,
                        'firebase_token' => $request->firebase_token,
                        'terminalID' => $request->terminalID,
                        'terminalChannel' => $request->terminalChannel,
                        'terminalCompanyName' => $request->terminalCompanyName,
                        'user_client_id' => $userClient->id
                    ]);
                    return response()->json([
                        'message' => 'Transacção Gerada com Sucesso',
                        'amount' => $res->amount,
                        'transaction' => $res->transaction,
                        //                        'transaction' => $res->partner_transaction_id,
                        'account_number' => $checkStore->account_number,
                        'address_store' => $checkStore->address,
                        //                        'duration' => $res->duration,
                        //                        'status' => $res->status,
                        'institution' => $checkStore->institution,
                        'promo' => 'Compra Recargas com Zero Taxas no i.Mali'
                    ], 201);
                } else {
                    return response()->json(['message' => 'Introduza um montante válido'], 407);
                }
            } else
                return response()->json(['message' => 'Loja Inválida'], 404);
        }
    }

    public function Qrcode(Request $request)
    {

        try {
            $this->validate($request, [
                'amount' => 'required',
                'accountNumber' => 'required',
                'transactionID' => 'required|min:12',
                'terminalID' => 'required',
                'terminalChannel' => 'required',
                'terminalCompanyName' => 'required'
            ]);
        } catch (\Throwable $th) {
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => $th->getMessage(),
            ], trans('error')[0]['http_code']);
        }

        //        $this->validate($request, [
        //            'amount' => 'required',
        //            'accountNumber' => 'required',
        //            'transactionID' => 'required|min:12',
        //            'terminalID' => 'required',
        //            'terminalChannel' => 'required',
        //            'terminalCompanyName' => 'required'
        //        ], [
        //            'accountNumber.required' => 'O Campo accountNumber é Obrigatório',
        //            'transactionID.required' => 'O Campo transactionId é Obrigatório',
        //            'amount.required' => 'O Campo amount é Obrigatório',
        //            'terminalCompanyName.required' => 'O campo terminalCompanyName é Obrigatório',
        //            'terminalID.required' => 'terminalID é Obrigatório',
        //            'terminalChannel.required' => 'terminalChannel é Obrigatório',
        //        ]);

        $kyc = new PartnerKyc();

        $result = $kyc->checkIntegrador($request);

        if ($result) {
            $log = new Record();
            $log->createLog([
                'description' => 'Gerar Qrcode Partner',
                'details' => $request,
                'operation' => 'Falha',
                'properties' => json_encode($request->all()),
                'origin_request' => $request->url(),
                'origin_ip' => $request->ip(),
                'status' => 'error',
                'user_id' => $request->user()->id
            ]);
            return $result;
        } else {
            $checkStore = Store::query()
                ->join('merchant_accounts', 'merchant_accounts.id', '=', 'stores.merchant_account_id')
                ->where('stores.account_number', '=', $request->accountNumber)
                ->select('stores.*', 'merchant_accounts.institution')
                ->first();

            $token = str_replace('Bearer ', '', $request->header('authorization'));
            $userClient = UserClient::query()->where('client_key', $token)->first();

            if ($checkStore) {
                if (is_numeric($request->amount)) {
                    $res = Payment::create([
                        //                        'transaction_id' => \Ramsey\Uuid\Uuid::uuid4(),
                        'transaction_id' => $request->transactionID,
                        'partner_transaction_id' => $request->transactionID,
                        'amount' => $request->amount,
                        'store_id' => $checkStore->id,
                        'status' => 'pending',
                        'estado' => 'pending',
                        'firebase_token' => $request->firebase_token,
                        'terminalID' => $request->terminalID,
                        'terminalChannel' => $request->terminalChannel,
                        'terminalCompanyName' => $request->terminalCompanyName,
                        'client_id' => $userClient->id
                    ]);

                    return response()->json([
                        'cody' => trans('success')[1]['cody'],
                        'success' => trans('success')[1]['success'],
                        'type' => trans('success')[1]['type'],
                        'message' => "Transaction created successfully",
                        'amount' => $res->amount,
                        'transaction' => $res->transaction_id,
                        'account_number' => $checkStore->account_number,
                        'address_store' => $checkStore->address,
                        'institution' => $checkStore->institution,
                    ], trans('success')[1]['http_code']);

                    //                    return response()->json([
                    //                        'message' => trans('transaction_generated'),
                    //                        'amount' => $res->amount,
                    //                        'transaction' => $res->transaction_id,
                    //                        'transaction' => $res->partner_transaction_id,
                    //                        'account_number' => $checkStore->account_number,
                    //                        'address_store' => $checkStore->address,
                    //                        'duration' => $res->duration,
                    //                        'status' => $res->status,
                    //                        'institution' => $checkStore->institution,
                    //                        'promo' => trans('promo')], 201);


                } else {
                    //                    return response()->json(['message' => trans('insert_valid_amount')], 407);

                    return response()->json([
                        'cody' => trans('error')[0]['cody'],
                        'error' => trans('error')[0]['error'],
                        'type' => trans('error')[0]['type'],
                        'message' => "Insert a valid amont",
                    ], trans('error')[0]['http_code']);
                }
            } else
                //                return response()->json(['message' => trans('invalid_store')], 404);

                return response()->json([
                    'cody' => trans('error')[3]['cody'],
                    'error' => trans('error')[3]['error'],
                    'type' => trans('error')[3]['type'],
                    'message' => "Store account number not found",
                ], trans('error')[3]['http_code']);
        }
    }

    public function QrcodeStore(Request $request)
    {

        try {
            $this->validate($request, [
                'amount' => 'required',
                // 'accountNumber' => 'required',
                'transactionID' => 'required|min:12',
                // 'terminalID' => 'required',
                'terminalChannel' => 'required',
                'terminalCompanyName' => 'required'
            ]);
        } catch (\Throwable $th) {
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => $th->getMessage(),
            ], trans('error')[0]['http_code']);
        }

        // $kyc = new PartnerKyc();

        // $result = $kyc->checkIntegrador($request);

        // if ($result) {
        //     $log = new Record();
        //     $log->createLog([
        //         'description' => 'Gerar Qrcode Partner',
        //         'details' => $request,
        //         'operation' => 'Falha',
        //         'properties' => json_encode($request->all()),
        //         'origin_request' => $request->url(),
        //         'origin_ip' => $request->ip(),
        //         'status' => 'error',
        //         'user_id' => $request->user()->id
        //     ]);
        //     return $result;
        // } else {
        $checkStore = Store::query()
            ->join('merchant_accounts', 'merchant_accounts.id', '=', 'stores.merchant_account_id')
            // ->where('stores.account_number', '=', $request->accountNumber)
            ->where('stores.id', '=', $request->store_id)
            ->select('stores.*', 'merchant_accounts.institution')
            ->first();

        // $token = str_replace('Bearer ', '', $request->header('authorization'));
        // $userClient = UserClient::query()->where('client_key', $token)->first();

        if ($checkStore) {
            if (is_numeric($request->amount)) {
                $res = Payment::create([
                    'transaction_id' => $request->transactionID,
                    'partner_transaction_id' => $request->transactionID,
                    'amount' => $request->amount,
                    'store_id' => $checkStore->id,
                    'status' => 'pending',
                    'estado' => 'pending',
                    'firebase_token' => $request->firebase_token,
                    'terminalID' => $request->terminalID,
                    'terminalChannel' => $request->terminalChannel,
                    'terminalCompanyName' => $request->terminalCompanyName,
                    // 'client_id' => $userClient->id
                ]);

                return response()->json([
                    'cody' => trans('success')[1]['cody'],
                    'success' => trans('success')[1]['success'],
                    'type' => trans('success')[1]['type'],
                    'message' => "Transaction created successfully",
                    'amount' => $res->amount,
                    'transaction' => $res->transaction_id,
                    'account_number' => $checkStore->account_number,
                    'address_store' => $checkStore->address,
                    'institution' => $checkStore->institution,
                ], trans('success')[1]['http_code']);
            } else {

                return response()->json([
                    'cody' => trans('error')[0]['cody'],
                    'error' => trans('error')[0]['error'],
                    'type' => trans('error')[0]['type'],
                    'message' => "Insert a valid amont",
                ], trans('error')[0]['http_code']);
            }
        } else

            return response()->json([
                'cody' => trans('error')[3]['cody'],
                'error' => trans('error')[3]['error'],
                'type' => trans('error')[3]['type'],
                'message' => "Store account number not found",
            ], trans('error')[3]['http_code']);
        // }///
    }

    public function getBalance($account_number)
    {
        if (is_numeric($account_number)) {
            $userBalance = ImaliAccount::query()
                ->where('account_number', $account_number)
                ->select('balance')
                ->first();

            if ($userBalance) {
                return response()->json($userBalance);
            } else {
                return response()->json(['message' => 'Conta inválida'], 400);
            }
        } else {
            return response()->json(['message' => 'Conta i.Mali contém apenas dígitos numéricos'], 400);
        }
    }

    public function addStoreToUserClient(Request $request)
    {
        $this->validate($request, [
            'store_account_number' => 'required',
            'user_client_id' => 'required',
            //            'id' => 'required',
        ], [
            'account_number.required' => 'campo store_account_number é de carácter obrigatório',
            //            'id.required' => 'Campo id é obrigatório',
            'user_client_id.required' => 'Campo user_client_id é obrigatório',
        ]);
        $store = Store::query()
            ->where('account_number', $request->store_account_number)
            //            ->where('account_number', $request->account_number)
            //            ->where('id', $request->id)
            ->first();

        $checkIntegration = Store::query()
            ->where('account_number', $request->store_account_number)
            ->where('user_client_id', $request->user_client_id)
            ->where('id', $request->id)
            ->first();

        if ($checkIntegration) {
            return response()->json(['message' => 'Está integração já foi feita!'], 400);
        } else {

            if ($store) {
                $store->update([
                    'user_client_id' => $request->user_client_id
                ]);

                return response()->json(['message' => 'Lojá integrada com Sucesso'], 200);
            } else {
                return response()->json(['message' => 'Lojá inválida'], 400);
            }
        }
    }

    public function sendToken(Request $request)
    {
        $this->validate($request, [
            'name' => 'required',
            'phone' => 'required|unique:users|min:9',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|min:8',
            'password_confirmation' => 'required|min:8',
            'terminalID' => 'required',
            //            'country_code' => 'required',
            'terminalChannel' => 'required',
            'terminalCompanyName' => 'required',
        ], [
            'email.required' => 'O Campo Email é de carácter Obrigatório',
            'email.unique' => 'Este Email já está em uso',
            'phone.required' => 'O Número do celular é obrigatório',
            'phone.unique' => 'O Número do celular já está em uso',
            'phone.min' => 'O Campo Celular deve ter 9 dígitos',
            'name.required' => 'O Campo Nome é obrigatório',
            //            'bi.required' => 'O campo Bi é Obrigatório',
            //            'bi.min' => 'O campo Bi ter 13 dígitos',
            'password.required' => 'O Campo Senha é obrigatório',
            'password.confirmed' => 'Senhas incompatíveis',
            'password.min' => 'A senha deve ter 8 digitos no mínimo',
            'terminalChannel.required' => 'terminalChannel é Obrigatório',
            'terminalID.required' => 'terminalID é Obrigatório',
            'terminalCompanyName.required' => 'terminalCompanyName é Obrigatório',
            //            'country_code.required' => 'country_code é Obrigatório'
        ]);

        $token = new GenerateToken();
        $data = ['phone' => $request->country_code . $request->phone, 'codigo' => $token->generatePhoneNumberCode()];
        //        $sms = new  SendSMS();
        //        $sent = $sms->verifyUser($data);
        //        $sislog = new SendSMSSislog();
        //        $sent = $sislog->smsVerifyUser($data);

        //        if ($sent) {

        $validate = PhoneValidation::query()->where('phone', $request->phone)->count();

        if ($validate === 0) {
            $save = PhoneValidation::create([
                'phone' => $request->phone,
                //                'country_code' => $request->country_code,
                'country_code' => +258,
                'expire_at' => now(),
                'duration' => 5,
                'codigo' => $data['codigo'],
                'is_Validated' => 0
            ]);
            if ($save) {
                return response()->json(['codigo' => $data['codigo'], 'message' => 'Codigo de Verificação enviado com sucesso!'], 200);
            }
        } else {
            $validate = PhoneValidation::query()->where('phone', $request->phone)->first();
            $save = $validate->update(['codigo' => $data['codigo']]);
            if ($save) {
                return response()->json(['message' => 'Codigo de Verificação enviado com sucesso!', 'codigo' => $data['codigo']], 200);
            }
        }

        //        }

    }

    public function checkCodigo(Request $request)
    {
        $this->validate($request, [
            'codigo' => 'required',
            'phone' => 'required',
        ], [
            //            'codigo.required' => 'O Campo Email é de carácter Obrigatório',
            //            'phone.required' => 'O Número do celular é obrigatório',
        ]);

        try {
            $validate = PhoneValidation::query()->where('phone', $request->phone)->where('codigo', $request->codigo)->count();
            $getPhone = PhoneValidation::query()->where('phone', $request->phone)->where('codigo', $request->codigo)->first();
            if ($validate > 0) {

                $log = new Record();
                $log->createLog([
                    'description' => $request->phone,
                    'details' => 'Celular Verificado com Successo!',
                    'operation' => 'Check Phone Validation',
                    'status' => 'Success',
                    'user_id' => 1
                ]);
                $getPhone->update(['is_Validated' => 1]);
                return response()->json(['message' => 'Celular Verificado com Successo!'], 200);
            } else {

                $log = new Record();
                $log->createLog([
                    'description' => $request->phone,
                    'details' => 'Código inválido',
                    'operation' => 'Check Phone Validation',
                    'status' => 'Error',
                    'user_id' => 1
                ]);

                return response()->json(['message' => 'Código inválido'], 400);
            }
        } catch (Exception $exception) {
            return response()->json($exception);
        }
    }

    public function registerUser(Request $request)
    {
        $this->validate($request, [
            'name' => 'required',
            'phone' => 'required|unique:users|min:9',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|max:8',
            'pin' => 'required|min:4|max:4',
            'terminalID' => 'required',
            'terminalChannel' => 'required',
            //            'description' => 'required',
            'terminalCompanyName' => 'required',
            //            'bi' => 'required|min:13'
        ], [
            'email.required' => 'O Campo Email é de carácter Obrigatório',
            'email.unique' => 'Este Email já está em uso',
            'phone.required' => 'O Número do celular é obrigatório',
            'phone.unique' => 'O Número do celular já está em uso',
            'phone.min' => 'O Campo Celular deve ter 9 dígitos',
            'name.required' => 'O Campo Nome é obrigatório',
            'bi.required' => 'O campo Bi é Obrigatório',
            'bi.min' => 'O campo Bi ter 13 dígitos',
            'password.required' => 'O Campo Senha é obrigatório',
            'password.confirmed' => 'Senhas incompatíveis',
            'password.min' => 'A senha deve ter 8 digitos no mínimo',
            'terminalChannel.required' => 'terminalChannel é Obrigatório'
        ]);

        $getPhone = PhoneValidation::query()
            ->where('phone', $request->phone)
            ->where('is_Validated', '=', 1)
            ->first();

        if (!$getPhone) {
            return response()->json(['message' => 'O Nr do Celular não confere ou Nr não validado.'], 401);
        }


        $generate = new GenerateUserId();
        $randomString = $generate->generatedUserId(30);


        $user = User::create([
            'firebase_token' => request('firebase_token'),
            'mobile_reference' => request('mobile_reference'),
            'name' => request('name'),
            'email' => request('email'),
            'phone' => request('phone'),
            //            'bi' => request('bi'),
            'pin' => Hash::make(request('pin')),
            'user_id' => $randomString,
            'password' => bcrypt(request('password')),
        ]);

        $mobile = UserMobilePhone::query()
            ->where('user_id', $request->user()->id)
            ->where('firebase_token', $request->firebase_token)
            ->where('mobile_reference', $request->mobile_reference)
            ->first();

        //        if (!$mobile) {
        //            $mobile->create([
        //                'firebase_token' => $request->firebase_token,
        //                'mobile_reference' => $request->mobile_reference,
        //                'user_id' => $user->id
        //            ]);
        //        } else {
        ////            $mobile->create([
        ////                'firebase_token' => $request->firebase_token,
        ////                'mobile_reference' => $request->mobile_reference,
        ////                'user_id' => $user->id
        ////            ]);
        //        }

        $imali = new GenerateImaliAccount();
        $generateImaliAcount = $imali->GenerateImaliAccountNumberAndStore();
        $account = '';
        if ($generateImaliAcount) {
            //            $imaliConfig = ImaliAccountConfig::find(4);
            $imaliConfig = ImaliAccountConfig::query()->first();
            $account = $user->imaliAccount()->create([
                'points' => 0,
                'user_id' => $user->id,
                'imali_account_config' => $imaliConfig->id,
                'account_number' => $generateImaliAcount,
                'reference' => $imali->generateReference(),
                'balance' => 0
            ]);
        }
        return response()->json(['message' => 'Conta Criada com Sucesso', 'accountNumber' => $account->account_number]);
    }

    public function getGeneratedPayments(Request $request, $accountNumber)
    {

        $kyc = new PartnerKyc();
        $checkKyc = $kyc->checkGetTransactions($request, $accountNumber);

        if ($checkKyc) {
            return $checkKyc;
        } else {

            $payments = Payment::query()
                ->join('stores', 'stores.id', '=', 'payments.store_id')
                ->orderByDesc('created_at')
                ->where('stores.account_number', '=', $accountNumber)
                ->whereDate('payments.created_at', '=', date('Y-m-d'))
                ->select('payments.*', 'stores.account_number as store_account_number')
                ->get();


            $payments->makeHidden([
                'id',
                'user_id',
                'imali_account_id',
                'user_client_id',
                'merchant_id',
                'store_id',
                'token',
                'token_sent',
                'duration',
                'updated_at',
                'transaction_id'
            ]);

            return response()->json(['data' => $payments]);
        }
    }

    public function getStorePayments(Request $request, $accountNumber)
    {

        $kyc = new PartnerKyc();
        $checkKyc = $kyc->checkGetTransactions($request, $accountNumber);

        if ($checkKyc) {
            return $checkKyc;
        } else {

            $payment = Payment::query()
                ->join('stores', 'stores.id', '=', 'payments.store_id')
                ->join('users', 'users.id', '=', 'payments.sender_id')
                ->join('imali_accounts', 'imali_accounts.user_id', '=', 'payments.sender_id')
                ->where('payments.client_id', '=', $request->user()->id)
                ->whereDate('payments.created_at', date('Y-m-d'))
                ->orderByDesc('payments.created_at')
                ->select('payments.*', 'stores.name as store_name', 'stores.account_number as store_account_number', 'imali_accounts.account_number as imali_account', 'users.name as imali_username')
                ->get();
            $payment->makeHidden([
                'id',
                'comissao',
                'sender_id',
                'store_id',
                'client_id',
                'category_id',
                'estado_color',
                'updated_at',
                'used_points',
                'received_points'
            ]);

            return response()->json(['data' => $payment]);
        }
    }

    public function getRefunds(Request $request, $accountNumber)
    {
        $kyc = new PartnerKyc();
        $checkKyc = $kyc->checkGetTransactions($request, $accountNumber);

        if ($checkKyc) {
            return $checkKyc;
        } else {

            $payment = Payment::query()
                ->join('stores', 'stores.id', '=', 'payments.store_id')
                ->join('users', 'users.id', '=', 'payments.sender_id')
                ->join('imali_accounts', 'imali_accounts.user_id', '=', 'payments.sender_id')
                ->where('payments.client_id', '=', $request->user()->id)
                ->where('stores.account_number', '=', $accountNumber)
                ->whereDate('payments.created_at', '=', date('Y-m-d'))
                ->where('payments.payment_type', '=', 'refund')
                ->orderByDesc('payments.created_at')
                ->select('payments.*', 'stores.name as store_name', 'stores.account_number as store_account_number', 'imali_accounts.account_number as imali_account', 'users.name as imali_username', 'payments.transaction_id as payment_tarnsaction')
                //                ->paginate(25)
                ->get();

            $payment->makeHidden([
                'id',
                'comissao',
                'sender_id',
                'store_id',
                'client_id',
                'updated_at',
                'merchant_id',
                'imali_user_id',
                'user_client_id',
                'payment_id',
                'estado_color',
                'token',
                'account_number',
                'transaction_id',
                'received_points',
                'used_points',
                'amount_credited',
                'amount_debited',
                'token_sent',
                'estado',
                'duration',
                'firebase_token',
                'qrcode',
                'device_name',
                'imali_account_id',
                'store_amount_generation_id',
                'category_id',
                'payment_tarnsaction'
            ]);

            return response()->json(['data' => $payment]);
        }
    }

    public function generatePayment(Request $request)
    {
        $this->validate($request, [
            'storeAccountNumber' => 'required|min:9',
            'clientAccountNumber' => 'required|min:9',
            'transactionID' => 'required',
            'amount' => 'required',
            'terminalID' => 'required',
            'terminalChannel' => 'required',
            'description' => 'required',
            'terminalCompanyName' => 'required',
        ], []);


        $trasactionGeneration = new TransactionGeneration();
        $kyc = new PartnerKyc();
        //        $checkKyc = $kyc->checkPaymentCliente($request);
        $checkKyc = $kyc->checkPaymentGeneration($request);

        $tokenGeral = '';

        if ($checkKyc) {
            return $checkKyc;
        } else {
            $this->request = $request;

            DB::transaction(function () {

                $store = DB::table('stores')->where('account_number', '=', $this->request->storeAccountNumber)->first();
                $imali = DB::table('imali_accounts')->where('account_number', '=', $this->request->clientAccountNumber)->first();
                $payerUser = DB::table('users')->where('id', $imali->user_id)->first();
                $token = str_replace('Bearer ', '', $this->request->header('authorization'));
                $clientStore = DB::table('user_clients')->where('client_key', $token)->first();

                $user = DB::table('users')->where('id', '=', $imali->user_id)->first();

                $merchant = MerchantAccount::find($store->merchant_account_id);


                $trasactionGeneration = new GenerateToken();
                $tra = new TransactionGeneration();

                $generatedToken = $trasactionGeneration->generatePhoneNumberCode();

                DB::table('payments')->insert([
                    //                    'transaction_id' => $tra->generateTransaction(),
                    'transaction_id' => $this->request->transactionID,
                    'partner_transaction_id' => $this->request->transactionID,
                    //                    'store_account_number' => $this->request->storeAccountNumber,
                    //                    'customer_account_number' => $this->request->clientAccountNumber,
                    'amount' => $this->request->amount,
                    'estado' => 'pending',
                    'status' => 'pending',
                    'description' => $this->request->description,
                    'token' => $generatedToken,
                    'terminalID' => $this->request->terminalID,
                    'terminalChannel' => $this->request->terminalChannel,
                    'terminalCompanyName' => $this->request->terminalCompanyName,
                    'store_id' => $store->id,
                    'merchant_id' => $merchant->id,
                    'client_id' => $clientStore->id,
                    'imali_account_id' => $imali->id,
                    'sender_id' => $imali->user_id,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                $data = ['phone' => $payerUser->phone, 'token' => $generatedToken];

                $this->token = $generatedToken;

                $this->smsManager->tokenPayment($data);
            });

            return response()->json(['message' => trans('otp_sent'), 'otp' => $this->token]);
        }
    }

    //? Gerar um pedido de pagamento 
    //? atraves da notificacao via PUSH

    public function generatePaymentPush(Request $request)
    {
        try {
            $this->validate(
                $request,
                [
                    'storeAccountNumber' => 'required',
                    'clientAccountNumber' => 'required',
                    'transactionID' => 'required',
                    'amount' => 'required',
                    'description' => 'required',
                    'terminalID' => 'required',
                    'terminalChannel' => 'required',
                    'terminalCompanyName' => 'required',
                ],
                [
                    'storeAccountNumber.required' => 'storeAccountNumber is required',

                    'clientAccountNumber.required' => 'clientAccountNumber is required',

                    'transactionID.required' => 'transactionID is required',
                    'amount.required' => 'amount is required',
                    'description.required' => 'description is required',
                    'terminalID.required' => 'terminalID is required',
                    'terminalChannel.required' => 'terminalChannel is required',
                    'terminalCompanyName.required' => 'terminalCompanyName is required'
                ]
            );
        } catch (\Throwable $th) {
            //return response()->json(['error'=> $th->getMessage()], 400);
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => $th->getMessage(),
            ], trans('error')[0]['http_code']);
        }

        if (!is_numeric($request->storeAccountNumber))
            // return response()->json(['error'=> 'storeAccountNumber is numeric'], 400);
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => 'storeAccountNumber is numeric',
            ], trans('error')[0]['http_code']);

        if (strlen($request->storeAccountNumber) != 9)
            //return response()->json(['error'=> 'storeAccountNumber min length is 9'], 400);
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => 'storeAccountNumber min length is 9',
            ], trans('error')[0]['http_code']);

        if (!is_numeric($request->clientAccountNumber))
            //return response()->json(['error'=> 'clientAccountNumber is numeric'], 400);
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => 'clientAccountNumber is numeric',
            ], trans('error')[0]['http_code']);

        if (strlen($request->clientAccountNumber) != 9)
            //return response()->json(['error'=> 'clientAccountNumber min length is 9'], 400);
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => 'clientAccountNumber min length is 9',
            ], trans('error')[0]['http_code']);

        $this->request = $request;
        //? Validacoes
        $token = str_replace('Bearer ', '', $this->request->header('authorization'));
        $clientStore = UserClient::query()->where('client_key', $token)->first();
        if (!$clientStore)
            //return response()->json(['message'=> 'Invalid Client Key', 'error_code'=> 403], 403);
            return response()->json([
                'cody' => trans('error')[2]['cody'],
                'error' => trans('error')[2]['error'],
                'type' => trans('error')[2]['type'],
                'message' => 'Invalid Client Key',
            ], trans('error')[2]['http_code']);

        $store = Store::query()->where('account_number', '=', $this->request->storeAccountNumber)->first();
        if (!$store)
            //return response()->json(['message'=> 'Store not found', 'error_code'=> 404], 404);
            return response()->json([
                'cody' => trans('error')[3]['cody'],
                'error' => trans('error')[3]['error'],
                'type' => trans('error')[3]['type'],
                'message' => 'Store not found',
            ], trans('error')[3]['http_code']);

        //? fazer a verificacao aqui...
        $imali = ImaliAccount::query()
            ->join('users', 'users.id', 'imali_accounts.user_id')
            ->where('imali_accounts.account_number', '=', $this->request->clientAccountNumber)
            ->orWhere('users.phone', '=', $this->request->clientAccountNumber)
            ->select('imali_accounts.*', 'users.phone as phone', 'users.firebase_token', 'users.name as nome', 'imali_accounts.user_id as user_id')
            ->first();

        if (!$imali)
            //return response()->json(['message'=> 'invalid iMali account or phone number', 'error_code'=> 404], 404);
            return response()->json([
                'cody' => trans('error')[3]['cody'],
                'error' => trans('error')[3]['error'],
                'type' => trans('error')[3]['type'],
                'message' => 'invalid iMali account or phone number',
            ], trans('error')[3]['http_code']);

        //? verificar auth
        if (!$imali->firebase_token)
            //return response()->json(['message'=> 'Unauthenticated, firebase token NULL', 'error_code'=> 403], 403);
            return response()->json([
                'cody' => trans('error')[2]['cody'],
                'error' => trans('error')[2]['error'],
                'type' => trans('error')[2]['type'],
                'message' => 'Unauthenticated, firebase token NULL',
            ], trans('error')[2]['http_code']);

        $trasactionGeneration = new TransactionGeneration();
        $kyc = new PartnerKyc();
        //        $checkKyc = $kyc->checkPaymentCliente($request);
        $checkKyc = $kyc->checkPaymentGeneration($request);

        $tokenGeral = '';

        if ($checkKyc) {
            return $checkKyc;
        } else {
            $this->request = $request;

            // DB::transaction(function () {

            // $client = User::query()->where('phone', $this->request->clientAccountNumber)->first();

            // $payerUser = DB::table('users')->where('id', $imali->user_id)->first();


            // $user = DB::table('users')->where('id', '=', $imali->user_id)->first();

            $merchant = MerchantAccount::find($store->merchant_account_id);


            // $trasactionGeneration = new GenerateToken();
            // $tra = new TransactionGeneration();

            DB::table('payments')->insert([
                'transaction_id' => $this->request->transactionID,
                'partner_transaction_id' => $this->request->transactionID,
                'amount' => $this->request->amount,
                'estado' => 'pending',
                'status' => 'pending',
                'description' => $this->request->description,
                'terminalID' => $this->request->terminalID,
                'terminalChannel' => $this->request->terminalChannel,
                'terminalCompanyName' => $this->request->terminalCompanyName,
                'store_id' => $store->id,
                'merchant_id' => $merchant->id,
                'client_id' => $clientStore->id,
                'imali_account_id' => $imali->id,
                'sender_id' => $imali->user_id,
                'created_at' => now(),
                'updated_at' => now(),
            ]);


            $paymentStore = Store::query()
                ->join('payments', 'payments.store_id', '=', 'stores.id')
                ->join('ramo_activities', 'ramo_activities.id', '=', 'stores.industry_activity')
                ->where('payments.transaction_id', '=', $this->request->transactionID)
                ->select(
                    'stores.name',
                    'stores.logo',
                    'stores.mobile_phone',
                    'stores.account_number as storeAccountNumber',
                    'stores.address',
                    'payments.transaction_id as transaction',
                    'payments.amount',
                    'ramo_activities.nome as category',
                    'ramo_activities.logo as logo_category'
                )
                ->first();


            // return $payment;
            $notification = array(
                //'icon' => 'ic_i_mali_cover',
                'icon' => 'ic_imali_logo_verde_01',
                'title' => 'Pagamento iMali : ' . $this->request->transactionID,
                'body' => $this->request->user()->name . ' gerou um pagamento de ' . $this->request->amount . ' MT',
                'click_action' => 'com.imali.payapp.payment_PUSH_NOTIFICATION',
                'color' => '#008577'
            );

            $data = array(
                'transaction' => $request->transactionID,
                'amount' => $request->amount,
                // 'account_number' => $request->clientAccountNumber,
                'account_number' => $paymentStore->storeAccountNumber,
                'name' => $paymentStore->name,
                'address' => $paymentStore->address,
                'mobile_phone' => $paymentStore->mobile_phone,
                //'store_account_number' => $paymentStore->storeAccountNumber,
                'logo' => $paymentStore->logo,
                'logo_category' => $paymentStore->logo_category,
                'category' => $paymentStore->category,
                'description' => $request->description,
                'route' => 'PUSH_NOTIFICATION',
                'created_at' => now()
            );


            $pushNotifi =  $this->pushNotifification($imali->firebase_token, $notification, $data);


            if ((int)$pushNotifi['success'] === 1) {
                $payment = $this->checkTransactionStatus($request, $request->transactionID);

                $paymentStatus = $this->checkSuccessPayment($request, $payment);

                if ($paymentStatus === 'success') {

                    $payment = $this->checkTransactionStatus($request, $request->transactionID);
                    $formatedPayment = array(
                        "partnerTransactionID" => $payment->getData()->partner_transaction_id,
                        "storeAccountNumber" => $request->storeAccountNumber,
                        "customerAccountNumber" => $request->clientAccountNumber,
                        "amount" => $payment->getData()->amount,
                        "status" => $payment->getData()->status,
                        "description" => $payment->getData()->description,
                        "terminalID" => $payment->getData()->terminalID,
                        "terminalChannel" => $payment->getData()->terminalChannel,
                        "terminalCompanyName" => $payment->getData()->terminalCompanyName,
                        "createdAt" => $payment->getData()->created_at
                    );

                    //return response()->json(['message' => trans('payment_done'), 'status'=> 200, 'data'=> $formatedPayment]);
                    return response()->json([
                        'cody' => trans('success')[0]['cody'],
                        'error' => trans('success')[0]['success'],
                        'type' => trans('success')[0]['type'],
                        'message' => 'Payment made successfully',
                        'data' => $formatedPayment
                    ], trans('success')[0]['http_code']);
                };

                if ($paymentStatus === 'rejected') {
                    $payment = $this->checkTransactionStatus($request, $request->transactionID);
                    $formatedPayment = array(
                        "partnerTransactionID" => $payment->getData()->partner_transaction_id,
                        "storeAccountNumber" => $request->storeAccountNumber,
                        "customerAccountNumber" => $request->clientAccountNumber,
                        "amount" => $payment->getData()->amount,
                        "status" => $payment->getData()->status,
                        "description" => $payment->getData()->description,
                        "terminalID" => $payment->getData()->terminalID,
                        "terminalChannel" => $payment->getData()->terminalChannel,
                        "terminalCompanyName" => $payment->getData()->terminalCompanyName,
                        "createdAt" => $payment->getData()->created_at
                    );

                    //return response()->json(['message' => trans('payment_rejected'), 'status'=> 401, 'data'=> $formatedPayment], 406);
                    return response()->json([
                        'cody' => trans('error')[7]['cody'],
                        'error' => trans('error')[7]['error'],
                        'type' => trans('error')[7]['type'],
                        'message' => 'Payment Rejected by User',
                        'data' => $formatedPayment
                    ], trans('error')[7]['http_code']);
                }

                if ($paymentStatus === 'expired') {

                    $payment = $this->checkTransactionStatus($request, $request->transactionID);
                    $formatedPayment = array(
                        "partnerTransactionID" => $payment->getData()->partner_transaction_id,
                        "storeAccountNumber" => $request->storeAccountNumber,
                        "customerAccountNumber" => $request->clientAccountNumber,
                        "amount" => $payment->getData()->amount,
                        "status" => $payment->getData()->status,
                        "description" => $payment->getData()->description,
                        "terminalID" => $payment->getData()->terminalID,
                        "terminalChannel" => $payment->getData()->terminalChannel,
                        "terminalCompanyName" => $payment->getData()->terminalCompanyName,
                        "createdAt" => $payment->getData()->created_at
                    );

                    $clientUser = User::find($request->user()->id);

                    $this->sendPush($clientUser->firebase_token, $data);

                    //return response()->json(['message' => trans('payment_expired'), 'status'=> 401, 'data'=> $formatedPayment], 408);
                    return response()->json([
                        'cody' => trans('error')[4]['cody'],
                        'error' => trans('error')[4]['error'],
                        'type' => trans('error')[4]['type'],
                        'message' => 'Expired Payment',
                        'data' => $formatedPayment
                    ], trans('error')[4]['http_code']);
                }
            } else if ((int)$pushNotifi['failure'] === 1) {

                //return response()->json(['message' => 'Erro ao tentar enviar push de pagamento', 'status'=> 500]);
                return response()->json([
                    'cody' => trans('warning')[0]['cody'],
                    'error' => trans('warning')[0]['warning'],
                    'type' => trans('warning')[0]['type'],
                    'message' => 'Error when trying to send payment push',
                ], trans('warning')[0]['http_code']);

                //? Colocar aqui uma mensagem a informar que o utilizador deve se autenticar na APP
            } else {
                //return response()->json(['message' => 'Erro desconhecido', 'status'=> 500]);
                return response()->json([
                    'cody' => trans('warning')[0]['cody'],
                    'error' => trans('warning')[0]['warning'],
                    'type' => trans('warning')[0]['type'],
                    'message' => 'Unknown error',
                ], trans('warning')[0]['http_code']);
            }
        }
    }




    public function sendPush($firebase_token, $data)
    {
        $notification = array(
            //'icon' => 'ic_i_mali_cover',
            'icon' => 'ic_imali_logo_verde_01',
            // 'title' => 'Pagamento de ' . $this->request->transactionID . ' pendente',
            'title' => 'Pagamento iMali : ',
            'body' =>  ' gerou um pagamento de MT',
            'click_action' => 'com.imali.payapp.payment_TARGET_NOTIFICATION',
            'color' => '#008577'
        );


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


    //? Recusar pagamento por push

    public function denyPaymentPush(Request $request)
    {


        $this->validate($request, [
            'transaction' => 'required',
        ]);

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

        // $PayTransaction = DB::table('payments')->where('partner_transaction_id', $request->transaction)->get();

        $payTransaction = Payment::query()->where('partner_transaction_id', $request->transaction)->first();

        if (($payTransaction && $payTransaction->status === 'rejected') || ($payTransaction && $payTransaction->status === 'expired') || ($payTransaction && $payTransaction->status === 'success')) {

            //return response()->json(['message' => trans('payment_invalid'), 'status'=> 401], 406);
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => trans('payment_invalid'),
            ], trans('error')[0]['http_code']);
        }

        if ($payTransaction) {
            $payTransaction->update([
                'estado' => 'rejected',
                'status' => 'rejected',
                'description' => 'Pagamento rejeitado por ' . $request->user()->name,
                'created_at' => now(),
                'updated_at' => now()
            ]);


            $notification = array(
                //                'icon' => 'ic_i_mali_cover',
                'icon' => 'ic_imali_logo_verde_01',
                'title' => 'Pedido Recusado',
                'body' => $request->user()->name . ' rejeitou pagamento de ' . $payTransaction->amount . ' MT',
                //                'click_action' => 'com.imali.payapp.payment_TARGET_NOTIFICATION',
                'click_action' => 'com.imali.payapp.payment_NOTICIA',
                //                'color' => '#008577'
                'color' => '#fff'
            );


            $data = array(
                'id' => $payTransaction->id,
                'name' => $request->user()->name,
                'client_id' => $payTransaction->client_id,
                'user_id' => $request->user()->id,
                'amount' => $payTransaction->amount,
                'account_number' => $imali->account_number,
                'sms' => $request->user()->name . ' rejeitou pagamento de ' . $payTransaction->amount . ' MT',
                'phone' => $request->user()->phone,
                'description' => $payTransaction->description,
                'route' => 'NOTICIA',
                'terminal' => 'firebase'
            );


            $clientUser = User::find($request->user()->id);

            $this->pushNotifification($clientUser->firebase_token, $notification, $data);

            //return response()->json(['message' => trans('payment_rejected'), 'status'=> 200]);
            return response()->json([
                'cody' => trans('success')[0]['cody'],
                'error' => trans('success')[0]['success'],
                'type' => trans('success')[0]['type'],
                'message' => trans('payment_rejected'),
            ], trans('success')[0]['http_code']);
        }
    }


    public function checkSuccessPayment($request, $payment)
    {

        $payment = $this->checkTransactionStatus($request, $request->transactionID);

        $payTransaction2 = Payment::query()->where('partner_transaction_id', $request->transactionID)->first();

        if ($payment->getData()->status === "pending") {

            $diffTime = (int) (time() - strtotime($payment->getData()->created_at));

            // Delay da transacao 40 secundos
            if ($diffTime >= 40) {
                $payTransaction2->update([
                    'estado' => 'expired',
                    'status' => 'expired',
                    'description' => 'Pagamento expirado',
                    'created_at' => now(),
                    'updated_at' => now()
                ]);
            }

            return $this->checkSuccessPayment($request, $payment);
        } else if ($payment->getData()->status === "rejected") {
            return "rejected";
        }
        if ($payment->getData()->status === "expired") {
            return "expired";
        } else {
            return "success";
        }
    }

    public function makePayment(Request $request)
    {
        $this->validate($request, [
            'token' => 'required|min:6',
            'partner_transaction_id' => 'required',
        ], [
            'token.required' => trans('token_required'),
            'partner_transaction_id.required' => trans('partner_transaction_id_required'),
        ]);

        $kyc = new PartnerKyc();
        $checkKyc = $kyc->confirmPayment($request);

        if ($checkKyc) {
            return $checkKyc;
        } else {
            $generatedPayment = Payment::query()->where('partner_transaction_id', '=', $request->partner_transaction_id)->first();

            $this->generatedPayment = $generatedPayment;
            $this->request = $request;

            if ($generatedPayment) {

                DB::transaction(function () {

                    $store = DB::table('stores')->where('id', $this->generatedPayment->store_id)->first();
                    $imali = DB::table('imali_accounts')->where('user_id', $this->generatedPayment->sender_id)->first();
                    $imaliConfig = DB::table('imali_account_configs')->where('id', $imali->imali_account_config)->first();

                    $valorAPagar = $this->generatedPayment->amount + $imaliConfig->taxa;
                    $points = round($valorAPagar);

                    // Payer or Sender Section
                    DB::table('imali_accounts')->where('user_id', $this->generatedPayment->user_id)->decrement('balance', $valorAPagar);
                    DB::table('imali_accounts')->where('user_id', $this->generatedPayment->user_id)->increment('points', $points);

                    $contractoComerciante = DB::table('merchant_contracts')->where('store_id', $this->generatedPayment->store_id)->first();

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

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

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

                    $valorFinal = $valorAPagar - $taxaDesconto;

                    // Recever User Merchante
                    DB::table('stores')->where('account_number', $this->generatedPayment->store_account_number)->increment('balance', $valorFinal);


                    //                    DB::table('payments')->insert([
                    //                        'transaction_id' => $this->generatedPayment->transaction_id,
                    //                        'partner_transaction_id' => $this->generatedPayment->partner_transaction_id,
                    //                        'sender_id' => $this->generatedPayment->user_id,
                    //                        'store_id' => $this->generatedPayment->store_id,
                    //                        'client_id' => $this->generatedPayment->user_client_id,
                    //                        'received_points' => $this->generatedPayment->amount,
                    //                        'amount' => $this->generatedPayment->amount,
                    //                        'amount_credited' => $valorFinal,
                    //                        'comissao' => $taxaDesconto,
                    //                        'description' => $this->generatedPayment->description,
                    //                        'used_points' => 0,
                    //                        'estado' => 'pago',
                    //                        'estado_color' => '#388E3C',
                    //                        'payment_type' => 'directo',
                    //                        'terminalID' => $this->generatedPayment->terminalID,
                    //                        'terminalChannel' => $this->generatedPayment->terminalChannel,
                    //                        'terminalCompanyName' => $this->generatedPayment->terminalCompanyName,
                    //                        'created_at' => now(),
                    //                        'updated_at' => now()
                    //                    ]);

                    DB::table('payments')
                        ->where('partner_transaction_id', $this->request->partner_transaction_id)
                        ->update([
                            'received_points' => $this->generatedPayment->amount,
                            'amount_credited' => $this->generatedPayment->amount - $taxaDesconto,
                            'amount_debited' => $valorAPagar,
                            'comissao' => $taxaDesconto,
                            'description' => $this->generatedPayment->description,
                            'used_points' => 0,
                            'estado' => 'success',
                            'status' => 'success',
                            'estado_color' => '#388E3C',
                            'payment_type' => 'directo',
                            'updated_at' => now()
                        ]);

                    $payerUser = DB::table('users')->where('id', $imali->user_id)->first();

                    $trasactionGeneration = new TransactionGeneration();
                    $transaction = $trasactionGeneration->generateTransaction();

                    $actualPoints = $imali->points + $points;

                    $createTransaction = DB::table('payments')->where('transaction_id', $this->generatedPayment->transaction_id)->first();

                    DB::table('history_payments')->insert([
                        'sender_account' => $imali->account_number,
                        'sender_name' => $payerUser->name,
                        'amount_credited' => $valorFinal,
                        'status_user' => 'sender',
                        'status' => 'done',
                        'comissao' => $taxaDesconto,
                        'amount' => $valorAPagar,
                        'user_id' => $payerUser->id,
                        'actual_points' => $actualPoints,
                        'last_points' => $imali->points,
                        'win_points' => $points,
                        'transaction_id' => $transaction,
                        'payment_id' => $createTransaction->id,
                        'created_at' => now(),
                        'updated_at' => now()
                    ]);

                    DB::table('profits')->insert([
                        'payer_id' => $payerUser->id,
                        'payer_account' => $store->account_number,
                        'amount' => $valorAPagar,
                        'amount_credited' => $valorFinal,
                        'comissao' => $taxaDesconto,
                        'profit_id' => $trasactionGeneration->generateTransaction(),
                        'payment_id' => $createTransaction->id,
                        'profit_payer_id' => $createTransaction->store_id,
                        'created_at' => now(),
                        'updated_at' => now()
                    ]);

                    DB::table('payment_generations')
                        ->where('transaction_id', $this->generatedPayment->transaction_id)
                        ->update(['status' => 'success', 'updated_at' => now()]);

                    DB::table('payment_generation_confirmations')->insert([
                        'payment_generation_id' => $this->generatedPayment->id,
                        'payment_id' => $createTransaction->id,
                        'created_at' => now(),
                        'updated_at' => now()
                    ]);

                    $result = json_decode(json_encode($createTransaction), true);
                    $this->smsManager->sendMessageToClientePayment($result);

                    //                        $sms->sendMessageToComerciante($createTransaction);
                    //                    $sms->sendMessageToClientePayment($payerUser);
                    //                        Mail::to($store->email)->send(new PagamentoConfirmado($createTransaction));
                    //                        Mail::to($payerUser->email)->send(new Pagamento($createTransaction));

                    $log = new Record();

                    $log->createLog([
                        'description' => 'Pagamento na loja do comerciante',
                        'details' => 'Pagamento Feito com Sucesso',
                        'operation' => 'Payment',
                        'properties' => json_encode($createTransaction),
                        'status' => 'Success',
                        'user_id' => $this->generatedPayment->user_id
                    ]);
                }, 5);
            }
        }

        return response()->json(['message' => trans('payment_done')]);
    }

    public function makePaymentOlD(Request $request)
    {
        $this->validate($request, [
            'storeAccountNumber' => 'required|min:9',
            'clientAccountNumber' => 'required|min:9',
            'transactionID' => 'required',
            'amount' => 'required',
            'pin' => 'required|min:4|max:4',
            //            'apiKey' => 'required',
            'terminalID' => 'required',
            'terminalChannel' => 'required',
            'description' => 'required',
            'terminalCompanyName' => 'required',
            'usedPoints' => 'required'
        ], [
            'clientAccountNumber.required' => 'O Campo clientAccountNumber é de carácter Obrigatório',
            'storeAccountNumber.required' => 'O Campo storeAccountNumber é de carácter Obrigatório',
            'storeAccountNumber.min' => 'O Campo storeAccountNumber deve ter 9 dígitos',
            'clientAccountNumber.min' => 'O Campo clientAccountNumber deve ter 9 dígitos',
            'transactionID.required' => 'O campo transactionID é obrigatório',
            'pin.required' => 'O pin é obrigatório',
            'pin.max' => 'O pin deve ter 4 digitos',
            'pin.min' => 'O pin deve ter 4 digitos',
            'terminalCompanyName.required' => 'O campo terminalCompanyName é Obrigatório',
            'terminalID.required' => 'terminalID é Obrigatório',
            'amount.required' => 'O Campo amount é obrigatório',
            'apiKey.required' => 'apiKey é obrigatória',
            'description.required' => 'Descrição de Pagamento é obrigatória',
            'usedPoints.required' => 'usedPoints é obrigatória'
        ]);

        $trasactionGeneration = new TransactionGeneration();
        $kyc = new PartnerKyc();
        $checkKyc = $kyc->checkPaymentCliente($request);

        if ($checkKyc) {
            return $checkKyc;
        } else {
            $store = Store::query()->where('account_number', '=', $request->storeAccountNumber)->first();
            $imali = ImaliAccount::query()->where('account_number', '=', $request->clientAccountNumber)->first();
            $payerUser = User::query()->where('id', $imali->user_id)->first();
            $store = Store::query()->where('account_number', $request->storeAccountNumber)->first();
            $token = str_replace('Bearer ', '', $request->header('authorization'));
            $clientStore = UserClient::query()->where('client_key', $token)->first();

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

            $valorAPagar = $request->amount;
            $points = round($valorAPagar);

            // Payer or Sender Section
            DB::table('imali_accounts')->where('user_id', $payer_id)->decrement('balance', $valorAPagar);
            DB::table('imali_accounts')->where('user_id', $payer_id)->increment('points', $points);

            $contractoComerciante = MerchantContract::query()->where('store_id', $store->id)->first();

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

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

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

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

            // Recever User Merchante
            DB::table('stores')->where('account_number', $store->account_number)->increment('balance', $valorFinal);

            //                $profit = $valorAPagar*($contractoComerciante->taxa)/100;

            $transaction = $trasactionGeneration->generateTransaction();

            $createTransaction = Payment::create([
                'transaction_id' => $request->transactionID,
                'sender_id' => $payer_id,
                'store_id' => $store->id,
                'client_id' => $clientStore->id,
                'received_points' => $points,
                'amount' => $valorAPagar,
                'amount_credited' => $valorFinal,
                'comissao' => $taxaDesconto,
                'description' => $request->description,
                'used_points' => $request->usedPoints,
                'estado' => 'pago',
                'estado_color' => '#388E3C',
                'terminalID' => $request->terminalID,
                'terminalChannel' => $request->terminalChannel,
                'terminalCompanyName' => $request->terminalCompanyName,
                'created_at' => now(),
                'updated_at' => now()
            ]);

            $actualPoints = $imali->points + $points;
            $createTransaction->paymentHistoric()->create([
                'sender_account' => $imali->account_number,
                'sender_name' => $payerUser->name,
                'amount_credited' => $valorFinal,
                'status_user' => 'sender',
                'status' => 'done',
                'comissao' => $taxaDesconto,
                'amount' => $valorAPagar,
                'user_id' => $payerUser->id,
                'actual_points' => $actualPoints,
                'last_points' => $imali->points,
                'win_points' => $points,
                'transaction_id' => $transaction
            ]);

            $saveProfit = $createTransaction->profit()->create([
                'payer_id' => $payer_id,
                'payer_account' => $store->account_number,
                'amount' => $valorAPagar,
                'amount_credited' => $valorFinal,
                'comissao' => $taxaDesconto,
                'profit_id' => $trasactionGeneration->generateTransaction(),
                'payment_id' => $createTransaction->id,
                'profit_payer_id' => $createTransaction->store_id
            ]);

            $this->smsManager->sendSMSToComerciante($createTransaction);
            //                        $sms->sendMessageToComerciante($createTransaction);
            //                    $sms->sendMessageToClientePayment($payerUser);
            //                        Mail::to($store->email)->send(new PagamentoConfirmado($createTransaction));
            //                        Mail::to($payerUser->email)->send(new Pagamento($createTransaction));

            $log = new Record();
            $log->createLog([
                'description' => $imali->account_number . ' - ' . $store->name,
                'details' => 'Pagamento Feito com Sucesso',
                'operation' => 'Payment',
                'status' => 'Success',
                'user_id' => $request->user()->id
            ]);

            return response()->json([
                'message' => 'Pagamento Feito com Sucesso!',
                //                'transaction' => $transaction,
                'transaction' => $createTransaction->transaction_id,
                'amount' => $createTransaction->amount,
                'created_at' => $createTransaction->created_at,
                'duration' => 3000
            ], 200);
        }
    }

    public function makePayment2(Request $request)
    {
        //        $user = User::find($request->user()->id);
        $user = User::query()
            ->join('imali_accounts', 'imali_accounts.user_id', '=', 'users.id')
            ->where('imali_accounts.account_number', '=', $request->account_number)
            ->select('users.*')
            ->first();

        if (Hash::check($request->pin, $user->pin)) {
            $trasactionGeneration = new TransactionGeneration();

            //            $payerUser = User::query()->where('user_id', $request->user()->user_id)->first();
            $payerUser = User::query()->where('user_id', $user->user_id)->first();
            $store = Store::query()->where('account_number', $request->store_account_number)->first();
            $payer_id = $payerUser->id;

            $imali = ImaliAccount::query()->where('user_id', $payer_id)->first();
            $kyc = new Kyc();

            $kycCheck = $kyc->checkSenderPayment($request);
            $kyc = new PartnerKyc();
            $checkKYC = $kyc->checkPaymentCliente($request);

            if ($kycCheck) {

                $log = new Record();
                $log->createLog([
                    'description' => $imali->account_number . ' ' . $store->name,
                    'details' => $kycCheck,
                    'operation' => 'Payment',
                    'status' => 'Error',
                    'user_id' => $request->user()->id
                ]);

                return $kycCheck;
            } else {
                if ($payerUser) {
                    if ($imali->balance < $request->amount) {

                        $log = new Record();
                        $log->createLog([
                            'description' => $imali->account_number . ' ' . $store->name,
                            'details' => 'Saldo Insuficiente',
                            'operation' => 'Payment',
                            'status' => 'Error',
                            'user_id' => $request->user()->id
                        ]);

                        return response()->json(['message' => 'Saldo insuficiente', 'class' => 'error'], 402, [], JSON_NUMERIC_CHECK);
                    } else {
                        $valorAPagar = $request->amount;
                        $points = round($valorAPagar);

                        // Payer or Sender Section
                        DB::table('imali_accounts')->where('user_id', $payer_id)->decrement('balance', $valorAPagar);
                        DB::table('imali_accounts')->where('user_id', $payer_id)->increment('points', $points);

                        $contractoComerciante = MerchantContract::query()->where('store_id', $store->id)->first();

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

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

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

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

                        // Recever User Merchante
                        DB::table('stores')->where('account_number', $store->account_number)->increment('balance', $valorFinal);

                        //                $profit = $valorAPagar*($contractoComerciante->taxa)/100;

                        $transaction = $trasactionGeneration->generateTransaction();

                        $createTransaction = Payment::create([
                            'transaction_id' => $transaction,
                            'sender_id' => $payer_id,
                            'store_id' => $store->id,
                            'received_points' => $points,
                            'amount' => $valorAPagar,
                            'amount_credited' => $valorFinal,
                            'comissao' => $taxaDesconto,
                            'description' => $request->description,
                            'used_points' => $request->used_points,
                            'estado' => 'pago',
                            'estado_color' => '#388E3C',
                            'created_at' => now(),
                            'updated_at' => now()
                        ]);

                        $actualPoints = $imali->points + $points;
                        $createTransaction->paymentHistoric()->create([
                            'sender_account' => $imali->account_number,
                            'sender_name' => $payerUser->name,
                            'amount_credited' => $valorFinal,
                            'status_user' => 'sender',
                            'status' => 'done',
                            'comissao' => $taxaDesconto,
                            'amount' => $valorAPagar,
                            'user_id' => $payerUser->id,
                            'actual_points' => $actualPoints,
                            'last_points' => $imali->points,
                            'win_points' => $points,
                            'transaction_id' => $transaction
                        ]);

                        $saveProfit = $createTransaction->profit()->create([
                            'payer_id' => $payer_id,
                            'payer_account' => $store->account_number,
                            'amount' => $valorAPagar,
                            'amount_credited' => $valorFinal,
                            'comissao' => $taxaDesconto,
                            'profit_id' => $trasactionGeneration->generateTransaction(),
                            'payment_id' => $createTransaction->id,
                            'profit_payer_id' => $createTransaction->store_id
                        ]);
                        if ($saveProfit) {

                            //                        $sms = new SendSMS();
                            //                        $sms->sendMessageToClientePayment($createTransaction);
                            //                        $sms->sendMessageToComerciante($createTransaction);
                            //                    $sms->sendMessageToClientePayment($payerUser);
                            //                        Mail::to($store->email)->send(new PagamentoConfirmado($createTransaction));
                            //                        Mail::to($payerUser->email)->send(new Pagamento($createTransaction));

                            $log = new Record();
                            $log->createLog([
                                'description' => $imali->account_number . ' ' . $store->name,
                                'details' => 'Pagamento Feito com Sucesso',
                                'operation' => 'Payment',
                                'status' => 'Success',
                                'user_id' => $request->user()->id
                            ]);

                            return response()->json([
                                'message' => 'Pagamento Feito com Sucesso!',
                                'transaction' => $transaction,
                                'created_at' => $createTransaction->created_at,
                                'duration' => 3000
                            ], 200);
                        }
                    }
                }
            }
        } else {
            return response()->json(['message' => 'Pin Incorrecto'], 400);
        }
    }

    public function refundCustomerNew(Request $request)
    {

        try {
            $this->validate($request, [
                'amount' => 'required',
                'description' => 'required',
                'customerAccountNumber' => 'required',
                'storeAccountNumber' => 'required',
                'paymentTransaction' => 'required',
                'partnerTransactionID' => 'required|min:12',
                'terminalID' => 'required',
                'terminalChannel' => 'required',
                'terminalCompanyName' => 'required',
            ]);
        } catch (\Throwable $th) {
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => $th->getMessage(),
            ], trans('error')[0]['http_code']);
        }

        //        $this->validate($request, [
        //            'amount' => 'required',
        //            'description' => 'required',
        //            'customerAccountNumber' => 'required',
        //            'storeAccountNumber' => 'required',
        //            'paymentTransaction' => 'required',
        //            'partnerTransactionID' => 'required|min:12',
        //            'terminalID' => 'required',
        //            'terminalChannel' => 'required',
        //            'terminalCompanyName' => 'required',
        //        ]);

        $kyc = new PartnerKyc();
        $kycCheck = $kyc->checkMerchantRefund($request);

        if ($kycCheck) {
            return $kycCheck;
        } else {
            $this->requestRefund = $request;

            DB::transaction(function () {

                $imaliUser = DB::table('imali_accounts')
                    ->join('users', 'users.id', '=', 'imali_accounts.user_id')
                    ->where('account_number', $this->requestRefund->customerAccountNumber)
                    ->select('users.*', 'imali_accounts.id as imali_account_id')
                    ->first();

                $merchant = DB::table('merchant_accounts')
                    ->join('stores', 'stores.merchant_account_id', '=', 'merchant_accounts.id')
                    ->where('stores.account_number', $this->requestRefund->storeAccountNumber)
                    ->select('merchant_accounts.*', 'stores.balance as store_balance', 'stores.id as store_id')
                    ->first();

                $imaliConfig = DB::table('imali_account_configs')
                    ->where('id', $merchant->kyc_config_id)
                    ->first();

                $loja = Store::query()->where('account_number', '=', $this->requestRefund->storeAccountNumber)->first();

                $payment = Payment::query()
                    ->where('transaction_id', '=', $this->requestRefund->paymentTransaction)
                    ->first();

                $generation = new GenerateToken();

                $token = $generation->generatePhoneNumberCode();

                DB::table('payments')->insert([
                    //                    'transaction_id' => $this->msid->generateTransaction(),
                    'transaction_id' => $this->requestRefund->partnerTransactionID,
                    'partner_transaction_id' => $this->requestRefund->partnerTransactionID,
                    'amount' => $this->requestRefund->amount,
                    'comissao' => $imaliConfig->taxa_refund_mechant,
                    'amount_debited' => $this->requestRefund->amount + $imaliConfig->taxa_refund_mechant,
                    'amount_credited' => $this->requestRefund->amount,
                    //                    'account_number' => $this->requestRefund->customerAccountNumber,
                    'description' => $this->requestRefund->description,
                    'store_id' => $merchant->store_id,
                    'sender_id' => $imaliUser->id,
                    'imali_account_id' => $imaliUser->imali_account_id,
                    'payment_id' => $payment->id,
                    'estado' => 'pending',
                    'status' => 'pending',
                    'payment_type' => 'refund',
                    'token' => $token,
                    'merchant_id' => $merchant->id,
                    'client_id' => $this->requestRefund->user()->id,
                    'terminalCompanyName' => $this->requestRefund->terminalCompanyName,
                    'terminalChannel' => $this->requestRefund->terminalChannel,
                    'terminalID' => $this->requestRefund->terminalID,
                    'created_at' => now(),
                    'updated_at' => now()
                ]);

                $data = ['phone' => $merchant->phone_number, 'token' => $token];

                $this->token = $token;
                $this->smsManager->tokenPayment($data);
            });

            //            return response()->json(['message' => trans('otp_sent'), 'token' => $this->token]);

            return response()->json([
                'cody' => trans('success')[1]['cody'],
                'success' => trans('success')[1]['success'],
                'type' => trans('success')[1]['type'],
                'message' => "OTP successfully sent",
                'token' => $this->token
            ], trans('success')[1]['http_code']);
        }
    }

    public function confirmRefund(Request $request)
    {

        try {
            $this->validate($request, [
                'partner_transaction_id' => 'required|min:12',
                'token_otp' => 'required'
            ]);
        } catch (\Throwable $th) {
            return response()->json([
                'cody' => trans('error')[0]['cody'],
                'error' => trans('error')[0]['error'],
                'type' => trans('error')[0]['type'],
                'message' => $th->getMessage(),
            ], trans('error')[0]['http_code']);
        }

        //        $this->validate($request, [
        //            'partner_transaction_id' => 'required|min:12',
        //            'token_otp' => 'required'
        //        ]);

        $kyc = new PartnerKyc();
        $kycCheck = $kyc->checkConfirmRefund($request);

        if ($kycCheck) {
            return $kycCheck;
        } else {

            $this->requestRefundConfirm = $request;
            DB::transaction(function () {

                //                $refund = DB::table('refunds')
                //                    ->where('partner_transaction_id', $this->requestRefundConfirm->partner_transaction_id)
                //                    ->first();

                $refund = DB::table('payments')
                    ->where('partner_transaction_id', $this->requestRefundConfirm->partner_transaction_id)
                    ->first();

                //                DB::table('payments')
                //                  ->where('partner_transaction_id', $this->requestRefundConfirm->partner_transaction_id)
                //                ->update([
                //                  'received_points' => 0,
                //              'used_points' => 0,
                //                'estado' => 'success',
                //            'status' => 'success',
                //          'updated_at' => now()
                //    ]);

                $merchant = DB::table('merchant_accounts')
                    ->join('stores', 'stores.merchant_account_id', '=', 'merchant_accounts.id')
                    ->where('stores.id', $refund->store_id)
                    ->select('merchant_accounts.*', 'stores.balance as store_balance')
                    ->first();

                $loja = DB::table('stores')->where('id', '=', $refund->store_id)->first();

                $imaliConfig = ImaliAccountConfig::find($merchant->kyc_config_id);

                $payment = DB::table('payments')->where('id', $refund->payment_id)->first();

                $user = DB::table('users')->where('id', $refund->sender_id)->first();
                $imali = DB::table('imali_accounts')->where('user_id', $refund->sender_id)->first();

                DB::table('imali_accounts')->where('user_id', $refund->sender_id)->increment('balance', $refund->amount);
                //                DB::table('merchant_accounts')->where('id', $refund->merchant_id)->increment('balance', $refund->amount + $imaliConfig->taxa_refund_mechant);
                DB::table('merchant_accounts')->where('id', $refund->merchant_id)->decrement('balance', $refund->amount + $imaliConfig->taxa_refund_mechant);


                $imali2 = DB::table('imali_accounts')->where('user_id', $refund->sender_id)->first();

                DB::table('payments')
                    ->where('partner_transaction_id', $this->requestRefundConfirm->partner_transaction_id)
                    ->update([
                        'received_points' => 0,
                        'used_points' => 0,
                        'estado' => 'success',
                        'status' => 'success',
                        'updated_at' => now(),
                        'old_balance' => $imali->balance,
                        'new_balance' => $imali2->balance,
                    ]);


                $tran = new TransactionGeneration();

                DB::table('profits')->insert([
                    'payer_id' => $user->id,
                    'payer_account' => $loja->account_number,
                    'amount' => $refund->amount,
                    'amount_credited' => $refund->amount + $imaliConfig->taxa_refund_mechant,
                    'comissao' => $imaliConfig->taxa_refund_mechant,
                    'profit_id' => $tran->generateTransaction(),
                    'payment_id' => $payment->id,
                    'profit_payer_id' => $payment->store_id,
                    'created_at' => now(),
                    'updated_at' => now()
                ]);

                //                DB::table('refunds')
                //                    ->where('transaction', $refund->transaction)
                //                    ->update(['estado' => 'successo', 'updated_at' => now()]);

                $notification = array(
                    'icon' => 'ic_imali_logo_verde_01',
                    //                            'icon' => 'ic_i_mali_cover',
                    'title' => 'Recebeste ' . $refund->amount . ' MT',
                    'body' => 'Parabéns, ' . ' recebeste reembolso ' . $refund->amount . ' MT ' . ' da loja ' . $loja->name,
                    'click_action' => 'com.imali.payapp.payment_PAGAR_NOTIFICATION',
                    //                            'color' => '#008577'
                    'color' => '#ffffff'
                );


                $data = array(
                    'transaction' => $refund->transaction_id,
                    'loja' => $loja->name,
                    'loja_account' => $loja->account_number,
                    'pontos' => $payment->received_points,
                    'pontos_usados' => $payment->used_points,
                    'amount' => (float)$refund->amount,
                    'amount_debited' => (float)$refund->amount,
                    'account_number' => (int)$imali->account_number,
                    'phone' => $user->phone,
                    'descricao' => $refund->description,
                    'data' => $refund->created_at,
                    'estado' => $refund->estado,
                    'comissao' => (float)$refund->comissao,
                    'route' => 'PAGAR_NOTIFICATION',
                    'terminal' => 'firebase'
                );

                $result = json_decode(json_encode($payment), true);

                $this->smsManager->sendMessageToCustomerPayment($data, $result);

                $this->pushNotifification($user->firebase_token, $notification, $data);
            });
            //            return response()->json(['message' => trans('refund_done')], 200);


            return response()->json([
                'cody' => trans('success')[0]['cody'],
                'success' => trans('success')[0]['success'],
                'type' => trans('success')[0]['type'],
                'message' => "Refund successful!"
            ], trans('success')[0]['http_code']);
        }
    }

    public function refundCustomer(Request $request)
    {
        $this->validate($request, [
            //            'transaction' => 'required',
            'amount' => 'required',
            'description' => 'required',
            'account_number' => 'required',
            'store_account_number' => 'required',
            'payment_transaction' => 'required',
            'partner_transaction_id' => 'required',
            //            'password' => 'required',
            'terminalID' => 'required',
            'terminalChannel' => 'required',
            'terminalCompanyName' => 'required',
        ], [
            'transaction.required' => 'O Campo transaction é de carácter Obrigatório',
            'amount.required' => 'O Campo transaction é de carácter Obrigatório',
            'description.required' => 'O campo description é obrigatório',
            'partner_transaction_id.required' => 'O campo partner_transaction_id é obrigatório',
            'account_number.required' => 'O campo account_number é obrigatório',
            'merchant_id.required' => 'O campo merchant_id é obrigatório',
            'imali_user_id.required' => 'O campo imali_user_id é obrigatório',
            'store_id.required' => 'O campo imali_user_id é obrigatório',
            'user_client_id.required' => 'O campo imali_user_id é obrigatório',
        ]);

        $kyc = new PartnerKyc();
        $kycCheck = $kyc->checkMerchantRefund($request);

        if ($kycCheck) {
            return $kycCheck;
        } else {
            $imaliUser = ImaliAccount::query()
                ->join('users', 'users.id', '=', 'imali_accounts.user_id')
                ->where('account_number', $request->account_number)
                ->select('users.*')
                ->first();


            $merchant = MerchantAccount::query()
                ->join('stores', 'stores.merchant_account_id', '=', 'merchant_accounts.id')
                ->where('stores.account_number', $request->store_account_number)
                ->select('merchant_accounts.*', 'stores.balance as store_balance', 'stores.id as store_id')
                ->first();

            $imaliConfig = ImaliAccountConfig::find($merchant->kyc_config_id);
            //            $loja = Store::query()->where('id', '=', $request->store_id)->first();
            $loja = Store::query()->where('account_number', '=', $request->store_account_number)->first();

            $payment = Payment::query()
                ->where('transaction_id', $request->payment_transaction)
                ->first();

            $refund = Refund::create([
                'transaction' => $this->msid->generateTransaction(),
                'amount' => $request->amount,
                'fee' => $imaliConfig->taxa_refund_mechant,
                'amount_debited' => $request->amount + $imaliConfig->taxa_refund_mechant,
                'account_number' => $request->account_number,
                'description' => $request->description,
                'store_id' => $merchant->store_id,
                'imali_user_id' => $imaliUser->id,
                'payment_id' => $payment->id,
                //                'estado' => 'Reembolso',
                'estado' => 'pendente',
                'merchant_id' => $merchant->id,
                'user_client_id' => $request->user()->id,
                'terminalCompanyName' => $request->terminalCompanyName,
                'terminalChannel' => $request->terminalChannel,
                'terminalID' => $request->terminalID
            ]);

            $payment = Payment::create([
                'transaction_id' => $refund->transaction,
                'sender_id' => $refund->imali_user_id,
                'store_id' => $refund->store_id,
                'received_points' => 0,
                'amount' => $refund->amount,
                'amount_credited' => $refund->amount,
                'comissao' => $refund->fee,
                'description' => $refund->description,
                'used_points' => 0,
                'estado' => 'pago',
                'client_id' => $request->user()->id,
                'payment_type' => 'reembolso',
                'estado_color' => '#388E3C',
                'created_at' => now(),
                'updated_at' => now()
            ]);

            DB::table('imali_accounts')->where('user_id', $refund->imali_user_id)->increment('balance', $refund->amount);
            DB::table('merchant_accounts')->where('id', $refund->merchant_id)->increment('balance', $refund->amount);

            $notification = array(
                'icon' => 'ic_imali_logo_verde_01',
                //                            'icon' => 'ic_i_mali_cover',
                'title' => 'Recebeste ' . $request->amount . ' MT',
                'body' => 'Parabéns, ' . ' recebeste reembolso ' . $request->amount . ' MT ' . ' da loja ' . $loja->name,
                'click_action' => 'com.imali.payapp.payment_PAGAR_NOTIFICATION',
                //                            'color' => '#008577'
                'color' => '#ffffff'
            );


            $data = array(
                'transaction' => $refund->transaction,
                'loja' => $loja->name,
                'loja_account' => $loja->account_number,
                'pontos' => $payment->received_points,
                'pontos_usados' => $payment->used_points,
                'amount' => (float)$refund->amount,
                'amount_debited' => (float)$refund->amount,
                'account_number' => (int)$refund->account_number,
                'phone' => $request->user()->phone,
                'descricao' => $refund->description,
                'data' => $refund->created_at,
                'estado' => $refund->estado,
                'comissao' => (float)$refund->comissao,
                'route' => 'PAGAR_NOTIFICATION',
                'terminal' => 'firebase'
            );

            $this->pushNotifification($imaliUser->firebase_token, $notification, $data);

            return response()->json(['message' => 'Reembolso feito com Sucesso!'], 200);
        }
    }


    //? Consultar Saldo da subconta - Check Card Balance
    public function checkCardBalance($card_number)
    {
        if (!$card_number) return response()->json(['message' => 'Número de cartão obrigatório!'], 400);

        $sub_account = ImaliSubAccount::query()->where('card_number', $card_number)->first();

        if (!$sub_account) return response()->json(['message' => 'Cartão invalido!'], 400);
        return response()->json(['balance' => $sub_account->balance], 200);
    }


    //? Refund SubAccount Payment
    public function makePaymentRefund(Request $request)
    {
        $this->validate($request, [
            'transaction_id' => 'required',
            'partner_transaction_id' => 'required',
            'refund_reason' => 'string|max:100',
        ], [
            'transaction_id.required' => 'O campo transaction_id é obrigatório',
            'partner_transaction_id.required' => 'O campo partner_transaction_id é obrigatório',
            'refund_reason.required' => 'O campo refund_reason é obrigatório',
            'refund_reason.max' => 'O campo Reason deve ter so até 100 caracteres',
        ]);

        // $payment_refund = Payment::query()->where('transaction_id', $request->transaction_id)->where('partner_transaction_id', $request->partner_transaction_id)->where('status', 'success')->first();
        $payment_refund = Payment::query()->where('transaction_id', $request->transaction_id)->where('partner_transaction_id', $request->partner_transaction_id)->first();
        // if (!$payment_refund) return response()->json(['message' => 'Pagamento invalido. Nao pode ser reembolsado'], 400);
        if (!$payment_refund) return response()->json(['message' => 'Pagamento invalido.'], 404);

        if ($payment_refund->status != 'success') return response()->json(['message' => 'Pagamento nao pode ser reembolsado.'], 400);

        $refunded_payment = Payment::query()->where('payment_id', $payment_refund->id)->where('payment_type', 'reembolso')->first();
        if ($refunded_payment) return response()->json(['message' => 'Este pagamento ja foi reembolsado.'], 400);

        $store_old = Store::query()->where('id', $payment_refund->store_id)->first();
        $store = Store::query()->where('id', $payment_refund->store_id)->first();
        if (!$store) return response()->json(['message' => 'Falha de pagamento. Loja nao encontrada.'], 404);

        //if (!($store->balance >= $payment_refund->amount_credited)) return response()->json(['message' => 'Falha de pagamento. Loja nao tem saldo para fazer o reembolso.'], 400);

        // Buscar dados do User que faz a transacao
        //$userPayer = User::getUserDetails($payment_refund->sender_id);

        //$accountPayer = User::getAccount($payment_refund->sender_account_number, $userPayer->id);
        //$accountPayerOld = User::getAccount($payment_refund->sender_account_number, $userPayer->id);

        //$this->msid = new TransactionGeneration();

        //return $userPayer;

        try {

            // Buscar dados do User que faz a transacao
            $userPayer = User::getUserDetails($payment_refund->sender_id);

            // $accountPayer = User::getAccount($payment_refund->sender_account_number, $userPayer->id);
            // $accountPayerOld = User::getAccount($payment_refund->sender_account_number, $userPayer->id);

            // Buscar dados da conta do User que faz a transacao
            // $accountPayer = User::getAccountByUser($userPayer->id, $userPayer->account_id);
            // $accountPayerOld = User::getAccountByUser($userPayer->id, $userPayer->account_id);

            // $accountCardPayer = User::getAccount($payment_refund->sender_card_number);

            $accountCardPayer = User::getAccount($payment_refund->sender_card_number);
            $accountCardPayerOld = User::getAccount($payment_refund->sender_card_number);

            // if ($accountCardPayer && $accountCardPayer->balance < 0) return SendResponse::errorResp400(
            //     'Não é possível fazer reembolso com saldo negativo sem cartão',
            //     'It is not possible to make a refund with a negative balance without card'
            // );

            $this->msid = new TransactionGeneration();

            //code...
            DB::beginTransaction();

            //$store->balance -= $payment_refund->amount_credited;
            $accountCardPayer->balance += $payment_refund->amount;
            //$store->update();
            $accountCardPayer->update();

            $payment = Payment::create([
                'transaction_id' => $this->msid->generateTransaction(),
                'partner_transaction_id' => $this->msid->generateTransaction(),
                'terminalID' => $request->terminal_id,
                'sender_id' => $payment_refund->sender_id,
                'store_id' => $payment_refund->store_id,
                'received_points' => 0,
                'is_real_payment' => 0,
                'amount' => $payment_refund->amount,
                'amount_credited' => $payment_refund->amount,
                'amount_debited' => $payment_refund->amount_credited,
                'payment_id' => $payment_refund->id,

                'sender_name' => $payment_refund->sender_name,
                'sender_account_number' => $payment_refund->sender_account_number,
                'sender_card_number' => $payment_refund->sender_card_number,

                'comissao' => 0,
                'new_balance' => $accountCardPayer->balance,
                'old_balance' => $accountCardPayerOld->balance,

                'old_store_balance' => $store_old->balance,
                'new_store_balance' => $store->balance,

                'description' => $payment_refund->description,
                'used_points' => 0,
                'estado' => 'pago',
                'estado_color' => $payment_refund->estado_color,
                'status' => 'success',
                'payment_type' => 'reembolso',

                'transaction_type' => 'credit',
                'transaction_name' => 'Reembolso'
            ]);

            // envio de notificacoes
            $this->send_refund_notifications($request, $store, $userPayer, $accountCardPayer, $payment);

            DB::commit();
            return response()->json(['message' => 'Reembolso efectuado com sucesso.', 'transaction_id' => $payment->transaction_id, 'partner_transaction_id' => $payment->partner_transaction_id], 200);
        } catch (\Throwable $th) {

            Log::info('Error Response', [
                'content' => $th,
            ]);

            //throw $th;
            DB::rollback();

            return response()->json(['message' => 'Falha de pagamento.'], 500);
        }

        // return $accountPayer;

        // return response()->json(['message' => 'Pagamento encontrado!'], 200);
    }


    // TODO -- 17-Marco-2025
    private function send_refund_notifications($request, $store, $userPayer, $accountPayer, $payment)
    {

        // notificar o utilizador que fez o pagamento
        $push_userPayer = new PushNotification(
            $request->has('sub_account_number') && $request->sub_account_number ? ' Depósito de ' . $request->amount . ' MT' : 'Reembolso de ' . $payment->amount . ' MT',
            'Parabéns, ' . ($request->has('sub_account_number') && $request->sub_account_number ? 'foi efectuado um reembolso no valor de ' . $request->amount . ' MT na tua subconta ' . $request->sub_account_number : 'foi efectuado um reembolso no valor de ' . $payment->amount . ' MT da loja ' . $store->name),
            $userPayer->firebase_token,
            'com.imali.payapp.payment_PAGAR_NOTIFICATION'
        );

        // $push_store = new PushNotification(
        //     'Pagamento ' . $request->amount . ' MT',
        //     'Parabéns, ' . ' recebeu o pagamento de ' . $request->amount . ' MT ' . ' do cliente ' . $userPayer->name,
        //     $store->firebase_token,
        //     'mz.co.imali.business.payment_TARGET_NOTIFICATION',
        //     'https://imali.co.mz/wp-content/uploads/2022/04/iMali-Business-Logo.png'
        // );

        $data = $this->get_notification_data($request, $userPayer, $store, $payment, $accountPayer);

        // Notificar o user que fez pagamento
        $push_userPayer->sendPush($data);

        // Notificar a loja que recebeu o pagamento
        // $this->send_notification_store($store, $push_store, $data, $created_payment);
    }
    // TODO -- 17-Marco-2025

    private function get_notification_data($request, $userPayer, $store_contract, $created_payment, $accountPayer)
    {
        $category = RamoActivity::find($store_contract->industry_activity);

        $data = array(
            'transaction' => $created_payment->transaction_id,
            'loja' => $store_contract->name,
            'name' => $userPayer->name,
            'loja_account' => $store_contract->account_number,
            'pontos' => $created_payment->received_points,
            'pontos_usados' => $created_payment->used_points,
            'amount' => $created_payment->amount,
            'amount_debited' => $created_payment->amount_credited,
            'amount_credited' => $created_payment->amount_credited,
            'account_number' => $accountPayer->account_number,
            'phone' => $userPayer->phone,
            'descricao' => $created_payment->description,
            'data' => $created_payment->created_at,
            'created_at' => $created_payment->created_at,
            'estado' => $created_payment->estado,
            'comissao' => $created_payment->comissao,
            'message_store' => trans('payment_received'),
            'message_customer' => trans('payment_done'),
            'logo_category' => $category->logo,
            'category' => $category->nome,
            'route' => 'PAGAR_NOTIFICATION',
            'terminal' => 'firebase'
        );

        return $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);
    }

    private function messageJsonToXML($message, $rsCd = 2, $allowPayment = false | 0)
    {
        $jsonResponse = [
            'Document' => [
                'ServiceReq' => [
                    'Hdr' => [
                        'MsgFctn' => env('msgFctn'),
                        'MsgUUID' => Str::orderedUuid(),
                        'PrtcolVrsn' => env('prtcolVrsn'),
                        'RsCd' => $rsCd
                    ],
                    'ResData' => [
                        'AllowPayment' => $allowPayment,
                        'Reason' => $message,
                    ]
                ],
            ],
        ];

        // Converter JSON para XML
        // $xml = ArrayToXml::convert($jsonResponse);
        $xml = ArrayToXml::convert($jsonResponse, [], true, 'UTF-8', '1.0', [], false);

        Log::info('Outgoing Response', [
            'content' => $xml,
        ]);

        return response($xml, 200)->header('Content-Type', 'text/xml');
    }


    private function messageJsonToXMLNotify($message, $rsCd = 2, $allowPayment = false | 0)
    {
        $jsonResponse = [
            'Document' => [
                'ServiceReq' => [
                    'Hdr' => [
                        'MsgFctn' => env('msgFctnNotfy'),
                        'MsgUUID' => Str::orderedUuid(),
                        'PrtcolVrsn' => env('prtcolVrsn'),
                        'RsCd' => $rsCd
                    ],
                    'ResData' => [
                        // 'AllowPayment' => $allowPayment,
                        'Reason' => $message,
                    ]
                ],
            ],
        ];

        // Converter JSON para XML
        $xml = ArrayToXml::convert($jsonResponse, [], true, 'UTF-8', '1.0', [], false);
        // $xml = ArrayToXml::convert($jsonResponse);

        Log::info('Outgoing Response', [
            'content' => $xml,
        ]);

        return response($xml, 200)->header('Content-Type', 'text/xml');
    }

    private function isXML($request)
    {
        $pos = strpos($request->header('Content-Type'), 'xml');
        $xml = substr($request->header('Content-Type'), 0, $pos + 3);

        if ($request->isXmlHttpRequest() || ($xml == 'text/xml') || ($xml == 'application/xml')) return true;
        else return false;
    }


    private function convertXMLToArray($request)
    {

        //NEW
        $fim = strpos($request->getContent(), "?>") + 2;
        $our_header = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>';
        $content = substr($request->getContent(), $fim, strlen($request->getContent()));
        $content = str_replace("code=943", 'code="943"', $content);
        $content = str_replace("<Document xmlns:ren=Renaissance>", "<Document>", $content);

        Log::info('Incoming Request', [
            'content' => $request->getContent(),
        ]);

        // $root_pos = strpos($request->getContent(), "root");
        $root_pos = strpos($content, "root");
        if ($root_pos == false)
            $xmlContent = $our_header . "<root>" . $content . "</root>";
        else
            $xmlContent = $our_header . $content;

        //NEW

        // Carregar dados XML
        $xmlObject = simplexml_load_string($xmlContent, 'SimpleXMLElement', LIBXML_NOCDATA);
        // $xmlObject = simplexml_load_string($xmlContent, 'SimpleXMLElement');

        // Converter para array
        $xmlObj = json_decode(json_encode($xmlObject, JSON_PRETTY_PRINT), true);

        foreach ($xmlObj['Document']['ServiceReq']['Hdr'] as $key => $value) {
            $newArr[$key] = $value;
        }
        foreach ($xmlObj['Document']['ServiceReq']['ReqData'] as $key => $value) {
            $newArr[$key] = $value;
            if ($key === 'Amount')
                $newArr['amountCode'] = (string)$xmlObject->Document->ServiceReq->ReqData->Amount->attributes()->code;
        }

        return new Request($newArr);
    }


    private function validateRequest($request)
    {
        try {
            $this->validate(
                $request,
                [
                    'BillID' => [
                        'required',
                        function ($attribute, $value, $fail) {
                            if ($value != env('BILLID')) {
                                $fail('O valor do parametro ' . $attribute . ' nao esta correcto.');
                            }
                        },
                    ],
                    'amountCode' => [
                        function ($attribute, $value, $fail) {
                            if ($value !== '943') {
                                $fail('Codigo da moeda invalido.');
                            }
                        },
                    ],
                    'EntityID' => 'required',
                    'RefNum' => 'required',
                    'Amount' => 'required'
                ],
                [
                    'BillID' => 'O campo billID informado nao esta correcto',
                    'EntityID' => 'O campo entityID e de caracter obrigatorio',
                    'RefNum' => 'O campo refNum e de caracter obrigatorio',
                    'Amount' => 'O campo amount e de caracter obrigatorio'
                ]
            );

            return response()->json('Done.', 200);
        } catch (\Illuminate\Validation\ValidationException $e) {
            $errors = $e->validator->errors()->getMessages();
            return response()->json(['data' => $errors], 500);
        }
    }

    //? Metodos de Validacao SIMO
    public function validatePayment(Request $request)
    {

        if (!$this->isXML($request)) return $this->messageJsonToXML('requisicao invalida');

        // $request = "<root>". $request->getContent() ."</root>";

        $request = $this->convertXMLToArray($request);

        $respValidation = $this->validateRequest($request);

        if ($respValidation->getStatusCode() != 200) return $this->messageJsonToXML('Erro de parâmetro: ' . json_encode($respValidation->getData()->data));

        $amount = $request->Amount;
        $amount = (float)str_replace(',', '.', $amount);
        $amount = $amount / 100;

        //Verificar tamanho da referencia
        if (!is_numeric($request->RefNum) || strlen($request->RefNum) != 11) return $this->messageJsonToXML('A referencia não foi encontrada.');

        try {
            // Buscar dados do User que faz a transacao
            $account_number = substr($request->RefNum, 0, 9);
            $userAccount = User::getAccount($account_number);

            // return $userAccount;

            // // Verificar se a conta do usuário foi encontrada
            // if (!$userAccount) {
            //     throw new \Exception('Conta do usuário não encontrada');
            // }

            $user = User::getUserDetails($userAccount->user_id);

            if (!$user) return $this->messageJsonToXML('A referencia não foi encontrada');

            //? Validacao do KYC XML
            $kyc = new UserKyc($user);
            $kycResp = $kyc->checkUserKYC($amount);

            if ($kycResp->getStatusCode() != 200) return $this->messageJsonToXML($kycResp->getData()->message);
            return $this->messageJsonToXML('Validacao efetuada com sucesso', 0, true);

            // // Verificar se os detalhes do usuário foram encontrados
            // if (!$user) {
            //     throw new \Exception('Detalhes do usuário não encontrados');
            // }

        } catch (\Throwable $th) {
            // return $this->messageJsonToXML('Erro interno de processamento');
            return $this->messageJsonToXML('A referencia não foi encontrada.');
        }
    }


    public function notifyPayment(Request $request)
    {

        if (!$this->isXML($request)) return $this->messageJsonToXMLNotify('requisicao invalida');

        $request = $this->convertXMLToArray($request);

        $this->validateRequest($request);

        $respValidation = $this->validateRequest($request);

        if ($respValidation->getStatusCode() != 200) return $this->messageJsonToXMLNotify('Erro de parâmetro: ' . json_encode($respValidation->getData()->data));

        //Verificar tamanho da referencia
        if (!is_numeric($request->RefNum) || strlen($request->RefNum) != 11) return $this->messageJsonToXMLNotify('A referencia não foi encontrada.');

        try {
            // Buscar dados do User que faz a transacao
            $account_number = substr($request->RefNum, 0, 9);
            $userAccount = User::getAccount($account_number);
            $user = User::getUserDetails($userAccount->user_id);
            // return $user;

            if (!$user) return $this->messageJsonToXMLNotify('A referencia não foi encontrada');

            $amount = $request->Amount;
            $amount = (float)str_replace(',', '.', $amount);

            $amount = $amount / 100;

            //? Validacao do KYC XML
            $kyc = new UserKyc($user);
            $kycResp = $kyc->checkUserKYC($amount);

            if ($kycResp->getStatusCode() != 200) return $this->messageJsonToXMLNotify($kycResp->getData()->message);
        } catch (\Throwable $th) {
            return $this->messageJsonToXMLNotify('Erro interno de processamento');
        }



        //?Processo de carregamento
        $account_number = substr($request->RefNum, 0, 9);
        $imaliAccount = User::getAccount($account_number);
        // return $userAccount;

        $transactionString = new TransactionGeneration();

        if ($imaliAccount) {
            $balanceActual = $imaliAccount->balance + $amount;

            $masterAccount = MasterAccount::find(2);
            $recharge = RechargeImaliAccount::create([
                'imali_account_id' => $imaliAccount->id,
                'transaction_id' => $transactionString->generateTransaction(),
                // 'bank_reference' => $request->refbancariatran,
                // 'bank_date' => $request->datatransaccao,
                'account_reference' => $imaliAccount->reference,
                'description' => 'Carregamento SIMO',
                'amount' => $amount,
                'last_balance' => $imaliAccount->balance,
                'balance' => $balanceActual,
                'recharge_way' => 'SIMO',
                'estado' => 'sucesso',
                'estado_color' => '#388E3C',
                'master_account_id' => $masterAccount->id
            ]);

            $masterBalance = $masterAccount->balance + $amount;

            $masterAccount->update(['balance' => $masterBalance]);

            if ($recharge) {

                $imaliAccount->update(['balance' => $balanceActual]);

                $notification = array(
                    'icon' => 'ic_imali_logo_verde_01',
                    'title' => 'Carregamento ' . $recharge->amount . ' MT',
                    'body' => 'Parabéns, ' . ' carregaste com ' . $recharge->amount . ' MT ' . ' na tua conta ' . $imaliAccount->account_number,
                    'click_action' => 'com.imali.payapp.payment_RECHARGE_DETAILS',
                    'color' => '#ffffff'
                );

                $data = array(
                    'transaction' => $recharge->transaction_id,
                    // 'bank_reference' => $request->refbancariatran,
                    'account_reference' => $imaliAccount->reference,
                    // 'bank_date' => $request->datatransaccao,
                    'description' => $request->description,
                    'name' => $user->name,
                    'amount' => (float)$recharge->amount,
                    'phone' => $user->phone,
                    'reference' => $imaliAccount->reference,
                    'data' => $recharge->created_at,
                    'estado' => $recharge->estado,
                    'route' => 'RECHARGE_DETAILS',
                    'recharge_way' => $recharge->recharge_way,
                    'account_number' => $user->account_number,
                    'terminal' => 'firebase'
                );

                $this->pushNotifification($user->firebase_token, $notification, $data);
                $this->smsManager->sendSMSForUserRecharge($recharge);
            }

            $log = new Record();
            $log->createLog([
                'description' => $imaliAccount->account_number,
                'details' => $user->name . ' ' . $user->last_name,
                'operation' => 'Recharge by Reference',
                'status' => 'success',
                'user_id' => $user->id
            ]);

            if ($kycResp->getStatusCode() != 200) return $this->messageJsonToXMLNotify($kycResp->getData()->message);
            return $this->messageJsonToXMLNotify('Pedido processado com sucesso', 0, true);
        }
    }


    private function validateCheckDigit($numero)
    {
        // Verifica se o número tem 11 dígitos
        if (strlen($numero) != 11) {
            return false;
        }

        $entity = env('SIMO_ENTITY');
        $ref = (float)substr($numero, 0, 9);
        $cd = (float)substr($numero, 9, 2);

        $check_digit = 98 - (($entity . $ref) * 100) % 97;

        if ($check_digit == $cd) return true;
        return false;
    }

    // GET Payments
    public function getPaymentAccounts()
    {

        // $userPayer = User::getUserDetails(Auth::user()->id);
        //return User::getMyAccounts();
        // return response()->json(['data' => [User::getUserAccount()]]); // servidor
        return response()->json(['data' => User::getMyAccounts()]); // todas contas | servidor
        // return User::getAccount($userPayer->account_number);
    }
}