<?php

namespace App;

use DB;
use EF;
use Auth;
use App\Loan;
use App\Commission;
use App\Installment;
use App\Inventory\Payable;
use Spatie\Permission\Models\Role;
use Illuminate\Database\Eloquent\Model;
use Gisplus\Package\EstatechVendor\Models\Invoice;


class Payment extends Model
{
   private $generic_condition;
   private $generic_index;


    public function __construct()
    {

       $this->setCondition(['is_recycle' => '0']);

       $this->generic_index = EF::getGenericTableIndex();
    }

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





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

    public function getAllPayments($status = ['Approve','Reject','Reversal'])
    {
       return Payment::where($this->getCondition())->whereIn('status',$status)->get();
    }

    public function getAllInvoicePayments()
    {
        return Payment::where($this->getCondition())->where(['payment_type' => 'Pay Invoice','auto_jv' => 0])->with(['invoice'])->orderBy('id','desc')->get();
    }

    public function getInstallmentById($id,$column = "*")
    {

      $condition = $this->getCondition();
      $condition += ['id' => $id];
      return Installment::where($condition)->select($column)->first();

    }

    // public function getPaymentsByInstallment($installments)
    // {
    //           $condition = $this->getCondition();
    //        return Payment::where($this->getCondition())->whereIn('installment_id',$installments)->get();



    // }

    public function getPaymentsByInstallment($installments = [],$booking)
    {

        $condition = $this->getCondition() + ['generic_type_id' => $this->generic_index['Installment'], 'auto_jv' => 0];

        return Payment::where($condition)->whereIn('generic_id',[$installments])->whereIn('status',['Approve'])->whereHas('installment',function($query) use ($booking){

             $query->where($this->getCondition() + ['booking_id' => $booking]);

        })->get();
    }

    public function getAllHeads(){

        return Head::where($this->getCondition())->get();
     }

