feat: RFQ portal, notifications, and project settings updates
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
1 parent
72e6c3170e
commit
dca9cd5d99
15 files changed
+1095
-140
No files matched your search
@@ -6,6 +6,8 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\RfqInvitation;
|
||||
use App\Models\SupplierQuote;
|
||||
use App\Models\SupplierQuoteItem;
|
||||
use App\Models\User;
|
||||
use App\Notifications\QuoteReceived;
|
||||
use App\Services\PurchaseStageService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -35,9 +37,16 @@ class RfqPortalController extends Controller
|
||||
}
|
||||
|
||||
$purchaseRequest = $invitation->purchaseRequest;
|
||||
$items = $purchaseRequest->items;
|
||||
$itemIds = $invitation->item_ids;
|
||||
$items = $itemIds
|
||||
? $purchaseRequest->items->whereIn('id', $itemIds)->values()
|
||||
: $purchaseRequest->items;
|
||||
|
||||
return view('rfq.show', compact('invitation', 'purchaseRequest', 'items'));
|
||||
// Generate a fresh confirmation code per page load and store in session
|
||||
$confirmCode = strtoupper(substr(bin2hex(random_bytes(3)), 0, 5));
|
||||
session(['rfq_confirm_' . $token => $confirmCode]);
|
||||
|
||||
return view('rfq.show', compact('invitation', 'purchaseRequest', 'items', 'confirmCode'));
|
||||
}
|
||||
|
||||
public function submit(Request $request, string $token)
|
||||
@@ -49,6 +58,8 @@ class RfqPortalController extends Controller
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'terms' => ['accepted'],
|
||||
'confirm_code' => ['required', 'string'],
|
||||
'lead_time_days' => ['nullable', 'integer', 'min:0'],
|
||||
'payment_terms' => ['nullable', 'string', 'max:200'],
|
||||
'notes' => ['nullable', 'string', 'max:1000'],
|
||||
@@ -56,7 +67,16 @@ class RfqPortalController extends Controller
|
||||
'items.*.unit_price' => ['required', 'numeric', 'min:0'],
|
||||
]);
|
||||
|
||||
$purchaseItems = $invitation->purchaseRequest->items;
|
||||
$expectedCode = session('rfq_confirm_' . $token);
|
||||
if (!$expectedCode || strtoupper(trim($validated['confirm_code'])) !== $expectedCode) {
|
||||
return back()->withErrors(['confirm_code' => 'Incorrect confirmation code. Please copy the code exactly as shown.'])->withInput();
|
||||
}
|
||||
session()->forget('rfq_confirm_' . $token);
|
||||
|
||||
$itemIds = $invitation->item_ids;
|
||||
$purchaseItems = $itemIds
|
||||
? $invitation->purchaseRequest->items->whereIn('id', $itemIds)->values()
|
||||
: $invitation->purchaseRequest->items;
|
||||
|
||||
$quote = SupplierQuote::create([
|
||||
'rfq_invitation_id' => $invitation->id,
|
||||
@@ -72,7 +92,7 @@ class RfqPortalController extends Controller
|
||||
$total = 0;
|
||||
foreach ($purchaseItems as $i => $item) {
|
||||
$unitPrice = (float)($validated['items'][$i]['unit_price'] ?? 0);
|
||||
$qty = (float)$item->quantity;
|
||||
$qty = (float)$item->quantity_required;
|
||||
$totalPrice = round($unitPrice * $qty, 3);
|
||||
$total += $totalPrice;
|
||||
|
||||
@@ -95,6 +115,10 @@ class RfqPortalController extends Controller
|
||||
app(PurchaseStageService::class)->setStage($pr, 'comparison');
|
||||
}
|
||||
|
||||
// Notify all admin users
|
||||
$invitation->load('supplier', 'purchaseRequest');
|
||||
User::role('Admin')->each(fn($u) => $u->notify(new QuoteReceived($invitation)));
|
||||
|
||||
return view('rfq.submitted', compact('invitation'));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user