관리-도구
편집 파일: ProvidersController.php
<?php namespace App\Http\Controllers; use App\Models\Provider; use App\Models\Setting; use App\utils\helpers; use Carbon\Carbon; use App\Models\Account; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; use App\Imports\ProviderImport; use Maatwebsite\Excel\Facades\Excel; use App\Models\Purchase; use App\Models\PaymentMethod; use App\Models\PaymentPurchase; use App\Models\PurchaseReturn; use App\Models\PaymentPurchaseReturns; use Illuminate\Support\Facades\Auth; use DB; use Illuminate\Http\Request; class ProvidersController extends BaseController { //----------- Get ALL Suppliers-------\\ public function index(request $request) { $this->authorizeForUser($request->user('api'), 'view', Provider::class); // How many items do you want to display. $perPage = $request->limit; $pageStart = \Request::get('page', 1); // Start displaying items from this number; $offSet = ($pageStart * $perPage) - $perPage; $order = $request->SortField; $dir = $request->SortType; $helpers = new helpers(); // Filter fields With Params to retrieve $columns = array(0 => 'name', 1 => 'code', 2 => 'phone', 3 => 'email'); $param = array(0 => 'like', 1 => 'like', 2 => 'like', 3 => 'like'); $data = array(); $providers = Provider::where('deleted_at', '=', null); //Multiple Filter $Filtred = $helpers->filter($providers, $columns, $param, $request) // Search With Multiple Param ->where(function ($query) use ($request) { return $query->when($request->filled('search'), function ($query) use ($request) { return $query->where('name', 'LIKE', "%{$request->search}%") ->orWhere('code', 'LIKE', "%{$request->search}%") ->orWhere('phone', 'LIKE', "%{$request->search}%") ->orWhere('email', 'LIKE', "%{$request->search}%"); }); }); $totalRows = $Filtred->count(); if($perPage == "-1"){ $perPage = $totalRows; } $providers = $Filtred->offset($offSet) ->limit($perPage) ->orderBy($order, $dir) ->get(); foreach ($providers as $provider) { $item['total_amount'] = DB::table('purchases') ->where('deleted_at', '=', null) ->where('statut', 'received') ->where('provider_id', $provider->id) ->sum('GrandTotal'); $item['total_paid'] = DB::table('purchases') ->where('deleted_at', '=', null) ->where('statut', 'received') ->where('provider_id', $provider->id) ->sum('paid_amount'); $item['due'] = $item['total_amount'] - $item['total_paid']; $item['total_amount_return'] = DB::table('purchase_returns') ->where('deleted_at', '=', null) ->where('provider_id', $provider->id) ->sum('GrandTotal'); $item['total_paid_return'] = DB::table('purchase_returns') ->where('deleted_at', '=', null) ->where('provider_id', $provider->id) ->sum('paid_amount'); $item['return_Due'] = $item['total_amount_return'] - $item['total_paid_return']; $item['id'] = $provider->id; $item['name'] = $provider->name; $item['phone'] = $provider->phone; $item['tax_number'] = $provider->tax_number; $item['code'] = $provider->code; $item['email'] = $provider->email; $item['country'] = $provider->country; $item['city'] = $provider->city; $item['adresse'] = $provider->adresse; $data[] = $item; } $company_info = Setting::where('deleted_at', '=', null)->first(); $accounts = Account::where('deleted_at', '=', null)->orderBy('id', 'desc')->get(['id','account_name']); $payment_methods = PaymentMethod::whereNull('deleted_at')->get(['id', 'name']); return response()->json([ 'providers' => $data, 'company_info' => $company_info, 'totalRows' => $totalRows, 'accounts' => $accounts, 'payment_methods' => $payment_methods, ]); } //----------- Store new Supplier -------\\ public function store(Request $request) { $this->authorizeForUser($request->user('api'), 'create', Provider::class); request()->validate([ 'name' => 'required', ]); Provider::create([ 'name' => $request['name'], 'code' => $this->getNumberOrder(), 'adresse' => $request['adresse'], 'phone' => $request['phone'], 'email' => $request['email'], 'country' => $request['country'], 'city' => $request['city'], 'tax_number' => $request['tax_number'], ]); return response()->json(['success' => true]); } //------------ function show -----------\\ public function show($id){ // } //----------- Update Supplier-------\\ public function update(Request $request, $id) { $this->authorizeForUser($request->user('api'), 'update', Provider::class); request()->validate([ 'name' => 'required', ]); Provider::whereId($id)->update([ 'name' => $request['name'], 'adresse' => $request['adresse'], 'phone' => $request['phone'], 'email' => $request['email'], 'country' => $request['country'], 'city' => $request['city'], 'tax_number' => $request['tax_number'], ]); return response()->json(['success' => true]); } //----------- Remdeleteove Provider-------\\ public function destroy(Request $request, $id) { $this->authorizeForUser($request->user('api'), 'delete', Provider::class); Provider::whereId($id)->update([ 'deleted_at' => Carbon::now(), ]); return response()->json(['success' => true]); } //-------------- Delete by selection ---------------\\ public function delete_by_selection(Request $request) { $this->authorizeForUser($request->user('api'), 'delete', Provider::class); $selectedIds = $request->selectedIds; foreach ($selectedIds as $Provider_id) { Provider::whereId($Provider_id)->update([ 'deleted_at' => Carbon::now(), ]); } return response()->json(['success' => true]); } //----------- get Number Order Of Suppliers-------\\ public function getNumberOrder() { $last = DB::table('providers')->latest('id')->first(); if ($last) { $code = $last->code + 1; } else { $code = 1; } return $code; } public function import(Request $request) { $this->authorizeForUser($request->user('api'), 'Suppliers_import', Provider::class); // 1) File-level validation $v = Validator::make($request->all(), [ 'suppliers' => 'required|file|mimes:xls,xlsx|max:20480', // 20MB ]); if ($v->fails()) { return response()->json([ 'status' => false, // intentionally omit "message" to avoid leaking "Validation failed" 'errors' => $v->errors()->all(), ], 422); } $rows = Excel::toArray([], $request->file('suppliers')); $sheet = $rows[0] ?? []; if (empty($sheet)) { return response()->json([ 'status' => false, 'errors' => ['No data found in the uploaded file.'], ], 422); } // Header detection $first = $sheet[0] ?? []; $assocInput = is_array($first) && count(array_filter(array_keys($first), 'is_string')) > 0; $normalized = []; if ($assocInput) { foreach ($sheet as $r) $normalized[] = $this->normalizeAssocRowSupplier($r); $lineBase = 1; // header already applied in source } else { $header = array_map(function ($h) { return $this->normalizeKeySupplier((string) $h); }, $first); for ($i = 1; $i < count($sheet); $i++) { $row = $sheet[$i]; $assoc = []; foreach ($header as $idx => $key) $assoc[$key] = $row[$idx] ?? null; $normalized[] = $this->normalizeAssocRowSupplier($assoc); } $lineBase = 2; // data start line if first row was header labels } $errors = []; $prepared = []; $codesInFile = []; foreach ($normalized as $i => $row) { $line = $i + $lineBase; $name = isset($row['name']) ? trim((string)$row['name']) : ''; $codeRaw = array_key_exists('code', $row) ? $row['code'] : null; $email = isset($row['email']) ? trim((string)$row['email']) : ''; $phone = isset($row['phone']) ? trim((string)$row['phone']) : ''; $country = isset($row['country']) ? trim((string)$row['country']) : ''; $city = isset($row['city']) ? trim((string)$row['city']) : ''; $adresse = isset($row['adresse']) ? trim((string)$row['adresse']) : ''; $tax_number = isset($row['tax_number']) ? trim((string)$row['tax_number']) : ''; if ($name === '') { $errors[] = "Row {$line}: name is required."; } // code must be integer $code = null; if ($codeRaw === null || $codeRaw === '') { $errors[] = "Row {$line}: code is required and must be an integer."; } else if (is_numeric($codeRaw) && intval($codeRaw) == $codeRaw) { $code = intval($codeRaw); } else { $errors[] = "Row {$line}: code '{$codeRaw}' is not a valid integer."; } if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors[] = "Row {$line}: email '{$email}' is not valid."; } // in-file duplicate codes if ($code !== null) { if (isset($codesInFile[$code])) { $errors[] = "Row {$line}: duplicate code '{$code}' found in the file (also on row {$codesInFile[$code]})."; } else { $codesInFile[$code] = $line; } } $prepared[] = [ 'name' => $name, 'code' => $code, 'email' => $email ?: null, 'phone' => $phone ?: null, 'country' => $country ?: null, 'city' => $city ?: null, 'adresse' => $adresse ?: null, 'tax_number' => $tax_number ?: null, ]; } // DB duplicate codes $codes = array_values(array_filter(array_map(function ($r) { return $r['code']; }, $prepared), function ($v) { return $v !== null; })); if (!empty($codes)) { $dupes = Provider::whereNull('deleted_at')->whereIn('code', $codes)->pluck('code')->all(); foreach ($dupes as $dup) $errors[] = "code '{$dup}' already exists in the system."; } if (!empty($errors)) { return response()->json([ 'status' => false, 'errors' => $errors, // ONLY errors[] ], 422); } // Insert suppliers $now = now(); $insertRows = []; foreach ($prepared as $r) { $insertRows[] = [ 'name' => $r['name'], 'code' => $r['code'], 'email' => $r['email'], 'phone' => $r['phone'], 'country' => $r['country'], 'city' => $r['city'], 'adresse' => $r['adresse'], 'tax_number' => $r['tax_number'], 'created_at' => $now, 'updated_at' => $now, ]; } DB::transaction(function () use ($insertRows) { foreach (array_chunk($insertRows, 1000) as $chunk) { Provider::insert($chunk); } }); return response()->json([ 'status' => true, 'imported' => count($insertRows), // optionally: 'warnings' => [...] ]); } // --- helpers (private methods in the same controller) --- private function normalizeAssocRowSupplier(array $row): array { $out = []; foreach ($row as $k => $v) { $key = $this->normalizeKeySupplier((string)$k); $out[$this->resolveSupplierSynonym($key)] = $v; } return $out; } private function normalizeKeySupplier(string $key): string { $key = trim(mb_strtolower($key)); return preg_replace('/[.\s\-]+/u', '_', $key); } private function resolveSupplierSynonym(string $key): string { $map = [ 'supplier' => 'name', 'vendor' => 'name', 'supplier_name' => 'name', 'vendor_name' => 'name', 'supplier_code' => 'code', 'vendor_code' => 'code', 'address' => 'adresse', 'addr' => 'adresse', 'tax' => 'tax_number', 'taxno' => 'tax_number', 'tax_no' => 'tax_number', 'vat' => 'tax_number', ]; return isset($map[$key]) ? $map[$key] : $key; } //------------- pay_supplier_due -------------\\ public function pay_supplier_due(Request $request) { $this->authorizeForUser($request->user('api'), 'pay_supplier_due', Provider::class); if($request['amount'] > 0){ $provider_purchases_due = Purchase::where('deleted_at', '=', null) ->where('statut', 'received') ->where([ ['payment_statut', '!=', 'paid'], ['provider_id', $request->provider_id] ])->get(); $paid_amount_total = $request->amount; foreach($provider_purchases_due as $key => $provider_purchase){ if($paid_amount_total == 0) break; $due = $provider_purchase->GrandTotal - $provider_purchase->paid_amount; if($paid_amount_total >= $due){ $amount = $due; $payment_status = 'paid'; }else{ $amount = $paid_amount_total; $payment_status = 'partial'; } $payment_purchase = new PaymentPurchase(); $payment_purchase->purchase_id = $provider_purchase->id; $payment_purchase->account_id = $request['account_id']?$request['account_id']:NULL; $payment_purchase->Ref = app('App\Http\Controllers\PaymentPurchasesController')->getNumberOrder(); $payment_purchase->date = Carbon::now(); $payment_purchase->payment_method_id = $request['payment_method_id']; $payment_purchase->montant = $amount; $payment_purchase->change = 0; $payment_purchase->notes = $request['notes']; $payment_purchase->user_id = Auth::user()->id; $payment_purchase->save(); $account = Account::where('id', $request['account_id'])->exists(); if ($account) { // Account exists, perform the update $account = Account::find($request['account_id']); $account->update([ 'balance' => $account->balance - $amount, ]); } $provider_purchase->paid_amount += $amount; $provider_purchase->payment_statut = $payment_status; $provider_purchase->save(); $paid_amount_total -= $amount; } } return response()->json(['success' => true]); } //------------- pay_purchase_return_due -------------\\ public function pay_purchase_return_due(Request $request) { $this->authorizeForUser($request->user('api'), 'pay_purchase_return_due', Provider::class); if($request['amount'] > 0){ $supplier_purchase_return_due = PurchaseReturn::where('deleted_at', '=', null) ->where([ ['payment_statut', '!=', 'paid'], ['provider_id', $request->provider_id] ])->get(); $paid_amount_total = $request->amount; foreach($supplier_purchase_return_due as $key => $supplier_purchase_return){ if($paid_amount_total == 0) break; $due = $supplier_purchase_return->GrandTotal - $supplier_purchase_return->paid_amount; if($paid_amount_total >= $due){ $amount = $due; $payment_status = 'paid'; }else{ $amount = $paid_amount_total; $payment_status = 'partial'; } $payment_purchase_return = new PaymentPurchaseReturns(); $payment_purchase_return->purchase_return_id = $supplier_purchase_return->id; $payment_purchase_return->account_id = $request['account_id']?$request['account_id']:NULL; $payment_purchase_return->Ref = app('App\Http\Controllers\PaymentPurchaseReturnsController')->getNumberOrder(); $payment_purchase_return->date = Carbon::now(); $payment_purchase_return->payment_method_id = $request['payment_method_id']; $payment_purchase_return->montant = $amount; $payment_purchase_return->change = 0; $payment_purchase_return->notes = $request['notes']; $payment_purchase_return->user_id = Auth::user()->id; $payment_purchase_return->save(); $account = Account::where('id', $request['account_id'])->exists(); if ($account) { // Account exists, perform the update $account = Account::find($request['account_id']); $account->update([ 'balance' => $account->balance + $amount, ]); } $supplier_purchase_return->paid_amount += $amount; $supplier_purchase_return->payment_statut = $payment_status; $supplier_purchase_return->save(); $paid_amount_total -= $amount; } } return response()->json(['success' => true]); } }