Skip to content

Commit d74734d

Browse files
authored
Improve webshop backend (#3810)
1 parent 5013a32 commit d74734d

File tree

67 files changed

+3851
-435
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+3851
-435
lines changed

.env.example

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,32 @@ VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
239239
# VITE_LOCAL_DEV=true
240240
# VITE_HTTP_PROXY_TARGET=http://localhost:8000
241241

242-
# DISABLE_IMPORT_FROM_SERVER=false
242+
# DISABLE_IMPORT_FROM_SERVER=false
243+
244+
###################################################################
245+
# Payment integration (requires SE) #
246+
###################################################################
247+
248+
# Enable test mode (Sandbox mode) for payment gateways.
249+
# In test mode, no real money transactions are done.
250+
# We set it to true by default for safety. Make sure to set it to false
251+
# when you go live.
252+
# OMNIPAY_TEST_MODE=true
253+
254+
# Configuration values for Mollie integration
255+
# MOLLIE_API_KEY=
256+
# MOLLIE_PROFILE_ID=
257+
258+
# Configuration values for Stripe integration (NOT WORKING YET, MAYBE LATER)
259+
# STRIPE_API_KEY=
260+
# STRIPE_PUBLISHABLE_KEY=
261+
262+
# https://github.com/thephpleague/omnipay-paypal/blob/master/src/RestGateway.php
263+
# PAYPAL_CLIENT_ID=
264+
# PAYPAL_SECRET=
265+
266+
# https://github.com/thephpleague/omnipay-paypal/blob/master/src/ExpressInContextGateway.php
267+
# https://github.com/thephpleague/omnipay-paypal/blob/master/src/ProGateway.php
268+
# PAYPAL_API_USERNAME=
269+
# PAYPAL_API_PASSWORD=
270+
# PAYPAL_API_SIGNATURE=

app/Actions/Diagnostics/Pipes/Checks/WebshopCheck.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
namespace App\Actions\Diagnostics\Pipes\Checks;
1010

11+
use App\Actions\Shop\OrderService;
1112
use App\Contracts\DiagnosticPipe;
1213
use App\DTO\DiagnosticData;
1314
use App\Enum\OmnipayProviderType;
@@ -22,6 +23,7 @@ class WebshopCheck implements DiagnosticPipe
2223
{
2324
public function __construct(
2425
private OmnipayFactory $factory,
26+
private OrderService $order_service,
2527
) {
2628
}
2729

@@ -37,6 +39,14 @@ public function handle(array &$data, \Closure $next): array
3739
if (!Configs::getValueAsBool('webshop_enabled')) {
3840
return $next($data);
3941
}
42+
// @codeCoverageIgnoreStart
43+
if (config('omnipay.testMode', false) === true) {
44+
$data[] = DiagnosticData::warn(
45+
'Webshop is running in test mode.',
46+
self::class,
47+
['This means that payments won\'t be executed.', 'Users may use it to get free content.']
48+
);
49+
}
4050

4151
if (config('app.env', 'production') !== 'production') {
4252
$data[] = DiagnosticData::warn(
@@ -61,6 +71,25 @@ public function handle(array &$data, \Closure $next): array
6171
);
6272
}
6373

74+
$number_broken_order = $this->order_service->selectClosedOrderNeedingFulfillmentQuery()->count();
75+
if ($number_broken_order > 0) {
76+
$data[] = DiagnosticData::error(
77+
'There are ' . $number_broken_order . ' closed orders with items that have no associated download link or size variant.',
78+
self::class,
79+
['Please check and assign the needed materials.']
80+
);
81+
}
82+
83+
$number_waiting_order = $this->order_service->selectCompleteOrderNeedingFulfillmentQuery()->count();
84+
if ($number_waiting_order > 0) {
85+
$data[] = DiagnosticData::warn(
86+
'There are ' . $number_waiting_order . ' completed orders which require your attention.',
87+
self::class,
88+
['Please check and fulfill them in order to mark them as closed.']
89+
);
90+
}
91+
// @codeCoverageIgnoreEnd
92+
6493
return $next($data);
6594
}
6695
}

app/Actions/Shop/BasketService.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,10 @@ protected function ensurePendingStatus(Order $basket): void
6060
public function getOrCreateBasket(?Order $basket, ?User $user = null): Order
6161
{
6262
if ($basket !== null) {
63-
$this->ensurePendingStatus($basket);
64-
6563
// If user is now logged in but basket wasn't associated with a user
6664
if ($user !== null && $basket->user_id === null) {
6765
$basket->user_id = $user->id;
66+
$basket->email = $user->email;
6867
$basket->save();
6968
}
7069

app/Actions/Shop/CheckoutService.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
use App\Models\Order;
1717
use App\Services\MoneyService;
1818
use Illuminate\Support\Facades\Log;
19+
use Illuminate\Support\Facades\Session;
1920
use Omnipay\Common\Exception\InvalidCreditCardException;
2021
use Omnipay\Common\Message\RedirectResponseInterface;
2122
use Omnipay\Common\Message\ResponseInterface;
23+
use Omnipay\Mollie\Message\Response\FetchTransactionResponse;
2224

2325
/**
2426
* Service for handling checkout operations using Omnipay.
@@ -80,6 +82,13 @@ public function processPayment(Order $order, string $return_url, string $cancel_
8082

8183
// Handle the response
8284
if ($response->isRedirect()) {
85+
if ($response instanceof FetchTransactionResponse) {
86+
$metadata = $response->getMetadata();
87+
$reference = $response->getTransactionReference();
88+
$metadata['transactionReference'] = $reference;
89+
Session::put('metadata.' . $order->id, $metadata);
90+
}
91+
8392
if (!$response instanceof RedirectResponseInterface) {
8493
throw new LycheeLogicException('Expected RedirectResponseInterface for redirect response.');
8594
}
@@ -151,22 +160,23 @@ public function completePayment(Order $order, ResponseInterface $response): Orde
151160
/**
152161
* Handle the return from the payment gateway.
153162
*
154-
* @param Order $order The order being processed
155-
* @param array $request_data The request data from the payment gateway
156-
* @param OmnipayProviderType $provider The payment provider used
163+
* @param Order $order The order being processed
164+
* @param OmnipayProviderType $provider The payment provider used
157165
*
158166
* @return Order|null The updated order if found, null otherwise
159167
*/
160-
public function handlePaymentReturn(Order $order, array $request_data, OmnipayProviderType $provider): ?Order
168+
public function handlePaymentReturn(Order $order, OmnipayProviderType $provider): ?Order
161169
{
170+
$metadata = Session::get('metadata.' . $order->id, []);
171+
Log::info('Payment return metadata', ['metadata' => $metadata]);
172+
162173
$gateway = $this->omnipay_factory->create_gateway($provider);
163174

164175
try {
165176
if ($order->status !== PaymentStatusType::PROCESSING) {
166177
throw new LycheeLogicException('Order with invalid status.');
167178
}
168-
169-
$response = $gateway->completePurchase($request_data)->send();
179+
$response = $gateway->completePurchase($metadata)->send();
170180
if ($response->isSuccessful()) {
171181
return $this->completePayment($order, $response);
172182
} else {

0 commit comments

Comments
 (0)