Skip to content

Commit 3960165

Browse files
authored
Merge pull request #32 from tighten/alk/refund
Add Refund from Charge Detail Page
2 parents a32c6fa + 8a4a096 commit 3960165

File tree

8 files changed

+175
-19
lines changed

8 files changed

+175
-19
lines changed

dist/js/tool.js

+64-2
Original file line numberDiff line numberDiff line change
@@ -2866,14 +2866,49 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
28662866
//
28672867
//
28682868
//
2869+
//
2870+
//
2871+
//
2872+
//
2873+
//
2874+
//
2875+
//
2876+
//
2877+
//
2878+
//
2879+
//
2880+
//
2881+
//
2882+
//
2883+
//
28692884

28702885

28712886

28722887
/* harmony default export */ __webpack_exports__["default"] = ({
28732888
props: ['chargeId'],
2874-
28752889
components: {
28762890
'charge-detail-card': __WEBPACK_IMPORTED_MODULE_0__components_ChargeDetailCard_vue___default.a
2891+
},
2892+
data: function data() {
2893+
return {
2894+
charge: undefined,
2895+
deleting: false
2896+
};
2897+
},
2898+
2899+
methods: {
2900+
refund: function refund(chargeId) {
2901+
var _this = this;
2902+
2903+
this.deleting = true;
2904+
2905+
Nova.request().post('/nova-vendor/nova-stripe/stripe/charges/' + this.chargeId + '/refund').then(function (response) {
2906+
Nova.success('Charge Successfully Refunded!');
2907+
_this.$refs.detail.getCharge();
2908+
});
2909+
2910+
this.deleting = false;
2911+
}
28772912
}
28782913
});
28792914

@@ -2996,6 +3031,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
29963031
Nova.request().get('/nova-vendor/nova-stripe/stripe/charges/' + this.chargeId).then(function (response) {
29973032
_this.charge = response.data.charge;
29983033
_this.initialLoading = false;
3034+
_this.$emit('charge-loaded', response.data.charge);
29993035
});
30003036
},
30013037
formatMoney: function formatMoney(amount, currency) {
@@ -3106,7 +3142,33 @@ var render = function() {
31063142
[
31073143
_c("heading", { staticClass: "mb-6" }, [_vm._v("Charge Details")]),
31083144
_vm._v(" "),
3109-
_c("charge-detail-card", { attrs: { "charge-id": _vm.chargeId } })
3145+
_c("div", { staticClass: "flex flex-row-reverse mb-3" }, [
3146+
_vm.charge && !_vm.charge.refunded
3147+
? _c(
3148+
"button",
3149+
{
3150+
staticClass: "btn-primary px-4 py-2 rounded",
3151+
attrs: { disabled: _vm.deleting },
3152+
on: {
3153+
click: function($event) {
3154+
return _vm.refund(_vm.charge.id)
3155+
}
3156+
}
3157+
},
3158+
[_vm._v("\n Refund\n ")]
3159+
)
3160+
: _vm._e()
3161+
]),
3162+
_vm._v(" "),
3163+
_c("charge-detail-card", {
3164+
ref: "detail",
3165+
attrs: { "charge-id": _vm.chargeId },
3166+
on: {
3167+
"charge-loaded": function($event) {
3168+
_vm.charge = $event
3169+
}
3170+
}
3171+
})
31103172
],
31113173
1
31123174
)

package.json

+6
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,11 @@
1616
"dependencies": {
1717
"currency.js": "^1.2.1",
1818
"vue": "^2.5.0"
19+
},
20+
"prettier": {
21+
"singleQuote": true,
22+
"trailingComma": "es5",
23+
"tabWidth": 4,
24+
"printWidth": 80
1925
}
2026
}

resources/js/components/ChargeDetailCard.vue

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export default {
6565
.then((response) => {
6666
this.charge = response.data.charge
6767
this.initialLoading = false
68+
this.$emit('charge-loaded', response.data.charge);
6869
})
6970
},
7071

resources/js/views/Detail.vue

+46-8
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,56 @@
22
<div>
33
<heading class="mb-6">Charge Details</heading>
44

5-
<charge-detail-card :charge-id="chargeId"></charge-detail-card>
5+
<div class="flex flex-row-reverse mb-3">
6+
<button
7+
v-if="charge && !charge.refunded"
8+
class="btn-primary px-4 py-2 rounded"
9+
@click="refund(charge.id)"
10+
:disabled="deleting"
11+
>
12+
Refund
13+
</button>
14+
</div>
15+
16+
<charge-detail-card
17+
ref="detail"
18+
:charge-id="chargeId"
19+
@charge-loaded="charge = $event"
20+
/>
621
</div>
722
</template>
823

924
<script>
10-
import ChargeDetailCard from '../components/ChargeDetailCard.vue'
25+
import ChargeDetailCard from '../components/ChargeDetailCard.vue';
26+
27+
export default {
28+
props: ['chargeId'],
29+
components: {
30+
'charge-detail-card': ChargeDetailCard,
31+
},
32+
data() {
33+
return {
34+
charge: undefined,
35+
deleting: false,
36+
};
37+
},
38+
methods: {
39+
refund(chargeId) {
40+
this.deleting = true;
1141
12-
export default {
13-
props: ['chargeId'],
42+
Nova.request()
43+
.post(
44+
'/nova-vendor/nova-stripe/stripe/charges/' +
45+
this.chargeId +
46+
'/refund'
47+
)
48+
.then((response) => {
49+
Nova.success('Charge Successfully Refunded!');
50+
this.$refs.detail.getCharge();
51+
});
1452
15-
components: {
16-
'charge-detail-card': ChargeDetailCard,
17-
}
18-
}
53+
this.deleting = false;
54+
},
55+
},
56+
};
1957
</script>

