Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
30.10% |
59 / 196 |
|
22.22% |
4 / 18 |
CRAP | |
0.00% |
0 / 1 |
| SaleController | |
30.10% |
59 / 196 |
|
22.22% |
4 / 18 |
478.59 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| posPrint | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
| index | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
1 | |||
| create | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
12 | |||
| store | |
74.36% |
29 / 39 |
|
0.00% |
0 / 1 |
11.69 | |||
| show | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| edit | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| update | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| addSale | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 | |||
| DeleteSale | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
| saleCartItemUpdate | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| saleCartItemDelete | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| saleCartItemEdit | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
2 | |||
| destroy | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| saleBackPage | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
2 | |||
| salePageCustomer | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| salePageShow | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
| addSaleCard | |
0.00% |
0 / 38 |
|
0.00% |
0 / 1 |
30 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace App\Http\Controllers\admin; |
| 4 | |
| 5 | use App\Enums\OrderStatus; |
| 6 | use App\Http\Controllers\Controller; |
| 7 | use App\Models\admin\Customer; |
| 8 | use App\Models\admin\Product; |
| 9 | use App\Models\admin\PurchaseDetails; |
| 10 | use App\Models\admin\Stock; |
| 11 | use App\Models\Brand; |
| 12 | use App\Models\Category; |
| 13 | use App\Models\Color; |
| 14 | use App\Models\Order; |
| 15 | use App\Models\Origin; |
| 16 | use App\Models\Payment; |
| 17 | use App\Models\PaymentType; |
| 18 | use App\Models\SaleCard; |
| 19 | use App\Models\Size; |
| 20 | use App\Repository\SaleCardRepository; |
| 21 | use App\Service\OrderService; |
| 22 | use App\Service\StockService; |
| 23 | use App\Services\Location\BranchContext; |
| 24 | use App\Services\Stock\InventoryService; |
| 25 | use Illuminate\Http\Request; |
| 26 | use Illuminate\Support\Facades\DB; |
| 27 | use Illuminate\Support\Facades\Log; |
| 28 | use Illuminate\Validation\Rule; |
| 29 | use Illuminate\Validation\ValidationException; |
| 30 | use Response; |
| 31 | |
| 32 | class SaleController extends Controller |
| 33 | { |
| 34 | protected $sale_repository; |
| 35 | |
| 36 | public function __construct(SaleCardRepository $saleRepository) |
| 37 | { |
| 38 | $this->sale_repository = $saleRepository; |
| 39 | } |
| 40 | |
| 41 | public function posPrint($id) |
| 42 | { |
| 43 | app(BranchContext::class)->scope(Order::query())->findOrFail($id); |
| 44 | $data['details'] = OrderService::getDetails($id); |
| 45 | $data['order'] = app(BranchContext::class)->scope(Order::query())->with('payment')->findOrFail($id); |
| 46 | |
| 47 | return view('admin.sales.print')->with($data); |
| 48 | // $html = view('admin.sales.print')->with($data)->render(); |
| 49 | // return response()->json(['html'=>$html]); |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | * Display a listing of the resource. |
| 54 | * |
| 55 | * @return \Illuminate\Http\Response |
| 56 | */ |
| 57 | public function index() |
| 58 | { |
| 59 | $orders = app(BranchContext::class)->scope(Order::query()) |
| 60 | ->with(['customer', 'payment', 'details.stock.product', 'details.stock.brand', 'details.stock.color', 'details.stock.size']) |
| 61 | ->latest(); |
| 62 | $branchOrders = app(BranchContext::class)->scope(Order::query()); |
| 63 | |
| 64 | // Summary Statistics for the redesign |
| 65 | $today = now()->startOfDay(); |
| 66 | $thisMonth = now()->startOfMonth(); |
| 67 | |
| 68 | // These three used to load every order (ever, unbounded) into PHP just to |
| 69 | // add up a couple of columns — fine at a handful of orders, not fine once |
| 70 | // the table has years of history. Same math, done as aggregate SQL instead. |
| 71 | $data['stat_today_sales'] = (clone $branchOrders)->where('created_at', '>=', $today) |
| 72 | ->selectRaw('COALESCE(SUM(total + shipping_cost), 0) as total')->value('total'); |
| 73 | $data['stat_month_sales'] = (clone $branchOrders)->where('created_at', '>=', $thisMonth) |
| 74 | ->selectRaw('COALESCE(SUM(total + shipping_cost), 0) as total')->value('total'); |
| 75 | |
| 76 | $paidPerOrder = DB::table('payments')->select('order_id', DB::raw('SUM(paid) as paid'))->groupBy('order_id'); |
| 77 | $data['stat_total_due'] = (clone $branchOrders) |
| 78 | ->leftJoinSub($paidPerOrder, 'paid_per_order', 'paid_per_order.order_id', '=', 'orders.id') |
| 79 | ->selectRaw('COALESCE(SUM(GREATEST(orders.total + orders.shipping_cost - COALESCE(paid_per_order.paid, 0), 0)), 0) as due') |
| 80 | ->value('due'); |
| 81 | |
| 82 | $data['stat_total_orders'] = $orders->count(); |
| 83 | |
| 84 | $data['data'] = $orders->paginate(15); |
| 85 | |
| 86 | return view('admin.sales.sale_list')->with($data); |
| 87 | } |
| 88 | |
| 89 | /** |
| 90 | * Show the form for creating a new resource. |
| 91 | * |
| 92 | * @return \Illuminate\Http\Response |
| 93 | */ |
| 94 | public function create(Request $request) |
| 95 | { |
| 96 | // $data['customers'] = Customer::query()->orderByDesc('id')->pluck('name', 'id'); |
| 97 | $data['customers'] = Customer::getAll(); |
| 98 | $data['colors'] = Color::query()->pluck('name', 'id'); |
| 99 | $data['sizes'] = Size::query()->pluck('name', 'id'); |
| 100 | $data['origins'] = Origin::query()->pluck('name', 'id'); |
| 101 | $data['categories'] = Category::query()->pluck('name', 'id'); |
| 102 | $data['brands'] = Brand::query()->pluck('name', 'id'); |
| 103 | |
| 104 | // BUG FIX (self-healing): products created/edited before the |
| 105 | // StockService::syncStockForProduct fix (or ones whose sync step got |
| 106 | // skipped for any reason) would stay permanently invisible in the POS |
| 107 | // unless someone remembered to run `php artisan pos:sync-stock` by |
| 108 | // hand. Instead of depending on that, just re-sync every product's |
| 109 | // Stock row right here, every time the POS page loads. syncStockForProduct |
| 110 | // is idempotent (create-if-missing / update-if-exists, never deletes), |
| 111 | // so this is safe to run on every page load and guarantees "all |
| 112 | // products with stock show up in the POS" without any manual step. |
| 113 | Product::with('variations')->get()->each(function ($product) { |
| 114 | StockService::syncStockForProduct($product); |
| 115 | }); |
| 116 | |
| 117 | // BUG FIX: was plain `Stock::query()->with('product')->get()` — a Stock |
| 118 | // row whose product had since been deleted (e.g. via the `import:products` |
| 119 | // command, which wipes/reimports `products` but never touched `stocks`) |
| 120 | // would still show up here with $stock->product == null, rendering as |
| 121 | // "Unnamed product" in the POS. whereHas('product') filters those out. |
| 122 | // BUG FIX: eager-loading `product.variations.attributeValues.attribute` |
| 123 | // too so the POS blade can derive a real variant label (e.g. "Size: 39 |
| 124 | // · Color: Black") from a Stock row's `VAR-{id}` sync marker — before |
| 125 | // this, the variant picker modal just showed "Standard" for every row |
| 126 | // because Stock.color_id/size_id are never populated for variants |
| 127 | // created through the current product form (they're a legacy pattern). |
| 128 | $data['stocks'] = Stock::query() |
| 129 | ->with(['product.variations.attributeValues.attribute']) |
| 130 | ->whereHas('product') |
| 131 | ->get()->unique('id'); |
| 132 | $data['paymentTypes'] = PaymentType::query()->pluck('name', 'id'); |
| 133 | $data['warehouses'] = feature('multi_warehouse') ? app(BranchContext::class)->warehouses()->active()->orderByDesc('is_default')->pluck('name', 'id') : collect(); |
| 134 | |
| 135 | // Lets the "+ Add customer" flow (see CustomerController::store) come |
| 136 | // back here with the just-created customer preselected, instead of |
| 137 | // bouncing through the dead legacy `admin.sale.back` page (which |
| 138 | // doesn't pass a `stocks` variable at all and would crash this view). |
| 139 | if ($request->filled('customer')) { |
| 140 | $data['customer'] = Customer::query()->find($request->query('customer')); |
| 141 | } |
| 142 | |
| 143 | return view('admin.sales.create')->with($data); |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Store a newly created resource in storage. |
| 148 | * |
| 149 | * @return \Illuminate\Http\Response |
| 150 | */ |
| 151 | public function store(Request $request) |
| 152 | { |
| 153 | if (! $request->has('customer_id') || $request->input('customer_id') === null) { |
| 154 | $request->merge(['customer_id' => 0]); |
| 155 | } |
| 156 | $request->validate([ |
| 157 | 'customer_id' => 'required|integer', |
| 158 | 'paid' => 'required|numeric|min:0', |
| 159 | 'status' => ['required', Rule::in(['Pending', 'Confirmed', 'Processing', 'Shipped', 'Delivered'])], |
| 160 | 'stock_id' => 'required|array|min:1', |
| 161 | 'stock_id.*' => 'required|integer|exists:stocks,id', |
| 162 | 'qty' => 'required|array|min:1', |
| 163 | 'qty.*' => 'required|integer|min:1', |
| 164 | 'deliver_date' => 'nullable|date', |
| 165 | 'payment_type_id' => 'required|exists:payment_types,id', |
| 166 | 'shipping_cost' => 'nullable|numeric|min:0', |
| 167 | 'note' => 'nullable|string', |
| 168 | 'order_date' => 'nullable|date', |
| 169 | 'warehouse_id' => feature('multi_warehouse') ? 'required|exists:warehouses,id' : 'nullable', |
| 170 | ]); |
| 171 | try { |
| 172 | DB::beginTransaction(); |
| 173 | app(BranchContext::class)->ensureWarehouse($request->integer('warehouse_id') ?: null); |
| 174 | if (isset($request->customer_id)) { |
| 175 | $customer = $request->customer_id; |
| 176 | $order = OrderService::posStoreOrder($customer); |
| 177 | $payment = OrderService::posPaymentStore($order); |
| 178 | |
| 179 | // FIX: this used to build $data from the request (status, note, |
| 180 | // deliver_date) and then never actually apply it — the order kept |
| 181 | // whatever the DB default was (status='Pending') no matter what |
| 182 | // the cashier picked on the form, and note/deliver_date had no |
| 183 | // columns to be saved into at all (added in the accompanying |
| 184 | // migration). Now the cashier's choices are genuinely persisted. |
| 185 | $order->update([ |
| 186 | 'status' => in_array($request->status, OrderStatus::values(), true) ? $request->status : OrderStatus::Pending->value, |
| 187 | 'note' => $request->note, |
| 188 | 'deliver_date' => $request->deliver_date, |
| 189 | ]); |
| 190 | |
| 191 | DB::commit(); |
| 192 | |
| 193 | return redirect()->route('admin.order.details', $order->id)->with('success', 'Sale created successfully.'); |
| 194 | } |
| 195 | } catch (\Throwable $e) { |
| 196 | DB::rollBack(); |
| 197 | |
| 198 | Log::error('Sale store failed: ' . $e->getMessage(), ['exception' => $e]); |
| 199 | |
| 200 | // FIX: this used to show the same generic "something went wrong" for |
| 201 | // every failure, including deliberate business-rule rejections (e.g. |
| 202 | // OrderService::posStoreOrder now throws a RuntimeException with the |
| 203 | // exact product/quantity when stock runs short) — the cashier had no |
| 204 | // way to know WHICH item was the problem. Surface that message |
| 205 | // verbatim; keep the generic message for genuine unexpected errors |
| 206 | // (DB failures, etc.) so those never leak internals to the user. |
| 207 | $message = $e instanceof ValidationException |
| 208 | ? collect($e->errors())->flatten()->first() |
| 209 | : ($e instanceof \RuntimeException |
| 210 | ? $e->getMessage() |
| 211 | : 'Something went wrong while creating the sale. Please try again.'); |
| 212 | |
| 213 | return redirect()->back()->withInput()->with('error', $message); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * Display the specified resource. |
| 219 | * |
| 220 | * @param int $id |
| 221 | * @return \Illuminate\Http\Response |
| 222 | */ |
| 223 | public function show($id) |
| 224 | { |
| 225 | // |
| 226 | } |
| 227 | |
| 228 | /** |
| 229 | * Show the form for editing the specified resource. |
| 230 | * |
| 231 | * @param int $id |
| 232 | * @return \Illuminate\Http\Response |
| 233 | */ |
| 234 | public function edit($id) |
| 235 | { |
| 236 | // |
| 237 | } |
| 238 | |
| 239 | /** |
| 240 | * Update the specified resource in storage. |
| 241 | * |
| 242 | * @param int $id |
| 243 | * @return \Illuminate\Http\Response |
| 244 | */ |
| 245 | public function update(Request $request, $id) |
| 246 | { |
| 247 | // |
| 248 | } |
| 249 | |
| 250 | public function addSale(Request $req) |
| 251 | { |
| 252 | |
| 253 | /**For product price, when select a product from select option then return this product price*/ |
| 254 | if ($req->select_product) { |
| 255 | $price = $this->sale_repository->PruductQuery($req->p_query); |
| 256 | // $stockGroup = $this->sale_repository->stockGroup($req->p_query); |
| 257 | $brand = $this->sale_repository->brandCheck($req->p_query); |
| 258 | $color = $this->sale_repository->colorCheck($req->p_query); |
| 259 | $size = $this->sale_repository->sizeCheck($req->p_query); |
| 260 | $totalStock = Stock::query()->where('product_id', $req->p_query)->get(); |
| 261 | $stock = $totalStock->sum('stock_in') - $totalStock->sum('stock_out'); |
| 262 | |
| 263 | return response()->json(['price' => $price, 'brand' => $brand, 'color' => $color, 'size' => $size, 'stock' => $stock]); |
| 264 | } |
| 265 | |
| 266 | /** |
| 267 | * for Customer Details , when a customer select from drop down select option then return those customer details |
| 268 | * Customer old data or previews data collecte from SaleCard and previews total |
| 269 | * this section work when customer name select, |
| 270 | */ |
| 271 | if ($req->customers) { |
| 272 | |
| 273 | $totalPrice = SaleCard::query()->where('customer_id', $req->customers)->sum('total_price'); |
| 274 | $previews = $this->sale_repository->customer_previews_sale_card($req->customers); |
| 275 | $customer_details = $this->sale_repository->customer_details($req->customers); |
| 276 | |
| 277 | return response()->json(['success' => $previews, 'customer' => $customer_details, 'total' => $totalPrice]); |
| 278 | } |
| 279 | |
| 280 | /* |
| 281 | * this seciton created for save temposery customer product data in SaleCard |
| 282 | * when find product_id and customer_id then this section work successfully |
| 283 | */ |
| 284 | |
| 285 | if ($req->customer_id) { |
| 286 | /* |
| 287 | * when found duplicate product in sale card |
| 288 | * then alert a message product already added in sale card |
| 289 | */ |
| 290 | |
| 291 | // if (SaleCard::query() |
| 292 | // ->where('product_id', $req->product_id) |
| 293 | // ->where('customer_id', $req->customer_id) |
| 294 | // ->where('size_id',$req->size_id) |
| 295 | // ->where('color_id',$req->color_id) |
| 296 | // ->where('brand_id',$req->brand_id) |
| 297 | // ->exists() |
| 298 | // ) |
| 299 | // { |
| 300 | // $qty = SaleCard::query()->update(['qty'=>$req->qty]); |
| 301 | // return response()->json(['qty' => ]); |
| 302 | // } |
| 303 | |
| 304 | /*if product not found in database |
| 305 | *Model SaleCard then product add to SaleCard |
| 306 | */ |
| 307 | $save_data = $this->sale_repository->save_product_saleCard($req->all()); |
| 308 | |
| 309 | /* |
| 310 | * load recent store data in blade file, |
| 311 | */ |
| 312 | $recent = SaleCard::query()->where('id', $save_data->id)->with(['customer', 'product'])->first(); |
| 313 | $html_data = $this->sale_repository->load_recent_add_product($recent); |
| 314 | $totalPrice = SaleCard::query()->where('customer_id', $recent->customer_id)->sum('total_price'); |
| 315 | |
| 316 | return response()->json(['success' => $html_data, 'total' => $totalPrice]); |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | public function DeleteSale(Request $request) |
| 321 | { |
| 322 | $order = app(BranchContext::class)->scope(Order::query())->with('details.stock')->findOrFail($request->id); |
| 323 | |
| 324 | DB::transaction(function () use ($order) { |
| 325 | // Put the sold quantity back — deleting a sale used to just drop the |
| 326 | // order + cascade its line items, leaving the stock_out increment |
| 327 | // from sale time permanently overstating consumed stock. |
| 328 | app(InventoryService::class)->restoreOrder($order); |
| 329 | |
| 330 | Payment::where('order_id', $order->id)->delete(); |
| 331 | $order->delete(); |
| 332 | }); |
| 333 | |
| 334 | return response()->json(['success' => 'Order deleted successfully', 'grand_total' => 0]); |
| 335 | } |
| 336 | |
| 337 | public function saleCartItemUpdate(Request $request) |
| 338 | { |
| 339 | $data = $request->only(['product_id', 'brand_id', 'color_id', 'size_id', 'qty']); |
| 340 | $update = SaleCard::query()->findOrFail($request->cart_id)->update($data); |
| 341 | session()->put('customer', $request->customer_id); |
| 342 | |
| 343 | return redirect()->route('admin.sale.back'); |
| 344 | |
| 345 | } |
| 346 | |
| 347 | public function saleCartItemDelete(Request $request) |
| 348 | { |
| 349 | $cart = SaleCard::query()->where('id', $request->id)->delete(); |
| 350 | session()->put('customer', $request->customer_id); |
| 351 | session()->flash('success', 'Cart item successfully deleted'); |
| 352 | |
| 353 | return response()->json(['success', 'Cart item successfully deleted']); |
| 354 | } |
| 355 | |
| 356 | /** |
| 357 | * Remove the specified resource from storage. |
| 358 | * |
| 359 | * @param int $id |
| 360 | * @return \Illuminate\Http\Response |
| 361 | */ |
| 362 | public function saleCartItemEdit(Request $request) |
| 363 | { |
| 364 | $product = SaleCard::query()->findOrFail($request->id); |
| 365 | $id = $product->product_id; |
| 366 | $data['item'] = Product::query()->findOrFail($id); |
| 367 | $product = PurchaseDetails::query()->where('product_id', $id)->first(); |
| 368 | $data['products'] = PurchaseDetails::query()->with(['product'])->get(); |
| 369 | $data['cart'] = SaleCard::query()->findOrFail($request->id); |
| 370 | $data['price'] = $product->selling_price; |
| 371 | $data['brand'] = Stock::query()->where('product_id', $id)->with(['brand'])->get()->unique('brand_id'); |
| 372 | $data['color'] = Stock::query()->where('product_id', $id)->with(['color'])->get()->unique('color_id'); |
| 373 | $data['size'] = Stock::query()->where('product_id', $id)->with(['size'])->get()->unique('size_id'); |
| 374 | $data['totalStock'] = Stock::query()->where('product_id', $id)->get(); |
| 375 | $data['stock'] = $data['totalStock']->sum('stock_in') - $data['totalStock']->sum('stock_out'); |
| 376 | $data['customer'] = Customer::query()->findOrFail($request->customer_id); |
| 377 | $editForm = view('admin.sales.sale-edit-form')->with($data)->render(); |
| 378 | |
| 379 | return response()->json(['form' => $editForm]); |
| 380 | } |
| 381 | |
| 382 | public function destroy($id) |
| 383 | { |
| 384 | // |
| 385 | } |
| 386 | |
| 387 | public function saleBackPage() |
| 388 | { |
| 389 | $id = session()->get('customer'); |
| 390 | $data['totalPrice'] = SaleCard::query()->where('customer_id', $id)->sum('total_price'); |
| 391 | $data['customer'] = Customer::query()->where('id', $id)->first(); |
| 392 | // $data['customers'] = Customer::query()->orderByDesc('id')->pluck('name', 'id'); |
| 393 | $data['customers'] = Customer::getAll(); |
| 394 | $data['colors'] = Color::query()->pluck('name', 'id'); |
| 395 | $data['sizes'] = Size::query()->pluck('name', 'id'); |
| 396 | $data['origins'] = Origin::query()->pluck('name', 'id'); |
| 397 | $data['categories'] = Category::query()->pluck('name', 'id'); |
| 398 | $data['brands'] = Brand::query()->pluck('name', 'id'); |
| 399 | $data['purchases'] = PurchaseDetails::query()->with('product')->get(); |
| 400 | $data['paymentTypes'] = PaymentType::query()->pluck('name', 'id'); |
| 401 | $data['products'] = SaleCard::query()->where('customer_id', $id)->get(); |
| 402 | |
| 403 | return view('admin.sales.create')->with($data); |
| 404 | } |
| 405 | |
| 406 | public function salePageCustomer(Request $request) |
| 407 | { |
| 408 | $customer = Customer::query()->create($request->all()); |
| 409 | |
| 410 | return redirect()->route('admin.sale.page', $customer->id); |
| 411 | } |
| 412 | |
| 413 | public function salePageShow($id) |
| 414 | { |
| 415 | $data['customers'] = Customer::query()->pluck('name', 'id'); |
| 416 | $data['colors'] = Color::query()->pluck('name', 'id'); |
| 417 | $data['sizes'] = Size::query()->pluck('name', 'id'); |
| 418 | $data['origins'] = Origin::query()->pluck('name', 'id'); |
| 419 | $data['categories'] = Category::query()->pluck('name', 'id'); |
| 420 | $data['brands'] = Brand::query()->pluck('name', 'id'); |
| 421 | $data['purchases'] = PurchaseDetails::query()->with('product')->get(); |
| 422 | $data['paymentTypes'] = PaymentType::query()->pluck('name', 'id'); |
| 423 | $data['customer'] = Customer::query()->findOrFail($id); |
| 424 | |
| 425 | return view('admin.sales.create')->with($data); |
| 426 | } |
| 427 | |
| 428 | public function addSaleCard(Request $request) |
| 429 | { |
| 430 | $data = $request->validate([ |
| 431 | 'customer_id' => 'required', |
| 432 | 'product_id' => 'required', |
| 433 | 'brand_id' => 'required', |
| 434 | 'size_id' => 'required', |
| 435 | 'color_id' => 'required', |
| 436 | ]); |
| 437 | try { |
| 438 | DB::beginTransaction(); |
| 439 | |
| 440 | if ($request->qty <= 0) { |
| 441 | return redirect()->back()->with('failed', 'Please Enter quantity less then one'); |
| 442 | } |
| 443 | |
| 444 | $saleCheck = SaleCard::query() |
| 445 | ->where('product_id', $request->product_id) |
| 446 | ->where('customer_id', $request->customer_id) |
| 447 | ->where('color_id', $request->color_id) |
| 448 | ->where('brand_id', $request->brand_id) |
| 449 | ->where('size_id', $request->size_id) |
| 450 | ->first(); |
| 451 | |
| 452 | if ($saleCheck != null && $saleCheck->exists() == true) { |
| 453 | $data['save_data'] = $saleCheck->update(['qty' => $request->qty + $saleCheck->qty]); |
| 454 | } else { |
| 455 | $data['save_data'] = $this->sale_repository->save_product_saleCard($request->all()); |
| 456 | } |
| 457 | $data['totalPrice'] = SaleCard::query()->where('customer_id', $request->customer_id)->sum('total_price'); |
| 458 | $data['customer'] = Customer::query()->where('id', $request->customer_id)->first(); |
| 459 | // $data['customers'] = Customer::query()->orderByDesc('id')->pluck('name', 'id'); |
| 460 | $data['customers'] = Customer::getAll(); |
| 461 | $data['colors'] = Color::query()->pluck('name', 'id'); |
| 462 | $data['sizes'] = Size::query()->pluck('name', 'id'); |
| 463 | $data['origins'] = Origin::query()->pluck('name', 'id'); |
| 464 | $data['categories'] = Category::query()->pluck('name', 'id'); |
| 465 | $data['brands'] = Brand::query()->pluck('name', 'id'); |
| 466 | $data['purchases'] = PurchaseDetails::query()->with('product')->get(); |
| 467 | $data['paymentTypes'] = PaymentType::query()->pluck('name', 'id'); |
| 468 | $data['products'] = SaleCard::query()->where('customer_id', $request->customer_id)->get(); |
| 469 | |
| 470 | DB::commit(); |
| 471 | session()->put('customer', $request->customer_id); |
| 472 | |
| 473 | return redirect()->route('admin.sale.back'); |
| 474 | // return view('admin.sales.create')->with($data); |
| 475 | |
| 476 | } catch (\Throwable $e) { |
| 477 | DB::rollBack(); |
| 478 | Log::error('Sale card add failed: ' . $e->getMessage(), ['exception' => $e]); |
| 479 | |
| 480 | return redirect()->back()->withInput()->with('error', 'Something went wrong while adding the item. Please try again.'); |
| 481 | } |
| 482 | } |
| 483 | } |