Order Transaction added for paypal smart button

This commit is contained in:
rahul shukla 2021-03-12 19:07:08 +05:30
parent 897c0cdc29
commit 7282bcabfc
18 changed files with 597 additions and 5 deletions

View File

@ -37,6 +37,12 @@ return [
'route' => 'admin.sales.refunds.index',
'sort' => 4,
'icon-class' => '',
], [
'key' => 'sales.transactions',
'name' => 'admin::app.layouts.transactions',
'route' => 'admin.sales.transactions.index',
'sort' => 5,
'icon-class' => '',
], [
'key' => 'catalog',
'name' => 'admin::app.layouts.catalog',

View File

@ -0,0 +1,76 @@
<?php
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Ui\DataGrid\DataGrid;
class OrderTransactionsDataGrid extends DataGrid
{
protected $index = 'id';
protected $sortOrder = 'desc';
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('order_transactions')
->leftJoin('orders as ors', 'order_transactions.order_id', '=', 'ors.id')
->select('order_transactions.id as id', 'order_transactions.transaction_id as transaction_id', 'ors.increment_id as order_id', 'order_transactions.created_at as created_at');
$this->addFilter('id', 'order_transactions.id');
$this->addFilter('transaction_id', 'order_transactions.transaction_id');
$this->addFilter('order_id', 'ors.increment_id');
$this->addFilter('created_at', 'order_transactions.created_at');
$this->setQueryBuilder($queryBuilder);
}
public function addColumns()
{
$this->addColumn([
'index' => 'id',
'label' => trans('admin::app.datagrid.id'),
'type' => 'number',
'searchable' => false,
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'transaction_id',
'label' => trans('admin::app.datagrid.transaction-id'),
'type' => 'string',
'searchable' => false,
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'order_id',
'label' => trans('admin::app.datagrid.order-id'),
'type' => 'number',
'searchable' => true,
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'created_at',
'label' => trans('admin::app.datagrid.transaction-date'),
'type' => 'datetime',
'searchable' => true,
'sortable' => true,
'filterable' => true,
]);
}
public function prepareActions()
{
$this->addAction([
'title' => trans('admin::app.datagrid.view'),
'method' => 'GET',
'route' => 'admin.sales.transactions.view',
'icon' => 'icon eye-icon',
]);
}
}

View File

@ -0,0 +1,92 @@
<?php
namespace Webkul\Admin\Http\Controllers\Sales;
use Illuminate\Support\Facades\Event;
use Webkul\Admin\Http\Controllers\Controller;
use Webkul\Sales\Repositories\OrderTransactionRepository;
class TransactionController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
protected $_config;
/**
* OrderRepository object
*
* @var \Webkul\Sales\Repositories\OrderTransactionRepository
*/
protected $orderTransactionRepository;
/**
* Create a new controller instance.
*
* @param \Webkul\Sales\Repositories\OrderTransactionRepository $orderTransactionRepository
* @return void
*/
public function __construct(OrderTransactionRepository $orderTransactionRepository)
{
$this->middleware('admin');
$this->_config = request('_config');
$this->orderTransactionRepository = $orderTransactionRepository;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\View\View
*/
public function index()
{
return view($this->_config['view']);
}
/**
* Show the view for the specified resource.
*
* @param int $id
* @return \Illuminate\View\View
*/
public function view($id)
{
$transaction = $this->orderTransactionRepository->findOrFail($id);
$transData = json_decode(json_encode(json_decode($transaction['data'])), true);
$transactionDeatilsData = $this->convertIntoSingleDimArray($transData);
return view($this->_config['view'], compact('transaction', 'transactionDeatilsData'));
}
/**
* Convert Transaction Details Data into single Dim Array.
*
* @param array $data
* @return array
*/
public function convertIntoSingleDimArray($transData) {
static $detailsData = [];
foreach ($transData as $key => $data) {
if (is_array($data)) {
$this->convertIntoSingleDimArray($data);
} else {
$skipAttributes = ['sku', 'name', 'category', 'quantity'];
if (gettype($key) == 'integer' || in_array($key, $skipAttributes)) {
continue;
}
$detailsData[$key] = $data;
}
}
return $detailsData;
}
}

View File

