223 lines
7.0 KiB
PHP
223 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace Modules\EcommerceFinance\Repositories;
|
|
|
|
use Illuminate\Database\ConnectionInterface;
|
|
use Illuminate\Database\DatabaseManager;
|
|
use Illuminate\Database\Query\Builder;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use RuntimeException;
|
|
|
|
class DingProcessDetailMirrorRepository
|
|
{
|
|
public const DEFAULT_SCOPE = 'personal_permission';
|
|
|
|
public const DATASET_PREFIX = 'ding.process_details.';
|
|
|
|
private readonly ConnectionInterface $connection;
|
|
|
|
public function __construct(DatabaseManager $database)
|
|
{
|
|
$this->connection = $database->connection(
|
|
(string) config('upstream_mirrors.connection', 'business_mirror')
|
|
);
|
|
}
|
|
|
|
public function scope(): string
|
|
{
|
|
$scope = trim((string) config(
|
|
'upstream_mirrors.ding_process_details.scope',
|
|
self::DEFAULT_SCOPE,
|
|
));
|
|
|
|
return $scope !== '' ? $scope : self::DEFAULT_SCOPE;
|
|
}
|
|
|
|
public function datasetKey(): string
|
|
{
|
|
return self::DATASET_PREFIX . $this->scope();
|
|
}
|
|
|
|
public function ready(): bool
|
|
{
|
|
$schema = Schema::connection($this->connection->getName());
|
|
|
|
if (! $schema->hasTable('ding_process_detail_mirror')
|
|
|| ! $schema->hasTable('business_mirror_table_states')) {
|
|
return false;
|
|
}
|
|
|
|
$state = $this->state();
|
|
|
|
return $state !== null && ($state['initial_completed_at'] ?? null) !== null;
|
|
}
|
|
|
|
/** @return array<string,mixed>|null */
|
|
public function state(): ?array
|
|
{
|
|
if (! Schema::connection($this->connection->getName())->hasTable('business_mirror_table_states')) {
|
|
return null;
|
|
}
|
|
|
|
$row = $this->connection->table('business_mirror_table_states')
|
|
->where('dataset_key', $this->datasetKey())
|
|
->first();
|
|
|
|
return $row === null ? null : (array) $row;
|
|
}
|
|
|
|
/**
|
|
* @param array<string,string> $filters
|
|
* @return array{
|
|
* data:list<object>,
|
|
* total:int,
|
|
* summary:array{rows:int,approvals:int,amount_total:float,bank_amount_total:float},
|
|
* status:string,
|
|
* last_synced_at:?string,
|
|
* scope:string
|
|
* }
|
|
*/
|
|
public function paginate(array $filters, int $page, int $perPage): array
|
|
{
|
|
if (! $this->ready()) {
|
|
throw new RuntimeException('ding_process_detail_mirror_not_ready');
|
|
}
|
|
|
|
$page = max($page, 1);
|
|
$perPage = min(max($perPage, 1), 100);
|
|
$query = $this->filteredQuery($filters);
|
|
|
|
$total = (clone $query)->count();
|
|
$summary = [
|
|
'rows' => $total,
|
|
'approvals' => (clone $query)->distinct()->count('business_id'),
|
|
'amount_total' => (float) ((clone $query)->sum('amount') ?? 0),
|
|
'bank_amount_total' => (float) ((clone $query)->sum('bank_amount') ?? 0),
|
|
];
|
|
$data = $query
|
|
->orderByDesc('business_month')
|
|
->orderByDesc('business_id')
|
|
->orderBy('line_no')
|
|
->forPage($page, $perPage)
|
|
->get()
|
|
->all();
|
|
$state = $this->state();
|
|
|
|
return [
|
|
'data' => $data,
|
|
'total' => $total,
|
|
'summary' => $summary,
|
|
'status' => (string) ($state['status'] ?? 'unknown'),
|
|
'last_synced_at' => isset($state['last_succeeded_at'])
|
|
? (string) $state['last_succeeded_at']
|
|
: null,
|
|
'scope' => $this->scope(),
|
|
];
|
|
}
|
|
|
|
/** @return array{months:list<string>,document_types:list<string>,statuses:list<string>} */
|
|
public function filterOptions(): array
|
|
{
|
|
if (! Schema::connection($this->connection->getName())->hasTable('ding_process_detail_mirror')) {
|
|
return ['months' => [], 'document_types' => [], 'statuses' => []];
|
|
}
|
|
|
|
$base = $this->connection->table('ding_process_detail_mirror')
|
|
->where('source_scope', $this->scope());
|
|
|
|
return [
|
|
'months' => (clone $base)
|
|
->whereNotNull('business_month')
|
|
->where('business_month', '!=', '')
|
|
->distinct()
|
|
->orderByDesc('business_month')
|
|
->pluck('business_month')
|
|
->map(static function (mixed $value): string {
|
|
$month = (string) $value;
|
|
|
|
return preg_match('/^\d{6}$/', $month) === 1
|
|
? substr($month, 0, 4) . '-' . substr($month, 4, 2)
|
|
: $month;
|
|
})
|
|
->all(),
|
|
'document_types' => (clone $base)
|
|
->whereNotNull('document_type')
|
|
->where('document_type', '!=', '')
|
|
->distinct()
|
|
->orderBy('document_type')
|
|
->pluck('document_type')
|
|
->map(static fn (mixed $value): string => (string) $value)
|
|
->all(),
|
|
'statuses' => (clone $base)
|
|
->whereNotNull('status')
|
|
->where('status', '!=', '')
|
|
->distinct()
|
|
->orderBy('status')
|
|
->pluck('status')
|
|
->map(static fn (mixed $value): string => (string) $value)
|
|
->all(),
|
|
];
|
|
}
|
|
|
|
/** @param array<string,string> $filters */
|
|
public function exportCount(array $filters): int
|
|
{
|
|
if (! Schema::connection($this->connection->getName())->hasTable('ding_process_detail_mirror')) {
|
|
return 0;
|
|
}
|
|
|
|
return (int) $this->filteredQuery($filters)->count();
|
|
}
|
|
|
|
/**
|
|
* @param array<string,string> $filters
|
|
* @return \Generator<int,array<string,mixed>>
|
|
*/
|
|
public function exportRows(array $filters): \Generator
|
|
{
|
|
$query = $this->filteredQuery($filters)
|
|
->orderByDesc('business_month')
|
|
->orderByDesc('business_id')
|
|
->orderBy('line_no');
|
|
|
|
foreach ($query->cursor() as $row) {
|
|
yield (array) $row;
|
|
}
|
|
}
|
|
|
|
/** @param array<string,string> $filters */
|
|
private function filteredQuery(array $filters): Builder
|
|
{
|
|
$query = $this->connection->table('ding_process_detail_mirror')
|
|
->where('source_scope', $this->scope());
|
|
|
|
$month = trim((string) ($filters['month'] ?? ''));
|
|
if (preg_match('/^\d{4}-\d{2}$/', $month) === 1) {
|
|
$query->where('business_month', str_replace('-', '', $month));
|
|
}
|
|
|
|
foreach ([
|
|
'document_type' => 'document_type',
|
|
'status' => 'status',
|
|
] as $filter => $column) {
|
|
$value = trim((string) ($filters[$filter] ?? ''));
|
|
if ($value !== '') {
|
|
$query->where($column, $value);
|
|
}
|
|
}
|
|
|
|
foreach ([
|
|
'business_id' => 'business_id',
|
|
'originator_name' => 'originator_name',
|
|
'keyword' => 'purpose',
|
|
] as $filter => $column) {
|
|
$value = mb_substr(trim((string) ($filters[$filter] ?? '')), 0, 100);
|
|
if ($value !== '') {
|
|
$query->where($column, 'like', '%' . $value . '%');
|
|
}
|
|
}
|
|
|
|
return $query;
|
|
}
|
|
}
|