=== 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');
----------------------------------------------------------------------------------------------------
     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');
----------------------------------------------------------------------------------------------------

====================================================================================================
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');
----------------------------------------------------------------------------------------------------
      67:         Route::get('shifts', 'ShiftApiController@index');
      68:         Route::post('shifts/open', 'ShiftApiController@open');
      69:         Route::post('shifts/close', 'ShiftApiController@close');
      70:         Route::get('shifts/{id}/report', 'ShiftApiController@report');
      71: 
>>    72:         Route::get('invoices', 'InvoiceController@index');
      73:         Route::post('invoices/preview-totals', 'InvoiceController@previewTotals');
      74:         Route::post('invoices', 'InvoiceController@store');
      75:         Route::post('invoices/zatca/submit-all', 'InvoiceController@submitAllZatca');
      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
ALL_METHODS=index,getSales,getPurchases,createSales,createPurchase,create,store,show,getPrint,edit,update,rollback,setOrderProfit,submitZatca,destroy

--- METHOD=index ---
	public function index($type='sales') {
        $returns = ReturnProduct::where('return_type',$type)->latest()->get();
		return view('returns.index', compact('returns','type'));
	}

--- 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();
    }

--- METHOD=submitZatca ---
    public function submitZatca($id, Request $request, FatooraInvoiceService $zatca)
    {
        $return = ReturnProduct::findOrFail($id);
        if (!auth()->user()->can('edit OrdersController')) {
            abort(403);
        }
        if ($return->return_type !== 'sales') {
            return redirect()->route('zatca.dashboard', ['view' => 'returns'])
                ->with('alert-danger', 'يمكن إرسال مردود المبيعات فقط.');
        }
        try {
            $result = $zatca->submitSalesReturn($return);
            if (empty($result['success'])) {
                return redirect()
                    ->route(
                        'zatca.dashboard',
                        ['view' => 'returns']
                    )
                    ->with(
                        'alert-danger',
                        $result['message']
                        ?? 'فشل إرسال إشعار الدائن'
                    );
            }

            if (empty($result['strict_pass'])) {
                return redirect()
                    ->route(
                        'zatca.dashboard',
                        [
                            'view' => 'returns',
                            'return' => $return->id,
                        ]
                    )
                    ->with(
                        'alert-warning',
                        $result['message']
                        ?? 'قُبل إشعار الدائن مع ملاحظات، وتوقف الطابور للمراجعة.'
                    );
            }

            return redirect()->route('zatca.dashboard', ['view' => 'returns', 'return' => $return->id])
                ->with('alert-success', 'تم إرسال إشعار الدائن (CREDIT_NOTE) — الحالة: ' . ($result['reporting_status'] ?? ''));
        } catch (ZatcaSubmissionOutOfOrderException $e) {
            return redirect()->route('zatca.dashboard', ['view' => 'returns'])
                ->with('alert-warning', $e->getMessage());
        } catch (\Throwable $e) {
            return redirect()->route('zatca.dashboard', ['view' => 'returns'])
                ->with('alert-danger', 'ZATCA: ' . $e->getMessage());
        }
    }

=== MOBILE RETURN SERVICE ===

====================================================================================================
FILE=app/Services/Mobile/CreateSalesReturnService.php
====================================================================================================
FILE_FOUND=YES
ALL_METHODS=__construct,handle

--- 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;
        }
    }

--- METHOD=resolveOriginalOrder ---
METHOD_FOUND=NO

--- METHOD=calculateTotals ---
METHOD_FOUND=NO

=== MOBILE RETURN API CONTROLLER ===

====================================================================================================
FILE=app/Http/Controllers/Api/V1/ReturnApiController.php
====================================================================================================
FILE_FOUND=YES
ALL_METHODS=index,show,store,transform

--- METHOD=index ---
    public function index(Request $request)
    {
        $query = ReturnProduct::with(['client'])
            ->where('return_type', 'sales')
            ->latest('id');

        if ($request->filled('client_id')) {
            $query->where('client_id', $request->client_id);
        }
        if ($request->filled('order_id')) {
            $query->where('order_id', $request->order_id);
        }

        $rows = $query->take(50)->get()->map(function (ReturnProduct $return) {
            return $this->transform($return, false);
        });

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

--- 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 EVENT ===

====================================================================================================
FILE=app/Events/ReturnCreated.php
====================================================================================================
FILE_FOUND=YES
ALL_METHODS=__construct,broadcastOn

--- METHOD=__construct ---
    public function __construct(ReturnProduct $order,$productStores=[])
    {
        $this->order = $order;
        $this->productStores = $productStores;
    }

=== RETURN LISTENER ===

====================================================================================================
FILE=app/Listeners/UpdateProductQuantityReturn.php
====================================================================================================
FILE_FOUND=YES
ALL_METHODS=__construct,handle

--- 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;
        }

    }

=== EVENT REGISTRATION ===

====================================================================================================
CONTEXT_FILE=app/Providers/EventServiceProvider.php
====================================================================================================
       1: <?php
       2: 
       3: namespace App\Providers;
       4: 
       5: use App\Events\OrderCreated;
>>     6: use App\Events\ReturnCreated;
       7: use App\Listeners\QueueZatcaInvoiceSubmission;
       8: use App\Listeners\UpdateProductQuantity;
       9: use App\Listeners\UpdateProductQuantityReturn;
      10: use Illuminate\Support\Facades\Event;
      11: use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
      12: 
      13: class EventServiceProvider extends ServiceProvider
      14: {
      15:     /**
      16:      * The event listener mappings for the application.
      17:      *
      18:      * @var array
      19:      */
      20:     protected $listen = [
      21:         OrderCreated::class => [
----------------------------------------------------------------------------------------------------
      22:             UpdateProductQuantity::class,
      23:             QueueZatcaInvoiceSubmission::class,
      24:         ],
----------------------------------------------------------------------------------------------------
>>    25:         ReturnCreated::class => [
      26:             UpdateProductQuantityReturn::class,
      27:         ],
      28:     ];
      29: 
      30:     /**
      31:      * Register any events for your application.
      32:      *
      33:      * @return void
      34:      */
      35:     public function boot()
      36:     {
      37:         parent::boot();
      38: 
      39:         //
      40:     }
----------------------------------------------------------------------------------------------------
      41: }
----------------------------------------------------------------------------------------------------

=== 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';
        });
    }

}


=== ORDER MODEL RETURN RELATIONS ===

====================================================================================================
CONTEXT_FILE=app/Order.php
====================================================================================================
       4: 
       5: use Illuminate\Database\Eloquent\Model;
       6: use Illuminate\Database\Eloquent\SoftDeletes;
       7: use Illuminate\Support\Facades\DB;
       8: use Kyslik\ColumnSortable\Sortable;
>>     9: use Salla\ZATCA\GenerateQrCode;
      10: use Salla\ZATCA\Tags\InvoiceDate;
      11: use Salla\ZATCA\Tags\InvoiceTaxAmount;
      12: use Salla\ZATCA\Tags\InvoiceTotalAmount;
      13: use Salla\ZATCA\Tags\Seller;
      14: use Salla\ZATCA\Tags\TaxNumber;
      15: 
      16: class Order extends Model
      17: {
      18:     use SoftDeletes;
      19:     protected $table = 'orders';
      20:     protected $fillable = [
      21:         'invoice_number',
      22:         'client_id',
      23:         'sale_id',
      24:         'total',
----------------------------------------------------------------------------------------------------
      25:         'paid',
----------------------------------------------------------------------------------------------------
      26:         'due',
----------------------------------------------------------------------------------------------------
      27:         'tax',
----------------------------------------------------------------------------------------------------
      28:         'discount',
----------------------------------------------------------------------------------------------------
      29:         'discount_type',
----------------------------------------------------------------------------------------------------
      45:         'is_withdrawable',
      46:         'note',
      47:         'manager_id',
      48:         'profit',
      49:         'priceType',
>>    50:         'total_return',
      51:         'auth_code',
      52:         'use_point',
      53:         'discount_value',
      54:         'creator_id',
      55:         'shift_id',
      56:         'supplier_invoice_number',
      57:         'tax_value',
      58:         'is_shipped',
      59:         'shipment_amount',
      60:         'zatca_invoice_uuid',
      61:         'zatca_qr_payload',
      62:         'zatca_signed_xml',
      63:         'zatca_reporting_status',
      64:         'zatca_validation_status',
      65:         'zatca_invoice_hash',
----------------------------------------------------------------------------------------------------
      66:         'zatca_raw_response',
      67:         'zatca_submitted_at',
      68:     ];
      69:     protected $casts = [
      70:         'totalDept' => 'double',
----------------------------------------------------------------------------------------------------
      71:         'totalReturn' => 'double',
      72:         'zatca_raw_response' => 'array',
      73:         'zatca_submitted_at' => 'datetime',
      74:     ];
      75: public function transaction()
----------------------------------------------------------------------------------------------------
      76:     {
----------------------------------------------------------------------------------------------------
      77:         return $this->morphOne(BankTransaction::class, 'transactionable');
----------------------------------------------------------------------------------------------------
      78:     }
----------------------------------------------------------------------------------------------------
      79:     public function items()
----------------------------------------------------------------------------------------------------
      80:     {
----------------------------------------------------------------------------------------------------
      81:         return $this->hasMany(OrderDetail::class, 'order_id', 'id');
----------------------------------------------------------------------------------------------------
      82:     }
----------------------------------------------------------------------------------------------------
      83: 
      84:     public function details()
      85:     {
      86:         return $this->belongsToMany(Product::class, 'order_detailes', 'order_id', 'product_id')
      87:             ->withPivot([
----------------------------------------------------------------------------------------------------
      88:                 'store_name',
----------------------------------------------------------------------------------------------------
      89:                 'unit_name',
      90:                 'product_name',
      91:                 'store_id',
      92:                 'unit_id',
      93:                 'qty',
      94:                 'bounse',
      95:                 'bounse_unit_id',
      96:                 'bounseUnitText',
      97:                 'is_service',
      98:                 'return_qty',
      99:                 'cost',
----------------------------------------------------------------------------------------------------
     100:                 'price',
     101:                 'total',
     102:                 'created_at',
     103:                 'markter',
     104:                 'customer_price',
     105:                 'status',
     106:                 'comment',
     107:                 'discount1',
     108:                 'discount2',
     109:                 'serive_datetime',
     110:                 'employee_id',
     111:                 'employee_name'
     112:             ])
     113:             ->withTimestamps();
----------------------------------------------------------------------------------------------------
     125:             ->whereNull('deleted_at');
     126:     }
     127: 
     128:     public function shift()
     129:     {
>>   130:         return $this->belongsTo(Shift::class, 'shift_id', 'id');
     131:     }
     132: 
     133:     public function creator()
     134:     {
     135:         return $this->belongsTo(User::class, 'creator_id', 'id');
     136:     }
     137:     public function saleMan()
     138:     {
     139:         return $this->belongsTo(Employee::class, 'sale_id', 'id')->withTrashed();
     140:     }
     141:     public function market()
     142:     {
     143:         return $this->belongsTo(Employee::class, 'markter_id', 'id');
     144:     }
     145: 
----------------------------------------------------------------------------------------------------
     162:     }
     163: 
     164:     public function getTotalCostAttribute()
     165:     {
     166:         return $this->hasMany(OrderDetail::class)
>>   167:             ->sum(DB::raw('(qty - return_qty) * cost'));
     168:     }
     169:     public function getTotalSaleAttribute()
     170:     {
     171:         return $this->hasMany(OrderDetail::class)
     172:             ->sum(DB::raw('(qty - return_qty) * price'));
     173:     }
     174: 
     175:     public function getOrderProfitAttribute()
     176:     {
     177:         $totalProfit = $this->hasMany(OrderDetail::class)
     178:             ->sum(DB::raw('(qty - return_qty) * (price - cost)'));
     179:         $totalProfit = floatval($totalProfit);
     180:         $discount = floatval($this->discount) ?: 0;
     181:         if ($discount) {
     182:             if ($this->discount_type == 2) {
----------------------------------------------------------------------------------------------------
     183:                 $discount = $this->total * ($this->discount / 100);
     184:             }
     185:         }
     186:         return $totalProfit - $discount;
     187:     }
----------------------------------------------------------------------------------------------------
     188: 
     189:     public function getFgrandOrderTotalAttribute()
     190:     {
     191:         return $this->hasMany(OrderDetail::class)->sum(DB::raw('(qty * price) - (return_qty * price)'));
     192:     }
     193:     public function setDiscountValueAttribute($value)
