CaiWuXiTong/modules/EcommerceFinance/Services/FinanceLedgerIndependentTransactionColumnEditor.php

127 lines
4.7 KiB
PHP

<?php
namespace Modules\EcommerceFinance\Services;
use App\Utilities\FinanceLedgerIndependentAccounts;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\DatabaseManager;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class FinanceLedgerIndependentTransactionColumnEditor
{
private const MAX_COLUMNS = 30;
private readonly ConnectionInterface $connection;
public function __construct(DatabaseManager $databases)
{
$this->connection = $databases->connection(
(string) config('upstream_mirrors.connection', 'business_mirror'),
);
}
/**
* @return array<string,mixed>
*/
public function create(string $accountShort, string $fieldName): array
{
$accountShort = trim($accountShort);
if (! FinanceLedgerIndependentAccounts::contains($accountShort)) {
throw ValidationException::withMessages([
'account_short' => '只有独立账单页面可以新增自定义列。',
]);
}
$fieldName = preg_replace('/\s+/u', ' ', trim($fieldName)) ?? trim($fieldName);
if ($fieldName === '') {
throw ValidationException::withMessages([
'field_name' => '请填写列名。',
]);
}
if (mb_strlen($fieldName) > 50) {
throw ValidationException::withMessages([
'field_name' => '列名不能超过 50 个字符。',
]);
}
return $this->connection->transaction(function () use ($accountShort, $fieldName): array {
$fields = $this->connection->table('fin_transaction_custom_fields')
->where('account_short', $accountShort);
if ((clone $fields)->count() >= self::MAX_COLUMNS) {
throw ValidationException::withMessages([
'field_name' => '每个独立账单最多可设置 ' . self::MAX_COLUMNS . ' 个自定义列。',
]);
}
if ((clone $fields)->where('field_name', $fieldName)->exists()) {
throw ValidationException::withMessages([
'field_name' => '该页面已存在同名列。',
]);
}
$now = now();
$field = [
'account_short' => $accountShort,
'field_key' => (string) Str::uuid(),
'field_name' => $fieldName,
'sort_order' => ((int) (clone $fields)->max('sort_order')) + 10,
'created_by' => (string) (user()?->name ?? ''),
'updated_by' => (string) (user()?->name ?? ''),
'created_at' => $now,
'updated_at' => $now,
];
$id = (int) $this->connection->table('fin_transaction_custom_fields')->insertGetId($field);
$this->audit(
'statement_col_add',
$accountShort . '|' . $field['field_key'],
['after' => $field + ['id' => $id]],
);
return ['id' => $id] + $field;
});
}
/**
* @return array<string,mixed>
*/
public function delete(int $id): array
{
return $this->connection->transaction(function () use ($id): array {
$field = $this->connection->table('fin_transaction_custom_fields')
->where('id', $id)
->lockForUpdate()
->first();
if ($field === null || ! FinanceLedgerIndependentAccounts::contains($field->account_short)) {
throw new NotFoundHttpException('未找到可删除的独立账单自定义列。');
}
$this->connection->table('fin_transaction_custom_values')
->where('custom_field_id', $id)
->delete();
$this->connection->table('fin_transaction_custom_fields')->where('id', $id)->delete();
$this->audit(
'statement_col_delete',
(string) $field->account_short . '|' . (string) $field->field_key,
['before' => (array) $field, 'after' => null],
);
return (array) $field;
});
}
/**
* @param array<string,mixed> $changes
*/
private function audit(string $entityType, string $entityKey, array $changes): void
{
$this->connection->table('fin_ledger_edit_events')->insert([
'entity_type' => $entityType,
'entity_key' => mb_substr('statement_column|' . $entityKey, 0, 200),
'changes' => json_encode($changes, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR),
'user_id' => user()?->id,
'user_name' => (string) (user()?->name ?? ''),
'created_at' => now(),
]);
}
}