v2 first commit

This commit is contained in:
denisdulici
2019-11-16 10:21:14 +03:00
parent 5b23e9c2c4
commit 6d50fa8442
3075 changed files with 3451681 additions and 65594 deletions

View File

@ -1,99 +0,0 @@
<?php
namespace Modules\OfflinePayment\Http\Controllers;
use App\Events\InvoicePaid;
use Illuminate\Routing\Controller;
use Illuminate\Http\Request;
use App\Http\Requests\Customer\InvoicePayment as PaymentRequest;
use App\Http\Requests\Customer\InvoiceConfirm as ConfirmRequest;
use App\Models\Income\Invoice;
use SignedUrl;
class OfflinePayment extends Controller
{
/**
* Show the form for editing the specified resource.
* @param Invoice
* @param PaymentRequest
* @return JSON
*/
public function show(Invoice $invoice, PaymentRequest $request)
{
$gateway = [];
$payment_methods = json_decode(setting('offlinepayment.methods'), true);
foreach ($payment_methods as $payment_method) {
if ($payment_method['code'] == $request['payment_method']) {
$gateway = $payment_method;
break;
}
}
$html = view('offlinepayment::show', compact('gateway', 'invoice'))->render();
return response()->json([
'code' => $gateway['code'],
'name' => $gateway['name'],
'description' => $gateway['description'],
'redirect' => false,
'html' => $html,
]);
}
/**
* Show the form for editing the specified resource.
* @param $invoice
* @param $request
* @return JSON
*/
public function link(Invoice $invoice, PaymentRequest $request)
{
$gateway = [];
$payment_methods = json_decode(setting('offlinepayment.methods'), true);
foreach ($payment_methods as $payment_method) {
if ($payment_method['code'] == $request['payment_method']) {
$gateway = $payment_method;
break;
}
}
$confirm_action = SignedUrl::sign(url('signed/invoices/' . $invoice->id . '/offlinepayment/confirm'), 1);
$html = view('offlinepayment::link', compact('gateway', 'invoice', 'confirm_action'))->render();
return response()->json([
'code' => $gateway['code'],
'name' => $gateway['name'],
'description' => $gateway['description'],
'redirect' => false,
'html' => $html,
]);
}
public function confirm(Invoice $invoice, Request $request)
{
$message = trans('messages.success.added', ['type' => trans_choice('general.customers', 1)]);
flash($message)->success();
$event_response = event(new InvoicePaid($invoice, [
'amount' => $invoice->amount,
'payment_method' => $request['payment_method'],
]));
return response()->json([
'error' => false,
'success' => true,
]);
}
}

View File

@ -1,30 +0,0 @@
<?php
Route::group([
'middleware' => 'admin',
'prefix' => 'apps/offlinepayment',
'namespace' => 'Modules\OfflinePayment\Http\Controllers'
], function () {
Route::get('settings', 'Settings@edit')->name('offlinepayment.edit');
Route::post('settings', 'Settings@update')->name('offlinepayment.update');
Route::post('settings/get', 'Settings@get')->name('offlinepayment.get');
Route::post('settings/delete', 'Settings@delete')->name('offlinepayment.delete');
});
Route::group([
'middleware' => 'customer',
'prefix' => 'customers',
'namespace' => 'Modules\OfflinePayment\Http\Controllers'
], function () {
Route::get('invoices/{invoice}/offlinepayment', 'OfflinePayment@show');
Route::post('invoices/{invoice}/offlinepayment/confirm', 'OfflinePayment@confirm');
});
Route::group([
'middleware' => ['signed', 'language'],
'prefix' => 'signed',
'namespace' => 'Modules\OfflinePayment\Http\Controllers'
], function () {
Route::post('invoices/{invoice}/offlinepayment', 'OfflinePayment@link');
Route::post('invoices/{invoice}/offlinepayment/confirm', 'OfflinePayment@confirm');
});

View File

@ -1,28 +0,0 @@
<?php
namespace Modules\OfflinePayment\Listeners;
use App\Events\AdminMenuCreated;
class AdminMenu
{
/**
* Handle the event.
*
* @param AdminMenuCreated $event
* @return void
*/
public function handle(AdminMenuCreated $event)
{
$user = auth()->user();
// Settings
if ($user->can(['read-settings-settings', 'read-settings-categories', 'read-settings-currencies', 'read-settings-taxes'])) {
// Add child to existing item
$item = $event->menu->whereTitle(trans_choice('general.settings', 2));
$item->url('apps/offlinepayment/settings', trans('offlinepayment::general.title'), 4, ['icon' => 'fa fa-angle-double-right']);
}
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace Modules\OfflinePayment\Listeners;
use App\Events\PaymentGatewayListing;
class Gateway
{
/**
* Handle the event.
*
* @param PaymentGatewayListing $event
* @return void
*/
public function handle(PaymentGatewayListing $event)
{
return json_decode(setting('offlinepayment.methods'), true);
}
}

View File

@ -1,99 +0,0 @@
<?php
namespace Modules\OfflinePayment\Providers;
use App\Events\AdminMenuCreated;
use App\Events\PaymentGatewayListing;
use Illuminate\Support\ServiceProvider;
use Modules\OfflinePayment\Listeners\AdminMenu;
use Modules\OfflinePayment\Listeners\Gateway;
class OfflinePaymentServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->registerTranslations();
$this->registerViews();
$this->registerMigrations();
$this->registerEvents();
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
}
/**
* Register views.
*
* @return void
*/
public function registerViews()
{
$viewPath = resource_path('views/modules/offlinepayment');
$sourcePath = __DIR__.'/../Resources/views';
$this->publishes([
$sourcePath => $viewPath
]);
$this->loadViewsFrom(array_merge(array_map(function ($path) {
return $path . '/modules/offlinepayment';
}, \Config::get('view.paths')), [$sourcePath]), 'offlinepayment');
}
/**
* Register translations.
*
* @return void
*/
public function registerTranslations()
{
$langPath = resource_path('lang/modules/offlinepayment');
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, 'offlinepayment');
} else {
$this->loadTranslationsFrom(__DIR__ .'/../Resources/lang', 'offlinepayment');
}
}
public function registerMigrations()
{
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
}
public function registerEvents()
{
$this->app['events']->listen(AdminMenuCreated::class, AdminMenu::class);
$this->app['events']->listen(PaymentGatewayListing::class, Gateway::class);
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
}

View File

@ -1,21 +0,0 @@
<?php
return [
'title' => 'Offline Payments',
'add_new' => 'Add New',
'edit' => 'Edit: :method',
'form' => [
'code' => 'Code',
'customer' => 'Show to Customer',
'order' => 'Order'
],
'payment_gateways' => 'Offline Payment Methods',
'confirm' => 'Confirm',
'loading' => 'Loading',
];

View File

@ -1,7 +0,0 @@
<h2>{{ $gateway['name'] }}</h2>
@if ($gateway['description'])
<div class="well well-sm">
{{ $gateway['description'] }}
</div>
@endif

View File

