126 lines
4.5 KiB
PHP
126 lines
4.5 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Recon;
|
||
|
||
use App\Exceptions\RepositoryException;
|
||
use App\Http\Requests\Recon\ReconItemUpdateRequest;
|
||
use App\Models\ReconciliationItemModel;
|
||
use App\Models\ReconciliationModel;
|
||
use Illuminate\Http\JsonResponse;
|
||
use Illuminate\Http\Request;
|
||
use Modules\AnnoRoute\Attribute\PutRoute;
|
||
use Modules\AnnoRoute\Attribute\RequestAttribute;
|
||
use Modules\Common\Http\Controllers\BaseController;
|
||
|
||
/**
|
||
* 对账明细操作(D4 修改 / D6 单品级门店备注 / D8 对账状态标记)
|
||
* 权限点前缀 recon.item,authorize: item.update → recon.item.item.update
|
||
*/
|
||
#[RequestAttribute('/recon/item', 'recon.item')]
|
||
class ReconItemController extends BaseController
|
||
{
|
||
/**
|
||
* D4 修改订货量/称重/数量/金额/商品名,自动重算本行 diff + 头汇总
|
||
*/
|
||
#[PutRoute(route: '/{id}', authorize: 'item.update', where: ['id' => '[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),
|
||
]);
|
||
}
|
||
}
|