diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php
index 6fa1d1ae5600..83714effe168 100644
--- a/app/Http/Controllers/InvoiceController.php
+++ b/app/Http/Controllers/InvoiceController.php
@@ -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;
diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php
index 1b055969138f..681956dd2a03 100644
--- a/app/Http/Controllers/PaymentController.php
+++ b/app/Http/Controllers/PaymentController.php
@@ -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;
diff --git a/app/Http/Controllers/PublicClientController.php b/app/Http/Controllers/PublicClientController.php
index 5dea7e9d8c9c..aabd2fdf1652 100644
--- a/app/Http/Controllers/PublicClientController.php
+++ b/app/Http/Controllers/PublicClientController.php
@@ -1,25 +1,162 @@
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()
diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php
index e60feff84e99..d86ff218ca70 100644
--- a/app/Libraries/Utils.php
+++ b/app/Libraries/Utils.php
@@ -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();
diff --git a/app/Libraries/lib_autolink.php b/app/Libraries/lib_autolink.php
new file mode 100644
index 000000000000..3bc86b843e29
--- /dev/null
+++ b/app/Libraries/lib_autolink.php
@@ -0,0 +1,335 @@
+
+ # 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("!!i", $pre);
+ $last_bit = array_pop($bits);
+ if (preg_match("!\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)
\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 .= "{$display_url_enc}";
+
+ }else{
+ #echo "fail 3 at $cursor
\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("!!i", $pre);
+ $last_bit = array_pop($bits);
+ if (preg_match("!\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)
\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)
\n";
+
+ $ok = 0;
+ $cursor += $fail_len;
+ $buffer .= $fail_text;
+ }
+ }
+
+ #
+ # commit
+ #
+
+ if ($ok) {
+
+ $cursor += strlen($pre) + strlen($hit);
+ $buffer .= $pre;
+ $buffer .= "$hit";
+
+ }
+
+ }
+
+ #
+ # add everything from the cursor to the end onto the buffer.
+ #
+
+ $buffer .= substr($text, $cursor);
+
+ return $buffer;
+ }
+
+ ####################################################################
+
+?>
diff --git a/app/Ninja/Mailers/ContactMailer.php b/app/Ninja/Mailers/ContactMailer.php
index 219f8104321d..5e75a81120ad 100644
--- a/app/Ninja/Mailers/ContactMailer.php
+++ b/app/Ninja/Mailers/ContactMailer.php
@@ -260,7 +260,8 @@ class ContactMailer extends Mailer
}
$str = str_replace(array_keys($variables), array_values($variables), $template);
-
+ $str = autolink($str, 100);
+
return $str;
}
}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index bf67c12498cc..74098a3966de 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -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) {
diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php
index 90c116502ba2..7a5147b0459e 100644
--- a/app/Services/PaymentService.php
+++ b/app/Services/PaymentService.php
@@ -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;
diff --git a/composer.json b/composer.json
index a7417f9deaf3..b5bd763f6cdc 100644
--- a/composer.json
+++ b/composer.json
@@ -86,7 +86,10 @@
],
"psr-4": {
"App\\": "app/"
- }
+ },
+ "files": [
+ "app/Libraries/lib_autolink.php"
+ ]
},
"autoload-dev": {
"classmap": [
diff --git a/database/seeds/PaymentLibrariesSeeder.php b/database/seeds/PaymentLibrariesSeeder.php
index 8a3907473d65..e89f5ef21711 100644
--- a/database/seeds/PaymentLibrariesSeeder.php
+++ b/database/seeds/PaymentLibrariesSeeder.php
@@ -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' => '.'],
diff --git a/readme.md b/readme.md
index d710247c5959..ab29279e83e8 100644
--- a/readme.md
+++ b/readme.md
@@ -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.
-
[](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### Referral Program
diff --git a/resources/views/emails/partials/account_logo.blade.php b/resources/views/emails/partials/account_logo.blade.php
index c16e142fd5c1..98c418bcc061 100644
--- a/resources/views/emails/partials/account_logo.blade.php
+++ b/resources/views/emails/partials/account_logo.blade.php
@@ -3,7 +3,7 @@
@endif
-
+
@if ($account->website)
diff --git a/resources/views/invoices/view.blade.php b/resources/views/invoices/view.blade.php
index 6b27fbf7fe0b..04ad660ae1ba 100644
--- a/resources/views/invoices/view.blade.php
+++ b/resources/views/invoices/view.blade.php
@@ -21,24 +21,28 @@
-
+
diff --git a/resources/views/partials/checkout_com_payment.blade.php b/resources/views/partials/checkout_com_payment.blade.php new file mode 100644 index 000000000000..9e5e63baae50 --- /dev/null +++ b/resources/views/partials/checkout_com_payment.blade.php @@ -0,0 +1,22 @@ + + + \ No newline at end of file diff --git a/tests/acceptance/TaxRatesCest.php b/tests/acceptance/TaxRatesCest.php new file mode 100644 index 000000000000..5793b2f12038 --- /dev/null +++ b/tests/acceptance/TaxRatesCest.php @@ -0,0 +1,103 @@ +/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"); + + } + */ +} \ No newline at end of file