Your IP : 216.73.217.77


Current Path : /home/users/unlimited/www/sigmaerp.codeskitter.site/app/Http/Controllers/Party/
Upload File :
Current File : /home/users/unlimited/www/sigmaerp.codeskitter.site/app/Http/Controllers/Party/PartyController.php

<?php

namespace App\Http\Controllers\Party;

use App\Traits\FormatNumber;
use App\Traits\FormatsDateInputs;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Contracts\View\View;
use App\Http\Requests\PartyRequest;
use Yajra\DataTables\Facades\DataTables;
use Illuminate\Database\QueryException;

use App\Services\AccountTransactionService;
use App\Services\PartyTransactionService;
use App\Services\PartyService;
use App\Models\Party\Party;
use App\Models\Party\PartyTransaction;

use App\Enums\AccountUniqueCode;
use App\Models\Accounts\AccountGroup;
use App\Models\Accounts\Account;

class PartyController extends Controller
{
    use FormatsDateInputs;

    use FormatNumber;

    public $accountTransactionService;

    public $partyTransactionService;

    public $partyService;

    public function __construct(PartyTransactionService $partyTransactionService, AccountTransactionService $accountTransactionService, PartyService $partyService)
    {
        $this->partyTransactionService = $partyTransactionService;
        $this->accountTransactionService = $accountTransactionService;
        $this->partyService = $partyService;
    }

    public function getLang($partyType) : array
    {
        if($partyType == 'customer'){
            $lang = [
                'party_list' => __('customer.list'),
                'party_create' => __('customer.create_customer'),
                'party_update' => __('customer.update_customer'),
                'party_type' => $partyType,
                'party_details' => __('customer.details'),
            ];
        }else{
            $lang = [
                'party_list' => __('supplier.list'),
                'party_create' => __('supplier.create_supplier'),
                'party_update' => __('supplier.update_supplier'),
                'party_type' => $partyType,
                'party_details' => __('supplier.details'),
            ];
        }
        return $lang;
    }

    /**
     * Create a new party.
     *
     * @return \Illuminate\View\View
     */
    public function create($partyType) : View {
        $lang = $this->getLang($partyType);
        return view('party.create', compact('lang'));
    }

    /**
     * Edit a party.
     *
     * @param int $id The ID of the party to edit.
     * @return \Illuminate\View\View
     */
    public function edit($partyType, $id) : View {
        $lang = $this->getLang($partyType);

        $party = Party::where('party_type', $partyType)->whereId($id)->get()->first();
        if(!$party){
            return abort(403, 'Unauthorized');
        }


        $transaction = $party->transaction()->get()->first();//Used Morph

        $opening_balance_type = 'to_pay';
        $to_receive = false;
        if($transaction){
            $transaction->opening_balance = ($transaction->to_pay > 0) ? $this->formatWithPrecision($transaction->to_pay, comma:false) : $this->formatWithPrecision($transaction->to_receive, comma:false);

            $opening_balance_type = ($transaction->to_pay > 0) ? 'to_pay' : 'to_receive';
        }

        /**
         * Todays Date
         * */
        $todaysDate = $this->toUserDateFormat(now());

        return view('party.edit', compact('party', 'transaction', 'opening_balance_type', 'todaysDate', 'lang'));
    }



