=== WEB RETURN ROUTES ===

====================================================================================================
CONTEXT_FILE=routes/web.php
====================================================================================================
      81:         Route::get('products/report', 'ProductsController@getReport')->name('products.report');
      82:         Route::get('products/getproductbarcode/{product}', 'ProductsController@getProductBarcode')->name('products.barcode');
      83:         Route::get('products/generateBarCode', 'ProductsController@generateBarCode')->name('products.generateBarCode');
      84:         Route::get('products/priceList', 'ProductsController@priceList')->name('products.priceList');
      85:         Route::get('products/search/getProductList/{is_raw?}', 'ProductsController@getProductList')->name('products.getProductList');
>>    86:         Route::get('products/getReturnsList', 'ProductsController@getReturnsList')->name('products.getReturnsList');
      87:         Route::get('products/getCriticalQuantity', 'ProductsController@getCriticalQuantity')->name('products.getCriticalQuantity');
      88:         Route::get('products/list/{is_raw?}', 'ProductsController@index')->name('products.index');
      89:         Route::resource('combinations', 'CombinationController');
      90:         Route::resource('products', 'ProductsController');
      91:         Route::resource('services', 'ServicesController');
      92:         Route::get("orders/getDetails", 'OrdersController@getDetails')->name('orders.details');
      93:         
      94:         Route::get('reservations/scheduler/data', 'ReservationController@schedulerData')->name('reservations.schedulerData');
      95: Route::post('reservations/appointments', 'ReservationController@storeAppointment')->name('reservations.appointments.store');
      96: Route::put('reservations/appointments/{appointment}', 'ReservationController@updateAppointment')->name('reservations.appointments.update');
      97: Route::post('reservations/appointments/{appointment}/move', 'ReservationController@moveAppointment')->name('reservations.appointments.move');
      98: Route::delete('reservations/appointments/{appointment}', 'ReservationController@cancelAppointment')->name('reservations.appointments.cancel');
----------------------------------------------------------------------------------------------------
     116:         Route::post('orders/{order}/zatca/submit', 'OrdersController@submitZatca')->name('orders.zatca.submit');
     117:         Route::post('orders/zatca/queue-manual', 'OrdersController@queueZatcaManual')->name('orders.zatca.queue-manual');
     118:         Route::post('orders/zatca/dismiss-ask', 'OrdersController@dismissZatcaAsk')->name('orders.zatca.dismiss-ask');
     119:         Route::get('orders/{order}/zatca/preview', 'OrdersController@previewZatca')->name('orders.zatca.preview');
     120:         Route::get('orders/{order}/zatca/pdf-a3', 'OrdersController@downloadZatcaPdfA3')->name('orders.zatca.pdf-a3');
>>   121:         Route::post('returns/{id}/zatca/submit', 'ReturnsController@submitZatca')->name('returns.zatca.submit');
     122:         Route::get('zatca/dashboard', 'ZatcaDashboardController@index')->name('zatca.dashboard');
     123:         Route::post('zatca/send-next', 'ZatcaDashboardController@sendNext')->name('zatca.send-next');
     124:         Route::get('zatca/files', 'ZatcaFilesController@index')->name('zatca.files');
     125:         Route::get('zatca/files/download', 'ZatcaFilesController@download')->name('zatca.files.download');
     126:         Route::resource('zatca-credentials', 'ZatcaCredentialController')->only(['index', 'create', 'store', 'edit', 'update', 'destroy']);
     127:         Route::post('zatca-credentials/{zatca_credential}/renew', 'ZatcaCredentialController@renew')->name('zatca-credentials.renew');
     128:         Route::get('returns/getPrint/{id}', 'ReturnsController@getPrint')->name('returns.getPrint');
     129:         Route::get('expenses/report', 'ExpensesController@report')->name('expenses.report');
     130:         Route::get('generaltaxreturnreport/report', 'ExpensesController@generaltaxreturnreport')->name('generaltaxreturnreport');
     131: 
     132:         Route::resource('expenses', 'ExpensesController');
     133:         Route::resource('damageOptions', 'DamageOptionController');
----------------------------------------------------------------------------------------------------
     134: 
     135:         Route::resource('tresuryTranactions', 'TresuryTranactionsController');
     136:         Route::resource('returns', 'ReturnsController');
     137:         Route::get('orderReturn/create', 'ReturnsController@createSales')->name('orderReturn.create');
     138:         Route::get('purchaseReturn/create', 'ReturnsController@createPurchase')->name('purchaseReturn.create');
     139:         Route::get('ordersReturn', 'ReturnsController@getSales')->name('ordersReturn.index');
     140:         Route::get('purchasesReturn', 'ReturnsController@getPurchases')->name('purchasesReturn.index');
----------------------------------------------------------------------------------------------------
     141:         Route::resource('users', 'UsersController');
     142:         Route::resource('roles', 'RolesController');
     143:         Route::any('employees/punishments_rewards/{employee}', 'EmployeesController@addPunishmentsRewards')->name('employees.addPunishmentsRewards');
     144:         Route::any('salesmanreport', 'EmployeesController@getSalesManReport')->name('employees.getSalesManReport');
     145:         Route::resource('employees', 'EmployeesController');
     146:         Route::any('Bank/addTransaction/{bank}', 'BanksController@addTransaction')->name('banks.addTransaction');
     147:         Route::get('trans/{id}', 'BanksController@banktransaction')->name('banktransaction');
     148:         Route::get('banks/index/{type?}', 'BanksController@index')->name('tresurycurrency');
----------------------------------------------------------------------------------------------------
     149:         Route::get('banks/create/{type?}', 'BanksController@create')->name('banks.create');
----------------------------------------------------------------------------------------------------
     150:         Route::resource('banks', 'BanksController');
----------------------------------------------------------------------------------------------------
     151:         Route::resource('currencies', 'CurrenciesController');
----------------------------------------------------------------------------------------------------
     152:         Route::resource('damages', 'DamagesController');
----------------------------------------------------------------------------------------------------

=== API RETURN ROUTES ===

====================================================================================================
CONTEXT_FILE=routes/api.php
====================================================================================================
      40:     // Mirrors branding/logo — bypasses broken public/storage symlinks on shared hosts.
      41:     Route::get('products/{id}/image', 'ProductController@image');
      42: 
      43:     // Device license status (no auth): the blocked-device screen polls this
      44:     // after a 423 so approval activates the device without reinstalling.
>>    45:     // Returns only the calling device's own status (X-Device-Id header).
      46:     Route::get('device/status', 'DeviceController@status');
      47: 
      48:     // Subscription status: auth only (not api.subscription/api.device) so the
      49:     // app can re-check after expiry/approval without being blocked.
      50:     Route::middleware('auth:api')->group(function () {
      51:         Route::get('subscription', 'SubscriptionController@show');
      52:     });
      53: 
      54:     Route::middleware(['auth:api', 'api.device', 'api.subscription'])->group(function () {
      55:         Route::post('auth/logout', 'AuthController@logout');
      56:         Route::get('auth/me', 'AuthController@me');
      57: 
----------------------------------------------------------------------------------------------------
      76:         Route::post('invoices/{id}/zatca/submit', 'InvoiceController@submitZatca');
      77:         Route::get('invoices/{id}', 'InvoiceController@show');
      78:         Route::get('invoices/{id}/receipt', 'InvoiceController@receipt');
      79: 
      80:         // Optional later — keep available but not required for printer MVP
>>    81:         Route::get('returns', 'ReturnApiController@index');
      82:         Route::post('returns', 'ReturnApiController@store');
      83:         Route::get('returns/{id}', 'ReturnApiController@show');
      84:     });
      85: });
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------

=== RETURNS CONTROLLER ===

====================================================================================================
FILE=app/Http/Controllers/ReturnsController.php
====================================================================================================
FILE_FOUND=YES

--- METHOD=create ---
	public function create($type) {
		$return  = new ReturnProduct;
        //dd($return->details);
		return view('returns.create', compact('return','type'));
	}

