Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117995054
D1900.1775538680.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
10 KB
Referenced Files
None
Subscribers
None
D1900.1775538680.diff
View Options
diff --git a/src/app/Http/Controllers/API/V4/PaymentsController.php b/src/app/Http/Controllers/API/V4/PaymentsController.php
--- a/src/app/Http/Controllers/API/V4/PaymentsController.php
+++ b/src/app/Http/Controllers/API/V4/PaymentsController.php
@@ -21,7 +21,7 @@
$user = Auth::guard()->user();
// TODO: Wallet selection
- $wallet = $user->wallets->first();
+ $wallet = $user->wallets()->first();
$mandate = self::walletMandate($wallet);
@@ -40,7 +40,7 @@
$current_user = Auth::guard()->user();
// TODO: Wallet selection
- $wallet = $current_user->wallets->first();
+ $wallet = $current_user->wallets()->first();
$rules = [
'amount' => 'required|numeric',
@@ -59,7 +59,15 @@
$amount = (int) ($request->amount * 100);
// Validate the minimum value
- if ($amount < PaymentProvider::MIN_AMOUNT) {
+ // It has to be at least minimum payment amount and must cover current debt
+ if (
+ $wallet->balance < 0
+ && $wallet->balance * -1 > PaymentProvider::MIN_AMOUNT
+ && $wallet->balance + $amount < 0
+ ) {
+ $errors = ['amount' => \trans('validation.minamountdebt')];
+ return response()->json(['status' => 'error', 'errors' => $errors], 422);
+ } elseif ($amount < PaymentProvider::MIN_AMOUNT) {
$min = intval(PaymentProvider::MIN_AMOUNT / 100) . ' CHF';
$errors = ['amount' => \trans('validation.minamount', ['amount' => $min])];
return response()->json(['status' => 'error', 'errors' => $errors], 422);
@@ -72,10 +80,15 @@
$request = [
'currency' => 'CHF',
- 'amount' => $amount,
'description' => \config('app.name') . ' Auto-Payment Setup',
];
+ // Normally the auto-payment operation is 0, if the balance is below 0,
+ // we'll charge for the mandate amount
+ if ($wallet->balance < 0) {
+ $request['amount'] = $amount;
+ }
+
$provider = PaymentProvider::factory($wallet);
$result = $provider->createMandate($wallet, $request);
@@ -95,7 +108,7 @@
$user = Auth::guard()->user();
// TODO: Wallet selection
- $wallet = $user->wallets->first();
+ $wallet = $user->wallets()->first();
$provider = PaymentProvider::factory($wallet);
@@ -121,7 +134,7 @@
$current_user = Auth::guard()->user();
// TODO: Wallet selection
- $wallet = $current_user->wallets->first();
+ $wallet = $current_user->wallets()->first();
$rules = [
'amount' => 'required|numeric',
@@ -185,7 +198,7 @@
$current_user = Auth::guard()->user();
// TODO: Wallet selection
- $wallet = $current_user->wallets->first();
+ $wallet = $current_user->wallets()->first();
$rules = [
'amount' => 'required|numeric',
diff --git a/src/app/Providers/Payment/Mollie.php b/src/app/Providers/Payment/Mollie.php
--- a/src/app/Providers/Payment/Mollie.php
+++ b/src/app/Providers/Payment/Mollie.php
@@ -50,10 +50,14 @@
// Register the user in Mollie, if not yet done
$customer_id = self::mollieCustomerId($wallet, true);
+ if (!isset($payment['amount'])) {
+ $payment['amount'] = 0;
+ }
+
$request = [
'amount' => [
'currency' => $payment['currency'],
- 'value' => '0.00',
+ 'value' => sprintf('%.2f', $payment['amount'] / 100),
],
'customerId' => $customer_id,
'sequenceType' => 'first',
@@ -71,6 +75,13 @@
$wallet->setSetting('mollie_mandate_id', $response->mandateId);
}
+ // Store the payment reference in database
+ $payment['status'] = $response->status;
+ $payment['id'] = $response->id;
+ $payment['type'] = self::TYPE_MANDATE;
+
+ $this->storePayment($payment, $wallet->id);
+
return [
'id' => $response->id,
'redirectUrl' => $response->getCheckoutUrl(),
diff --git a/src/tests/Feature/Controller/PaymentsMollieTest.php b/src/tests/Feature/Controller/PaymentsMollieTest.php
--- a/src/tests/Feature/Controller/PaymentsMollieTest.php
+++ b/src/tests/Feature/Controller/PaymentsMollieTest.php
@@ -80,6 +80,7 @@
$response->assertStatus(401);
$user = $this->getTestUser('john@kolab.org');
+ $wallet = $user->wallets()->first();
// Test creating a mandate (invalid input)
$post = [];
@@ -104,7 +105,7 @@
$this->assertCount(1, $json['errors']);
$this->assertSame('The balance must be a number.', $json['errors']['balance'][0]);
- // Test creating a mandate (invalid input)
+ // Test creating a mandate (amount smaller than the minimum value)
$post = ['amount' => -100, 'balance' => 0];
$response = $this->actingAs($user)->post("api/v4/payments/mandate", $post);
$response->assertStatus(422);
@@ -116,6 +117,18 @@
$min = intval(PaymentProvider::MIN_AMOUNT / 100) . ' CHF';
$this->assertSame("Minimum amount for a single payment is {$min}.", $json['errors']['amount']);
+ // Test creating a mandate (negative balance, amount too small)
+ Wallet::where('id', $wallet->id)->update(['balance' => -2000]);
+ $post = ['amount' => PaymentProvider::MIN_AMOUNT / 100, 'balance' => 0];
+ $response = $this->actingAs($user)->post("api/v4/payments/mandate", $post);
+ $response->assertStatus(422);
+
+ $json = $response->json();
+
+ $this->assertSame('error', $json['status']);
+ $this->assertCount(1, $json['errors']);
+ $this->assertSame("The specified amount does not cover the balance on the account.", $json['errors']['amount']);
+
// Test creating a mandate (valid input)
$post = ['amount' => 20.10, 'balance' => 0];
$response = $this->actingAs($user)->post("api/v4/payments/mandate", $post);
@@ -126,6 +139,13 @@
$this->assertSame('success', $json['status']);
$this->assertRegExp('|^https://www.mollie.com|', $json['redirectUrl']);
+ // Assert the proper payment amount has been used
+ $payment = Payment::where('id', $json['id'])->first();
+ $this->assertSame(2010, $payment->amount);
+ $this->assertSame($wallet->id, $payment->wallet_id);
+ $this->assertSame("Kolab Now Auto-Payment Setup", $payment->description);
+ $this->assertSame(PaymentProvider::TYPE_MANDATE, $payment->type);
+
// Test fetching the mandate information
$response = $this->actingAs($user)->get("api/v4/payments/mandate");
$response->assertStatus(200);
@@ -456,12 +476,14 @@
$result = PaymentsController::topUpWallet($wallet);
$this->assertTrue($result);
- // Check that the payments table contains a new record with proper amount
- // There should be two records, one for the first payment and another for
- // the recurring payment
- $this->assertCount(1, $wallet->payments()->get());
- $payment = $wallet->payments()->first();
- $this->assertSame(2010, $payment->amount);
+ // Check that the payments table contains a new record with proper amount.
+ // There should be two records, one for the mandate payment and another for
+ // the top-up payment
+ $payments = $wallet->payments()->orderBy('amount')->get();
+ $this->assertCount(2, $payments);
+ $this->assertSame(0, $payments[0]->amount);
+ $this->assertSame(2010, $payments[1]->amount);
+ $payment = $payments[1];
// In mollie we don't have to wait for a webhook, the response to
// PaymentIntent already sets the status to 'paid', so we can test
@@ -488,7 +510,7 @@
$wallet->setSetting('mandate_disabled', 1);
$result = PaymentsController::topUpWallet($wallet);
$this->assertFalse($result);
- $this->assertCount(1, $wallet->payments()->get());
+ $this->assertCount(2, $wallet->payments()->get());
// Expect no payment if balance is ok
$wallet->setSetting('mandate_disabled', null);
@@ -496,7 +518,7 @@
$wallet->save();
$result = PaymentsController::topUpWallet($wallet);
$this->assertFalse($result);
- $this->assertCount(1, $wallet->payments()->get());
+ $this->assertCount(2, $wallet->payments()->get());
// Expect no payment if the top-up amount is not enough
$wallet->setSetting('mandate_disabled', null);
@@ -504,7 +526,7 @@
$wallet->save();
$result = PaymentsController::topUpWallet($wallet);
$this->assertFalse($result);
- $this->assertCount(1, $wallet->payments()->get());
+ $this->assertCount(2, $wallet->payments()->get());
Bus::assertDispatchedTimes(\App\Jobs\PaymentMandateDisabledEmail::class, 1);
Bus::assertDispatched(\App\Jobs\PaymentMandateDisabledEmail::class, function ($job) use ($wallet) {
@@ -518,7 +540,7 @@
$wallet->save();
$result = PaymentsController::topUpWallet($wallet);
$this->assertFalse($result);
- $this->assertCount(1, $wallet->payments()->get());
+ $this->assertCount(2, $wallet->payments()->get());
Bus::assertDispatchedTimes(\App\Jobs\PaymentMandateDisabledEmail::class, 1);
diff --git a/src/tests/Feature/Controller/WalletsTest.php b/src/tests/Feature/Controller/WalletsTest.php
--- a/src/tests/Feature/Controller/WalletsTest.php
+++ b/src/tests/Feature/Controller/WalletsTest.php
@@ -190,6 +190,8 @@
$john = $this->getTestUser('john@kolab.org');
$jack = $this->getTestUser('jack@kolab.org');
$wallet = $john->wallets()->first();
+ $wallet->balance = -100;
+ $wallet->save();
// Accessing a wallet of someone else
$response = $this->actingAs($jack)->get("api/v4/wallets/{$wallet->id}");
@@ -209,7 +211,6 @@
$this->assertSame('CHF', $json['currency']);
$this->assertSame($wallet->balance, $json['balance']);
$this->assertTrue(empty($json['description']));
- // TODO: This assertion does not work after a longer while from seeding
$this->assertTrue(!empty($json['notice']));
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 7, 5:11 AM (6 h, 59 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18841192
Default Alt Text
D1900.1775538680.diff (10 KB)
Attached To
Mode
D1900: Trigger auto-payment immediately after configuration
Attached
Detach File
Event Timeline