----------------------------------------------------------------------------------------------------
     194:     {
     195:         $order = request()->all()['order'];
     196:         $discount = $this->attributes['discount'] ?: 0;
     197:         if ($discount && isset($this->attributes['discount_type'])) {
     198:             if ($this->attributes['discount_type'] == 2) {
     199:                 $discount = $order['total'] * ($discount / 100);
     200:             }
     201:         }
     202:         $this->attributes['discount_value'] = $discount;
     203:     }
     204:     public function getDicountValueAttribute()
     205:     {
     206: 
----------------------------------------------------------------------------------------------------
     296:     {
     297:         try {
     298:             if (!$TaxAmount) {
     299:                 return '';
     300:             }
>>   301:             // Format to 2dp strings to match ZATCA spec and avoid float precision issues
     302:             $totalStr = number_format((float) $TotalAmount, 2, '.', '');
     303:             $taxStr   = number_format((float) $TaxAmount,   2, '.', '');
     304:             $generatedString = GenerateQrCode::fromArray([
     305:                 new Seller($name),
     306:                 new TaxNumber($taxNumber),
     307:                 new InvoiceDate($date),
     308:                 new InvoiceTotalAmount($totalStr),
     309:                 new InvoiceTaxAmount($taxStr)
     310:             ])->render();
     311:             return $generatedString;
     312:         } catch (\Exception $e) {
     313:             return 0;
     314:         }
     315:     }
     316: 
----------------------------------------------------------------------------------------------------
     317:     /*
     318:      * FORCE_NEW_ORDER_CURRENCY_TO_SAR
>>   319:      * This Saudi/ZATCA installation creates records in SAR only.
     320:      */
     321:     protected static function boot()
     322:     {
     323:         parent::boot();
     324: 
     325:         static::creating(function ($model) {
     326:             $model->currency = 'SAR';
     327:         });
     328:     }
     329: 
     330: 
     331:     /**
     332:      * NATURAL_ORDER_SEQUENCE_NUMBER
     333:      *
     334:      * Returns the next natural orders.id value without using
----------------------------------------------------------------------------------------------------
>>   335:      * a separate application counter. This preserves the ZATCA
     336:      * ICV sequence even when historical orders are cleared.
     337:      */
     338:     public static function nextNaturalInvoiceNumber()
     339:     {
     340:         $sequence = null;
     341: 
     342:         if (DB::connection()->getDriverName() === 'sqlite') {
     343:             $sequence = DB::table('sqlite_sequence')
     344:                 ->where('name', 'orders')
     345:                 ->value('seq');
     346:         }
     347: 
     348:         if ($sequence === null) {
     349:             $sequence = static::query()->max('id') ?: 0;
     350:         }
----------------------------------------------------------------------------------------------------

=== ORDER DETAIL MODEL ===
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;


class OrderDetail extends Model
{

    /**
     * SERVICE_UNIT_ID_ONE_NORMALIZATION
     *
     * All service lines use unit_id=1 and store_id=1.
     * This keeps web, Flutter and imported appointment lines identical.
     */
    protected static function boot()
    {
        parent::boot();

        static::saving(function (OrderDetail $detail) {
            $product = null;

            if ($detail->product_id) {
                $product = Product::withTrashed()
                    ->find($detail->product_id);
            }

            $isService =
                (int) $detail->is_service === 1
                || (
                    $product
                    && (int) $product->is_service === 1
                )
                || trim((string) $detail->unit_id) === 'خدمة'
                || trim((string) $detail->unit_name) === 'خدمة';

            if (!$isService) {
                return;
            }

            $unit = Unit::find(1);

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

            $store = Store::find(1);

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

            $detail->unit_id = 1;
            $detail->unit_name = 'خدمة';
            $detail->store_id = 1;
            $detail->store_name = $store->name;
            $detail->is_service = 1;
        });
    }

    protected $table = 'order_detailes';

    protected $fillable = [
        'order_id',
        'product_id',
        'store_id',
        'unit_id',
        'cost_egp',
        'price_egp',
        'bounse',
        'store_name',
        'unit_name',
        'product_name',
        'store_id',
        'unit_id',
        'qty',
        'bounse',
        'bounse_unit_id',
        'bounseUnitText',
        'is_service',
        'return_qty',
        'cost',
        'price',
        'total',
        'created_at',
        'markter',
        'bounse_unit_id',
        'bounseUnitText',
        'customer_price',
        'status',
        'comment',
        'discount1',
        'discount2',
        'serive_datetime', 'employee_id', 'employee_name'

    ];

    public function product()
    {
        return $this->belongsTo(Product::class, 'product_id', 'id')->withTrashed();
    }

    public function employee()
    {
        return $this->belongsTo(Employee::class, 'employee_id', 'id')->withTrashed();
    }

    public function store()
    {
        return $this->belongsTo(Store::class, 'store_id', 'id');
    }

    public function order()
    {
        return $this->belongsTo(Order::class, 'order_id', 'id');
    }

    public function unit()
    {
        return $this->belongsTo(Unit::class, 'unit_id', 'id');
    }

    public function invoice()
    {
        return $this->belongsTo(Order::class, 'order_id', 'id');
    }

    public function getCostAttribute($value)
    {
        return round($value, 2);
    }
    public function getPriceAttribute($value)
    {
        return round($value, 2);
    }
    public function getTotalAttribute($value)
    {
        return round($value, 2);
    }

    public function scopeFilter($query)
    {
        $client_id = request('client_id');
        $fromdate = request('fromdate');
        $todate = request('todate');
        $employee_id = request('employee_id');
        $product_id = request('product_id');
        $status = request('status');
        if ($client_id) {
            $query->whereHas('order', function ($q) use ($client_id) {
                $q->where('client_id', $client_id);
            });
        }
        if ($product_id) {
            $query->where('product_id', $product_id);
        }
        if ($employee_id) {
            $query->where('employee_id', $employee_id);
        }
        if ($fromdate) {
            $query->whereDate('serive_datetime','>=', $fromdate);
        }
        if ($todate) {
            $query->whereDate('serive_datetime','<=', $todate);
        }
        if ($status) {
            $query->where('status', $status);
        }
        $keyword = request('keyword');
        if ($keyword) {
            $query->whereHas('order.client', function ($subqry) use ($keyword) {
                $subqry->where('name', 'like', '%' . $keyword . '%')
                    ->orwhere('mobile', 'like', '%' . $keyword . '%');;
            });;
        }
        return $query;
    }
}


=== ZATCA RETURN BUILDING ===

====================================================================================================
FILE=app/Services/Zatca/FatooraInvoiceService.php
====================================================================================================
FILE_FOUND=YES
ALL_METHODS=submitOrder,submitSalesReturn,assessSubmissionResult,normalizeReporterMessages,getNextPendingDocument,getNextPendingOrder,getNextPendingReturn,buildReturnInvoiceItems,mapPaymentType,paymentNote,isB2BClient,makeSeller,makeClient,decodeAddress,buildInvoiceItems,aggregateItems,saveXmlFile

--- 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),
        ];
    }

--- METHOD=getNextPendingDocument ---
    public function getNextPendingDocument(): ?array
    {
        return (new ZatcaSubmissionQueue())->getNextPending();
    }

=== RETURN PAYMENT AND BANK ROUTING ===

====================================================================================================
CONTEXT_FILE=app/Listeners/UpdateProductQuantityReturn.php
====================================================================================================
       1: <?php
       2: 
       3: namespace App\Listeners;
       4: 
       5: use App\Bank;
>>     6: use App\BankTransaction;
       7: use App\ProductStore;
       8: use App\ProductUnit;
       9: use App\Setting;
      10: use App\Transaction;
      11: use App\TresuryTranaction;
      12: use Illuminate\Queue\InteractsWithQueue;
      13: use Illuminate\Contracts\Queue\ShouldQueue;
      14: 
      15: class UpdateProductQuantityReturn
      16: {
      17:     /**
      18:      * Create the event listener.
      19:      *
      20:      * @return void
      21:      */
      22:     public function __construct()
      23:     {
      24:         //
----------------------------------------------------------------------------------------------------
      25:     }
      26: 
      27:     /**
      28:      * Handle the event.
----------------------------------------------------------------------------------------------------
      89:                     $productStore->qty -= $orderQty;
      90:                 }
      91: 
      92:                 $productStore->save();
      93: 
      94:             }
      95:             /*
      96:              * Sales returns must follow the financial treatment of the
>>    97:              * original invoice. Never trust request('bank_id') or a mobile
      98:              * is_cash value when an original invoice is linked.
      99:              *
     100:              * cash          => original invoice treasury
     101:              * visa          => original invoice bank
     102:              * link transfer => original invoice bank (تحويل بنكي)
     103:              * delayed       => reduce client receivable
     104:              */
     105:             if ($order->return_type == 'sales') {
     106:                 $originalOrder = $order->order;
     107: 
     108:                 $paymentType = $originalOrder
     109:                     ? strtolower(trim((string) $originalOrder->payment_type))
     110:                     : null;
     111: 
     112:                 $isCreditReturn =
     113:                     ($originalOrder && $paymentType == 'delayed')
     114:                     || (!$originalOrder && !$order->is_cash);
     115: 
----------------------------------------------------------------------------------------------------
     116:                 if ($isCreditReturn) {
----------------------------------------------------------------------------------------------------
     117:                     $order->client
     118:                         ->transactions()
----------------------------------------------------------------------------------------------------
     119:                         ->create([
----------------------------------------------------------------------------------------------------
     120:                             'value' => -$order->return_value,
----------------------------------------------------------------------------------------------------
     121:                             'note' => ' خصم قيمة مرتجعات من الحساب ',
----------------------------------------------------------------------------------------------------
     122:                             'transaction_type' => $order->return_type,
     123:                             'record_id' => $order->id
     124:                         ]);
     125:                 } else {
     126:                     if ($originalOrder) {
     127:                         $bankPaymentTypes = [
----------------------------------------------------------------------------------------------------
     128:                             'cash',
     129:                             'visa',
     130:                             'link transfer',
     131:                         ];
----------------------------------------------------------------------------------------------------
     132: 
----------------------------------------------------------------------------------------------------
     133:                         if (!in_array(
     134:                             $paymentType,
     135:                             $bankPaymentTypes,
     136:                             true
----------------------------------------------------------------------------------------------------
     137:                         )) {
     138:                             throw new \Exception(
     139:                                 'طريقة دفع الفاتورة الأصلية غير مدعومة للمرتجع: '
     140:                                 . $originalOrder->payment_type
----------------------------------------------------------------------------------------------------
     141:                             );
     142:                         }
     143: 
     144:                         $bankId = (int) $originalOrder->bank_id;
     145:                     } else {
     146:                         /*
     147:                          * Backward-compatible fallback for old unlinked
----------------------------------------------------------------------------------------------------
     148:                          * returns created from the web interface.
----------------------------------------------------------------------------------------------------
     149:                          */
     150:                         $bankId = (int) request('bank_id');
     151:                     }
     152: 
     153:                     if (!$bankId) {
     154:                         throw new \Exception(
     155:                             'تعذر تحديد حساب رد قيمة المرتجع'
     156:                         );
     157:                     }
     158: 
----------------------------------------------------------------------------------------------------
     159:                     $bank = Bank::find($bankId);
     160: 
     161:                     if (!$bank) {
     162:                         throw new \Exception(
----------------------------------------------------------------------------------------------------
     163:                             'الحساب المالي المرتبط بالفاتورة الأصلية غير موجود'
     164:                         );
     165:                     }
     166: 
     167:                     $grand = currency(
     168:                         $order->return_value,
----------------------------------------------------------------------------------------------------
     169:                         currency()->getUserCurrency(),
     170:                         $bank->currency,
     171:                         false
     172:                     );
     173: 
     174:                     $grand = round((float) $grand, 2);
     175: 
     176:                     $trans = [
>>   177:                         'bank_id' => $bank->id,
     178:                         'op_date' => date('Y-m-d'),
     179:                         'total' => $bank->balance,
     180:                         'due' => (float) $bank->balance - $grand,
     181:                         'type' => '1',
     182:                         'note' => 'مرتجع مبيعات  | ' . $order->client->name,
     183:                         'value' => $grand,
     184:                     ];
     185: 
     186:                     $bank->balance =
     187:                         (float) $bank->balance - $grand;
     188: 
     189:                     $bank->save();
     190: 
     191:                     if ($order->transaction) {
     192:                         $order->transaction()->update($trans);
     193:                     } else {
     194:                         $order->transaction()->create($trans);
     195:                     }
----------------------------------------------------------------------------------------------------
     196:                 }
     197:             } elseif ($order->is_cash) {
     198:                 /*
     199:                  * Purchase return behavior is preserved unchanged.
     200:                  */
     201:                 $bankId = request('bank_id');
     202: 
     203:                 if ($bankId) {
     204:                     $banktans = $order->transaction()->first();
     205: 
     206:                     if ($banktans) {
     207:                         $bank = $banktans->bank;
     208:                     } else {
     209:                         $bank = Bank::find($bankId);
----------------------------------------------------------------------------------------------------
     210:                     }
----------------------------------------------------------------------------------------------------
     211: 
     212:                     $trans["bank_id"] = $bankId;
----------------------------------------------------------------------------------------------------
     213:                     $bank = Bank::find($bankId);
     214:                     $trans["op_date"] = date('Y-m-d');
     215:                     $trans["total"] = $bank->balance;
----------------------------------------------------------------------------------------------------
     216: 
     217:                     $grand = currency(
     218:                         $order->return_value,
     219:                         currency()->getUserCurrency(),
----------------------------------------------------------------------------------------------------
     220:                         $bank->currency,
     221:                         false
     222:                     );
----------------------------------------------------------------------------------------------------
     223: 
     224:                     $note = 'مرتجع مشتريات  | ' . $order->client->name;
     225:                     $trans["due"] = $bank->balance + $grand;
     226:                     $bank->balance += $grand;
     227:                     $trans["type"] = "2";
     228:                     $trans["note"] = $note;
     229:                     $trans["value"] = $grand;
     230:                     $bank->save();
----------------------------------------------------------------------------------------------------
     231: 
>>   232:                     if ($order->transaction) {
     233:                         $order->transaction()->update($trans);
     234:                     } else {
     235:                         $order->transaction()->create($trans);
     236:                     }
     237:                 }
     238:             } else {
     239:                 $order->client
     240:                     ->transactions()
     241:                     ->create([
     242:                         'value' => -$order->return_value,
     243:                         'note' => ' خصم قيمة مرتجعات من الحساب ',
     244:                         'transaction_type' => $order->return_type,
     245:                         'record_id' => $order->id
     246:                     ]);
     247:             }
     248:         } catch (\Exception $exception) {
     249:             \Log::error($exception->getMessage());
     250: 
----------------------------------------------------------------------------------------------------
     251:             throw $exception;
----------------------------------------------------------------------------------------------------
     252:         }
     253: 
----------------------------------------------------------------------------------------------------
     254:     }
     255: }
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------