--- METHOD=store ---
	public function store(Request $request) {

	    try {
            DB::beginTransaction();
            $inputs = $request->except('_token');
            $inputs['order']['creator_id'] = auth()->user()->id;
            $inputs['order']['is_cash'] = $request->has('is_cash');
            $inputs['order']['discount_type'] = isset($inputs['order']['discount_type'])?2:1;
            $inputs['order']['sales_value_egp'] = currency($inputs['order']['sales_value'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
            $order = null;
            if($inputs['order']['order_id']){
                $order = Order::find($inputs['order']['order_id']);
            }
            $client = $inputs['order']['client_id'];
            foreach ($inputs['product'] as $pid=>$prod){
                $totalReturn = ReturnDetail::join('returns',function($qry)use($client){
                    $qry->on('returns.id','=','return_id');
                    $qry->where('client_id',$client);
                    $qry->whereNull('deleted_at');
                })->where('product_id',$pid)->sum('qty');
                $settings = Setting::get()->pluck('value','key')->toArray();
                if(isset($settings['show_all_products_returns']) && $settings['show_all_products_returns']==1) {
                    $totalOrder = OrderDetail::join('orders', function ($qry) use ($client) {
                        $qry->on('orders.id', '=', 'order_id');
                        $qry->where('client_id', $client);
                    })->where('product_id', $pid)->sum(DB::raw('qty'));
                    //dd($totalReturn,$totalOrder,$prod['qty']);
                    $totalReturn += $prod['qty'];
                    if ($totalReturn > $totalOrder) {
                        throw new \Exception('المرتجعات أكبر من المبيعات لهذا الصنف  ' . $prod['product_name']);
                    }
                }
                if($order){
                    $details = OrderDetail::where('order_id',$order->id)
                        ->where('product_id',$pid)
                        ->first();
                    if($details->unit_id==$prod['unit_id']){
                        $details->return_qty += $prod['qty'];
                        $details->save();
                    }
                }
            }

            $return = ReturnProduct::create($inputs['order']);
            if($return->return_type=='sales'){
                $logNote = "فاتورة مرتجع مبيعات رقم ".$return->id." للعميل ".$return->client->name." بقيمة ".$return->return_value;
            }else{
                $logNote = "فاتورة مرتجع مشتريات رقم ".$return->id." من المورد ".$return->client->name." بقيمة ".$return->return_value;
            }
            /*activity()
                ->performedOn($return)
                ->log($logNote);*/
            if(isset($inputs['product'])){
                foreach ($inputs['product'] as $key=>$value){
                    //$inputs['product'][$key]['cost'] = currency($inputs['product'][$key]['cost'],"SAR",$return->currency, false);
                    if($inputs['product'][$key]['cost'] > $inputs['product'][$key]['price']){
                        $inputs['product'][$key]['cost'] = $inputs['product'][$key]['price'];
                    }
                    $inputs['product'][$key]['cost_egp'] = currency($value['cost'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
                    $inputs['product'][$key]['price_egp'] = currency($value['price'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
                }
            }
            $return->details()->attach($inputs['product']);

            event(new ReturnCreated($return));
            if($order){
                $this->setOrderProfit($order,$inputs['order']['return_value']);
            }
            DB::commit();
            if($return->return_type=='sales'){
                $route = route('ordersReturn.index');
            }else{
                $route = route('purchasesReturn.index');
            }
            $request->session()->flash('alert-success', 'تم إضافة المرتجع بنجاح');
            //return redirect(route('returns.getPrint',$return->id));
            return redirect($route);
		} catch (\Exception $e) {
			DB::rollback();
            $request->session()->flash('alert-danger', ' حدث خطأ اثناء اضافة المرتجع '.$e->getMessage());
			//dd($e->getMessage());
		}
        return back();
	}

--- METHOD=show ---
    public function show(ReturnProduct $return) {
        return view("returns.show", compact('return'));
    }

--- METHOD=edit ---
	public function edit(ReturnProduct $return) {
	    // TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721
	    \App\Services\Zatca\ZatcaDocumentLock::abortIfLocked(
	        $return
	    );

	    $type = $return->return_type;
	    //dd($return->details);
		return view('returns.edit', compact('return','type'));
	}

--- METHOD=update ---
	public function update(Request $request, ReturnProduct $return) {
	    // TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721
	    \App\Services\Zatca\ZatcaDocumentLock::abortIfLocked(
	        $return
	    );

		try {
            DB::beginTransaction();
            $inputs = $request->except('_token');
            $productStores = $this->rollback($return);
            $inputs['order']['is_cash'] = $request->has('is_cash');
            $inputs['order']['sales_value_egp'] = currency($inputs['order']['sales_value'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
            $order = null;
            if($inputs['order']['order_id']){
                $order = Order::find($inputs['order']['order_id']);
            }
            $inputs['order']['discount_type'] = isset($inputs['order']['discount_type'])?2:1;
            if(isset($inputs['product'])){
                foreach ($inputs['product'] as $key=>$value){
                    //$inputs['product'][$key]['cost'] = currency($inputs['product'][$key]['cost'],"SAR",$return->currency, false);
                    if($inputs['product'][$key]['cost'] > $inputs['product'][$key]['price']){
                        $inputs['product'][$key]['cost'] = $inputs['product'][$key]['price'];
                    }
                    $inputs['product'][$key]['cost_egp'] = currency($value['cost'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
                    $inputs['product'][$key]['price_egp'] = currency($value['price'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
                    if($order){
                        $details = OrderDetail::where('order_id',$order->id)
                            ->where('product_id',$key)
                            ->first();
                        if($details->unit_id==$value['unit_id']){
                            $details->return_qty += $value['qty'];
                            $details->save();
                        }
                    }

                }
            }
            //dd($inputs['product']);
            $return->update($inputs['order']);
            if($return->return_type=='sales'){
                $logNote = "تعديل فاتورة مرتجع مبيعات رقم ".$return->id." للعميل ".$return->client->name." بقيمة ".$return->return_value;
            }else{
                $logNote = "تعديل فاتورة مرتجع مشتريات رقم ".$return->id." من المورد ".$return->client->name." بقيمة ".$return->return_value;
            }
            activity()
                ->performedOn($return)
                ->log($logNote);
            $return->details()->sync($inputs['product']);
            event(new ReturnCreated($return,$productStores));
            if($order){
                $this->setOrderProfit($order,$inputs['order']['return_value']);
            }
            DB::commit();
            if($return->return_type=='sales'){
                $route = route('ordersReturn.index');
            }else{
                $route = route('purchasesReturn.index');
            }
            return redirect($route);
		} catch (\Exception $e) {
           // \Log::error($e->getMessage());
			DB::rollback();
			dd($e->getMessage());
		}
		return back();
	}

--- METHOD=rollback ---
	public function rollback($return){
        $return->client->transactions()
                ->where('record_id',$return->id)
                ->where('transaction_type',$return->return_type)
                ->delete();
        //TresuryTranaction::where('record_id',$return->id)->delete();
        $order = null;
        if($return->order_id){
            $order = Order::find($return->order_id);
        }

        $banktans = $return->transaction;//BankTransaction::where('record_id',$order->id)->first();

        if($banktans){
            if($banktans->type==1){
                $banktans->bank->balance += $banktans->getOriginal('value');
            }else{
                $banktans->bank->balance -= $banktans->getOriginal('value');
            }
            $banktans->bank->save();
            //$banktans->delete();
        }

        $details = $return->details;
        $productStores = array();
        foreach ($details as $item){
            if($item->is_service==1)continue;
            $productStore = ProductStore::where('product_id', $item->id)
                                        ->where('store_id', $item->pivot->store_id)
                                        ->first();
            $returnQty  = $item->pivot->qty;

            $prodstorUnit = $productStore->unit_id;
            $produtUnits =  ProductUnit::where('product_id', $item->id)->get();
            $returnUnit = $produtUnits->where('unit_id', $item->pivot->unit_id)->first();
            $storUnit  = $produtUnits->where('unit_id', $prodstorUnit)->first();
            /*if ($prodstorUnit != $item->pivot->unit_id) {
                if ($storUnit->pieces_num > $returnUnit->pieces_num) {
                    $returnQty = $returnQty/$storUnit->pieces_num;
                } else {
                    $returnQty = $returnQty*$returnUnit->pieces_num;
                }
            }*/
            if ($prodstorUnit != $item->pivot->unit_id) {
                if ($storUnit->pieces_num < $returnUnit->pieces_num) {
                    $a = $returnUnit->pieces_num/$storUnit->pieces_num;
                    $returnQty = $returnQty*$a;
                } else {
                    $a = $returnUnit->pieces_num/$storUnit->pieces_num;
                    if($a<1){
                        $returnQty = $returnQty*$a;
                    }else{
                        $returnQty = $returnQty/$a;
                    }
                }
            }
            if($order){
                $details = OrderDetail::where('order_id',$return->order_id)
                    ->where('product_id',$item->id)
                    ->first();
                if($details->unit_id==$item->pivot->unit_id){
                    $details->return_qty -= $returnQty;
                    $details->save();
                }
            }
            if($order){
                $this->setOrderProfit($order,$return->return_value);
            }
            if($return->return_type=='sales'){
                $productStore->sale_count += $returnQty;
            }else{
                $productCost = $item->last_cost;
                if(Setting::findByKey('productCost')=='avg') {
                    $oldCost = $storUnit->cost_price;
                    $oldQty = ($productStore->qty - $productStore->sale_count) ?: 1;
                    $newQty = $returnQty;
                    $newCost = $item->pivot->price;
                    $newAvg = (($oldCost * $oldQty) + ($newQty * $newCost)) / ($oldQty + $newQty);
                    $productCost = $newAvg;
                }
                $productCost = round($productCost,2);
                $storUnit->cost_price = $productCost;
                $storUnit->save();
                $item->last_cost = $productCost;
                $item->avg_cost = $productCost;
                $item->save();
                $productStore->qty += $returnQty;
            }
            $productStore->save();
            $productStores[$item->id.$item->pivot->store_id] = $productStore;
        }
        return $productStores;
    }

--- METHOD=destroy ---
    public function destroy($id)
    {
        // TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721
        $lockedReturn = ReturnProduct::findOrFail($id);
        
        \App\Services\Zatca\ZatcaDocumentLock::abortIfLocked(
            $lockedReturn
        );

        return "done";
        try{
            $return = ReturnProduct::find($id);
            $this->rollback($return);
            $trans = $return->transaction;
            if($trans){
                $trans->delete();
            }
            if($return->delete()){
                return "done";
            }
            return "failed";
        }catch(Exception $e){
            dd($e->getMessage());
        }
    }

--- METHOD=setOrderProfit ---
    public function setOrderProfit($order,$return_value){
        // $order->total = $order->fgrand_order_total;
        // $order->total_return += $return_value;
        // $order->discount_value = $order->dicount_value;
        // $total = $order->total - $order->discount_value;
        // $total = $total>0?$total:0;
        // if($total==0) {
        //     $order->discount = 0;
        //     $order->discount_value = 0;
        // }
        // if($order->paid>=$total){
        //     $order->paid = $total;
        // }
        // $order->due = $total - $order->paid;
        $order->profit = $order->order_profit;
        $order->save();
    }

=== MOBILE RETURN SERVICE ===

====================================================================================================
FILE=app/Services/Mobile/CreateSalesReturnService.php
====================================================================================================
FILE_FOUND=YES

--- METHOD=handle ---
    public function handle(array $payload)
    {
        $user = Auth::user();
        if (!$user) {
            throw new \Exception('غير مصرح');
        }

        $settings = Setting::query()->pluck('value', 'key')->toArray();
        $priceIncludesTax = $settings['PriceIncludesTax'] ?? 'no';
        $taxPercent = isset($payload['tax'])
            ? (float) $payload['tax']
            : (float) ($settings['taxValue'] ?? 15);
        $roundingUp = isset($settings['rounding_up']) && (string) $settings['rounding_up'] === '1';

        $clientId = (int) ($payload['client_id'] ?? 0);
        $client = Person::find($clientId);
        if (!$client) {
            throw new \Exception('العميل غير موجود');
        }

        $order = null;
        if (!empty($payload['order_id'])) {
            $order = Order::find($payload['order_id']);
            if (!$order) {
                throw new \Exception('الفاتورة الأصلية غير موجودة');
            }
        }

        $items = isset($payload['items']) && is_array($payload['items']) ? $payload['items'] : [];
        if (count($items) === 0) {
            throw new \Exception('يجب إضافة أصناف للمرتجع');
        }

        $attach = [];
        $itemsSubtotal = 0.0;

        /*
         * MOBILE_SERVICE_RETURN_NO_STOCK
         *
         * return_qty updates are collected here and executed only inside
         * the database transaction after all rows pass validation.
         */
        $orderDetailAdjustments = [];

        foreach ($items as $row) {
            $productId = (int) ($row['product_id'] ?? 0);
            $product = Product::with(['productUnit', 'productStore'])->find($productId);
            if (!$product) {
                throw new \Exception('صنف غير موجود');
            }

            $qty = (float) ($row['qty'] ?? 0);
            if ($qty <= 0) {
                throw new \Exception('كمية مرتجع غير صحيحة لـ ' . $product->name);
            }

            // Cap returns vs sold qty when setting requires it (same as web)
            if (isset($settings['show_all_products_returns']) && (string) $settings['show_all_products_returns'] === '1') {
                $totalReturn = ReturnDetail::join('returns', function ($qry) use ($clientId) {
                    $qry->on('returns.id', '=', 'return_id');
                    $qry->where('client_id', $clientId);
                    $qry->whereNull('deleted_at');
                })->where('product_id', $productId)->sum('qty');

                $totalOrder = OrderDetail::join('orders', function ($qry) use ($clientId) {
                    $qry->on('orders.id', '=', 'order_id');
                    $qry->where('client_id', $clientId);
                })->where('product_id', $productId)->sum(DB::raw('qty'));

                if (($totalReturn + $qty) > $totalOrder) {
                    throw new \Exception('المرتجعات أكبر من المبيعات لهذا الصنف ' . $product->name);
                }
            }

            $isService = !empty($product->is_service);

            if ($isService) {
                /*
                 * A service has no product_unit or product_store balance.
                 * IDs 1 are reference values only and never cause stock
                 * movement because ReturnCreated skips service products.
                 */
                $unit = \App\Unit::find(1);
                $store = \App\Store::find(1);

                if (!$unit) {
                    throw new \Exception(
                        'الوحدة الافتراضية رقم 1 غير موجودة'
                    );
                }

                if (!$store) {
                    throw new \Exception(
                        'المخزن الافتراضي رقم 1 غير موجود'
                    );
                }

                $unitId = 1;
                $unitName = 'خدمة';
                $storeId = 1;
                $storeName = $store->name;

                $price = array_key_exists('price', $row)
                    ? (float) $row['price']
                    : (float) ($product->last_cost ?? 0);

                // Services never carry inventory cost.
                $cost = 0.0;
            } else {
                $unitId = isset($row['unit_id'])
                    ? (int) $row['unit_id']
                    : null;

                $unit = $unitId
                    ? $product->productUnit
                        ->firstWhere('id', $unitId)
                    : $product->productUnit->first();

                if (!$unit) {
                    throw new \Exception(
                        'لا توجد وحدة للصنف ' . $product->name
                    );
                }

                $storeId = isset($row['store_id'])
                    ? (int) $row['store_id']
                    : (int) optional(
                        $product->productStore->first()
                    )->store_id;

                if (!$storeId) {
                    throw new \Exception(
                        'لا يوجد مخزن للصنف ' . $product->name
                    );
                }

                $unitId = (int) $unit->id;
                $unitName = $unit->name;
                $storeName = $row['store_name']
                    ?? optional(
                        \App\Store::find($storeId)
                    )->name;

                $price = array_key_exists('price', $row)
                    ? (float) $row['price']
                    : (float) (
                        $unit->pivot->sale_price ?? 0
                    );

                $cost = array_key_exists('cost', $row)
                    ? (float) $row['cost']
                    : (float) (
                        $unit->pivot->cost_price ?? 0
                    );

                if ($cost > $price) {
                    $cost = $price;
                }
            }

            $lineTotal = round($qty * $price, 2);
            $itemsSubtotal += $lineTotal;

            if ($order) {
                $details = OrderDetail::where(
                    'order_id',
                    $order->id
                )
                    ->where(
                        'product_id',
                        $productId
                    )
                    ->first();

                if (
                    $details
                    && (int) $details->unit_id ===
                        (int) $unitId
                ) {
                    if (
                        !isset(
                            $orderDetailAdjustments[
                                $details->id
                            ]
                        )
                    ) {
                        $orderDetailAdjustments[
                            $details->id
                        ] = 0.0;
                    }

                    $orderDetailAdjustments[
                        $details->id
                    ] += $qty;
                }
            }

            $attach[$productId] = [
                'store_id' => $storeId,
                'unit_id' => $unitId,
                'store_name' => $storeName,
                'unit_name' => $unitName,
                'product_name' => $product->name,
                'qty' => $qty,
                'cost' => $cost,
                'price' => $price,
                'cost_egp' => $cost,
                'price_egp' => $price,
            ];
        }

        $discount = (float) ($payload['discount'] ?? 0);
        $discountType = (int) ($payload['discount_type'] ?? 1);
        if ($discountType !== 2) {
            $discountType = 1;
        }

        $totals = $this->calculator->calculate(
            $itemsSubtotal,
            $discount,
            $discountType,
            $taxPercent,
            $priceIncludesTax,
            $roundingUp
        );

        DB::beginTransaction();

        try {
            foreach (
                $orderDetailAdjustments
                as $detailId => $adjustmentQty
            ) {
                $detail = OrderDetail::find($detailId);

                if (!$detail) {
                    throw new \Exception(
                        'تعذر العثور على سطر الفاتورة الأصلية'
                    );
                }

                $detail->return_qty =
                    (float) $detail->return_qty
                    + (float) $adjustmentQty;

                $detail->save();
            }

            $returnData = [
                'client_id' => $client->id,
                'return_type' => 'sales',
                'creator_id' => $user->id,
                'order_id' => $order ? $order->id : null,
                'return_date' => $payload['return_date'] ?? date('Y-m-d'),
                'currency' => 'SAR',
                'tax' => $taxPercent,
                'tax_value' => $totals['tax_value_stored'],
                'discount' => $discount,
                'discount_type' => $discountType,
                'sales_value' => $totals['items_subtotal'],
                'sales_value_egp' => $totals['items_subtotal'],
                'return_value' => $totals['total'],
                'total' => $totals['total'],
                /*
                 * The financial treatment of a linked sales return must
                 * follow the original invoice, not a client-supplied flag.
                 *
                 * cash / visa / bank transfer => refund from original bank
                 * delayed                     => reduce client receivable
                 */
                'is_cash' => $order && in_array(
                    strtolower(trim((string) $order->payment_type)),
                    ['cash', 'visa', 'link transfer'],
                    true
                ) ? 1 : 0,
            ];

            $return = ReturnProduct::create($returnData);
            $return->details()->attach($attach);

            event(new ReturnCreated($return));

            if ($order) {
                $order->total_return = (float) $order->total_return + (float) $totals['total'];
                $order->save();
            }

            DB::commit();

            return $return->fresh(['details', 'client', 'order']);
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

=== RETURN API CONTROLLER ===

====================================================================================================
FILE=app/Http/Controllers/Api/V1/ReturnApiController.php
====================================================================================================
FILE_FOUND=YES

--- METHOD=store ---
    public function store(Request $request, CreateSalesReturnService $service)
    {
        $this->validate($request, [
            'client_id' => 'required|integer',
            'items' => 'required|array|min:1',
            'items.*.product_id' => 'required',
            'items.*.qty' => 'required|numeric|min:0.001',
        ]);

        try {
            $return = $service->handle($request->all());
            return response()->json([
                'success' => true,
                'message' => 'تم إنشاء المرتجع بنجاح',
                'data' => $this->transform($return, true),
            ], 201);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 422);
        }
    }

--- METHOD=show ---
    public function show($id)
    {
        $return = ReturnProduct::with(['details', 'client', 'order'])->findOrFail($id);
        return response()->json([
            'success' => true,
            'data' => $this->transform($return, true),
        ]);
    }

--- METHOD=transform ---
    protected function transform(ReturnProduct $return, $withItems = false)
    {
        $data = [
            'id' => $return->id,
            'client_id' => $return->client_id,
            'client_name' => optional($return->client)->name,
            'order_id' => $return->order_id,
            'return_date' => $return->return_date,
            'return_value' => (float) $return->return_value,
            'total' => (float) $return->total,
            'tax' => (float) ($return->getAttributes()['tax'] ?? 0),
            'tax_value' => (float) $return->tax_value,
            'is_cash' => (bool) $return->is_cash,
            'zatca_submitted_at' => optional($return->zatca_submitted_at)->toDateTimeString(),
            'zatca_reporting_status' => $return->zatca_reporting_status,
            'created_at' => optional($return->created_at)->toDateTimeString(),
        ];

        if ($withItems) {
            $data['items'] = $return->details->map(function ($product) {
                return [
                    'product_id' => $product->id,
                    'product_name' => $product->pivot->product_name ?? $product->name,
                    'qty' => (float) ($product->pivot->qty ?? 0),
                    'price' => (float) ($product->pivot->price ?? 0),
                    'cost' => (float) ($product->pivot->cost ?? 0),
                    'unit_id' => $product->pivot->unit_id ?? null,
                    'unit_name' => $product->pivot->unit_name ?? null,
                    'store_id' => $product->pivot->store_id ?? null,
                ];
            })->values();
        }

        return $data;
    }

=== RETURN ACCOUNTING LISTENER ===

====================================================================================================
FILE=app/Listeners/UpdateProductQuantityReturn.php
====================================================================================================
FILE_FOUND=YES

--- METHOD=handle ---
    public function handle($event)
    {
        try {

            $order = $event->order;
            $productStores = $event->productStores;
            $details = $order->details()->get();
            foreach ($details as $item){
                if($item->is_service==1)continue;
                $productStore = isset($productStores[$item->id.$item->pivot->store_id])
                    ?$productStores[$item->id.$item->pivot->store_id]
                    :ProductStore::where('product_id', $item->id)
                        ->where('store_id', $item->pivot->store_id)
                        ->first();
                $orderQty  = $item->pivot->qty;
                $prodstorUnit = $productStore->unit_id;
                $produtUnits =  ProductUnit::where('product_id', $item->id)->get();
                $orderUnit = $produtUnits->where('unit_id', $item->pivot->unit_id)->first();
                $storUnit  = $produtUnits->where('unit_id', $prodstorUnit)->first();

                if ($prodstorUnit != $item->pivot->unit_id) {
                    if ($storUnit->pieces_num < $orderUnit->pieces_num) {
                        $a = $orderUnit->pieces_num/$storUnit->pieces_num;
                        $orderQty = $orderQty*$a;
                    } else {
                        $a = $orderUnit->pieces_num/$storUnit->pieces_num;
                        if($a<1){
                            $orderQty = $orderQty*$a;
                        }else{
                            $orderQty = $orderQty/$a;
                        }
                    }
                }
                if($order->return_type=='sales'){
                    $productStore->sale_count -= $orderQty;
                }else{
                    $oldCost = $storUnit->cost_price;
                    $oldQty = ($productStore->qty-$productStore->sale_count)?:1;
                    $newQty = $orderQty;
                    $newCost = $item->pivot->price;
                    //$totalNew = ($newQty*$newCost)/$oldQty;
                    //$newAvg = $oldCost-$totalNew;
                    $totalqty = $oldQty-$newQty;
                    if($totalqty) {
                        $productCost = $newCost;
                        if(Setting::findByKey('productCost')=='avg') {
                            $newAvg = (($oldCost * $oldQty) - ($newQty * $newCost)) / ($oldQty - $newQty);
                            $productCost = $newAvg;
                        }
                        $productCost = round($productCost, 2);
                        $item->last_cost = $storUnit->cost_price;
                        $storUnit->cost_price = $productCost;
                        $storUnit->save();
                        $item->avg_cost = round($productCost, 2);
                        $item->save();
                    }
                    $productStore->qty -= $orderQty;
                }

                $productStore->save();

            }
            /*
             * Sales returns must follow the financial treatment of the
             * original invoice. Never trust request('bank_id') or a mobile
             * is_cash value when an original invoice is linked.
             *
             * cash          => original invoice treasury
             * visa          => original invoice bank
             * link transfer => original invoice bank (تحويل بنكي)
             * delayed       => reduce client receivable
             */
            if ($order->return_type == 'sales') {
                $originalOrder = $order->order;

                $paymentType = $originalOrder
                    ? strtolower(trim((string) $originalOrder->payment_type))
                    : null;

                $isCreditReturn =
                    ($originalOrder && $paymentType == 'delayed')
                    || (!$originalOrder && !$order->is_cash);

                if ($isCreditReturn) {
                    $order->client
                        ->transactions()
                        ->create([
                            'value' => -$order->return_value,
                            'note' => ' خصم قيمة مرتجعات من الحساب ',
                            'transaction_type' => $order->return_type,
                            'record_id' => $order->id
                        ]);
                } else {
                    if ($originalOrder) {
                        $bankPaymentTypes = [
                            'cash',
                            'visa',
                            'link transfer',
                        ];

                        if (!in_array(
                            $paymentType,
                            $bankPaymentTypes,
                            true
                        )) {
                            throw new \Exception(
                                'طريقة دفع الفاتورة الأصلية غير مدعومة للمرتجع: '
                                . $originalOrder->payment_type
                            );
                        }

                        $bankId = (int) $originalOrder->bank_id;
                    } else {
                        /*
                         * Backward-compatible fallback for old unlinked
                         * returns created from the web interface.
                         */
                        $bankId = (int) request('bank_id');
                    }

                    if (!$bankId) {
                        throw new \Exception(
                            'تعذر تحديد حساب رد قيمة المرتجع'
                        );
                    }

                    $bank = Bank::find($bankId);

                    if (!$bank) {
                        throw new \Exception(
                            'الحساب المالي المرتبط بالفاتورة الأصلية غير موجود'
                        );
                    }

                    $grand = currency(
                        $order->return_value,
                        currency()->getUserCurrency(),
                        $bank->currency,
                        false
                    );

                    $grand = round((float) $grand, 2);

                    $trans = [
                        'bank_id' => $bank->id,
                        'op_date' => date('Y-m-d'),
                        'total' => $bank->balance,
                        'due' => (float) $bank->balance - $grand,
                        'type' => '1',
                        'note' => 'مرتجع مبيعات  | ' . $order->client->name,
                        'value' => $grand,
                    ];

                    $bank->balance =
                        (float) $bank->balance - $grand;

                    $bank->save();

                    if ($order->transaction) {
                        $order->transaction()->update($trans);
                    } else {
                        $order->transaction()->create($trans);
                    }
                }
            } elseif ($order->is_cash) {
                /*
                 * Purchase return behavior is preserved unchanged.
                 */
                $bankId = request('bank_id');

                if ($bankId) {
                    $banktans = $order->transaction()->first();

                    if ($banktans) {
                        $bank = $banktans->bank;
                    } else {
                        $bank = Bank::find($bankId);
                    }

                    $trans["bank_id"] = $bankId;
                    $bank = Bank::find($bankId);
                    $trans["op_date"] = date('Y-m-d');
                    $trans["total"] = $bank->balance;

                    $grand = currency(
                        $order->return_value,
                        currency()->getUserCurrency(),
                        $bank->currency,
                        false
                    );

                    $note = 'مرتجع مشتريات  | ' . $order->client->name;
                    $trans["due"] = $bank->balance + $grand;
                    $bank->balance += $grand;
                    $trans["type"] = "2";
                    $trans["note"] = $note;
                    $trans["value"] = $grand;
                    $bank->save();

                    if ($order->transaction) {
                        $order->transaction()->update($trans);
                    } else {
                        $order->transaction()->create($trans);
                    }
                }
            } else {
                $order->client
                    ->transactions()
                    ->create([
                        'value' => -$order->return_value,
                        'note' => ' خصم قيمة مرتجعات من الحساب ',
                        'transaction_type' => $order->return_type,
                        'record_id' => $order->id
                    ]);
            }
        } catch (\Exception $exception) {
            \Log::error($exception->getMessage());

            throw $exception;
        }

    }

=== RETURN MODEL ===
<?php

namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Kyslik\ColumnSortable\Sortable;

class ReturnProduct extends Model
{
    use SoftDeletes;
    protected $table = 'returns';
    protected $fillable = [
        'client_id','return_type','return_value','is_cash','return_date','currency','sales_value','sales_value_egp',
        'sale_id','discount','discount_type','total','manager_id','order_id','creator_id','tax','tax_value',
        'zatca_invoice_uuid',
        'zatca_qr_payload',
        'zatca_signed_xml',
        'zatca_reporting_status',
        'zatca_validation_status',
        'zatca_invoice_hash',
        'zatca_raw_response',
        'zatca_submitted_at',
    ];

    protected $casts = [
        'zatca_raw_response' => 'array',
        'zatca_submitted_at' => 'datetime',
    ];

    public function gettaxValueAttribute(){
        $tax =  $this->tax/100;
        $total = $this->total;
        $taxplusone = 1+ $tax;
        $orignalValue = $total / $taxplusone;
        $taxvalue =$orignalValue * $tax;
        return $taxvalue;
    }
    public function gettaxValueCaluclatedAttribute(){
        $tax =  $this->tax/100;
        $total = $this->total;
        $taxplusone = 1+ $tax;
        $orignalValue = $total / $taxplusone;
        $taxvalue =$orignalValue * $tax;
        return $taxvalue;
    }
    public function transaction(){
        return $this->morphOne(BankTransaction::class,'transactionable');
    }
    public function details(){
        return $this->belongsToMany(Product::class,'return_detailes','return_id','product_id')
            ->withPivot(['store_name','unit_name','product_name','store_id','unit_id', 'qty','cost','price','created_at'])
            ->withTimestamps()->withTrashed();

    }
    public function creator(){
        return $this->belongsTo(User::class,'creator_id','id');
    }
    public function client(){
        return $this->belongsTo(Person::class,'client_id','id');
    }
    public function order(){
        return $this->belongsTo(Order::class,'order_id','id')->withTrashed();
    }
    public function saleMan(){
        return $this->belongsTo(Employee::class,'sale_id','id');
    }

    /*
     * FORCE_NEW_RETURN_CURRENCY_TO_SAR
     * This Saudi/ZATCA installation creates records in SAR only.
     */
    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            $model->currency = 'SAR';
        });
    }

}


=== RETURN CREATE VIEW ===
@extends('layouts.app')

@section('content')
	<!-- Content Header (Page header) -->
	<section class="content-header">
		<h1>
			@lang('front.Add')
			<small>
				@if($type=='sales')
					@lang('front.ordreturn')
				@else
					@lang('front.purreturn')
				@endif
			</small>
		</h1>
	</section>
	<!-- Main content -->
	<form action="{{route('returns.store')}}" method="post">
		{{ csrf_field() }}
		@include('returns._form')
	</form>
@stop


=== SALES INVOICE CREATION ===

====================================================================================================
FILE=app/Http/Controllers/OrdersController.php
====================================================================================================
FILE_FOUND=YES

--- METHOD=store ---
    public function store(Request $request)
    {

        $inputs = $request->except('_token');
        $appointmentId = $request->input('appointment_id');
        $appointment = null;

        try {

            DB::beginTransaction();

            if ($appointmentId) {
                $appointment = Appointment::with(['services'])->lockForUpdate()->find($appointmentId);
                if (!$appointment) {
                    throw new \Exception('الحجز غير موجود');
                }
                if ($appointment->invoice_order_id) {
                    throw new \Exception('تم إنشاء فاتورة لهذا الحجز بالفعل');
                }
            }

            if (Setting::findByKey('enable_empty_invoice') == 0 && !isset($inputs['product'])) {
                throw new \Exception('لا يمكنك إضافة الفاتورة بدون منتجات');
            }
            if (isset($inputs['productNew'])) {
                foreach ($inputs['productNew'] as $k => $product) {
                    if ($product['isnew'] == 'true') {
                        $this->addNewProduct($inputs, $k);
                    }
                }
                
                if ($request->has('ispos') && Setting::findByKey('pos_employee_required', 0) == 1 && isset($inputs['product'])) {
    foreach ($inputs['product'] as $posItem) {
        if (empty($posItem['employee_id'])) {
            throw new \Exception('يجب اختيار موظف قبل حفظ فاتورة نقطة البيع');
        }
    }
}

            }

            $inputs['order']['shipment_amount'] = isset($inputs['order']['shipment_amount']) ? $inputs['order']['shipment_amount'] : 0;
            $inputs['order']['creator_id'] = auth()->user()->id;
            $inputs['order']['invoice_date'] = $inputs['order']['invoice_date'] ?? date('Y-m-d');
            $inputs['order']['discount_type'] = isset($inputs['order']['discount_type']) ? 2 : 1;

            $invoiceTypeForShift = isset($inputs['order']['invoice_type'])
                ? $inputs['order']['invoice_type']
                : ($request->has('ispos') ? 'sales' : 'sales');

            if ($invoiceTypeForShift == 'sales') {
                $openShift = Shift::where('user_id', auth()->id())
                    ->where('status', 'open')
                    ->latest('id')
                    ->first();

                if (!$openShift) {
                    throw new \Exception('يجب فتح وردية أولاً قبل إنشاء فاتورة مبيعات');
                }

                $inputs['order']['shift_id'] = $openShift->id;
            }

            //return back()->withInput($inputs)->with('alert-danger', ' حدث خطأ اثناء اضافة الفاتورة ');
            /*
             * PAYMENT_BANK_ROUTING_SAR
             * cash/delayed -> user treasury
             * visa/link transfer -> SAR bank account
             */
            $paymentTypeForBank =
                $inputs['order']['payment_type'] ?? 'cash';

            $bank = Bank::resolveForPayment(
                $paymentTypeForBank,
                auth()->user()->treasury_id
            );

            $inputs['order']['bank_id'] = $bank->id;

            if (!isset($inputs['order']['invoice_number'])) {
                $inputs['order']['invoice_type'] = $inputs['order']['invoice_type'] ?? 'sales';

                /*
                 * NATURAL_ORDER_SEQUENCE_NUMBER
                 * Keep invoice number aligned with the next orders.id.
                 */
                $inputs['order']['invoice_number'] =
                    Order::nextNaturalInvoiceNumber();
              
            } else {
                if ($inputs['order']['invoice_type'] == 'sales') {
                    $checkNumber = Order::where('invoice_type', 'sales')->where('invoice_number', $inputs['order']['invoice_number'])->first();
                    if ($checkNumber) {
                        return back()->withInput($inputs)->with('alert-danger', 'رقم الفاتورة ' . $inputs['order']['invoice_number'] . ' مكرر حاول اضافة الفاتورة مره اخرى  ');
                    }
                }
            }

            $inputs['order']['paid_egp'] = currency($inputs['order']['paid'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
            $inputs['order']['is_withdrawable'] = $request->has('is_withdrawable');
            $client = Person::find($inputs['order']['client_id']);
            $pointval = Setting::findByKey('point_value');
            $inputs['order']['use_point'] = isset($inputs['order']['use_point']) ? 1 : 0;
            if ($inputs['order']['use_point'] && $client->total_points) {
                $totalValue = $pointval * $client->total_points;
                $balance = $client->total_points;
                $discount = $totalValue;
                if ($totalValue > $inputs['order']['total']) {
                    $balance = $inputs['order']['total'];
                    $discount = $inputs['order']['total'];
                }
                $inputs['order']['discount_type'] = 1;
                $inputs['order']['discount'] = $discount;
            }

            if (($inputs['order']['invoice_type'] ?? null) === 'sales') {
                $inputs['order']['currency'] = 'SAR';
            }

            $order = Order::create($inputs['order']);

            if ($order->invoice_type == 'sales') {
                $logNote = "فاتورة مبيعات رقم " . $order->invoice_number . " للعميل " . $order->client->name . " بقيمة " . $order->total;
            } else {
                $logNote = "فاتورة مشتريات رقم " . $order->invoice_number . " من المورد " . $order->client->name . " بقيمة " . $order->total;
            }
            //activity()->performedOn($order)->log($logNote);
            if ($inputs['order']['use_point'] && $client->total_points) {
                UserPoint::create([
                    'user_id' => $order->client_id,
                    'balance' => -$balance,
                    'order_id' => $order->id
                ]);
            }
           if ($pointval && !$inputs['order']['use_point']) {
    $earnRate = floatval(Setting::findByKey('point_earn_rate', 0.10));
    $earnedPoints = floor(($order->total - $order->discount_value) * $earnRate);
    if ($earnedPoints > 0) {
        UserPoint::create([
            'user_id' => $order->client_id,
            'balance' => $earnedPoints,
            'order_id' => $order->id
        ]);
    }
}
            if (isset($inputs['duepayment'])) {
                foreach ($inputs['duepayment']['date'] as $i => $date) {
                    CalanderPayment::create([
                        'order_id' => $order->id,
                        'date' => $date,
                        'value' => $inputs['duepayment']['value'][$i]
                    ]);
                }
            }
            if (isset($inputs['product'])) {
                $rawproductids = [];
                $rawCostPrice = [];
                foreach ($inputs['product'] as $key => $value) {
                    // if(!isset($inputs['product'][$key]['store_id'])){
                    //     $poductRow = Product::with(['productStore','productUnit'])
                    //                 ->where('id',$value['product_id'])
                    //                 ->first();
                    //     $inputs['product'][$key]['store_id'] = $poductRow->productStore->first()->id;
                    //     $inputs['product'][$key]['unit_id'] = $poductRow->productUnit->first()->id;
                    // }
                    $inputs['product'][$key]['total'] = $inputs['product'][$key]['qty'] * $value['price'];
                    $inputs['product'][$key]['cost_egp'] = currency($value['cost'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
                    $inputs['product'][$key]['price_egp'] = currency($value['price'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
                    $rawproductids[] = $value['product_id'];
                    $rawCostPrice[$value['product_id']] = $value['price'];
                }
                if (!in_array($order->invoice_type, ['sales', 'bookings'])) {
                    $raws = DB::table('product_raw_materials')
                        ->whereIn('raw_material_id', $rawproductids)
                        ->pluck('product_id')
                        ->toArray();
                    $rpoduct = Product::with(['rawMatrial', 'productUnit'])
                        ->whereIn('id', $raws)
                        //->where('id',26)
                        ->get();

                    foreach ($rpoduct as $p) {
                        $finalcost = 0;
                        foreach ($p->rawMatrial as $r) {
                            $cost = $rawCostPrice[$r->id] ?? $r->last_cost;
                            $finalcost += ($r->pivot->qty * $cost);
                        }
                        foreach ($p->productUnit as $unit) {
                            $unit->pivot->cost_price = $finalcost * $unit->pivot->pieces_num;
                            $unit->pivot->save();
                        }
                    }
                }
                foreach ($inputs['product'] as $pitem) {
                    //dd($pitem);
                    $pitem['order_id'] = $order->id;
                    OrderDetail::create($pitem);
                }
                //dd("done");
                //$order->details()->attach($inputs['product']);

            } else {
                if (Setting::findByKey('enable_empty_invoice') == 0) {
                    throw new \Exception('لا يمكنك إضافة الفاتورة بدون منتجات');
                }
            }
            event(new OrderCreated($order));
            $clientTrans = $order->client->transactions()
                ->where('record_id', $order->id)
                ->where('transaction_type', $order->invoice_type)
                ->first();
            if ($clientTrans) {
                if ($order->due) {
                    $clientTrans->update([
                        'value' => $order->due,
                        'note' => ' فاتورة رقم ' . $order->invoice_number,
                        'transaction_type' => $order->invoice_type,
                        'record_id' => $order->id
                    ]);
                } else {
                    $clientTrans->delete();
                }
            } elseif ($order->due) {
                $order->client
                    ->transactions()
                    ->create([
                        'value' => $order->due,
                        'note' => ' فاتورة رقم ' . $order->invoice_number,
                        'transaction_type' => $order->invoice_type,
                        'record_id' => $order->id
                    ]);
            }
            //if($order->payment_type=='cash'){
            $trans["bank_id"] = $bank->id;
            if ($order->invoice_type == 'sales') {
                $trans["note"] = " فاتورة مبيعات رقم  " . $order->invoice_number;
            } elseif ($order->invoice_type == 'bookings') {
                $trans["note"] = " فاتورة رقم  " . $order->invoice_number;
            } else {
                $trans["note"] = " فاتورة مشتربات رقم  " . $order->invoice_number;
            }
            $trans["record_id"] = $order->id;
            $trans["op_date"] = date('Y-m-d');
            $trans["total"] = $bank->balance;
            $grand = $order->paid;


            if ($order->invoice_type == 'sales' && $order->paid > 0) {
                $commision = $order->paid * ($bank->percent / 100);
                $grand = $order->paid - $commision;
                $grand = currency($grand, currency()->getUserCurrency(), $bank->currency, $format = false);
                //$commision = currency($commision,$bank->currency,"SAR", $format = false);
                /*$expense['note'] = ' خصم عمولة الفاتورة رقم  '.$order->invoice_number;
                $expense['value'] = $commision;
                Expense::create($expense);*/
                $order->is_visa = $bank->type == 1 ? true : false;
                $order->commision = $commision;
                $order->commision_egp = currency($commision, currency()->getUserCurrency(), currency()->config('default'), $format = false);
                $order->save();
                $trans["due"] = $bank->balance + $grand;
                $bank->balance += $grand;
                $trans["type"] = "2";
            } else {
                $grand = currency($grand, currency()->getUserCurrency(), $bank->currency, $format = false);
                $trans["due"] = $bank->balance - $grand;
                $bank->balance -= $grand;
                $trans["type"] = "1";
            }
            if ($grand > 0) {
                $trans["value"] = $grand;
                $bank->save();
                $order->transaction()->create($trans);
            }
            //BankTransaction::create($trans);
            //}

            DB::commit();
            // WhatsApp Invoice PDF (Auto بحسب الإعدادات)
            try {
                if (
                    $order->invoice_type == 'sales' &&
                    Setting::findByKey('whatsapp_enabled', '0') == '1' &&
                    Setting::findByKey('whatsapp_auto_invoice', '0') == '1'
                ) {
                    $order->load('client', 'items', 'saleMan', 'market');
            
                    $to = optional($order->client)->mobile;
            
                    if (!empty($to)) {
            
                        // نص مرافق للـ PDF (اختياري)
                        $tpl = DB::table('whatsapp_templates')
                            ->where('context', 'invoice')
                            ->where('is_active', 1)
                            ->orderBy('id', 'desc')
                            ->first();
            
                        $text = $tpl ? trim((string)$tpl->body) : null;
            
                        if (!empty($text)) {
                            $text = str_replace(
                                ['{name}','{invoice_number}','{total}','{paid}','{due}','{date}'],
                                [
                                    optional($order->client)->name,
                                    $order->invoice_number,
                                    $order->total,
                                    $order->paid,
                                    $order->due,
                                    $order->order_date ?: ($order->invoice_date ?: optional($order->created_at)->format('Y-m-d'))
                                ],
                                $text
                            );
                        }
            
                        // إعدادات القالب (شعار/بيانات/ملاحظات)
                        $settings = Setting::pluck('value','key')->toArray();
            
                        // نوع الورقة: A4 أو POS80
                        $paper = strtoupper((string) Setting::findByKey('whatsapp_invoice_pdf_paper', 'A4'));
                        $isPos = in_array($paper, ['POS','POS80','RECEIPT','80'], true);
            
                        // مسار حفظ PDF
                        $safeNo = preg_replace('/[^0-9A-Za-z_-]/', '_', (string)$order->invoice_number);
                        $relativePath = "whatsapp/invoices/invoice_{$safeNo}_{$order->id}.pdf";
                        $pdfAbsPath = storage_path('app/public/' . $relativePath);
                        @mkdir(dirname($pdfAbsPath), 0755, true);
            
                        // HTML (قالب الواتساب الجديد)
                        $html = view('orders.whatsapp_invoice_pdf', [
                            'order' => $order,
                            'settings' => $settings,
                            'paper' => $isPos ? 'POS80' : 'A4',
                        ])->render();
            
                        // توليد PDF عبر mPDF (يعالج العربية RTL بشكل صحيح)
                        $tmpDir = storage_path('app/tmp/mpdf');
                        @mkdir($tmpDir, 0755, true);
            
                        $mpdfConfig = [
                            'mode' => 'utf-8',
                            'tempDir' => $tmpDir,
                            'default_font' => 'dejavusans',
                            'autoScriptToLang' => true,
                            'autoLangToFont' => true,
                        ];
            
                        if ($isPos) {
                            // تقدير ارتفاع POS حسب عدد العناصر
                            $rows = 0;
                            try { $rows = is_countable($order->items) ? count($order->items) : 0; } catch (\Exception $e) { $rows = 0; }
            
                            $baseMm  = 140;
                            $rowMm   = 7;
                            $extraMm = 80;
                            $heightMm = $baseMm + ($rows * $rowMm) + $extraMm;
                            if ($heightMm < 250) $heightMm = 250;
                            if ($heightMm > 2000) $heightMm = 2000;
            
                            $mpdfConfig['format'] = [80, $heightMm];
                            $mpdfConfig['margin_left'] = 3;
                            $mpdfConfig['margin_right'] = 3;
                            $mpdfConfig['margin_top'] = 3;
                            $mpdfConfig['margin_bottom'] = 3;
                        } else {
                            $mpdfConfig['format'] = 'A4';
                            $mpdfConfig['margin_left'] = 10;
                            $mpdfConfig['margin_right'] = 10;
                            $mpdfConfig['margin_top'] = 10;
                            $mpdfConfig['margin_bottom'] = 10;
                        }
            
                        $mpdf = new \Mpdf\Mpdf($mpdfConfig);
                        $mpdf->simpleTables = true;
                        $mpdf->packTableData = true;
                        $mpdf->useSubstitutions = true;
                        $mpdf->SetDirectionality('rtl');
                        // رفع حدود PCRE (إذا كانت مسموحة) لتفادي خطأ backtrack_limit
                        @ini_set('pcre.backtrack_limit', '10000000');
                        @ini_set('pcre.recursion_limit', '10000000');

                        // mPDF قد يفشل إذا كان HTML كبير جداً، لذلك نمرره على دفعات
                        $maxChunk = 200000;
                        $htmlSafe = preg_replace('/>\s*</', ">\n<", $html); // إضافة أسطر لتسهيل التقسيم
                        $buf = '';
                        foreach (explode("\n", $htmlSafe) as $line) {
                            if (strlen($buf) + strlen($line) + 1 > $maxChunk) {
                                $mpdf->WriteHTML($buf);
                                $buf = '';
                            }
                            $buf .= $line . "\n";
                        }
                        if (trim($buf) !== '') {
                            $mpdf->WriteHTML($buf);
                        }
            
                        $mpdf->Output($pdfAbsPath, \Mpdf\Output\Destination::FILE);
            
                        // رابط عام
                        $publicUrl = url(\Storage::url($relativePath));
                        $fileName  = "Invoice-{$order->invoice_number}.pdf";
            
                        // إرسال PDF
                        $api = new \App\Services\WasenderApi();
                        $res = $api->sendDocument($to, $publicUrl, $fileName, $text);
            
                        $success = (isset($res['body']['success']) && $res['body']['success'] === true);
                        $msgId   = $res['body']['data']['msgId'] ?? null;
            
                        DB::table('whatsapp_logs')->insert([
                            'context'       => 'invoice',
                            'model_type'    => 'App\\Order',
                            'model_id'      => $order->id,
                            'to'            => $to,
                            'message_type'  => 'document',
                            'text'          => $text,
                            'document_url'  => $publicUrl,
                            'file_name'     => $fileName,
                            'api_msg_id'    => $msgId,
                            'status_code'   => $success ? 2 : 0,
                            'status_label'  => $success ? 'SENT' : 'FAILED',
                            'payload'       => json_encode($res['payload'], JSON_UNESCAPED_UNICODE),
                            'response'      => json_encode($res['body'], JSON_UNESCAPED_UNICODE),
                            'error'         => $success ? null : ('HTTP ' . $res['http_code']),
                            'created_by'    => auth()->id(),
                            'created_at'    => now(),
                            'updated_at'    => now(),
                        ]);
                    }
                }
            } catch (\Exception $e) {
                DB::table('whatsapp_logs')->insert([
                    'context'       => 'invoice',
                    'model_type'    => 'App\\Order',
                    'model_id'      => $order->id ?? null,
                    'to'            => optional($order->client)->mobile ?? '',
                    'message_type'  => 'document',
                    'status_code'   => 0,
                    'status_label'  => 'FAILED',
                    'error'         => $e->getMessage(),
                    'created_by'    => auth()->id(),
                    'created_at'    => now(),
                    'updated_at'    => now(),
                ]);
            }
            if ($appointment) {
                $appointment->update([
                    'invoice_order_id' => $order->id,
                    'status' => Appointment::STATUS_INVOICED,
                ]);
            }

            if ($order->invoice_type == 'sales') {
                $this->setOrderProfit($order);
                $route = $appointment
                    ? route('reservations.index', ['date' => optional($appointment->start_at)->toDateString()])
                    : route('orders.index');
            } elseif ($order->invoice_type == 'bookings') {
                $route = route('reservations.index');
            } else {
                $route = route('purchases.index');
            }
            if (
                $order->invoice_type === 'sales' &&
                Setting::findByKey('zatca_enabled', '0') == '1' &&
                Setting::findByKey('zatca_auto_submit', '0') != '1'
            ) {
                session([
                    'zatca_pending_order_id'      => $order->id,
                    'zatca_pending_invoice_number' => $order->invoice_number,
                ]);
            }

            //return redirect(route('orders.getPrint',$order->id));
            if (isset($inputs['savePrint']) && $inputs['savePrint'] == 'print') {
                $route = route('orders.getPrint', $order->id);
                if (request()->has('ispos')) {
                    $route .= '?ispos=1';
                }
                return redirect($route);
            }
            if (isset($inputs['saveandPrintBarcode']) && $inputs['saveandPrintBarcode'] == 1) {
                $route = route('orders.getPrintBarcode', $order->id);
                return redirect($route);
            }

            $request->session()->flash('alert-success', 'تم إضافة الفاتورة بنجاح');
            return redirect($route);
        } catch (\Exception $e) {
            DB::rollback();
            dd($e->getMessage());
            return back()->withInput($inputs)->with('alert-danger', ' حدث خطأ اثناء اضافة الفاتورة ' . $e->getMessage());
            //dd($e->getMessage());
            //$request->session()->flash('alert-danger', ' حدث خطأ اثناء اضافة الفاتورة '.$e->getMessage());
            //dd($e->getMessage());
        }
        return back();
    }

=== SALES INVOICE ACTION BUTTONS ===

====================================================================================================
CONTEXT_FILE=app/Http/Controllers/OrdersController.php
====================================================================================================
     303:         }
     304: 
     305:         $list->orderBy('id', 'DESC');
     306:         //->with('client','saleMan','creator');
     307:         if (!empty(request('client_id'))) {
     308:             $list->where('client_id', request('client_id'));
     309:         }
     310: 
>>   311:         if (!empty(request('priceType'))) {
     312:             $list->where('priceType', request('priceType'));
     313:         }
     314:         $from = request('fromdate');
     315:         $to = request('todate');
     316:         if (!empty($from)) {
     317:             $list->whereRaw("DATE(invoice_date) >= '{$from}'");
     318:         }
     319:         if (!empty($to)) {
     320:             $list->whereRaw("DATE(invoice_date) <= '{$to}'");
     321:         }
     322:         $currentUser = auth()->user();
     323: 
     324:         $datatable = DataTables::of($list);
     325:         if ($type === 'sales') {
     326:             $datatable->addColumn('zatca_status', function ($order) {
     327:                 if ($order->zatca_submitted_at) {
     328:                     return e($order->zatca_reporting_status ?: 'SENT');
     329:                 }
     330: 
     331:                 return '<span class="text-muted">—</span>';
     332:             });
     333:         }
     334:         $datatable
     335:             ->addColumn('total', function ($order) {
     336:                 $total = $order->total;
----------------------------------------------------------------------------------------------------
     337:                 return currency($total, $order->currency, $order->currency, $format = true);
----------------------------------------------------------------------------------------------------
     356:             })
     357:             ->addColumn('due', function ($order) {
     358:                 $due = $order->due;
     359:                 return currency($due, $order->currency, $order->currency, $format = true);
     360:             })
     361:             ->addColumn('dicount_value', function ($order) {
     362:                 return $order->dicount_value;
     363:             })
>>   364:             ->addColumn('priceType', function ($order) {
     365:                 return trans('front.' . $order->priceType);
     366:             })
     367:             ->addColumn('priceType', function ($order) {
     368:                 $priceType = $order->priceType;
     369:                 return trans("front.$priceType");
     370:             })
     371:             ->addColumn('payment_type', function ($order) {
     372:                 $payment = $order->payment_type;
     373:                 if ($order->payment_type == 'cash') {
     374:                     $payment = trans("front.$payment");
     375:                 } elseif ($order->payment_type == 'delayed') {
     376:                     $payment = trans("front.$payment");
     377:                 } elseif ($order->payment_type == 'visa') {
     378:                     $payment = trans("front.$payment");
     379:                 } else {
     380:                     $payment = trans("front.$payment");
     381:                     /*if($order->getOriginal('due')>0){
     382:                         $payment = trans("front.$payment");
     383:                     }*/
     384:                     if ((float) $order->commision) {
     385:                         $com = currency($order->commision, $order->currency, $order->currency, $format = true);
     386:                         $payment .= '<a style="margin: 5px;" class="btn btn-warning"> ' . $com . '</a>';
     387:                     }
     388:                 }
     389:                 return $payment;
----------------------------------------------------------------------------------------------------
     390:             })
----------------------------------------------------------------------------------------------------
     391:             ->addColumn('status', function ($order) {
     392:                 $btn = '';
----------------------------------------------------------------------------------------------------
     393:                 if ($order->status == 'delivered') {
----------------------------------------------------------------------------------------------------
     394:                     $btn .= '<button href = "#" type = "button" class="btn btn-sm btn-success" ><i class="fa  fa-check" ></i ></button >';
----------------------------------------------------------------------------------------------------
     395:                 } else {
     396:                     $btn .= '<a href = "' . route('orders.changeStatus', $order) . '" type = "button" class="btn btn-sm btn-danger changeStatus" ><i class="fa fa-times" ></i ></a>';
     397:                 }
     398:                 if ($order->is_withdrawable == 1) {
     399:                     $btn .= '<div class="bg-yellow" style="padding: 5px;"> مسحوبات </div>';
     400:                 }
     401:                 return $btn;
     402:             })
>>   403:             ->addColumn('actions', function ($order) use ($currentUser, $type) {
     404:                 $btn = "";
     405: 
     406:                 // TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721
     407:                 $zatcaLocked =
     408:                     \App\Services\Zatca\ZatcaDocumentLock::isLocked(
     409:                         $order
     410:                     );
     411: 
     412:                 if ($zatcaLocked) {
     413:                     $btn .= '<span class="btn btn-xs btn-default disabled"'
     414:                         . ' title="المستند مقفل بعد الإرسال إلى ZATCA">'
     415:                         . '<i class="fa fa-lock"></i></span> ';
     416:                 }
     417:                 if ($type === 'sales' && Setting::findByKey('zatca_enabled', '0') == '1' && !$order->zatca_submitted_at && $currentUser->can('edit OrdersController')) {
     418:                     $btn .= '<button type="button" class="btn btn-xs btn-default btn-zatca-submit" title="ZATCA"'
     419:                         . ' data-action="' . route('orders.zatca.submit', $order) . '"'
     420:                         . ' data-token="' . csrf_token() . '">'
     421:                         . '<i class="fa fa-cloud-upload"></i></button> ';
     422:                 }
     423:                 if (env('turbo_authentication_key') && !$order->is_shipped) {
     424:                     $btn .= ' <a data-toggle="modal" data-target="#myModalShipment" href="' . route('createTurpoShipment', $order) . '" class="btn btn-info btn-xs">
     425:                         <i class="fa fa-truck fa-fw" aria-hidden="true"></i>
     426:                     </a> ';
     427:                 }
     428:                 if (!$zatcaLocked && $currentUser->can('edit OrdersController')) {
----------------------------------------------------------------------------------------------------
     429: 
     430:                     $btn .= '<a href="' . route('orders.edit', $order) . '" class="btn btn-primary btn-xs">
     431:                         <i class="fa fa-pencil fa-fw" aria-hidden="true"></i>
     432:                     </a>';
     433:                 }
----------------------------------------------------------------------------------------------------
     434:                 if ($currentUser->can('show OrdersController')) {
     435:                     $printLink = route('orders.getPrint', $order->id);
     436:                     if ($order->invoice_type == 'bookings') {
     437:                         $printLink .= '?ispos=1';
     438:                         $btn .= '<form action="' . route('orders.changebooktoinvoice', $order) . '" method="POST" style="display: inline;">
     439:                                     ' . csrf_field() . '
     440:                                     <button type="submit" title="تحويل لفاتورة" class="btn btn-xs btn-info" onclick="confirmChangeToInvoice(' . $order->id . ')">
     441:                                         <i class="fa fa-file"></i>
     442:                                     </button>
     443:                                 </form>';
     444:                     }
     445:                     $btn .= ' <a data-toggle="modal" data-target="#addPersonModal" href="' . route('orders.show', $order) . '" class="btn btn-warning btn-xs">
     446:                     <i class="fa fa-eye fa-fw" aria-hidden="true"></i>
     447:                 </a> <a class=" btn btn-success btn-xs print-window" href="' . $printLink . '" target="_blank"
     448:                 role="button">
     449:                                     <i class="fa fa-print" aria-hidden="true"></i>
     450:                             </a>';
     451:                 }
     452:                 if (!$zatcaLocked && $currentUser->can('destroy OrdersController')) {
     453: 
     454:                     $btn .= ' <a class="btn btn-xs btn-danger remove-record" data-toggle="modal" data-url="' . route('orders.destroy', $order) . '" data-id="' . $order->id . '" data-target="#custom-width-modal">
     455:                     <i class="fa fa-trash"></i>
----------------------------------------------------------------------------------------------------
     456:                     </a>';
     457:                 }
     458: 
     459: 
     460:                 return $btn;
     461:             });
     462:         if (isset(request('search')['value']) && !empty(request('search')['value'])) {
----------------------------------------------------------------------------------------------------
     463:             $datatable->filter(function ($instance) {
     464:                 if (
     465:                     in_array(request('search')['value'], [
     466:                         'لم',
     467:                         'لم تسلم',
     468:                         'آجل',
     469:                         'اجل'
     470:                     ])
     471:                 ) {
     472:                     return $instance->where('payment_type', 'delayed');
     473:                 } else {
     474:                     $term = request('search')['value'];
     475:                     return $instance->whereHas('client', function ($q) use ($term) {
     476:                         $q->where('name', 'like', "%$term%");
     477:                     });
     478:                 }
     479:             });
----------------------------------------------------------------------------------------------------
     487:             $clone = clone $list;
     488:             $datatable = $datatable->with('totaldue', $clone->sum('due'));
     489:             $clone = clone $list;
     490:             $sumDiscount = $clone->get()->sum(function ($item) {
     491:                 return $item->dicount_value;
     492:             });
     493:             $datatable = $datatable->with('dicount_value', $sumDiscount);
     494:             $one = clone $list;
>>   495:             $datatable = $datatable->with('sumPriceOne', $one->priceTypeOne()->sum('total'));
     496:             $multi = clone $list;
     497:             $datatable = $datatable->with('sumPriceOneGomla', $multi->priceTypeGomla()->sum('total'));
     498:             $gomla = clone $list;
     499:             $datatable = $datatable->with('sumPriceOneGomlaGomla', $gomla->priceTypeGomlaGomla()->sum('total'));
     500: 
     501: 
     502: 
     503:             $cashOrders = clone $list;
     504:             $datatable = $datatable->with('cashOrders', $cashOrders->cashOrders()->sum('total'));
     505: 
     506:             $cashOrders = clone $list;
     507:             $datatable = $datatable->with('postPaidOrders', $cashOrders->postPaidOrders()->sum('total'));
     508: 
     509:             $cashOrders = clone $list;
     510:             $datatable = $datatable->with('visaOrders', $cashOrders->visaOrders()->sum('total'));
     511: 
     512:             $cashOrders = clone $list;
     513:             $datatable = $datatable->with('linkTransferOrders', $cashOrders->linkTransferOrders()->sum('total'));
     514:         }
     515:         $raw = ['actions', 'status', 'payment_type', 'is_withdrawable', 'clientname'];
     516:         if ($type === 'sales') {
     517:             $raw[] = 'zatca_status';
     518:         }
     519:         $datatable->rawColumns($raw);
     520:         return $datatable->make(true);;
----------------------------------------------------------------------------------------------------
     521:     }
     522: 
----------------------------------------------------------------------------------------------------
     523:     public function createSales()
     524:     {
----------------------------------------------------------------------------------------------------
     631:             }
     632:             if (isset($inputs['productNew'])) {
     633:                 foreach ($inputs['productNew'] as $k => $product) {
     634:                     if ($product['isnew'] == 'true') {
     635:                         $this->addNewProduct($inputs, $k);
     636:                     }
     637:                 }
     638:                 
>>   639:                 if ($request->has('ispos') && Setting::findByKey('pos_employee_required', 0) == 1 && isset($inputs['product'])) {
     640:     foreach ($inputs['product'] as $posItem) {
     641:         if (empty($posItem['employee_id'])) {
     642:             throw new \Exception('يجب اختيار موظف قبل حفظ فاتورة نقطة البيع');
     643:         }
     644:     }
     645: }
     646: 
     647:             }
     648: 
     649:             $inputs['order']['shipment_amount'] = isset($inputs['order']['shipment_amount']) ? $inputs['order']['shipment_amount'] : 0;
     650:             $inputs['order']['creator_id'] = auth()->user()->id;
     651:             $inputs['order']['invoice_date'] = $inputs['order']['invoice_date'] ?? date('Y-m-d');
     652:             $inputs['order']['discount_type'] = isset($inputs['order']['discount_type']) ? 2 : 1;
     653: 
     654:             $invoiceTypeForShift = isset($inputs['order']['invoice_type'])
     655:                 ? $inputs['order']['invoice_type']
     656:                 : ($request->has('ispos') ? 'sales' : 'sales');
     657: 
     658:             if ($invoiceTypeForShift == 'sales') {
     659:                 $openShift = Shift::where('user_id', auth()->id())
     660:                     ->where('status', 'open')
     661:                     ->latest('id')
     662:                     ->first();
     663: 
     664:                 if (!$openShift) {
----------------------------------------------------------------------------------------------------
     665:                     throw new \Exception('يجب فتح وردية أولاً قبل إنشاء فاتورة مبيعات');
     666:                 }
     667: 
     668:                 $inputs['order']['shift_id'] = $openShift->id;
     669:             }
     670: 
     671:             //return back()->withInput($inputs)->with('alert-danger', ' حدث خطأ اثناء اضافة الفاتورة ');
     672:             /*
     673:              * PAYMENT_BANK_ROUTING_SAR
     674:              * cash/delayed -> user treasury
     675:              * visa/link transfer -> SAR bank account
     676:              */
     677:             $paymentTypeForBank =
     678:                 $inputs['order']['payment_type'] ?? 'cash';
     679: 
     680:             $bank = Bank::resolveForPayment(
     681:                 $paymentTypeForBank,
----------------------------------------------------------------------------------------------------
     682:                 auth()->user()->treasury_id
     683:             );
     684: 
     685:             $inputs['order']['bank_id'] = $bank->id;
     686: 
     687:             if (!isset($inputs['order']['invoice_number'])) {
     688:                 $inputs['order']['invoice_type'] = $inputs['order']['invoice_type'] ?? 'sales';
     689: 
     690:                 /*
     691:                  * NATURAL_ORDER_SEQUENCE_NUMBER
     692:                  * Keep invoice number aligned with the next orders.id.
     693:                  */
----------------------------------------------------------------------------------------------------
     919:                             );
     920:                         }
     921:             
     922:                         // إعدادات القالب (شعار/بيانات/ملاحظات)
     923:                         $settings = Setting::pluck('value','key')->toArray();
     924:             
     925:                         // نوع الورقة: A4 أو POS80
     926:                         $paper = strtoupper((string) Setting::findByKey('whatsapp_invoice_pdf_paper', 'A4'));
>>   927:                         $isPos = in_array($paper, ['POS','POS80','RECEIPT','80'], true);
     928:             
     929:                         // مسار حفظ PDF
     930:                         $safeNo = preg_replace('/[^0-9A-Za-z_-]/', '_', (string)$order->invoice_number);
     931:                         $relativePath = "whatsapp/invoices/invoice_{$safeNo}_{$order->id}.pdf";
     932:                         $pdfAbsPath = storage_path('app/public/' . $relativePath);
     933:                         @mkdir(dirname($pdfAbsPath), 0755, true);
     934:             
     935:                         // HTML (قالب الواتساب الجديد)
     936:                         $html = view('orders.whatsapp_invoice_pdf', [
     937:                             'order' => $order,
     938:                             'settings' => $settings,
     939:                             'paper' => $isPos ? 'POS80' : 'A4',
     940:                         ])->render();
     941:             
     942:                         // توليد PDF عبر mPDF (يعالج العربية RTL بشكل صحيح)
     943:                         $tmpDir = storage_path('app/tmp/mpdf');
     944:                         @mkdir($tmpDir, 0755, true);
     945:             
     946:                         $mpdfConfig = [
     947:                             'mode' => 'utf-8',
     948:                             'tempDir' => $tmpDir,
     949:                             'default_font' => 'dejavusans',
     950:                             'autoScriptToLang' => true,
     951:                             'autoLangToFont' => true,
     952:                         ];
----------------------------------------------------------------------------------------------------
     953:             
     954:                         if ($isPos) {
     955:                             // تقدير ارتفاع POS حسب عدد العناصر
     956:                             $rows = 0;
     957:                             try { $rows = is_countable($order->items) ? count($order->items) : 0; } catch (\Exception $e) { $rows = 0; }
     958:             
     959:                             $baseMm  = 140;
     960:                             $rowMm   = 7;
     961:                             $extraMm = 80;
     962:                             $heightMm = $baseMm + ($rows * $rowMm) + $extraMm;
     963:                             if ($heightMm < 250) $heightMm = 250;
     964:                             if ($heightMm > 2000) $heightMm = 2000;
----------------------------------------------------------------------------------------------------
     965:             
     966:                             $mpdfConfig['format'] = [80, $heightMm];
     967:                             $mpdfConfig['margin_left'] = 3;
     968:                             $mpdfConfig['margin_right'] = 3;
     969:                             $mpdfConfig['margin_top'] = 3;
     970:                             $mpdfConfig['margin_bottom'] = 3;
     971:                         } else {
     972:                             $mpdfConfig['format'] = 'A4';
     973:                             $mpdfConfig['margin_left'] = 10;
     974:                             $mpdfConfig['margin_right'] = 10;
     975:                             $mpdfConfig['margin_top'] = 10;
     976:                             $mpdfConfig['margin_bottom'] = 10;
     977:                         }
     978:             
     979:                         $mpdf = new \Mpdf\Mpdf($mpdfConfig);
----------------------------------------------------------------------------------------------------
    1075:                     'zatca_pending_order_id'      => $order->id,
    1076:                     'zatca_pending_invoice_number' => $order->invoice_number,
    1077:                 ]);
    1078:             }
    1079: 
    1080:             //return redirect(route('orders.getPrint',$order->id));
    1081:             if (isset($inputs['savePrint']) && $inputs['savePrint'] == 'print') {
    1082:                 $route = route('orders.getPrint', $order->id);
>>  1083:                 if (request()->has('ispos')) {
    1084:                     $route .= '?ispos=1';
    1085:                 }
    1086:                 return redirect($route);
    1087:             }
    1088:             if (isset($inputs['saveandPrintBarcode']) && $inputs['saveandPrintBarcode'] == 1) {
    1089:                 $route = route('orders.getPrintBarcode', $order->id);
    1090:                 return redirect($route);
    1091:             }
    1092: 
    1093:             $request->session()->flash('alert-success', 'تم إضافة الفاتورة بنجاح');
    1094:             return redirect($route);
    1095:         } catch (\Exception $e) {
    1096:             DB::rollback();
    1097:             dd($e->getMessage());
    1098:             return back()->withInput($inputs)->with('alert-danger', ' حدث خطأ اثناء اضافة الفاتورة ' . $e->getMessage());
    1099:             //dd($e->getMessage());
    1100:             //$request->session()->flash('alert-danger', ' حدث خطأ اثناء اضافة الفاتورة '.$e->getMessage());
    1101:             //dd($e->getMessage());
    1102:         }
    1103:         return back();
    1104:     }
    1105: 
    1106: 
    1107: 
    1108:     /**
----------------------------------------------------------------------------------------------------
    1109:      * Display the specified resource.
----------------------------------------------------------------------------------------------------
    1158:      * Show the form for editing the specified resource.
    1159:      *
    1160:      * @param  int  $id
    1161:      * @return \Illuminate\Http\Response
    1162:      */
    1163:     public function edit(Order $order)
    1164:     {
    1165:         // TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721
>>  1166:         \App\Services\Zatca\ZatcaDocumentLock::abortIfLocked(
    1167:             $order
    1168:         );
    1169: 
    1170:         $type = $order->invoice_type;
    1171:         //dd($order->details);
    1172:         return view('orders.edit', compact('order', 'type'));
    1173:     }
    1174: 
    1175: 
    1176:     public function destroy(Order $order)
    1177:     {
    1178:         // TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721
    1179:         \App\Services\Zatca\ZatcaDocumentLock::abortIfLocked(
    1180:             $order
    1181:         );
    1182: 
    1183:         $this->rollback($order);
    1184:         $order->transaction()->delete();
    1185:         $order->client->transactions()
    1186:             ->where('record_id', $order->id)
    1187:             ->where('transaction_type', $order->invoice_type)
    1188:             ->delete();
    1189:         if ($order->delete()) {
    1190:             return "done";
    1191:         }
----------------------------------------------------------------------------------------------------
    1192:         return "failed";
    1193:     }
    1194:     public function deleteworkorder($id)
    1195:     {
    1196:         try {
    1197:             DB::beginTransaction();
----------------------------------------------------------------------------------------------------
    1198:             $order = WorkOrder::find($id);
    1199:             $details = $order->details;
    1200:             foreach ($details as $raw) {
    1201:                 $productStore = ProductStore::where('product_id', $raw->pivot->raw_unit_id)->first();
    1202:                 if ($productStore) {
    1203:                     $productStore->sale_count -= $raw->pivot->totalneedqty;
    1204:                     $productStore->save();
----------------------------------------------------------------------------------------------------
    1228:      *
    1229:      * @param  \Illuminate\Http\Request  $request
    1230:      * @param  int  $id
    1231:      * @return \Illuminate\Http\Response
    1232:      */
    1233:     public function update(Request $request, Order $order)
    1234:     {
    1235:         // TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721
>>  1236:         \App\Services\Zatca\ZatcaDocumentLock::abortIfLocked(
    1237:             $order
    1238:         );
    1239: 
    1240:         $inputs = $request->except('_token');
    1241:         try {
    1242:             DB::beginTransaction();
    1243:             $oldDue = $order->due;
    1244:             $oldClient = $order->client_id;
    1245:             $newClient = $inputs['order']['client_id'];
    1246:             if ($newClient != $oldClient) {
    1247:                 $order->client->transactions()
    1248:                     ->where('record_id', $order->id)
    1249:                     ->where('transaction_type', $order->invoice_type)
    1250:                     ->delete();
    1251:             }
    1252:             //dd($order->transaction);
    1253:             $productStores = $this->rollback($order);
    1254:             $inputs['order']['discount_type'] = isset($inputs['order']['discount_type']) ? 2 : 1;
    1255: 
    1256:             $invoiceTypeForShift = isset($inputs['order']['invoice_type'])
    1257:                 ? $inputs['order']['invoice_type']
    1258:                 : ($request->has('ispos') ? 'sales' : 'sales');
    1259: 
    1260:             if ($invoiceTypeForShift == 'sales') {
    1261:                 $openShift = Shift::where('user_id', auth()->id())
----------------------------------------------------------------------------------------------------
    1262:                     ->where('status', 'open')
    1263:                     ->latest('id')
    1264:                     ->first();
    1265: 
    1266:                 if (!$openShift) {
    1267:                     throw new \Exception('يجب فتح وردية أولاً قبل إنشاء فاتورة مبيعات');
    1268:                 }
    1269: 
    1270:                 $inputs['order']['shift_id'] = $openShift->id;
    1271:             }
    1272: 
    1273:             /*
    1274:              * PAYMENT_BANK_ROUTING_SAR
    1275:              * Re-resolve the bank when an invoice payment method changes.
    1276:              */
    1277:             $paymentTypeForBank =
    1278:                 $inputs['order']['payment_type']
    1279:                 ?? $order->payment_type
    1280:                 ?? 'cash';
    1281: 
    1282:             $bank = Bank::resolveForPayment(
    1283:                 $paymentTypeForBank,
----------------------------------------------------------------------------------------------------
    1284:                 auth()->user()->treasury_id
    1285:             );
    1286: 
    1287:             $inputs['order']['bank_id'] = $bank->id;
    1288:             if (isset($inputs['productNew'])) {
    1289:                 foreach ($inputs['productNew'] as $k => $product) {
    1290:                     if ($product['isnew'] == 'true') {
    1291:                         $this->addNewProduct($inputs, $k);
    1292:                     }
    1293:                 }
    1294:                 if ($request->has('ispos') && Setting::findByKey('pos_employee_required', 0) == 1 && isset($inputs['product'])) {
    1295:     foreach ($inputs['product'] as $posItem) {
----------------------------------------------------------------------------------------------------
    1296:         if (empty($posItem['employee_id'])) {
    1297:             throw new \Exception('يجب اختيار موظف قبل حفظ فاتورة نقطة البيع');
    1298:         }
    1299:     }
    1300: }
    1301: 
    1302:             }
    1303:             $inputs['order']['paid_egp'] = currency($inputs['order']['paid'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
    1304:             $inputs['order']['is_withdrawable'] = $request->has('is_withdrawable');
    1305:             //dd($inputs['product']);
    1306:             if (($inputs['order']['invoice_type'] ?? $order->invoice_type ?? null) === 'sales') {
    1307:                 $inputs['order']['currency'] = 'SAR';
    1308:             }
    1309: 
    1310:             $order->fill($inputs['order'])->save();
    1311:             if ($order->invoice_type == 'sales') {
    1312:                 $logNote = "تعديل فاتورة مبيعات رقم " . $order->invoice_number . " للعميل " . $order->client->name . " بقيمة " . $order->total;
    1313:             } else {
    1314:                 $logNote = "تعديل فاتورة مشتريات رقم " . $order->invoice_number . " من المورد " . $order->client->name . " بقيمة " . $order->total;
    1315:             }
    1316:             activity()->performedOn($order)->log($logNote);
    1317:             //$order->fill($inputs['order'])->save();
    1318:             $order->calander()->where('is_paid', false)->delete();
    1319:             if (isset($inputs['duepayment'])) {
----------------------------------------------------------------------------------------------------
    1746:         return [
    1747:             'appointment_id' => $appointment->id,
    1748:             'client' => [
    1749:                 'id' => $client ? $client->id : null,
    1750:                 'name' => $client ? $client->name : '',
    1751:                 'mobile' => $client ? $client->mobile : '',
    1752:                 'mobile2' => $client ? $client->mobile2 : '',
    1753:                 'total_due' => $client ? $client->total_due : 0,
>>  1754:                 'priceType' => $client ? $client->priceType : null,
    1755:                 'last_transaction' => $client ? $client->last_transaction : null,
    1756:                 'points' => $client ? $client->total_points : 0,
    1757:             ],
    1758:             'employee_id' => (string) $appointment->employee_id,
    1759:             'start_at' => $startAt->format('Y-m-d\TH:i'),
    1760:             'display_time' => $appointment->start_at->format('H:i') . ' - ' . $appointment->end_at->format('H:i'),
    1761:             'date' => $appointment->start_at->format('Y-m-d'),
    1762:             'services_total' => (float) $appointment->services->sum('service_price'),
    1763:             'services' => $appointment->services->map(function ($service) use ($appointment, $startAt) {
    1764:                 return [
    1765:                     'product_id' => $service->product_id,
    1766:                     'product_name' => $service->service_name,
    1767:                     'unit_id' => 1,
    1768:                     'unit_name' => 'خدمة',
    1769:                     'price' => (float) $service->service_price,
    1770:                     'cost' => 0,
    1771:                     'qty' => 1,
    1772:                     'total' => (float) $service->service_price,
    1773:                     'employee_id' => (string) $appointment->employee_id,
    1774:                     'serive_datetime' => $startAt->format('Y-m-d\TH:i'),
    1775:                 ];
    1776:             })->values()->all(),
    1777:         ];
    1778:     }
    1779: 
----------------------------------------------------------------------------------------------------

=== ZATCA CREDIT NOTE BUILDER ===

====================================================================================================
FILE=app/Services/Zatca/FatooraInvoiceService.php
====================================================================================================
FILE_FOUND=YES

--- METHOD=submitSalesReturn ---
    public function submitSalesReturn(ReturnProduct $return): array
    {
        if (Setting::findByKey('zatca_enabled', '0') != '1') {
            return ['success' => false, 'message' => 'ZATCA integration is disabled in settings.'];
        }
        if ($return->return_type !== 'sales') {
            return ['success' => false, 'message' => 'Only sales returns can be submitted as ZATCA credit notes.'];
        }
        if ($return->zatca_submitted_at) {
            return ['success' => false, 'message' => 'Return was already submitted to ZATCA.'];
        }
        if (!$return->order_id) {
            return ['success' => false, 'message' => 'Link the return to the original sales invoice before ZATCA submission.'];
        }

        return DB::transaction(function () use ($return) {
            /** @var ReturnProduct $return */
            $return = ReturnProduct::query()->whereKey($return->id)->lockForUpdate()->first();
            if (!$return) {
                return ['success' => false, 'message' => 'Return not found.'];
            }
            $return->load(['order.client', 'details']);

            $parent = $return->order;
            if (!$parent || !$parent->zatca_submitted_at) {
                return ['success' => false, 'message' => 'The original sales invoice must be sent to ZATCA before this credit note.'];
            }

            /** @var ZatcaCredential|null $credential */
            $credential = ZatcaCredential::query()->where('is_active', 1)->lockForUpdate()->first();
            if (!$credential || !$credential->private_key || !$credential->certificate || !$credential->secret) {
                return ['success' => false, 'message' => 'No active ZATCA credentials configured.'];
            }

            $nextDoc = (new ZatcaSubmissionQueue())->getNextPending();
            if (!$nextDoc || $nextDoc['type'] !== 'return' || (int) $nextDoc['model']->id !== (int) $return->id) {
                throw new ZatcaSubmissionOutOfOrderException(
                    'يجب إرسال الوثائق بالترتيب — توجد فاتورة أو مردود سابق لم يُرسل إلى الهيئة بعد.'
                );
            }

            config(['zatca.app.environment' => $credential->environment]);

            $seller = $this->makeSeller($credential);
            $invoiceItems = $this->buildReturnInvoiceItems($return);
            if (count($invoiceItems) === 0) {
                return ['success' => false, 'message' => 'Return has no line items.'];
            }

            $aggregates = $this->aggregateItems($invoiceItems);
            $taxPercent = (float) ($return->tax ?? 0);
            if ($taxPercent > 0 && !in_array($taxPercent, [5.0, 15.0], true)) {
                return ['success' => false, 'message' => "Invalid VAT rate {$taxPercent}% — KSA Standard Rate must be 5% or 15% (BR-KSA-84)."];
            }
            $invoiceUuid = $return->zatca_invoice_uuid ?: (string) Str::uuid();
            if (!$return->zatca_invoice_uuid) {
                $return->zatca_invoice_uuid = $invoiceUuid;
                $return->save();
            }

            $returnCreatedAtKsa = $return->created_at->copy()->setTimezone('Asia/Riyadh');
            $invoiceDate = $return->return_date
                ? \Carbon\Carbon::parse($return->return_date)->toDateString()
                : $returnCreatedAtKsa->toDateString();
            $invoiceTime = $returnCreatedAtKsa->format('H:i:s');
            $previousHash = $credential->last_invoice_hash ?: null;

            $creditNumber = 'CR-' . $return->id;
            $billingRef = (string) $parent->invoice_number;
            $invoiceNote = 'Credit note for sales return #' . $return->id . ' referencing invoice ' . $billingRef;

            $invoice = new Invoice(
                (int) (self::CREDIT_NOTE_ICV_OFFSET + (int) $return->id),
                $creditNumber,
                $invoiceUuid,
                $invoiceDate,
                $invoiceTime,
                InvoiceType::CREDIT_NOTE,
                $this->mapPaymentType($parent->payment_type),
                $aggregates['price'],
                $aggregates['discount'],
                $aggregates['tax'],
                $aggregates['total'],
                $invoiceItems,
                $previousHash,
                $billingRef,
                $invoiceNote,
                'return #' . $return->id,
                'SAR',
                $taxPercent,
                $invoiceDate
            );

            // TESTMOBILE_ZATCA_DOCUMENT_TOTALS_BT115_FIX_20260720
            $invoice->prepaid_amount = 0.0;
            $invoice->payable_amount = round(
                (float) (
                    $return->total
                    ?: $return->return_value
                ),
                2
            );
            $invoice->payable_rounding_amount = round(
                $invoice->payable_amount
                    - (float) $invoice->total,
                2
            );

            $clientPerson = $parent->client;
            $useB2b = $this->isB2BClient($clientPerson);

            if ($useB2b) {
                $fatooraClient = $this->makeClient($clientPerson);
                $reporter = B2B::make($seller, $invoice, $fatooraClient)->report();
            } else {
                $reporter = B2C::make($seller, $invoice)->report();
            }

            $assessment = $this->assessSubmissionResult($reporter);

            $validationStatus = $assessment['validation_status'];
            $reportingStatus = $assessment['reporting_status'];

            $return->zatca_qr_payload = $assessment['qr'];
            $return->zatca_signed_xml = $assessment['xml'];
            $return->zatca_reporting_status = $reportingStatus;
            $return->zatca_validation_status = $validationStatus;
            $return->zatca_invoice_hash = $assessment['invoice_hash'];
            $return->zatca_raw_response = [
                'validation' => $assessment['validation'],
                'info' => $assessment['info'],
                'warnings' => $assessment['warnings'],
                'errors' => $assessment['errors'],
                'classification' => $assessment['classification'],
                'strict_pass' => $assessment['strict_pass'],
                'accepted' => $assessment['accepted'],
                'artifacts_complete' => $assessment['artifacts_complete'],
            ];

            if ($assessment['accepted']) {
                /*
                 * Accepted credit notes must remain in the local PIH chain,
                 * including documents accepted with validation warnings.
                 */
                $return->zatca_submitted_at = now();
                $return->save();

                if ($assessment['invoice_hash'] !== '') {
                    $credential->last_invoice_hash =
                        $assessment['invoice_hash'];
                    $credential->save();
                }

                if ($assessment['xml'] !== '') {
                    $this->saveXmlFile(
                        $useB2b
                            ? 'standard'
                            : 'simplified/credit',
                        'CR-' . $return->id,
                        $assessment['xml']
                    );
                }
            } else {
                $return->zatca_submitted_at = null;
                $return->save();
            }

            return [
                'success' => $assessment['accepted'],
                'accepted' => $assessment['accepted'],
                'strict_pass' => $assessment['strict_pass'],
                'classification' => $assessment['classification'],
                'reporting_status' => $reportingStatus,
                'validation_status' => $validationStatus,
                'warnings_count' => count($assessment['warnings']),
                'errors_count' => count($assessment['errors']),
                'message' => $assessment['message'],
            ];
        });
    }

--- METHOD=buildReturnInvoiceItems ---
    protected function buildReturnInvoiceItems(ReturnProduct $return): array
    {
        $return->loadMissing('details');
        $taxPercent = (float) ($return->tax ?? 0);
        $taxCategoryCode = $taxPercent > 0 ? TaxCategoryCode::STANDARD_RATE : TaxCategoryCode::ZERO_RATE;
        $items = [];
        $lineNo = 1;

        foreach ($return->details as $product) {
            $pivot = $product->pivot;
            $qty = (float) $pivot->qty;
            if ($qty <= 0) {
                continue;
            }

            $lineTotalInclTax = round((float) $pivot->price * $qty, 4);
            $rate = $taxPercent > 0 ? ($taxPercent / 100) : 0;
            $lineTax = $rate > 0 ? round($lineTotalInclTax - ($lineTotalInclTax / (1 + $rate)), 4) : 0.0;
            $lineNet = round($lineTotalInclTax - $lineTax, 4);
            $unitNet = $qty > 0 ? round($lineNet / $qty, 12) : 0.0;
            $name = $pivot->product_name ?: $product->name;

            $items[] = new InvoiceItem(
                $lineNo++,
                (string) $name,
                (int) round($qty),
                (float) $unitNet,
                0.0,
                (float) $lineTax,
                (float) $taxPercent,
                (float) $lineTotalInclTax,
                null,
                $taxCategoryCode
            );
        }

        return $items;
    }

--- METHOD=aggregateItems ---
    protected function aggregateItems(array $invoiceItems): array
    {
        // TESTMOBILE_ZATCA_DOCUMENT_TOTALS_BT115_FIX_20260720
        // BT-106 and BT-116 must be based on the sum of
        // individually rounded invoice line net amounts (BT-131).
        $price = 0.0;
        $discount = 0.0;
        $taxGroups = [];

        foreach ($invoiceItems as $item) {
            $lineNet = round((float) $item->sub_total, 2);
            $lineDiscount = round((float) $item->discount, 2);
            $taxPercent = (float) $item->tax_percent;
            $taxCategory = (string) $item->tax_category_code;

            $price = round($price + $lineNet, 2);
            $discount = round(
                $discount + $lineDiscount,
                2
            );

            $groupKey = $taxCategory
                . '|'
                . number_format(
                    $taxPercent,
                    6,
                    '.',
                    ''
                );

            if (!isset($taxGroups[$groupKey])) {
                $taxGroups[$groupKey] = [
                    'taxable' => 0.0,
                    'rate' => $taxPercent,
                ];
            }

            $taxGroups[$groupKey]['taxable'] = round(
                $taxGroups[$groupKey]['taxable']
                    + $lineNet,
                2
            );
        }

        $tax = 0.0;

        foreach ($taxGroups as $group) {
            $groupTax = $group['rate'] > 0
                ? round(
                    $group['taxable']
                    * ($group['rate'] / 100),
                    2
                )
                : 0.0;

            $tax = round($tax + $groupTax, 2);
        }

        // BT-112 = BT-109 + BT-110.
        $total = round($price + $tax, 2);

        return [
            'price' => round($price, 2),
            'discount' => round($discount, 2),
            'tax' => round($tax, 2),
            'total' => round($total, 2),
        ];
    }