[PROMOTE] dev → demo:領藥單 UI 改版、機台報表手機支付標籤、員工卡 hotfix
1. [FEAT] 領藥單頁面改套極簡奢華風 UI(對齊取貨碼):x-page-header、Alpine 建立彈窗、x-searchable-select 機台下拉、+/- 數量計數器、桌面表格+手機卡片、取消確認彈窗、luxury 分頁;新增 productsAjax 端點與路由;修正麵包屑顯示「領藥單」層級。 2. [FEAT] 機台報表付款類型對照表新增代碼 10「手機支付」(NFC 手機感應)標籤。 3. [FIX] 員工卡編輯彈窗回填所屬公司並防止 company_id 被洗為 null(backport hotfix 至 dev)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
9856a68d84
@ -95,6 +95,7 @@ class AnalysisController extends Controller
|
||||
7 => __('Welcome Gift'),
|
||||
8 => __('Questionnaire'),
|
||||
9 => __('Coin Acceptor'),
|
||||
10 => __('Mobile Pay'), // NFC 手機感應(手機支付)
|
||||
11 => __('QR Code Payment - TayPay'), // 掃碼支付-TayPay
|
||||
41 => __('Staff Card'),
|
||||
42 => __('Pickup Voucher'),
|
||||
|
||||
@ -59,6 +59,20 @@ class PharmacyPickupController extends AdminController
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX:回傳某機台目前可領藥品(建立領藥單彈窗用,對齊取貨碼 slots-ajax 模式)。
|
||||
*/
|
||||
public function productsAjax(Machine $machine)
|
||||
{
|
||||
$enabled = ($machine->settings['shopping_mode'] ?? null) === 'pickup_sheet'
|
||||
&& (bool) ($machine->settings['pharmacy_pickup_enabled'] ?? false);
|
||||
abort_unless($enabled, 403);
|
||||
|
||||
return response()->json([
|
||||
'products' => $this->service->availableProducts($machine)->values(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
|
||||
@ -10,177 +10,449 @@
|
||||
'abandoned' => __('Abandoned'),
|
||||
];
|
||||
$statusColors = [
|
||||
'awaiting_pickup' => 'bg-amber-100 text-amber-700 dark:bg-amber-500/10 dark:text-amber-400',
|
||||
'completed' => 'bg-emerald-100 text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-400',
|
||||
'failed' => 'bg-rose-100 text-rose-700 dark:bg-rose-500/10 dark:text-rose-400',
|
||||
'awaiting_pickup' => 'bg-amber-500/10 border border-amber-500/20 text-amber-600 dark:text-amber-400',
|
||||
'completed' => 'bg-emerald-500/10 border border-emerald-500/20 text-emerald-600 dark:text-emerald-400',
|
||||
'failed' => 'bg-rose-500/10 border border-rose-500/20 text-rose-600 dark:text-rose-400',
|
||||
'pending' => 'bg-slate-500/10 border border-slate-500/20 text-slate-500',
|
||||
'abandoned' => 'bg-slate-500/10 border border-slate-500/20 text-slate-500',
|
||||
];
|
||||
@endphp
|
||||
|
||||
<div class="space-y-6 pb-20">
|
||||
<div class="space-y-4 pb-20" x-data="pharmacyPickupManager()">
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
<h1 class="text-2xl font-black text-slate-800 dark:text-white tracking-tight">{{ __('menu.sales.pharmacy-pickup') }}</h1>
|
||||
<span class="text-sm text-slate-400">{{ __('Issue a pharmacy pickup order, print the QR ticket, patient scans at the machine to dispense.') }}</span>
|
||||
</div>
|
||||
{{-- Page Header --}}
|
||||
<x-page-header
|
||||
:title="__('menu.sales.pharmacy-pickup')"
|
||||
:subtitle="__('Issue a pharmacy pickup order, print the QR ticket, patient scans at the machine to dispense.')">
|
||||
@if($machines->isNotEmpty())
|
||||
<button @click="openCreateModal()"
|
||||
class="btn-luxury-primary whitespace-nowrap flex items-center gap-2 transition-all duration-300">
|
||||
<svg class="w-4 h-4 stroke-[2.5]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 5v14M5 12h14" />
|
||||
</svg>
|
||||
<span class="text-sm sm:text-base">{{ __('Create Pharmacy Pickup Order') }}</span>
|
||||
</button>
|
||||
@endif
|
||||
</x-page-header>
|
||||
|
||||
{{-- Flash / Errors --}}
|
||||
@if(session('success'))
|
||||
<div class="px-4 py-3 rounded-xl bg-emerald-50 text-emerald-700 border border-emerald-200 dark:bg-emerald-500/10 dark:text-emerald-400 dark:border-emerald-500/20 text-sm font-bold">{{ session('success') }}</div>
|
||||
<div class="p-5 bg-emerald-500/10 border border-emerald-500/20 text-emerald-600 dark:text-emerald-400 rounded-2xl flex items-center gap-3 font-bold text-sm animate-luxury-in">
|
||||
<svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
@if(session('error'))
|
||||
<div class="px-4 py-3 rounded-xl bg-rose-50 text-rose-700 border border-rose-200 dark:bg-rose-500/10 dark:text-rose-400 dark:border-rose-500/20 text-sm font-bold">{{ session('error') }}</div>
|
||||
<div class="p-5 bg-rose-500/10 border border-rose-500/20 text-rose-600 dark:text-rose-400 rounded-2xl flex items-center gap-3 font-bold text-sm animate-luxury-in">
|
||||
<svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 9v2m0 4h.01M5.07 19h13.86a2 2 0 001.74-3L13.74 4a2 2 0 00-3.48 0L3.33 16a2 2 0 001.74 3z"/></svg>
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
@if($errors->any())
|
||||
<div class="px-4 py-3 rounded-xl bg-rose-50 text-rose-700 border border-rose-200 dark:bg-rose-500/10 dark:text-rose-400 dark:border-rose-500/20 text-sm">
|
||||
<ul class="list-disc ps-5 space-y-1">
|
||||
<div class="p-5 bg-rose-500/10 border border-rose-500/20 text-rose-600 dark:text-rose-400 rounded-2xl text-sm animate-luxury-in">
|
||||
<ul class="list-disc ps-5 space-y-1 font-bold">
|
||||
@foreach($errors->all() as $err)<li>{{ $err }}</li>@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- 建立領藥單 --}}
|
||||
<div class="bg-white dark:bg-slate-800/60 rounded-2xl border border-slate-200 dark:border-slate-700/50 p-6 space-y-5">
|
||||
<h2 class="text-lg font-black text-slate-700 dark:text-slate-200">{{ __('Create Pharmacy Pickup Order') }}</h2>
|
||||
|
||||
@if($machines->isEmpty())
|
||||
<p class="text-sm text-amber-600 dark:text-amber-400">{{ __('No machines enabled for pharmacy pickup. Enable it under Machine System Settings (Pickup Sheet mode → Pharmacy Pickup switch).') }}</p>
|
||||
@else
|
||||
{{-- 選機台(變更即重新載入該機台可領藥品) --}}
|
||||
<form method="GET" action="{{ route('admin.sales.pharmacy-pickup') }}" class="flex flex-wrap items-end gap-3">
|
||||
<div class="flex flex-col gap-1">
|
||||
<label class="text-xs font-black text-slate-400 uppercase tracking-widest">{{ __('Select Machine') }}</label>
|
||||
<select name="machine_id" onchange="this.form.submit()"
|
||||
class="luxury-input min-w-[260px] rounded-xl border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900/50 dark:text-slate-200 py-2.5 px-3 text-sm">
|
||||
<option value="">{{ __('-- Select Machine --') }}</option>
|
||||
@foreach($machines as $m)
|
||||
<option value="{{ $m->id }}" @selected($selectedMachine && $selectedMachine->id === $m->id)>{{ $m->name }} ({{ $m->serial_no }})</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@if($selectedMachine)
|
||||
<form method="POST" action="{{ route('admin.sales.pharmacy-pickup.store') }}" class="space-y-4">
|
||||
@csrf
|
||||
<input type="hidden" name="machine_id" value="{{ $selectedMachine->id }}">
|
||||
|
||||
<div class="flex flex-col gap-1 max-w-xs">
|
||||
<label class="text-xs font-black text-slate-400 uppercase tracking-widest">{{ __('Pricing Slip No.') }} <span class="text-slate-300 normal-case">({{ __('optional') }})</span></label>
|
||||
<input type="text" name="pricing_slip_no" value="{{ old('pricing_slip_no') }}" maxlength="64"
|
||||
class="luxury-input rounded-xl border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900/50 dark:text-slate-200 py-2.5 px-3 text-sm"
|
||||
placeholder="{{ __('e.g. the hospital pricing slip number') }}">
|
||||
</div>
|
||||
|
||||
@if($products->isEmpty())
|
||||
<p class="text-sm text-slate-500">{{ __('This machine currently has no medicine in stock.') }}</p>
|
||||
@else
|
||||
<div class="overflow-x-auto rounded-xl border border-slate-200 dark:border-slate-700/50">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-slate-50 dark:bg-slate-900/40 text-slate-500 dark:text-slate-400">
|
||||
<tr>
|
||||
<th class="py-2.5 px-3 text-left w-10"></th>
|
||||
<th class="py-2.5 px-3 text-left">{{ __('Medicine') }}</th>
|
||||
<th class="py-2.5 px-3 text-left">{{ __('Spec') }}</th>
|
||||
<th class="py-2.5 px-3 text-center">{{ __('Available') }}<br><span class="text-[10px] font-normal text-slate-400">{{ __('(deducted by issued pickup orders)') }}</span></th>
|
||||
<th class="py-2.5 px-3 text-center w-32">{{ __('Quantity') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100 dark:divide-slate-800">
|
||||
@foreach($products as $p)
|
||||
<tr class="hover:bg-slate-50 dark:hover:bg-slate-800/40">
|
||||
<td class="py-2 px-3 text-center">
|
||||
<input type="checkbox" name="products[]" value="{{ $p->product_id }}"
|
||||
class="w-4 h-4 text-cyan-500 rounded border-slate-300 dark:border-slate-600">
|
||||
</td>
|
||||
<td class="py-2 px-3 font-bold text-slate-700 dark:text-slate-200">{{ $p->name }}</td>
|
||||
<td class="py-2 px-3 text-slate-500">{{ $p->spec ?: '-' }}</td>
|
||||
<td class="py-2 px-3 text-center text-slate-600 dark:text-slate-300">
|
||||
<span class="font-bold">{{ $p->available }}</span>
|
||||
@if(($p->reserved ?? 0) > 0)
|
||||
<span class="text-[11px] text-slate-400">({{ __('physical') }} {{ $p->physical }} − {{ __('reserved') }} {{ $p->reserved }})</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="py-2 px-3 text-center">
|
||||
<input type="number" name="qty[{{ $p->product_id }}]" value="1" min="1" max="{{ $p->available }}"
|
||||
class="w-20 text-center rounded-lg border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-900/50 dark:text-slate-200 py-1.5 px-2 text-sm">
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="inline-flex items-center gap-2 px-5 py-2.5 rounded-xl bg-cyan-500 hover:bg-cyan-600 text-white font-bold text-sm transition-colors">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4"/></svg>
|
||||
{{ __('Create & Generate QR') }}
|
||||
</button>
|
||||
@endif
|
||||
</form>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
@if($machines->isEmpty())
|
||||
<div class="p-5 bg-amber-500/10 border border-amber-500/20 text-amber-600 dark:text-amber-400 rounded-2xl flex items-start gap-4 font-bold text-sm">
|
||||
<svg class="w-5 h-5 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 9v2m0 4h.01M5.07 19h13.86a2 2 0 001.74-3L13.74 4a2 2 0 00-3.48 0L3.33 16a2 2 0 001.74 3z"/></svg>
|
||||
{{ __('No machines enabled for pharmacy pickup. Enable it under Machine System Settings (Pickup Sheet mode → Pharmacy Pickup switch).') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- 領藥單列表 --}}
|
||||
<div class="bg-white dark:bg-slate-800/60 rounded-2xl border border-slate-200 dark:border-slate-700/50 p-6 space-y-4">
|
||||
<h2 class="text-lg font-black text-slate-700 dark:text-slate-200">{{ __('Pharmacy Pickup Orders') }}</h2>
|
||||
<div class="luxury-card rounded-3xl p-8 animate-luxury-in relative overflow-hidden">
|
||||
|
||||
<div class="overflow-x-auto rounded-xl border border-slate-200 dark:border-slate-700/50">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-slate-50 dark:bg-slate-900/40 text-slate-500 dark:text-slate-400">
|
||||
<tr>
|
||||
<th class="py-2.5 px-3 text-left">{{ __('Order No.') }}</th>
|
||||
<th class="py-2.5 px-3 text-left">{{ __('Pricing Slip No.') }}</th>
|
||||
<th class="py-2.5 px-3 text-left">{{ __('Machine') }}</th>
|
||||
<th class="py-2.5 px-3 text-left">{{ __('Items') }}</th>
|
||||
<th class="py-2.5 px-3 text-center">{{ __('Pickup Code') }}</th>
|
||||
<th class="py-2.5 px-3 text-center">{{ __('Status') }}</th>
|
||||
<th class="py-2.5 px-3 text-left">{{ __('Created') }}</th>
|
||||
<th class="py-2.5 px-3 text-center">{{ __('Actions') }}</th>
|
||||
{{-- Desktop Table --}}
|
||||
<div class="hidden xl:block overflow-x-auto">
|
||||
<table class="w-full text-left border-separate border-spacing-0">
|
||||
<thead>
|
||||
<tr class="bg-slate-50/50 dark:bg-slate-900/10">
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Order No.') }}</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Machine') }}</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Items') }}</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Pickup Code') }}</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-center">{{ __('Status') }}</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800">{{ __('Created') }}</th>
|
||||
<th class="px-6 py-4 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-[0.15em] border-b border-slate-100 dark:border-slate-800 text-right">{{ __('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100 dark:divide-slate-800">
|
||||
<tbody class="divide-y divide-slate-100 dark:divide-slate-800/80">
|
||||
@forelse($orders as $order)
|
||||
<tr class="hover:bg-slate-50 dark:hover:bg-slate-800/40 {{ session('created_order_id') == $order->id ? 'bg-emerald-50 dark:bg-emerald-500/5' : '' }}">
|
||||
<td class="py-2.5 px-3 font-mono font-bold text-slate-700 dark:text-slate-200">{{ $order->order_no }}</td>
|
||||
<td class="py-2.5 px-3 text-slate-500">{{ $order->pricing_slip_no ?: '-' }}</td>
|
||||
<td class="py-2.5 px-3 text-slate-600 dark:text-slate-300">{{ $order->machine?->name ?? '-' }}</td>
|
||||
<td class="py-2.5 px-3 text-slate-600 dark:text-slate-300">
|
||||
@foreach($order->items as $it)
|
||||
<div>{{ $it->product_name }} × {{ $it->quantity }}</div>
|
||||
@endforeach
|
||||
<tr class="group hover:bg-slate-50/50 dark:hover:bg-white/[0.02] transition-colors duration-200 {{ session('created_order_id') == $order->id ? 'bg-emerald-50/60 dark:bg-emerald-500/5' : '' }}">
|
||||
<td class="px-6 py-6 whitespace-nowrap">
|
||||
<div class="text-base font-black font-mono text-slate-800 dark:text-slate-100 tracking-tight">{{ $order->order_no }}</div>
|
||||
@if($order->pricing_slip_no)
|
||||
<div class="text-[10px] font-bold text-slate-400 uppercase tracking-[0.2em] mt-0.5">{{ __('Pricing Slip No.') }}: {{ $order->pricing_slip_no }}</div>
|
||||
@endif
|
||||
</td>
|
||||
<td class="py-2.5 px-3 text-center font-mono font-bold text-cyan-600 dark:text-cyan-400">{{ $order->pickupCode?->code ?? '-' }}</td>
|
||||
<td class="py-2.5 px-3 text-center">
|
||||
<span class="inline-block px-2.5 py-1 rounded-full text-xs font-bold {{ $statusColors[$order->status] ?? 'bg-slate-100 text-slate-600' }}">{{ $statusLabels[$order->status] ?? $order->status }}</span>
|
||||
<td class="px-6 py-6">
|
||||
<div class="text-base font-extrabold text-slate-800 dark:text-slate-100 tracking-tight">{{ $order->machine?->name ?? '-' }}</div>
|
||||
<div class="text-[10px] font-mono font-bold text-slate-400 uppercase tracking-[0.2em]">{{ $order->machine?->serial_no }}</div>
|
||||
</td>
|
||||
<td class="py-2.5 px-3 text-slate-500 text-xs">
|
||||
<div>{{ $order->created_at?->format('Y-m-d H:i') }}</div>
|
||||
<div class="text-slate-400">{{ $order->creator?->name }}</div>
|
||||
<td class="px-6 py-6">
|
||||
<div class="space-y-0.5">
|
||||
@foreach($order->items as $it)
|
||||
<div class="text-sm font-bold text-slate-700 dark:text-slate-300">{{ $it->product_name }} <span class="text-cyan-600 dark:text-cyan-400 font-black">× {{ $it->quantity }}</span></div>
|
||||
@endforeach
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-2.5 px-3 text-center">
|
||||
<div class="flex items-center justify-center gap-3">
|
||||
<td class="px-6 py-6 text-center whitespace-nowrap">
|
||||
@if($order->pickupCode?->code)
|
||||
<span class="text-base font-black font-mono text-cyan-600 dark:text-cyan-400 tracking-widest bg-cyan-50 dark:bg-cyan-500/10 px-3 py-1.5 rounded-xl border border-cyan-100 dark:border-cyan-500/20">{{ $order->pickupCode->code }}</span>
|
||||
@else
|
||||
<span class="text-slate-300 dark:text-slate-600">-</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="px-6 py-6 text-center whitespace-nowrap">
|
||||
<span class="inline-block px-3 py-1 rounded-full text-[10px] font-black uppercase tracking-widest {{ $statusColors[$order->status] ?? 'bg-slate-500/10 border border-slate-500/20 text-slate-500' }}">{{ $statusLabels[$order->status] ?? $order->status }}</span>
|
||||
</td>
|
||||
<td class="px-6 py-6 whitespace-nowrap">
|
||||
<div class="text-sm font-black text-slate-600 dark:text-slate-300 font-mono">{{ $order->created_at?->format('Y-m-d H:i') }}</div>
|
||||
<div class="text-[10px] font-bold text-slate-400 uppercase tracking-widest mt-0.5">{{ $order->creator?->name }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-6 whitespace-nowrap text-right">
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
@if($order->status !== 'failed' && $order->pickupCode)
|
||||
<a href="{{ route('admin.sales.pharmacy-pickup.print', $order) }}" target="_blank" class="text-xs font-bold text-cyan-600 hover:text-cyan-700">{{ __('Print') }}</a>
|
||||
<a href="{{ route('admin.sales.pharmacy-pickup.print', $order) }}" target="_blank"
|
||||
class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 dark:hover:bg-cyan-500/10 border border-transparent hover:border-cyan-500/20 transition-all"
|
||||
title="{{ __('Print') }}">
|
||||
<svg class="w-4 h-4 stroke-[2.5]" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0110.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0l.229 2.523a1.125 1.125 0 01-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0021 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 00-1.913-.247M6.34 18H5.25A2.25 2.25 0 013 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 011.913-.247m10.5 0a48.536 48.536 0 00-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5zm-3 0h.008v.008H15V10.5z"/></svg>
|
||||
</a>
|
||||
@endif
|
||||
@if($order->status === 'awaiting_pickup')
|
||||
<form method="POST" action="{{ route('admin.sales.pharmacy-pickup.cancel', $order) }}" onsubmit="return confirm('{{ __('Cancel this pharmacy pickup order?') }}')">
|
||||
<form id="pp-cancel-desktop-{{ $order->id }}" method="POST" action="{{ route('admin.sales.pharmacy-pickup.cancel', $order) }}">
|
||||
@csrf
|
||||
<button type="submit" class="text-xs font-bold text-rose-500 hover:text-rose-600">{{ __('Cancel') }}</button>
|
||||
<button type="button" @click="confirmCancel('pp-cancel-desktop-{{ $order->id }}')"
|
||||
class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-rose-500 hover:bg-rose-500/5 border border-transparent hover:border-rose-500/20 transition-all"
|
||||
title="{{ __('Cancel') }}">
|
||||
<svg class="w-4 h-4 stroke-[2.5]" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-3.38a2.25 2.25 0 00-2.25-2.25h-3.51a2.25 2.25 0 00-2.25 2.25v3.38"/></svg>
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
@if($order->status === 'failed' && !($order->pickupCode))
|
||||
<span class="text-slate-300">-</span>
|
||||
@if($order->status !== 'awaiting_pickup' && !($order->status !== 'failed' && $order->pickupCode))
|
||||
<span class="text-slate-300 dark:text-slate-600 pr-2">-</span>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="8" class="py-8 text-center text-slate-400">{{ __('No pharmacy pickup orders yet.') }}</td></tr>
|
||||
<x-empty-state mode="table" :colspan="7" :message="__('No pharmacy pickup orders yet.')" />
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>{{ $orders->links() }}</div>
|
||||
{{-- Mobile Card Grid --}}
|
||||
<div class="xl:hidden grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
@forelse($orders as $order)
|
||||
<div class="luxury-card p-6 rounded-[2rem] border border-slate-100 dark:border-slate-800 bg-white/50 dark:bg-slate-900/50 transition-all duration-300 group {{ session('created_order_id') == $order->id ? 'ring-2 ring-emerald-500/30' : '' }}">
|
||||
{{-- Header --}}
|
||||
<div class="flex items-start justify-between gap-4 mb-6">
|
||||
<div class="flex items-center gap-4 min-w-0">
|
||||
<div class="w-14 h-14 rounded-2xl bg-slate-100 dark:bg-slate-800 flex items-center justify-center text-slate-400 border border-slate-200 dark:border-slate-700 group-hover:bg-cyan-500 group-hover:text-white transition-all duration-300 shadow-sm shrink-0">
|
||||
<svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<h3 class="text-base font-extrabold text-slate-800 dark:text-slate-100 truncate tracking-tight font-mono">{{ $order->order_no }}</h3>
|
||||
<p class="text-xs font-mono font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest truncate">{{ $order->machine?->name ?? '-' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<span class="inline-block px-3 py-1 rounded-full text-[10px] font-black uppercase tracking-widest shrink-0 {{ $statusColors[$order->status] ?? 'bg-slate-500/10 border border-slate-500/20 text-slate-500' }}">{{ $statusLabels[$order->status] ?? $order->status }}</span>
|
||||
</div>
|
||||
|
||||
{{-- Info Grid --}}
|
||||
<div class="grid grid-cols-2 gap-y-4 mb-6 border-y border-slate-100 dark:border-slate-800/50 py-4">
|
||||
<div>
|
||||
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">{{ __('Pickup Code') }}</p>
|
||||
<p class="text-sm font-black font-mono text-cyan-600 dark:text-cyan-400 tracking-widest">{{ $order->pickupCode?->code ?? '-' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">{{ __('Pricing Slip No.') }}</p>
|
||||
<p class="text-sm font-bold text-slate-700 dark:text-slate-300">{{ $order->pricing_slip_no ?: '-' }}</p>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">{{ __('Items') }}</p>
|
||||
<div class="space-y-0.5">
|
||||
@foreach($order->items as $it)
|
||||
<p class="text-sm font-bold text-slate-700 dark:text-slate-300">{{ $it->product_name }} <span class="text-cyan-600 dark:text-cyan-400 font-black">× {{ $it->quantity }}</span></p>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<p class="text-[10px] font-black text-slate-400 dark:text-slate-500 uppercase tracking-widest mb-1">{{ __('Created') }}</p>
|
||||
<p class="text-sm font-bold text-slate-700 dark:text-slate-300 font-mono">{{ $order->created_at?->format('Y-m-d H:i') }} <span class="text-slate-400 font-sans">· {{ $order->creator?->name }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Actions --}}
|
||||
@if(($order->status !== 'failed' && $order->pickupCode) || $order->status === 'awaiting_pickup')
|
||||
<div class="flex items-center gap-3">
|
||||
@if($order->status !== 'failed' && $order->pickupCode)
|
||||
<a href="{{ route('admin.sales.pharmacy-pickup.print', $order) }}" target="_blank"
|
||||
class="flex-1 flex items-center justify-center gap-2 py-3 rounded-xl bg-slate-50 dark:bg-slate-800 text-slate-600 dark:text-slate-300 font-black text-xs uppercase tracking-widest border border-slate-100 dark:border-slate-800 hover:text-cyan-500 hover:bg-cyan-500/5 transition-all duration-300">
|
||||
<svg class="w-4 h-4 stroke-[2.5]" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0110.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0l.229 2.523a1.125 1.125 0 01-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0021 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 00-1.913-.247M6.34 18H5.25A2.25 2.25 0 013 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 011.913-.247"/></svg>
|
||||
{{ __('Print') }}
|
||||
</a>
|
||||
@endif
|
||||
@if($order->status === 'awaiting_pickup')
|
||||
<form id="pp-cancel-mobile-{{ $order->id }}" method="POST" action="{{ route('admin.sales.pharmacy-pickup.cancel', $order) }}" class="flex-1">
|
||||
@csrf
|
||||
<button type="button" @click="confirmCancel('pp-cancel-mobile-{{ $order->id }}')"
|
||||
class="w-full flex items-center justify-center gap-2 py-3 rounded-xl bg-rose-500/5 text-rose-500 text-xs font-black uppercase tracking-widest border border-rose-500/20 hover:bg-rose-500 hover:text-white transition-all duration-300">
|
||||
<svg class="w-4 h-4 stroke-[2.5]" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79"/></svg>
|
||||
{{ __('Cancel') }}
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-span-full">
|
||||
<x-empty-state :message="__('No pharmacy pickup orders yet.')" />
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
{{-- Pagination --}}
|
||||
<div class="mt-8 border-t border-slate-100/50 dark:border-slate-800/50 pt-6">
|
||||
{{ $orders->appends(request()->query())->links('vendor.pagination.luxury') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Create Pharmacy Pickup Order Modal --}}
|
||||
<div x-show="showCreateModal" class="fixed inset-0 z-50 overflow-y-auto"
|
||||
x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100" x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0" x-cloak style="display:none;">
|
||||
<div class="flex items-center justify-center min-h-screen px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div class="fixed inset-0 transition-opacity bg-slate-900/60 backdrop-blur-sm" @click="showCreateModal = false"></div>
|
||||
|
||||
<div x-show="showCreateModal" x-transition:enter="ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0 translate-y-4 sm:scale-95"
|
||||
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
|
||||
x-transition:leave="ease-in duration-200" x-transition:leave-start="opacity-100 sm:scale-100"
|
||||
x-transition:leave-end="opacity-0 translate-y-4 sm:scale-95"
|
||||
class="inline-block px-8 py-10 text-left align-bottom transition-all transform luxury-card rounded-3xl dark:bg-slate-900 border-slate-200/50 dark:border-slate-700/50 shadow-2xl sm:my-8 sm:align-middle sm:max-w-3xl sm:w-full overflow-visible">
|
||||
|
||||
<div class="flex justify-between items-center mb-8">
|
||||
<h3 class="text-2xl font-black text-slate-800 dark:text-white font-display tracking-tight">{{ __('Create Pharmacy Pickup Order') }}</h3>
|
||||
<button @click="showCreateModal = false" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M6 18L18 6M6 6l12 12"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('admin.sales.pharmacy-pickup.store') }}" method="POST" class="space-y-6"
|
||||
@submit.prevent="validateAndSubmit" x-ref="createForm">
|
||||
@csrf
|
||||
<input type="hidden" name="machine_id" :value="selectedMachine">
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{{-- Machine --}}
|
||||
<div class="space-y-2 relative focus-within:z-[60]">
|
||||
<label class="text-xs font-black text-slate-500 uppercase tracking-widest pl-1">{{ __('Select Machine') }} <span class="text-rose-500">*</span></label>
|
||||
<x-searchable-select name="machine_select" id="pp-machine"
|
||||
placeholder="{{ __('-- Select Machine --') }}" x-model="selectedMachine"
|
||||
@change="selectedMachine = $event.target.value; fetchProducts()">
|
||||
@foreach($machines as $m)
|
||||
<option value="{{ $m->id }}" data-title="{{ $m->name }} ({{ $m->serial_no }})">{{ $m->name }} ({{ $m->serial_no }})</option>
|
||||
@endforeach
|
||||
</x-searchable-select>
|
||||
</div>
|
||||
|
||||
{{-- Pricing Slip No. --}}
|
||||
<div class="space-y-2">
|
||||
<label class="text-xs font-black text-slate-500 uppercase tracking-widest pl-1">{{ __('Pricing Slip No.') }} <span class="text-slate-300 normal-case font-bold">({{ __('optional') }})</span></label>
|
||||
<input type="text" name="pricing_slip_no" x-model="pricingSlipNo" maxlength="64"
|
||||
class="luxury-input w-full py-3 px-4 text-sm" placeholder="{{ __('e.g. the hospital pricing slip number') }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Medicine selection --}}
|
||||
<div class="space-y-3">
|
||||
<label class="text-xs font-black text-slate-500 uppercase tracking-widest pl-1">{{ __('Medicine') }} <span class="text-rose-500">*</span></label>
|
||||
|
||||
{{-- Empty: no machine selected --}}
|
||||
<div x-show="!selectedMachine" class="rounded-[2rem] border border-dashed border-slate-200 dark:border-slate-700 bg-slate-50/50 dark:bg-slate-900/30 p-10 text-center">
|
||||
<p class="text-sm font-bold text-slate-400">{{ __('Please select a machine') }}</p>
|
||||
</div>
|
||||
|
||||
{{-- Loading --}}
|
||||
<div x-show="selectedMachine && loadingProducts" class="rounded-[2rem] border border-slate-100 dark:border-slate-800 bg-slate-50/50 dark:bg-slate-900/30 p-10 flex items-center justify-center">
|
||||
<x-luxury-spinner show="loadingProducts" />
|
||||
</div>
|
||||
|
||||
{{-- No products --}}
|
||||
<div x-show="selectedMachine && !loadingProducts && products.length === 0" class="rounded-[2rem] border border-amber-500/20 bg-amber-500/5 p-8 text-center">
|
||||
<p class="text-sm font-bold text-amber-600 dark:text-amber-400">{{ __('This machine currently has no medicine in stock.') }}</p>
|
||||
</div>
|
||||
|
||||
{{-- Product table --}}
|
||||
<div x-show="selectedMachine && !loadingProducts && products.length > 0"
|
||||
class="overflow-hidden rounded-[2rem] border border-slate-100 dark:border-slate-800">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-slate-50/70 dark:bg-slate-900/40">
|
||||
<tr>
|
||||
<th class="py-3 px-4 text-left w-10"></th>
|
||||
<th class="py-3 px-4 text-left text-[10px] font-black text-slate-400 uppercase tracking-widest">{{ __('Medicine') }}</th>
|
||||
<th class="py-3 px-4 text-left text-[10px] font-black text-slate-400 uppercase tracking-widest">{{ __('Spec') }}</th>
|
||||
<th class="py-3 px-4 text-center text-[10px] font-black text-slate-400 uppercase tracking-widest">{{ __('Available') }}</th>
|
||||
<th class="py-3 px-4 text-center text-[10px] font-black text-slate-400 uppercase tracking-widest w-40">{{ __('Quantity') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-100 dark:divide-slate-800/80">
|
||||
<template x-for="p in products" :key="p.product_id">
|
||||
<tr class="transition-colors duration-200"
|
||||
:class="p.checked ? 'bg-cyan-50/40 dark:bg-cyan-500/5' : 'hover:bg-slate-50/50 dark:hover:bg-white/[0.02]'">
|
||||
<td class="py-3 px-4 text-center">
|
||||
<input type="checkbox" x-model="p.checked"
|
||||
class="w-4 h-4 text-cyan-500 rounded border-slate-300 dark:border-slate-600 focus:ring-cyan-500/30 cursor-pointer">
|
||||
</td>
|
||||
<td class="py-3 px-4 font-bold text-slate-700 dark:text-slate-200" x-text="p.name"></td>
|
||||
<td class="py-3 px-4 text-slate-500" x-text="p.spec || '-'"></td>
|
||||
<td class="py-3 px-4 text-center">
|
||||
<span class="font-black text-slate-700 dark:text-slate-200" x-text="p.available"></span>
|
||||
<template x-if="p.reserved > 0">
|
||||
<span class="block text-[10px] font-bold text-slate-400" x-text="'({{ __('physical') }} ' + p.physical + ' − {{ __('reserved') }} ' + p.reserved + ')'"></span>
|
||||
</template>
|
||||
</td>
|
||||
<td class="py-3 px-4">
|
||||
{{-- Luxury +/- counter --}}
|
||||
<div class="flex items-center h-10 mx-auto rounded-xl border border-slate-200/70 dark:border-slate-700/50 bg-white dark:bg-slate-900/50 overflow-hidden w-[140px] transition-all"
|
||||
:class="{ 'opacity-40 pointer-events-none': !p.checked }">
|
||||
<button type="button" @click="p.qty > 1 ? p.qty-- : 1"
|
||||
class="shrink-0 w-10 h-full flex items-center justify-center text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 active:scale-90 transition-all">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M20 12H4"/></svg>
|
||||
</button>
|
||||
<div class="h-5 w-px bg-slate-200 dark:bg-slate-700/50"></div>
|
||||
<input type="text" x-model.number="p.qty" readonly
|
||||
class="flex-1 w-full min-w-0 bg-transparent border-none text-center text-base font-black text-slate-800 dark:text-white focus:ring-0 p-0">
|
||||
<div class="h-5 w-px bg-slate-200 dark:bg-slate-700/50"></div>
|
||||
<button type="button" @click="p.qty < p.available ? p.qty++ : p.available"
|
||||
class="shrink-0 w-10 h-full flex items-center justify-center text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 active:scale-90 transition-all">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 5v14M5 12h14"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
{{-- Submitted only when checked (empty name = skipped) --}}
|
||||
<input type="hidden" :name="p.checked ? 'products[]' : ''" :value="p.product_id">
|
||||
<input type="hidden" :name="p.checked ? `qty[${p.product_id}]` : ''" :value="p.qty">
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="text-[10px] font-bold text-slate-400 pl-1">{{ __('(deducted by issued pickup orders)') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-x-4 pt-4">
|
||||
<button type="button" @click="showCreateModal = false" class="btn-luxury-ghost px-8">{{ __('Cancel') }}</button>
|
||||
<button type="submit" class="btn-luxury-primary px-12 flex items-center gap-2">
|
||||
<svg class="w-4 h-4 stroke-[2.5]" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4"/></svg>
|
||||
{{ __('Create & Generate QR') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Confirm Cancel Modal --}}
|
||||
<x-confirm-modal alpineVar="showCancelModal" :title="__('Cancel Pickup Code')"
|
||||
:message="__('Cancel this pharmacy pickup order?')"
|
||||
:confirmText="__('Yes, Cancel')" confirmAction="submitCancel()" confirmColor="rose" iconType="danger" />
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('pharmacyPickupManager', () => ({
|
||||
showCreateModal: false,
|
||||
selectedMachine: '',
|
||||
pricingSlipNo: '',
|
||||
products: [],
|
||||
loadingProducts: false,
|
||||
showCancelModal: false,
|
||||
cancelTargetForm: null,
|
||||
|
||||
openCreateModal() {
|
||||
this.selectedMachine = '';
|
||||
this.pricingSlipNo = '';
|
||||
this.products = [];
|
||||
this.showCreateModal = true;
|
||||
this.syncSelect('pp-machine', ' ');
|
||||
},
|
||||
|
||||
async fetchProducts() {
|
||||
if (!this.selectedMachine) {
|
||||
this.products = [];
|
||||
return;
|
||||
}
|
||||
this.loadingProducts = true;
|
||||
try {
|
||||
const res = await fetch(`/admin/sales/pharmacy-pickup/${this.selectedMachine}/products-ajax`, {
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' }
|
||||
});
|
||||
const data = await res.json();
|
||||
this.products = (data.products || []).map(p => ({
|
||||
...p,
|
||||
checked: false,
|
||||
qty: 1,
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error('Error fetching products:', e);
|
||||
window.showToast?.('{{ __("Loading failed") }}', 'error');
|
||||
this.products = [];
|
||||
} finally {
|
||||
this.loadingProducts = false;
|
||||
}
|
||||
},
|
||||
|
||||
validateAndSubmit() {
|
||||
if (!this.selectedMachine || this.selectedMachine.toString().trim() === '') {
|
||||
window.showToast?.('{{ __("Please select a machine") }}', 'error');
|
||||
return;
|
||||
}
|
||||
if (!this.products.some(p => p.checked)) {
|
||||
window.showToast?.('{{ __("Please select at least one medicine with quantity.") }}', 'error');
|
||||
return;
|
||||
}
|
||||
this.$refs.createForm.submit();
|
||||
},
|
||||
|
||||
confirmCancel(formId) {
|
||||
this.cancelTargetForm = formId;
|
||||
this.showCancelModal = true;
|
||||
},
|
||||
|
||||
submitCancel() {
|
||||
if (this.cancelTargetForm) {
|
||||
const form = document.getElementById(this.cancelTargetForm);
|
||||
if (form) form.submit();
|
||||
}
|
||||
this.showCancelModal = false;
|
||||
},
|
||||
|
||||
syncSelect(id, value) {
|
||||
this.$nextTick(() => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) {
|
||||
const valStr = (value !== undefined && value !== null && value.toString().trim() !== '') ? value.toString() : ' ';
|
||||
el.value = valStr;
|
||||
window.HSSelect?.getInstance(el)?.setValue(valStr);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
init() {
|
||||
this.$watch('selectedMachine', (val) => {
|
||||
this.syncSelect('pp-machine', val);
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@ -120,6 +120,7 @@
|
||||
'promotions' => __('Promotions'),
|
||||
'pass-codes' => __('Pass Codes'),
|
||||
'store-gifts' => __('Store Gifts'),
|
||||
'pharmacy-pickup' => __('menu.sales.pharmacy-pickup'),
|
||||
'change-stock' => __('Change Stock'),
|
||||
'machine-reports' => __('Machine Reports'),
|
||||
'product-reports' => __('Product Reports'),
|
||||
|
||||
@ -174,6 +174,7 @@ Route::middleware(['auth', 'auth.session', 'verified', 'tenant.access'])->prefix
|
||||
// 領藥單(取物單模式 / 領藥模組)— 受權限 menu.sales.pharmacy-pickup 控管
|
||||
Route::get('/pharmacy-pickup', [App\Http\Controllers\Admin\PharmacyPickupController::class, 'index'])->name('pharmacy-pickup')->middleware('can:menu.sales.pharmacy-pickup');
|
||||
Route::post('/pharmacy-pickup', [App\Http\Controllers\Admin\PharmacyPickupController::class, 'store'])->name('pharmacy-pickup.store')->middleware('can:menu.sales.pharmacy-pickup');
|
||||
Route::get('/pharmacy-pickup/{machine}/products-ajax', [App\Http\Controllers\Admin\PharmacyPickupController::class, 'productsAjax'])->name('pharmacy-pickup.products-ajax')->middleware('can:menu.sales.pharmacy-pickup');
|
||||
Route::get('/pharmacy-pickup/{order}/print', [App\Http\Controllers\Admin\PharmacyPickupController::class, 'print'])->name('pharmacy-pickup.print')->middleware('can:menu.sales.pharmacy-pickup');
|
||||
Route::post('/pharmacy-pickup/{order}/cancel', [App\Http\Controllers\Admin\PharmacyPickupController::class, 'cancel'])->name('pharmacy-pickup.cancel')->middleware('can:menu.sales.pharmacy-pickup');
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user