diff --git a/app/Services/Etsy.php b/app/Services/Etsy.php index 66f7586..0cc12e9 100644 --- a/app/Services/Etsy.php +++ b/app/Services/Etsy.php @@ -64,12 +64,30 @@ class Etsy ]); } + /** Paid, unshipped orders that still need dispatching, excluding cancelled and fully refunded ones. */ public function receipts(EtsyConnection $connection, bool $fresh = false): array { - return $this->cache->remember('etsy.receipts.'.$connection->shop_id, 300, fn (): array => $this->get( - 'application/shops/'.$connection->shop_id.'/receipts', $this->accessToken($connection), [ - 'was_paid' => 'true', 'was_shipped' => 'false', 'limit' => 20, - ]), $fresh); + return $this->cache->remember('etsy.receipts.'.$connection->shop_id, 300, function () use ($connection): array { + $response = $this->get('application/shops/'.$connection->shop_id.'/receipts', $this->accessToken($connection), [ + 'was_paid' => 'true', 'was_shipped' => 'false', 'limit' => 50, + ]); + $results = array_values(array_filter($response['results'] ?? [], fn ($receipt): bool => is_array($receipt) && ! $this->isCancelledOrRefunded($receipt))); + + return ['count' => count($results), 'results' => $results] + $response; + }, $fresh); + } + + /** @param array $receipt */ + public function isCancelledOrRefunded(array $receipt): bool + { + if (in_array(strtolower((string) ($receipt['status'] ?? '')), ['canceled', 'cancelled'], true) || ! empty($receipt['was_canceled'])) { + return true; + } + + $total = (float) ($receipt['grandtotal']['amount'] ?? 0) / max(1, (int) ($receipt['grandtotal']['divisor'] ?? 1)); + $refunded = collect($receipt['refunds'] ?? [])->sum(fn ($refund): float => (float) ($refund['amount']['amount'] ?? 0) / max(1, (int) ($refund['amount']['divisor'] ?? 1))); + + return $total > 0 && $refunded >= $total; } public function listings(EtsyConnection $connection): array diff --git a/tests/Unit/EtsyReceiptFilterTest.php b/tests/Unit/EtsyReceiptFilterTest.php new file mode 100644 index 0000000..c1b6ccb --- /dev/null +++ b/tests/Unit/EtsyReceiptFilterTest.php @@ -0,0 +1,22 @@ + 1500, 'divisor' => 100, 'currency_code' => 'GBP']; + + $this->assertTrue($etsy->isCancelledOrRefunded(['status' => 'Canceled', 'grandtotal' => $total])); + $this->assertTrue($etsy->isCancelledOrRefunded(['status' => 'Paid', 'grandtotal' => $total, 'refunds' => [['amount' => ['amount' => 1500, 'divisor' => 100]]]])); + $this->assertTrue($etsy->isCancelledOrRefunded(['status' => 'Paid', 'grandtotal' => $total, 'refunds' => [['amount' => ['amount' => 1000, 'divisor' => 100]], ['amount' => ['amount' => 500, 'divisor' => 100]]]])); + $this->assertFalse($etsy->isCancelledOrRefunded(['status' => 'Paid', 'grandtotal' => $total, 'refunds' => [['amount' => ['amount' => 500, 'divisor' => 100]]]])); + $this->assertFalse($etsy->isCancelledOrRefunded(['status' => 'Paid', 'grandtotal' => $total])); + } +}