order; if (!$order) { return null; } return WaterDelivery::query()->where('enterprise_id', $referral->invited_id)->where('sku_id', $order->sku_id) ->where('id', '>', (int) $referral->delivery_floor_id) ->where('status', 'completed')->where('delivered_qty', '>', 0) ->where('created_at', '>=', $order->created_at)->where('received_at', '>=', $order->created_at) ->orderBy('received_at')->orderBy('id')->first(); } public function review(array $input, int $actor): array { $id = WaterBusiness::positive($input['id'] ?? null, '奖励记录'); $revision = WaterBusiness::positive($input['revision'] ?? null, '记录版本'); $decision = $input['decision'] ?? ''; $note = $input['note'] ?? ''; if (!in_array($decision, ['issued', 'rejected'], true) || !is_string($note) || trim($note) === '' || mb_strlen($note) > 500) { throw new ApiException('请选择审核结果并填写1至500字的核实说明'); } if ($decision === 'issued' && ($input['receipt_refund_checked'] ?? null) !== true) { throw new ApiException('请先核实真实收款、无退款及重复客户情况'); } $note = trim($note); return WaterModel::transaction(function () use ($id, $revision, $decision, $note, $actor) { $snapshot = WaterPromotionReferral::query()->find($id); if (!$snapshot) { throw new ApiException('奖励记录不存在'); } // Match receipt/inventory lock order: SKU -> enterprise(s) -> referral -> account. $sku = WaterSku::query()->lockForUpdate()->find($snapshot->sku_id); $ids = [(int) $snapshot->inviter_id, (int) $snapshot->invited_id]; sort($ids, SORT_NUMERIC); $companies = WaterEnterprise::query()->whereIn('id', $ids)->orderBy('id')->lockForUpdate()->get(); $row = WaterPromotionReferral::query()->lockForUpdate()->find($id); if (!$row) { throw new ApiException('奖励记录不存在'); } if (in_array($row->status, ['issued', 'rejected'], true)) { if ($row->status === $decision && $row->review_note === $note) { return ['id' => $id, 'status' => $row->status, 'replayed' => true]; } throw new ApiException('奖励已经处理,请刷新查看'); } if ($row->status !== 'pending' || (int) $row->revision !== $revision) { throw new ApiException('尚未首购或记录已更新,请刷新查看'); } $delivery = null; if ($decision === 'issued') { if (!$sku || (int) $sku->status !== 1 || $companies->count() !== 2 || $companies->contains(fn ($company) => (int) $company->status !== 1)) { throw new ApiException('企业或赠水规格已停用或不存在'); } $order = $row->order; $checkout = $row->checkout_id ? MiniCheckout::query()->find($row->checkout_id) : null; $amount = (int) $row->purchase_amount_cents; if (!$order || (int) $order->enterprise_id !== (int) $row->invited_id || $amount < max(1, (int) $row->min_amount_cents) || str_starts_with($order->reference, 'TEST-') || str_contains($order->package_name, '测试')) { throw new ApiException('首购收款记录不符合奖励条件'); } if ($row->checkout_id) { if (!$checkout || $checkout->status !== 'paid' || (int) $checkout->enterprise_id !== (int) $row->invited_id || (int) $checkout->amount_cents !== $amount || !str_starts_with($order->reference, $checkout->code . '-')) { throw new ApiException('首购结算记录不符合奖励条件'); } } elseif ((int) $order->amount_cents !== $amount) { throw new ApiException('首购金额已发生变化,不能发放奖励'); } $delivery = self::delivery($row); if (!$delivery) { throw new ApiException('首购后尚无对应规格的有效完整签收'); } $account = WaterAccount::query()->where('enterprise_id', $row->inviter_id) ->where('sku_id', $row->sku_id)->lockForUpdate()->first(); if (!$account) { $account = WaterAccount::query()->create([ 'enterprise_id' => $row->inviter_id, 'sku_id' => $row->sku_id, 'updated_at' => date('Y-m-d H:i:s'), ]); $account->refresh(); } $account->entitlement = (int) $account->entitlement + (int) $row->quantity; $account->updated_at = date('Y-m-d H:i:s'); $account->save(); } $row->fill([ 'status' => $decision, 'reviewed_by' => $actor, 'reviewed_at' => date('Y-m-d H:i:s'), 'review_note' => $note, 'delivery_id' => $delivery?->id, 'revision' => $revision + 1, ])->save(); WaterLedger::query()->create([ 'kind' => $decision === 'issued' ? 'promotion_reward' : 'promotion_reject', 'created_by' => $actor, 'sku_id' => $row->sku_id, 'enterprise_id' => $row->inviter_id, 'quantity' => $decision === 'issued' ? (int) $row->quantity : 0, 'reference' => 'promotion:' . $id, 'note' => '邀请企业#' . $row->invited_id . ',首购#' . $row->order_id . ',' . $note, 'created_at' => date('Y-m-d H:i:s'), ]); return ['id' => $id, 'status' => $decision]; }); } }