join('store_order', 'store_order.id', '=', 'store_order_item.order_id') ->where('store_order_item.store_id', $store->id) ->whereDate('store_order.order_date', '>=', $periodStart) ->whereDate('store_order.order_date', '<=', $periodEnd) ->where('store_order.status', '<>', StoreOrderModel::STATUS_CANCELLED) ->select('store_order_item.*') ->get(); if ($orderItems->isEmpty()) { throw new RepositoryException('周期内本店无订单数据,无法生成对账单'); } // 防重复入账:剔除已计入过对账单的订单明细 $usedItemIds = StatementItemModel::query() ->whereIn('statement_id', StatementModel::where('store_id', $store->id)->pluck('id')) ->pluck('order_item_id'); $orderItems = $orderItems->reject(fn ($item) => $usedItemIds->contains($item->id)); if ($orderItems->isEmpty()) { throw new RepositoryException('周期内的订单明细均已生成过对账单'); } // 快照回款周期 → 应结算日期 $cycleDays = (int) $store->payment_cycle_days; $totalAmount = $orderItems->reduce( static fn (string $carry, $item): string => bcadd($carry, (string) $item->amount, 2), '0' ); $statement = StatementModel::create([ 'statement_no' => $this->billNumberService->make('ST'), 'store_id' => $store->id, 'period_start' => $periodStart, 'period_end' => $periodEnd, 'total_amount' => $totalAmount, 'payment_cycle_days' => $cycleDays, 'settlement_date' => Carbon::parse($periodEnd)->addDays($cycleDays)->toDateString(), 'status' => StatementModel::STATUS_PENDING, ]); $rows = []; $now = now(); foreach ($orderItems as $item) { $rows[] = [ 'statement_id' => $statement->id, 'order_id' => $item->order_id, 'order_item_id' => $item->id, 'product_id' => $item->product_id, 'product_name' => $item->product_name, 'price' => $item->price, 'quantity' => $item->quantity, 'weight' => $item->weight, 'amount' => $item->amount, 'is_reconciled' => StatementItemModel::NOT_RECONCILED, 'store_remark' => '', 'created_at' => $now, 'updated_at' => $now, ]; } StatementItemModel::insert($rows); return $statement; }); } }