@ -250,6 +250,15 @@ Route::group(['middleware' => ['web']], function () {
Route::get('/refunds/view/{id}', 'Webkul\Admin\Http\Controllers\Sales\RefundController@view')->defaults('_config', [
'view' => 'admin::sales.refunds.view',
])->name('admin.sales.refunds.view');
// Sales Transactions Routes
Route::get('/transactions', 'Webkul\Admin\Http\Controllers\Sales\TransactionController@index')->defaults('_config', [
'view' => 'admin::sales.transactions.index',
])->name('admin.sales.transactions.index');
Route::get('/transactions/view/{id}', 'Webkul\Admin\Http\Controllers\Sales\TransactionController@view')->defaults('_config', [
'view' => 'admin::sales.transactions.view',
])->name('admin.sales.transactions.view');
});
// Catalog Routes

View File

@ -82,7 +82,8 @@ return [
'email-templates' => 'Email Templates',
'events' => 'Events',
'discount' => 'Discount',
'cms' => 'CMS'
'cms' => 'CMS',
'transactions' => 'Transactions'
],
'acl' => [
@ -249,7 +250,9 @@ return [
'ltr' => 'LTR',
'update-status' => 'Update Status',
'subject' => 'Subject',
'date' => 'Date'
'date' => 'Date',
'transaction-id' => 'Transaction Id',
'transaction-date' => 'Transaction Date',
],
'account' => [
@ -401,7 +404,8 @@ return [
'submit-comment' => 'Submit Comment',
'notify-customer' => 'Notify Customer',
'customer-notified' => ':date | Customer <b>Notified</b>',
'customer-not-notified' => ':date | Customer <b>Not Notified</b>'
'customer-not-notified' => ':date | Customer <b>Not Notified</b>',
'transactions' => 'Transactions'
],
'invoices' => [
@ -478,6 +482,20 @@ return [
'view-title' => 'Refund #:refund_id',
'invalid-refund-amount-error' => 'Refund amount should be non zero.'
],
'transactions' => [
'title' => 'Transactions',
'id' => 'Id',
'transaction-id' => 'Transaction Id',
'payment-method' => 'Payment method',
'action' => 'Action',
'view-title' => 'Transaction #:transaction_id',
'transaction-data' => 'Transaction Data',
'order-id' => 'Order Id',
'status' => 'Status',
'created-at' => 'Created At',
'transaction-details' => 'Transaction Details'
]
],

View File

@ -509,6 +509,7 @@
<td class="empty" colspan="7">{{ __('admin::app.common.no-result-found') }}</td>
<tr>
@endif
</tbody>
</table>
</div>
@ -551,6 +552,7 @@
<td class="empty" colspan="7">{{ __('admin::app.common.no-result-found') }}</td>
<tr>
@endif
</tbody>
</table>
</div>
@ -595,6 +597,49 @@
<td class="empty" colspan="7">{{ __('admin::app.common.no-result-found') }}</td>
<tr>
@endif
</tbody>
</table>
</div>
</tab>
<tab name="{{ __('admin::app.sales.orders.transactions') }}">
<div class="table" style="padding: 20px 0">
<table>
<thead>
<tr>
<th>{{ __('admin::app.sales.transactions.transaction-id') }}</th>
<th>{{ __('admin::app.sales.invoices.order-id') }}</th>
<th>{{ __('admin::app.sales.transactions.payment-method') }}</th>
<th>{{ __('admin::app.sales.transactions.action') }}</th>
</tr>
</thead>
<tbody>
@foreach ($order->transactions as $transaction)
<tr>
<td>#{{ $transaction->transaction_id }}</td>
<td>{{ $transaction->order_id }}</td>
<td>
{{ core()->getConfigData('sales.paymentmethods.' . $transaction->payment_method . '.title') }}
</td>
<td class="action">
<a href="{{ route('admin.sales.transactions.view', $transaction->id) }}">
<i class="icon eye-icon"></i>
</a>
</td>
</tr>
@endforeach
@if (! $order->transactions->count())
<tr>
<td class="empty" colspan="7">{{ __('admin::app.common.no-result-found') }}</td>
<tr>
@endif
</tbody>
</table>
</div>

View File

@ -0,0 +1,40 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.sales.transactions.title') }}
@stop
@section('content')
<div class="content">
<div class="page-header">
<div class="page-title">
<h1>{{ __('admin::app.sales.transactions.title') }}</h1>
</div>
<div class="page-action">
<div class="export-import" @click="showModal('downloadDataGrid')">
<i class="export-icon"></i>
<span>
{{ __('admin::app.export.export') }}
</span>
</div>
</div>
</div>
<div class="page-content">
@inject('orderTransactionsDataGrid', 'Webkul\Admin\DataGrids\OrderTransactionsDataGrid')
{!! $orderTransactionsDataGrid->render() !!}
</div>
</div>
<modal id="downloadDataGrid" :is-open="modalIds.downloadDataGrid">
<h3 slot="header">{{ __('admin::app.export.download') }}</h3>
<div slot="body">
<export-form></export-form>
</div>
</modal>
@stop
@push('scripts')
@include('admin::export.export', ['gridName' => $orderTransactionsDataGrid])
@endpush

View File

@ -0,0 +1,123 @@
@extends('admin::layouts.master')
@section('page_title')
{{ __('admin::app.sales.transactions.view-title', ['transaction_id' => $transaction->id]) }}
@stop
@section('content-wrapper')
<div class="content full-page">
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" onclick="window.location = '{{ route('admin.sales.transactions.index') }}'"></i>
{{ __('admin::app.sales.transactions.view-title', ['transaction_id' => $transaction->id]) }}
</h1>
</div>
<div class="page-action">
</div>
</div>
<div class="page-content">
<div class="sale-container">
<accordian :title="'{{ __('admin::app.sales.transactions.transaction-data') }}'" :active="true">
<div slot="body">
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.transactions.transaction-data') }}</span>
</div>
<div class="section-content">
<div class="row">
<span class="title">
{{ __('admin::app.sales.transactions.transaction-id') }}
</span>
<span class="value">
{{ $transaction->transaction_id }}
</span>
</div>
<div class="row">
<span class="title">
{{ __('admin::app.sales.transactions.order-id') }}
</span>
<span class="value">
<a href="{{ route('admin.sales.orders.view', $transaction->order_id)}}">
{{ $transaction->order_id }}
</a>
</span>
</div>
<div class="row">
<span class="title">
{{ __('admin::app.sales.transactions.payment-method') }}
</span>
<span class="value">
{{ core()->getConfigData('sales.paymentmethods.' . $transaction->payment_method . '.title') }}
</span>
</div>
{{-- <div class="row">
<span class="title">
{{ __('admin::app.sales.transactions.status') }}
</span>
<span class="value">
{{ $transaction->status }}
</span>
</div> --}}
<div class="row">
<span class="title">
{{ __('admin::app.sales.transactions.created-at') }}
</span>
<span class="value">
{{ $transaction->created_at }}
</span>
</div>
</div>
</div>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.sales.transactions.transaction-details') }}'" :active="true">
<div slot="body">
@php
$transData = json_decode(json_encode(json_decode($transaction['data'])), true);
@endphp
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.transactions.transaction-details') }}</span>
</div>
<div class="section-content">
@foreach ($transactionDeatilsData as $key => $data)
<div class="row">
<span class="title">
{{ $key }}
</span>
<span class="value">
{{ $data }}
</span>
</div>
@endforeach
</div>
</div>
</div>
</accordian>
</div>
</div>
</div>
@stop

View File

@ -255,7 +255,7 @@ class SmartButtonController extends Controller
'success' => true,
]);
} catch (\Exception $e) {
session()->flash('error', trans('shop::app.common.error'));
session()->flash('error', trans($e->getMessage()));
throw $e;
}

