<?php

namespace App;
use Gisplus\Package\EstatechVendor\Models\Invoice;

use Illuminate\Database\Eloquent\Model;
use App\DB;
use App\Journal;
use App\ReverseTransaction;
use App\Loan;
use App\Payroll;
use EF;

class Transaction extends Model
{
    private $generic_condition;
  

    public function __construct()
    {
           
       $this->setCondition(['is_recycle' => '0']);
    }

    public function setCondition($condition = [])
    {
        $this->generic_condition = $condition;
    }

    public function getCondition()
    {
        return $this->generic_condition;
    }

    public function getJournalListByTransaction($id)
    {
        $journal = new Journal;

        return $journal->getJournalListByTransaction($id);
    }

    public function getRejectedJournalListByTransaction($id)
    {
        $journal = new Journal;

        return $journal->getRejectedJournalListByTransaction($id);
    }

    public function getBranch($id)
    {
       $condition = ['transaction_id' => $id];

       $condition += $this->getCondition();

       $journal = Journal::where($condition)->get();

       if(@count($journal) > 0)
       {
          $branch = new Branch;

          $curr_branch = $branch->getBranchById($journal[0]->branch_id);

          if(isset($curr_branch))
          {
            return $curr_branch->name;
          }
       }
         

       return ' ';
    }

    public function getRejectedBranch($id)
    {
       $condition = ['transaction_id' => $id];


       $journal = Journal::where($condition)->get();

       if(@count($journal) > 0)
       {
          $branch = new Branch;

          $curr_branch = $branch->getBranchById($journal[0]->branch_id);

          if(isset($curr_branch))
          {
            return $curr_branch->name;
          }
       }
         

       return ' ';
    }

   public function getTransactionByColumn($column)
   {
       return Transaction::where($this->getCondition())->distinct($column)->orderBy($column,'asc')->get([$column]);
   }

    // public function updateStatusByTransaction($object)
    // {
    //     return \DB::transaction(function () use ($object)  {
        
    //         $curr_transaction = Transaction::find($object['transaction_id']);

    //         $journal = new Journal;
    //         // $loan    = new Loan;
    //         $subhead = new Account;
    //         // $payroll = new Payroll;

    //         if(isset($curr_transaction->id))
    //         {

    //             $curr_journal  = $journal->getJournalByTransactionId($curr_transaction->id);

           
    //           if($object['status']=='Approve' && $curr_transaction->status == "Unapprove")
    //           { 

    //             $curr_transaction->voucher_number   = $this->generateSerialNumber($curr_transaction);
            
    //           }
    //           else if($object['status']=='Reject' && $curr_transaction->status == "Unapprove")
    //           {
    //               if(isset($curr_loan->id))
    //               {
    //                  $curr_loan = $loan->removeLoanById($curr_loan->id);
    //               }

    //               $curr_transaction->is_recycle = 1;
    //           }
             
    //           else if($object['status']=='Reverse' && $curr_transaction->status == "Approve")
    //           {

    //             $transaction = new Transaction;

    //             if(isset($curr_loan->id))
    //             {

    //              $uninitialized_loan = $loan->uninitializeLoanById($curr_loan->id);
    //             }


    //            $transaction = $transaction->reverseVoucher($curr_transaction,$object['date']);

    //             return with($transaction);
            
    //           }
    //           else 
    //           {
    //              return with(false);
    //           }


    //           // ITS FOR APPROVE, REJECT, RESERVE
    //           $curr_transaction->status           = $object['status'];
    //           $curr_transaction->updated_at       = date('Y-m-d',strtotime($object['date']));

    //           $curr_transaction->update();

    //           $journal = new Journal;

    //           $journal->updateJournalByTransaction($curr_transaction->id,$object);
              
    //           return with($curr_transaction);

    //         }

    //     });
    // }

