mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 20:52:56 +01:00
Working on buy now buttons
This commit is contained in:
parent
e68e213237
commit
401851e212
@ -2,7 +2,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [2.6] - 2016-07-08
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- Added 'Buy Now' buttons
|
||||
|
||||
## [2.6] - 2016-07-12
|
||||
|
||||
### Added
|
||||
- Configuration for first day of the week #950
|
||||
|
@ -25,6 +25,7 @@ use App\Models\Document;
|
||||
use App\Models\Gateway;
|
||||
use App\Models\InvoiceDesign;
|
||||
use App\Models\TaxRate;
|
||||
use App\Models\Product;
|
||||
use App\Models\PaymentTerm;
|
||||
use App\Ninja\Repositories\AccountRepository;
|
||||
use App\Ninja\Repositories\ReferralRepository;
|
||||
@ -714,6 +715,14 @@ class AccountController extends BaseController
|
||||
);
|
||||
}
|
||||
|
||||
$types = [GATEWAY_TYPE_CREDIT_CARD, GATEWAY_TYPE_BANK_TRANSFER, GATEWAY_TYPE_PAYPAL, GATEWAY_TYPE_BITCOIN, GATEWAY_TYPE_DWOLLA];
|
||||
$options = [];
|
||||
foreach ($types as $type) {
|
||||
if ($account->getGatewayByType($type)) {
|
||||
$options[$type] = trans("texts.{$type}");
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'client_view_css' => $css,
|
||||
'enable_portal_password' => $account->enable_portal_password,
|
||||
@ -721,6 +730,8 @@ class AccountController extends BaseController
|
||||
'title' => trans('texts.client_portal'),
|
||||
'section' => ACCOUNT_CLIENT_PORTAL,
|
||||
'account' => $account,
|
||||
'products' => Product::scope()->orderBy('product_key')->get(),
|
||||
'gateway_types' => $options,
|
||||
];
|
||||
|
||||
return View::make('accounts.client_portal', $data);
|
||||
|
@ -4,14 +4,20 @@ use Session;
|
||||
use Input;
|
||||
use Utils;
|
||||
use View;
|
||||
use Auth;
|
||||
use URL;
|
||||
use Exception;
|
||||
use Validator;
|
||||
use App\Models\Invitation;
|
||||
use App\Models\Account;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Product;
|
||||
use App\Models\PaymentMethod;
|
||||
use App\Services\PaymentService;
|
||||
use App\Ninja\Mailers\UserMailer;
|
||||
use App\Http\Requests\CreateOnlinePaymentRequest;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
use App\Services\InvoiceService;
|
||||
|
||||
/**
|
||||
* Class OnlinePaymentController
|
||||
@ -203,4 +209,57 @@ class OnlinePaymentController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
public function handleBuyNow(ClientRepository $clientRepo, InvoiceService $invoiceService, $gatewayType = false)
|
||||
{
|
||||
$account = Account::whereAccountKey(Input::get('account_key'))->first();
|
||||
$redirectUrl = Input::get('redirect_url', URL::previous());
|
||||
|
||||
if ( ! $account) {
|
||||
return redirect()->to("{$redirectUrl}/?error=invalid account");
|
||||
}
|
||||
|
||||
Auth::onceUsingId($account->users[0]->id);
|
||||
$product = Product::scope(Input::get('product_id'))->first();
|
||||
|
||||
if ( ! $product) {
|
||||
return redirect()->to("{$redirectUrl}/?error=invalid product");
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'first_name' => 'string|max:100',
|
||||
'last_name' => 'string|max:100',
|
||||
'email' => 'email|string|max:100',
|
||||
];
|
||||
|
||||
$validator = Validator::make(Input::all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
return redirect()->to("{$redirectUrl}/?error=" . $validator->errors()->first());
|
||||
}
|
||||
|
||||
$data = [
|
||||
'contact' => Input::all()
|
||||
];
|
||||
$client = $clientRepo->save($data);
|
||||
|
||||
$data = [
|
||||
'client_id' => $client->public_id,
|
||||
'invoice_items' => [[
|
||||
'product_key' => $product->product_key,
|
||||
'notes' => $product->notes,
|
||||
'cost' => $product->cost,
|
||||
'qty' => 1,
|
||||
'tax_rate1' => $product->default_tax_rate ? $product->default_tax_rate->rate : 0,
|
||||
'tax_name1' => $product->default_tax_rate ? $product->default_tax_rate->name : '',
|
||||
]]
|
||||
];
|
||||
$invoice = $invoiceService->save($data);
|
||||
$invitation = $invoice->invitations[0];
|
||||
$link = $invitation->getLink();
|
||||
|
||||
if ($gatewayType) {
|
||||
return redirect()->to($invitation->getLink('payment') . "/{$gatewayType}");
|
||||
} else {
|
||||
return redirect()->to($invitation->getLink());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ class VerifyCsrfToken extends BaseVerifier
|
||||
'hook/email_bounced',
|
||||
'reseller_stats',
|
||||
'payment_hook/*',
|
||||
'buy_now/*',
|
||||
];
|
||||
|
||||
/**
|
||||
@ -42,7 +43,6 @@ class VerifyCsrfToken extends BaseVerifier
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
foreach ($this->openRoutes as $route) {
|
||||
|
||||
if ($request->is($route)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ Route::post('signup/submit', 'AccountController@submitSignup');
|
||||
|
||||
Route::get('/auth/{provider}', 'Auth\AuthController@authLogin');
|
||||
Route::get('/auth_unlink', 'Auth\AuthController@authUnlink');
|
||||
Route::match(['GET', 'POST'], '/buy_now/{gateway_type?}', 'OnlinePaymentController@handleBuyNow');
|
||||
|
||||
Route::post('/hook/email_bounced', 'AppController@emailBounced');
|
||||
Route::post('/hook/email_opened', 'AppController@emailOpened');
|
||||
|
@ -227,7 +227,7 @@ class BasePaymentDriver
|
||||
$gateway = $this->gateway();
|
||||
|
||||
if ($input) {
|
||||
$this->updateAddress();
|
||||
$this->updateClient();
|
||||
}
|
||||
|
||||
// load or create token
|
||||
@ -280,8 +280,13 @@ class BasePaymentDriver
|
||||
}
|
||||
}
|
||||
|
||||
private function updateAddress()
|
||||
private function updateClient()
|
||||
{
|
||||
if ( ! $this->contact()->email && $this->input['email']) {
|
||||
$this->contact()->email = $this->input['email'];
|
||||
$this->contact()->save();
|
||||
}
|
||||
|
||||
if ( ! $this->isGatewayType(GATEWAY_TYPE_CREDIT_CARD)) {
|
||||
return;
|
||||
}
|
||||
|
@ -12,21 +12,6 @@ use App\Ninja\Datatables\PaymentDatatable;
|
||||
|
||||
class PaymentService extends BaseService
|
||||
{
|
||||
/**
|
||||
* @var DatatableService
|
||||
*/
|
||||
protected $datatableService;
|
||||
|
||||
/**
|
||||
* @var PaymentRepository
|
||||
*/
|
||||
protected $paymentRepo;
|
||||
|
||||
/**
|
||||
* @var AccountRepository
|
||||
*/
|
||||
protected $accountRepo;
|
||||
|
||||
/**
|
||||
* PaymentService constructor.
|
||||
*
|
||||
@ -157,5 +142,4 @@ class PaymentService extends BaseService
|
||||
return parent::bulk($ids, $action);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2027,7 +2027,14 @@ $LANG = array(
|
||||
'restored_expense_category' => 'Successfully restored expense category',
|
||||
'apply_taxes' => 'Apply taxes',
|
||||
'min_to_max_users' => ':min to :max users',
|
||||
'max_users_reached' => 'The maximum number of users has been reached.'
|
||||
'max_users_reached' => 'The maximum number of users has been reached.',
|
||||
'buy_now_buttons' => 'Buy Now Buttons',
|
||||
'landing_page' => 'Landing Page',
|
||||
'payment_type' => 'Payment Type',
|
||||
'form' => 'Form',
|
||||
'link' => 'Link',
|
||||
'fields' => 'Fields',
|
||||
'buy_now_buttons_warning' => 'Note: client and invoice records are created even if the transaction isn\'t completed.',
|
||||
|
||||
);
|
||||
|
||||
|
@ -3,7 +3,16 @@
|
||||
@section('head')
|
||||
@parent
|
||||
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto+Mono' rel='stylesheet' type='text/css'>
|
||||
@include('money_script')
|
||||
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto+Mono' rel='stylesheet' type='text/css'>
|
||||
|
||||
<style>
|
||||
.checkbox-inline input[type="checkbox"] {
|
||||
margin-left:-20px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
@ -69,6 +78,65 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{!! trans('texts.buy_now_buttons') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-md-10 col-md-offset-1">
|
||||
|
||||
{!! Former::select('product')
|
||||
->onchange('updateBuyNowButtons()')
|
||||
->addOption('', '')
|
||||
->inlineHelp('buy_now_buttons_warning')
|
||||
->addGroupClass('product-select') !!}
|
||||
|
||||
{!! Former::inline_checkboxes('client_fields')
|
||||
->onchange('updateBuyNowButtons()')
|
||||
->checkboxes([
|
||||
trans('texts.first_name') => ['value' => 'first_name', 'name' => 'first_name'],
|
||||
trans('texts.last_name') => ['value' => 'last_name', 'name' => 'last_name'],
|
||||
trans('texts.email') => ['value' => 'email', 'name' => 'email'],
|
||||
]) !!}
|
||||
|
||||
{!! Former::inline_radios('landing_page')
|
||||
->onchange('showPaymentTypes();updateBuyNowButtons();')
|
||||
->radios([
|
||||
trans('texts.invoice') => ['value' => 'invoice', 'name' => 'landing_page_type'],
|
||||
trans('texts.payment') => ['value' => 'payment', 'name' => 'landing_page_type'],
|
||||
])->check('invoice') !!}
|
||||
|
||||
<div id="paymentTypesDiv" style="display:none">
|
||||
{!! Former::select('payment_type')
|
||||
->onchange('updateBuyNowButtons()')
|
||||
->options($gateway_types) !!}
|
||||
</div>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<div role="tabpanel">
|
||||
<ul class="nav nav-tabs" role="tablist" style="border: none">
|
||||
<li role="presentation" class="active">
|
||||
<a href="#form" aria-controls="form" role="tab" data-toggle="tab">{{ trans('texts.form') }}</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a href="#link" aria-controls="link" role="tab" data-toggle="tab">{{ trans('texts.link') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane active" id="form">
|
||||
<textarea id="formTextarea" class="form-control" rows="4" readonly></textarea>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="link">
|
||||
<textarea id="linkTextarea" class="form-control" rows="4" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (Utils::hasFeature(FEATURE_CLIENT_PORTAL_CSS))
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@ -95,12 +163,74 @@
|
||||
</center>
|
||||
|
||||
{!! Former::close() !!}
|
||||
|
||||
<script>
|
||||
|
||||
var products = {!! $products !!};
|
||||
console.log(products);
|
||||
|
||||
$(function() {
|
||||
var $productSelect = $('select#product');
|
||||
for (var i=0; i<products.length; i++) {
|
||||
var product = products[i];
|
||||
|
||||
$productSelect.append(new Option(formatMoney(product.cost) + ' - ' + product.product_key, product.public_id));
|
||||
}
|
||||
$productSelect.combobox();
|
||||
|
||||
fixCheckboxes();
|
||||
updateBuyNowButtons();
|
||||
})
|
||||
|
||||
$('#enable_portal_password').change(fixCheckboxes);
|
||||
function fixCheckboxes(){
|
||||
|
||||
function fixCheckboxes() {
|
||||
var checked = $('#enable_portal_password').is(':checked');
|
||||
$('#send_portal_password').prop('disabled', !checked);
|
||||
}
|
||||
fixCheckboxes();
|
||||
|
||||
function showPaymentTypes() {
|
||||
var val = $('input[name=landing_page_type]:checked').val()
|
||||
if (val == '{{ ENTITY_PAYMENT }}') {
|
||||
$('#paymentTypesDiv').fadeIn();
|
||||
} else {
|
||||
$('#paymentTypesDiv').hide();
|
||||
}
|
||||
}
|
||||
|
||||
function updateBuyNowButtons() {
|
||||
var productId = $('#product').val();
|
||||
var landingPage = $('input[name=landing_page_type]:checked').val()
|
||||
var paymentType = landingPage == 'payment' ? '/' + $('#payment_type').val() : '';
|
||||
|
||||
var form = '';
|
||||
var link = '';
|
||||
|
||||
if (productId) {
|
||||
var link = '{{ url('/buy_now') }}' + paymentType +
|
||||
'?account_key={{ $account->account_key }}' +
|
||||
'&product_id=' + productId;
|
||||
|
||||
var form = '<form action="{{ url('/buy_now') }}' + paymentType + '" method="post" target="_top">' + "\n" +
|
||||
'<input type="hidden" name="account_key" value="{{ $account->account_key }}"/>' + "\n" +
|
||||
'<input type="hidden" name="product_id" value="' + productId + '"/>' + "\n";
|
||||
|
||||
@foreach (['first_name', 'last_name', 'email'] as $field)
|
||||
if ($('input#{{ $field }}').is(':checked')) {
|
||||
form += '<input type="{{ $field == 'email' ? 'email' : 'text' }}" name="{{ $field }}" placeholder="{{ trans("texts.{$field}") }}" required/>' + "\n";
|
||||
link += '&{{ $field }}=';
|
||||
}
|
||||
@endforeach
|
||||
|
||||
form += '<input type="submit" value="Buy Now" name="submit"/>' + "\n" + '</form>';
|
||||
}
|
||||
|
||||
$('#formTextarea').text(form);
|
||||
$('#linkTextarea').text(link);
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@stop
|
||||
|
@ -77,8 +77,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (isset($paymentTitle) || ! empty($contact->email))
|
||||
<div class="row" style="display:{{ isset($paymentTitle) ? 'block' : 'none' }}">
|
||||
<div class="row" style="display:{{ isset($paymentTitle) || empty($contact->email) ? 'block' : 'none' }}">
|
||||
<div class="col-md-12">
|
||||
{!! Former::text('email')
|
||||
->placeholder(trans('texts.email'))
|
||||
@ -86,7 +85,6 @@
|
||||
->label('') !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<p> <br/> </p>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user