Purchase Request Approval
Alpha notice: This walkthrough mirrors the hosted demo. Status names and thresholds are demo-specific.
What you will build
Draft / Rejected → Submit for internal review
→ Procurement Manager Review → Amount Gate
→ [amount >= 10000] Finance Review → Approved
→ [default] → Approved
After approval, host actions such as archive become available. ERP, PO creation, and payment logic stay outside DBFlow Core.
Business object
| Item | Value |
|---|---|
| Model | App\Models\ProcurementRequest |
| Workflow key | procurement_request_approval |
| Constants class | App\DBFlow\ProcurementRequest\ProcurementRequestWorkflow |
ProcurementRequest implements Workflowable and WorkflowContextInterface:
public function getWorkflowVariables(): array
{
return [
'amount' => (float) $this->amount,
'department' => $this->department,
// ...
];
}
Demo business status (ProcurementRequestStatus enum):
| Status | Meaning |
|---|---|
draft |
Editable request, not in review |
pending_review |
Submitted; workflow running or awaiting completion |
approved |
Workflow approved; ready for downstream purchasing steps |
rejected |
Workflow rejected; may return to draft |
archived |
Host archival after approval (not a DBFlow terminal state) |
Demo source paths:
| Area | Path |
|---|---|
| Model | app/Models/ProcurementRequest.php |
| Workflow constants | app/DBFlow/ProcurementRequest/ProcurementRequestWorkflow.php |
| Hooks | app/DBFlow/ProcurementRequest/ProcurementRequestWorkflowHooks.php |
| Status guard (optional) | app/DBFlow/ProcurementRequest/ProcurementRequestStatusGuard.php |
| Definition seeder | database/seeders/Demo/ProcurementRequestWorkflowSeeder.php |
| Integration test | tests/Feature/ProcurementRequestDbflowIntegrationTest.php |
Workflow
Node keys:
procurement_manager_reviewamount_gatefinance_review(high amount only)end_approved
Amount condition: amount >= 10000 (ProcurementRequestWorkflow::CONDITION_HIGH_AMOUNT).
ProcurementRequestWorkflowSeeder builds the JSON graph, validates, and publishes — same pipeline as refund disputes.
Hooks keep DBFlow and host columns aligned:
| Hook | Host update |
|---|---|
onStarted |
draft or rejected → pending_review, set submitted_at |
onApproved |
→ approved, set reviewed_at |
onRejected |
→ rejected, set reviewed_at |
onCancelled |
conservative return to draft (unless already archived) |
Implementation: app/DBFlow/ProcurementRequest/ProcurementRequestWorkflowHooks.php.
Why this matters
- Clear draft → review → approved lifecycle on a familiar business object
- Amount-based escalation without ERP complexity
- Shows guarded downstream actions after approval
- Builds on the same patterns as Refund Approval
Minimal code
Submit for internal review is visible when status is draft or rejected, no running workflow exists, and the record is not archived.
DBFlow::start(
ProcurementRequestWorkflow::KEY,
$record,
Auth::user(),
);
Assignees use My Tasks. Finance reviewers receive tasks only when amount >= 10000 routes through finance_review.
Guard post-approval business actions on host status — not workflow internals:
->visible(fn (ProcurementRequest $record): bool =>
$record->status === ProcurementRequestStatus::Approved
)
DBFlow does not ship ERP adapters. If you sync to an external system, invoke that from WorkflowHooks::onApproved() or a host job — keep integration code in app/, not in Core.
Filament integration
| Area | Path |
|---|---|
| Resource actions | app/Filament/Resources/ProcurementRequestResource/Concerns/HasLifecycleActions.php |
| Presenter | app/Filament/Resources/ProcurementRequestResource/Support/ProcurementRequestWorkflowPresenter.php |
ProcurementRequestResource composes HasLifecycleActions for submit, return-to-draft, and archive actions. ProcurementRequestWorkflowPresenter surfaces workflow metadata on the resource view.
Use Workflow Instances or the presenter link to inspect dbflow_workflow_logs through the Standard timeline. See Workflow Timeline.
What to try next
- Workflow Hooks → —
onStarted/onApproved/onRejected/onCancelledreference - Eloquent Models — traits and hooks overview
- Filament Resource Actions — action visibility patterns
- Refund Approval — simpler first example
Alpha caveats:
- Threshold (
10000) and assignee user IDs are demo constants archivedis a host-only state after approval — not an DBFlow end node- Cancel hook rolls back to
draft; adjust for your production policy - Published definition must exist before
DBFlow::start()— run Host Integration sync on deploy permission/callbackassignees requireregisterAssigneeResolver()— not Laravel permission names