   public function updateStatusByTransaction($object)
    {
        return \DB::transaction(function () use ($object)  {
        
            $curr_transaction = Transaction::find($object['transaction_id']);
            $journal = new Journal;
            // $loan    = new Loan;
            $subhead = new Account;
            // $payroll = new Payroll;

            if(isset($curr_transaction->id))
            {

                $curr_journal  = $journal->getJournalByTransactionId($curr_transaction->id);

    
              if($object['status']=='Approve' && $curr_transaction->status == "Unapprove")
              { 

                $curr_transaction->voucher_number   = $this->generateSerialNumber($curr_transaction);

                 $this->updateVendorInvoicePayments($curr_transaction);
            
              }
              else if($object['status']=='Reject' && $curr_transaction->status == "Unapprove")
              {
                  if(isset($curr_loan->id))
                  {
                     $curr_loan = $loan->removeLoanById($curr_loan->id);
                  }

                  $curr_transaction->is_recycle = 1;
              }
             
              else if($object['status']=='Reverse' && $curr_transaction->status == "Approve")
              {

                $transaction = new Transaction;

                $this->updateVendorPaidInvoice($curr_transaction);

                if(isset($curr_loan->id))
                {

                 $uninitialized_loan = $loan->uninitializeLoanById($curr_loan->id);
                }


               $transaction = $transaction->reverseVoucher($curr_transaction,$object['date']);

                return with($transaction);
            
              }
              else 
              {
                 return with(false);
              }


              // ITS FOR APPROVE, REJECT, RESERVE
              $curr_transaction->status           = $object['status'];
              $curr_transaction->updated_at       = date('Y-m-d',strtotime($object['date']));

              $curr_transaction->update();

              $journal = new Journal;

              $journal->updateJournalByTransaction($curr_transaction->id,$object);
              
              return with($curr_transaction);

            }

        });
    }
    
    public function reverseVoucher($curr_transaction,$date,$amount = 0)
    {
       return \DB::transaction(function () use ($curr_transaction,$date,$amount)  {

                $journal = new Journal;

                //REPLICATING CURRENT TRANSACTION
                $reverse_transaction                      = $curr_transaction->replicate();

                $reverse_transaction->status              = "Reversal";

                $reverse_transaction->compound_type       = "General";


                if($amount > 0)
                {
                    $reverse_transaction->total_amount              = $amount;

                }


                $reverse_transaction->voucher_type        = "JV";

                $reverse_transaction->voucher_number      = $this->generateSerialNumber($reverse_transaction);

                $reverse_transaction->created_at          = date('Y-m-d',strtotime($date));

                $reverse_transaction->updated_at          = date('Y-m-d',strtotime($date));


                $reverse_transaction->save();

                //MAPPING CURRENT AND REVERSE TRANSACTION
                 
                $reverse_entry = new ReverseTransaction;

                $reverse_entry->transaction_id = $curr_transaction->id;

                $reverse_entry->reverse_transaction_id = $reverse_transaction->id;

                $reverse_entry->save();

                //RETRIEVING DEBIT JOURNALS 

                $debit_journals = Journal::where('transaction_id',$curr_transaction->id)->where('debit','>',0)->get();

                 //RETRIEVING CREDIT JOURNALS 

                $credit_journals = Journal::where('transaction_id',$curr_transaction->id)->where('credit','>',0)->get();

                $count = 0;

                foreach ($debit_journals as $rows) 
                {
                   // if($amount == 0)
                   // {
                      $amount = $rows->debit;
                   // }

                  //UPDATING PAYMENT RECORD STATUS ON REVERSE

                    $payment = $rows->payment;

                    //REPLICATING PAYMENT ENTRY 
                    $reverse_payment = $payment->replicate();

                    $reverse_payment->status = "Reversal";

                    $reverse_payment->amount = $amount;

                    $reverse_payment->created_at     = date('Y-m-d',strtotime($date));

                    $reverse_payment->updated_at     = date('Y-m-d',strtotime($date));

                    $reverse_payment->save();

           
                    $payment_verification = new Payment;

                    $payment->amount = 0;

                    $payment_verification->genericPaymentVerification($payment,$amount,false);

                    // //UPDATING INSTALLMENT RECEIVED AMOUNT AND STATUS
                    // if($reverse_payment->installment_id > 0)
                    // {
                    //   $installment = new Installment;

                    //   $installment->updateInstallmentByPayment($reverse_payment->installment_id,0,$reverse_payment->amount);

                    // }
                    //   //UPDATING COMMISSION RECEIVED AMOUNT AND STATUS
                    // elseif($reverse_payment->commission_id > 0)
                    // {
                      
                    //   $commission = new Commission;

                    //   $commission->updateCommissionByPayment($reverse_payment->commission_id,0,$reverse_payment->amount);
                    // }


                    //UPDATING JOURNAL ENTRIES ON REVERSE

                    // DEBIT SIDE

                    $reversal_journal_debit = $rows->replicate();

                    $reversal_journal_debit->debit = $amount;
                    


                 
                    $reversal_journal_debit->account_id = $credit_journals[$count]['account_id'];

                    $reversal_journal_debit->transaction_id = $reverse_transaction->id;

                    $reversal_journal_debit->payment_id = $reverse_payment->id;

                    $reversal_journal_debit->created_at     = date('Y-m-d',strtotime($date));

                    $reversal_journal_debit->updated_at     = date('Y-m-d',strtotime($date));


                    $reversal_journal_debit->save(); 

                    // CREDIT SIDE

                    $reversal_journal_credit = $credit_journals[$count]->replicate();

                    $reversal_journal_credit->account_id = $rows->account_id;

                    $reversal_journal_credit->transaction_id = $reverse_transaction->id;

                    $reversal_journal_credit->payment_id = $reverse_payment->id;

                    $reversal_journal_credit->created_at     = date('Y-m-d',strtotime($date));

                    $reversal_journal_credit->updated_at     = date('Y-m-d',strtotime($date));

                    $reversal_journal_credit->credit = $amount;
                    


                    $reversal_journal_credit->save(); 

                    $count++;

                }  

                return with($reverse_transaction);      

                  
       });

    }

