diff --git a/app/Console/BaseCommand.php b/app/Console/BaseCommand.php index 9d662bd7..86a511e1 100644 --- a/app/Console/BaseCommand.php +++ b/app/Console/BaseCommand.php @@ -3,13 +3,30 @@ namespace App\Console; use Illuminate\Console\Command; +use Monolog\Handler\StreamHandler; use Symfony\Component\Process\Process; class BaseCommand extends Command { + /** + * Splice the logger and replace the handler to direct + * everything to stdout as well as the log + */ + public function redirectLoggingToStdout() + { + $logger = app(\Illuminate\Log\Logger::class); + $handlers = $logger->getHandlers(); + + try { + $handlers[] = new StreamHandler('php://stdout'); + $logger->setHandlers($handlers); + } catch (\Exception $e) { + $this->error('Couldn\'t splice the logger'); + } + } /** - * Streaming file read + * Streaming file reader * @param $filename * @return \Generator */ @@ -33,6 +50,8 @@ class BaseCommand extends Command * @param $cmd * @param bool $return * @return string + * @throws \Symfony\Component\Process\Exception\RuntimeException + * @throws \Symfony\Component\Process\Exception\LogicException */ public function runCommand($cmd, $return=false, $verbose=true) { @@ -46,18 +65,12 @@ class BaseCommand extends Command $val = ''; $process = new Process($cmd); - $process->run(function ($type, $buffer) use ($return, $val) { + $process->run(function ($type, $buffer) use ($return, &$val) { if ($return) { $val .= $buffer; } else { echo $buffer; } - - /*if (Process::ERR === $type) { - echo $buffer; - } else { - echo $buffer; - }*/ }); return $val; diff --git a/app/Console/Cron/Monthly.php b/app/Console/Cron/Monthly.php new file mode 100644 index 00000000..e17b3deb --- /dev/null +++ b/app/Console/Cron/Monthly.php @@ -0,0 +1,24 @@ +redirectLoggingToStdout(); + event(new CronMonthly()); + } +} diff --git a/app/Console/Cron/Nightly.php b/app/Console/Cron/Nightly.php new file mode 100644 index 00000000..4f4b6b53 --- /dev/null +++ b/app/Console/Cron/Nightly.php @@ -0,0 +1,24 @@ +redirectLoggingToStdout(); + event(new CronNightly()); + } +} diff --git a/app/Console/Cron/Weekly.php b/app/Console/Cron/Weekly.php new file mode 100644 index 00000000..e14aeb08 --- /dev/null +++ b/app/Console/Cron/Weekly.php @@ -0,0 +1,24 @@ +redirectLoggingToStdout(); + event(new CronMonthly()); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index af28558c..a397987e 100755 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,9 @@ namespace App\Console; +use App\Console\Cron\Monthly; +use App\Console\Cron\Nightly; +use App\Console\Cron\Weekly; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -25,24 +28,24 @@ class Kernel extends ConsoleKernel /** * Define the application's command schedule. - * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */ - protected function schedule(Schedule $schedule) + protected function schedule(Schedule $schedule): void { - // $schedule->command('inspire') - // ->hourly(); + $schedule->command(Nightly::class)->dailyAt('01:00'); + $schedule->command(Weekly::class)->weeklyOn(0); + $schedule->command(Monthly::class)->monthlyOn(1); } /** * Register the Closure based commands for the application. - * * @return void */ - protected function commands() + protected function commands(): void { require app_path('Routes/console.php'); $this->load(__DIR__ . '/Commands'); + $this->load(__DIR__ . '/Cron'); } } diff --git a/app/Console/Logger.php b/app/Console/Logger.php new file mode 100644 index 00000000..c1945a31 --- /dev/null +++ b/app/Console/Logger.php @@ -0,0 +1,23 @@ +pushHandler(new StreamHandler('php://stdout')); + } catch (\Exception $e) { + } + + return $logger; + } +} diff --git a/app/Database/migrations/2018_02_28_231807_create_journal_transactions_table.php b/app/Database/migrations/2018_02_28_231807_create_journal_transactions_table.php index 5588a2cc..52d6e828 100644 --- a/app/Database/migrations/2018_02_28_231807_create_journal_transactions_table.php +++ b/app/Database/migrations/2018_02_28_231807_create_journal_transactions_table.php @@ -25,7 +25,7 @@ class CreateJournalTransactionsTable extends Migration $table->string('ref_class', 50)->nullable(); $table->string('ref_class_id', 36)->nullable(); $table->timestamps(); - $table->dateTime('post_date'); + $table->date('post_date'); $table->primary('id'); $table->index('journal_id'); diff --git a/app/Database/seeds/sample.yml b/app/Database/seeds/sample.yml index 0e997378..45870c04 100644 --- a/app/Database/seeds/sample.yml +++ b/app/Database/seeds/sample.yml @@ -216,6 +216,22 @@ expenses: ref_class_id: 1 created_at: now updated_at: now + - name: Catering Staff + amount: 1000 + type: 1 + active: 1 + ref_class: App\Models\Subfleet + ref_class_id: 1 + created_at: now + updated_at: now + - name: Maintenance + amount: 1000 + type: 1 + active: 1 + ref_class: App\Models\Aircraft + ref_class_id: 1 + created_at: now + updated_at: now fares: - id: 1 @@ -448,7 +464,7 @@ journals: id: 1 ledger_id: null type: 0 - balance: 23710000 + balance: 7870000 currency: USD morphed_type: App\Models\Airline morphed_id: 1 @@ -458,7 +474,7 @@ journals: id: 2 ledger_id: null type: 1 - balance: 45000 + balance: 15000 currency: USD morphed_type: App\Models\User morphed_id: 1 diff --git a/app/Events/CronMonthly.php b/app/Events/CronMonthly.php new file mode 100644 index 00000000..d5a776d1 --- /dev/null +++ b/app/Events/CronMonthly.php @@ -0,0 +1,21 @@ +dfSvc = $dfSvc; + } + + /** + * Apply all of the expenses for a month + * @param CronMonthly $event + * @throws \UnexpectedValueException + * @throws \InvalidArgumentException + * @throws \Prettus\Validator\Exceptions\ValidatorException + */ + public function handle(CronMonthly $event) + { + $this->dfSvc->processExpenses(ExpenseType::MONTHLY); + } +} diff --git a/app/Listeners/Cron/Nightly/ApplyExpenses.php b/app/Listeners/Cron/Nightly/ApplyExpenses.php new file mode 100644 index 00000000..e6612246 --- /dev/null +++ b/app/Listeners/Cron/Nightly/ApplyExpenses.php @@ -0,0 +1,33 @@ +dfSvc = $dfSvc; + } + + /** + * Apply all of the expenses for a day + * @param CronNightly $event + * @throws \UnexpectedValueException + * @throws \InvalidArgumentException + * @throws \Prettus\Validator\Exceptions\ValidatorException + */ + public function handle(CronNightly $event): void + { + $this->dfSvc->processExpenses(ExpenseType::DAILY); + } +} diff --git a/app/Listeners/Cron/Nightly/RecalculateBalances.php b/app/Listeners/Cron/Nightly/RecalculateBalances.php new file mode 100644 index 00000000..b643c9fa --- /dev/null +++ b/app/Listeners/Cron/Nightly/RecalculateBalances.php @@ -0,0 +1,57 @@ +journalRepo = $journalRepo; + } + + /** + * Recalculate all the balances for the different ledgers + * @param CronNightly $event + * @throws \UnexpectedValueException + * @throws \InvalidArgumentException + */ + public function handle(CronNightly $event): void + { + Log::info('Recalculating balances'); + + $journals = Journal::all(); + foreach ($journals as $journal) { + + $where = ['journal_id' => $journal->id]; + $credits = Money::create(JournalTransaction::where($where)->sum('credit') ?: 0); + $debits = Money::create(JournalTransaction::where($where)->sum('debit') ?: 0); + $balance = $credits->subtract($debits); + + Log::info('Adjusting balance on ' . + $journal->morphed_type . ':' . $journal->morphed_id + . ' from ' . $journal->balance . ' to ' . $balance); + + $journal->balance = $balance->getAmount(); + $journal->save(); + } + + Log::info('Done calculating balances'); + } +} diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 9dca8737..b696ee51 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -4,8 +4,11 @@ namespace App\Models; /** * Class Expense + * @property int airline_id * @property float amount * @property string name + * @property string ref_class + * @property string ref_class_id * @package App\Models */ class Expense extends BaseModel @@ -33,6 +36,27 @@ class Expense extends BaseModel 'charge_to_user' => 'bool', ]; + /** + * Get the referring object + */ + public function getReference() + { + if (!$this->ref_class || !$this->ref_class_id) { + return null; + } + + if($this->ref_class === __CLASS__) { + return $this; + } + + try { + $klass = new $this->ref_class; + return $klass->find($this->ref_class_id); + } catch (\Exception $e) { + return null; + } + } + /** * Foreign Keys */ diff --git a/app/Models/Journal.php b/app/Models/Journal.php index 1a8545e0..682c9ad8 100644 --- a/app/Models/Journal.php +++ b/app/Models/Journal.php @@ -11,7 +11,7 @@ use Carbon\Carbon; /** * Class Journal - * @package Scottlaurent\Accounting + * @property mixed id * @property Money $balance * @property string $currency * @property Carbon $updated_at diff --git a/app/Models/JournalTransaction.php b/app/Models/JournalTransaction.php index 3f8a962b..fd7d7c3b 100644 --- a/app/Models/JournalTransaction.php +++ b/app/Models/JournalTransaction.php @@ -41,6 +41,13 @@ class JournalTransaction extends BaseModel 'tags' => 'array', ]; + protected $dateFormat = 'Y-m-d'; + protected $dates = [ + 'created_at', + 'updated_at', + 'post_date', + ]; + /** * Callbacks * @throws \UnexpectedValueException diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index b2345a73..75012654 100755 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -2,11 +2,15 @@ namespace App\Providers; +use App\Events\CronMonthly; +use App\Events\CronNightly; +use App\Events\CronWeekly; +use App\Events\Expenses; +use App\Listeners\Cron\Nightly\RecalculateBalances; +use App\Listeners\ExpenseListener; use App\Listeners\FinanceEvents; use App\Listeners\NotificationEvents; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; -use App\Listeners\ExpenseListener; -use App\Events\Expenses; class EventServiceProvider extends ServiceProvider @@ -20,6 +24,19 @@ class EventServiceProvider extends ServiceProvider Expenses::class => [ ExpenseListener::class ], + + # Cron hooks + CronNightly::class => [ + \App\Listeners\Cron\Nightly\ApplyExpenses::class, + RecalculateBalances::class, + ], + + CronWeekly::class => [ + ], + + CronMonthly::class => [ + \App\Listeners\Cron\Monthly\ApplyExpenses::class + ], ]; protected $subscribe = [ diff --git a/app/Repositories/JournalRepository.php b/app/Repositories/JournalRepository.php index 19d999b2..d1573114 100644 --- a/app/Repositories/JournalRepository.php +++ b/app/Repositories/JournalRepository.php @@ -27,6 +27,20 @@ class JournalRepository extends BaseRepository implements CacheableInterface return JournalTransaction::class; } + /** + * Return a Y-m-d string for the post date + * @param Carbon $date + * @return string + */ + public function formatPostDate(Carbon $date=null) + { + if(!$date) { + return null; + } + + return $date->setTimezone('UTC')->toDateString(); + } + /** * Post a new transaction to a journal, and also adjust the balance * on the transaction itself. A cron will run to reconcile the journal @@ -55,22 +69,26 @@ class JournalRepository extends BaseRepository implements CacheableInterface ) { # tags can be passed in a list - if($tags && \is_array($tags)) { + if ($tags && \is_array($tags)) { $tags = implode(',', $tags); } + if(!$post_date) { + $post_date = Carbon::now('UTC'); + } + $attrs = [ - 'journal_id' => $journal->id, - 'credit' => $credit ? $credit->getAmount():null, - 'debit' => $debit ? $debit->getAmount():null, - 'currency' => config('phpvms.currency'), - 'memo' => $memo, - 'post_date' => $post_date ?? Carbon::now(), + 'journal_id' => $journal->id, + 'credit' => $credit ? $credit->getAmount() : null, + 'debit' => $debit ? $debit->getAmount() : null, + 'currency' => config('phpvms.currency'), + 'memo' => $memo, + 'post_date' => $post_date, 'transaction_group' => $transaction_group, - 'tags' => $tags + 'tags' => $tags ]; - if($reference !== null) { + if ($reference !== null) { $attrs['ref_class'] = \get_class($reference); $attrs['ref_class_id'] = $reference->id; } @@ -112,6 +130,8 @@ class JournalRepository extends BaseRepository implements CacheableInterface * @param Carbon|null $start_date * @param null $transaction_group * @return Money + * @throws \UnexpectedValueException + * @throws \InvalidArgumentException */ public function getCreditBalanceBetween( Carbon $date, @@ -124,7 +144,7 @@ class JournalRepository extends BaseRepository implements CacheableInterface ['post_date', '<=', $date] ]; - if($journal) { + if ($journal) { $where['journal_id'] = $journal->id; } @@ -152,10 +172,13 @@ class JournalRepository extends BaseRepository implements CacheableInterface */ public function getDebitBalanceBetween( Carbon $date, - Journal $journal=null, - Carbon $start_date=null, - $transaction_group=null - ): Money { + Journal $journal = null, + Carbon $start_date = null, + $transaction_group = null + ): Money + { + + $date = $this->formatPostDate($date); $where = [ ['post_date', '<=', $date] @@ -165,11 +188,12 @@ class JournalRepository extends BaseRepository implements CacheableInterface $where['journal_id'] = $journal->id; } - if($start_date) { + if ($start_date) { + $start_date = $this->formatPostDate($start_date); $where[] = ['post_date', '>=', $start_date]; } - if($transaction_group) { + if ($transaction_group) { $where['transaction_group'] = $transaction_group; } @@ -184,25 +208,31 @@ class JournalRepository extends BaseRepository implements CacheableInterface * Return all transactions for a given object * @param $object * @param null $journal + * @param Carbon|null $date * @return array * @throws \UnexpectedValueException * @throws \InvalidArgumentException */ - public function getAllForObject($object, $journal=null) + public function getAllForObject($object, $journal = null, Carbon $date = null) { $where = [ 'ref_class' => \get_class($object), 'ref_class_id' => $object->id, ]; - if($journal) { + if ($journal) { $where['journal_id'] = $journal->id; } + if ($date) { + $date = $this->formatPostDate($date); + $where[] = ['post_date', '=', $date]; + } + $transactions = $this->whereOrder($where, [ - 'credit' => 'desc', - 'debit' => 'desc' - ])->get(); + 'credit' => 'desc', + 'debit' => 'desc' + ])->get(); return [ 'credits' => new Money($transactions->sum('credit')), diff --git a/app/Services/Finance/DailyFinanceService.php b/app/Services/Finance/DailyFinanceService.php deleted file mode 100644 index 46efa754..00000000 --- a/app/Services/Finance/DailyFinanceService.php +++ /dev/null @@ -1,20 +0,0 @@ -journalRepo = $journalRepo; + } + + /** + * Determine the journal to charge to, otherwise, it's charged + * to every airline journal + * @param Expense $expense + * @return \Generator + */ + protected function findJournals(Expense $expense) + { + if($expense->airline_id) { + $airline = Airline::find($expense->airline_id)->first(['id', 'icao']); + Log::info('Charging to ' . $airline->icao); + yield $airline->journal; + } else { + $airlines = Airline::all(['id', 'icao']); + foreach($airlines as $airline) { + Log::info('Charging to ' . $airline->icao); + yield $airline->journal; + } + } + } + + /** + * Get the name of the transaction group from the expense + * @param Expense $expense + * @return array + */ + protected function getMemoAndGroup(Expense $expense): array + { + $klass = 'Expense'; + if ($expense->ref_class) { + $ref = explode('\\', $expense->ref_class); + $klass = end($ref); + $obj = $expense->getReference(); + } + + if ($klass === 'Airport') { + $memo = "Airport Expense: {$expense->name} ({$expense->ref_class_id})"; + $transaction_group = "Airport: {$expense->ref_class_id}"; + } elseif ($klass === 'Subfleet') { + $memo = "Subfleet Expense: {$expense->name}"; + $transaction_group = "Subfleet: {$expense->name}"; + } elseif ($klass === 'Aircraft') { + $memo = "Aircraft Expense: {$expense->name} ({$obj->name})"; + $transaction_group = "Aircraft: {$expense->name} ({$obj->name}-{$obj->registration})"; + } else { + $memo = "Expense: {$expense->name}"; + $transaction_group = "Expense: {$expense->name}"; + } + + return [$memo, $transaction_group]; + } + + + /** + * Run all of the daily expense/financials + * @param int $type + * @throws \UnexpectedValueException + * @throws \InvalidArgumentException + * @throws \Prettus\Validator\Exceptions\ValidatorException + */ + public function processExpenses($type=ExpenseType::DAILY): void + { + $expenses = Expense::where(['type' => $type])->get(); + + $tag = 'expense_recurring'; + if($type === ExpenseType::DAILY) { + $tag = 'expenses_daily'; + } elseif ($type === ExpenseType::MONTHLY) { + $tag === 'expenses_monthly'; + } + + /** + * @var $expenses Expense[] + */ + foreach ($expenses as $expense) { + + # Apply the expenses to the appropriate journals + $journals = $this->findJournals($expense); + foreach($journals as $journal) { + + $amount = $expense->amount; + + # Has this expense already been charged? Check + # against this specific journal, on today + $w = [ + 'journal_id' => $journal->id, + 'ref_class' => Expense::class, + 'ref_class_id' => $expense->id, + 'post_date' => \Carbon::now('UTC')->format('Y-m-d'), + ]; + + $found = JournalTransaction::where($w)->count(['id']); + if($found > 0) { + Log::info('Expense "'.$expense->name.'" already charged for today, skipping'); + continue; + } + + [$memo, $ta_group] = $this->getMemoAndGroup($expense); + + $this->journalRepo->post( + $journal, + null, + Money::createFromAmount($amount), + $expense, + $memo, + null, + $ta_group, + $tag + ); + + Log::info('Expense memo: "'.$memo.'"; group: "'. $ta_group. '" charged!'); + } + } + } +} diff --git a/composer.lock b/composer.lock index b72b4e23..ed63cd16 100644 --- a/composer.lock +++ b/composer.lock @@ -876,16 +876,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.49", + "version": "v0.50", "source": { "type": "git", "url": "https://github.com/google/google-api-php-client-services.git", - "reference": "7552d7d1bb92e933fc93088014c8c2555c0feab6" + "reference": "3e792254734e4444dd8a594e927926f28de2e609" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/google/google-api-php-client-services/zipball/7552d7d1bb92e933fc93088014c8c2555c0feab6", - "reference": "7552d7d1bb92e933fc93088014c8c2555c0feab6", + "url": "https://api.github.com/repos/google/google-api-php-client-services/zipball/3e792254734e4444dd8a594e927926f28de2e609", + "reference": "3e792254734e4444dd8a594e927926f28de2e609", "shasum": "" }, "require": { @@ -909,7 +909,7 @@ "keywords": [ "google" ], - "time": "2018-03-04T00:24:05+00:00" + "time": "2018-03-10T00:23:06+00:00" }, { "name": "google/auth", @@ -1567,16 +1567,16 @@ }, { "name": "laravel/framework", - "version": "v5.6.11", + "version": "v5.6.12", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "195ba6a67bdad2a23105c7ab410cd43e0f20bb73" + "reference": "82d8165d1ea86bdd81ddfa1db9343fa19e7d1450" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/195ba6a67bdad2a23105c7ab410cd43e0f20bb73", - "reference": "195ba6a67bdad2a23105c7ab410cd43e0f20bb73", + "url": "https://api.github.com/repos/laravel/framework/zipball/82d8165d1ea86bdd81ddfa1db9343fa19e7d1450", + "reference": "82d8165d1ea86bdd81ddfa1db9343fa19e7d1450", "shasum": "" }, "require": { @@ -1585,7 +1585,7 @@ "erusev/parsedown": "~1.7", "ext-mbstring": "*", "ext-openssl": "*", - "league/flysystem": "~1.0", + "league/flysystem": "^1.0.8", "monolog/monolog": "~1.12", "nesbot/carbon": "^1.24.1", "php": "^7.1.3", @@ -1701,7 +1701,7 @@ "framework", "laravel" ], - "time": "2018-03-09T16:53:27+00:00" + "time": "2018-03-14T17:29:38+00:00" }, { "name": "laravelcollective/html", @@ -2162,16 +2162,16 @@ }, { "name": "nesbot/carbon", - "version": "1.24.1", + "version": "1.24.2", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "ef12cbd8ba5ce624f0a6a95e0850c4cc13e71e41" + "reference": "bba6c6e410c6b4317e37a9474aeaa753808c3875" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/ef12cbd8ba5ce624f0a6a95e0850c4cc13e71e41", - "reference": "ef12cbd8ba5ce624f0a6a95e0850c4cc13e71e41", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bba6c6e410c6b4317e37a9474aeaa753808c3875", + "reference": "bba6c6e410c6b4317e37a9474aeaa753808c3875", "shasum": "" }, "require": { @@ -2211,7 +2211,7 @@ "datetime", "time" ], - "time": "2018-03-09T15:49:34+00:00" + "time": "2018-03-10T10:10:14+00:00" }, { "name": "nikic/php-parser", @@ -2362,7 +2362,7 @@ "lib/random.php" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "MIT" ], @@ -2588,16 +2588,16 @@ }, { "name": "pragmarx/version", - "version": "v0.2.5", + "version": "v0.2.6", "source": { "type": "git", "url": "https://github.com/antonioribeiro/version.git", - "reference": "ed34e37904067bdb15857d3f2bcc11683f37eb84" + "reference": "73439723bf8f32534e0a79a07a914971b729ec1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/version/zipball/ed34e37904067bdb15857d3f2bcc11683f37eb84", - "reference": "ed34e37904067bdb15857d3f2bcc11683f37eb84", + "url": "https://api.github.com/repos/antonioribeiro/version/zipball/73439723bf8f32534e0a79a07a914971b729ec1e", + "reference": "73439723bf8f32534e0a79a07a914971b729ec1e", "shasum": "" }, "require": { @@ -2645,7 +2645,7 @@ "version", "versioning" ], - "time": "2018-02-10T17:40:28+00:00" + "time": "2018-03-13T00:04:06+00:00" }, { "name": "pragmarx/yaml", @@ -2795,7 +2795,7 @@ "Prettus\\Validator\\": "src/Prettus/Validator/" } }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "authors": [ { "name": "Anderson Andrade", @@ -2884,7 +2884,7 @@ "Psr\\Container\\": "src/" } }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "MIT" ], @@ -3439,7 +3439,7 @@ "lib/swift_required.php" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "MIT" ], @@ -5387,7 +5387,7 @@ "Faker\\": "src/Faker/" } }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "MIT" ], @@ -5739,7 +5739,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -5786,7 +5786,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -5843,7 +5843,7 @@ ] } }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "MIT" ], @@ -6606,7 +6606,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -6658,7 +6658,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -6726,7 +6726,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -6776,7 +6776,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -6821,7 +6821,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -6866,7 +6866,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], @@ -7055,7 +7055,7 @@ "src/" ] }, - "notification-url": "https://packagist.org/downloads/", + "notification-url": "http://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], diff --git a/config/logging.php b/config/logging.php index b42babb7..f6fc76c3 100644 --- a/config/logging.php +++ b/config/logging.php @@ -28,7 +28,16 @@ return [ 'channels' => [ 'stack' => [ 'driver' => 'stack', - 'channels' => ['daily'], + 'channels' => [ + 'daily', + # PHP_SAPI === 'cli' ? 'console' : 'daily', + ], + ], + 'console' => [ + 'driver' => 'stack', + 'channels' => [ + 'stdout', + ], ], 'single' => [ 'driver' => 'single', @@ -48,6 +57,10 @@ return [ 'emoji' => ':boom:', 'level' => 'critical', ], + 'stdout' => [ + 'driver' => 'custom', + 'via' => \App\Console\Logger::class, + ], 'syslog' => [ 'driver' => 'syslog', 'level' => 'debug',