Files
ladill-merchant/app/Http/Controllers/Merchant/ProductController.php
T
isaaccladandCursor 30ec8943dc
Deploy Ladill Merchant / deploy (push) Successful in 42s
Add Events-style heroes to Storefronts and Products index pages.
Surface wallet balance and key counts in gradient hero sections so Merchant list pages match the Events pattern.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 16:55:16 +00:00

103 lines
3.4 KiB
PHP

<?php
namespace App\Http\Controllers\Merchant;
use App\Http\Controllers\Controller;
use App\Services\Crm\CrmClient;
use App\Services\Qr\QrCodeManagerService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
/**
* Products page — fully backed by the Ladill CRM products API. The merchant's
* catalog lives in CRM (owner-scoped); this controller proxies CRUD to it.
*/
class ProductController extends Controller
{
public function __construct(private QrCodeManagerService $manager) {}
private function crm(): CrmClient
{
return CrmClient::for((string) ladill_account()->public_id);
}
public function index(Request $request): View
{
$search = trim((string) $request->query('search', ''));
$response = $this->crm()->products([
'type' => 'product',
'per_page' => 100,
'search' => $search !== '' ? $search : null,
]);
$products = (array) ($response['data'] ?? []);
$wallet = $this->manager->walletFor(ladill_account());
return view('merchant.products.index', [
'products' => $products,
'search' => $search,
'wallet' => $wallet,
'productCount' => count($products),
'activeCount' => collect($products)->filter(fn ($p) => ($p['active'] ?? true))->count(),
]);
}
public function create(): View
{
return view('merchant.products.create');
}
public function store(Request $request): RedirectResponse
{
$this->crm()->createProduct($this->payload($request));
return redirect()->route('merchant.products.index')->with('success', 'Product created.');
}
public function edit(string $product): View
{
return view('merchant.products.edit', ['product' => $this->crm()->product($product)]);
}
public function update(Request $request, string $product): RedirectResponse
{
$this->crm()->updateProduct($product, $this->payload($request));
return redirect()->route('merchant.products.index')->with('success', 'Product updated.');
}
public function destroy(string $product): RedirectResponse
{
$this->crm()->deleteProduct($product);
return redirect()->route('merchant.products.index')->with('success', 'Product deleted.');
}
/** @return array<string,mixed> */
private function payload(Request $request): array
{
$data = $request->validate([
'name' => ['required', 'string', 'max:255'],
'sku' => ['nullable', 'string', 'max:80'],
'description' => ['nullable', 'string', 'max:5000'],
'unit_price' => ['nullable', 'numeric', 'min:0'],
'currency' => ['nullable', 'string', 'size:3'],
'tax_rate' => ['nullable', 'numeric', 'min:0', 'max:100'],
'active' => ['nullable', 'boolean'],
]);
return [
'name' => $data['name'],
'sku' => $data['sku'] ?? null,
'type' => 'product',
'description' => $data['description'] ?? null,
'unit_price_minor' => (int) round(((float) ($data['unit_price'] ?? 0)) * 100),
'currency' => strtoupper((string) ($data['currency'] ?? config('crm.default_currency', 'GHS'))),
'tax_rate' => (float) ($data['tax_rate'] ?? 0),
'active' => $request->boolean('active'),
];
}
}