    /**
     * Return JsonResponse
     * */
    public function store(PartyRequest $request)  {
        try {

            DB::beginTransaction();

            /**
             * Get the validated data from the ItemRequest
             * */
            $validatedData = $request->validated();

            /**
             * Know which party type
             * `supplier` or `customer`
             * */
            $partyType = $request->party_type;

            /**
             * Know which operation want
             * `save` or `update`
             * */
            $operation = $request->operation;

            /**
             * Save or Update the Items Model
             * */
            $recordsToSave = [
                'first_name'        =>  $request->first_name,
                'last_name'         =>  $request->last_name,
                'email'             =>  $request->email,
                'mobile'            =>  $request->mobile,
                'phone'             =>  $request->phone,
                'whatsapp'          =>  $request->whatsapp,
                'party_type'        =>  $partyType,
                'tax_number'        =>  $request->tax_number,
                'shipping_address'  =>  $request->shipping_address,
                'billing_address'   =>  $request->billing_address,
                'is_set_credit_limit'=>  $request->is_set_credit_limit,
                'credit_limit'      =>  $request->credit_limit,
                'status'            =>  $request->status,
                'default_party'     =>  $request->default_party,
                'currency_id'       =>  $request->currency_id,
            ];
            if($request->has('state_id')){
                $recordsToSave['state_id'] = $request->state_id??null;
            }

            /**
             * for Party_type = "Customer"
             * */
            if($request->has('is_wholesale_customer')){
                $recordsToSave['is_wholesale_customer'] = $request->is_wholesale_customer;
            }

            if($request->operation == 'save'){
                $partyModel = Party::create($recordsToSave);
            }else{
                $partyModel = Party::find($request->party_id);

                //Load Party Transactions
                $partyTransactions = $partyModel->transaction;

                foreach ($partyTransactions as $partyTransaction) {
                    //Delete Account Transaction
                    $partyTransaction->accountTransaction()->delete();

                    //Delete Party Transaction
                    $partyTransaction->delete();
                }

                //Update the party records
                $partyModel->update($recordsToSave);
            }

            $request->request->add(['partyModel' => $partyModel]);

            /**
             * Update Party Transaction for opening Balance
             * */

            $transaction = $this->partyTransactionService->recordPartyTransactionEntry($partyModel, [
                    'transaction_date'      =>  $request->transaction_date,
                    'to_pay'                =>  ($request->opening_balance_type == 'to_pay')? $request->opening_balance??0 : 0,
                    'to_receive'                =>  ($request->opening_balance_type == 'to_receive')? $request->opening_balance??0 : 0,
                ]);
            if(!$transaction){
                throw new \Exception(__('party.failed_to_record_party_transactions'). " " . $recordDetails);
            }

            $this->accountTransactionService->partyOpeningBalanceTransaction($partyModel);

            //Account Create or Update
            $acccountCreateOrUpdate = $this->accountTransactionService->createOrUpdateAccountOfParty(partyId: $request->partyModel->id, partyName: $request->partyModel->first_name." ".$request->partyModel->last_name, partyType: $request->partyModel->party_type );
            if(!$acccountCreateOrUpdate){
                throw new \Exception(__('account.failed_to_create_or_update_account'));
            }

            //Update Other Default Party as a 0
            if($request->default_party){
                Party::where('party_type', $partyType)
                     ->whereNot('id', $request->partyModel->id)
                     ->update(['default_party' => 0]);
            }

            DB::commit();


            return response()->json([
                'status' => true,
                'message' => __('app.record_saved_successfully'),
                'data'  => [
                    'id' => $partyModel->id,
                    'first_name' => $partyModel->first_name,
                    'last_name' => $partyModel->last_name??'',
                    'curreny_id' => $partyModel->currency_id,
                ]
            ]);
        } catch (\Exception $e) {
                DB::rollback();

                return response()->json([
                    'status' => false,
                    'message' => $e->getMessage(),
                ], 409);

        }
    }


    /**
     * partyType: customer or supplier
     * */
    public function list($partyType) : View {
        $lang = $this->getLang($partyType);
        return view('party.list', compact('lang'));
    }

    public function datatableList(Request $request, $partyType){
        /**
         * party_type == customer then filter wholesale or retail customer
         * */
        $isWholesaleCustomer = $request->input('is_wholesale_customer');

        $data = Party::query()->where('party_type', $partyType);
        return DataTables::of($data)
                    ->filter(function ($query) use ($request, $isWholesaleCustomer) {
                        if ($request->has('search')) {
                            $searchTerm = $request->search['value'];
                            $query->where(function ($q) use ($searchTerm) {
                                $q->where('first_name', 'like', "%{$searchTerm}%")
                                  ->orWhere('last_name', 'like', "%{$searchTerm}%")
                                  ->orWhere('whatsapp', 'like', "%{$searchTerm}%")
                                  ->orWhere('phone', 'like', "%{$searchTerm}%")
                                  ->orWhere('email', 'like', "%{$searchTerm}%")
                                  ;
                            });
                        }
                        if($isWholesaleCustomer!==null){
                            $query->where('is_wholesale_customer', $isWholesaleCustomer);
                        }
                    })
                    ->addIndexColumn()
                    ->addColumn('created_at', function ($row) {
                        return $row->created_at->format(app('company')['date_format']);
                    })
                    ->addColumn('name', function ($row) {
                        return $row->first_name." ".$row->last_name;
                    })
                    ->addColumn('username', function ($row) {
                        return $row->user->username??'';
                    })
                    ->addColumn('balance', function ($row) {
                        // Store the balance data in the row
                        $row->balanceData = $this->partyService->getPartyBalance($row->id);

                        // Return the formatted balance
                        return $this->formatWithPrecision($row->balanceData['balance']);
                    })
                    ->addColumn('balance_type', function ($row) {
                        // Return the status using the stored balance data
                        return $row->balanceData['status'];
                    })
                    ->addColumn('action', function($row) use ($partyType){
                            $id = $row->id;

                            $editUrl = route('party.edit', ['id' => $id, 'partyType' => $partyType]);
                            $deleteUrl = route('party.delete', ['id' => $id, 'partyType' => $partyType]);
                            $transactionUrl = route('party.transaction.list', ['id' => $id, 'partyType' => $partyType]);
                            $paymentUrl = route('party.payment.create', ['id' => $id, 'partyType' => $partyType]);

                            $actionBtn = '<div class="dropdown ms-auto">
                            <a class="dropdown-toggle dropdown-toggle-nocaret" href="#" data-bs-toggle="dropdown"><i class="bx bx-dots-vertical-rounded font-22 text-option"></i>
                            </a>
                            <ul class="dropdown-menu">

                                <li>
                                    <a class="dropdown-item" href="' . $editUrl . '"><i class="bi bi-trash"></i><i class="bx bx-edit"></i> '.__('app.edit').'</a>
                                </li>
                                <li>
                                    <a class="dropdown-item" href="' . $paymentUrl . '"><i class="bi bi-trash"></i><i class="bx bx-money"></i> '.__('payment.payment').'</a>
                                </li>
                                <li>
                                    <a class="dropdown-item party-payment-history" data-party-id="' . $id . '" role="button"></i><i class="bx bx-table"></i> '.__('payment.history').'</a>
                                </li>
                                <li>
                                    <a class="dropdown-item" href="' . $transactionUrl . '"><i class="bi bi-trash"></i><i class="bx bx-transfer-alt"></i> '.__('app.transactions').'</a>
                                </li>
                                <li>
                                    <button type="button" class="dropdown-item text-danger deleteRequest" data-delete-id='.$id.'><i class="bx bx-trash"></i> '.__('app.delete').'</button>
                                </li>
                            </ul>
                        </div>';
                            return $actionBtn;
                    })
                    ->rawColumns(['action'])
                    ->make(true);
    }

