Added autolink to emails and fixed checkout.com integration

This commit is contained in:
Hillel Coren 2016-01-18 10:30:42 +02:00
parent 6e5237b7dd
commit cbe2b2905e
15 changed files with 660 additions and 143 deletions

View File

@ -20,12 +20,9 @@ use App\Models\Product;
use App\Models\TaxRate;
use App\Models\InvoiceDesign;
use App\Models\Activity;
use App\Models\Gateway;
use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\ClientRepository;
use App\Events\InvoiceInvitationWasViewed;
use App\Events\QuoteInvitationWasViewed;
use App\Services\InvoiceService;
use App\Services\RecurringInvoiceService;
use App\Http\Requests\SaveInvoiceWithClientRequest;
@ -86,119 +83,6 @@ class InvoiceController extends BaseController
return $this->recurringInvoiceService->getDatatable($accountId, $clientPublicId, ENTITY_RECURRING_INVOICE, $search);
}
public function view($invitationKey)
{
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
return response()->view('error', [
'error' => trans('texts.invoice_not_found'),
'hideHeader' => true,
]);
}
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $invoice->account;
if (!$account->checkSubdomain(Request::server('HTTP_HOST'))) {
return response()->view('error', [
'error' => trans('texts.invoice_not_found'),
'hideHeader' => true,
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
]);
}
if (!Input::has('phantomjs') && !Session::has($invitationKey) && (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
if ($invoice->is_quote) {
event(new QuoteInvitationWasViewed($invoice, $invitation));
} else {
event(new InvoiceInvitationWasViewed($invoice, $invitation));
}
}
Session::put($invitationKey, true); // track this invitation has been seen
Session::put('invitation_key', $invitationKey); // track current invitation
$account->loadLocalizationSettings($client);
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
$invoice->is_pro = $account->isPro();
$invoice->invoice_fonts = $account->getFontsData();
if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
$invoice->invoice_design->javascript = $account->custom_design;
} else {
$invoice->invoice_design->javascript = $invoice->invoice_design->pdfmake;
}
$contact = $invitation->contact; $contact->setVisible([
'first_name',
'last_name',
'email',
'phone',
]);
$paymentTypes = $this->getPaymentTypes($client, $invitation);
$paymentURL = '';
if (count($paymentTypes)) {
$paymentURL = $paymentTypes[0]['url'];
if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
$paymentURL = URL::to($paymentURL);
}
}
$showApprove = $invoice->quote_invoice_id ? false : true;
if ($invoice->due_date) {
$showApprove = time() < strtotime($invoice->due_date);
}
$data = array(
'showApprove' => $showApprove,
'showBreadcrumbs' => false,
'hideLogo' => $account->isWhiteLabel(),
'hideHeader' => $account->isNinjaAccount(),
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
'invoice' => $invoice->hidePrivateFields(),
'invitation' => $invitation,
'invoiceLabels' => $account->getInvoiceLabels(),
'contact' => $contact,
'paymentTypes' => $paymentTypes,
'paymentURL' => $paymentURL,
'phantomjs' => Input::has('phantomjs'),
);
return View::make('invoices.view', $data);
}
private function getPaymentTypes($client, $invitation)
{
$paymentTypes = [];
$account = $client->account;
if ($client->getGatewayToken()) {
$paymentTypes[] = [
'url' => URL::to("payment/{$invitation->invitation_key}/token"), 'label' => trans('texts.use_card_on_file')
];
}
foreach(Gateway::$paymentTypes as $type) {
if ($account->getGatewayByType($type)) {
$typeLink = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
$url = URL::to("/payment/{$invitation->invitation_key}/{$typeLink}");
// PayPal doesn't allow being run in an iframe so we need to open in new tab
if ($type === PAYMENT_TYPE_PAYPAL && $account->iframe_url) {
$url = 'javascript:window.open("'.$url.'", "_blank")';
}
$paymentTypes[] = [
'url' => $url, 'label' => trans('texts.'.strtolower($type))
];
}
}
return $paymentTypes;
}
public function edit($publicId, $clone = false)
{
$account = Auth::user()->account;

View File

@ -532,7 +532,8 @@ class PaymentController extends BaseController
try {
if (method_exists($gateway, 'completePurchase')
&& !$accountGateway->isGateway(GATEWAY_TWO_CHECKOUT)) {
&& !$accountGateway->isGateway(GATEWAY_TWO_CHECKOUT)
&& !$accountGateway->isGateway(GATEWAY_CHECKOUT_COM)) {
$details = $this->paymentService->getPaymentDetails($invitation, $accountGateway);
$response = $this->paymentService->completePurchase($gateway, $accountGateway, $details, $token);
$ref = $response->getTransactionReference() ?: $token;

View File

@ -1,25 +1,162 @@
<?php namespace App\Http\Controllers;
use Auth;
use View;
use DB;
use URL;
use Input;
use Utils;
use Request;
use Session;
use Datatable;
use App\Models\Gateway;
use App\Models\Invitation;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\ActivityRepository;
use App\Events\InvoiceInvitationWasViewed;
use App\Events\QuoteInvitationWasViewed;
use App\Services\PaymentService;
class PublicClientController extends BaseController
{
private $invoiceRepo;
private $paymentRepo;
public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo)
public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo, PaymentService $paymentService)
{
$this->invoiceRepo = $invoiceRepo;
$this->paymentRepo = $paymentRepo;
$this->activityRepo = $activityRepo;
$this->paymentService = $paymentService;
}
public function view($invitationKey)
{
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
return response()->view('error', [
'error' => trans('texts.invoice_not_found'),
'hideHeader' => true,
]);
}
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $invoice->account;
if (!$account->checkSubdomain(Request::server('HTTP_HOST'))) {
return response()->view('error', [
'error' => trans('texts.invoice_not_found'),
'hideHeader' => true,
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
]);
}
if (!Input::has('phantomjs') && !Session::has($invitationKey) && (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
if ($invoice->is_quote) {
event(new QuoteInvitationWasViewed($invoice, $invitation));
} else {
event(new InvoiceInvitationWasViewed($invoice, $invitation));
}
}
Session::put($invitationKey, true); // track this invitation has been seen
Session::put('invitation_key', $invitationKey); // track current invitation
$account->loadLocalizationSettings($client);
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
$invoice->is_pro = $account->isPro();
$invoice->invoice_fonts = $account->getFontsData();
if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
$invoice->invoice_design->javascript = $account->custom_design;
} else {
$invoice->invoice_design->javascript = $invoice->invoice_design->pdfmake;
}
$contact = $invitation->contact;
$contact->setVisible([
'first_name',
'last_name',
'email',
'phone',
]);
$paymentTypes = $this->getPaymentTypes($client, $invitation);
$paymentURL = '';
if (count($paymentTypes)) {
$paymentURL = $paymentTypes[0]['url'];
if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
$paymentURL = URL::to($paymentURL);
}
}
$showApprove = $invoice->quote_invoice_id ? false : true;
if ($invoice->due_date) {
$showApprove = time() < strtotime($invoice->due_date);
}
// Checkout.com requires first getting a payment token
$checkoutComToken = false;
$checkoutComKey = false;
if ($accountGateway = $account->getGatewayConfig(GATEWAY_CHECKOUT_COM)) {
if ($checkoutComToken = $this->paymentService->getCheckoutComToken($invitation)) {
$checkoutComKey = $accountGateway->getConfigField('publicApiKey');
$invitation->transaction_reference = $checkoutComToken;
$invitation->save();
}
}
$data = array(
'account' => $account,
'showApprove' => $showApprove,
'showBreadcrumbs' => false,
'hideLogo' => $account->isWhiteLabel(),
'hideHeader' => $account->isNinjaAccount(),
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
'invoice' => $invoice->hidePrivateFields(),
'invitation' => $invitation,
'invoiceLabels' => $account->getInvoiceLabels(),
'contact' => $contact,
'paymentTypes' => $paymentTypes,
'paymentURL' => $paymentURL,
'checkoutComToken' => $checkoutComToken,
'checkoutComKey' => $checkoutComKey,
'phantomjs' => Input::has('phantomjs'),
);
return View::make('invoices.view', $data);
}
private function getPaymentTypes($client, $invitation)
{
$paymentTypes = [];
$account = $client->account;
if ($client->getGatewayToken()) {
$paymentTypes[] = [
'url' => URL::to("payment/{$invitation->invitation_key}/token"), 'label' => trans('texts.use_card_on_file')
];
}
foreach(Gateway::$paymentTypes as $type) {
if ($account->getGatewayByType($type)) {
$typeLink = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
$url = URL::to("/payment/{$invitation->invitation_key}/{$typeLink}");
// PayPal doesn't allow being run in an iframe so we need to open in new tab
if ($type === PAYMENT_TYPE_PAYPAL && $account->iframe_url) {
$url = 'javascript:window.open("'.$url.'", "_blank")';
}
$paymentTypes[] = [
'url' => $url, 'label' => trans('texts.'.strtolower($type))
];
}
}
return $paymentTypes;
}
public function dashboard()