====================================================================================================
CONTEXT_FILE=app/Services/Mobile/CreateSalesReturnService.php
====================================================================================================
      64: 
      65:         $attach = [];
      66:         $itemsSubtotal = 0.0;
      67: 
      68:         /*
      69:          * MOBILE_SERVICE_RETURN_NO_STOCK
      70:          *
      71:          * return_qty updates are collected here and executed only inside
>>    72:          * the database transaction after all rows pass validation.
      73:          */
      74:         $orderDetailAdjustments = [];
      75: 
      76:         foreach ($items as $row) {
      77:             $productId = (int) ($row['product_id'] ?? 0);
      78:             $product = Product::with(['productUnit', 'productStore'])->find($productId);
      79:             if (!$product) {
      80:                 throw new \Exception('صنف غير موجود');
      81:             }
      82: 
      83:             $qty = (float) ($row['qty'] ?? 0);
      84:             if ($qty <= 0) {
      85:                 throw new \Exception('كمية مرتجع غير صحيحة لـ ' . $product->name);
      86:             }
      87: 
      88:             // Cap returns vs sold qty when setting requires it (same as web)
      89:             if (isset($settings['show_all_products_returns']) && (string) $settings['show_all_products_returns'] === '1') {
      90:                 $totalReturn = ReturnDetail::join('returns', function ($qry) use ($clientId) {
----------------------------------------------------------------------------------------------------
     250:             $itemsSubtotal,
     251:             $discount,
     252:             $discountType,
     253:             $taxPercent,
     254:             $priceIncludesTax,
     255:             $roundingUp
     256:         );
     257: 
>>   258:         DB::beginTransaction();
     259: 
     260:         try {
     261:             foreach (
     262:                 $orderDetailAdjustments
     263:                 as $detailId => $adjustmentQty
     264:             ) {
     265:                 $detail = OrderDetail::find($detailId);
     266: 
     267:                 if (!$detail) {
     268:                     throw new \Exception(
     269:                         'تعذر العثور على سطر الفاتورة الأصلية'
     270:                     );
     271:                 }
     272: 
     273:                 $detail->return_qty =
     274:                     (float) $detail->return_qty
     275:                     + (float) $adjustmentQty;
     276: 
----------------------------------------------------------------------------------------------------
     291:                 'sales_value' => $totals['items_subtotal'],
     292:                 'sales_value_egp' => $totals['items_subtotal'],
     293:                 'return_value' => $totals['total'],
     294:                 'total' => $totals['total'],
     295:                 /*
     296:                  * The financial treatment of a linked sales return must
     297:                  * follow the original invoice, not a client-supplied flag.
     298:                  *
>>   299:                  * cash / visa / bank transfer => refund from original bank
     300:                  * delayed                     => reduce client receivable
     301:                  */
     302:                 'is_cash' => $order && in_array(
     303:                     strtolower(trim((string) $order->payment_type)),
     304:                     ['cash', 'visa', 'link transfer'],
     305:                     true
     306:                 ) ? 1 : 0,
     307:             ];
     308: 
     309:             $return = ReturnProduct::create($returnData);
     310:             $return->details()->attach($attach);
     311: 
     312:             event(new ReturnCreated($return));
     313: 
     314:             if ($order) {
     315:                 $order->total_return = (float) $order->total_return + (float) $totals['total'];
     316:                 $order->save();
     317:             }
----------------------------------------------------------------------------------------------------
     318: 
----------------------------------------------------------------------------------------------------
     319:             DB::commit();
     320: 
----------------------------------------------------------------------------------------------------
     321:             return $return->fresh(['details', 'client', 'order']);
----------------------------------------------------------------------------------------------------
     322:         } catch (\Exception $e) {
----------------------------------------------------------------------------------------------------

====================================================================================================
CONTEXT_FILE=app/Http/Controllers/ReturnsController.php
====================================================================================================
       1: <?php
       2: 
       3: namespace App\Http\Controllers;
       4: 
>>     5: use App\BankTransaction;
       6: use App\Events\ReturnCreated;
       7: use App\Events\ReturnProductCreated;
       8: use App\Order;
       9: use App\OrderDetail;
      10: use App\ReturnDetail;
      11: use App\ReturnProduct;
      12: use App\ProductStore;
      13: use App\ProductUnit;
      14: use App\Setting;
      15: use App\TresuryTranaction;
      16: use App\Services\Zatca\FatooraInvoiceService;
      17: use App\Services\Zatca\Exceptions\ZatcaSubmissionOutOfOrderException;
      18: use Carbon\Carbon;
      19: use DB;
      20: use Exception;
      21: use Illuminate\Http\Request;
      22: 
      23: class ReturnsController extends Controller {
----------------------------------------------------------------------------------------------------
      53: 	 * Store a newly created resource in storage.
      54: 	 *
      55: 	 * @param  \Illuminate\Http\Request  $request
      56: 	 * @return \Illuminate\Http\Response
      57: 	 */
      58: 	public function store(Request $request) {
      59: 
      60: 	    try {
>>    61:             DB::beginTransaction();
      62:             $inputs = $request->except('_token');
      63:             $inputs['order']['creator_id'] = auth()->user()->id;
      64:             $inputs['order']['is_cash'] = $request->has('is_cash');
      65:             $inputs['order']['discount_type'] = isset($inputs['order']['discount_type'])?2:1;
      66:             $inputs['order']['sales_value_egp'] = currency($inputs['order']['sales_value'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
      67:             $order = null;
      68:             if($inputs['order']['order_id']){
      69:                 $order = Order::find($inputs['order']['order_id']);
      70:             }
      71:             $client = $inputs['order']['client_id'];
      72:             foreach ($inputs['product'] as $pid=>$prod){
      73:                 $totalReturn = ReturnDetail::join('returns',function($qry)use($client){
      74:                     $qry->on('returns.id','=','return_id');
      75:                     $qry->where('client_id',$client);
      76:                     $qry->whereNull('deleted_at');
      77:                 })->where('product_id',$pid)->sum('qty');
      78:                 $settings = Setting::get()->pluck('value','key')->toArray();
      79:                 if(isset($settings['show_all_products_returns']) && $settings['show_all_products_returns']==1) {
----------------------------------------------------------------------------------------------------
      80:                     $totalOrder = OrderDetail::join('orders', function ($qry) use ($client) {
      81:                         $qry->on('orders.id', '=', 'order_id');
      82:                         $qry->where('client_id', $client);
----------------------------------------------------------------------------------------------------
     185: 	 */
     186: 	public function update(Request $request, ReturnProduct $return) {
     187: 	    // TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721
     188: 	    \App\Services\Zatca\ZatcaDocumentLock::abortIfLocked(
     189: 	        $return
     190: 	    );
     191: 
     192: 		try {
>>   193:             DB::beginTransaction();
     194:             $inputs = $request->except('_token');
     195:             $productStores = $this->rollback($return);
     196:             $inputs['order']['is_cash'] = $request->has('is_cash');
     197:             $inputs['order']['sales_value_egp'] = currency($inputs['order']['sales_value'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
     198:             $order = null;
     199:             if($inputs['order']['order_id']){
     200:                 $order = Order::find($inputs['order']['order_id']);
     201:             }
     202:             $inputs['order']['discount_type'] = isset($inputs['order']['discount_type'])?2:1;
     203:             if(isset($inputs['product'])){
     204:                 foreach ($inputs['product'] as $key=>$value){
     205:                     //$inputs['product'][$key]['cost'] = currency($inputs['product'][$key]['cost'],"SAR",$return->currency, false);
     206:                     if($inputs['product'][$key]['cost'] > $inputs['product'][$key]['price']){
     207:                         $inputs['product'][$key]['cost'] = $inputs['product'][$key]['price'];
     208:                     }
     209:                     $inputs['product'][$key]['cost_egp'] = currency($value['cost'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
     210:                     $inputs['product'][$key]['price_egp'] = currency($value['price'],currency()->getUserCurrency(),currency()->config('default'), $format = false);
     211:                     if($order){
----------------------------------------------------------------------------------------------------
     212:                         $details = OrderDetail::where('order_id',$order->id)
     213:                             ->where('product_id',$key)
     214:                             ->first();
----------------------------------------------------------------------------------------------------
     246:            // \Log::error($e->getMessage());
     247: 			DB::rollback();
     248: 			dd($e->getMessage());
     249: 		}
     250: 		return back();
     251: 	}
     252: 
     253: 	public function rollback($return){
>>   254:         $return->client->transactions()
     255:                 ->where('record_id',$return->id)
     256:                 ->where('transaction_type',$return->return_type)
     257:                 ->delete();
     258:         //TresuryTranaction::where('record_id',$return->id)->delete();
     259:         $order = null;
     260:         if($return->order_id){
     261:             $order = Order::find($return->order_id);
     262:         }
     263: 
     264:         $banktans = $return->transaction;//BankTransaction::where('record_id',$order->id)->first();
     265: 
     266:         if($banktans){
     267:             if($banktans->type==1){
     268:                 $banktans->bank->balance += $banktans->getOriginal('value');
     269:             }else{
     270:                 $banktans->bank->balance -= $banktans->getOriginal('value');
     271:             }
     272:             $banktans->bank->save();
----------------------------------------------------------------------------------------------------
     273:             //$banktans->delete();
     274:         }
----------------------------------------------------------------------------------------------------
     275: 
     276:         $details = $return->details;
     277:         $productStores = array();
     278:         foreach ($details as $item){
     279:             if($item->is_service==1)continue;
     280:             $productStore = ProductStore::where('product_id', $item->id)
     281:                                         ->where('store_id', $item->pivot->store_id)
     282:                                         ->first();
----------------------------------------------------------------------------------------------------
     420:         \App\Services\Zatca\ZatcaDocumentLock::abortIfLocked(
     421:             $lockedReturn
     422:         );
     423: 
     424:         return "done";
     425:         try{
     426:             $return = ReturnProduct::find($id);
     427:             $this->rollback($return);
>>   428:             $trans = $return->transaction;
     429:             if($trans){
     430:                 $trans->delete();
     431:             }
     432:             if($return->delete()){
     433:                 return "done";
     434:             }
     435:             return "failed";
     436:         }catch(Exception $e){
     437:             dd($e->getMessage());
     438:         }
     439:     }
     440: 
     441: 
     442: }
----------------------------------------------------------------------------------------------------

====================================================================================================
CONTEXT_FILE=app/Bank.php
====================================================================================================
      10:     protected $table = 'banks';
      11: 
      12:     protected $fillable = ['name','number','balance','percent','currency','type'];
      13: 
      14:     public function getCreatedAtAttribute($value)
      15:     { 
      16:         return date('Y-m-d', strtotime($value));
      17:     }
>>    18:     public function transactions(){
      19:         return $this->hasMany(BankTransaction::class);
      20:     }
      21: /*
      22:     public function getBalanceAttribute($value)
      23:     {
      24:         $value =  currency($value,$this->currency,currency()->getUserCurrency(), $format = true);
      25:         return round($value,2);
      26:     }*/
      27: 
      28: 
      29:     /*
      30:      * FORCE_NEW_BANK_CURRENCY_TO_SAR
      31:      * This Saudi/ZATCA installation creates records in SAR only.
      32:      */
      33:     protected static function boot()
      34:     {
      35:         parent::boot();
      36: 
----------------------------------------------------------------------------------------------------
      37:         static::creating(function ($model) {
----------------------------------------------------------------------------------------------------
      38:             $model->currency = 'SAR';
      39:         });
      40:     }
      41: 
      42: 
      43:     /**
      44:      * PAYMENT_BANK_ROUTING_SAR
      45:      *
>>    46:      * cash / delayed:
      47:      *     User treasury, which must be a SAR cash treasury.
      48:      *
      49:      * visa / link transfer:
      50:      *     First active operational SAR bank account (type 1).
      51:      */
      52:     public static function resolveForPayment($paymentType, $treasuryId)
      53:     {
      54:         $paymentType = strtolower(trim((string) $paymentType));
      55: 
      56:         if (in_array($paymentType, ['visa', 'link transfer'], true)) {
      57:             $bank = static::query()
      58:                 ->where('type', 1)
      59:                 ->where('currency', 'SAR')
      60:                 ->orderBy('id')
      61:                 ->first();
      62: 
      63:             if (!$bank) {
      64:                 throw new \RuntimeException(
----------------------------------------------------------------------------------------------------
      65:                     'لا يوجد حساب بنكي بالريال السعودي لاستقبال دفعات الشبكة أو التحويل'
----------------------------------------------------------------------------------------------------
      66:                 );
      67:             }
----------------------------------------------------------------------------------------------------
      68: 
      69:             return $bank;
      70:         }
----------------------------------------------------------------------------------------------------
      71: 
      72:         if (in_array($paymentType, ['cash', 'delayed'], true)) {
      73:             $bank = static::query()
      74:                 ->where('id', (int) $treasuryId)
----------------------------------------------------------------------------------------------------
      75:                 ->where('type', 2)
      76:                 ->where('currency', 'SAR')
      77:                 ->first();
      78: 
      79:             if (!$bank) {
      80:                 throw new \RuntimeException(
      81:                     'لا توجد خزنة ريال سعودي صحيحة مرتبطة بالمستخدم الحالي'
      82:                 );
      83:             }
      84: 
      85:             return $bank;
      86:         }
      87: 
      88:         throw new \InvalidArgumentException(
      89:             'طريقة الدفع غير مدعومة: ' . $paymentType
      90:         );
----------------------------------------------------------------------------------------------------
      91:     }
      92: 
----------------------------------------------------------------------------------------------------

=== RETURN CREATE VIEW ===

====================================================================================================
CONTEXT_FILE=resources/views/returns/create.blade.php
====================================================================================================
      13: 				@endif
      14: 			</small>
      15: 		</h1>
      16: 	</section>
      17: 	<!-- Main content -->
>>    18: 	<form action="{{route('returns.store')}}" method="post">
      19: 		{{ csrf_field() }}
      20: 		@include('returns._form')
      21: 	</form>
      22: @stop
----------------------------------------------------------------------------------------------------

=== RETURN EDIT VIEW ===

====================================================================================================
CONTEXT_FILE=resources/views/returns/edit.blade.php
====================================================================================================
       9: 				{{$return->id}}
      10: 			</small>
      11: 		</h1>
      12: 	</section>
      13: 	<!-- Main content -->
>>    14: 	<form action="{{route('returns.update',$return)}}" method="post">
      15: 		{{ csrf_field() }}
      16: 		{{ method_field('PUT')  }}
      17: 		@include('returns._form')
      18: 	</form>
      19: @stop
----------------------------------------------------------------------------------------------------

=== RETURN INDEX VIEW ===

====================================================================================================
CONTEXT_FILE=resources/views/returns/index.blade.php
====================================================================================================
      53: 								<tr>
      54: 									<td>{{$loop->iteration}}</td>
      55:                                     <td>{{optional($return->creator)->name}}</td>
      56: 									<td>{{$return->return_date}}</td>
      57:                                     <td>{{optional($return->client)->name}}</td>
      58:                                     <td>{{optional($return->saleMan)->name}}</td>
      59: 									<td>
>>    60: 										{{currency($return->return_value,$return->currency, $return->currency, $format = true)}}
      61: 									</td>
      62: 									<td>
      63: 										{{currency($return->sales_value,$return->currency, $return->currency, $format = true)}}
      64: 									</td>
      65: 									<td>
      66: 										{{$return->is_cash?trans('front.cash'):trans('front.from previous balance')}}
      67: 									</td>
      68: 									<td class="actions">
      69: 										@if (!\App\Services\Zatca\ZatcaDocumentLock::isLocked($return)) {-- TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721 --}
      70: 										<a href="{{route('returns.edit',$return)}}" class="btn btn-primary btn-xs">
      71: 											<i class="fa fa-pencil fa-fw" aria-hidden="true"></i>
      72: 											@lang('front.edit')
      73: 										</a>
      74: 										@endif
----------------------------------------------------------------------------------------------------
      75: 										<a data-toggle="modal" data-target="#addPersonModal"  href="{{route('returns.show',$return)}}" class="btn btn-warning btn-xs">
      76: 											<i class="fa fa-eye fa-fw" aria-hidden="true"></i>
      77: 											 @lang('front.show')
      78: 										</a>
      79: 										@if (!\App\Services\Zatca\ZatcaDocumentLock::isLocked($return)) {-- TESTMOBILE_ZATCA_IMMUTABLE_DOCUMENT_LOCK_20260721 --}
      80: 										<a class="btn btn-xs btn-danger remove-record" data-toggle="modal" data-url="{{route('returns.destroy',$return)  }}" data-id="{{$return->id}}" data-target="#custom-width-modal">
      81: 											<i class="fa fa-trash"></i>
      82: 											@lang('front.delete')
      83: 										</a>
----------------------------------------------------------------------------------------------------
      84: 										@endif
----------------------------------------------------------------------------------------------------
      85: 
      86: 									</td>
      87: 								</tr>
      88: 							@endforeach
      89: 							</tbody>
      90: 						</table>
      91: 					</div>
      92: 					<!-- /.box-body -->
      93: 				</div>
----------------------------------------------------------------------------------------------------
      94: 				<!-- /.box -->
----------------------------------------------------------------------------------------------------

=== SALES INVOICE ACTION COLUMN ===

====================================================================================================
CONTEXT_FILE=app/Http/Controllers/OrdersController.php
====================================================================================================
      33: use Illuminate\Http\Request;
      34: use Picqer\Barcode\BarcodeGeneratorPNG;
      35: use Yajra\DataTables\DataTables;
      36: use Illuminate\Pagination\LengthAwarePaginator;
      37: 
      38: class OrdersController extends Controller
      39: {
      40: 
      41:     public function index($type = 'sales')
      42:     {
>>    43:         $orders = []; //Order::where('invoice_type',$type)->latest()->get();
      44:         return view('orders.index', compact('orders', 'type'));
      45:     }
      46:     public function report()
      47:     {
      48:         if (!request()->ajax()) {
      49:             return view('reports.orders');
      50:         } else {
      51:             return $this->getData('sales');
      52:         }
      53:     }
      54: 
      55: 
      56:     public function purchasereport()
      57:     {
      58:         if (!request()->ajax()) {
      59:             return view('reports.purchase');
      60:         } else {
      61:             return $this->getData('purchase');
      62:         }
      63:     }
      64: 
      65: 
      66:     /*  public function getSales(){
      67:           return $this->index('sales');
      68:       }*/
      69:     public function getSales(Request $request)
      70:     {
      71:         // $orders = Order::where('invoice_type','sales')
----------------------------------------------------------------------------------------------------
      72:         // ->whereRaw(DB::raw('CAST(invoice_number AS INT) >= 120')  )
      73:         //                 ->orderBy('id','ASC')->get();
      74:         // $i = 120;
      75:         // foreach($orders as $order){
      76:         //     $order->invoice_number = $i;
      77:         //     $i++;
      78:         //     $order->save();
      79:         // }
      80:         ini_set('memory_limit', -1);
      81: 
      82:         if (!$request->ajax()) {
      83:             $type = 'sales';
      84:             $urlRoute = route('orders.index');
      85:             return view('orders.index', compact('type', 'urlRoute'));
      86:         } else {
      87:             return $this->getData('sales');
      88:         }
      89:     }
      90: 
      91:     public function getBookings(Request $request)
      92:     {
      93:         $filters = [
      94:             'fromdate' => $request->get('fromdate', now()->startOfMonth()->toDateString()),
      95:             'todate' => $request->get('todate', now()->toDateString()),
      96:             'employee_id' => $request->get('employee_id'),
      97:             'client_id' => $request->get('client_id'),
      98:             'status' => $request->get('status'),
      99:             'invoice_filter' => $request->get('invoice_filter'),
----------------------------------------------------------------------------------------------------
     272:     {
     273:         $order->profit = $order->order_profit;
     274:         $order->save();
     275:     }
     276:     public function getData($type)
     277:     {
     278:         ini_set('memory_limit', -1);
     279:         //Order::query()->update(['bank_id'=>1]);
     280:         $userTreasury = (int) auth()->user()->treasury_id;
     281: 
>>   282:         $list = Order::where('invoice_type', $type);
     283: 
     284:         if ($type === 'sales') {
     285:             /*
     286:              * SALES_LIST_ALL_PAYMENT_BANKS
     287:              *
     288:              * A Visa or bank-transfer invoice belongs to the user's
     289:              * treasury/shift even though its bank_id points to the
     290:              * settlement bank instead of the cash treasury.
     291:              */
     292:             $list->where(function ($query) use ($userTreasury) {
     293:                 $query->where('bank_id', $userTreasury)
     294:                     ->orWhereHas('shift', function ($shiftQuery) use ($userTreasury) {
     295:                         $shiftQuery->where('treasury_id', $userTreasury);
     296:                     })
     297:                     ->orWhereHas('creator', function ($userQuery) use ($userTreasury) {
     298:                         $userQuery->where('treasury_id', $userTreasury);
     299:                     });
     300:             });
     301:         } else {
     302:             $list->where('bank_id', $userTreasury);
     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);
     338:             })
     339:             ->addColumn('totalbefore', function ($order) {
----------------------------------------------------------------------------------------------------
     340:                 return round(($order->total - $order->tax_value), 2);
----------------------------------------------------------------------------------------------------
     354:             ->addColumn('paid', function ($order) {
     355:                 return currency($order->getOriginal('paid'), $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:             });
     480:         }
     481:         $roteName = request()->route()->getName();
     482: 
----------------------------------------------------------------------------------------------------
     485:             $clone = clone $list;
     486:             $datatable = $datatable->with('totalpaid', $clone->sum('paid'));
     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:     {
     525:         return $this->create('sales');
----------------------------------------------------------------------------------------------------
     526:     }
     527: 
----------------------------------------------------------------------------------------------------
     580:         $product->productStore()->attach($store);
     581:     }
     582: 
     583:     public function changebooktoinvoice($id)
     584:     {
     585:         /*
     586:          * NATURAL_ORDER_SEQUENCE_NUMBER
     587:          * Keep the cloned invoice aligned with the next orders.id.
     588:          */
     589:         $invoice_number = Order::nextNaturalInvoiceNumber();
>>   590:         // Order::query()->where('id', $id)->update(['invoice_type' => 'sales', 'invoice_number' => $invoice_number]);
     591: 
     592: 
     593:         $originalOrder = Order::with('items')->findOrFail($id);
     594: 
     595:         $clonedOrder = $originalOrder->replicate();
     596:         $clonedOrder->invoice_number = $invoice_number;
     597:         $clonedOrder->invoice_type = 'sales';
     598:         $clonedOrder->save();
     599: 
     600:         foreach ($originalOrder->items as $originalItem) {
     601:             $clonedItem = $originalItem->replicate();
     602:             $clonedItem->order_id = $clonedOrder->id;
     603:             $clonedItem->save();
     604:         }
     605: 
     606:         return back()->with('alert-success', 'تم تحويل الحجز الى فاتورة');
     607:     }
     608:     public function store(Request $request)
     609:     {
     610: 
     611:         $inputs = $request->except('_token');
     612:         $appointmentId = $request->input('appointment_id');
     613:         $appointment = null;
     614: 
     615:         try {
     616: 
     617:             DB::beginTransaction();
     618: 
----------------------------------------------------------------------------------------------------
     619:             if ($appointmentId) {
     620:                 $appointment = Appointment::with(['services'])->lockForUpdate()->find($appointmentId);
     621:                 if (!$appointment) {
     622:                     throw new \Exception('الحجز غير موجود');
     623:                 }
     624:                 if ($appointment->invoice_order_id) {
     625:                     throw new \Exception('تم إنشاء فاتورة لهذا الحجز بالفعل');
----------------------------------------------------------------------------------------------------
     629:             if (Setting::findByKey('enable_empty_invoice') == 0 && !isset($inputs['product'])) {
     630:                 throw new \Exception('لا يمكنك إضافة الفاتورة بدون منتجات');
     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:                  */
     694:                 $inputs['order']['invoice_number'] =
     695:                     Order::nextNaturalInvoiceNumber();
     696:               
----------------------------------------------------------------------------------------------------
     697:             } else {
     698:                 if ($inputs['order']['invoice_type'] == 'sales') {
     699:                     $checkNumber = Order::where('invoice_type', 'sales')->where('invoice_number', $inputs['order']['invoice_number'])->first();
     700:                     if ($checkNumber) {
     701:                         return back()->withInput($inputs)->with('alert-danger', 'رقم الفاتورة ' . $inputs['order']['invoice_number'] . ' مكرر حاول اضافة الفاتورة مره اخرى  ');
     702:                     }
     703:                 }
     704:             }
     705: 
     706:             $inputs['order']['paid_egp'] = currency($inputs['order']['paid'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
     707:             $inputs['order']['is_withdrawable'] = $request->has('is_withdrawable');
     708:             $client = Person::find($inputs['order']['client_id']);
     709:             $pointval = Setting::findByKey('point_value');
     710:             $inputs['order']['use_point'] = isset($inputs['order']['use_point']) ? 1 : 0;
     711:             if ($inputs['order']['use_point'] && $client->total_points) {
     712:                 $totalValue = $pointval * $client->total_points;
     713:                 $balance = $client->total_points;
     714:                 $discount = $totalValue;
     715:                 if ($totalValue > $inputs['order']['total']) {
     716:                     $balance = $inputs['order']['total'];
----------------------------------------------------------------------------------------------------
     717:                     $discount = $inputs['order']['total'];
     718:                 }
     719:                 $inputs['order']['discount_type'] = 1;
     720:                 $inputs['order']['discount'] = $discount;
     721:             }
     722: 
     723:             if (($inputs['order']['invoice_type'] ?? null) === 'sales') {
     724:                 $inputs['order']['currency'] = 'SAR';
     725:             }
     726: 
----------------------------------------------------------------------------------------------------
     727:             $order = Order::create($inputs['order']);
----------------------------------------------------------------------------------------------------
     728: 
     729:             if ($order->invoice_type == 'sales') {
     730:                 $logNote = "فاتورة مبيعات رقم " . $order->invoice_number . " للعميل " . $order->client->name . " بقيمة " . $order->total;
     731:             } else {
     732:                 $logNote = "فاتورة مشتريات رقم " . $order->invoice_number . " من المورد " . $order->client->name . " بقيمة " . $order->total;
     733:             }
     734:             //activity()->performedOn($order)->log($logNote);
     735:             if ($inputs['order']['use_point'] && $client->total_points) {
     736:                 UserPoint::create([
     737:                     'user_id' => $order->client_id,
     738:                     'balance' => -$balance,
     739:                     'order_id' => $order->id
     740:                 ]);
     741:             }
     742:            if ($pointval && !$inputs['order']['use_point']) {
     743:     $earnRate = floatval(Setting::findByKey('point_earn_rate', 0.10));
     744:     $earnedPoints = floor(($order->total - $order->discount_value) * $earnRate);
     745:     if ($earnedPoints > 0) {
     746:         UserPoint::create([
     747:             'user_id' => $order->client_id,
     748:             'balance' => $earnedPoints,
     749:             'order_id' => $order->id
     750:         ]);
     751:     }
----------------------------------------------------------------------------------------------------
     752: }
     753:             if (isset($inputs['duepayment'])) {
     754:                 foreach ($inputs['duepayment']['date'] as $i => $date) {
     755:                     CalanderPayment::create([
     756:                         'order_id' => $order->id,
     757:                         'date' => $date,
----------------------------------------------------------------------------------------------------
     769:                     //                 ->first();
     770:                     //     $inputs['product'][$key]['store_id'] = $poductRow->productStore->first()->id;
     771:                     //     $inputs['product'][$key]['unit_id'] = $poductRow->productUnit->first()->id;
     772:                     // }
     773:                     $inputs['product'][$key]['total'] = $inputs['product'][$key]['qty'] * $value['price'];
     774:                     $inputs['product'][$key]['cost_egp'] = currency($value['cost'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
     775:                     $inputs['product'][$key]['price_egp'] = currency($value['price'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
     776:                     $rawproductids[] = $value['product_id'];
     777:                     $rawCostPrice[$value['product_id']] = $value['price'];
     778:                 }
>>   779:                 if (!in_array($order->invoice_type, ['sales', 'bookings'])) {
     780:                     $raws = DB::table('product_raw_materials')
     781:                         ->whereIn('raw_material_id', $rawproductids)
     782:                         ->pluck('product_id')
     783:                         ->toArray();
     784:                     $rpoduct = Product::with(['rawMatrial', 'productUnit'])
     785:                         ->whereIn('id', $raws)
     786:                         //->where('id',26)
     787:                         ->get();
     788: 
     789:                     foreach ($rpoduct as $p) {
     790:                         $finalcost = 0;
     791:                         foreach ($p->rawMatrial as $r) {
     792:                             $cost = $rawCostPrice[$r->id] ?? $r->last_cost;
     793:                             $finalcost += ($r->pivot->qty * $cost);
     794:                         }
     795:                         foreach ($p->productUnit as $unit) {
     796:                             $unit->pivot->cost_price = $finalcost * $unit->pivot->pieces_num;
     797:                             $unit->pivot->save();
     798:                         }
     799:                     }
     800:                 }
     801:                 foreach ($inputs['product'] as $pitem) {
     802:                     //dd($pitem);
     803:                     $pitem['order_id'] = $order->id;
     804:                     OrderDetail::create($pitem);
     805:                 }
     806:                 //dd("done");
     807:                 //$order->details()->attach($inputs['product']);
----------------------------------------------------------------------------------------------------
     808: 
     809:             } else {
     810:                 if (Setting::findByKey('enable_empty_invoice') == 0) {
     811:                     throw new \Exception('لا يمكنك إضافة الفاتورة بدون منتجات');
     812:                 }
     813:             }
     814:             event(new OrderCreated($order));
     815:             $clientTrans = $order->client->transactions()
     816:                 ->where('record_id', $order->id)
>>   817:                 ->where('transaction_type', $order->invoice_type)
     818:                 ->first();
     819:             if ($clientTrans) {
     820:                 if ($order->due) {
     821:                     $clientTrans->update([
     822:                         'value' => $order->due,
     823:                         'note' => ' فاتورة رقم ' . $order->invoice_number,
     824:                         'transaction_type' => $order->invoice_type,
     825:                         'record_id' => $order->id
     826:                     ]);
     827:                 } else {
     828:                     $clientTrans->delete();
     829:                 }
     830:             } elseif ($order->due) {
     831:                 $order->client
     832:                     ->transactions()
     833:                     ->create([
     834:                         'value' => $order->due,
     835:                         'note' => ' فاتورة رقم ' . $order->invoice_number,
     836:                         'transaction_type' => $order->invoice_type,
     837:                         'record_id' => $order->id
     838:                     ]);
     839:             }
     840:             //if($order->payment_type=='cash'){
     841:             $trans["bank_id"] = $bank->id;
     842:             if ($order->invoice_type == 'sales') {
     843:                 $trans["note"] = " فاتورة مبيعات رقم  " . $order->invoice_number;
     844:             } elseif ($order->invoice_type == 'bookings') {
     845:                 $trans["note"] = " فاتورة رقم  " . $order->invoice_number;
----------------------------------------------------------------------------------------------------
     846:             } else {
     847:                 $trans["note"] = " فاتورة مشتربات رقم  " . $order->invoice_number;
     848:             }
     849:             $trans["record_id"] = $order->id;
     850:             $trans["op_date"] = date('Y-m-d');
     851:             $trans["total"] = $bank->balance;
     852:             $grand = $order->paid;
----------------------------------------------------------------------------------------------------
     853: 
     854: 
     855:             if ($order->invoice_type == 'sales' && $order->paid > 0) {
     856:                 $commision = $order->paid * ($bank->percent / 100);
     857:                 $grand = $order->paid - $commision;
     858:                 $grand = currency($grand, currency()->getUserCurrency(), $bank->currency, $format = false);
     859:                 //$commision = currency($commision,$bank->currency,"SAR", $format = false);
     860:                 /*$expense['note'] = ' خصم عمولة الفاتورة رقم  '.$order->invoice_number;
     861:                 $expense['value'] = $commision;
     862:                 Expense::create($expense);*/
     863:                 $order->is_visa = $bank->type == 1 ? true : false;
     864:                 $order->commision = $commision;
----------------------------------------------------------------------------------------------------
     865:                 $order->commision_egp = currency($commision, currency()->getUserCurrency(), currency()->config('default'), $format = false);
     866:                 $order->save();
     867:                 $trans["due"] = $bank->balance + $grand;
     868:                 $bank->balance += $grand;
     869:                 $trans["type"] = "2";
     870:             } else {
----------------------------------------------------------------------------------------------------
     871:                 $grand = currency($grand, currency()->getUserCurrency(), $bank->currency, $format = false);
     872:                 $trans["due"] = $bank->balance - $grand;
----------------------------------------------------------------------------------------------------
     873:                 $bank->balance -= $grand;
     874:                 $trans["type"] = "1";
     875:             }
     876:             if ($grand > 0) {
     877:                 $trans["value"] = $grand;
     878:                 $bank->save();
     879:                 $order->transaction()->create($trans);
     880:             }
     881:             //BankTransaction::create($trans);
     882:             //}
     883: 
----------------------------------------------------------------------------------------------------
     884:             DB::commit();
     885:             // WhatsApp Invoice PDF (Auto بحسب الإعدادات)
     886:             try {
     887:                 if (
>>   888:                     $order->invoice_type == 'sales' &&
     889:                     Setting::findByKey('whatsapp_enabled', '0') == '1' &&
     890:                     Setting::findByKey('whatsapp_auto_invoice', '0') == '1'
     891:                 ) {
     892:                     $order->load('client', 'items', 'saleMan', 'market');
     893:             
     894:                     $to = optional($order->client)->mobile;
     895:             
     896:                     if (!empty($to)) {
     897:             
     898:                         // نص مرافق للـ PDF (اختياري)
     899:                         $tpl = DB::table('whatsapp_templates')
     900:                             ->where('context', 'invoice')
     901:                             ->where('is_active', 1)
     902:                             ->orderBy('id', 'desc')
     903:                             ->first();
     904:             
     905:                         $text = $tpl ? trim((string)$tpl->body) : null;
     906:             
     907:                         if (!empty($text)) {
     908:                             $text = str_replace(
     909:                                 ['{name}','{invoice_number}','{total}','{paid}','{due}','{date}'],
     910:                                 [
     911:                                     optional($order->client)->name,
     912:                                     $order->invoice_number,
     913:                                     $order->total,
     914:                                     $order->paid,
     915:                                     $order->due,
     916:                                     $order->order_date ?: ($order->invoice_date ?: optional($order->created_at)->format('Y-m-d'))
----------------------------------------------------------------------------------------------------
     917:                                 ],
     918:                                 $text
     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);
     980:                         $mpdf->simpleTables = true;
     981:                         $mpdf->packTableData = true;
     982:                         $mpdf->useSubstitutions = true;
----------------------------------------------------------------------------------------------------
    1049:                     'updated_at'    => now(),
    1050:                 ]);
    1051:             }
    1052:             if ($appointment) {
    1053:                 $appointment->update([
    1054:                     'invoice_order_id' => $order->id,
    1055:                     'status' => Appointment::STATUS_INVOICED,
    1056:                 ]);
    1057:             }
    1058: 
>>  1059:             if ($order->invoice_type == 'sales') {
    1060:                 $this->setOrderProfit($order);
    1061:                 $route = $appointment
    1062:                     ? route('reservations.index', ['date' => optional($appointment->start_at)->toDateString()])
    1063:                     : route('orders.index');
    1064:             } elseif ($order->invoice_type == 'bookings') {
    1065:                 $route = route('reservations.index');
    1066:             } else {
    1067:                 $route = route('purchases.index');
    1068:             }
    1069:             if (
    1070:                 $order->invoice_type === 'sales' &&
    1071:                 Setting::findByKey('zatca_enabled', '0') == '1' &&
    1072:                 Setting::findByKey('zatca_auto_submit', '0') != '1'
    1073:             ) {
    1074:                 session([
    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.
    1110:      *
    1111:      * @param  int  $id
----------------------------------------------------------------------------------------------------
    1112:      * @return \Illuminate\Http\Response
----------------------------------------------------------------------------------------------------
    1156: 
    1157:     /**
    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();
    1205:                 }
    1206:             }
    1207:             $productStore = ProductStore::where('product_id', $order->product_id)
----------------------------------------------------------------------------------------------------
    1208:                 ->where('store_id', $order->store_id)
    1209:                 ->first();
    1210:             $productStore->qty -= $order->itemqty;
    1211:             $productStore->save();
    1212:             $order->details()->detach();
    1213:             if ($order->delete()) {
    1214:                 DB::commit();
    1215:                 return "done";
----------------------------------------------------------------------------------------------------
    1226:     /**
    1227:      * Update the specified resource in storage.
    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'])) {
    1320:                 foreach ($inputs['duepayment']['date'] as $i => $date) {
    1321: 
    1322:                     CalanderPayment::create([
----------------------------------------------------------------------------------------------------
    1323:                         'order_id' => $order->id,
    1324:                         'date' => $date,
    1325:                         'value' => $inputs['duepayment']['value'][$i]
    1326:                     ]);
    1327:                 }
    1328:             }
    1329:             if (!isset($inputs['product'])) {
    1330:                 $order->details()->detach();
    1331:             } else {
    1332:                 $order->details()->detach();
    1333:                 foreach ($inputs['product'] as $key => $value) {
    1334:                     $inputs['product'][$key]['cost_egp'] = currency($value['cost'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
----------------------------------------------------------------------------------------------------
    1335:                     $inputs['product'][$key]['price_egp'] = currency($value['price'], currency()->getUserCurrency(), currency()->config('default'), $format = false);
    1336:                 }
    1337:                 //$order->details()->attach($inputs['product']);
    1338:                 foreach ($inputs['product'] as $pitem) {
    1339:                     $pitem['order_id'] = $order->id;
----------------------------------------------------------------------------------------------------
    1340:                     OrderDetail::create($pitem);
    1341:                 }
    1342:             }
    1343:             event(new OrderCreated($order, $productStores));
    1344: 
    1345:             $clientTrans = $order->client->transactions()
    1346:                 ->where('record_id', $order->id)
>>  1347:                 ->where('transaction_type', $order->invoice_type)
    1348:                 ->first();
    1349:             if ($clientTrans) {
    1350:                 if ($order->due) {
    1351:                     $clientTrans->update([
    1352:                         'value' => $order->due,
    1353:                         'note' => ' فاتورة رقم ' . $order->invoice_number,
    1354:                         'transaction_type' => $order->invoice_type,
    1355:                         'record_id' => $order->id
    1356:                     ]);
    1357:                 } else {
    1358:                     $clientTrans->delete();
    1359:                 }
    1360:             } elseif ($order->due) {
    1361:                 $order->client
    1362:                     ->transactions()
    1363:                     ->create([
    1364:                         'value' => $order->due,
    1365:                         'note' => ' فاتورة رقم ' . $order->invoice_number,
    1366:                         'transaction_type' => $order->invoice_type,
    1367:                         'record_id' => $order->id
    1368:                     ]);
    1369:             }
    1370:             //if(!in_array($order->payment_type,['cash','delayed'])){
    1371:             $trans["bank_id"] = $bank->id;
    1372: 
    1373:             if ($order->invoice_type == 'sales') {
    1374:                 $trans["note"] = " فاتورة مبيعات رقم  " . $order->invoice_number;
    1375:             } else {
----------------------------------------------------------------------------------------------------
    1376:                 $trans["note"] = " فاتورة مشتربات رقم  " . $order->invoice_number;
    1377:             }
    1378:             $trans["record_id"] = $order->id;
    1379:             $trans["op_date"] = $order->invoice_date;
    1380:             $trans["total"] = $bank->balance;
    1381:             $grand = $order->paid;
    1382:             if ($order->invoice_type == 'sales') {
----------------------------------------------------------------------------------------------------
    1383:                 $commision = $order->paid * ($bank->percent / 100);
    1384:                 $grand = $order->paid - $commision;
    1385:                 $grand = currency($grand, currency()->getUserCurrency(), $bank->currency, $format = false);
    1386:                 $order->is_visa = $bank->type == 1 ? true : false;
    1387:                 $order->commision = $commision;
    1388:                 $order->commision_egp = currency($commision, currency()->getUserCurrency(), currency()->config('default'), $format = false);
    1389:                 $order->save();
    1390:                 $trans["due"] = $bank->balance + $grand;
    1391:                 $bank->balance += $grand;
    1392:                 $trans["type"] = "2";
    1393:             } else {
    1394:                 $grand = currency($grand, currency()->getUserCurrency(), $bank->currency, $format = false);
----------------------------------------------------------------------------------------------------
    1395:                 $trans["due"] = $bank->balance - $grand;
    1396:                 $bank->balance -= $grand;
    1397:                 $trans["type"] = "1";
    1398:             }
    1399:             $trans["value"] = $grand;
    1400:             $bank->save();
    1401:             //BankTransaction::create($trans);
----------------------------------------------------------------------------------------------------
    1402:             if ($order->transaction) {
    1403:                 $order->transaction()->update($trans);
    1404:             } else {
    1405:                 $order->transaction()->create($trans);
    1406:             }
    1407:             //}
    1408:             DB::commit();
    1409: 
    1410:             if ($order->invoice_type == 'sales') {
----------------------------------------------------------------------------------------------------
    1411:                 $this->setOrderProfit($order);
    1412:                 $route = route('orders.index');
    1413:             } else {
    1414:                 $route = route('purchases.index');
    1415:             }
    1416:             if ($inputs['savePrint'] == 'print') {
    1417:                 $route = route('orders.getPrint', $order->id);
    1418:                 return redirect($route);
    1419:             }
    1420:             if ($inputs['saveandPrintBarcode'] == 1) {
    1421:                 $route = route('orders.getPrintBarcode', $order->id);
    1422:                 return redirect($route);
    1423:             }
    1424: 
    1425:             $request->session()->flash('alert-success', 'تم تعديل الفاتورة بنجاح');
    1426:             return redirect($route);
    1427:         } catch (\Exception $e) {
    1428:             //\Log::error($e->getMessage());
    1429:             DB::rollback();
    1430:             dd($inputs, $e->getMessage());
    1431:             return back()->withInput($inputs)->with('alert-danger', ' حدث خطأ اثناء تعديل الفاتورة ' . $e->getMessage());
    1432:             //$request->session()->flash('alert-danger', ' حدث خطأ اثناء تعديل الفاتورة '.$e->getMessage());
    1433:             //dd($inputs,$e->getMessage());
    1434:         }
    1435:         return back();
    1436:     }
    1437: 
    1438:     public function rollback($order)
----------------------------------------------------------------------------------------------------
    1439:     {
    1440:         //dd($order->transaction);
    1441:         /*$order->client->transactions()
    1442:             ->where('record_id',$order->id)
>>  1443:             ->where('transaction_type',$order->invoice_type)
    1444:             ->delete();*/
    1445:         /*$expensenote = ' خصم عمولة الفاتورة رقم  '.$order->invoice_number;
    1446:         Expense::where('note',$expensenote)->delete();*/
    1447: 
    1448:         $banktans = $order->transaction; //BankTransaction::where('record_id',$order->id)->first();
    1449:         $order->commision = 0;
    1450:         $order->save();
    1451:         if ($banktans) {
    1452:             if ($banktans->type == 1) {
    1453:                 $banktans->bank->balance += $banktans->getOriginal('value');
    1454:             } else {
    1455:                 $banktans->bank->balance -= $banktans->getOriginal('value');
    1456:             }
    1457:             $banktans->bank->save();
    1458:             //$banktans->delete();
    1459:         }
    1460:         $details = $order->details;
    1461:         $productStores = array();
    1462:         foreach ($details as $item) {
    1463:             if ($item->is_service == 1)
    1464:                 continue;
    1465:             $productStore = ProductStore::where('product_id', $item->id)
    1466:                 ->where('store_id', $item->pivot->store_id)
    1467:                 ->first();
    1468:             $orderQty = $item->pivot->qty;
    1469:             if (empty($productStore)) {
    1470:                 throw new \Exception(" الصنف $item->name غير معرف بالمخزن برجاء تعديل بيانات الصنف ");
    1471:             }
----------------------------------------------------------------------------------------------------
    1507:                             $bounse = $bounse / $a;
    1508:                         }
    1509:                     }
    1510:                 }
    1511:                 $orderQty += $bounse;
    1512:             }
    1513: 
    1514: 
    1515:             if ($order->status == 'delivered') {
    1516: 
>>  1517:                 if ($order->invoice_type == 'sales') {
    1518:                     $productStore->sale_count -= $orderQty;
    1519:                 } else {
    1520:                     $productCost = $item->last_cost;
    1521:                     if (Setting::findByKey('productCost') == 'avg') {
    1522:                         $oldCost = $orderUnit->cost_price;
    1523:                         $oldQty = ($productStore->qty - $productStore->sale_count) ?: 1;
    1524:                         $newQty = $orderQty;
    1525:                         $newCost = $item->pivot->price;
    1526:                         $totalNew = ($newQty * $newCost) / $oldQty;
    1527:                         $revertCost = $oldCost + $totalNew;
    1528:                         $productCost = $orderUnit->cost_price;
    1529:                     }
    1530:                     $orderUnit->cost_price = $productCost;
    1531:                     $orderUnit->save();
    1532: 
    1533:                     $productStore->qty -= $orderQty;
    1534:                     $item->last_cost = $productCost;
    1535:                     $item->avg_cost = round($productCost, 2);
    1536:                     $item->save();
    1537:                 }
    1538:                 $productStore->save();
    1539:                 $productStores[$item->id . $item->pivot->store_id] = $productStore;
    1540:                 //\Log::info($item->id.' '.($productStore->qty-$productStore->sale_count));
    1541: 
    1542:             }
    1543:         }
    1544:         return $productStores;
    1545:     }
----------------------------------------------------------------------------------------------------
    1555:         } catch (\Exception $e) {
    1556:             DB::rollback();
    1557:             return back()->with('alert-danger', 'حطأ! لم تتم العملية بنجاح');
    1558:         }
    1559:     }
    1560: 
    1561:     public function getDetails(Request $req)
    1562:     {
    1563:         $from = $req->fromdate;
    1564:         $to = $req->todate;
>>  1565:         $orders = Order::where('invoice_type', 'sales');
    1566:         if ($from) {
    1567:             $orders->whereRaw("DATE(orders.invoice_date) >= '{$from}'");
    1568:         }
    1569:         if ($to) {
    1570:             $orders->whereRaw("DATE(orders.invoice_date) <= '{$to}'");
    1571:         }
    1572:         $orders = $orders->latest()->get();
    1573:         return view('orders.details', compact('orders'));
    1574:     }
    1575: 
    1576:     public function getWorkOrders(Request $req)
    1577:     {
    1578:         $from = $req->fromdate;
    1579:         $to = $req->todate;
    1580:         $orders = WorkOrder::query()->with('details');
    1581:         if ($from) {
    1582:             $orders->whereRaw("DATE(date) >= '{$from}'");
    1583:         }
    1584:         if ($to) {
    1585:             $orders->whereRaw("DATE(date) <= '{$to}'");
    1586:         }
    1587:         $orders = $orders->latest()->get();
    1588:         return view('orders.workorders_list', compact('orders'));
    1589:     }
    1590: 
    1591:     public function allworkorders(Request $req)
    1592:     {
    1593:         $from = $req->fromdate;
----------------------------------------------------------------------------------------------------
    1642:                 DB::rollback();
    1643:                 //throw new \Exception('خطأ استرجاع الكمية الى المخزن ');
    1644:                 dd($e->getMessage());
    1645:             }
    1646:         }
    1647:         return view('orders.work_order');
    1648:     }
    1649:     public function getSalesDebt()
    1650:     {
    1651:         /*$result = Order::selectRaw('sum(due) as totalDept')
>>  1652:             ->where('invoice_type','sales')
    1653:             ->where('sale_id',request('sale_id'))
    1654:             ->groupBy('sale_id')
    1655:             ->first();*/
    1656:         $persons = Person::join('orders', function ($qry) {
    1657:             $qry->on('persons.id', '=', 'client_id');
    1658:             $qry->whereNotNull('sale_id');
    1659:         })
    1660:             ->where('is_client_supplier', 1)
    1661:             ->selectRaw('persons.*,sale_id')
    1662:             ->groupBy('client_id')
    1663:             ->get();
    1664:         $salesP = [];
    1665:         foreach ($persons as $p) {
    1666:             $salesP[$p->sale_id] = $p->balnce_value;
    1667:         }
    1668:         if (!isset($salesP[request('sale_id')])) {
    1669:             $salesP[request('sale_id')] = 0;
    1670:         }
    1671:         //return $salesP[request('sale_id')];
    1672:         //dd($salesP);
    1673:         $result = Order::selectRaw('employees.id,employees.name,sum(due) as totalDept')
    1674:             ->join("persons", function ($qry) {
    1675:                 $qry->on('persons.id', '=', 'client_id');
    1676:                 $qry->where('is_client_supplier', 0);
    1677:             })
    1678:             ->join("employees", function ($qry) {
    1679:                 $qry->on('employees.id', '=', 'sale_id');
    1680:             })
----------------------------------------------------------------------------------------------------
    1681:             ->addSelect(
    1682:                 \DB::raw(
    1683:                     '(select sum(return_value) from returns
    1684:                     where return_type = "sales" and returns.sale_id=orders.sale_id)
    1685:                      as totalReturn'
    1686:                 )
    1687:             )
>>  1688:             ->where('invoice_type', 'sales')
    1689:             ->where('sale_id', request('sale_id'))
    1690:             ->groupBy('sale_id')
    1691:             ->having('totalDept', '>', 0)
    1692:             ->first();
    1693: 
    1694:         return $result->totalDept - $result->totalReturn;
    1695:     }
    1696: 
    1697:     public function pos(Request $request)
    1698:     {
    1699:         $categories = Category::query()
    1700:             ->with([
    1701:                 'products' => function ($query) {
    1702:                     $query->where('is_sellable', 1);
    1703:                 },
    1704:                 'products.productUnit',
    1705:                 'productsSubCategory' => function ($query) {
    1706:                     $query->where('is_sellable', 1);
    1707:                 },
    1708:                 'productsSubCategory.productUnit',
    1709:                 'productsservices' => function ($query) {
    1710:                     $query->where('is_sellable', 1);
    1711:                 },
    1712:                 'productsservices.productUnit',
    1713:                 'productsservicesSubCategory' => function ($query) {
    1714:                     $query->where('is_sellable', 1);
    1715:                 },
    1716:                 'productsservicesSubCategory.productUnit',
----------------------------------------------------------------------------------------------------
    1744:         $startAt = $appointment->start_at ?: now();
    1745: 
    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: 
    1780:     public function createTurpoShipment($id)
    1781:     {
    1782:         $order = Order::find($id);
----------------------------------------------------------------------------------------------------
    1845:         } else {
    1846:             return view('orders.create_shipment', compact('order'));
    1847:         }
    1848:     }
    1849: 
    1850:     public function submitZatca(Order $order, Request $request, FatooraInvoiceService $zatca)
    1851:     {
    1852:         if (!auth()->user()->can('edit OrdersController')) {
    1853:             abort(403);
    1854:         }
>>  1855:         if ($order->invoice_type !== 'sales') {
    1856:             return back()->with('alert-danger', 'لا يمكن إرسال إلا فواتير المبيعات.');
    1857:         }
    1858:         try {
    1859:             $result = $zatca->submitOrder($order);
    1860:             if (empty($result['success'])) {
    1861:                 return back()->with(
    1862:                     'alert-danger',
    1863:                     $result['message'] ?? 'فشل الإرسال'
    1864:                 );
    1865:             }
    1866: 
    1867:             if (empty($result['strict_pass'])) {
    1868:                 return redirect()
    1869:                     ->route(
    1870:                         'zatca.dashboard',
    1871:                         [
    1872:                             'order' => $order->id,
    1873:                             'filter' => 'all',
    1874:                         ]
    1875:                     )
    1876:                     ->with(
    1877:                         'alert-warning',
    1878:                         $result['message']
    1879:                         ?? 'قُبلت الفاتورة مع ملاحظات، وتوقف الطابور للمراجعة.'
    1880:                     );
    1881:             }
    1882: 
    1883:             // بعد الإرسال انتقل للتالي في الطابور مباشرة
----------------------------------------------------------------------------------------------------
    1918:         $orderId = (int) $request->input('order_id');
    1919: 
    1920:         if (Setting::findByKey('zatca_enabled', '0') != '1') {
    1921:             return response()->json(['success' => false, 'message' => 'ZATCA غير مفعّل']);
    1922:         }
    1923:         if (!$orderId) {
    1924:             return response()->json(['success' => false, 'message' => 'لم يتم تحديد الفاتورة']);
    1925:         }
    1926: 
    1927:         $order = Order::find($orderId);
>>  1928:         if (!$order || $order->invoice_type !== 'sales') {
    1929:             return response()->json(['success' => false, 'message' => 'الفاتورة غير موجودة']);
    1930:         }
    1931:         if ($order->zatca_submitted_at) {
    1932:             return response()->json(['success' => true, 'message' => 'الفاتورة مرسلة بالفعل']);
    1933:         }
    1934: 
    1935:         try {
    1936:             // Check that this order is actually next in the ZATCA sequence
    1937:             $svc  = app(\App\Services\Zatca\FatooraInvoiceService::class);
    1938:             $next = $svc->getNextPendingDocument();
    1939: 
    1940:             if (!$next || $next['type'] !== 'order' || (int) $next['model']->id !== $orderId) {
    1941:                 return response()->json([
    1942:                     'success' => false,
    1943:                     'message' => 'لا يمكن الإرسال — توجد فواتير أو مردودات سابقة لم تُرسل للهيئة بعد',
    1944:                 ]);
    1945:             }
    1946: 
    1947:             \App\Jobs\ProcessNextZatcaInvoiceJob::dispatch($orderId, true);
    1948: 
    1949:             return response()->json(['success' => true, 'message' => 'تم إضافة الفاتورة لطابور الإرسال']);
    1950:         } catch (\Throwable $e) {
    1951:             return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
    1952:         }
    1953:     }
    1954: 
    1955:     public function dismissZatcaAsk()
    1956:     {
----------------------------------------------------------------------------------------------------
    1957:         session()->forget('zatca_pending_order_id');
    1958:         return response()->json(['success' => true]);
    1959:     }
    1960: 
    1961:     public function previewZatca(Order $order)
    1962:     {
>>  1963:         if ($order->invoice_type !== 'sales') {
    1964:             abort(404);
    1965:         }
    1966:         $order->loadMissing(['items.product', 'client']);
    1967:         return view('orders.zatca_preview', compact('order'));
    1968:     }
    1969: 
    1970:     public function downloadZatcaPdfA3(Order $order, ZatcaPdfA3Service $pdfA3)
    1971:     {
    1972:         if ($order->invoice_type !== 'sales') {
    1973:             abort(404);
    1974:         }
    1975:         try {
    1976:             $binary = $pdfA3->buildPdfBinary($order);
    1977:             $safeName = preg_replace('/[^A-Za-z0-9_-]+/', '_', (string) $order->invoice_number);
    1978: 
    1979:             return response($binary, 200, [
    1980:                 'Content-Type' => 'application/pdf',
    1981:                 'Content-Disposition' => 'attachment; filename="ZATCA-PDFA3-' . $safeName . '.pdf"',
    1982:             ]);
    1983:         } catch (\Throwable $e) {
    1984:             return back()->with('alert-danger', $e->getMessage());
    1985:         }
    1986:     }
    1987: }
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------

=== SALES INVOICE PAGE ===

====================================================================================================
CONTEXT_FILE=resources/views/orders/index.blade.php
====================================================================================================
      18: @push('css')
      19: <style>
      20:     .print-report-header { display: none; }
      21:     .print-report-footer { display: none; }
      22: 
>>    23:     /* إخفاء أزرار DataTables القديمة */
      24:     .dt-buttons { display: none !important; }
      25: 
      26:     @media print {
      27:         @page {
      28:             size: A4 landscape !important;
      29:             margin: 8mm !important;
      30:             @top-left { content: none !important; }
      31:             @top-center { content: none !important; }
      32:             @top-right { content: none !important; }
      33:             @bottom-left { content: none !important; }
      34:             @bottom-center { content: none !important; }
      35:             @bottom-right { content: none !important; }
      36:         }
      37: 
----------------------------------------------------------------------------------------------------
      54:         .slimScrollBar, .slimScrollRail { display: none !important; }
      55:         .content-wrapper, .content, .slimScrollDiv { overflow: hidden !important; }
      56: 
      57:         .main-header, .main-sidebar, .main-footer, .content-header,
      58:         .sidebar, .navbar, nav, .hideprint,
>>    59:         .dataTables_filter, .dataTables_length, .dataTables_paginate, .dataTables_info,
      60:         .dt-buttons, .btn-success, .btn-info, .btn-primary, .btn-default, .modal,
      61:         .box-tools, .dataTables_processing, #myModalShipment {
      62:             display: none !important;
      63:         }
      64: 
      65:         .content-wrapper { margin-left: 0 !important; margin-right: 0 !important; padding: 0 !important; background: #fff !important; }
      66:         .content { padding: 0 !important; margin: 0 !important; }
      67:         .box { border: none !important; box-shadow: none !important; margin: 0 !important; }
      68: 
      69:         /* هيدر الطباعة */
      70:         .print-report-header {
      71:             display: table !important;
      72:             width: 100% !important;
      73:             border: 2px solid #1e40af !important;
----------------------------------------------------------------------------------------------------
      74:             padding: 10px 14px !important;
      75:             margin-bottom: 10px !important;
----------------------------------------------------------------------------------------------------
      82:         .print-report-header .prh-title { font-size: 18px !important; font-weight: 700 !important; color: #1e40af !important; margin: 0 !important; }
      83:         .print-report-header .prh-date { font-size: 11px !important; color: #475569 !important; margin-top: 3px !important; }
      84:         .print-report-header .prh-logo { width: 60px !important; height: 60px !important; object-fit: contain !important; }
      85: 
      86:         /* الجدول */
>>    87:         .dataTableList {
      88:             border-collapse: collapse !important;
      89:             width: 100% !important;
      90:             max-width: 100% !important;
      91:             border: 2px solid #1e40af !important;
      92:         }
      93: 
      94:         /* حدود كل صف واضحة عشان لمن ينقطع الجدول بين الصفحات */
      95:         .dataTableList tbody tr td {
      96:             border-top: 1px solid #cbd5e1 !important;
      97:             border-bottom: 1px solid #cbd5e1 !important;
      98:             border-left: 1px solid #cbd5e1 !important;
      99:             border-right: 1px solid #cbd5e1 !important;
     100:         }
     101: 
----------------------------------------------------------------------------------------------------
     102:         .dataTableList tbody tr:first-child td { border-top: 1px solid #cbd5e1 !important; }
     103: 
     104:         /* حدود يمين ويسار الجدول قوية */
     105:         .dataTableList tbody tr td:first-child { border-right: 2px solid #1e40af !important; }
     106:         .dataTableList tbody tr td:nth-last-child(3) { border-left: 2px solid #1e40af !important; }
     107: 
     108:         .dataTableList thead th {
     109:             background: #1e40af !important;
----------------------------------------------------------------------------------------------------
     110:             color: #fff !important;
     111:             font-weight: 700 !important;
     112:             font-size: 12px !important;
     113:             padding: 10px 10px !important;
     114:             text-align: right !important;
     115:             border: 1px solid #1e3a8a !important;
     116:         }
----------------------------------------------------------------------------------------------------
     117: 
     118:         .dataTableList tbody td {
     119:             font-size: 12px !important;
----------------------------------------------------------------------------------------------------
     120:             padding: 8px 10px !important;
----------------------------------------------------------------------------------------------------
     121:             border: 1px solid #cbd5e1 !important;
     122:             font-weight: 600 !important;
----------------------------------------------------------------------------------------------------
     123:             color: #334155 !important;
     124:         }
     125: 
     126:         /* حد الجدول السفلي */
     127:         .box-body { border-bottom: 2px solid #1e40af !important; }
     128: 
     129:         .dataTableList tbody tr:nth-child(even) td { background: #f8fafc !important; }
     130:         .dataTableList tbody tr { page-break-inside: avoid !important; }
     131:         .dataTableList thead { display: table-header-group !important; }
     132: 
----------------------------------------------------------------------------------------------------
     133:         /* عرض الأعمدة في الطباعة */
     134:         .dataTableList th:first-child, .dataTableList td:first-child { width: 50px !important; } /* رقم الفاتورة */
     135:         .dataTableList th:nth-child(3), .dataTableList td:nth-child(3) { min-width: 120px !important; } /* العميل */
     136: 
     137:         /* إخفاء عمود الإجراءات والحالة */
     138:         .dataTableList th:last-child, .dataTableList td:last-child { display: none !important; }
     139:         .dataTableList th:nth-last-child(2), .dataTableList td:nth-last-child(2) { display: none !important; }
     140: 
     141:         /* إخفاء أيقونات الترتيب */
     142:         .table.dataTable thead .sorting:after,
     143:         .table.dataTable thead .sorting_asc:after,
----------------------------------------------------------------------------------------------------
     144:         .table.dataTable thead .sorting_desc:after { display: none !important; }
----------------------------------------------------------------------------------------------------
     145: 
----------------------------------------------------------------------------------------------------
     146:         a { color: #334155 !important; text-decoration: none !important; visibility: visible !important; display: inline !important; }
     147:         a[href]:after { content: none !important; display: none !important; }
     148: 
----------------------------------------------------------------------------------------------------
     149:         .printHeader { display: none !important; }
----------------------------------------------------------------------------------------------------
     150:         .fixedHeader-floating, .fixedHeader-locked { display: none !important; }
     151: 
     152:         /* فوتر الطباعة */
----------------------------------------------------------------------------------------------------
     153:         .print-report-footer {
----------------------------------------------------------------------------------------------------
     154:             display: block !important;
     155:             margin-top: 15px !important;
     156:             padding-top: 10px !important;
----------------------------------------------------------------------------------------------------
     157:             border-top: 2px solid #1e40af !important;
----------------------------------------------------------------------------------------------------
     158:             font-size: 13px !important;
----------------------------------------------------------------------------------------------------
     210:                             </td>
     211:                         </tr>
     212:                     </table>
     213: 
     214:                     <div class="box-body">
>>   215:                         <table class="dataTableList table table-bordered table-striped">
     216:                             <thead>
     217:                                 <tr>
     218:                                     <th>@lang('front.invoicenumber')</th>
     219:                                     <th>@lang('front.date')</th>
     220:                                     @if ($type == 'sales')
     221:                                         <th>@lang('front.client')</th>
     222:                                     @elseif($type == 'bookings')
     223:                                         <th>@lang('front.client')</th>
     224:                                     @else
     225:                                         <th>@lang('front.supplier')</th>
     226:                                     @endif
     227:                                     <th>@lang('front.payment')</th>
     228:                                     <th>@lang('front.total')</th>
     229:                                     <th>@lang('front.discount')</th>
----------------------------------------------------------------------------------------------------
     325:         .tt-suggestion { padding: 3px 20px; line-height: 24px; direction: rtl; }
     326:         .tt-suggestion.tt-cursor, .tt-suggestion:hover { color: #fff; background-color: #0097cf; }
     327:         .tt-suggestion p { margin: 0; }
     328:     </style>
     329: @endpush
>>   330: @push('dataTableJs')
     331:     <script>
     332:         var pageUrl = "{{ $urlRoute }}";
     333:         @if ($type == 'sales')
     334:         var columns = [
     335:             {data: "invoice_number", name: "invoice_number"},
     336:             {data: "invoice_date", name: "invoice_date"},
     337:             {data: "clientname", name: "clientname", orderable: false},
     338:             {data: "payment_type", name: "payment_type", orderable: false, searchable: false},
     339:             {data: "total", name: "total"},
     340:             {data: "dicount_value", name: "dicount_value"},
     341:             {data: "paid", name: "paid"},
     342:             {data: "due", name: "due"},
     343:             {data: "zatca_status", name: "zatca_status", orderable: false, searchable: false},
     344:             {data: "status", name: "status"},
----------------------------------------------------------------------------------------------------
>>   345:             {data: 'actions', name: 'actions', orderable: false, searchable: false}
     346:         ];
     347:         @else
     348:         var columns = [
     349:             {data: "invoice_number", name: "invoice_number"},
     350:             {data: "invoice_date", name: "invoice_date"},
     351:             {data: "clientname", name: "clientname", orderable: false},
     352:             {data: "payment_type", name: "payment_type", orderable: false, searchable: false},
     353:             {data: "total", name: "total"},
     354:             {data: "dicount_value", name: "dicount_value"},
     355:             {data: "paid", name: "paid"},
     356:             {data: "due", name: "due"},
     357:             {data: "status", name: "status"},
     358:             {data: 'actions', name: 'actions', orderable: false, searchable: false}
     359:         ];
----------------------------------------------------------------------------------------------------
     360:         @endif
     361:     </script>
     362: @endpush
     363: @push('js')
     364:     <script>
     365:         $(document).on('click', '.btn-zatca-submit', function () {
     366:             var action = $(this).data('action');
     367:             var token  = $(this).data('token');
     368:             $('#formZatcaOrderSubmit').attr('action', action);
     369:             $('#zatcaToken').val(token);
     370:             $('#modalZatcaOrderSubmit').modal('show');
     371:         });
     372:         $('#btnZatcaConfirm').on('click', function () {
----------------------------------------------------------------------------------------------------
     392:                     window.location = url;
     393:                 });
     394:         });
     395: 
     396:         function printFullReport() {
>>   397:             var dt = $('.dataTableList').DataTable();
     398:             var currentLength = dt.page.len();
     399:             var currentOrder = dt.order();
     400: 
     401:             // عرض كل السجلات
     402:             dt.page.len(-1).draw();
     403: 
     404:             dt.one('draw', function() {
     405:                 setTimeout(function() {
     406:                     var tbody = document.querySelector('.dataTableList tbody');
     407: 
     408:                     // عكس ترتيب الصفوف في الـ DOM (تصاعدي)
     409:                     if (tbody) {
     410:                         var rows = Array.from(tbody.querySelectorAll('tr'));
     411:                         if (rows.length > 1) {
----------------------------------------------------------------------------------------------------
     412:                             var firstNum = parseInt(rows[0].querySelector('td').textContent) || 0;
     413:                             var lastNum = parseInt(rows[rows.length - 1].querySelector('td').textContent) || 0;
     414:                             if (firstNum > lastNum) {
     415:                                 rows.reverse();
     416:                                 rows.forEach(function(row) { tbody.appendChild(row); });
     417:                             }
     418:                         }
     419:                     }
     420: 
----------------------------------------------------------------------------------------------------
     452:                 }, 800);
     453:             });
     454:         }
     455: 
     456:         function exportToExcel(filename) {
>>   457:             var dt = $('.dataTableList').DataTable();
     458:             var currentLength = dt.page.len();
     459:             dt.page.len(-1).draw();
     460:             dt.one('draw', function() {
     461:                 setTimeout(function() {
     462:                     var table = document.querySelector('.dataTableList');
     463:                     var clone = table.cloneNode(true);
     464:                     var rows = clone.querySelectorAll('tr');
     465:                     rows.forEach(function(row) {
     466:                         var cells = row.querySelectorAll('th, td');
     467:                         if (cells.length > 0) {
     468:                             // إزالة عمود الإجراءات
     469:                             cells[cells.length - 1].remove();
     470:                             // إزالة عمود الحالة
     471:                             cells = row.querySelectorAll('th, td');
----------------------------------------------------------------------------------------------------
     472:                             if (cells.length > 0) cells[cells.length - 1].remove();
     473:                         }
     474:                     });
     475:                     var html = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta charset="utf-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>' + filename + '</x:Name><x:WorksheetOptions><x:DisplayRightToLeft/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>' + clone.outerHTML + '</body></html>';
     476:                     var blob = new Blob(['\uFEFF' + html], { type: 'application/vnd.ms-excel;charset=utf-8' });
----------------------------------------------------------------------------------------------------

====================================================================================================
CONTEXT_FILE=resources/views/orders/show.blade.php
====================================================================================================
     218:                                             @endif
     219: 
     220:                                             <td>{{ $item->unit_name }}</td>
     221:                                             <td>
     222:                                                 <span style="font-weight: bold;"> {{ $tqty }} </span>
>>   223:                                                 @if ((int) $item->return_qty)
     224:                                                     <span style="color: red;font-size: 10px;">
     225:                                                         ({{ $item->return_qty }} مرتجع)
     226:                                                     </span>
     227:                                                 @endif
     228:                                             </td>
     229:                                             <td>
     230:                                                 {{ currency($item->price, $order->currency, currency()->getUserCurrency(), $format = false) }}
     231:                                             </td>
     232: 
     233:                                             @if ($order->invoice_type == 'sales' && isset($settings['ShowCustomerPrice']) && $settings['ShowCustomerPrice'] == 1)
     234:                                                 <td>{{ $item->customer_price }}</td>
     235:                                             @endif
     236: 
     237:                                             @if ($settings['use_bounse'] == 1)
----------------------------------------------------------------------------------------------------
     238:                                                 <td>{{ $item->bounse }} {{ $item->bounseUnitText }}</td>
     239:                                             @endif
----------------------------------------------------------------------------------------------------

====================================================================================================
CONTEXT_FILE=resources/views/orders/show_invoice.blade.php
====================================================================================================
FILE_FOUND=NO

=== RETURN-RELATED MIGRATIONS ===

MIGRATION_FILE=database/migrations/2018_12_19_101458_create_returns_table.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateReturnsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('returns', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('client_id')->nullable();
            $table->foreign('client_id')
                ->references('id')
                ->on('persons')
                ->onDelete('set null');
            $table->string('return_type')->comment('sales,purchase');
            $table->boolean('return_value');
            $table->boolean('is_cash');
            $table->date('return_date');
            $table->softDeletes();
            $table->timestamps();
        });
        Schema::create('return_detailes', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('return_id')->nullable();
            $table->foreign('return_id')
                ->references('id')
                ->on('returns')
                ->onDelete('set null');
            $table->unsignedInteger('store_id')->nullable();
            $table->foreign('store_id')
                ->references('id')
                ->on('stores')
                ->onDelete('set null');
            $table->string('store_name');
            $table->unsignedInteger('product_id')->nullable();
            $table->foreign('product_id')
                ->references('id')
                ->on('products')
                ->onDelete('set null');
            $table->unsignedInteger('unit_id')->nullable();
            $table->foreign('unit_id')
                ->references('id')
                ->on('units')
                ->onDelete('set null');
            $table->string('unit_name');
            $table->string('product_name');
            $table->integer('qty');
            $table->double('price');
            $table->double('cost');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('returns');
        Schema::dropIfExists('return_detailes');
    }
}


MIGRATION_FILE=database/migrations/2019_05_16_095041_update_table_orders_add_currency.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UpdateTableOrdersAddCurrency extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->string('currency')->default('SAR')->after('total');
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->string('currency')->default('SAR')->after('return_value');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->dropColumn('currency');
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->dropColumn('currency');
        });
    }
}


MIGRATION_FILE=database/migrations/2019_05_19_103027_update_returns_add_sales.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UpdateReturnsAddSales extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->string('sales_value')->nullable()->default('0')->after('return_value');
            $table->unsignedInteger('sale_id')->nullable();
            $table->foreign('sale_id')
                ->references('id')
                ->on('employees')
                ->onDelete('set null');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->dropForeign('returns_sale_id_foreign');
            $table->dropColumn(['sales_value','sale_id']);
        });
    }
}


MIGRATION_FILE=database/migrations/2019_05_27_132842_update_returns_discount.php
di<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UpdateReturnsDiscount extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->double('discount')->default(0);
            $table->double('discount_type')->default(0);
            $table->double('total')->default(0);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->dropColumn(['discount','discount_type','total']);
        });
    }
}


MIGRATION_FILE=database/migrations/2019_06_21_150407_add_order_detail_transferd_value.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddOrderDetailTransferdValue extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('order_detailes', function (Blueprint $table) {
            $table->double('cost_egp')->default(0);
            $table->double('price_egp')->default(0)->nullable();

        });
        \DB::statement('UPDATE order_detailes SET cost_egp = cost,price_egp=price ');
        Schema::table('return_detailes', function (Blueprint $table) {
            $table->double('cost_egp')->default(0);
            $table->double('price_egp')->default(0);

        });
        \DB::statement('UPDATE return_detailes SET cost_egp = cost,price_egp=price ');

    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('order_detailes', function (Blueprint $table) {
            $table->dropColumn(['cost_egp','price_egp']);
        });
        Schema::table('return_detailes', function (Blueprint $table) {
            $table->dropColumn(['cost_egp','price_egp']);
        });
    }
}


MIGRATION_FILE=database/migrations/2019_07_07_131441_add_sales_egp_returns.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddSalesEgpReturns extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->double('sales_value_egp')->default(0)->after('sales_value');

        });

    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->dropColumn('sales_value_egp');
        });
    }
}


MIGRATION_FILE=database/migrations/2020_04_24_152216_update_employees_manager_id.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UpdateEmployeesManagerId extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('employees', function (Blueprint $table) {
            $table->unsignedInteger('manager_id')->nullable();
            $table->double('target')->nullable();
            $table->foreign('manager_id')
                ->references('id')
                ->on('employees')
                ->onDelete('set null');
        });
        Schema::table('orders', function (Blueprint $table) {
            $table->unsignedInteger('manager_id')->nullable();
            $table->foreign('manager_id')
                ->references('id')
                ->on('employees')
                ->onDelete('set null');
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->unsignedInteger('manager_id')->nullable();
            $table->foreign('manager_id')
                ->references('id')
                ->on('employees')
                ->onDelete('set null');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('employees', function (Blueprint $table) {
            $table->dropForeign('employees_manager_id_foreign');
            $table->dropColumn(['manager_id','target']);
        });
        Schema::table('orders', function (Blueprint $table) {
            $table->dropForeign('orders_manager_id_foreign');
            $table->dropColumn('manager_id');
        });
    }
}


MIGRATION_FILE=database/migrations/2020_07_17_134613_create_order_return.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateOrderReturn extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->double('total_return')->nullable()->default(0);
        });
        Schema::table('order_detailes', function (Blueprint $table) {
            $table->double('return_qty')->nullable()->default(0);
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->unsignedInteger('order_id')->nullable()->default(0);
        });


        $list = \App\Order::where('invoice_type','sales')
            //->whereNotNull('discount')
            ->get();
        if($list){
            foreach ($list as $order){
                $order->profit =  $order->order_profit;
                $order->save();
            }
        }
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->dropColumn('total_return');
        });
        Schema::table('order_detailes', function (Blueprint $table) {
            $table->dropColumn('return_qty');
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->dropColumn('order_id');
        });
    }
}


MIGRATION_FILE=database/migrations/2021_03_20_212420_add_orders_creator.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddOrdersCreator extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->unsignedBigInteger('creator_id')->nullable();
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->unsignedBigInteger('creator_id')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->dropColumn('creator_id');
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->dropColumn('creator_id');
        });
    }
}


MIGRATION_FILE=database/migrations/2021_12_06_113524_add_setting.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddSetting extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        DB::table('settings')->insert([
            [ 'key' => 'show_shipment_company', 'name' =>'Show Shipment Company', 'value'=>'0'],
            [ 'key' => 'show_all_products_returns', 'name' =>'Show All Products In Returns', 'value'=>'0']
        ]);
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        DB::table('settings')->wherein('key',
            [
            'show_shipment_company',
            'show_all_products_returns'
            ]
        )->delete();
    }
}


MIGRATION_FILE=database/migrations/2023_04_05_060350_add_tax_returns.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddTaxReturns extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->double('tax')->nullable()->default(0);
        });
        Schema::table('expenses', function (Blueprint $table) {
            $table->double('tax')->nullable()->default(0);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->dropColumn('tax');
        });
        Schema::table('expenses', function (Blueprint $table) {
            $table->dropColumn('tax');
        });
    }
}


MIGRATION_FILE=database/migrations/2023_05_01_062817_add_tax_value_order_expense_return.php
<?php

use App\Expense;
use App\Order;
use App\ReturnProduct;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddTaxValueOrderExpenseReturn extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('orders', function (Blueprint $table) {
            $table->double('tax_value')->default(0)->after('tax');
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->double('tax_value')->default(0)->after('tax');
        });
        Schema::table('expenses', function (Blueprint $table) {
            $table->double('tax_value')->default(0)->after('tax');
        });
        $orders = Order::where("tax",">",0)->get();
        if($orders){
            foreach($orders as $row){
                $row->tax_value = $row->tax_value_caluclated;
                $row->save();
            }
        }
        $returns = ReturnProduct::where("tax",">",0)->get();
        if($returns){
            foreach($returns as $row){
                $row->tax_value = $row->tax_value_caluclated;
                $row->save();
            }
        }
        $expenses = Expense::where("tax",">",0)->get();
        if($expenses){
            foreach($expenses as $row){
                $row->tax_value = $row->tax_value_caluclated;
                $row->save();
            }
        }
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {

        Schema::table('orders', function (Blueprint $table) {
            $table->dropColumn('tax_value');
        });
        Schema::table('returns', function (Blueprint $table) {
            $table->dropColumn('tax_value');
        });
        Schema::table('expenses', function (Blueprint $table) {
            $table->dropColumn('tax_value');
        });
    }
}


MIGRATION_FILE=database/migrations/2026_05_10_140000_zatca_phase2_returns_and_pdf.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ZatcaPhase2ReturnsAndPdf extends Migration
{
    public function up()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->string('zatca_invoice_uuid', 64)->nullable();
            $table->text('zatca_qr_payload')->nullable();
            $table->longText('zatca_signed_xml')->nullable();
            $table->string('zatca_reporting_status', 64)->nullable();
            $table->string('zatca_validation_status', 64)->nullable();
            $table->string('zatca_invoice_hash', 512)->nullable();
            $table->text('zatca_raw_response')->nullable();
            $table->timestamp('zatca_submitted_at')->nullable();
        });
    }

    public function down()
    {
        Schema::table('returns', function (Blueprint $table) {
            $table->dropColumn([
                'zatca_invoice_uuid',
                'zatca_qr_payload',
                'zatca_signed_xml',
                'zatca_reporting_status',
                'zatca_validation_status',
                'zatca_invoice_hash',
                'zatca_raw_response',
                'zatca_submitted_at',
            ]);
        });
    }
}


MIGRATION_FILE=database/migrations/2026_07_20_130000_enforce_sar_operational_currency.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class EnforceSarOperationalCurrency extends Migration
{
    public function up()
    {
        $now = date('Y-m-d H:i:s');

        if (Schema::hasTable('currencies')) {
            DB::table('currencies')
                ->where('code', '<>', 'SAR')
                ->delete();

            $sarExists = DB::table('currencies')
                ->where('code', 'SAR')
                ->exists();

            if ($sarExists) {
                DB::table('currencies')
                    ->where('code', 'SAR')
                    ->update([
                        'name' => 'ريال سعودي',
                        'symbol' => 'ر.س',
                        'format' => '1,0.00 ر.س',
                        'exchange_rate' => 1,
                        'active' => 1,
                        'updated_at' => $now,
                    ]);
            } else {
                DB::table('currencies')->insert([
                    'name' => 'ريال سعودي',
                    'code' => 'SAR',
                    'symbol' => 'ر.س',
                    'format' => '1,0.00 ر.س',
                    'exchange_rate' => 1,
                    'active' => 1,
                    'created_at' => $now,
                    'updated_at' => $now,
                ]);
            }
        }

        if (Schema::hasTable('banks')) {
            DB::table('banks')->update([
                'currency' => 'SAR',
            ]);
        }

        if (Schema::hasTable('orders')) {
            DB::table('orders')->update([
                'currency' => 'SAR',
            ]);
        }

        if (Schema::hasTable('returns')) {
            DB::table('returns')->update([
                'currency' => 'SAR',
            ]);
        }

        if (Schema::hasTable('settings')) {
            DB::table('settings')
                ->whereRaw(
                    "UPPER(TRIM(CAST(value AS TEXT))) = 'EGP'"
                )
                ->update([
                    'value' => 'SAR',
                ]);
        }
    }

    public function down()
    {
        // No automatic downgrade to EGP.
    }
}


=== DATABASE RETURN STRUCTURE ===

TABLE=orders
TABLE_FOUND=YES
COLUMN=id TYPE=integer NOTNULL=1 DEFAULT=None PK=1
COLUMN=client_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=sale_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=invoice_number TYPE=varchar NOTNULL=1 DEFAULT=None PK=0
COLUMN=invoice_type TYPE=varchar NOTNULL=1 DEFAULT=None PK=0
COLUMN=payment_type TYPE=varchar NOTNULL=1 DEFAULT=None PK=0
COLUMN=total TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=paid TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=due TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=tax TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=discount TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=discount_type TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=note TYPE=text NOTNULL=0 DEFAULT=None PK=0
COLUMN=status TYPE=varchar NOTNULL=1 DEFAULT='1' PK=0
COLUMN=bank_id TYPE=integer NOTNULL=0 DEFAULT='1' PK=0
COLUMN=meta TYPE=text NOTNULL=0 DEFAULT=None PK=0
COLUMN=invoice_date TYPE=date NOTNULL=0 DEFAULT=None PK=0
COLUMN=deleted_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=created_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=updated_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=markter_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=currency TYPE=varchar NOTNULL=1 DEFAULT='EGP' PK=0
COLUMN=commision TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=is_visa TYPE=tinyint(1) NOTNULL=1 DEFAULT='0' PK=0
COLUMN=commision_egp TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=paid_egp TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=is_withdrawable TYPE=tinyint(1) NOTNULL=1 DEFAULT='0' PK=0
COLUMN=manager_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=profit TYPE=float NOTNULL=0 DEFAULT=None PK=0
COLUMN=priceType TYPE=varchar NOTNULL=0 DEFAULT='multi' PK=0
COLUMN=total_return TYPE=float NOTNULL=0 DEFAULT='0' PK=0
COLUMN=auth_code TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=use_point TYPE=tinyint(1) NOTNULL=1 DEFAULT='0' PK=0
COLUMN=discount_value TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=creator_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=supplier_invoice_number TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=tax_value TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=is_shipped TYPE=tinyint(1) NOTNULL=1 DEFAULT='0' PK=0
COLUMN=shipment_amount TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=zatca_invoice_uuid TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_qr_payload TYPE=text NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_signed_xml TYPE=text NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_reporting_status TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_validation_status TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_invoice_hash TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_raw_response TYPE=text NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_submitted_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=shift_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
INDEX=orders_shift_id_index UNIQUE=0
FOREIGN_KEY=sale_id REFERENCES=persons.id
FOREIGN_KEY=client_id REFERENCES=persons.id

TABLE=order_detailes
TABLE_FOUND=YES
COLUMN=id TYPE=integer NOTNULL=1 DEFAULT=None PK=1
COLUMN=order_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=product_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=store_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=store_name TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=unit_name TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=product_name TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=serial_number TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=expiration_date TYPE=date NOTNULL=0 DEFAULT=None PK=0
COLUMN=unit_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=qty TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=cost TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=price TYPE=float NOTNULL=0 DEFAULT=None PK=0
COLUMN=total TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=created_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=updated_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=markter TYPE=float NOTNULL=0 DEFAULT='0' PK=0
COLUMN=cost_egp TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=price_egp TYPE=float NOTNULL=0 DEFAULT='0' PK=0
COLUMN=return_qty TYPE=float NOTNULL=0 DEFAULT='0' PK=0
COLUMN=bounse TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=bounse_unit_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=bounseUnitText TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=is_service TYPE=tinyint(1) NOTNULL=1 DEFAULT='0' PK=0
COLUMN=customer_price TYPE=float NOTNULL=0 DEFAULT=None PK=0
COLUMN=status TYPE=integer NOTNULL=1 DEFAULT='1' PK=0
COLUMN=comment TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=discount1 TYPE=float NOTNULL=0 DEFAULT=None PK=0
COLUMN=discount2 TYPE=float NOTNULL=0 DEFAULT=None PK=0
COLUMN=serive_datetime TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=employee_id TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=employee_name TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
INDEX=order_detailes_employee_id_index UNIQUE=0
INDEX=order_detailes_created_at_index UNIQUE=0
FOREIGN_KEY=unit_id REFERENCES=units.id
FOREIGN_KEY=store_id REFERENCES=stores.id
FOREIGN_KEY=product_id REFERENCES=products.id
FOREIGN_KEY=order_id REFERENCES=orders.id

TABLE=returns
TABLE_FOUND=YES
COLUMN=id TYPE=integer NOTNULL=1 DEFAULT=None PK=1
COLUMN=client_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=return_type TYPE=varchar NOTNULL=1 DEFAULT=None PK=0
COLUMN=return_value TYPE=tinyint(1) NOTNULL=1 DEFAULT=None PK=0
COLUMN=is_cash TYPE=tinyint(1) NOTNULL=1 DEFAULT=None PK=0
COLUMN=return_date TYPE=date NOTNULL=1 DEFAULT=None PK=0
COLUMN=deleted_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=created_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=updated_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=currency TYPE=varchar NOTNULL=1 DEFAULT='EGP' PK=0
COLUMN=sales_value TYPE=varchar NOTNULL=0 DEFAULT='0' PK=0
COLUMN=sale_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=discount TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=discount_type TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=total TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=sales_value_egp TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=manager_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=order_id TYPE=integer NOTNULL=0 DEFAULT='0' PK=0
COLUMN=creator_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=tax TYPE=float NOTNULL=0 DEFAULT='0' PK=0
COLUMN=tax_value TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=zatca_invoice_uuid TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_qr_payload TYPE=text NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_signed_xml TYPE=text NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_reporting_status TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_validation_status TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_invoice_hash TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_raw_response TYPE=text NOTNULL=0 DEFAULT=None PK=0
COLUMN=zatca_submitted_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
FOREIGN_KEY=client_id REFERENCES=persons.id

TABLE=return_detailes
TABLE_FOUND=YES
COLUMN=id TYPE=integer NOTNULL=1 DEFAULT=None PK=1
COLUMN=return_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=store_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=store_name TYPE=varchar NOTNULL=1 DEFAULT=None PK=0
COLUMN=product_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=unit_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=unit_name TYPE=varchar NOTNULL=1 DEFAULT=None PK=0
COLUMN=product_name TYPE=varchar NOTNULL=1 DEFAULT=None PK=0
COLUMN=qty TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=price TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=cost TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=created_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=updated_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=cost_egp TYPE=float NOTNULL=1 DEFAULT='0' PK=0
COLUMN=price_egp TYPE=float NOTNULL=1 DEFAULT='0' PK=0
FOREIGN_KEY=unit_id REFERENCES=units.id
FOREIGN_KEY=product_id REFERENCES=products.id
FOREIGN_KEY=store_id REFERENCES=stores.id
FOREIGN_KEY=return_id REFERENCES=returns.id

TABLE=product_store
TABLE_FOUND=YES
COLUMN=id TYPE=integer NOTNULL=1 DEFAULT=None PK=1
COLUMN=product_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=store_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=unit_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=qty TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=sale_count TYPE=integer NOTNULL=1 DEFAULT='0' PK=0
COLUMN=created_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=updated_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
FOREIGN_KEY=unit_id REFERENCES=units.id
FOREIGN_KEY=store_id REFERENCES=stores.id
FOREIGN_KEY=product_id REFERENCES=products.id

TABLE=transactions
TABLE_FOUND=YES
COLUMN=id TYPE=integer NOTNULL=1 DEFAULT=None PK=1
COLUMN=model_type TYPE=varchar NOTNULL=1 DEFAULT=None PK=0
COLUMN=model_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=value TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=note TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=record_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=created_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=updated_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=transaction_type TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=deleted_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=sale_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=is_effective_invoices TYPE=tinyint(1) NOTNULL=1 DEFAULT='0' PK=0
COLUMN=creator_id TYPE=integer NOTNULL=0 DEFAULT='1' PK=0
INDEX=transactions_model_type_model_id_index UNIQUE=0

TABLE=bank_transactions
TABLE_FOUND=YES
COLUMN=id TYPE=integer NOTNULL=1 DEFAULT=None PK=1
COLUMN=bank_id TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=op_date TYPE=date NOTNULL=1 DEFAULT=None PK=0
COLUMN=value TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=total TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=due TYPE=float NOTNULL=1 DEFAULT=None PK=0
COLUMN=type TYPE=integer NOTNULL=1 DEFAULT=None PK=0
COLUMN=record_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=note TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=created_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=updated_at TYPE=datetime NOTNULL=0 DEFAULT=None PK=0
COLUMN=transactionable_id TYPE=integer NOTNULL=0 DEFAULT=None PK=0
COLUMN=transactionable_type TYPE=varchar NOTNULL=0 DEFAULT=None PK=0
COLUMN=creator_id TYPE=integer NOTNULL=0 DEFAULT='1' PK=0
FOREIGN_KEY=bank_id REFERENCES=banks.id

=== CURRENT RETURN DATA ===
id=4 | order_id=341 | return_type=sales | return_value=10 | sales_value=10 | discount=0.0 | discount_type=1.0 | total=10.0 | tax=15.0 | tax_value=0.0 | is_cash=1 | currency=SAR | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 19:44:39 | detail_count=1

=== RECENT SALES INVOICES ===
id=358 | invoice_number=358 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=75.0 | paid=75.0 | due=0.0 | discount=30.0 | discount_type=1.0 | discount_value=30.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 21:06:15 | line_count=2 | returned_line_count=0 | returned_qty_total=0.0
id=357 | invoice_number=357 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=46.9 | paid=46.9 | due=0.0 | discount=33.0 | discount_type=2.0 | discount_value=15.477 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 21:06:11 | line_count=3 | returned_line_count=0 | returned_qty_total=0.0
id=356 | invoice_number=356 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=40.0 | paid=40.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 21:06:08 | line_count=2 | returned_line_count=0 | returned_qty_total=0.0
id=355 | invoice_number=355 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=105.08 | paid=105.08 | due=0.0 | discount=26.0 | discount_type=2.0 | discount_value=26.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 21:04:20 | line_count=3 | returned_line_count=0 | returned_qty_total=0.0
id=354 | invoice_number=354 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=190.0 | paid=190.0 | due=0.0 | discount=33.0 | discount_type=1.0 | discount_value=33.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 21:04:17 | line_count=3 | returned_line_count=0 | returned_qty_total=0.0
id=353 | invoice_number=353 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=11.0 | paid=11.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 21:04:13 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0
id=352 | invoice_number=352 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=126.0 | paid=126.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 21:04:10 | line_count=4 | returned_line_count=0 | returned_qty_total=0.0
id=351 | invoice_number=351 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=123.0 | paid=123.0 | due=0.0 | discount=10.0 | discount_type=1.0 | discount_value=10.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 21:04:07 | line_count=3 | returned_line_count=0 | returned_qty_total=0.0
id=350 | invoice_number=350 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=41.0 | paid=41.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=WARNING | zatca_submitted_at=2026-07-20 20:52:43 | line_count=2 | returned_line_count=0 | returned_qty_total=0.0
id=349 | invoice_number=349 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=41.0 | paid=41.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 20:52:39 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0
id=348 | invoice_number=348 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=30.0 | paid=30.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 20:52:36 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0
id=347 | invoice_number=347 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=15.0 | paid=15.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 20:52:33 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0
id=346 | invoice_number=346 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=30.0 | paid=30.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=WARNING | zatca_submitted_at=2026-07-20 20:18:55 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0
id=345 | invoice_number=345 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=15.0 | paid=15.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 20:18:52 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0
id=344 | invoice_number=344 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=11.0 | paid=11.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=multi | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 19:58:58 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0
id=343 | invoice_number=343 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=127.55 | paid=127.55 | due=0.0 | discount=7.5 | discount_type=2.0 | discount_value=9.56625 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 19:41:49 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0
id=342 | invoice_number=342 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=13 | total=55.0 | paid=55.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=REPORTED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 19:41:46 | line_count=2 | returned_line_count=0 | returned_qty_total=0.0
id=341 | invoice_number=341 | invoice_type=sales | payment_type=visa | bank_id=2 | client_id=1 | total=10.0 | paid=10.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=10.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 19:19:27 | line_count=1 | returned_line_count=1 | returned_qty_total=1.0
id=340 | invoice_number=340 | invoice_type=sales | payment_type=cash | bank_id=1 | client_id=1 | total=15.0 | paid=15.0 | due=0.0 | discount=0.0 | discount_type=1.0 | discount_value=0.0 | tax=15.0 | tax_value=0.0 | total_return=0.0 | shift_id=1 | priceType=one | creator_id=4 | zatca_reporting_status=CLEARED | zatca_validation_status=PASS | zatca_submitted_at=2026-07-20 19:19:24 | line_count=1 | returned_line_count=0 | returned_qty_total=0.0

=== RECENT SALES INVOICE LINES ===
id=33 | order_id=358 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=2 | return_qty=0.0 | price=15.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=34 | order_id=358 | product_id=4 | product_name=سشوار شعر | store_id=1 | unit_id=1 | qty=3 | return_qty=0.0 | price=25.0 | total=75.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=30 | order_id=357 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=15.0 | total=15.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=31 | order_id=357 | product_id=4 | product_name=سشوار شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=25.0 | total=25.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=32 | order_id=357 | product_id=5 | product_name=تصفيف شعر و دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=30.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=28 | order_id=356 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=15.0 | total=15.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=29 | order_id=356 | product_id=4 | product_name=سشوار شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=25.0 | total=25.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=25 | order_id=355 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=2 | return_qty=0.0 | price=15.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=26 | order_id=355 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=2 | return_qty=0.0 | price=11.0 | total=22.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=27 | order_id=355 | product_id=5 | product_name=تصفيف شعر و دقن | store_id=1 | unit_id=1 | qty=3 | return_qty=0.0 | price=30.0 | total=90.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=22 | order_id=354 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=3 | return_qty=0.0 | price=11.0 | total=33.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=23 | order_id=354 | product_id=5 | product_name=تصفيف شعر و دقن | store_id=1 | unit_id=1 | qty=4 | return_qty=0.0 | price=30.0 | total=120.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=24 | order_id=354 | product_id=18 | product_name=صبغة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=70.0 | total=70.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=21 | order_id=353 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=11.0 | total=11.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=17 | order_id=352 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=15.0 | total=15.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=18 | order_id=352 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=11.0 | total=11.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=19 | order_id=352 | product_id=5 | product_name=تصفيف شعر و دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=30.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=20 | order_id=352 | product_id=18 | product_name=صبغة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=70.0 | total=70.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=14 | order_id=351 | product_id=18 | product_name=صبغة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=70.0 | total=70.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=15 | order_id=351 | product_id=5 | product_name=تصفيف شعر و دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=30.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=16 | order_id=351 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=3 | return_qty=0.0 | price=11.0 | total=33.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=12 | order_id=350 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=11.0 | total=11.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=2
id=13 | order_id=350 | product_id=5 | product_name=تصفيف شعر و دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=30.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=2
id=11 | order_id=349 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=11.0 | total=11.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=10 | order_id=348 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=2 | return_qty=0.0 | price=15.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=9 | order_id=347 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=15.0 | total=15.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=8 | order_id=346 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=2 | return_qty=0.0 | price=15.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=7 | order_id=345 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=15.0 | total=15.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=6 | order_id=344 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=11.0 | total=11.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=5 | order_id=343 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=137.89 | total=137.89 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=3 | order_id=342 | product_id=4 | product_name=سشوار شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=25.0 | total=25.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=4 | order_id=342 | product_id=5 | product_name=تصفيف شعر و دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=30.0 | total=30.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=2 | order_id=341 | product_id=3 | product_name=حلاقة دقن | store_id=1 | unit_id=1 | qty=1 | return_qty=1.0 | price=10.0 | total=10.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1
id=1 | order_id=340 | product_id=1 | product_name=حلاقة شعر | store_id=1 | unit_id=1 | qty=1 | return_qty=0.0 | price=15.0 | total=15.0 | cost=0.0 | discount1=None | discount2=None | is_service=1 | employee_id=1

=== DATA SAFETY CHECKS ===
UNLINKED_ACTIVE_SALES_RETURNS=0
DUPLICATE_RETURNED_ORDER_IDS=0
OVER_RETURNED_LINES=0
PARTIALLY_RETURNED_ORDERS=0
FULLY_RETURNED_ORDERS=1

=== DATABASE SAFETY ===
DATABASE_INTEGRITY=ok
FOREIGN_KEY_ERRORS=0
DATABASE_WRITE_PERFORMED=NO
ZATCA_REQUEST_SENT=NO