    public function delete(Request $request) : JsonResponse{

        $selectedRecordIds = $request->input('record_ids');

        // Perform validation for each selected record ID
        foreach ($selectedRecordIds as $recordId) {
            $record = Party::find($recordId);
            if (!$record) {
                // Invalid record ID, handle the error (e.g., show a message, log, etc.)
                return response()->json([
                    'status'    => false,
                    'message' => __('app.invalid_record_id',['record_id' => $recordId]),
                ]);

            }
            // You can perform additional validation checks here if needed before deletion
        }

        /**
         * All selected record IDs are valid, proceed with the deletion
         * Delete all records with the selected IDs in one query
         * */
        try{


            // Attempt deletion (as in previous responses)
            Party::whereIn('id', $selectedRecordIds)->chunk(100, function ($parties) {
                foreach ($parties as $party) {
                    //Load Party Transactions like Opening Balance and other payments
                    $partyTransactions = $party->transaction;

                    foreach ($partyTransactions as $partyTransaction) {
                        //Delete Payment Account Transactions
                        $partyTransaction->accountTransaction()->delete();

                        //Delete Party Transaction
                        $partyTransaction->delete();
                    }
                }
            });

            //Delete party
            Party::whereIn('id', $selectedRecordIds)->delete();

        }catch (QueryException $e){
            return response()->json(['message' => __('app.cannot_delete_records')], 409);
        }

        return response()->json([
            'status'    => true,
            'message' => __('app.record_deleted_successfully'),
        ]);
    }
    /**
     * Ajax Response
     * Search Bar for select2 list
     * */
    function getAjaxSearchBarList(){
        $search = request('search');
        $partyType = request('party_type');

        $parties = Party::with('currency')->where(function($query) use ($search) {
                        $query->where('first_name', 'LIKE', "%{$search}%")
                              ->orWhere('last_name', 'LIKE', "%{$search}%")
                              ->orWhere('mobile', 'LIKE', "%{$search}%")
                              ->orWhere('phone', 'LIKE', "%{$search}%")
                              ->orWhere('email', 'LIKE', "%{$search}%");
                    })
                    ->select('id', 'first_name', 'last_name', 'mobile', 'is_wholesale_customer', 'to_pay', 'to_receive', 'currency_id')
                    ->where('party_type', $partyType)
                    ->limit(8)
                    ->get();

        $response = [
            'results' => $parties->map(function ($party) {
                $partyBalance = $this->partyService->getPartyBalance($party->id);

                return [
                    'id' => $party->id,
                    'text' => $party->getFullName(),
                    'mobile' => $party->mobile,
                    'currency_id' => $party->currency_id,
                    'currency_name' => $party->currency->name,
                    'currency_code' => $party->currency->code,
                    'currency_exchange_rate_current' => $party->currency->exchange_rate,
                    'is_wholesale_customer' => $party->is_wholesale_customer,
                    'to_pay' => $partyBalance['status']=='you_pay' ? $partyBalance['balance'] : 0,
                    'to_receive' => $partyBalance['status']=='you_collect' ? $partyBalance['balance'] : 0,
                ];
            })->toArray(),
        ];

        return json_encode($response);

    }
}