Files
kulakpos_web/Modules/Business/App/Http/Controllers/CartController.php
eko54r 05fd3230b8
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 5m14s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 17s
Build, Push and Deploy / deploy-staging (push) Successful in 41s
Build, Push and Deploy / deploy-production (push) Has been skipped
update marketing
2026-05-14 11:55:22 +07:00

356 lines
14 KiB
PHP

<?php
namespace Modules\Business\App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Stock;
use Gloudemans\Shoppingcart\Exceptions\InvalidRowIDException;
use Gloudemans\Shoppingcart\Facades\Cart;
use Illuminate\Http\Request;
class CartController extends Controller
{
public function index()
{
$cart_contents = Cart::content()->filter(fn($item) => $item->options->type == 'sale');
$stockIds = $cart_contents->pluck('options.stock_id')->filter()->unique();
$batchNos = Stock::whereIn('id', $stockIds)->pluck('batch_no', 'id');
foreach ($cart_contents as $cartItem) {
$stockId = $cartItem->options->stock_id ?? null;
if ($stockId && isset($batchNos[$stockId])) {
$newOptions = $cartItem->options->merge([
'batch_no' => $batchNos[$stockId],
]);
Cart::update($cartItem->rowId, [
'qty' => $cartItem->qty,
'options' => $newOptions,
]);
}
}
$modules = product_setting()->modules ?? [];
return view('business::sales.cart-list', compact('cart_contents', 'modules'));
}
public function store(Request $request)
{
$this->validate($request, [
'stock_id' => 'nullable|exists:stocks,id',
'warehouse_id' => 'nullable|exists:warehouses,id',
'type' => 'nullable|string|in:sale,purchase',
'id' => 'required|integer',
'name' => 'nullable|string',
'quantity' => 'required|numeric',
'price' => 'required|numeric',
'product_code' => 'nullable|string',
'product_unit_id' => 'nullable|integer',
'product_unit_name' => 'nullable|string',
'product_image' => 'nullable|string',
'profit_percent' => 'nullable|numeric',
'sales_price' => 'nullable|numeric',
'whole_sale_price' => 'nullable|numeric',
'dealer_price' => 'nullable|numeric',
'expire_date' => 'nullable|date',
'product_type' => 'nullable|in:single,variant,combo',
'variant_name' => 'nullable|string',
'serial_numbers' => 'nullable|array',
'serial_numbers.*' => 'string',
'has_serial' => 'nullable|boolean',
'price_without_tax' => 'required_without:serial_numbers|numeric|nullable',
'customer_type' => 'nullable|string'
]);
$incomingSerials = $request->serial_numbers ?? [];
// Serial Mode
if (!empty($incomingSerials)) {
// Sale
if ($request->type === 'sale') {
$stocks = Stock::where('business_id', auth()->user()->business_id)
->where('product_id', $request->id)
->where(function ($query) use ($incomingSerials) {
foreach ($incomingSerials as $serial) {
$query->orWhereJsonContains('serial_numbers', $serial);
}
})->get();
// Map serial → stock
$serialStockMap = [];
foreach ($stocks as $stock) {
foreach ($incomingSerials as $serial) {
if (in_array($serial, $stock->serial_numbers ?? [])) {
$serialStockMap[$stock->id][] = $serial;
}
}
}
// Add or merge cart per stock
foreach ($serialStockMap as $stockId => $serialsForStock) {
$resolvedStock = $stocks->firstWhere('id', $stockId);
$qty = count($serialsForStock);
$customerType = $request->customer_type ?? 'Retailer';
// Determine price based on customer type
$price = round($resolvedStock->productSalePrice ?? 0, 2);
if ($customerType === 'Dealer') {
$price = round($resolvedStock->productDealerPrice ?? 0, 2);
} elseif ($customerType === 'Wholesaler') {
$price = round($resolvedStock->productWholeSalePrice ?? 0, 2);
}
$existingCartItem = Cart::search(function ($item) use ($request, $stockId) {
return $item->id == $request->id &&
$item->options->type === 'sale' &&
$item->options->stock_id == $stockId;
})->first();
if ($existingCartItem) {
$existingSerials = $existingCartItem->options->serial_numbers ?? [];
// Remove already existing serials from incoming
$newSerials = array_diff($serialsForStock, $existingSerials);
$duplicates = array_intersect($existingSerials, $newSerials);
if (!empty($duplicates)) {
return response()->json([
'success' => false,
'message' => 'Serial already exists in cart',
'duplicates' => array_values($duplicates),
], 422);
}
$mergedSerials = array_values(array_unique(
array_merge($existingSerials, $serialsForStock)
));
Cart::update($existingCartItem->rowId, [
'qty' => count($mergedSerials),
'options' => $existingCartItem->options->merge([
'serial_numbers' => $mergedSerials,
]),
]);
} else {
Cart::add([
'id' => $request->id,
'name' => $request->name,
'qty' => $qty,
'price' => $price,
'options' => [
'type' => 'sale',
'product_code' => $request->product_code,
'product_unit_id' => $request->product_unit_id,
'product_unit_name' => $request->product_unit_name,
'product_image' => $request->product_image,
'product_type' => $request->product_type,
'variant_name' => $request->variant_name,
'stock_id' => $resolvedStock->id,
'warehouse_id' => $resolvedStock->warehouse_id,
'sales_price' => $resolvedStock->productSalePrice,
'whole_sale_price' => $resolvedStock->productWholeSalePrice,
'dealer_price' => $resolvedStock->productDealerPrice,
'serial_numbers' => $serialsForStock,
'has_serial' => $request->has_serial ?? 1,
'price_without_tax' => $resolvedStock->price_without_tax,
]
]);
}
}
}
// Purchase
else {
Cart::add([
'id' => $request->id,
'name' => $request->name,
'qty' => count($incomingSerials),
'price' => round($request->price, 2),
'options' => [
'type' => 'purchase',
'product_code' => $request->product_code,
'product_unit_id' => $request->product_unit_id,
'product_unit_name' => $request->product_unit_name,
'product_image' => $request->product_image,
'product_type' => $request->product_type,
'variant_name' => $request->variant_name,
'stock_id' => null,
'warehouse_id' => $request->warehouse_id,
'serial_numbers' => $incomingSerials,
'batch_no' => $request->batch_no,
'expire_date' => $request->expire_date,
'purchase_price' => $request->purchase_price,
'profit_percent' => $request->profit_percent,
'sales_price' => $request->sales_price,
'whole_sale_price' => $request->whole_sale_price,
'dealer_price' => $request->dealer_price,
'has_serial' => $request->has_serial ?? 1,
'price_without_tax' => $request->price_without_tax,
]
]);
}
return response()->json([
'success' => true,
'message' => 'Serial product added successfully.'
]);
}
// Normal product ( without serial)
$existingCartItem = Cart::search(function ($item) use ($request) {
return $item->id == $request->id &&
$item->options->type == $request->type;
})->first();
if ($existingCartItem) {
Cart::update($existingCartItem->rowId, [
'qty' => $existingCartItem->qty + $request->quantity
]);
} else {
Cart::add([
'id' => $request->id,
'name' => $request->name,
'qty' => $request->quantity,
'price' => round($request->price, 2),
'options' => [
'type' => $request->type,
'product_code' => $request->product_code,
'product_unit_id' => $request->product_unit_id,
'product_unit_name' => $request->product_unit_name,
'product_image' => $request->product_image,
'product_type' => $request->product_type,
'variant_name' => $request->variant_name,
'stock_id' => $request->stock_id,
'batch_no' => $request->batch_no,
'expire_date' => $request->expire_date,
'purchase_price' => $request->purchase_price,
'profit_percent' => $request->profit_percent,
'sales_price' => $request->sales_price,
'whole_sale_price' => $request->whole_sale_price,
'dealer_price' => $request->dealer_price,
'warehouse_id' => $request->warehouse_id,
'has_serial' => $request->has_serial ?? 0,
'price_without_tax' => $request->price_without_tax,
]
]);
}
return response()->json([
'success' => true,
'message' => 'Item added to cart successfully.'
]);
}
public function update(Request $request, $id)
{
$cart = Cart::get($id);
if (!$cart) {
return response()->json([
'success' => false,
'message' => __('Item not found in cart')
]);
}
$qty = $request->qty ?? $cart->qty;
if ($qty < 0) {
return response()->json([
'success' => false,
'message' => __('Enter a valid quantity')
]);
}
// incoming serial
$incomingSerials = $request->serial_numbers ?? null;
if (is_array($incomingSerials)) {
$existingSerials = $incomingSerials;
} else {
$existingSerials = $cart->options->serial_numbers ?? [];
}
// normalize to array
if (!is_array($existingSerials)) {
$existingSerials = !empty($existingSerials) ? [$existingSerials] : [];
}
$hasSerial = $cart->options->has_serial ?? 0;
if ($hasSerial) {
$qty = count($existingSerials);
}
Cart::update($id, [
'qty' => $qty,
'price' => round($request->price ?? $cart->price, 2),
'options' => [
'type' => $cart->options->type,
'expire_date' => $request->expire_date ?? $cart->options->expire_date,
'stock_id' => $request->stock_id ?? $cart->options->stock_id,
'batch_no' => $request->batch_no ?? $cart->options->batch_no,
'product_code' => $cart->options->product_code,
'product_unit_id' => $cart->options->product_unit_id,
'product_unit_name' => $cart->options->product_unit_name,
'product_image' => $cart->options->product_image,
'profit_percent' => $cart->options->profit_percent,
'sales_price' => $cart->options->sales_price,
'discount' => $request->discount ?? $cart->options->discount,
'whole_sale_price' => $cart->options->whole_sale_price,
'dealer_price' => $cart->options->dealer_price,
'purchase_price' => $cart->options->purchase_price,
'product_type' => $cart->options->product_type,
'warehouse_id' => $cart->options->warehouse_id,
'variant_name' => $cart->options->variant_name,
'price_without_tax' => $cart->options->price_without_tax,
'has_serial' => $hasSerial,
'serial_numbers' => $existingSerials,
]
]);
return response()->json([
'success' => true,
'message' => __('Cart updated successfully')
]);
}
public function destroy($id)
{
try {
Cart::remove($id);
return response()->json(['success' => true, 'message' => __('Item removed from cart')]);
} catch (InvalidRowIDException $e) {
return response()->json(['success' => false, 'message' => __('The cart does not contain this item')]);
}
}
public function removeAllCart(Request $request)
{
$carts = Cart::content();
if ($carts->count() < 1) {
return response()->json(['message' => __('Cart is empty. Add items first!')]);
}
Cart::destroy();
$response = [
'success' => true,
'message' => __('All cart removed successfully!'),
];
return response()->json($response);
}
}