    // public function storeTransaction($object)
    // {

    //     return \DB::transaction(function () use ($object)  {
              
                        
    //         $total_amount = array_sum($object['amount']);

    //         $transaction                  = new Transaction();

    //         $transaction->status            = 'Unapprove';
    //         $transaction->voucher_type      = $object['voucher_list'];
    //         $transaction->compound_type     = $object['compound_type'];
    //         $transaction->total_amount      = $total_amount;
    //         $transaction->created_at        = date('Y-m-d',strtotime($object['date']));
    //         $transaction->save();
          
    //         return with($transaction);

    //     });
    // }

    public function storeTransaction($object)
    {

        return \DB::transaction(function () use ($object)  {
              
                        
            $total_amount = array_sum($object['amount']);

            $transaction                  = new Transaction();

            $transaction->status            = 'Unapprove';
            $transaction->voucher_type      = $object['voucher_list'];
            $transaction->compound_type     = $object['compound_type'];
            $transaction->total_amount      = $total_amount;
            $transaction->created_at        = date('Y-m-d',strtotime($object['date']));
            $transaction->save();
          
            return with($transaction);

        });
    }

    public function getUnpaidTransaction()
    {
        $condition = $this->getCondition();
        $condition += ['status' => 'Unapprove'];

        return Transaction::where($condition)->orderBy('id','asc')->get();

    }

    public function getUnpaidTransactionWithJournals()
    {
        $condition = $this->getCondition();
        $condition += ['status' => 'Unapprove'];

        return Transaction::where($condition)->with('journals')->orderBy('id','asc')->cursor();

    }
   

    public function geAlltRejectedTransaction()
    {
        $condition = [];
        $condition += ['status' => 'Reject'];

        return Transaction::where($condition)->orderBy('id','asc')->get();

    }

    public function getUnpaidFilterTransaction($from = '',$to = '',$branch)
    {
        $condition = $this->getCondition();

        $condition += ['status' => 'Unapprove'];

        $transaction = Transaction::where($condition);

        if(trim(strlen($from)) > 0 && trim(strlen($to)) > 0)
        {
          $from = EF::dateHtml($from);
          $to = EF::dateHtml($to);

          $transaction = $transaction->whereDate('created_at','>=',$from)->whereDate('created_at','<=',$to);
        }

        $transaction = $transaction->whereHas('singleJournal',function($query) use ($branch){

          if($branch > 0)
          {
              $query->where('branch_id',$branch);
          }

        });
        return $transaction->orderBy('id','asc')->get();

    }

      // VOUCHER NUMBER GENERATE SECTION
    public function getRejectedTransaction($type)
    {
        return Transaction::where(['is_recycle' => 1,'voucher_type' => $type])->where('voucher_number','>',0)->orderby('id','asc')->get();
    }

    public function generateSerialNumber($transaction)
    {

        $code = 0;

        $old_transaction_list = $transaction->getRejectedTransaction($transaction->voucher_type);

        foreach ($old_transaction_list as $rows) 
        {
            $rows->is_recycle = 2;

            $rows->update();

            return $rows->voucher_number;

        }

        $code = Transaction::where('voucher_type','=',$transaction->voucher_type)->max('voucher_number');


        if($code > 0)
        {     
            $formattedNumber = sprintf('%04d', ++$code);
        }
        else
        {
            $code = 1;

            $formattedNumber = sprintf('%04d', $code);
        }

        return $formattedNumber;


    } 

    // END

    // public function generateSerialNumber($transaction){
      
    //     $formattedNumber = null;
    //     $transaction =$transaction->maxVoucherNumber($transaction->voucher_type);
    //     if(isset($transaction)){     
    //         $formattedNumber = sprintf('%04d', ++$transaction);
    //     }
    //     else{

    //         $transaction = 1;
    //         $formattedNumber = sprintf('%04d', $transaction);
    //     }
    //     return $formattedNumber;
    // } 

