Files
hub/app/Console/Commands/RunRecurringSchedules.php
kelly b47fc35857 feat: expand Management Suite with AR, budgets, expenses, fixed assets, recurring schedules, and CFO dashboard
Adds comprehensive financial management capabilities:
- Accounts Receivable (AR) with customers, invoices, payments
- Budget management with lines and variance tracking
- Expense tracking with approval workflow
- Fixed asset management with depreciation
- Recurring transaction schedules (AP, AR, journal entries)
- CFO dashboard with financial KPIs
- Cash flow forecasting
- Directory views for customers and vendors
- Division filtering support across all modules
2025-12-06 23:26:14 -07:00

104 lines
3.3 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Services\Accounting\RecurringSchedulerService;
use Carbon\Carbon;
use Illuminate\Console\Command;
class RunRecurringSchedules extends Command
{
protected $signature = 'recurring:run
{--date= : The date to run schedules for (YYYY-MM-DD, default: today)}
{--business= : Specific business ID to run schedules for}
{--dry-run : Preview what would be generated without actually creating transactions}';
protected $description = 'Run due recurring schedules to generate AR invoices, AP bills, and journal entries';
public function __construct(
protected RecurringSchedulerService $schedulerService
) {
parent::__construct();
}
public function handle(): int
{
$dateString = $this->option('date');
$businessId = $this->option('business') ? (int) $this->option('business') : null;
$dryRun = $this->option('dry-run');
$date = $dateString ? Carbon::parse($dateString) : now();
$this->info("Running recurring schedules for {$date->toDateString()}...");
if ($businessId) {
$this->info("Filtering to business ID: {$businessId}");
}
// Get due schedules
$dueSchedules = $this->schedulerService->getDueSchedules($date, $businessId);
if ($dueSchedules->isEmpty()) {
$this->info('No schedules are due for execution.');
return self::SUCCESS;
}
$this->info("Found {$dueSchedules->count()} schedule(s) due for execution.");
if ($dryRun) {
$this->warn('DRY RUN MODE - No transactions will be created.');
$this->table(
['ID', 'Name', 'Type', 'Business', 'Next Run Date', 'Auto Post'],
$dueSchedules->map(fn ($s) => [
$s->id,
$s->name,
$s->type_label,
$s->business->name ?? 'N/A',
$s->next_run_date->toDateString(),
$s->auto_post ? 'Yes' : 'No',
])
);
return self::SUCCESS;
}
// Run all due schedules
$results = $this->schedulerService->runAllDue($date, $businessId);
// Output results
$this->newLine();
$this->info('Execution Summary:');
$this->line(" Processed: {$results['processed']}");
$this->line(" Successful: {$results['success']}");
$this->line(" Failed: {$results['failed']}");
if (! empty($results['generated'])) {
$this->newLine();
$this->info('Generated Transactions:');
$this->table(
['Schedule', 'Type', 'Result ID'],
collect($results['generated'])->map(fn ($g) => [
$g['schedule_name'],
$g['type'],
$g['result_id'],
])
);
}
if (! empty($results['errors'])) {
$this->newLine();
$this->error('Errors:');
foreach ($results['errors'] as $error) {
$this->line(" [{$error['schedule_id']}] {$error['schedule_name']}: {$error['error']}");
}
return self::FAILURE;
}
return self::SUCCESS;
}
}