Initial commit
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 NekoMonci12
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
BIN
Photos/Cover.png
Normal file
BIN
Photos/Cover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
BIN
Photos/Example.png
Normal file
BIN
Photos/Example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 96 KiB |
BIN
Photos/Logo.png
Normal file
BIN
Photos/Logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
26
README.md
Normal file
26
README.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
## Installation
|
||||||
|
Download the code and place it in the `app/Extensions/Gateways/Midtrans` directory.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
In the admin panel, go to `Settings > Payment Gateways` and click on the `Midtrans` gateway. Enter Midtrans `MerchantID`/`Server-Key`/`Client-Key` then `Save`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
When a user selects the `Midtrans` gateway, they will be redirected to the Midtrans payment page. After the payment is completed, the user will be redirected back to the site.
|
||||||
|
|
||||||
|
## Setup Callback On Midtrans
|
||||||
|
1. Settings > SNAP Preferences > System Settings
|
||||||
|
```
|
||||||
|
Finish URL = https://yourdomain.com
|
||||||
|
Unfinish URL = https://yourdomain.com
|
||||||
|
Error Payment URL = https://yourdomain.com
|
||||||
|
```
|
||||||
|
2. Settings > Payment > Finish Redirect URL
|
||||||
|
```
|
||||||
|
Finish Redirect URL = https://yourdomain.com
|
||||||
|
```
|
||||||
|
3. Settings > Payment > Notification URL
|
||||||
|
```
|
||||||
|
Notification URL = https://yourdomain.com/extensions/midtrans/webhook
|
||||||
|
Recurring payment notification URL = https://yourdomain.com
|
||||||
|
Account linking notification URL = https://yourdomain.com
|
||||||
|
```
|
||||||
134
Upload/Midtrans.php
Normal file
134
Upload/Midtrans.php
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Extensions\Gateways\Midtrans;
|
||||||
|
|
||||||
|
use App\Classes\Extensions\Gateway;
|
||||||
|
use App\Helpers\ExtensionHelper;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class Midtrans extends Gateway
|
||||||
|
{
|
||||||
|
public function getMetadata()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'display_name' => 'Midtrans',
|
||||||
|
'version' => '1.0.0',
|
||||||
|
'author' => 'NekoMonci12',
|
||||||
|
'website' => 'https://github.com/NekoMonci12',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pay($total, $products, $invoiceId)
|
||||||
|
{
|
||||||
|
$hash = substr(hash('sha256', time()), 0, 16);
|
||||||
|
$orderId = 'PAYMENTER-' . $invoiceId . '-' . $hash;
|
||||||
|
|
||||||
|
$serverKey = ExtensionHelper::getConfig('Midtrans', 'server_key');
|
||||||
|
$merchantId = ExtensionHelper::getConfig('Midtrans', 'merchant_id');
|
||||||
|
$clientKey = ExtensionHelper::getConfig('Midtrans', 'client_key');
|
||||||
|
$debugMode = ExtensionHelper::getConfig('Midtrans', 'debug_mode');
|
||||||
|
if ($debugMode) {
|
||||||
|
$url = 'https://app.sandbox.midtrans.com/snap/v1/transactions';
|
||||||
|
} else {
|
||||||
|
$url = 'https://app.midtrans.com/snap/v1/transactions';
|
||||||
|
}
|
||||||
|
$transactionDetails = [
|
||||||
|
'order_id' => $orderId,
|
||||||
|
'gross_amount' => round($total, 2),
|
||||||
|
];
|
||||||
|
$itemDetails = [];
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$itemDetails[] = [
|
||||||
|
'id' => $product['id'] ?? uniqid(),
|
||||||
|
'price' => $product['price'] ?? 0,
|
||||||
|
'quantity' => $product['quantity'] ?? 1,
|
||||||
|
'name' => $product['name'] ?? 'Product',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$payload = [
|
||||||
|
'transaction_details' => $transactionDetails,
|
||||||
|
'item_details' => $itemDetails,
|
||||||
|
];
|
||||||
|
$headers = [
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'Authorization' => 'Basic ' . base64_encode($serverKey . ':'),
|
||||||
|
];
|
||||||
|
$response = Http::withHeaders($headers)
|
||||||
|
->post($url, $payload);
|
||||||
|
|
||||||
|
$responseJson = $response->json();
|
||||||
|
if ($response->failed() || isset($responseJson['error_messages'])) {
|
||||||
|
ExtensionHelper::error('Midtrans', $responseJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($responseJson['redirect_url'])) {
|
||||||
|
ExtensionHelper::error('Midtrans', [
|
||||||
|
'error' => 'Missing redirect_url in response.',
|
||||||
|
'response' => $responseJson,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $responseJson['redirect_url'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function webhook(Request $request)~
|
||||||
|
{
|
||||||
|
if (!$request->isMethod('post')) {
|
||||||
|
return response('Method Not Allowed', 405);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode($request->getContent(), true);
|
||||||
|
if (
|
||||||
|
isset($data['status_code'], $data['transaction_status']) &&
|
||||||
|
$data['status_code'] === "200" &&
|
||||||
|
in_array($data['transaction_status'], ['capture', 'settlement'])
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
$orderId = $data['order_id'];
|
||||||
|
$parts = explode('-', $orderId);
|
||||||
|
if (count($parts) >= 3) {
|
||||||
|
$invoiceId = $parts[1];
|
||||||
|
} else {
|
||||||
|
\Log::error('Invalid order_id format: ' . $orderId);
|
||||||
|
return response('Invalid order id format', 400);
|
||||||
|
}
|
||||||
|
ExtensionHelper::paymentDone($invoiceId, 'Midtrans', $data['transaction_id']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::error('Error processing paymentDone: ' . $e->getMessage());
|
||||||
|
return response('Error processing webhook', 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response('OK', 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfig()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'name' => 'server_key',
|
||||||
|
'type' => 'text',
|
||||||
|
'friendlyName' => 'Server Key',
|
||||||
|
'required' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'merchant_id',
|
||||||
|
'type' => 'text',
|
||||||
|
'friendlyName' => 'Merchant ID',
|
||||||
|
'required' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'client_key',
|
||||||
|
'type' => 'text',
|
||||||
|
'friendlyName' => 'Client Key',
|
||||||
|
'required' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'debug_mode',
|
||||||
|
'type' => 'boolean',
|
||||||
|
'friendlyName' => 'Should Debug Mode be enabled?',
|
||||||
|
'required' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
5
Upload/routes.php
Normal file
5
Upload/routes.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
Route::post('/midtrans/webhook', [App\Extensions\Gateways\Midtrans\Midtrans::class, 'webhook'])->name('midtrans.webhook');
|
||||||
Reference in New Issue
Block a user