public function handle(): void
{
$order = Order::with(['billingAddress', 'user', 'items'])->find($this->orderId);
// On-site (POS) sales are invoiced through another flow and have no billing address.
if (Str::startsWith($order?->order_number ?? '', 'POS-')) {
return;
}
// What was actually paid is authoritative, not the list price of the items:
// a fully discounted order has total_amount = 0 and must not be invoiced.
if ((float) ($order?->total_amount ?? 0) <= 0) {
Log::info('Invoice skipped: order total is zero', ['order_id' => $this->orderId]);
return;
}
if (empty($order?->billingAddress)) {
Log::error('Invoice skipped: billing address is empty', ['order_id' => $this->orderId]);
return;
}
// ... build the invoice and hand it to the provider configured for this organiser
}
/** No response at all = network failure (offline, timeout). A 4xx/5xx reply is not. */
function isNetworkError(error: unknown): boolean {
return axios.isAxiosError(error) && !error.response;
}
/**
* Retries a call once on a network failure. ONLY use it for calls that are
* safe to repeat: reads, or writes that are idempotent on the server.
*/
async function withNetworkRetry<T>(call: () => Promise<T>, retries = 1): Promise<T> {
try {
return await call();
} catch (error) {
if (retries > 0 && isNetworkError(error)) {
await new Promise((resolve) => setTimeout(resolve, 700));
return withNetworkRetry(call, retries - 1);
}
throw error;
}
}
Connects online stores to over 400 wholesalers, with automatic price, stock and order handling, no developer needed. Behind it, it processes up to millions of records per second, reshapes and saves them by rules with no room for error, keeping states and statistics too.
public function evaluate(User $user, string $channel, ?CarbonInterface $now = null): PolicyDecision
{
$now = ($now ?? Carbon::now())->copy();
$reasons = []; // collect ALL reasons, not just the first, so a preview can explain every skip
if (! (bool) $this->cfg('enabled', false)) {
$reasons[] = 'kill_switch_off';
}
if ($user->is_banned || $user->deleted_at) {
$reasons[] = 'account_blocked';
}
if ($channel === self::CHANNEL_EMAIL) {
if (! (bool) $user->is_subscribed) {
$reasons[] = 'no_marketing_consent';
}
if ($this->emailSuppressed(trim((string) $user->email))) {
$reasons[] = 'email_suppressed';
}
} elseif ($channel === self::CHANNEL_PUSH) {
if ($this->isQuietHour($now)) {
$reasons[] = 'quiet_hours';
}
}
// ... weekly cap from the shared marketing ledger, then the holdout control group
}
/** Temporarily disable logging, e.g. during a bulk import or seeding. */
public static function withoutLogging(callable $callback): mixed
{
$previous = self::$paused;
self::$paused = true;
try {
return $callback();
} finally {
self::$paused = $previous;
}
}
/** On `updating`, keep the original row in memory, so no extra SELECT is needed. */
public function captureOriginal(Model $model): void
{
if (! $this->enabled($model)) {
return;
}
$this->originals[spl_object_id($model)] = $model->getOriginal();
}