@ -1,212 +0,0 @@
@extends('layouts.admin')
@section('title', trans('offlinepayment::general.title'))
@section('content')
<div class="row">
<div class="col-md-4">
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('offlinepayment::general.add_new') }}</h3>
<!-- /.box-tools -->
</div>
<!-- /.box-header -->
{!! Form::open(['route' => 'offlinepayment.update', 'files' => true, 'role' => 'form', 'class' => 'form-loading-button']) !!}
<div class="box-body">
<div id="install-loading"></div>
{{ Form::textGroup('name', trans('general.name'), 'id-card-o', ['required' => 'required'], null, 'col-md-12') }}
{{ Form::textGroup('code', trans('offlinepayment::general.form.code'), 'key', ['required' => 'required'], null, 'col-md-12') }}
{{ Form::radioGroup('customer', trans('offlinepayment::general.form.customer'), '', ['required' => 'required'], 0, 'col-md-12') }}
{{ Form::textGroup('order', trans('offlinepayment::general.form.order'), 'sort', [], null, 'col-md-12') }}
{{ Form::textareaGroup('description', trans('general.description')) }}
</div>
<!-- /.box-body -->
<div class="box-footer">
{{ Form::saveButtons('apps/offlinepayment/settings') }}
</div>
<!-- /.box-footer -->
{!! Form::close() !!}
</div>
<!-- /.box -->
</div>
<div class="col-md-8">
<!-- Default box -->
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">{{ trans('offlinepayment::general.payment_gateways') }}</h3>
<!-- /.box-tools -->
</div>
<!-- /.box-header -->
<div class="box-body">
<div id="delete-loading"></div>
<div class="table table-responsive">
<table class="table table-striped table-hover" id="tbl-items">
<thead>
<tr>
<th class="col-md-3">{{ trans('general.name') }}</th>
<th class="col-md-4">{{ trans('offlinepayment::general.form.code') }}</th>
<th class="col-md-2 text-center">{{ trans('offlinepayment::general.form.order') }}</th>
<th class="col-md-3 text-center">{{ trans('general.actions') }}</th>
</tr>
</thead>
<tbody>
@if($items)
@foreach($items as $item)
<tr id="method-{{ $item->code }}">
<td>{{ $item->name }}</td>
<td>{{ $item->code }}</td>
<td class="text-center">{{ $item->order }}</td>
<td class="text-center">
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" data-toggle-position="left" aria-expanded="false">
<i class="fa fa-ellipsis-h"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="#" class="method-edit" id="edit-{{ $item->code }}">{{ trans('general.edit') }}</a></li>
<li class="divider"></li>
<li><a href="#" class="method-delete" id="delete-{{ $item->code }}">{{ trans('general.delete') }}</a></li>
</ul>
</div>
</td>
</tr>
@endforeach
@else
@endif
</tbody>
</table>
</div>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
</div>
@endsection
@push('stylesheet')
<style type="text/css">
#install-loading.active, #delete-loading.active {
font-size: 35px;
position: absolute;
z-index: 500;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background: rgb(136, 136, 136);
opacity: 0.2;
-moz-border-radius-bottomleft: 1px;
-moz-border-radius-bottomright: 1px;
border-bottom-left-radius: 1px;
border-bottom-right-radius: 1px;
}
.install-loading-spin {
font-size: 100px;
position: absolute;
margin: auto;
color: #fff;
padding: 45% 40%;
}
#delete-loading .install-loading-spin {
padding: 8% 40%;
}
</style>
@endpush
@push('scripts')
<script type="text/javascript">
var text_yes = '{{ trans('general.yes') }}';
var text_no = '{{ trans('general.no') }}';
var code = '';
var tr = '';
$(document).ready(function() {
$('.method-edit').on('click', function() {
code = $(this).attr('id').replace('edit-', '');
$.ajax({
url: '{{ route("offlinepayment.get") }}',
type: 'post',
dataType: 'json',
data: {code: code},
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
beforeSend: function() {
$('#install-loading').addClass('active');
$('#install-loading').html('<span class="install-loading-bar"><span class="install-loading-spin"><i class="fa fa-spinner fa-spin"></i></span></span>');
},
complete: function() {
$('#install-loading').removeClass('active');
$('#install-loading .install-loading-bar').remove();
},
success: function(json) {
if (json['error']) {
}
if (json['success']) {
$('.col-md-4.no-padding-left .box-header.with-border .box-title').html(json['data']['title']);
$('input[name="name"]').val(json['data']['name']);
$('input[name="code"]').val(json['data']['code']);
if (json['data']['customer'] == 1) {
$('#customer_1 input').trigger('click');
} else {
$('#customer_0 input').trigger('click');
}
$('input[name="order"]').val(json['data']['order']);
$('textarea[name="description"]').val(json['data']['description']);
$('input[name="method"]').remove();
$('.col-md-4 .box-body').append('<input type="hidden" name="method" value="' + json['data']['method'] + '">');
}
}
});
});
$('.method-delete').on('click', function() {
code = $(this).attr('id').replace('delete-', '');
tr = $(this).parent().parent();
$.ajax({
url: '{{ route("offlinepayment.delete") }}',
type: 'post',
dataType: 'json',
data: {code: code},
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
beforeSend: function() {
$('#delete-loading').addClass('active');
$('#delete-loading').html('<span class="install-loading-bar"><span class="install-loading-spin"><i class="fa fa-spinner fa-spin"></i></span></span>');
},
complete: function() {
//$('#delete-loading').removeClass('active');
//$('#delete-loading .install-loading-bar').remove();
},
success: function(json) {
if (json['error']) {
}
if (json['success']) {
$('#method-' + code).remove();
location.reload();
}
}
});
});
});
</script>
@endpush

View File

@ -1,19 +0,0 @@
{
"name": "OfflinePayment",
"alias": "offlinepayment",
"description": "",
"version": "1.0.0",
"category": "payment-gateway",
"keywords": [],
"active": 1,
"order": 0,
"providers": [
"Modules\\OfflinePayment\\Providers\\OfflinePaymentServiceProvider"
],
"aliases": {},
"files": [
"start.php"
],
"requires": [],
"settings": []
}

View File

@ -1,17 +0,0 @@
<?php
/*
|--------------------------------------------------------------------------
| Register Namespaces And Routes
|--------------------------------------------------------------------------
|
| When a module starting, this file will executed automatically. This helps
| to register some namespaces like translator or view. Also this file
| will load the routes file for each module. You may also modify
| this file as you want.
|
*/
if (!app()->routesAreCached()) {
require __DIR__ . '/Http/routes.php';
}

View File

@ -39,7 +39,7 @@ class OfflineFile extends Migration
// Set the active company settings
setting()->setExtraColumns(['company_id' => 1]);
setting()->set('offlinepayment.methods', json_encode($offlinepayment));
setting()->set('offline-payments.methods', json_encode($offlinepayment));
setting()->forget('offline.payment.methods');

View File

@ -1,11 +1,12 @@
<?php
namespace Modules\OfflinePayment\Database\Seeders;
namespace Modules\OfflinePayments\Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Setting;
class OfflinePaymentDatabaseSeeder extends Seeder
class OfflinePaymentsDatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
@ -23,28 +24,24 @@ class OfflinePaymentDatabaseSeeder extends Seeder
private function create()
{
$company_id = $this->command->argument('company');
$methods = array();
setting()->setExtraColumns(['company_id' => $company_id]);
$methods = [];
$methods[] = [
'code' => 'offlinepayment.cash.1',
$methods[] = array(
'code' => 'offline-payments.cash.1',
'name' => 'Cash',
'customer' => '0',
'order' => '1',
'description' => null,
];
);
$methods[] = [
'code' => 'offlinepayment.bank_transfer.2',
$methods[] = array(
'code' => 'offline-payments.bank_transfer.2',
'name' => 'Bank Transfer',
'customer' => '0',
'order' => '2',
'description' => null,
];
);
setting()->set('offlinepayment.methods', json_encode($methods));
Setting::set('offline-payments.methods', json_encode($methods));
}
}

View File

