Skip to content

Commit

Permalink
Refactor Lunar transactions to use payment checks DTO (#1767)
Browse files Browse the repository at this point in the history
  • Loading branch information
alecritson committed May 23, 2024
1 parent 631dedc commit fe6108a
Show file tree
Hide file tree
Showing 10 changed files with 441 additions and 21 deletions.
14 changes: 14 additions & 0 deletions docs/core/reference/payments.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,20 @@ $order->charges; // Get all transactions that are charges.
$order->refunds; // Get all transactions that are refunds.
```
### Payment Checks
Some providers return information based on checks that can occur before payment is validated and completed.
This is usually related to 3DSecure but in some cases can relate to credit checks or anything the payment provider has deemed relevant to the transaction.
You can get access to these checks via the `paymentChecks()` method on the `Transaction`.
```php
foreach($transaction->paymentChecks() as $check) {
$check->successful;
$check->label;
$check->message;
}
```
## Payments
We will be looking to add support for the most popular payment providers, so keep an eye out here as we will list them all out.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
'!border-red-500 bg-red-50' => !$transaction->success,
'bg-gray-50' => $transaction->success,
])
>
>
<div class="p-2 space-y-2">
<div class="px-4 py-2 rounded text-xs bg-white dark:bg-gray-800 shadow text-gray-600 dark:text-gray-400 ring-1 ring-gray-100 dark:ring-gray-700">
<span>{{ $transaction->driver }}</span> //
Expand Down Expand Up @@ -53,7 +53,7 @@
@endif
</div>

<strong
<strong
@class([
"text-sm",
'text-red-500' => !$transaction->success,
Expand All @@ -75,26 +75,19 @@
class="w-4"
/>
</div>

<span>{{ $transaction->created_at->format('jS F Y h:ia') }}</span>
</div>

@if($threeD = $transaction->meta['threedSecure'] ?? null)
<div class="flex space-x-2">
@foreach([
'address' => 'Address',
'postalCode' => 'Postal Code',
'securityCode' => 'Security Code',
] as $metaKey => $metaLabel)
<x-filament::badge
:icon="$threeD[$metaKey] ?? false ? 'heroicon-m-check' : 'heroicon-m-x-mark'"
:color="$threeD[$metaKey] ?? false ? \Filament\Support\Colors\Color::Sky : 'gray'"
>
{{ $metaLabel }}
</x-filament::badge>
@endforeach
</div>
@endif
<div class="flex space-x-2">
@foreach($transaction->paymentChecks() as $check)
<x-filament::badge
:icon="$check->successful ? 'heroicon-m-check' : 'heroicon-m-x-mark'"
:color="$check->successful ? \Filament\Support\Colors\Color::Sky : 'gray'"
>
{{ $check->label }}: {{ $check->message }}
</x-filament::badge>
@endforeach
</div>
</div>

@if($transaction->notes)
Expand All @@ -111,7 +104,7 @@ class="w-4"
@endif
</div>

<div
<div
@class([
"bottom-0 left-0 block w-full text-center rounded-b-lg border-t text-xs py-1",
"!bg-red-50 !dark:bg-red-400/10 !border-red-300 !text-red-600 !dark:text-red-400" => !$transaction->success,
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/Base/DataTransferObjects/PaymentCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Lunar\Base\DataTransferObjects;

class PaymentCheck
{
public function __construct(
public bool $successful,
public string $label,
public string $message
) {
}
}
69 changes: 69 additions & 0 deletions packages/core/src/Base/DataTransferObjects/PaymentChecks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Lunar\Base\DataTransferObjects;

class PaymentChecks implements \ArrayAccess, \Iterator
{
private int $position = 0;

protected array $checks = [];

public function addCheck(PaymentCheck $check): void
{
$this->checks[] = $check;
}

public function getChecks(): array
{
return $this->checks;
}

public function current(): PaymentCheck
{
return $this->checks[$this->position];
}

public function next(): void
{
$this->position++;
}

public function key(): mixed
{
return $this->position;
}

public function valid(): bool
{
return isset($this->checks[$this->position]);
}

public function rewind(): void
{
$this->position = 0;
}

public function offsetExists(mixed $offset): bool
{
return isset($this->checks[$offset]);
}

public function offsetGet(mixed $offset): mixed
{
return $this->checks[$offset];
}

public function offsetSet(mixed $offset, mixed $value): void
{
if (is_null($offset)) {
$this->checks[] = $value;
} else {
$this->checks[$offset] = $value;
}
}

public function offsetUnset(mixed $offset): void
{
unset($this->checks[$offset]);
}
}
5 changes: 5 additions & 0 deletions packages/core/src/Models/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ public function driver()
return Payments::driver($this->driver);
}

public function paymentChecks()
{
return $this->driver()->getPaymentChecks($this);
}

public function refund(int $amount, $notes = null)
{
return $this->driver()->refund($this, $amount, $notes);
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/PaymentTypes/AbstractPayment.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

namespace Lunar\PaymentTypes;

use Lunar\Base\DataTransferObjects\PaymentChecks;
use Lunar\Base\PaymentTypeInterface;
use Lunar\Models\Cart;
use Lunar\Models\Order;
use Lunar\Models\Transaction;

abstract class AbstractPayment implements PaymentTypeInterface
{
Expand Down Expand Up @@ -71,4 +73,9 @@ public function setConfig(array $config): self

return $this;
}

public function getPaymentChecks(Transaction $transaction): PaymentChecks
{
return new PaymentChecks;
}
}
78 changes: 78 additions & 0 deletions packages/opayo/src/OpayoPaymentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Illuminate\Support\Str;
use Lunar\Base\DataTransferObjects\PaymentCapture;
use Lunar\Base\DataTransferObjects\PaymentCheck;
use Lunar\Base\DataTransferObjects\PaymentChecks;
use Lunar\Base\DataTransferObjects\PaymentRefund;
use Lunar\Events\PaymentAttemptEvent;
use Lunar\Models\Order;
Expand Down Expand Up @@ -421,6 +423,82 @@ public function setPolicy(mixed $policy): void
$this->policy = $policy;
}

public function getPaymentChecks(Transaction $transaction): PaymentChecks
{
$meta = $transaction->meta['threedSecure'] ?? null;

$checks = new PaymentChecks;

if (! $meta) {
return $checks;
}

if (isset($meta['address'])) {
$message = $meta['address'];
$successful = $meta['address'] == 'Matched';

if (is_bool($message) && ! $message) {
$message = 'NotMatched';
$successful = false;
}
if (is_bool($message) && $message) {
$message = 'Matched';
$successful = true;
}
$checks->addCheck(
new PaymentCheck(
successful: $successful,
label: 'Address',
message: $message,
)
);
}

if (isset($meta['postalCode'])) {
$message = $meta['postalCode'];
$successful = $meta['postalCode'] == 'Matched';

if (is_bool($message) && ! $message) {
$message = 'NotMatched';
$successful = false;
}
if (is_bool($message) && $message) {
$message = 'Matched';
$successful = true;
}
$checks->addCheck(
new PaymentCheck(
successful: $successful,
label: 'Postal Code',
message: $message,
)
);
}

if (isset($meta['securityCode'])) {
$message = $meta['securityCode'];
$successful = $meta['securityCode'] == 'Matched';

if (is_bool($message) && ! $message) {
$message = 'NotMatched';
$successful = false;
}
if (is_bool($message) && $message) {
$message = 'Matched';
$successful = true;
}
$checks->addCheck(
new PaymentCheck(
successful: $successful,
label: 'Security Code',
message: $message,
)
);
}

return $checks;
}

private function saveCard(Order $order, object $details, string $authCode = null)
{
if (! $order->user_id) {
Expand Down
41 changes: 41 additions & 0 deletions packages/stripe/src/StripePaymentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Lunar\Base\DataTransferObjects\PaymentAuthorize;
use Lunar\Base\DataTransferObjects\PaymentCapture;
use Lunar\Base\DataTransferObjects\PaymentCheck;
use Lunar\Base\DataTransferObjects\PaymentChecks;
use Lunar\Base\DataTransferObjects\PaymentRefund;
use Lunar\Events\PaymentAttemptEvent;
use Lunar\Exceptions\DisallowMultipleCartOrdersException;
Expand Down Expand Up @@ -193,4 +195,43 @@ public function refund(Transaction $transaction, int $amount = 0, $notes = null)
success: true
);
}

public function getPaymentChecks(Transaction $transaction): PaymentChecks
{
$meta = $transaction->meta;

$checks = new PaymentChecks;

if (isset($meta['address_line1_check'])) {
$checks->addCheck(
new PaymentCheck(
successful: $meta['address_line1_check'] == 'pass',
label: 'Address Line 1',
message: $meta['address_line1_check'],
)
);
}

if (isset($meta['address_postal_code_check'])) {
$checks->addCheck(
new PaymentCheck(
successful: $meta['address_postal_code_check'] == 'pass',
label: 'Postal Code',
message: $meta['address_postal_code_check'],
)
);
}

if (isset($meta['cvc_check'])) {
$checks->addCheck(
new PaymentCheck(
successful: $meta['cvc_check'] == 'pass',
label: 'CVC Check',
message: $meta['cvc_check'],
)
);
}

return $checks;
}
}

0 comments on commit fe6108a

Please sign in to comment.