Files
hub/app/Http/Controllers/Seller/Crm/AutomationController.php
kelly 539cd0e4e1 fix: pass $business to all CRM views and add sidebar menu ordering
- Fix all CRM controllers to explicitly pass $business to views
- Add scopeOutstanding() to CrmInvoice model
- Add fallback in CRM layout to get $business from route
- Reorder sidebar menu sections (Overview, Inbox, Commerce, etc.)
- Add delivery location selector to quote create form
- Add migration for location_id on crm_quotes table
2025-12-08 12:59:21 -07:00

257 lines
8.9 KiB
PHP

<?php
namespace App\Http\Controllers\Seller\Crm;
use App\Http\Controllers\Controller;
use App\Models\Business;
use App\Models\Crm\CrmAutomation;
use App\Models\Crm\CrmAutomationAction;
use App\Models\Crm\CrmAutomationCondition;
use Illuminate\Http\Request;
class AutomationController extends Controller
{
/**
* List automations
*/
public function index(Request $request, Business $business)
{
$automations = CrmAutomation::forBusiness($business->id)
->with('creator')
->withCount(['logs as successful_runs' => fn ($q) => $q->completed()])
->orderByDesc('created_at')
->paginate(25);
return view('seller.crm.automations.index', compact('automations', 'business'));
}
/**
* Show automation builder
*/
public function create(Request $request, Business $business)
{
$triggers = CrmAutomation::TRIGGERS;
$operators = CrmAutomationCondition::OPERATORS;
$actionTypes = CrmAutomationAction::TYPES;
return view('seller.crm.automations.create', compact('triggers', 'operators', 'actionTypes', 'business'));
}
/**
* Store automation
*/
public function store(Request $request, Business $business)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string|max:1000',
'trigger_type' => 'required|string',
'trigger_config' => 'nullable|array',
'is_active' => 'boolean',
'stop_on_error' => 'boolean',
'max_runs_per_day' => 'nullable|integer|min:1',
'conditions' => 'nullable|array',
'conditions.*.field' => 'required|string',
'conditions.*.operator' => 'required|string',
'conditions.*.value' => 'nullable',
'conditions.*.logic_operator' => 'nullable|in:AND,OR',
'actions' => 'required|array|min:1',
'actions.*.type' => 'required|string',
'actions.*.config' => 'nullable|array',
]);
$automation = CrmAutomation::create([
'business_id' => $business->id,
'created_by' => $request->user()->id,
'name' => $validated['name'],
'description' => $validated['description'],
'trigger_type' => $validated['trigger_type'],
'trigger_config' => $validated['trigger_config'] ?? [],
'is_active' => $validated['is_active'] ?? false,
'stop_on_error' => $validated['stop_on_error'] ?? true,
'max_runs_per_day' => $validated['max_runs_per_day'],
]);
// Create conditions
if (! empty($validated['conditions'])) {
foreach ($validated['conditions'] as $index => $condition) {
CrmAutomationCondition::create([
'automation_id' => $automation->id,
'field' => $condition['field'],
'operator' => $condition['operator'],
'value' => $condition['value'],
'logic_operator' => $condition['logic_operator'] ?? 'AND',
'order' => $index,
]);
}
}
// Create actions
foreach ($validated['actions'] as $index => $action) {
CrmAutomationAction::create([
'automation_id' => $automation->id,
'type' => $action['type'],
'config' => $action['config'] ?? [],
'order' => $index,
'is_active' => true,
]);
}
return redirect()->route('seller.business.crm.automations.show', [$business, $automation])
->with('success', 'Automation created successfully.');
}
/**
* Show automation details
*/
public function show(Request $request, Business $business, CrmAutomation $automation)
{
if ($automation->business_id !== $business->id) {
abort(404);
}
$automation->load(['conditions', 'actions', 'logs' => fn ($q) => $q->latest()->limit(50)]);
return view('seller.crm.automations.show', compact('automation', 'business'));
}
/**
* Edit automation
*/
public function edit(Request $request, Business $business, CrmAutomation $automation)
{
if ($automation->business_id !== $business->id) {
abort(404);
}
$automation->load(['conditions', 'actions']);
$triggers = CrmAutomation::TRIGGERS;
$operators = CrmAutomationCondition::OPERATORS;
$actionTypes = CrmAutomationAction::TYPES;
return view('seller.crm.automations.edit', compact('automation', 'triggers', 'operators', 'actionTypes', 'business'));
}
/**
* Update automation
*/
public function update(Request $request, Business $business, CrmAutomation $automation)
{
if ($automation->business_id !== $business->id) {
abort(404);
}
$validated = $request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string|max:1000',
'trigger_type' => 'required|string',
'trigger_config' => 'nullable|array',
'is_active' => 'boolean',
'stop_on_error' => 'boolean',
'max_runs_per_day' => 'nullable|integer|min:1',
'conditions' => 'nullable|array',
'conditions.*.field' => 'required|string',
'conditions.*.operator' => 'required|string',
'conditions.*.value' => 'nullable',
'conditions.*.logic_operator' => 'nullable|in:AND,OR',
'actions' => 'required|array|min:1',
'actions.*.type' => 'required|string',
'actions.*.config' => 'nullable|array',
]);
$automation->update([
'name' => $validated['name'],
'description' => $validated['description'],
'trigger_type' => $validated['trigger_type'],
'trigger_config' => $validated['trigger_config'] ?? [],
'is_active' => $validated['is_active'] ?? false,
'stop_on_error' => $validated['stop_on_error'] ?? true,
'max_runs_per_day' => $validated['max_runs_per_day'],
]);
// Clear error if reactivating
if ($validated['is_active'] ?? false) {
$automation->clearError();
}
// Replace conditions
$automation->conditions()->delete();
if (! empty($validated['conditions'])) {
foreach ($validated['conditions'] as $index => $condition) {
CrmAutomationCondition::create([
'automation_id' => $automation->id,
'field' => $condition['field'],
'operator' => $condition['operator'],
'value' => $condition['value'],
'logic_operator' => $condition['logic_operator'] ?? 'AND',
'order' => $index,
]);
}
}
// Replace actions
$automation->actions()->delete();
foreach ($validated['actions'] as $index => $action) {
CrmAutomationAction::create([
'automation_id' => $automation->id,
'type' => $action['type'],
'config' => $action['config'] ?? [],
'order' => $index,
'is_active' => true,
]);
}
return redirect()->route('seller.business.crm.automations.show', [$business, $automation])
->with('success', 'Automation updated successfully.');
}
/**
* Toggle automation active status
*/
public function toggle(Request $request, Business $business, CrmAutomation $automation)
{
if ($automation->business_id !== $business->id) {
abort(404);
}
$automation->update(['is_active' => ! $automation->is_active]);
if ($automation->is_active) {
$automation->clearError();
}
return back()->with('success', $automation->is_active ? 'Automation activated.' : 'Automation deactivated.');
}
/**
* Duplicate automation
*/
public function duplicate(Request $request, Business $business, CrmAutomation $automation)
{
if ($automation->business_id !== $business->id) {
abort(404);
}
$copy = $automation->duplicate();
return redirect()->route('seller.business.crm.automations.edit', [$business, $copy])
->with('success', 'Automation duplicated. Make your changes and activate when ready.');
}
/**
* Delete automation
*/
public function destroy(Request $request, Business $business, CrmAutomation $automation)
{
if ($automation->business_id !== $business->id) {
abort(404);
}
$automation->delete();
return redirect()->route('seller.business.crm.automations.index', $business)
->with('success', 'Automation deleted.');
}
}