@ -0,0 +1,95 @@
<?php
namespace Modules\OfflinePayments\Http\Controllers;
use App\Abstracts\Http\PaymentController;
use App\Http\Requests\Portal\InvoicePayment as PaymentRequest;
use App\Models\Income\Invoice;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;
class Payment extends PaymentController
{
public $alias = 'offline-payments';
public $type = 'redirect';
public function show(Invoice $invoice, PaymentRequest $request)
{
$setting = [];
$payment_methods = json_decode(setting('offline-payments.methods'), true);
foreach ($payment_methods as $payment_method) {
if ($payment_method['code'] == $request['payment_method']) {
$setting = $payment_method;
break;
}
}
$html = view('offline-payments::show', compact('setting', 'invoice'))->render();
return response()->json([
'code' => $setting['code'],
'name' => $setting['name'],
'description' => $setting['description'],
'redirect' => false,
'html' => $html,
]);
}
public function signed(Invoice $invoice, PaymentRequest $request)
{
$setting = [];
$payment_methods = json_decode(setting('offline-payments.methods'), true);
foreach ($payment_methods as $payment_method) {
if ($payment_method['code'] == $request['payment_method']) {
$setting = $payment_method;
break;
}
}
$confirm_url = URL::signedRoute('signed.invoices.offline-payments.confirm', [$invoice->id, 'company_id' => session('company_id')]);
$html = view('offline-payments::signed', compact('setting', 'invoice', 'confirm_url'))->render();
return response()->json([
'code' => $setting['code'],
'name' => $setting['name'],
'description' => $setting['description'],
'redirect' => false,
'html' => $html,
]);
}
public function confirm(Invoice $invoice, Request $request)
{
try {
event(new \App\Events\Income\PaymentReceived($invoice, $request));
$message = trans('messages.success.added', ['type' => trans_choice('general.payments', 1)]);
$response = [
'success' => true,
'error' => false,
'message' => $message,
'data' => false,
];
} catch(\Exception $e) {
$message = $e->getMessage();
$response = [
'success' => false,
'error' => true,
'message' => $message,
'data' => false,
];
}
return response()->json($response);
}
}

View File

@ -1,14 +1,13 @@
<?php
namespace Modules\OfflinePayment\Http\Controllers;
namespace Modules\OfflinePayments\Http\Controllers;
use Artisan;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Modules\OfflinePayment\Http\Requests\Setting as Request;
use Modules\OfflinePayment\Http\Requests\SettingGet as GRequest;
use Modules\OfflinePayment\Http\Requests\SettingDelete as DRequest;
use Modules\OfflinePayments\Http\Requests\Setting as Request;
use Modules\OfflinePayments\Http\Requests\SettingGet as GRequest;
use Modules\OfflinePayments\Http\Requests\SettingDelete as DRequest;
class Settings extends Controller
{
@ -20,9 +19,9 @@ class Settings extends Controller
*/
public function edit()
{
$items = json_decode(setting('offlinepayment.methods'));
$items = json_decode(setting('offline-payments.methods'));
return view('offlinepayment::edit', compact('items'));
return view('offline-payments::edit', compact('items'));
}
/**
@ -34,7 +33,7 @@ class Settings extends Controller
*/
public function update(Request $request)
{
$methods = json_decode(setting('offlinepayment.methods'), true);
$methods = json_decode(setting('offline-payments.methods'), true);
if (isset($request['method'])) {
foreach ($methods as $key => $method) {
@ -44,30 +43,45 @@ class Settings extends Controller
$method = explode('.', $request['method']);
$methods[$key]['code'] = 'offlinepayment.' . $request['code'] . '.' . $method[2];
$methods[$key]['code'] = 'offline-payments.' . $request['code'] . '.' . $method[2];
$methods[$key]['name'] = $request['name'];
$methods[$key]['customer'] = $request['customer'];
$methods[$key]['order'] = $request['order'];
$methods[$key]['description'] = $request['description'];
}
$message = trans('messages.success.updated', ['type' => $request['name']]);
} else {
$methods[] = array(
'code' => 'offlinepayment.' . $request['code'] . '.' . (count($methods) + 1),
'code' => 'offline-payments.' . $request['code'] . '.' . (count($methods) + 1),
'name' => $request['name'],
'customer' => $request['customer'],
'order' => $request['order'],
'description' => $request['description']
);
$message = trans('messages.success.added', ['type' => $request['name']]);
}
// Set Api Token
setting()->set('offlinepayment.methods', json_encode($methods));
setting()->set('offline-payments.methods', json_encode($methods));
setting()->save();
Artisan::call('cache:clear');
return redirect()->route('offlinepayment.edit');
$response = [
'status' => null,
'success' => true,
'error' => false,
'message' => $message,
'data' => null,
'redirect' => route('offline-payments.edit'),
];
flash($message)->success();
return response()->json($response);
}
/**
@ -83,15 +97,15 @@ class Settings extends Controller
$code = $request['code'];
$methods = json_decode(setting('offlinepayment.methods'), true);
$methods = json_decode(setting('offline-payments.methods'), true);
foreach ($methods as $key => $method) {
if ($method['code'] != $code) {
continue;
}
$method['title'] = trans('offlinepayment::offlinepayment.edit', ['method' => $method['name']]);
$method['method'] = $code;
$method['title'] = trans('offline-payments::offline-payments.edit', ['method' => $method['name']]);
$method['update'] = $code;
$code = explode('.', $method['code']);
@ -116,30 +130,36 @@ class Settings extends Controller
*
* @return Response
*/
public function delete(DRequest $request)
public function destroy(DRequest $request)
{
$code = $request['code'];
$methods = json_decode(setting('offlinepayment.methods'), true);
$methods = json_decode(setting('offline-payments.methods'), true);
$remove = false;
foreach ($methods as $key => $method) {
if ($method['code'] != $code) {
continue;
}
$remove = $methods[$key];
unset($methods[$key]);
}
// Set Api Token
setting()->set('offlinepayment.methods', json_encode($methods));
setting()->set('offline-payments.methods', json_encode($methods));
setting()->save();
Artisan::call('cache:clear');
$message = trans('messages.success.deleted', ['type' => $remove['name']]);
return response()->json([
'errors' => false,
'success' => true,
'message' => $message
]);
}
}

View File