View File

@ -0,0 +1,73 @@
<?php
namespace Webkul\Paypal\Listeners;
use Webkul\Paypal\Payment\SmartButton;
use Webkul\Sales\Repositories\OrderTransactionRepository;
class Transaction
{
/**
* SmartButton $smartButton
*
* @var \Webkul\Paypal\Payment\SmartButton
*/
protected $smartButton;
/**
* OrderTransactionRepository object
*
* @var \Webkul\Sales\Repositories\OrderTransactionRepository
*/
protected $orderTransactionRepository;
/**
* Create a new listener instance.
*
* @param \Webkul\Paypal\Payment\SmartButton $smartButton
* @param \Webkul\Sales\Repositories\OrderTransactionRepository $orderTransactionRepository
* @return void
*/
public function __construct(
SmartButton $smartButton,
OrderTransactionRepository $orderTransactionRepository
)
{
$this->smartButton = $smartButton;
$this->orderTransactionRepository = $orderTransactionRepository;
}
/**
* Save the transaction data for online payment.
* @param \Webkul\Sales\Models\Invoice $invoice
*
* @return void
*/
public function saveTransaction($invoice) {
$data = request()->all();
if ($invoice->order->payment->method == 'paypal_smart_button') {
if (isset($data['orderData']) && isset($data['orderData']['orderID'])) {
$smartButtonOrderId = $data['orderData']['orderID'];
$transactionDetails = $this->smartButton->getOrder($smartButtonOrderId);
$transactionDetails = json_decode(json_encode($transactionDetails), true);
if ($transactionDetails['statusCode'] == 200) {
$transactionData['transaction_id'] = $transactionDetails['result']['id'];
$transactionData['status'] = $transactionDetails['result']['status'];
$transactionData['type'] = $transactionDetails['result']['intent'];
$transactionData['payment_method'] = $invoice->order->payment->method;
$transactionData['order_id'] = $invoice->order->id;
$transactionData['invoice_id'] = $invoice->id;
$transactionData['data'] = json_encode (
array_merge($transactionDetails['result']['purchase_units'],
$transactionDetails['result']['payer'])
);
$this->orderTransactionRepository->create($transactionData);
}
}
}
}
}