View File

@ -46,6 +46,11 @@ class Utils
return file_exists(storage_path() . '/framework/down');
}
public static function isCron()
{
return php_sapi_name() == 'cli';
}
public static function isNinja()
{
return self::isNinjaProd() || self::isNinjaDev();

View File

@ -0,0 +1,335 @@
<?php
#
# A PHP auto-linking library
#
# https://github.com/iamcal/lib_autolink
#
# By Cal Henderson <cal@iamcal.com>
# This code is licensed under the MIT license
#
####################################################################
#
# These are global options. You can set them before calling the autolinking
# functions to change the output.
#
$GLOBALS['autolink_options'] = array(
# Should http:// be visibly stripped from the front
# of URLs?
'strip_protocols' => false,
);
####################################################################
function autolink($text, $limit=30, $tagfill='', $auto_title = true){
$text = autolink_do($text, '![a-z][a-z-]+://!i', $limit, $tagfill, $auto_title);
$text = autolink_do($text, '!(mailto|skype):!i', $limit, $tagfill, $auto_title);
$text = autolink_do($text, '!www\\.!i', $limit, $tagfill, $auto_title, 'http://');
return $text;
}
####################################################################
function autolink_do($text, $sub, $limit, $tagfill, $auto_title, $force_prefix=null){
$text_l = StrToLower($text);
$cursor = 0;
$loop = 1;
$buffer = '';
while (($cursor < strlen($text)) && $loop){
$ok = 1;
$matched = preg_match($sub, $text_l, $m, PREG_OFFSET_CAPTURE, $cursor);
if (!$matched){
$loop = 0;
$ok = 0;
}else{
$pos = $m[0][1];
$sub_len = strlen($m[0][0]);
$pre_hit = substr($text, $cursor, $pos-$cursor);
$hit = substr($text, $pos, $sub_len);
$pre = substr($text, 0, $pos);
$post = substr($text, $pos + $sub_len);
$fail_text = $pre_hit.$hit;
$fail_len = strlen($fail_text);
#
# substring found - first check to see if we're inside a link tag already...
#
$bits = preg_split("!</a>!i", $pre);
$last_bit = array_pop($bits);
if (preg_match("!<a\s!i", $last_bit)){
#echo "fail 1 at $cursor<br />\n";
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
#
# looks like a nice spot to autolink from - check the pre
# to see if there was whitespace before this match
#
if ($ok){
if ($pre){
if (!preg_match('![\s\(\[\{>]$!s', $pre)){
#echo "fail 2 at $cursor ($pre)<br />\n";
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
}
#
# we want to autolink here - find the extent of the url
#
if ($ok){
if (preg_match('/^([a-z0-9\-\.\/\-_%~!?=,:;&+*#@\(\)\$]+)/i', $post, $matches)){
$url = $hit.$matches[1];
$cursor += strlen($url) + strlen($pre_hit);
$buffer .= $pre_hit;
$url = html_entity_decode($url);
#
# remove trailing punctuation from url
#
while (preg_match('|[.,!;:?]$|', $url)){
$url = substr($url, 0, strlen($url)-1);
$cursor--;
}
foreach (array('()', '[]', '{}') as $pair){
$o = substr($pair, 0, 1);
$c = substr($pair, 1, 1);
if (preg_match("!^(\\$c|^)[^\\$o]+\\$c$!", $url)){
$url = substr($url, 0, strlen($url)-1);
$cursor--;
}
}
#
# nice-i-fy url here
#
$link_url = $url;
$display_url = $url;
if ($force_prefix) $link_url = $force_prefix.$link_url;
if ($GLOBALS['autolink_options']['strip_protocols']){
if (preg_match('!^(http|https)://!i', $display_url, $m)){
$display_url = substr($display_url, strlen($m[1])+3);
}
}
$display_url = autolink_label($display_url, $limit);
#
# add the url
#
$currentTagfill = $tagfill;
if ($display_url != $link_url && !preg_match('@title=@msi',$currentTagfill) && $auto_title) {
$display_quoted = preg_quote($display_url, '!');
if (!preg_match("!^(http|https)://{$display_quoted}$!i", $link_url)){
$currentTagfill .= ' title="'.$link_url.'"';
}
}
$link_url_enc = HtmlSpecialChars($link_url);
$display_url_enc = HtmlSpecialChars($display_url);
$buffer .= "<a href=\"{$link_url_enc}\"$currentTagfill>{$display_url_enc}</a>";
}else{
#echo "fail 3 at $cursor<br />\n";
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
}
#
# add everything from the cursor to the end onto the buffer.
#
$buffer .= substr($text, $cursor);
return $buffer;
}
####################################################################
function autolink_label($text, $limit){
if (!$limit){ return $text; }
if (strlen($text) > $limit){
return substr($text, 0, $limit-3).'...';
}
return $text;
}
####################################################################
function autolink_email($text, $tagfill=''){
$atom = '[^()<>@,;:\\\\".\\[\\]\\x00-\\x20\\x7f]+'; # from RFC822
#die($atom);
$text_l = StrToLower($text);
$cursor = 0;
$loop = 1;
$buffer = '';
while(($cursor < strlen($text)) && $loop){
#
# find an '@' symbol
#
$ok = 1;
$pos = strpos($text_l, '@', $cursor);
if ($pos === false){
$loop = 0;
$ok = 0;
}else{
$pre = substr($text, $cursor, $pos-$cursor);
$hit = substr($text, $pos, 1);
$post = substr($text, $pos + 1);
$fail_text = $pre.$hit;
$fail_len = strlen($fail_text);
#die("$pre::$hit::$post::$fail_text");
#
# substring found - first check to see if we're inside a link tag already...
#
$bits = preg_split("!</a>!i", $pre);
$last_bit = array_pop($bits);
if (preg_match("!<a\s!i", $last_bit)){
#echo "fail 1 at $cursor<br />\n";
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
#
# check backwards
#
if ($ok){
if (preg_match("!($atom(\.$atom)*)\$!", $pre, $matches)){
# move matched part of address into $hit
$len = strlen($matches[1]);
$plen = strlen($pre);
$hit = substr($pre, $plen-$len).$hit;
$pre = substr($pre, 0, $plen-$len);
}else{
#echo "fail 2 at $cursor ($pre)<br />\n";
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
#
# check forwards
#
if ($ok){
if (preg_match("!^($atom(\.$atom)*)!", $post, $matches)){
# move matched part of address into $hit
$len = strlen($matches[1]);
$hit .= substr($post, 0, $len);
$post = substr($post, $len);
}else{
#echo "fail 3 at $cursor ($post)<br />\n";
$ok = 0;
$cursor += $fail_len;
$buffer .= $fail_text;
}
}
#
# commit
#
if ($ok) {
$cursor += strlen($pre) + strlen($hit);
$buffer .= $pre;
$buffer .= "<a href=\"mailto:$hit\"$tagfill>$hit</a>";
}
}
#
# add everything from the cursor to the end onto the buffer.
#
$buffer .= substr($text, $cursor);
return $buffer;
}
####################################################################
?>

View File

@ -260,7 +260,8 @@ class ContactMailer extends Mailer
}
$str = str_replace(array_keys($variables), array_values($variables), $template);
$str = autolink($str, 100);
return $str;
}
}

View File

@ -62,7 +62,7 @@ class AppServiceProvider extends ServiceProvider {
});
HTML::macro('image_data', function($imagePath) {
return 'data:image/jpeg;base64,' . base64_encode(file_get_contents(public_path().'/'.$imagePath));
return 'data:image/jpeg;base64,' . base64_encode(file_get_contents($imagePath));
});
HTML::macro('flatButton', function($label, $color) {

View File

@ -184,6 +184,30 @@ class PaymentService extends BaseService
return $cardReference;
}
public function getCheckoutComToken($invitation)
{
$token = false;
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $invoice->account;
$accountGateway = $account->getGatewayConfig(GATEWAY_CHECKOUT_COM);
$gateway = $this->createGateway($accountGateway);
$response = $gateway->purchase([
'amount' => $invoice->getRequestedAmount(),
'currency' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD')
])->send();
if ($response->isRedirect()) {
$token = $response->getTransactionReference();
}
Session::set($invitation->id . 'payment_type', PAYMENT_TYPE_CREDIT_CARD);
return $token;
}
public function createPayment($invitation, $accountGateway, $ref, $payerId = null)
{
$invoice = $invitation->invoice;

View File

@ -86,7 +86,10 @@
],
"psr-4": {
"App\\": "app/"
}
},
"files": [
"app/Libraries/lib_autolink.php"
]
},
"autoload-dev": {
"classmap": [

View File

@ -110,7 +110,7 @@ class PaymentLibrariesSeeder extends Seeder
['name' => 'Argentine Peso', 'code' => 'ARS', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Bangladeshi Taka', 'code' => 'BDT', 'symbol' => 'Tk', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'United Arab Emirates Dirham', 'code' => 'AED', 'symbol' => 'DH ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Hong Kong Dollar', 'code' => 'HKD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Hong Kong Dollar', 'code' => 'HKD', 'symbol' => 'HKD ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Indonesian Rupiah', 'code' => 'IDR', 'symbol' => 'Rp', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Mexican Peso', 'code' => 'MXN', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Egyptian Pound', 'code' => 'EGP', 'symbol' => 'E£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],

View File

@ -5,8 +5,6 @@
# Invoice Ninja
### [https://www.invoiceninja.com](https://www.invoiceninja.com)
We're starting to work on our expenses, vendors and receipts module. If you'd like to help us design it please send us an email to join the discussion.
[![Join the chat at https://gitter.im/hillelcoren/invoice-ninja](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### Referral Program

View File

@ -3,7 +3,7 @@
<a href="{{ $account->website }}" style="color: #19BB40; text-decoration: underline;">
@endif
<img src="{{ $message->embed($account->getLogoPath()) }}" style="max-height:50px; max-width:140px; margin-left: 33px;" />
<img src="{{ $message->embed($account->getAbsoluteLogoPath()) }}" style="max-height:50px; max-width:140px; margin-left: 33px;" />
@if ($account->website)
</a>

View File

@ -21,24 +21,28 @@
<div class="container">
<p>&nbsp;</p>
<div class="pull-right" style="text-align:right">
@if ($invoice->is_quote)
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}&nbsp;&nbsp;
@if ($showApprove)
{!! Button::success(trans('texts.approve'))->asLinkTo(URL::to('/approve/' . $invitation->invitation_key))->large() !!}
@endif
@elseif ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_recurring)
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}&nbsp;&nbsp;
@if (count($paymentTypes) > 1)
{!! DropdownButton::success(trans('texts.pay_now'))->withContents($paymentTypes)->large() !!}
@else
<a href='{!! $paymentURL !!}' class="btn btn-success btn-lg">{{ trans('texts.pay_now') }}</a>
@endif
@else
{!! Button::normal('Download PDF')->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
@endif
</div>
@if ($checkoutComToken)
@include('partials.checkout_com_payment')
@else
<p>&nbsp;</p>
<div class="pull-right" style="text-align:right">
@if ($invoice->is_quote)
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}&nbsp;&nbsp;
@if ($showApprove)
{!! Button::success(trans('texts.approve'))->asLinkTo(URL::to('/approve/' . $invitation->invitation_key))->large() !!}
@endif
@elseif ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_recurring)
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}&nbsp;&nbsp;
@if (count($paymentTypes) > 1)
{!! DropdownButton::success(trans('texts.pay_now'))->withContents($paymentTypes)->large() !!}
@else
<a href='{!! $paymentURL !!}' class="btn btn-success btn-lg">{{ trans('texts.pay_now') }}</a>
@endif
@else
{!! Button::normal('Download PDF')->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
@endif
</div>
@endif
<div class="clearfix"></div><p>&nbsp;</p>

View File

@ -0,0 +1,22 @@
<script src="https://sandbox.checkout.com/js/v1/checkout.js"></script>
<form method="POST" class="payment-form">
<script>
Checkout.render({
debugMode: true,
publicKey: '{{ $checkoutComKey }}',
paymentToken: '{{ $checkoutComToken }}',
customerEmail: '{{ $contact->email }}',
customerName: '{{ $contact->getFullName() }}',
value: {{ $invoice->getRequestedAmount() * 100 }},
currency: '{{ $invoice->getCurrencyCode() }}',
widgetContainerSelector: '.payment-form',
widgetColor: '#333',
themeColor: '#3075dd',
buttonColor:'#51c470',
cardCharged: function(event){
location.href = '{{ URL::to('/complete?token=' . $checkoutComToken) }}';
}
});
</script>
</form>

View File

@ -0,0 +1,103 @@
/<?php
use Codeception\Util\Fixtures;
use \AcceptanceTester;
use Faker\Factory;
class TaxRatesCest
{
private $faker;
public function _before(AcceptanceTester $I)
{
$I->checkIfLogin($I);
$this->faker = Factory::create();
}
public function taxRates(AcceptanceTester $I)
{
}
/*
public function onlinePayment(AcceptanceTester $I)
{
$I->wantTo('test an online payment');
$clientEmail = $this->faker->safeEmail;
$productKey = $this->faker->text(10);
// set gateway info
$I->wantTo('create a gateway');
$I->amOnPage('/settings/online_payments');
if (strpos($I->grabFromCurrentUrl(), 'create') !== false) {
$I->fillField(['name' =>'23_apiKey'], Fixtures::get('gateway_key'));
$I->selectOption('#token_billing_type_id', 4);
$I->click('Save');
$I->see('Successfully created gateway');
}
// create client
$I->amOnPage('/clients/create');
$I->fillField(['name' => 'contacts[0][email]'], $clientEmail);
$I->click('Save');
$I->see($clientEmail);
// create product
$I->amOnPage('/products/create');
$I->fillField(['name' => 'product_key'], $productKey);
$I->fillField(['name' => 'notes'], $this->faker->text(80));
$I->fillField(['name' => 'cost'], $this->faker->numberBetween(1, 20));
$I->click('Save');
$I->wait(1);
$I->see($productKey);
// create invoice
$I->amOnPage('/invoices/create');
$I->selectDropdown($I, $clientEmail, '.client_select .dropdown-toggle');
$I->fillField('table.invoice-table tbody tr:nth-child(1) #product_key', $productKey);
$I->click('Save');
$I->see($clientEmail);
// enter payment
$clientId = $I->grabFromDatabase('contacts', 'client_id', ['email' => $clientEmail]);
$invoiceId = $I->grabFromDatabase('invoices', 'id', ['client_id' => $clientId]);
$invitationKey = $I->grabFromDatabase('invitations', 'invitation_key', ['invoice_id' => $invoiceId]);
$clientSession = $I->haveFriend('client');
$clientSession->does(function(AcceptanceTester $I) use ($invitationKey) {
$I->amOnPage('/view/' . $invitationKey);
$I->click('Pay Now');
$I->fillField(['name' => 'first_name'], $this->faker->firstName);
$I->fillField(['name' => 'last_name'], $this->faker->lastName);
$I->fillField(['name' => 'address1'], $this->faker->streetAddress);
$I->fillField(['name' => 'address2'], $this->faker->streetAddress);
$I->fillField(['name' => 'city'], $this->faker->city);
$I->fillField(['name' => 'state'], $this->faker->state);
$I->fillField(['name' => 'postal_code'], $this->faker->postcode);
$I->selectDropdown($I, 'United States', '.country-select .dropdown-toggle');
$I->fillField(['name' => 'card_number'], '4242424242424242');
$I->fillField(['name' => 'cvv'], '1234');
$I->selectOption('#expiration_month', 12);
$I->selectOption('#expiration_year', date('Y'));
$I->click('.btn-success');
$I->see('Successfully applied payment');
});
$I->wait(1);
// create recurring invoice and auto-bill
$I->amOnPage('/recurring_invoices/create');
$I->selectDropdown($I, $clientEmail, '.client_select .dropdown-toggle');
$I->fillField('table.invoice-table tbody tr:nth-child(1) #product_key', $productKey);
$I->checkOption('#auto_bill');
$I->executeJS('preparePdfData(\'email\')');
$I->wait(2);
$I->see("$0.00");
}
*/
}