     public function createVoucher($object)
      {

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

         $transaction = new Transaction();

         $current_transaction = $transaction->storeTransaction($object);

         $object['transaction_id'] = $current_transaction->id;

         $this->storePayment($object);


        // IF NORMAL PAYMENT AUTO APPROVE

        if(isset($object['approve_transaction']) && $object['approve_transaction'] == true)
        {
            $voucher_data['status']           = 'Approve';

            $voucher_data['transaction_id']   = $current_transaction->id;

            $voucher_data['date']             = $current_transaction->created_at;

            $transaction = new Transaction;

            $approved_voucher = $transaction->updateStatusByTransaction($voucher_data);
        }      
        //  END NORMAL PAYMENT AUTO APPROVE 



         return with($current_transaction);


    });

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

            $index = 0;

            $journal = new Journal;




            foreach ($object['amount'] as $rows)
            {
                $payment = new Payment;

                $payment = $payment->getPaymentById($object['payment'][$index]);

                // VERIFIY IF PAYMENT IS NOT CREATED THEN CREATED;
                if(!isset($payment->id) && $object['generic_type'][$index] != 0)
                {

                    $new_payment['receipt']          = $object['receipt'];
                    $new_payment['mode']             = $object['payment_mode'][$index];
                    $new_payment['instrument']       = $object['instrument'][$index];
                    $new_payment['instrument_date']  = $object['instrument_date'][$index];
                    $new_payment['drawn_on']         = $object['drawn'][$index];
                    $new_payment['amount']           = $object['amount'][$index];
                    $new_payment['date']             = $object['date'];
                    $new_payment['generic_type']     = $object['generic_type'][$index];

                    if(isset($object['role'][$index]))
                    {
                        $new_payment['role']             = $object['role'][$index];
                    }
                    if($new_payment['generic_type'] === $this->generic_index['Booking'])
                    {
                        $new_payment['generic']          = $object['booking'][$index];
                    }
                    else
                    {
                        if(isset($object['generic'][$index]))
                        {
                             $new_payment['generic']          = $object['generic'][$index];
                        }
                        else
                        {
                            $new_payment['generic'] = 0;
                        }

                    }

                    $new_payment['payment_type']     = $object['payment_type'][$index];
                    $new_payment['description']      = $object['narration'][$index];
                    $new_payment['branch']           = $object['branch'][$index];
                    $new_payment['user']             = $object['user'][$index];
                    $new_payment['auto_jv']          = $object['auto_jv'];


                    // CREATE PAYMENT
                    $payment = $this->payGenericPayment($new_payment);

                }

                // VERIFIY 2 THINGS 1 IS PAYMENT AND OTHER IS GENERIC TYPE
                $generic_type = new GenericType;

                if(isset($payment->id) && isset($generic_type->getGenericTypeById($payment->generic_type_id)->id))
                {

                    $payment_data['id']         = $payment->id;

                    $payment->status            = 'Approve';

                    $payment->mode              = $object['payment_mode'][$index];
                    $payment->drawn_on          = $object['drawn'][$index];
                    $payment->instrument        = $object['instrument'][$index];
                    $payment->instrument_date   = $object['instrument_date'][$index];

                    $payment->update();

                    $payment_data['role']       =   $payment->role_id;

                    $payment_data['payment_id']        = $payment_data['id'];

                    // START GENERIC SECTION
                    if($payment->generic_type_id === $this->generic_index['Installment'])
                    {
                        $payment_data['booking_id'] = $payment->installment->booking->id;
                    }
                    elseif($payment->generic_type_id === $this->generic_index['Commission'])
                    {
                        $payment_data['booking_id'] = $payment->commission->booking->id;
                    }
                    elseif($payment->generic_type_id === $this->generic_index['Booking'])
                    {
                        $payment_data['booking_id'] = $payment->generic_id;
                    }
                    else
                    {
                        $payment_data['booking_id']        = 0;
                    }
                    // END GERNERIC SECTION

                    $payment_data['branch_id']         = $payment->branch_id;

                    $payment_data['user_id']           = $payment->user_id;

                    $payment_data['amount']            = $payment->amount;

                    $payment_data['mode']              = $payment->mode;

                    $payment_data['drawn_on']          = $payment->drawn_on;

                    $payment_data['instrument']        = $payment->instrument;

                    $payment_data['instrument_date']   = $payment->instrument_date;

                }
                else
                {
                    $payment_data['id']                = 0;
                    $payment_data['payment_id']        = 0;
                    $payment_data['booking_id']        = $object['booking'][$index];
                    $payment_data['branch_id']         = $object['branch'][$index];
                    $payment_data['user_id']           = $object['user'][$index];
                    if(isset($object['role'][$index])){
                        $payment_data['role']              = $object['role'][$index];
                    }
                    // $payment->post_dated        = $object['postdated'][$index];

                    $payment_data['amount']            = $rows;
                    $payment_data['mode']              = $object['payment_mode'][$index];
                    $payment_data['drawn_on']          = $object['drawn'][$index];
                    $payment_data['instrument']        = $object['instrument'][$index];
                    $payment_data['instrument_date']   = $object['instrument_date'][$index];

                }

                $payment_data['debit_account']     = $object['debit_subhead'][$index];
                $payment_data['credit_account']    = $object['credit_subhead'][$index];
                $payment_data['created_at']        = date('Y-m-d',strtotime($object['date']));
                $payment_data['status']            = 'Unapprove';
                $payment_data['description']       = $object['narration'][$index];
                $payment_data['deposit_no']        = $object['deposit_no'][$index];
                $payment_data['deposit_date']        = $object['deposit_date'][$index];

                $payment_data['voucher_list'] = $object['voucher_list'];

                $index++;


                    // $payment_data['installment_id']    = $object['installment'][$index];
                    // $payment_data['commission_id']     = $object['commission'][$index];


                    $journal->storeJournal($payment_data,$object['transaction_id']);
                // }

            }

        });
    }

    public function getRemovePayment($branch)
    {
        return Payment::where(['is_recycle' => 1, 'branch_id' => $branch, 'payment_type' => 'Installment','generic_type_id' => $this->generic_index['Installment']])->orderby('id','asc')->get();
    }

    public function generateReceiptNumber($branch_id)
    {
        $data = ['old_payment_id' => 0, 'code' => 0];

        $branch    =   new Branch;
        $payment   =   new Payment;

        $branch = $branch->getBranchById($branch_id);

        $old_payment_list = $payment->getRemovePayment($branch_id);

        if(isset($branch->id))
        {
            foreach ($old_payment_list as $rows) {

                $data['old_payment_id'] = $rows->id;

                $data['code']           = $rows->receipt_no;

                return $data;
            }

            $condition = $this->getCondition();

            $condition += ['branch_id' => $branch_id, 'payment_type' => 'Installment', 'generic_type_id' => $this->generic_index['Installment']];

            $max = Payment::where($condition)->max('receipt_no');


            if(strlen($max) > 0)
            {
                $code = explode('/',$max);

                if(isset($code[3]))
                {
                   $data['code'] = 'RS/RCPT/'.$branch->code.'/'.str_pad(($code[3]+1),5, '0', STR_PAD_LEFT);
                }
            }
            else
            {

                $data['code'] = 'RS/RCPT/'.$branch->code.'/'.str_pad((1),5, '0', STR_PAD_LEFT);

            }


        }

        return $data;
    }

    public function payGenericPayment($object)
    {
        return \DB::transaction(function () use ($object)  {
            // DECLARE MODELS
            $payment      = new Payment;
            // END DECLARE MODELS

            $payment->added_id       =  Auth::user()->id;

            // $payment->receipt_no      = $object['receipt'];
            $payment->mode            = $object['mode'];
            $payment->instrument      = $object['instrument'];
            $payment->instrument_date = $object['instrument_date'];
            $payment->drawn_on        = $object['drawn_on'];
            $payment->created_at      = str_replace('1970-01-01','',date('Y-m-d',strtotime($object['date'])));
         

            // GENERIC PAYMENT DETAIL SECTION
            $payment_detail = $this->getGenericPayment($object['generic_type'],$object['generic']);
            if(@count($payment_detail) > 0)
            {
                $payment->generic_type_id    = $payment_detail['generic_type_id'];
                $payment->generic_id         = $payment_detail['generic_id'];
                $payment->payment_type       = $payment_detail['payment_type'];
                $payment->description        = $payment_detail['description'];
                $payment->branch_id          = $payment_detail['branch'];
                $payment->user_id            = $payment_detail['user'];
                if(isset($payment_detail['role']) && $payment_detail['role']){
                    $payment->role_id            = $payment_detail['role'];
                }
                else
                {
                    $payment->role_id = 0;
                }

                $code = $this->generateReceiptNumber($payment->branch_id);

                if(isset($code['code']) && $payment->payment_type === "Installment")
                {
                    $payment->receipt_no     =  $code['code'];
                }

                if(isset($code['old_payment_id']))
                {
                    $old_payment = Payment::find($code['old_payment_id']);

                    if(isset($old_payment->id))
                    {
                        $old_payment->is_recycle = '2';

                        $old_payment->update();
                    }
                }
            }
            else
            {
                if (isset($object['role'])) {
                    // first check if role exists then insert role ID
                    $role = new Role;
                    $role = $role->findById($object['role']);
                    if (isset($role->id)) {
                        $payment->role_id   =   $object['role'];
                    }
                }

                $payment->generic_type_id    = $object['generic_type'];
                $payment->generic_id         = $object['generic'];
                $payment->payment_type       = $object['payment_type'];
                $payment->description        = $object['description'];
                $payment->branch_id          = $object['branch'];
                $payment->user_id            = $object['user'];
            }

            $payment->amount             = $object['amount'];




            if(isset($object['auto_jv']))
            {
                $payment->auto_jv       = $object['auto_jv'];
                $payment->payment_type  = $object['payment_type'];
            }

             // PDC STAND FOR POST DATED CHEQUE
            if(isset($object['pdc']))
            {
                $payment->post_dated = 1;
            }
            else
            {
                $payment->post_dated = 0;
            }
            //GENERIC PAYMENT DETAIL SECTION
            $payment->save();

            // GENERIC TYPE PAYMENTS UPDATE LIKE INSTALLMENT AND COMMISSION ETC
            $this->genericPaymentVerification($payment);
            // END

            return with($payment);


        });
    }

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

            $payment  = Payment::find($object['payment']);

            if(isset($payment->id) && $payment->status === "Unapprove")
            {
                $old_amount = $payment->amount;

                $payment->receipt_no      = $object['receipt'];
                $payment->mode            = $object['mode'];
                $payment->instrument      = $object['instrument'];
                $payment->instrument_date = $object['instrument_date'];
                $payment->drawn_on        = $object['drawn_on'];
                $payment->created_at      = str_replace('1970-01-01','',date('Y-m-d',strtotime($object['date'])));

                $payment->amount          = $object['amount'];

                 // PDC STAND FOR POST DATED CHEQUE
                if(isset($object['pdc']))
                {
                    $payment->post_dated = 1;
                }
                else
                {
                    $payment->post_dated = 0;
                }
                $payment->update();

                if (isset($object['role'])) {
                    // first check if role exists then insert role ID
                    $role = new Role;
                    $role = $role->findById($object['role']);
                    if (isset($role->id)) {
                        $payment->role_id   =   $object['role'];
                    }
                }

                // GENERIC TYPE PAYMENTS UPDATE LIKE INSTALLMENT AND COMMISSION ETC
                $this->genericPaymentVerification($payment,$old_amount,false);
                // END
            }

            return with($payment);

        });
    }

    public function updateVoucherPayment($new_payment_id,$old_payment_id,$object)
    {
        return \DB::transaction(function () use ($new_payment_id,$old_payment_id,$object)  {

            $generic_type = new GenericType;

            $generic_type = $generic_type->getGenericTypeById($object['generic_type']);

            // CHECK IF BOTH PAYMENT IS EQUAL
            if($new_payment_id === $old_payment_id)
            {
                $payment  = Payment::find($old_payment_id);

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

                    $payment->mode            = $object['mode'];
                    $payment->instrument      = $object['instrument'];
                    $payment->instrument_date = $object['instrument_date'];
                    $payment->drawn_on        = $object['drawn'];
                    // $payment->amount          = $object['amount'];

                    $payment->update();



                    return with($payment);
                }
            }
            elseif($new_payment_id != $old_payment_id)
            {
                $this->updatePaymentStatusById($old_payment_id ,'Unapprove');

                $payment = Payment::find($new_payment_id);

                if(isset($payment->id))
                {
                    $payment->status = "Approve";

                    $payment->mode            = $object['mode'];
                    $payment->instrument      = $object['instrument'];
                    $payment->instrument_date = $object['instrument_date'];
                    $payment->drawn_on        = $object['drawn'];

                    $payment->update();

                    return $payment;
                }

            }


            return false;

        });
    }



    public function getGenericPayment($generic_type_id,$generic_id)
    {
        $data = [];

        // DECLARTION AND QUERY SECTION
        $generic_type = new GenericType;

        $generic_type = $generic_type->getGenericTypeById($generic_type_id);
        // END
        if(isset($generic_type->id))
        {
            if($generic_type->id === $this->generic_index['Installment'])
            {
                $installment = new Installment;

                $installment = $installment->getInstallmentById($generic_id);

                if(isset($installment->id))
                {
                    $data['generic_id']        =  $installment->id;
                    $data['generic_type_id']   =  $generic_type->id;

                    $data['payment_type']      =  'Installment';
                    $data['description']       =  $installment->description;
                    // $data['amount']            =  $installment->amount;
                    $data['branch']            =  $installment->booking->branch_id;
                    $data['user']              =  $installment->booking->user_id;
                    $data['role']              =  EF::getRoleIdByName('Customer');

                }
            }
            else if($generic_type->id === $this->generic_index['Commission'])
            {
                $commission = new Commission;

                $commission = $commission->getCommissionById($generic_id);

                if(isset($commission->id))
                {
                    $data['generic_id']        =  $commission->id;
                    $data['generic_type_id']   =  $generic_type->id;

                    $data['payment_type']      =  $commission->payment_type;
                    $data['description']       =  $commission->description;
                    // $data['amount']            =  $commission->amount;
                    $data['branch']            =  $commission->booking->branch_id;
                    $data['user']              =  $commission->user_id;
                    $data['role']              =  $commission->role_id;

                }
            }
            else if($generic_type->id === $this->generic_index['Invoice'])
            {
                $invoice = new Invoice;

                $invoice = $invoice->getInvoiceById($generic_id);


                if(isset($invoice->id))
                {
                    $description = $invoice->purchaseItems->pluck('description')->toarray();

                    $description = implode(',',$description);

                    $data['generic_id']        =  $invoice->id;
                    $data['generic_type_id']   =  $generic_type->id;
                    $data['description']       =  'Payment made against invoice no '.$invoice->invocie_no;
                    $data['payment_type']      =  'Pay Invoice';
                    $data['description']       =  'Pay Invoice';
                    $data['branch']            =  $invoice->branch_id;
                    $data['user']              =  $invoice->user_id;
                    $data['role']              =  $invoice->role_id;

                }
            }
            else if($generic_type->id === $this->generic_index['Vendor Payment'])
            {
                $vendor_payment = new VendorPayment;

                $vendor_payment = $vendor_payment->getVendorPaymentById($generic_id);

                if(isset($vendor_payment->id))
                {
                    $data['generic_id']        =  $vendor_payment->id;
                    $data['generic_type_id']   =  $generic_type->id;

                    $data['payment_type']      =  'Vendor Payment';
                    $data['description']       =  $vendor_payment->description;
                    // $data['amount']            =  $commission->amount;
                    $data['branch']            =  $vendor_payment->vendor->branch_id;
                    $data['user']              =  NULL;

                }
            }
            else if($generic_type->id === $this->generic_index['Inventory Payable'])
            {
                $payable         = new Payable;

                $payable = $payable->getPayableById($generic_id);
                $role_name =$payable->purchaseOrder->user->userRoles->pluck('name')->toArray();
                
                $role = new Role;

                $role = $role->findByName($role_name[0]);
                if (isset($role->id)) {
                    $data['user_type']      = $role->name;
                    $data['role']           = $role->id;
                }

                // $payable_payment = $this->getPaymentByPayableId($generic_id);
           
                if(isset($payable->id))
                {
                    $data['generic_id']        =  $payable->id;
                    $data['generic_type_id']   =  $generic_type->id;
                    $data['payment_type']      =  'Inventory Payable';
                    $data['description']       =  'Payable against '.$payable->grn->grn_number;
                    $data['branch']            =  $payable->purchaseOrder->boq->branch_id;
                    $data['user_name']         =  $payable->purchaseOrder->user->name;
                    $data['user']              =  $payable->purchaseOrder->user_id;


                }
            }
        }
        return $data;
    }

    public function genericPaymentVerification($payment,$old_amount = 0,$flag = true)
    {
        if($payment->generic_type_id === $this->generic_index['Installment'])
        {
            if($payment->status === "Reversal" || $payment->auto_jv != 1)
            {
               // WHEN NEW PAYMENT APPEAR
                if($flag === true)
                {
                    $payment_detail_list = array();

                    $installment_description = '';

                    $installment = new Installment;

                    // ACC TO PAY MULTIPLE INSTALLMENT STRUCTURE


                    $payment_amount = $payment->amount;

                    $installment_detail = $installment->updateInstallmentByPayment($payment->generic_id,$payment_amount,0);

                    $remaining_amount = $installment_detail['remaining_amount'];
                    $payment_detail_list[] = array(

                        'payment_id'        => $payment->id,
                        'installment_id'    => $installment_detail['installment']->id,
                        'amount'            => $installment_detail['collect_amount'],
                        'penalty_amount'    => 0,
                    );

                    $installment_description.= $installment_detail['installment']->description.', ';

                    $unpaid_installment = $installment->getInstallmentByStauts($installment_detail['installment']->booking_id,['Unpaid'],'asc');

                    foreach ($unpaid_installment as $rows)
                    {
                        if($remaining_amount > 0)
                        {
                            $installment_detail = $installment->updateInstallmentByPayment($rows->id,$remaining_amount,0);

                            $remaining_amount = $installment_detail['remaining_amount'];

                            $payment_detail_list[] = array(

                                'payment_id'        => $payment->id,
                                'installment_id'    => $installment_detail['installment']->id,
                                'amount'            => $installment_detail['collect_amount'],
                                'penalty_amount'    => 0,
                            );

                            $installment_description.= $installment_detail['installment']->description.', ';
                        }
                        else
                        {
                            break;
                        }


                    }

                    $payment_detail = new PaymentDetail;

                    $payment_detail->bulkStorePaymentDetail($payment_detail_list);

                    $payment->description = rtrim($installment_description,', ');

                    $payment->update();



                    // END



                }
                // WHEN PAYMENT IS UPDATE
                else
                {
                    $payment_detail = new PaymentDetail;

                    $installment = new Installment;

                    $remaining_amount = $payment->amount;

                    $installment_description = '';


                    $payment_detail_list = $payment_detail->getPaymentDetailByPayment($payment->id);

                    foreach ($payment_detail_list as $rows)
                    {
                        if($remaining_amount > 0)
                        {
                            $installment_detail = $installment->updateInstallmentByPayment($rows->installment_id,$remaining_amount,$rows->amount);

                            $remaining_amount = $installment_detail['remaining_amount'];

                            $installment_description.= $installment_detail['installment']->description.', ';

                            $rows->amount = $installment_detail['collect_amount'];

                            $rows->save();

                        }
                        else
                        {
                           $installment_detail = $installment->updateInstallmentByPayment($rows->installment_id,0,$rows->amount);

                            $rows->is_recycle   = '1';

                            $rows->save();
                        }

                    }

                    $payment_detail_list = array();

                    $unpaid_installment = $installment->getInstallmentByStauts($installment_detail['installment']->booking_id,['Unpaid'],'asc');

                    foreach ($unpaid_installment as $rows)
                    {
                        if($remaining_amount > 0)
                        {
                            $installment_detail = $installment->updateInstallmentByPayment($rows->id,$remaining_amount,0);

                            $remaining_amount = $installment_detail['remaining_amount'];

                            $payment_detail_list[] = array(

                                'payment_id'        => $payment->id,
                                'installment_id'    => $installment_detail['installment']->id,
                                'amount'            => $installment_detail['collect_amount'],
                                'penalty_amount'    => 0,
                            );

                            $installment_description.= $installment_detail['installment']->description.', ';

                        }
                        else
                        {
                            break;
                        }


                    }

                    if(@count($payment_detail_list) > 0)
                    {
                        $payment_detail = new PaymentDetail;

                        $payment_detail->bulkStorePaymentDetail($payment_detail_list);
                    }

                    if(strlen(trim($installment_description)) > 0)
                    {
                        $payment->description = rtrim($installment_description,', ');

                        $payment->update();

                    }



                }
            }

        }
        else if($payment->generic_type_id === $this->generic_index['Commission'])
        {
            if($payment->status === "Reversal" || $payment->auto_jv != 1)
            {
                // WHEN NEW PAYMENT APPEAR
                if($flag === true)
                {
                    $commission = new Commission;

                    $commission->updateCommissionByPayment($payment->generic_id,$payment->amount,0);
                }
                // WHEN PAYMENT IS UPDATE
                else
                {
                    $commission = new Commission;

                    $commission->updateCommissionByPayment($payment->generic_id,$payment->amount,$old_amount);
                }
            }

        }
        else if($payment->generic_type_id === $this->generic_index['Loan'])
        {

             $loan = new Loan;

             $curr_loan = $loan->getLoanById($payment->generic_id);

             if(isset($curr_loan->id))
             {
                 $initialized_loan        =  $loan->initializeLoanById($curr_loan->id);
             }
        }
        else if($payment->generic_type_id === $this->generic_index['Payroll'])
        {
            $payroll = new Payroll;

            $curr_payroll = $payroll->getPayrollById($payment->generic_id);

            if(isset($curr_payroll->id))
            {
                  $payroll_obj['status'] = 'Approved';
                  $payroll_obj['id']     = $curr_payroll->id;
                  $updated_payroll       = $payroll->updatePayrollStatus($payroll_obj);
            }
        }
        else if($payment->generic_type_id == $this->generic_index['Inventory Payable'])
        {
    // WHEN NEW PAYMENT APPEAR
                if($flag === true)
                {
                    $payable = new Payable;

                    $payable->updatePayableByPayment($payment->generic_id,$payment->amount,0);
                }
                // WHEN PAYMENT IS UPDATE
                else
                {
                    $payable = new Payable;

                    $payable->updatePayableByPayment($payment->generic_id,$payment->amount,$old_amount);
                }
            }
            else if($payment->generic_type_id === $this->generic_index['Invoice'])
            {
                if($payment->status === "Reversal" || $payment->auto_jv != 1)
                {
                    // WHEN NEW INVOICE APPEAR
                    if($flag === true)
                    {
                        $invoice = new Invoice;
    
                        $invoice->updateInvoiceByPayment($payment->generic_id,$payment->amount,0);
                    }
                    // WHEN INVOICE IS UPDATE
                    else
                    {
                        $invoice = new Invoice;
    
                        $invoice->updateInvoiceByPayment($payment->generic_id,$payment->amount,$old_amount);
                    }
                }
                 
               
            }
            else if($payment->generic_type_id === $this->generic_index['Vendor Payment'])
            {
                if($payment->status === "Reversal" || $payment->auto_jv != 1)
                {
                    // WHEN NEW PAYMENT APPEAR
                    if($flag === true)
                    {
                        $vendor_payment = new VendorPayment;

                        $vendor_payment->updateVenderPaymentById($payment->generic_id,$payment->amount,0);
                    }
                    // WHEN PAYMENT IS UPDATE
                    else
                    {
                        $vendor_payment = new VendorPayment;
                        

                        $vendor_payment->updateVenderPaymentById($payment->generic_id,$payment->amount,$old_amount);
                    }
                }
                
            }

    }

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


            $payment      = new Payment;
            $installment  = new Installment;
            $commission   = new Commission;

            $payment->user_id         = $object['user'];

            $payment->booking_id      = $object['booking'];

            $payment->receipt_no      = $object['receipt'];
            $payment->mode            = $object['mode'];
            $payment->instrument      = $object['instrument'];
            $payment->instrument_date = $object['instrument_date'];
            $payment->drawn_on        = $object['drawn_on'];
            $payment->created_at      = str_replace('1970-01-01','',date('Y-m-d',strtotime($object['date'])));

             // TWO NEW COLUMN INTRODUCE GENERIC TYPE & ID
            if(isset($object['generic_type']))
            {
                $payment->generic_type_id = $object['generic_type'];
            }

            if(isset($object['generic']))
            {
                $payment->generic_id = $object['generic'];
            }
            // END

            if(isset($object['deposit_no']))
            {
                $payment->deposit_no = $object['deposit_no'];
            }

            if(isset($object['deposit_date']))
            {
               $payment->deposit_date = str_replace('1970-01-01','',date('Y-m-d',strtotime($object['deposit_date'])));
            }

            // PAYMENT CONFIRMATION AREA
            $installment = $installment->getInstallmentById($object['installment']);

            $commission = $commission->getCommissionById($object['commission']);


            if(isset($installment->id))
            {
                $payment->installment_id  = $installment->id;
                $payment->payment_type    = 'Installment';
                $payment->description     = $installment->description;
                $payment->amount          =  $object['amount'];
                $payment->branch_id = $payment->booking->branch_id;

            }
            elseif(isset($commission->id))
            {
                $payment->commission_id  = $commission->id;

                $payment->payment_type = $commission->payment_type;
                $payment->description  = $commission->description;
                $payment->amount       =  $object['amount'];
                $payment->branch_id = $payment->booking->branch_id;

            }
            else
            {
                $payment->payment_type = $object['payment_type'];
                $payment->description  = $object['description'];
                $payment->amount       = $object['amount'];
                $payment->branch_id    = $object['branch'];

            }
            // END PAYMENT CONFIRMATION AREA


            $payment->save();


            // GENERIC TYPE PAYMENTS UPDATE LIKE INSTALLMENT AND COMMISSION
            $installment = new Installment;
            $curr_installment = $installment->updateInstallmentByPayment($payment->installment_id,$payment->amount,0);

            $commission = new Commission;
            $curr_commission = $commission->updateCommissionByPayment($payment->commission_id,$payment->amount,0);
            // END


            return with($payment);


        });
    }

    


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


            $payment = Payment::find($object['payment']);

            if(isset($payment->id) && $payment->status == "Unapprove")
            {

                $payment->receipt_no      = $object['receipt'];
                $payment->mode            = $object['mode'];
                $payment->instrument      = $object['instrument'];
                $payment->instrument_date = $object['instrument_date'];
                $payment->drawn_on        = $object['drawn_on'];
                $payment->created_at      = str_replace('1970-01-01','',date('Y-m-d',strtotime($object['date'])));

                if(isset($object['deposit_no']))
                {
                    $payment->deposit_no = $object['deposit_no'];
                }

                if(isset($object['deposit_date']))
                {
                   $payment->deposit_date =str_replace('1970-01-01','',date('Y-m-d',strtotime($object['deposit_date'])));
                }


                if(isset($payment->installment->id))
                {
                      $installment = new Installment;

                      // REMOVE OLDER ONE
                      $installment->updateInstallmentByPayment($payment->installment_id,0,$payment->amount);

                      // ADD NEWER ONE
                      $installment->updateInstallmentByPayment($payment->installment_id,$object['amount'],0);

                      $payment->amount          =  $object['amount'];

                }
                elseif(isset($payment->commission->id))
                {
                    $commission = new Commission;

                    // REMOVE OLDER ONE
                    $commission->updateCommissionByPayment($payment->commission_id,0,$payment->amount);

                    // ADD NEWER ONE
                    $commission->updateCommissionByPayment($payment->commission_id,$object['amount'],0);

                    $payment->amount       =  $object['amount'];
                }


                $payment->update();

            }

            return with($payment);


        });
    }

    public function removePayment($id)
    {
        return DB::transaction(function () use ($id) {

            $payment = Payment::find($id);

            if(isset($payment->id) && $payment->status == "Unapprove")
            {
                // 1 MEAN INSTALLMENT
                if($payment->generic_type_id === $this->generic_index['Installment'])
                {
                    $payment_detail = new PaymentDetail;

                    $payment_detail->removePaymentDetailByPayment($payment->id);

                }
                // 2 MEAN COMMISSION
                elseif($payment->generic_type_id === $this->generic_index['Commission'])
                {
                    $commission = new Commission;

                    // REMOVE OLDER ONE
                    $commission->updateCommissionByPayment($payment->generic_id,0,$payment->amount);

                }

                // 3 MEAN INVENTORY PAYABLES
                elseif($payment->generic_type_id === $this->generic_index['Inventory Payable'])
                {
                    $payable = new Payable;

                    $payable->updatePayableByPayment($payment->generic_id,0,$payment->amount);
                 
                }

                $payment->is_recycle   = '1';

                $payment->update();


                return 1;
            }




            return 0;
        });
    }

    public function UpdatePaymentByJournal($id,$object)
    {
        return \DB::transaction(function () use ($id,$object){

        $payment = Payment::find($id);

        if(isset($payment->id))
        {
            if($object['status']== "Reject")
            {
                $payment->is_recycle = 1;

                $old_amount = $payment->amount;

                $reject_payment = $payment;

                $reject_payment->amount = 0;


                $this->genericPaymentVerification($reject_payment,$old_amount,false);

                $payment->amount = $old_amount;

                // if($payment->installment_id > 0)
                // {
                //    $installment = new Installment;
                //    $installment->updateInstallmentByPayment($payment->installment_id,0,$payment->amount);
                // }
                // else if($payment->commission_id > 0)
                // {
                //     $commission = new Commission;
                //     $commission->updateCommissionByPayment($payment->commission_id,0,$payment->amount);
                // }
            }



            $payment->status           = $object['status'];

            $payment->updated_at       = date('Y-m-d',strtotime($object['date']));

            $payment->update();
        }

        return with($payment);



      });

    }

 public function removeHead($id)
    {

        return DB::transaction(function () use ($id) {

            $head = Head::find($id);


            if(isset($head->id) && $this->isexsitSubhead($head->id)==0)
            {
                $head->is_recycle   = '1';
                $head->update();

                return 1;
            }

            return 0;
        });
    }



    public function isexsitSubhead($id)
    {
        return Account::where('head_id', $id)->count();
    }

    public function installment(){
        return $this->belongsTo(Installment::class,'generic_id')->where($this->getCondition())->withDefault();
    }

    public function inventoryPayable(){
        return $this->belongsTo(Payable::class,'generic_id')->where($this->getCondition())->withDefault();
    }

    public function invoice(){
        return $this->belongsTo(Invoice::class,'generic_id')->where($this->getCondition())->withDefault();
    }

    public function commission(){

       return $this->belongsTo(Commission::class,'generic_id')->where($this->getCondition())->withDefault();

    }
    public function booking()
    {
               return $this->belongsTo(Booking::class,'booking_id')->where($this->getCondition())->withDefault();
    }
    public function reversalPayment($id){
            $payment_data               = Payment::Find($id);
            $payment                    = new Payment;
            $payment->booking_id        = $payment_data->booking_id;
            $payment->branch_id         = $payment_data->branch_id;
            $payment->installment_id    = $payment_data->installment_id;
            $payment->commission_id     = $payment_data->commission_id;
            $payment->user_id           = $payment_data->user_id;
            $payment->post_dated        = $payment_data->post_dated;
            $payment->status            = "Reversal";
            $payment->description       = $payment_data->description;
            $payment->amount            = $payment_data->amount;
            $payment->payment_type      = $payment_data->payment_type ;
            $payment->mode              = $payment_data->mode;
            $payment->drawn_on          = $payment_data->drawn_on;
            $payment->instrument        = $payment_data->instrument;
            $payment->instrument_date   = $payment_data->instrument_date;
            $payment->save();
            return \DB::getPdo()->lastInsertId();
    }

    public function reversalVocuher($payment_id,$transaction_id,$journal_id)
    {
        $payment_id=$this->reversalPayment($payment_id);



        $transaction    = new Transaction;
        $transaction_id = $transaction->reversalTransaction($transaction_id);

        $journal = new Journal;
        $journal->reversalJournal($journal_id,$payment_id,$transaction_id);


    }

    public function getInstallmentPaymentList($booking,$generic_type_id,$status_in = ['Approve','Unapprove','Reversal'])
    {


        $condition = $this->getCondition() + ['generic_type_id' => $generic_type_id, 'auto_jv' => 0];

        return Payment::where($condition)->whereIn('status',$status_in)->whereHas('installment',function($query) use ($booking){

             $query->where($this->getCondition() + ['booking_id' => $booking]);

        })->get();
    }

    public function getAllInstallmentPaymentList($booking,$generic_type_id,$status_in = ['Approve','Unapprove','Reversal'])
    {

        $condition = ['generic_type_id' => $generic_type_id, 'auto_jv' => 0] + $this->getCondition();

        return Payment::where($condition)->whereIn('status',$status_in)->whereHas('installment',function($query) use ($booking){

             $query->where($this->getCondition() + ['booking_id' => $booking]);

        })->get();
    }

    public function getAllPayablePaymentList($generic_type_id,$status_in = ['Approve','Unapprove','Reversal'])
    {

        $condition = ['generic_type_id' => $generic_type_id,'is_recycle' => 0];

        return Payment::where($condition)->whereIn('status',$status_in)->whereHas('inventoryPayable',function($query) use ($condition){

             $query->where($this->getCondition());

        })->get();
    }

    
    public function getCommissionPaymentList($booking,$generic_type_id,$status_in = ['Approve','Unapprove','Reversal'])
    {

        $condition = $this->getCondition() + ['generic_type_id' => $generic_type_id,'auto_jv' => 0];

        return Payment::where($condition)->whereIn('status',$status_in)->whereHas('commission',function($query) use ($booking){

             $query->where($this->getCondition() + ['booking_id' => $booking]);

        })->get();
    }

    public function getAllCommissionPaymentList($booking,$generic_type_id,$status_in = ['Approve','Unapprove','Reversal']){

        $condition = ['generic_type_id' => $generic_type_id,'auto_jv' => 0] + $this->getCondition();

        return Payment::where($condition)->whereIn('status',$status_in)->whereHas('commission',function($query) use ($booking){

             $query->where($this->getCondition() + ['booking_id' => $booking]);

        })->get();
    }

    public function getOtherPaymentList($generic_type_id,$status_in = ['Approve','Unapprove'])
    {
        $condition = $this->getCondition() + ['generic_type_id' => $generic_type_id,  'auto_jv' => 0];

        return Payment::where($condition)->whereIn('status',$status_in)->get();
    }

    public function getPaymentByGenericIdWithType($generic_id,$generic_type_id,$status_in = ['Approve','Unapprove'])
    {
        
        $condition = $this->getCondition() + ['generic_type_id' => $generic_type_id,'generic_id' => $generic_id, 'auto_jv' => 0];

        return Payment::where($condition)->whereIn('status',$status_in)->get();
    }

    public function getBookingPayments($booking_id,$type = ["Installment","Commission","Transfer","Refund","Deduction","Document Charges","Baloon Charges"],$status_in = ['Approve','Unapprove','Reversal'],$column = '*')
    {

        $condition = $this->getCondition();

        $condition += ['booking_id'=>$booking_id];

       return $payment_list = Payment::where($condition)->whereIn('payment_type',$type)->whereIn('status',$status_in)->orderBy('id','desc')->select($column)->get();


    }

    public function getPaymentById($id)
    {

        $condition = $this->getCondition();

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


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

    }

    public function getPaymentByIdWithRecycle($id)
    {

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


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

    }

    public function getPaymentByPayableId($generic_id)
    {
        $condition = $this->getCondition() + ['generic_id' => $generic_id];

        return Payment::where($condition)->first();
    }

    public function updatePaymentLedger($journal,$ledger)
    {
       return \DB::transaction(function () use ($journal,$ledger) {

           $payment = Payment::find($journal->payment_id);

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

               $payment->booking_id        = $ledger['booking_id'];
               $payment->description       = $ledger['narration'];
               $payment->mode              = $ledger['mode'];
               $payment->drawn_on          = $ledger['drawn'];
               $payment->instrument        = $ledger['instrument'];
               $payment->instrument_date   = $ledger['instrument_date'];
               $payment->created_at        = $ledger['date'];
               $payment->user_id           = $ledger['user_id'];

            // INSTALLMENT PART

                // REBACK THE OLD INSTALLMENT
                $installment = new Installment;

                $curr_installment = $installment->updateInstallmentByPayment($payment->installment_id,0,$payment->amount);

                // BIND THE NEW INSTALLMENT
                $installment = new Installment;
                $curr_installment =  $installment->updateInstallmentByPayment($ledger['installment_id'],$ledger['amount'],0);

            // END INSTALLMENT PART

            // COMMISSION PART

                // REBACK THE OLD COMMISSION
                $commission = new Commission;
                $curr_commission = $commission->updateCommissionByPayment($payment->commission_id,0,$payment->amount);

                // BIND THE NEW INSTALLMENT
                $commission = new Commission;
                $curr_commission = $commission->updateCommissionByPayment($ledger['commission_id'],$ledger['amount'],0);

            // END COMMISSION

                // INSTALLMENT CONFIRMATION
               if(isset($curr_installment->id))
               {
                    $payment->installment_id = $curr_installment->id;
                    $payment->user_id        = $curr_installment->booking->user_id;

               }
               else
               {
                    $payment->installment_id = NULL;
               }

               // COMMISSION CONFIRMATION
               if(isset($curr_commission->id))
               {
                    $payment->commission_id     = $curr_commission->id;
                    $payment->user_id           = $curr_commission->user_id;
               }
               else
               {
                    $payment->commission_id     = NULL;

               }

               $payment->amount            = $ledger['amount'];



               $payment->update();



               return with($payment);


           }

       });
    }

    public function updatePaymentStatusById($id,$status)
    {

      return \DB::transaction(function () use ($id,$status)  {

        $payment = Payment::find($id);

        if(isset($payment->id))
        {
            $payment->status = $status;

            $payment->update();

            return with($payment);
        }

      });

    }

    public function getPaymentHistory($booking,$user_id,$generic_type_id,$status_in = ['Approve','Unapprove','Reversal'])
    {


        $condition = $this->getCondition() + ['generic_type_id' => $generic_type_id, 'auto_jv' => 0,'user_id' => $user_id];

        return Payment::where($condition)->whereIn('status',$status_in)->whereHas('installment',function($query) use ($booking){

             $query->where($this->getCondition() + ['booking_id' => $booking]);

        })->get();
    }

    // public function getPaymentHistory($booking_id,$user_id,$type = ["Installment"])
    // {



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

    //     $condition += ['booking_id'=>$booking_id , 'user_id'=> $user_id];


    //    $payment_list = Payment::where($condition)->whereIn('payment_type',$type)->orderBy('id','desc')->get();

    //    return $payment_list;
    // }

    public function incomeWiseReport($from,$to,$payment_condition = [],$booking_condition = [])
    {
      $payment_type = ['Installment','Transfer','Deduction','Baloon Charges','Document Charges'];

      $status_list = ['Approve','Reversal'];



      $payment_condition += $this->getCondition() + ['auto_jv' => 0];

        return Payment::where($payment_condition)->whereIn('status',$status_list)->whereHas('installment',function($query) use ($booking_condition){

             $query->where($booking_condition);

        })->whereDate('payments.created_at','>=',$from)

          ->whereDate('payments.created_at','<=',$to)

          ->whereIn('payments.payment_type',$payment_type)

          ->get();
    }

    public function getCollectionReport($from,$to,$payment_condition,$booking_condition,$status_in = ['Approve','Unapprove','Reversal'])
    {

        $condition = $this->getCondition() + ['generic_type_id' => $this->generic_index['Installment'], 'auto_jv' => 0] + $payment_condition;

        return Payment::where($condition)->whereIn('status',$status_in)->whereDate('created_at','>=',$from)->whereDate('created_at','<=',$to)->whereHas('installment',function($query) use ($booking_condition){

             $query->where($this->getCondition() + $booking_condition);

        })->get();
    }

    public function expenseWiseReport($from,$to,$payment_condition = [])
    {
      $payment_type = ['Expense','Commission','Refund'];

      return Payment::where($payment_condition)

              ->where($this->getCondition())

              ->whereDate('payments.created_at','>=',$from)

              ->whereDate('payments.created_at','<=',$to)

              ->whereHas('booking')

              ->whereIn('payments.payment_type',$payment_type)

              ->get();
      }

    public function user()
    {
        return $this->belongsTo(User::class,'user_id')->withDefault();
    }



    public function commissionReport($from,$to,$payment_condition = [],$booking_condition = [])
    {
        $payment_type = ['Installment','Transfer','Deduction','Baloon Charges','Document Charges'];

        $status_list = ['Approve','Reversal'];

        $payment_condition += $this->getCondition() + ['auto_jv' => 0];

        return Payment::where($payment_condition)->whereIn('status',$status_list)->whereHas('commission',function($query) use ($booking_condition){

             $query->where($booking_condition);

        })->whereDate('payments.created_at','>=',$from)

          ->whereDate('payments.created_at','<=',$to)

          ->whereNotIn('payments.payment_type',$payment_type)

          ->get();


    }

     public function removeBulkPayment($generic_type_name,$booking)
    {
        $generic_type = new GenericType;

        $generic_type = $generic_type->getGenericTypeByName($generic_type_name);

        if(isset($generic_type->id))
        {
            $generic_type = $generic_type->id;

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

            $update_column = ['is_recycle' => 1, 'status' => 'Reject'];

            if($this->generic_index['Installment'] == $generic_type)
            {
                return Payment::where($condition)->whereHas('installment', function ($query) use ($booking) {

                    $query->where( ['booking_id' => $booking]);
                })->update($update_column);
            }
            else if($this->generic_index['Commission'] == $generic_type)
            {

                return Payment::where($condition)->whereHas('commission', function ($query) use ($booking) {

                    $query->where(['booking_id' => $booking]);
                })->update($update_column);
            }
            else if($this->generic_index['Booking'] == $generic_type)
            {

                return Payment::where($condition + ['generic_id' => $booking])->update($update_column);
            }
           
        }
        

        
    }

    public function createBookingJv($booking,$debit_account,$credit_account)
    {
       return \DB::transaction(function () use ($booking,$debit_account,$credit_account)  {

        // SET DATA FOR THE PAYMENTS
          $payment_data['branch']              = $booking['branch_id'];
          $payment_data['receipt']             = NULL;
          $payment_data['user']                = $booking['user_id'];
          $payment_data['booking']             = $booking['id'];
          $payment_data['amount']              = $booking['agreed_amount'];
          $payment_data['description']         = 'Auto-JV.';
          $payment_data['payment_type']        = 'Booking JV';
          $payment_data['mode']                = NULL;
          $payment_data['instrument']          = NULL;
          $payment_data['instrument_date']     = NULL;
          $payment_data['drawn_on']               = NULL;
          $payment_data['installment']         = 0;
          $payment_data['commission']          = 0;
          $payment_data['date']                   = $booking['created_at'];
          // END DATA

          $payment = $this->payPayment($payment_data);

          $form_jv['voucher_list']           = 'JV';
          $form_jv['compound_type']          = 'General';
          $form_jv['branch'][0]              = $payment_data['branch'];
          $form_jv['user'][0]                = $payment_data['user'];
          $form_jv['booking'][0]             = $payment_data['booking'];
          $form_jv['amount'][0]              = $payment_data['amount'];
          $form_jv['narration'][0]           = $payment_data['description'];
          $form_jv['description'][0]         = 'Auto-JV.';
          $form_jv['payment_type'][0]        = $payment->id;
          $form_jv['payment_mode'][0]        = $payment_data['mode'] ;
          $form_jv['instrument'][0]          = $payment_data['instrument'];
          $form_jv['instrument_date'][0]     = $payment_data['instrument_date'] ;
          $form_jv['drawn'][0]               = $payment_data['drawn_on'] ;
          $form_jv['debit_subhead'][0]       = $debit_account;
          $form_jv['credit_subhead'][0]      = $credit_account;
          $form_jv['date']                   = $payment_data['date'] ;

          // dd($form_jv[0]);


          $curr_transaction = $this->createVoucher($form_jv);

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

              $transaction_approval['transaction_id'] = $curr_transaction->id;

              $transaction_approval['status'] = 'Approve';

              $transaction_approval['date']   = $booking['approve_date'];

              $transaction = new Transaction;

              $curr_transaction = $transaction->updateStatusByTransaction($transaction_approval);

          }

          return with($curr_transaction);

         });
    }

    // LIKE BOOKING DETAIL / LOAN DETAIL / INVENTORY DETAIL
    public function showGenericTypeDetail($payment)
    {
        $data = [
            'description' => 'NA',
        ];


        if(isset($payment->id))
        {
            if($payment->generic_type_id === $this->generic_index['Installment'])
            {
                $data['description'] = EF::showPlotFormat($payment->installment->booking->plot);
            }
            else if($payment->generic_type_id === $this->generic_index['Commission'])
            {
                $data['description'] = EF::showPlotFormat($payment->commission->booking->plot);
            }
        }

        return $data;
    }

    public function updateAutoJvSidePayment($generic,$generic_type,$amount)
    {
       return \DB::transaction(function () use ($generic,$generic_type,$amount)  {

            $payment = Payment::where($this->getCondition() + ['generic_id' => $generic, 'generic_type_id' => $generic_type, 'auto_jv' => 1, 'status' => 'Approve'])->first();


            if(isset($payment->id))
            {
                $payment->amount = $amount;

                $payment->update();

                $journal = new Journal;

                $journal->updateJournalAmountByPayment($payment->id,$payment->amount);
            }

            

            return with($payment);

        });
    }

    public function removeAutoJvSidePayment($generic,$generic_type)
    {
       return \DB::transaction(function () use ($generic,$generic_type)  {

            $payment = Payment::where($this->getCondition() + ['generic_id' => $generic, 'generic_type_id' => $generic_type, 'auto_jv' => 1, 'status' => 'Approve'])->first();
            if(isset($payment->id))
            {
                $payment->status = 'Reject';

                $payment->is_recycle = '1';

                $payment->update();

                $journal = new Journal;

                $journal->removeJournalAmountByPayment($payment->id);
            }



            return with($payment);

        });
    }



 // FORIGN KEY TYPE FUNCTION LIST
    public function branch()
    {
        return $this->belongsTo(Branch::class,'branch_id')->where($this->getCondition())->withDefault();
    }

    public function genericType()
    {
        return $this->belongsTo(GenericType::class,'generic_type_id')->withDefault();
    }

    public function systemUser()
    {
        return $this->belongsTo(User::class,'added_id')->withDefault();
    }

    public function role()
    {
        return $this->belongsTo(Role::class)->withDefault();
    }



}