View File

@ -15,9 +15,11 @@ class EventServiceProvider extends ServiceProvider
* @return void
*/
public function boot()
{
{
Event::listen('bagisto.shop.layout.body.after', static function(ViewRenderEventManager $viewRenderEventManager) {
$viewRenderEventManager->addTemplate('paypal::checkout.onepage.paypal-smart-button');
});
Event::listen('sales.invoice.save.after', 'Webkul\Paypal\Listeners\Transaction@saveTransaction');
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace Webkul\Sales\Contracts;
interface OrderTransaction
{
}

View File

@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOrderTransactionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('order_transactions', function (Blueprint $table) {
$table->increments('id');
$table->string('transaction_id');
$table->string('status')->nullable();
$table->string('type')->nullable();
$table->string('payment_method')->nullable();
$table->json('data')->nullable();
$table->integer('invoice_id')->unsigned();
$table->integer('order_id')->unsigned();
$table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('order_transactions');
}
}

View File

@ -126,6 +126,14 @@ class Order extends Model implements OrderContract
return $this->hasMany(RefundProxy::modelClass());
}
/**
* Get the order transactions record associated with the order.
*/
public function transactions()
{
return $this->hasMany(OrderTransactionProxy::modelClass());
}
/**
* Get the customer record associated with the order.
*/

View File

@ -0,0 +1,17 @@
<?php
namespace Webkul\Sales\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Sales\Contracts\OrderTransaction as OrderTransactionContract;
class OrderTransaction extends Model implements OrderTransactionContract
{
protected $table = 'order_transactions';
protected $guarded = [
'id',
'created_at',
'updated_at',
];
}

View File

@ -0,0 +1,10 @@
<?php
namespace Webkul\Sales\Models;
use Konekt\Concord\Proxies\ModelProxy;
class OrderTransactionProxy extends ModelProxy
{
}

View File

@ -19,5 +19,6 @@ class ModuleServiceProvider extends CoreModuleServiceProvider
\Webkul\Sales\Models\ShipmentItem::class,
\Webkul\Sales\Models\Refund::class,
\Webkul\Sales\Models\RefundItem::class,
\Webkul\Sales\Models\OrderTransaction::class,
];
}

View File

@ -0,0 +1,26 @@
<?php
namespace Webkul\Sales\Repositories;
use Webkul\Core\Eloquent\Repository;
use Webkul\Sales\Contracts\OrderTransaction;
/**
* Order Transaction Repository
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class OrderTransactionRepository extends Repository
{
/**
* Specify Model class name
*
* @return string
*/
function model()
{
return OrderTransaction::class;
}
}