info('There is no business for auditing.'); continue; } $business = Business::orderBy('calculated_at')->first(); if ($business === null) { continue; } if ($business->calculated_at->isFuture()) { continue; } $next_month = jdate($business->calculated_at)->addMonths(); [$year, $month, $day] = CalendarUtils::toGregorian( $next_month->getYear(), $next_month->getMonth(), 1 ); $now = Carbon::createFromDate($year, $month, $day); $now->setTime(0, 0, 0); if ($now->isFuture()) { $now = Carbon::now(); } // if calculated_at less than an hour stop if ($now->diffInMinutes($business->calculated_at) <= 59) { $this->info('Must be one hour after the last audit.'); $this->ensureLockIsWritten(); continue; } try { DB::beginTransaction(); // Fixed amounts of expenses $business->load('users', 'files'); $costs = 0; $costs += $this->calculateCostOfBusinessUsers($business, $now); $costs += $this->calculateCostOfBusinessFiles($business, $now); // increment and decrement of wallet in php // deduct costs from your business wallet // make sure save the calculated_at $business->update([ 'wallet' => $business->wallet - $costs, 'calculated_at' => $now, ]); DB::commit(); $this->info("The business #{$business->id} was audited."); } catch (Throwable $throwable) { throw $throwable; DB::rollback(); report($throwable); continue; } } } public function calculateCostOfBusinessUsers($business, $now) { $user_fee = enum('business.fee.user'); $recorded_month = jdate($business->calculated_at)->format("Y-m-01"); if ($business->users->isEmpty()) { return 0; } // get business employee $users_cost = $business->cost ->where('type', '=', Cost::USER_TYPE) ->where('fee', '=', $user_fee) ->where('month', '=', $recorded_month) ->where('amount', '=', $business->users->count()) ->first(); if ($users_cost === null) { $business->cost()->create([ 'type' => Cost::USER_TYPE, 'month' => $recorded_month, 'amount' => $business->users->count(), 'fee' => $user_fee, 'duration' => $duration = $now->diffInMinutes($business->calculated_at), // from the created_at time of the newset fifth user 'additional' => $business->users->pluck('id')->toArray(), ]); } else { $users_cost->update([ 'duration' => $duration = $now->diffInMinutes($business->calculated_at) + $users_cost->duration, // last calc - (current month - now else last calc - end of the past month), 'additional' => $business->users->pluck('id')->toArray(), ]); } return $user_fee * $duration; } public function calculateCostOfBusinessFiles($business, $now) { $file_fee = enum('business.fee.file'); $calculated_at = $business->calculated_at; $recorded_month = jdate($business->calculated_at)->format("Y-m-01"); // do the math in php $packs = intdiv($business->files_volume, 200); if ($packs === 0) { return 0; } else { $packs--; } $files = $business->cost ->where('type', '=', Cost::FILE_TYPE) ->where('fee', '=', $file_fee) ->where('month', '=', $recorded_month) ->where('amount', '=', $packs) ->first(); if ($files === null) { $business->cost()->create([ 'type' => Cost::FILE_TYPE, 'month' => $recorded_month, 'amount' => $packs, 'fee' => $file_fee, 'duration' => $duration = $now->diffInMinutes($calculated_at), // how to determine the file?, 'additional' => ['volume' => $business->files_volume], ]); } else { $files->update([ 'duration' => $duration = $now->diffInMinutes($calculated_at) + $files->duration, // last calc - (current month - now else last calc - end of the past month),, 'additional' => ['volume' => $business->files_volume], ]); } return $file_fee * $duration; } public function ensureLockIsWritten(): void { Cache::put('lock', true, 3600); while (Cache::get('lock', false) === false) { // prevent } } }