'[0-9]+'])] public function update(int $id, ReconItemUpdateRequest $request): JsonResponse { $item = ReconciliationItemModel::find($id); if (empty($item)) { throw new RepositoryException('对账明细不存在'); } $this->assertEditable($item); $validated = $request->validated(); if (isset($validated['product_name'])) { $item->product_name = $validated['product_name']; } if (isset($validated['quantity'])) { $item->quantity = $validated['quantity']; } if (isset($validated['weight'])) { $item->weight = $validated['weight']; } if (isset($validated['publish_amount'])) { $item->publish_amount = $validated['publish_amount']; } if (isset($validated['actual_amount'])) { $item->actual_amount = $validated['actual_amount']; } // 重算本行差额 $item->diff_amount = bcsub((string) $item->publish_amount, (string) $item->actual_amount, 2); $item->save(); $this->refreshReconSummary((int) $item->recon_id); return $this->success(['diff_amount' => $item->diff_amount]); } /** D8 对账状态标记翻转 */ #[PutRoute(route: '/{id}/toggle', authorize: 'item.update', where: ['id' => '[0-9]+'])] public function toggle(int $id): JsonResponse { $item = ReconciliationItemModel::find($id); if (empty($item)) { throw new RepositoryException('对账明细不存在'); } $this->assertEditable($item); $item->is_reconciled = $item->is_reconciled === ReconciliationItemModel::RECONCILED ? ReconciliationItemModel::NOT_RECONCILED : ReconciliationItemModel::RECONCILED; $item->save(); return $this->success(['is_reconciled' => $item->is_reconciled]); } /** D6 单品级门店备注 */ #[PutRoute(route: '/{id}/remark', authorize: 'item.update', where: ['id' => '[0-9]+'])] public function remark(int $id, Request $request): JsonResponse { $data = $request->validate([ 'store_remark' => 'nullable|string|max:255', ], [ 'store_remark.max' => '备注最长 255 个字符', ]); $item = ReconciliationItemModel::find($id); if (empty($item)) { throw new RepositoryException('对账明细不存在'); } $this->assertEditable($item); $item->store_remark = (string) ($data['store_remark'] ?? ''); $item->save(); return $this->success(); } /** * 已结算的对账单明细不允许修改 */ private function assertEditable(ReconciliationItemModel $item): void { $recon = ReconciliationModel::find($item->recon_id); if ($recon !== null && $recon->status === ReconciliationModel::STATUS_SETTLED) { throw new RepositoryException('对账单已结算,明细不能修改'); } } /** * 明细变更后重算对账单头汇总(publish / actual / diff) */ private function refreshReconSummary(int $reconId): void { $sums = ReconciliationItemModel::query() ->where('recon_id', $reconId) ->selectRaw('COALESCE(SUM(publish_amount), 0) as publish_total, COALESCE(SUM(actual_amount), 0) as actual_total') ->first(); ReconciliationModel::whereKey($reconId)->update([ 'publish_amount' => $sums->publish_total, 'actual_amount' => $sums->actual_total, 'diff_amount' => bcsub((string) $sums->publish_total, (string) $sums->actual_total, 2), ]); } }