routes/api.php

+1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@
1818

1919
Route::get('/stripe/charges', StripeChargesController::class . '@index');
2020
Route::get('/stripe/charges/{id}', StripeChargesController::class . '@show');
21+
Route::post('/stripe/charges/{id}/refund', StripeChargesController::class . '@refund');
2122
Route::get('/stripe/balance', StripeBalanceController::class . '@index');

src/Clients/StripeClient.php

+19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Exception;
66
use Stripe\Balance;
77
use Stripe\Charge;
8+
use Stripe\Refund;
89

910
class StripeClient
1011
{
@@ -52,4 +53,22 @@ public function getBalance()
5253

5354
}
5455
}
56+
57+
public function refundCharge($chargeId)
58+
{
59+
try {
60+
return Refund::create(['charge' => $chargeId], ['api_key' => $this->apiKey]);
61+
} catch (Exception $e) {
62+
63+
}
64+
}
65+
66+
public function createCharge(array $params)
67+
{
68+
try {
69+
return Charge::create($params, ['api_key' => $this->apiKey]);
70+
} catch (Exception $e) {
71+
72+
}
73+
}
5574
}

src/Http/StripeChargesController.php

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Tighten\NovaStripe\Http;
44

55
use Illuminate\Routing\Controller;
6+
use Stripe\Charge;
67
use Tighten\NovaStripe\Clients\StripeClient;
78

89
class StripeChargesController extends Controller
@@ -20,4 +21,9 @@ public function show($id)
2021
{
2122
return response()->json(['charge' => (new StripeClient)->getCharge($id)]);
2223
}
24+
25+
public function refund($id)
26+
{
27+
return response()->json((new StripeClient)->refundCharge($id));
28+
}
2329
}

tests/StripeChargeControllerTest.php

+32-9
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
namespace Tighten\NovaStripe\Tests;
44

55
use Illuminate\Foundation\Testing\WithFaker;
6-
use Illuminate\Support\Facades\Config;
7-
use Stripe\Charge;
8-
use Stripe\StripeClient;
6+
use Tighten\NovaStripe\Clients\StripeClient;
97

108
class StripeChargeControllerTest extends TestCase
119
{
@@ -17,11 +15,10 @@ class StripeChargeControllerTest extends TestCase
1715
public function setUp(): void
1816
{
1917
parent::setUp();
20-
$this->stripe = new StripeClient(Config::get('services.stripe.secret'));
18+
$this->stripe = new StripeClient;
2119

22-
$this->charge = $this->stripe->charges->all()->count()
23-
? $this->stripe->charges->all(['limit' => 1])->first()
24-
: $this->stripe->charges->create([
20+
$this->charge = $this->findSuccessfulNonRefundedCharge()
21+
?: $this->stripe->createCharge([
2522
'amount' => $this->faker->numberBetween(50, 1000),
2623
'currency' => 'usd',
2724
'source' => 'tok_mastercard',
@@ -54,7 +51,7 @@ public function it_returns_a_list_of_charges()
5451
public function it_returns_charge_details()
5552
{
5653
$response = $this->get('nova-vendor/nova-stripe/stripe/charges/' . $this->charge->id);
57-
$stripeCharge = Charge::retrieve(['id' => $this->charge->id, 'expand' => ['balance_transaction']], ['api_key' => Config::get('services.stripe.secret')]);
54+
$stripeCharge = $this->stripe->getCharge($this->charge->id);
5855

5956
$response->assertJsonFragment([
6057
'id' => $stripeCharge->id,
@@ -86,12 +83,38 @@ public function it_returns_charge_details()
8683
/** @test */
8784
public function it_shows_the_current_balance()
8885
{
89-
$balance = $this->stripe->balance->retrieve();
86+
$balance = $this->stripe->getBalance();
9087

9188
$this->get('nova-vendor/nova-stripe/stripe/balance')
9289
->assertJsonFragment([
9390
'available' => $balance->available,
9491
'pending' => $balance->pending,
9592
]);
9693
}
94+
95+
/** @test */
96+
public function it_can_refund_a_charge_successfully()
97+
{
98+
$this->post('nova-vendor/nova-stripe/stripe/charges/' . $this->charge->id . '/refund')
99+
->assertSuccessful()
100+
->assertJsonFragment([
101+
'charge' => $this->charge->id,
102+
'status' => 'succeeded',
103+
]);
104+
105+
$this->assertTrue($this->stripe->getCharge($this->charge->id)->refunded);
106+
}
107+
108+
public function findSuccessfulNonRefundedCharge()
109+
{
110+
$charges = $this->stripe->listCharges();
111+
112+
foreach ($charges as $charge) {
113+
if (! $charge->refunded && $charge->status === 'succeeded') {
114+
return $charge;
115+
}
116+
}
117+
118+
return null;
119+
}
97120
}

0 commit comments

Comments
 (0)