diff --git a/app/Listeners/Updates/Version109.php b/app/Listeners/Updates/Version109.php new file mode 100644 index 000000000..51a432783 --- /dev/null +++ b/app/Listeners/Updates/Version109.php @@ -0,0 +1,36 @@ +check($event)) { + return; + } + + // Create new bill statuses + $companies = Company::all(); + + foreach ($companies as $company) { + Artisan::call('module:install', ['alias' => 'offlinepayment', 'company_id' => $company->id]); + Artisan::call('module:install', ['alias' => 'paypalstandard', 'company_id' => $company->id]); + } + } +} diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 8c0a79fe1..de24146b8 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -17,6 +17,7 @@ class EventServiceProvider extends ServiceProvider 'App\Listeners\Updates\Version106', 'App\Listeners\Updates\Version107', 'App\Listeners\Updates\Version108', + 'App\Listeners\Updates\Version109', ], 'Illuminate\Auth\Events\Login' => [ 'App\Listeners\Auth\Login', diff --git a/database/seeds/CompanySeeder.php b/database/seeds/CompanySeeder.php index e66269074..bbcf49a85 100644 --- a/database/seeds/CompanySeeder.php +++ b/database/seeds/CompanySeeder.php @@ -16,6 +16,7 @@ class CompanySeeder extends Seeder $this->call(Database\Seeds\Categories::class); $this->call(Database\Seeds\Currencies::class); $this->call(Database\Seeds\InvoiceStatuses::class); + $this->call(Database\Seeds\Modules::class); $this->call(Database\Seeds\Settings::class); $this->call(Database\Seeds\Taxes::class); } diff --git a/database/seeds/Modules.php b/database/seeds/Modules.php new file mode 100644 index 000000000..3f5960fdd --- /dev/null +++ b/database/seeds/Modules.php @@ -0,0 +1,33 @@ +create(); + + Model::reguard(); + } + + private function create() + { + $company_id = $this->command->argument('company'); + + Artisan::call('module:install', ['alias' => 'offlinepayment', 'company_id' => $company_id]); + Artisan::call('module:install', ['alias' => 'paypalstandard', 'company_id' => $company_id]); + } +} diff --git a/modules/PaypalStandard/Assets/.gitkeep b/modules/PaypalStandard/Assets/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Config/.gitkeep b/modules/PaypalStandard/Config/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Config/config.php b/modules/PaypalStandard/Config/config.php new file mode 100644 index 000000000..cdec48cf0 --- /dev/null +++ b/modules/PaypalStandard/Config/config.php @@ -0,0 +1,7 @@ + 'PaypalStandard', + +]; diff --git a/modules/PaypalStandard/Console/.gitkeep b/modules/PaypalStandard/Console/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Database/Migrations/.gitkeep b/modules/PaypalStandard/Database/Migrations/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Database/Seeders/.gitkeep b/modules/PaypalStandard/Database/Seeders/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Database/Seeders/PaypalStandardDatabaseSeeder.php b/modules/PaypalStandard/Database/Seeders/PaypalStandardDatabaseSeeder.php new file mode 100644 index 000000000..258e3d6ec --- /dev/null +++ b/modules/PaypalStandard/Database/Seeders/PaypalStandardDatabaseSeeder.php @@ -0,0 +1,21 @@ +call("OthersTableSeeder"); + } +} diff --git a/modules/PaypalStandard/Entities/.gitkeep b/modules/PaypalStandard/Entities/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Events/.gitkeep b/modules/PaypalStandard/Events/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Events/Handlers/.gitkeep b/modules/PaypalStandard/Events/Handlers/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Events/Handlers/PaypalStandardGateway.php b/modules/PaypalStandard/Events/Handlers/PaypalStandardGateway.php new file mode 100644 index 000000000..e6001a9ea --- /dev/null +++ b/modules/PaypalStandard/Events/Handlers/PaypalStandardGateway.php @@ -0,0 +1,23 @@ +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()); + } + } + } +} diff --git a/modules/PaypalStandard/Http/Middleware/.gitkeep b/modules/PaypalStandard/Http/Middleware/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Http/Requests/.gitkeep b/modules/PaypalStandard/Http/Requests/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Http/routes.php b/modules/PaypalStandard/Http/routes.php new file mode 100644 index 000000000..e229a748c --- /dev/null +++ b/modules/PaypalStandard/Http/routes.php @@ -0,0 +1,10 @@ + ['web', 'auth', 'language', 'customermenu', 'permission:read-customer-panel'], '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'); +}); diff --git a/modules/PaypalStandard/Jobs/.gitkeep b/modules/PaypalStandard/Jobs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Mail/.gitkeep b/modules/PaypalStandard/Mail/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Providers/.gitkeep b/modules/PaypalStandard/Providers/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Providers/PaypalStandardServiceProvider.php b/modules/PaypalStandard/Providers/PaypalStandardServiceProvider.php new file mode 100644 index 000000000..6d414e2ac --- /dev/null +++ b/modules/PaypalStandard/Providers/PaypalStandardServiceProvider.php @@ -0,0 +1,119 @@ +registerTranslations(); + $this->registerConfig(); + $this->registerViews(); + $this->registerFactories(); + + $this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); + + $this->app['events']->listen(PaymentGatewayListing::class, PaypalStandardGateway::class); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + // + } + + /** + * Register config. + * + * @return void + */ + protected function registerConfig() + { + $this->publishes([ + __DIR__.'/../Config/config.php' => config_path('paypalstandard.php'), + ], 'config'); + + $this->mergeConfigFrom( + __DIR__.'/../Config/config.php', 'paypalstandard' + ); + } + + /** + * 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'); + } + } + + /** + * Register an additional directory of factories. + * @source https://github.com/sebastiaanluca/laravel-resource-flow/blob/develop/src/Modules/ModuleServiceProvider.php#L66 + */ + public function registerFactories() + { + if (! app()->environment('production')) { + app(Factory::class)->load(__DIR__ . '/Database/factories'); + } + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return []; + } +} diff --git a/modules/PaypalStandard/Repositories/.gitkeep b/modules/PaypalStandard/Repositories/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Resources/lang/.gitkeep b/modules/PaypalStandard/Resources/lang/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Resources/lang/en-GB/paypalstandard.php b/modules/PaypalStandard/Resources/lang/en-GB/paypalstandard.php new file mode 100644 index 000000000..5fdb3af27 --- /dev/null +++ b/modules/PaypalStandard/Resources/lang/en-GB/paypalstandard.php @@ -0,0 +1,17 @@ + 'Paypal Standard', + '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', + +]; diff --git a/modules/PaypalStandard/Resources/views/.gitkeep b/modules/PaypalStandard/Resources/views/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/modules/PaypalStandard/Resources/views/show.blade.php b/modules/PaypalStandard/Resources/views/show.blade.php new file mode 100644 index 000000000..b465cdcf7 --- /dev/null +++ b/modules/PaypalStandard/Resources/views/show.blade.php @@ -0,0 +1,48 @@ +