Files
ladill-pos/app/Http/Controllers/Pos/SettingsController.php
T
isaaccladandCursor 9d7dac6c24
Deploy Ladill POS / deploy (push) Successful in 1m58s
Add multi-branch POS with team roles and branch-scoped cashiers.
Pro and Business users can manage branches, invite cashiers with branch assignment, and switch registers; sales and register flows respect acting location.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 06:05:30 +00:00

150 lines
5.5 KiB
PHP

<?php
namespace App\Http\Controllers\Pos;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Pos\Concerns\ScopesToAccount;
use App\Models\PosLocation;
use App\Models\PosTable;
use App\Services\Import\CrmProductImportService;
use App\Services\Import\MerchantCatalogImportService;
use App\Services\Pos\PosLocationService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
use RuntimeException;
class SettingsController extends Controller
{
use ScopesToAccount;
public function __construct(
private PosLocationService $locations,
private \App\Services\Pos\SubscriptionService $subscriptions,
) {}
public function index(Request $request): View
{
$owner = $this->ownerRef($request);
$location = $this->location($request);
return view('pos.settings', [
'location' => $location,
'merchantImportEnabled' => (bool) config('pos.merchant_import_enabled', true),
'tables' => $this->scopeToLocation($request, PosTable::owned($owner))
->orderBy('area')->orderBy('position')->orderBy('label')->get(),
]);
}
public function update(Request $request): RedirectResponse
{
$data = $request->validate([
'name' => ['required', 'string', 'max:120'],
'currency' => ['required', 'string', 'size:3'],
'service_style' => ['required', 'in:retail,restaurant'],
'receipt_footer' => ['nullable', 'string', 'max:1000'],
'receipt_header' => ['nullable', 'string', 'max:500'],
'receipt_logo' => ['nullable', 'image', 'mimes:jpeg,jpg,png,gif,webp', 'max:2048'],
'remove_receipt_logo' => ['sometimes', 'boolean'],
'printer_paper_mm' => ['required', 'in:58,80'],
'printer_auto_print' => ['sometimes', 'boolean'],
]);
$user = ladill_account() ?? $request->user();
if ($data['service_style'] === 'restaurant' && ! $this->subscriptions->canUseRestaurantMode($user)) {
return redirect()->route('pos.pro.index')
->with('upsell', 'Restaurant mode is part of Ladill POS Pro.');
}
$location = $this->location($request);
if ($request->boolean('remove_receipt_logo') && $location->receipt_logo_path) {
Storage::disk('public')->delete($location->receipt_logo_path);
$location->receipt_logo_path = null;
}
if ($request->hasFile('receipt_logo')) {
if ($location->receipt_logo_path) {
Storage::disk('public')->delete($location->receipt_logo_path);
}
$location->receipt_logo_path = $request->file('receipt_logo')->store(
'pos/receipt-logos/'.$this->ownerRef($request),
'public'
);
}
$location->update([
'name' => $data['name'],
'currency' => strtoupper($data['currency']),
'service_style' => $data['service_style'],
'receipt_footer' => $data['receipt_footer'] ?? null,
'receipt_header' => $data['receipt_header'] ?? null,
'printer_paper_mm' => (int) $data['printer_paper_mm'],
'printer_auto_print' => $request->boolean('printer_auto_print'),
'receipt_logo_path' => $location->receipt_logo_path,
]);
return back()->with('success', 'Settings saved.');
}
public function storeTable(Request $request): RedirectResponse
{
$data = $request->validate([
'area' => ['nullable', 'string', 'max:60'],
'label' => ['required', 'string', 'max:60'],
'seats' => ['nullable', 'integer', 'min:1', 'max:99'],
]);
$owner = $this->ownerRef($request);
$location = $this->location($request);
PosTable::create([
'owner_ref' => $owner,
'location_id' => $location->id,
'area' => $data['area'] ?? null,
'label' => $data['label'],
'seats' => $data['seats'] ?? 2,
'status' => PosTable::STATUS_FREE,
'position' => (int) PosTable::owned($owner)->max('position') + 1,
]);
return back()->with('success', 'Table added.');
}
public function destroyTable(Request $request, PosTable $table): RedirectResponse
{
$this->authorizeOwner($request, $table);
if (! $table->isFree()) {
return back()->with('error', 'Settle the open ticket before removing this table.');
}
$table->delete();
return back()->with('success', 'Table removed.');
}
public function importCrm(Request $request, CrmProductImportService $import): RedirectResponse
{
try {
$result = $import->import($this->ownerRef($request));
return back()->with('success', "Imported {$result['imported']} product(s), updated {$result['updated']}.");
} catch (RuntimeException $e) {
return back()->with('error', $e->getMessage());
}
}
public function importMerchant(Request $request, MerchantCatalogImportService $import): RedirectResponse
{
try {
$result = $import->import($this->ownerRef($request));
return back()->with('success', "Imported {$result['imported']} item(s) from {$result['storefronts']} storefront(s), updated {$result['updated']}.");
} catch (RuntimeException $e) {
return back()->with('error', $e->getMessage());
}
}
}