@ -1,8 +1,8 @@
<?php
namespace Modules\OfflinePayment\Http\Requests;
namespace Modules\OfflinePayments\Http\Requests;
use App\Http\Requests\Request;
use App\Abstracts\Http\FormRequest as Request;
class Setting extends Request
{

View File

@ -1,8 +1,8 @@
<?php
namespace Modules\OfflinePayment\Http\Requests;
namespace Modules\OfflinePayments\Http\Requests;
use App\Http\Requests\Request;
use App\Abstracts\Http\FormRequest as Request;
class SettingDelete extends Request
{

View File

@ -1,8 +1,8 @@
<?php
namespace Modules\OfflinePayment\Http\Requests;
namespace Modules\OfflinePayments\Http\Requests;
use App\Http\Requests\Request;
use App\Abstracts\Http\FormRequest as Request;
class SettingGet extends Request
{

View File

@ -1,8 +1,8 @@
<?php
namespace Modules\OfflinePayment\Http\Requests;
namespace Modules\OfflinePayments\Http\Requests;
use App\Http\Requests\Request;
use App\Abstracts\Http\FormRequest as Request;
class Show extends Request
{

View File

@ -0,0 +1,23 @@
<?php
namespace Modules\OfflinePayments\Listeners;
use App\Events\Module\PaymentMethodShowing as Event;
class ShowPaymentMethod
{
/**
* Handle the event.
*
* @param Event $event
* @return void
*/
public function handle(Event $event)
{
$methods = json_decode(setting('offline-payments.methods'), true);
foreach ($methods as $method) {
$event->modules->payment_methods[] = $method;
}
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace Modules\OfflinePayments\Listeners;
use App\Events\Module\SettingShowing as Event;
class ShowSetting
{
/**
* Handle the event.
*
* @param Event $event
* @return void
*/
public function handle(Event $event)
{
$event->modules->settings['offline-payments'] = [
'name' => trans('offline-payments::general.name'),
'description' => trans('offline-payments::general.description'),
'url' => 'settings/offline-payments',
'icon' => 'fas fa-credit-card',
];
}
}

View File

@ -0,0 +1,106 @@
<?php
namespace Modules\OfflinePayments\Providers;
use Illuminate\Support\ServiceProvider as Provider;
use Modules\OfflinePayments\Listeners\ShowPaymentMethod;
use Modules\OfflinePayments\Listeners\ShowSetting;
class Main extends Provider
{
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->loadTranslations();
$this->loadMigrations();
$this->loadViews();
$this->loadEvents();
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->loadRoutes();
}
/**
* Register views.
*
* @return void
*/
public function loadViews()
{
$this->loadViewsFrom(__DIR__ . '/../Resources/views', 'offline-payments');
}
/**
* Register translations.
*
* @return void
*/
public function loadTranslations()
{
$this->loadTranslationsFrom(__DIR__ .'/../Resources/lang', 'offline-payments');
}
/**
* Load migrations.
*
* @return void
*/
public function loadMigrations()
{
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
}
/**
* Load events.
*
* @return void
*/
public function loadEvents()
{
$this->app['events']->listen(\App\Events\Module\PaymentMethodShowing::class, ShowPaymentMethod::class);
$this->app['events']->listen(\App\Events\Module\SettingShowing::class, ShowSetting::class);
}
/**
* Load routes.
*
* @return void
*/
public function loadRoutes()
{
if (app()->routesAreCached()) {
return;
}
$routes = [
'admin.php',
'portal.php',
'signed.php',
];
foreach ($routes as $route) {
$this->loadRoutesFrom(__DIR__ . '/../Routes/' . $route);
}
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
}

View File

@ -0,0 +1,83 @@
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./../../../../../resources/assets/js/bootstrap');
import Vue from 'vue';
import Global from './../../../../../resources/assets/js/mixins/global';
import Form from './../../../../../resources/assets/js/plugins/form';
const app = new Vue({
el: '#app',
mixins: [
Global
],
data() {
return {
form: new Form('offline-payments')
}
},
methods:{
onEdit(event) {
var code = event.target.dataset.code;
this.form.loading = true;
axios.post('offline-payments/get', {
code: code
})
.then(response => {
this.form.name = response.data.data.name;
this.form.code = response.data.data.code;
this.form.customer = response.data.data.customer;
this.form.order = response.data.data.order;
this.form.description = response.data.data.description;
this.form.update = response.data.data.update;
this.form.loading = false;
})
.catch(error => {
this.form.loading = false;
});
},
onDelete() {
axios({
method: 'DELETE',
url: 'offline-payments/delete',
data: {
code: this.confirm.code
}
})
.then(response => {
if (response.data.success) {
var type = (response.data.success) ? 'success' : 'warning';
this.$notify({
message: response.data.message,
timeout: 5000,
icon: 'fas fa-bell',
type
});
document.getElementById('method-' + this.confirm.code).remove();
this.confirm.code = '';
this.confirm.title = '';
this.confirm.message = '';
this.confirm.show = false;
}
})
.catch(error => {
this.success = false;
});
}
}
});

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,21 @@
<?php
return [
'name' => 'Offline Payments',
'description' => 'Create unlimited payment options for admin usage',
'add_new' => 'Add New',
'edit' => 'Edit: :method',
'form' => [
'code' => 'Code',
'customer' => 'Show to Customer',
'order' => 'Order'
],
'methods' => 'Method|Methods',
'payment_gateways' => 'Offline Payment Methods',
];

View File

@ -0,0 +1,7 @@
<h2>{{ $setting['name'] }}</h2>
@if ($setting['description'])
<div class="well well-sm">
{{ $setting['description'] }}
</div>
@endif

View File

@ -0,0 +1,124 @@
@extends('layouts.admin')
@section('title', trans('offline-payments::general.name'))
@section('content')
<div class="row">
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h3 class="mb-0">{{ trans('offline-payments::general.add_new') }}</h3>
</div>
{!! Form::open([
'id' => 'offline-payments',
'route' => 'offline-payments.update',
'@submit.prevent' => 'onSubmit',
'@keydown' => 'form.errors.clear($event.target.name)',
'files' => true,
'role' => 'form',
'class' => 'form-loading-button',
'novalidate' => true
]) !!}
<div class="card-body">
<div class="row">
{{ Form::textGroup('name', trans('general.name'), 'money-check', ['required' => 'required'], null, 'col-md-12') }}
{{ Form::textGroup('code', trans('offline-payments::general.form.code'), 'code', ['required' => 'required'], null, 'col-md-12') }}
{{ Form::radioGroup('customer', trans('offline-payments::general.form.customer'), 0, trans('general.yes'), trans('general.no'), ['required' => 'required'], 'col-md-12') }}
{{ Form::textGroup('order', trans('offline-payments::general.form.order'), 'sort', [], null, 'col-md-12') }}
{{ Form::textareaGroup('description', trans('general.description')) }}
{!! Form::hidden('update', null) !!}
</div>
</div>
<div class="card-footer">
<div class="row float-right">
{{ Form::saveButtons('apps/offline-payments/settings') }}
</div>
</div>
{!! Form::close() !!}
</div>
</div>
<div class="col-md-8">
<div class="card">
<div class="card-header border-bottom-0">
<h3 class="mb-0">{{ trans('offline-payments::general.payment_gateways') }}</h3>
</div>
<div id="delete-loading"></div>
<div class="table-responsive">
<table class="table table-flush table-hover" id="tbl-items">
<thead class="thead-light">
<tr class="row table-head-line">
<th class="col-xs-6 col-sm-4 col-md-4 col-lg-3">{{ trans('general.name') }}</th>
<th class="col-sm-4 col-md-4 col-lg-4 hidden-sm">{{ trans('offline-payments::general.form.code') }}</th>
<th class="col-lg-2 hidden-lg">{{ trans('offline-payments::general.form.order') }}</th>
<th class="col-xs-6 col-sm-4 col-md-4 col-lg-3 text-center">{{ trans('general.actions') }}</th>
</tr>
</thead>
<tbody>
@if($items)
@foreach($items as $item)
<tr class="row align-items-center border-top-1" id="method-{{ $item->code }}">
<td class="col-xs-6 col-sm-4 col-md-4 col-lg-3">{{ $item->name }}</td>
<td class="col-sm-4 col-md-4 col-lg-4 hidden-sm">{{ $item->code }}</td>
<td class="col-lg-2 hidden-lg">{{ $item->order }}</td>
<td class="col-xs-6 col-sm-4 col-md-4 col-lg-3 text-center">
<div class="dropdown">
<a class="btn btn-neutral btn-sm text-light items-align-center p-2" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-ellipsis-h text-muted"></i>
</a>
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
{!! Form::button(trans('general.edit'), array(
'type' => 'button',
'class' => 'dropdown-item method-edit',
'title' => trans('general.edit'),
'data-code' => $item->code,
'id' => 'edit-' . $item->code,
'@click' => 'onEdit'
)) !!}
<div class="dropdown-divider"></div>
{!! Form::button(trans('general.delete'), array(
'type' => 'button',
'class' => 'dropdown-item method-delete',
'title' => trans('general.delete'),
'data-code' => $item->code,
'id' => 'delete-' . $item->code,
'@click' => 'confirmDelete("' . $item->code . '", "' . trans('general.delete') . ' ' . trans_choice('offline-payments::general.methods', 1) . '", "' . trans('general.delete_confirm', ['name' => '<strong>' . $item->name . '</strong>', 'type' => mb_strtolower(trans('offline-payments::general.title'))]) . '", "' . trans('general.cancel') . '", "' . trans('general.delete') . '")'
)) !!}
</div>
</div>
</td>
</tr>
@endforeach
@endif
</tbody>
</table>
</div>
</div>
</div>
</div>
<akaunting-modal
:show="confirm.show"
:title="confirm.title"
:message="confirm.message"
:button_cancel="confirm.button_cancel"
:button_delete="confirm.button_delete"
v-if='confirm.show'
@confirm='onDelete'
@cancel="cancelDelete">
</akaunting-modal>
@endsection
@push('scripts_start')
<script src="{{ asset('modules/OfflinePayments/Resources/js/offline-payments.min.js?v=' . version('short')) }}"></script>
@endpush

View File

@ -1,23 +1,23 @@
<h2>{{ $gateway['name'] }}</h2>
<h2>{{ $setting['name'] }}</h2>
@if ($gateway['description'])
<div class="well well-sm">
{{ $gateway['description'] }}
</div>
@if ($setting['description'])
<div class="well well-sm">
{{ $setting['description'] }}
</div>
@endif
<div class="buttons">
<div class="pull-right">
<input type="button" value="{{ trans('offlinepayment::general.confirm') }}" id="button-confirm" class="btn btn-success" data-loading-text="{{ trans('offlinepayment::general.loading') }}" />
<div class="float-right">
<input type="button" value="{{ trans('offline-payments::general.confirm') }}" id="button-confirm" class="btn btn-success" data-loading-text="{{ trans('offline-payments::general.loading') }}" />
</div>
</div>
<script type="text/javascript"><!--
$('#button-confirm').on('click', function() {
$.ajax({
url: '{{ url("customers/invoices/" . $invoice->id . "/offlinepayment/confirm") }}',
url: '{{ route("portal.invoices.offline-payments.confirm", $invoice->id) }}',
type: 'POST',
dataType: 'JSON',
data: {payment_method: '{{ $gateway['code'] }}'},
data: {payment_method: '{{ $setting['code'] }}'},
cache: false,
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
beforeSend: function() {

View File

@ -1,23 +1,23 @@
<h2>{{ $gateway['name'] }}</h2>
<h2>{{ $setting['name'] }}</h2>
@if ($gateway['description'])
<div class="well well-sm">
{{ $gateway['description'] }}
</div>
@if ($setting['description'])
<div class="well well-sm">
{{ $setting['description'] }}
</div>
@endif
<div class="buttons">
<div class="pull-right">
<input type="button" value="{{ trans('offlinepayment::general.confirm') }}" id="button-confirm" class="btn btn-success" data-loading-text="{{ trans('offlinepayment::general.loading') }}" />
<div class="float-right">
<input type="button" value="{{ trans('offline-payments::general.confirm') }}" id="button-confirm" class="btn btn-success" data-loading-text="{{ trans('offline-payments::general.loading') }}" />
</div>
</div>
<script type="text/javascript"><!--
$('#button-confirm').on('click', function() {
$.ajax({
url: '{!! urldecode($confirm_action) !!}',
url: '{!! urldecode($confirm_url) !!}',
type: 'POST',
dataType: 'JSON',
data: {payment_method: '{{ $gateway['code'] }}'},
data: {payment_method: '{{ $setting['code'] }}'},
cache: false,
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
beforeSend: function() {

View File

@ -0,0 +1,13 @@
<?php
Route::group([
'middleware' => 'admin',
'namespace' => 'Modules\OfflinePayments\Http\Controllers'
], function () {
Route::group(['prefix' => 'settings'], function () {
Route::get('offline-payments', 'Settings@edit')->name('offline-payments.edit');
Route::post('offline-payments', 'Settings@update')->name('offline-payments.update');
Route::post('offline-payments/get', 'Settings@get')->name('offline-payments.get');
Route::delete('offline-payments/delete', 'Settings@destroy')->name('offline-payments.delete');
});
});

View File

@ -0,0 +1,10 @@
<?php
Route::group([
'prefix' => 'portal',
'middleware' => 'portal',
'namespace' => 'Modules\OfflinePayments\Http\Controllers'
], function () {
Route::get('invoices/{invoice}/offline-payments', 'Payment@show')->name('portal.invoices.offline-payments.show');
Route::post('invoices/{invoice}/offline-payments/confirm', 'Payment@confirm')->name('portal.invoices.offline-payments.confirm');
});

View File

@ -0,0 +1,10 @@
<?php
Route::group([
'prefix' => 'signed',
'middleware' => 'signed',
'namespace' => 'Modules\OfflinePayments\Http\Controllers'
], function () {
Route::get('invoices/{invoice}/offline-payments', 'Payment@signed')->name('signed.invoices.offline-payments.show');
Route::post('invoices/{invoice}/offline-payments/confirm', 'Payment@confirm')->name('signed.invoices.offline-payments.confirm');
});

View File

@ -0,0 +1,4 @@
{
"/Resources/assets/js/offline-payments.min.js": "/Resources/assets/js/offline-payments.min.js",
"/public/css/argon.css": "/public/css/argon.css"
}

View File

@ -0,0 +1,14 @@
{
"alias": "offline-payments",
"version": "2.0.0",
"category": "payment-method",
"active": 1,
"order": 0,
"providers": [
"Modules\\OfflinePayments\\Providers\\Main"
],
"aliases": {},
"files": [],
"requires": [],
"settings": []
}

View File

@ -0,0 +1,83 @@
{
"name": "akaunting",
"version": "2.0.0",
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "npm run development -- --watch",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"serve": "vue-cli-service serve --open",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@fullcalendar/core": "^4.3.1",
"@fullcalendar/daygrid": "^4.3.0",
"@fullcalendar/interaction": "^4.3.0",
"@fullcalendar/timegrid": "^4.3.0",
"@fullcalendar/vue": "^4.3.1",
"bootstrap": "^4.3.1",
"chart.js": "^2.7.1",
"d3": "^5.12.0",
"datamaps": "^0.5.9",
"date-fns": "^1.30.1",
"dropzone": "^5.5.1",
"element-ui": "^2.12.0",
"es6-promise": "^4.1.1",
"flatpickr": "^4.6.3",
"fuse.js": "^3.2.0",
"google-maps": "^3.2.1",
"nouislider": "^12.1.0",
"nprogress": "^0.2.0",
"perfect-scrollbar": "^1.3.0",
"quill": "^1.3.7",
"sweetalert2": "^7.29.2",
"v-money": "^0.8.1",
"vee-validate": "^2.2.15",
"vue": "^2.6.10",
"vue-chartjs": "^3.4.0",
"vue-clipboard2": "^0.3.1",
"vue-flatpickr-component": "^8.1.3",
"vue-router": "^3.1.3",
"vue2-transitions": "^0.2.3"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.11.0",
"@vue/cli-plugin-eslint": "^3.11.0",
"@vue/cli-service": "^3.11.0",
"@vue/eslint-config-prettier": "^4.0.1",
"axios": "^0.18.1",
"babel-plugin-component": "^1.1.0",
"bootstrap": "^4.0.0",
"cross-env": "^5.2.1",
"jquery": "^3.4.1",
"laravel-mix": "^4.1.4",
"lodash": "^4.17.15",
"node-sass": "^4.12.0",
"popper.js": "^1.12",
"resolve-url-loader": "^2.3.1",
"sass": "^1.22.12",
"sass-loader": "^7.3.1",
"vue": "^2.5.17",
"vue-loading-overlay": "^3.2.0",
"vue-template-compiler": "^2.6.10",
"vue2-transitions": "^0.3.0"
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 10"
],
"author": "Akaunting Inc <info@akaunting.com>",
"description": "Free Accounting Software"
}

18
modules/OfflinePayments/webpack.mix.js vendored Normal file
View File

@ -0,0 +1,18 @@
const mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel application. By default, we are compiling the Sass
| file for the application as well as bundling up all the JS files.
|
*/
//mix.js('resources/assets/js/views/**/*.js', 'public/js')
mix.js('Resources/assets/js/offline-payments.js', 'Resources/assets/js/offline-payments.min.js')
.sass('./../../resources/assets/sass/argon.scss', './../../public/css');

View File

@ -0,0 +1,144 @@
<?php
namespace Modules\PaypalStandard\Http\Controllers;
use App\Abstracts\Http\PaymentController;
use App\Http\Requests\Portal\InvoicePayment as PaymentRequest;
use App\Models\Income\Invoice;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
class Payment extends PaymentController
{
public $alias = 'paypal-standard';
public $type = 'redirect';
public function show(Invoice $invoice, PaymentRequest $request)
{
$setting = $this->setting;
$this->setContactFirstLastName($invoice);
$setting['action'] = ($setting['mode'] == 'live') ? 'https://www.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
$invoice_url = $this->getInvoiceUrl($invoice);
$html = view('paypal-standard::show', compact('setting', 'invoice', 'invoice_url'))->render();
return response()->json([
'code' => $setting['code'],
'name' => $setting['name'],
'description' => trans('paypal-standard::general.description'),
'redirect' => false,
'html' => $html,
]);
}
public function return(Invoice $invoice, Request $request)
{
$success = true;
switch ($request['payment_status']) {
case 'Completed':
$message = trans('messages.success.added', ['type' => trans_choice('general.payments', 1)]);
break;
case 'Canceled_Reversal':
case 'Denied':
case 'Expired':
case 'Failed':
case 'Pending':
case 'Processed':
case 'Refunded':
case 'Reversed':
case 'Voided':
$message = trans('messages.error.added', ['type' => trans_choice('general.payments', 1)]);
$success = false;
break;
}
if ($success) {
flash($message)->success();
} else {
flash($message)->warning();
}
$invoice_url = $this->getInvoiceUrl($invoice);
return redirect($invoice_url);
}
public function complete(Invoice $invoice, Request $request)
{
$setting = $this->setting;
$paypal_log = new Logger('Paypal');
$paypal_log->pushHandler(new StreamHandler(storage_path('logs/paypal.log')), Logger::INFO);
if (!$invoice) {
return;
}
$url = ($setting['mode'] == 'live') ? 'https://ipnpb.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
$client = new Client(['verify' => false]);
$paypal_request['cmd'] = '_notify-validate';
foreach ($request->toArray() as $key => $value) {
$paypal_request[$key] = urlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8'));
}
$response = $client->post($url, $paypal_request);
if ($response->getStatusCode() != 200) {
$paypal_log->info('PAYPAL_STANDARD :: CURL failed ', $response->getBody()->getContents());
} else {
$response = $response->getBody()->getContents();
}
if ($setting['debug']) {
$paypal_log->info('PAYPAL_STANDARD :: IPN REQUEST: ', $request->toArray());
}
if ((strcmp($response, 'VERIFIED') != 0 || strcmp($response, 'UNVERIFIED') != 0)) {
$paypal_log->info('PAYPAL_STANDARD :: VERIFIED != 0 || UNVERIFIED != 0 ' . $request->toArray());
return;
}
switch ($request['payment_status']) {
case 'Completed':
$receiver_match = (strtolower($request['receiver_email']) == strtolower($setting['email']));
$total_paid_match = ((double) $request['mc_gross'] == $invoice->amount);
if ($receiver_match && $total_paid_match) {
event(new \App\Events\Income\PaymentReceived($invoice, $request));
}
if (!$receiver_match) {
$paypal_log->info('PAYPAL_STANDARD :: RECEIVER EMAIL MISMATCH! ' . strtolower($request['receiver_email']));
}
if (!$total_paid_match) {
$paypal_log->info('PAYPAL_STANDARD :: TOTAL PAID MISMATCH! ' . $request['mc_gross']);
}
break;
case 'Canceled_Reversal':
case 'Denied':
case 'Expired':
case 'Failed':
case 'Pending':
case 'Processed':
case 'Refunded':
case 'Reversed':
case 'Voided':
$paypal_log->info('PAYPAL_STANDARD :: NOT COMPLETED ' . $request->toArray());
break;
}
}
}

View File

@ -1,164 +0,0 @@
<?php
namespace Modules\PaypalStandard\Http\Controllers;
use App\Events\InvoicePaid;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use App\Http\Requests\Customer\InvoicePayment as PaymentRequest;
use App\Models\Income\Invoice;
class PaypalStandard extends Controller
{
/**
* Show the form for editing the specified resource.
* @param Invoice
* @param PaymentRequest
* @return Response
*/
public function show(Invoice $invoice, PaymentRequest $request)
{
$gateway = setting('paypalstandard');
$gateway['action'] = 'https://www.paypal.com/cgi-bin/webscr';
if ($gateway['mode'] == 'sandbox') {
$gateway['action'] = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
}
$customer = explode(" ", $invoice->customer_name);
$last_name = array_pop($customer);
$first_name = implode(" ", $customer);
$invoice->first_name = $first_name;
$invoice->last_name = $last_name;
$gateway['language'] = \App::getLocale();
$html = view('paypalstandard::show', compact('gateway', 'invoice'))->render();
return response()->json([
'code' => 'paypalstandard',
'name' => $gateway['name'],
'description' => trans('paypalstandard::paypalstandard.description'),
'redirect' => false,
'html' => $html,
]);
}
public function result(Invoice $invoice, Request $request)
{
$success = true;
switch ($request['payment_status']) {
case 'Completed':
$message = trans('messages.success.added', ['type' => trans_choice('general.customers', 1)]);
break;
case 'Canceled_Reversal':
case 'Denied':
case 'Expired':
case 'Failed':
case 'Pending':
case 'Processed':
case 'Refunded':
case 'Reversed':
case 'Voided':
$message = trans('messages.error.added', ['type' => trans_choice('general.customers', 1)]);
$success = false;
break;
}
if ($success) {
flash($message)->success();
} else {
flash($message)->warning();
}
$redirect = url('customers/invoices/' . $invoice->id);
return redirect($redirect);
}
public function callback(Invoice $invoice, Request $request)
{
$gateway = setting('paypalstandard');
$paypal_log = new Logger('Paypal');
$paypal_log->pushHandler(new StreamHandler(storage_path('logs/paypal.log')), Logger::INFO);
if ($invoice) {
$url = 'https://ipnpb.paypal.com/cgi-bin/webscr';
if ($gateway['mode'] == 'sandbox') {
$url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
}
$client = new Client(['verify' => false]);
$paypal_request['cmd'] = '_notify-validate';
foreach ($request->toArray() as $key => $value) {
$paypal_request[$key] = urlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8'));
}
$result = $client->post($url, $paypal_request);
if ($result->getStatusCode() != 200) {
$paypal_log->info('PAYPAL_STANDARD :: CURL failed ', $result->getBody()->getContents());
} else {
$result = $result->getBody()->getContents();
}
if ($gateway['debug']) {
$paypal_log->info('PAYPAL_STANDARD :: IPN REQUEST: ', $request->toArray());
//$paypal_log->info('PAYPAL_STANDARD :: IPN RESULT: ', $result);
}
if ((strcmp($result, 'VERIFIED') == 0 || strcmp($result, 'UNVERIFIED') == 0) || true) {
switch ($request['payment_status']) {
case 'Completed':
$receiver_match = (strtolower($request['receiver_email']) == strtolower($gateway['email']));
$total_paid_match = ((float)$request['mc_gross'] == $invoice->amount);
if ($receiver_match && $total_paid_match) {
event(new InvoicePaid($invoice, $request->toArray()));
}
if (!$receiver_match) {
$paypal_log->info('PAYPAL_STANDARD :: RECEIVER EMAIL MISMATCH! ' . strtolower($request['receiver_email']));
}
if (!$total_paid_match) {
$paypal_log->info('PAYPAL_STANDARD :: TOTAL PAID MISMATCH! ' . $request['mc_gross']);
}
break;
case 'Canceled_Reversal':
case 'Denied':
case 'Expired':
case 'Failed':
case 'Pending':
case 'Processed':
case 'Refunded':
case 'Reversed':
case 'Voided':
$paypal_log->info('PAYPAL_STANDARD :: NOT COMPLETED ' . $request->toArray());
break;
}
} else {
$paypal_log->info('PAYPAL_STANDARD :: VERIFIED != 0 || UNVERIFIED != 0 ' . $request->toArray());
}
}
}
}

View File

@ -1,25 +0,0 @@
<?php
Route::group([
'middleware' => 'customer',
'prefix' => 'customers',
'namespace' => 'Modules\PaypalStandard\Http\Controllers'
], function () {
Route::get('invoices/{invoice}/paypalstandard', 'PaypalStandard@show');
});
Route::group([
'prefix' => 'customers',
'namespace' => 'Modules\PaypalStandard\Http\Controllers'
], function () {
Route::post('invoices/{invoice}/paypalstandard/result', 'PaypalStandard@result');
Route::post('invoices/{invoice}/paypalstandard/callback', 'PaypalStandard@callback');
});
Route::group([
'middleware' => ['signed', 'language'],
'prefix' => 'signed',
'namespace' => 'Modules\PaypalStandard\Http\Controllers'
], function () {
Route::post('invoices/{invoice}/paypalstandard', 'PaypalStandard@show');
});

View File

@ -1,23 +0,0 @@
<?php
namespace Modules\PaypalStandard\Listeners;
use App\Events\PaymentGatewayListing;
class Gateway
{
/**
* Handle the event.
*
* @param PaymentGatewayListing $event
* @return void
*/
public function handle(PaymentGatewayListing $event)
{
$setting = setting('paypalstandard');
$setting['code'] = 'paypalstandard';
return [$setting];
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Modules\PaypalStandard\Listeners;
use App\Events\Module\PaymentMethodShowing as Event;
class ShowPaymentMethod
{
/**
* Handle the event.
*
* @param Event $event
* @return void
*/
public function handle(Event $event)
{
$method = setting('paypal-standard');
$method['code'] = 'paypal-standard';
$event->modules->payment_methods[] = $method;
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace Modules\PaypalStandard\Providers;
use Illuminate\Support\ServiceProvider as Provider;
use Modules\PaypalStandard\Listeners\ShowPaymentMethod;
class Main extends Provider
{
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->loadTranslations();
$this->loadViews();
$this->loadEvents();
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->loadRoutes();
}
/**
* Load views.
*
* @return void
*/
public function loadViews()
{
$this->loadViewsFrom(__DIR__ . '/../Resources/views', 'paypal-standard');
}
/**
* Load translations.
*
* @return void
*/
public function loadTranslations()
{
$this->loadTranslationsFrom(__DIR__ . '/../Resources/lang', 'paypal-standard');
}
/**
* Load events.
*
* @return void
*/
public function loadEvents()
{
$this->app['events']->listen(\App\Events\Module\PaymentMethodShowing::class, ShowPaymentMethod::class);
}
/**
* Load routes.
*
* @return void
*/
public function loadRoutes()
{
if (app()->routesAreCached()) {
return;
}
$routes = [
'guest.php',
'portal.php',
'signed.php',
];
foreach ($routes as $route) {
$this->loadRoutesFrom(__DIR__ . '/../Routes/' . $route);
}
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
}

View File

@ -1,90 +0,0 @@
<?php
namespace Modules\PaypalStandard\Providers;
use App\Events\PaymentGatewayListing;
use Illuminate\Support\ServiceProvider;
use Modules\PaypalStandard\Listeners\Gateway;
class PaypalStandardServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* Boot the application events.
*
* @return void
*/
public function boot()
{
$this->registerTranslations();
$this->registerViews();
$this->registerEvents();
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
}
/**
* Register views.
*
* @return void
*/
public function registerViews()
{
$viewPath = resource_path('views/modules/paypalstandard');
$sourcePath = __DIR__.'/../Resources/views';
$this->publishes([
$sourcePath => $viewPath
]);
$this->loadViewsFrom(array_merge(array_map(function ($path) {
return $path . '/modules/paypalstandard';
}, \Config::get('view.paths')), [$sourcePath]), 'paypalstandard');
}
/**
* Register translations.
*
* @return void
*/
public function registerTranslations()
{
$langPath = resource_path('lang/modules/paypalstandard');
if (is_dir($langPath)) {
$this->loadTranslationsFrom($langPath, 'paypalstandard');
} else {
$this->loadTranslationsFrom(__DIR__ .'/../Resources/lang', 'paypalstandard');
}
}
public function registerEvents()
{
$this->app['events']->listen(PaymentGatewayListing::class, Gateway::class);
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
}

View File

@ -2,20 +2,19 @@
return [
'title' => 'Paypal Standard',
'paypalstandard' => 'Paypal Standard',
'name' => 'PayPal Standard',
'description' => 'Enable the standard payment option of PayPal',
'form' => [
'email' => 'Email',
'mode' => 'Mode',
'debug' => 'Debug',
'transaction' => 'Transaction',
'customer' => 'Show to Customer',
'order' => 'Order',
'email' => 'Email',
'mode' => 'Mode',
'debug' => 'Debug',
'transaction' => 'Transaction',
'customer' => 'Show to Customer',
'order' => 'Order',
],
'test_mode' => 'Warning: The payment gateway is in \'Sandbox Mode\'. Your account will not be charged.',
'description' => 'Pay with PAYPAL',
'confirm' => 'Confirm',
'test_mode' => 'Warning: The payment gateway is in \'Sandbox Mode\'. Your account will not be charged.',
//'description' => 'Pay with PAYPAL',
];

View File

@ -1,26 +1,23 @@
<h2>{{ $gateway['name'] }}</h2>
<h2>{{ $setting['name'] }}</h2>
@if($gateway['mode'] == 'sandbox')
<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> {{ trans('paypalstandard::general.test_mode') }}</div>
@if($setting['mode'] == 'sandbox')
<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> {{ trans('paypal-standard::general.test_mode') }}</div>
@endif
<div class="well well-sm">
{{ trans('paypalstandard::general.description') }}
{{ trans('paypal-standard::general.description') }}
</div>
<form action="{{ $gateway['action'] }}" method="post">
<form action="{{ $setting['action'] }}" method="post">
<input type="hidden" name="cmd" value="_cart" />
<input type="hidden" name="upload" value="1" />
<input type="hidden" name="business" value="{{ $gateway['email'] }}" />
<input type="hidden" name="business" value="{{ $setting['email'] }}" />
<?php $i = 1; ?>
@foreach ($invoice->items as $item)
<input type="hidden" name="item_name_{{ $i }}" value="{{ $item->name }}" />
@if($item->sku)
<input type="hidden" name="item_number_{{ $i }}" value="{{ $item->sku }}" />
@endif
<input type="hidden" name="amount_{{ $i }}" value="{{ $item->price }}" />
<input type="hidden" name="quantity_{{ $i }}" value="{{ $item->quantity }}" />
<?php $i++; ?>
<input type="hidden" name="item_name_{{ $i }}" value="{{ $item->name }}" />
<input type="hidden" name="amount_{{ $i }}" value="{{ $item->price }}" />
<input type="hidden" name="quantity_{{ $i }}" value="{{ $item->quantity }}" />
<?php $i++; ?>
@endforeach
<input type="hidden" name="currency_code" value="{{ $invoice->currency_code}}" />
<input type="hidden" name="first_name" value="{{ $invoice->first_name }}" />
@ -29,20 +26,21 @@
<input type="hidden" name="address_override" value="0" />
<input type="hidden" name="email" value="{{ $invoice->customer_email }}" />
<input type="hidden" name="invoice" value="{{ $invoice->id . '-' . $invoice->customer_name }}" />
<input type="hidden" name="lc" value="{{ $gateway['language'] }}" />
<input type="hidden" name="lc" value="{{ $setting['language'] }}" />
<input type="hidden" name="rm" value="2" />
<input type="hidden" name="no_note" value="1" />
<input type="hidden" name="no_shipping" value="1" />
<input type="hidden" name="charset" value="utf-8" />
<input type="hidden" name="return" value="{{ url('customers/invoices/' . $invoice->id . '/paypalstandard/result') }}" />
<input type="hidden" name="notify_url" value="{{ url('customers/invoices/' . $invoice->id . '/paypalstandard/callback') }}" />
<input type="hidden" name="cancel_return" value="{{ url('customers/invoices/' . $invoice->id) }}" />
<input type="hidden" name="paymentaction" value="{{ $gateway['transaction'] }}" />
<input type="hidden" name="return" value="{{ route('portal.invoices.paypal-standard.return', $invoice->id) }}" />
<input type="hidden" name="notify_url" value="{{ route('portal.invoices.paypal-standard.complete', $invoice->id) }}" />
<input type="hidden" name="cancel_return" value="{{ $invoice_url }}" />
<input type="hidden" name="paymentaction" value="{{ $setting['transaction'] }}" />
<input type="hidden" name="custom" value="{{ $invoice->id }}" />
<input type="hidden" name="bn" value="Akaunting_1.0_WPS" />
<input type="hidden" name="bn" value="Akaunting_2.0_WPS" />
<div class="buttons">
<div class="pull-right">
<input type="submit" value="{{ trans('paypalstandard::general.confirm') }}" class="btn btn-success" />
<div class="float-right">
<input type="submit" value="{{ trans('paypal-standard::general.confirm') }}" class="btn btn-success" />
</div>
</div>
</form>

View File

@ -0,0 +1,10 @@
<?php
Route::group([
'prefix' => 'portal',
'middleware' => 'guest',
'namespace' => 'Modules\PaypalStandard\Http\Controllers'
], function () {
Route::post('invoices/{invoice}/paypal-standard/return', 'Payment@return')->name('portal.invoices.paypal-standard.return');
Route::post('invoices/{invoice}/paypal-standard/complete', 'Payment@complete')->name('portal.invoices.paypal-standard.complete');
});

View File

@ -0,0 +1,9 @@
<?php
Route::group([
'prefix' => 'portal',
'middleware' => 'portal',
'namespace' => 'Modules\PaypalStandard\Http\Controllers'
], function () {
Route::get('invoices/{invoice}/paypal-standard', 'Payment@show')->name('portal.invoices.paypal-standard.show');
});

View File

@ -0,0 +1,9 @@
<?php
Route::group([
'prefix' => 'signed',
'middleware' => 'signed',
'namespace' => 'Modules\PaypalStandard\Http\Controllers'
], function () {
Route::post('invoices/{invoice}/paypal-standard', 'Payment@show')->name('signed.invoices.paypal-standard.show');
});

View File

@ -1,26 +1,22 @@
{
"name": "PaypalStandard",
"alias": "paypalstandard",
"description": "",
"version": "1.0.0",
"category": "payment-gateway",
"keywords": [],
"alias": "paypal-standard",
"icon": "fab fa-paypal",
"version": "2.0.0",
"category": "payment-method",
"active": 1,
"order": 0,
"providers": [
"Modules\\PaypalStandard\\Providers\\PaypalStandardServiceProvider"
"Modules\\PaypalStandard\\Providers\\Main"
],
"aliases": {},
"files": [
"start.php"
],
"files": [],
"requires": [],
"settings": [
{
"type": "textGroup",
"name": "name",
"title": "general.name",
"icon": "id-card-o",
"icon": "fa fa-font",
"attributes": {
"required": "required"
}
@ -28,8 +24,8 @@
{
"type": "textGroup",
"name": "email",
"title": "paypalstandard::general.form.email",
"icon": "envelope-o",
"title": "paypal-standard::general.form.email",
"icon": "envelope",
"attributes": {
"required": "required"
}
@ -37,7 +33,7 @@
{
"type": "selectGroup",
"name": "mode",
"title": "paypalstandard::general.form.mode",
"title": "paypal-standard::general.form.mode",
"icon": "plane",
"values": {
"live": "Live",
@ -49,8 +45,8 @@
{
"type": "selectGroup",
"name": "transaction",
"title": "paypalstandard::general.form.transaction",
"icon": "exchange",
"title": "paypal-standard::general.form.transaction",
"icon": "exchange-alt",
"values": {
"authorization": "Authorization",
"sale": "Sale"
@ -61,7 +57,7 @@
{
"type": "radioGroup",
"name": "customer",
"title": "paypalstandard::general.form.customer",
"title": "paypal-standard::general.form.customer",
"enable": "general.yes",
"disable": "general.no",
"attributes": {}
@ -69,7 +65,7 @@
{
"type": "radioGroup",
"name": "debug",
"title": "paypalstandard::general.form.debug",
"title": "paypal-standard::general.form.debug",
"enable": "general.yes",
"disable": "general.no",
"attributes": {}
@ -77,7 +73,7 @@
{
"type": "textGroup",
"name": "order",
"title": "paypalstandard::general.form.order",
"title": "paypal-standard::general.form.order",
"icon": "sort",
"attributes": {}
}

View File

@ -1,17 +0,0 @@
<?php
/*
|--------------------------------------------------------------------------
| Register Namespaces And Routes
|--------------------------------------------------------------------------
|
| When a module starting, this file will executed automatically. This helps
| to register some namespaces like translator or view. Also this file
| will load the routes file for each module. You may also modify
| this file as you want.
|
*/
if (!app()->routesAreCached()) {
require __DIR__ . '/Http/routes.php';
}