    public function updateTransactionStatus($object){
       return \DB::transaction(function () use ($object) {

            $transaction = Transaction::find($object['transaction_id']);

            if(isset($transaction->id))
            {
              if($object['status']=='Approve'){ 
                  $transaction->voucher_number   = $this->generateSerialNumber($transaction->voucher_type,$transaction);
                  $transaction->status           = $object['status'];
                  $transaction->updated_at       = $object['date'];

                  $transaction->update();
                return 1;
                }
              if($object['status']=='Reject'){ 
             
                  $transaction->status           = $object['status'];
                  $transaction->is_recycle       = "1";
                  $transaction->updated_at       = $object['date'];
               
                  $transaction->update();
                return 1;
                }
            }
            else{
             
        
                return 0;
            }
            
           
        });
    }
    public function getTransactionById($id)
    {

      $condition = $this->getCondition();
      
        $condition += ['id'=> $id];

         return Transaction::where($condition)->first();

      

    }

    public function getRejectedTransactionById($id)
    {

      
        $condition = ['id'=> $id];

         return Transaction::where($condition)->first();

      
    }

    public function maxVoucherNumber($type){
      return Transaction::where('voucher_type','=',$type)->max('voucher_number');
    }

    public function reversalTransaction($id){
        return \DB::transaction(function () use ($id)  {
              
            $type=\EF::getVoucherList();            
            $transaction_data = Transaction::find($id);

            $transaction = new Transaction;
            $transaction->status            = "Reversal";
            $transaction->voucher_number    = $transaction_data->voucher_number;
            $transaction->voucher_type      = $type[4];
            $transaction->compound_type     = $transaction_data->compound_type;
            $transaction->total_amount      = $transaction_data->total_amount;
            $transaction->save();
         
            return \DB::getPdo()->lastInsertId();

        });

    }

     public function getChequeNumber($id)
     {
       
        $condition = $this->getCondition();
        $condition += ['transaction_id' => $id];

        $bank_detail = Journal::where($condition)->distinct('instrument')->get(['instrument','instrument_date','deposit_no','deposit_date']);
        
        $instrument = '';
        $deposit_no = '';
        $deposit_date = '';
        $instrument_date = '';


         foreach($bank_detail as $rows)
         {
            if(strlen($rows->instrument) > 0)
            {
              $instrument.= $rows->instrument.', ';
            }

            if(strlen($rows->deposit_no) > 0)
            {
              $deposit_no.= $rows->deposit_no.', ';
            }

            if(strlen($rows->deposit_date) > 0)
            {
              $deposit_date.= EF::dateFormat($rows->deposit_date).', ';
            }

            if(strlen($rows->instrument_date) > 0)
            {
              $instrument_date.= EF::dateFormat($rows->instrument_date).', ';
            }
         }

      

         return [

          'instrument'        => rtrim($instrument,', '),
          'instrument_date'   => rtrim($instrument_date,', '),
          'deposit_no'        => rtrim($deposit_no,', '),
          'deposit_date'      => rtrim($deposit_date,', '),

         ];



     }

     public function updateVendorInvoicePayments($curr_transaction)
     {
        $journal = new Journal;

        foreach ($journal->getDebitJournal($curr_transaction->id) as $rows) {

              if($rows->role_id > '0')
              {
                 $role_name = EF::getRoleNameById($rows->role_id);
                
              if($role_name == "Vendor" && in_array($curr_transaction->voucher_type,['JV','BPV','CPV']))
              {
             
                  $invoice = new Invoice;

                  $invoice->updateUnpaidVendorInvoice($rows->id,$rows->user_id,$rows->branch_id,$rows->debit,$journal->getVendorPayableLedger($rows->user_id,$rows->branch_id));
              }
            }
        }
     }

     public function updateVendorPaidInvoice($curr_transaction)
     {
      $journal = new Journal;

        foreach ($journal->getDebitJournal($curr_transaction->id) as $rows) {

              $role_name = EF::getRoleNameById($rows->role_id);

              if($role_name == "Vendor" && in_array($curr_transaction->voucher_type,['JV','BPV','CPV']))
              {
                  $invoice = new Invoice;

                  $invoice->updatePaidVendorInvoice($rows->id,$rows->debit);
              }

        }
      
     }

    public function singleJournal()
    {
       return $this->hasOne(Journal::class,'transaction_id')->withDefault();
    }

    public function journals()
    {
       return $this->hasMany(Journal::class,'transaction_id')->orderBy('id','asc')->where('is_recycle',0);
    }

    public function reverseTransaction()
    {
        return $this->hasOne(ReverseTransaction::class)->where($this->getCondition())->withDefault();
    }

   



}
