108 lines
3.6 KiB
PHP
108 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace classes;
|
|
|
|
use InvalidArgumentException;
|
|
|
|
class invoicing_period_utils
|
|
{
|
|
/**
|
|
* Normalize date range for invoicing endpoints to full-day timestamps.
|
|
*
|
|
* @return array{dateFrom:string,dateTo:string}
|
|
*/
|
|
public static function normalizeDateRange(string $dateFrom, string $dateTo): array
|
|
{
|
|
if (!self::isValidDate($dateFrom)) {
|
|
throw new InvalidArgumentException('Invalid date format. Expected: Y-m-d Got: ' . $dateFrom);
|
|
}
|
|
if (!self::isValidDate($dateTo)) {
|
|
throw new InvalidArgumentException('Invalid date format. Expected: Y-m-d Got: ' . $dateTo);
|
|
}
|
|
|
|
if (strtotime($dateFrom) === false || strtotime($dateTo) === false) {
|
|
throw new InvalidArgumentException('Invalid date range provided');
|
|
}
|
|
|
|
if (strtotime($dateFrom) > strtotime($dateTo)) {
|
|
throw new InvalidArgumentException('Invalid date range. dateFrom must be before or equal to dateTo');
|
|
}
|
|
|
|
return [
|
|
'dateFrom' => date('Y-m-d 00:00:00', strtotime($dateFrom)),
|
|
'dateTo' => date('Y-m-d 23:59:59', strtotime($dateTo)),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Filter grouped orders down to orders that have at least one neighbor within the time window.
|
|
*
|
|
* @param array<string, array<int, array<string,mixed>>> $ordersByRegistration
|
|
* @return array<string, array<int, array<string,mixed>>>
|
|
*/
|
|
public static function filterPossibleDuplicates(array $ordersByRegistration, int $windowSeconds = 86400): array
|
|
{
|
|
$possibleDuplicates = [];
|
|
|
|
foreach ( $ordersByRegistration as $registration => $orderList ) {
|
|
if (count($orderList) < 2) {
|
|
continue;
|
|
}
|
|
|
|
$normalizedOrders = [];
|
|
foreach ( $orderList as $order ) {
|
|
$createdAt = (string)($order['created_at'] ?? '');
|
|
$timestamp = strtotime($createdAt);
|
|
if ($timestamp === false) {
|
|
continue;
|
|
}
|
|
$order['_timestamp'] = $timestamp;
|
|
$normalizedOrders[] = $order;
|
|
}
|
|
|
|
if (count($normalizedOrders) < 2) {
|
|
continue;
|
|
}
|
|
|
|
usort($normalizedOrders, function (array $a, array $b) {
|
|
return (int)$a['_timestamp'] <=> (int)$b['_timestamp'];
|
|
});
|
|
|
|
$duplicateIndexes = [];
|
|
$count = count($normalizedOrders);
|
|
for ( $i = 0; $i < $count; $i++ ) {
|
|
$currentTimestamp = (int)$normalizedOrders[$i]['_timestamp'];
|
|
for ( $j = $i - 1; $j >= 0; $j-- ) {
|
|
$delta = $currentTimestamp - (int)$normalizedOrders[$j]['_timestamp'];
|
|
if ($delta > $windowSeconds) {
|
|
break;
|
|
}
|
|
$duplicateIndexes[$i] = true;
|
|
$duplicateIndexes[$j] = true;
|
|
}
|
|
}
|
|
|
|
if (count($duplicateIndexes) < 2) {
|
|
continue;
|
|
}
|
|
|
|
$possibleDuplicates[$registration] = [];
|
|
$indexes = array_keys($duplicateIndexes);
|
|
sort($indexes);
|
|
foreach ( $indexes as $index ) {
|
|
$order = $normalizedOrders[$index];
|
|
unset($order['_timestamp']);
|
|
$possibleDuplicates[$registration][] = $order;
|
|
}
|
|
}
|
|
|
|
return $possibleDuplicates;
|
|
}
|
|
|
|
private static function isValidDate(string $date): bool
|
|
{
|
|
$parsed = \DateTime::createFromFormat('Y-m-d', $date);
|
|
return $parsed !== false && $parsed->format('Y-m-d') === $date;
|
|
}
|
|
}
|