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;
}
}
Webáruházak összekötése 400 feletti nagykereskedővel, automatikus ár-, készlet- és rendeléskezeléssel, fejlesztői tudás nélkül. A háttérben másodpercenként akár több millió adatot dolgoz fel, szabályok alapján alakít át és ment el, hibalehetőség nélkül, állapotokkal és statisztikával együtt.
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();
}