mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-12 06:02:39 +01:00
commit
c450ccc4bd
@ -1 +1 @@
|
||||
5.3.27
|
||||
5.3.29
|
@ -52,6 +52,8 @@ class Handler extends ExceptionHandler
|
||||
MaxAttemptsExceededException::class,
|
||||
CommandNotFoundException::class,
|
||||
ValidationException::class,
|
||||
ModelNotFoundException::class,
|
||||
NotFoundHttpException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -15,6 +15,7 @@ use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
|
||||
use App\Models\Activity;
|
||||
use App\Transformers\ActivityTransformer;
|
||||
use App\Utils\HostedPDF\NinjaPdf;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\PhantomJS\Phantom;
|
||||
use App\Utils\Traits\Pdf\PdfMaker;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@ -147,7 +148,12 @@ class ActivityController extends BaseController
|
||||
*/
|
||||
|
||||
if($backup && $backup->filename && Storage::disk(config('filesystems.default'))->exists($backup->filename)){ //disk
|
||||
$html_backup = file_get_contents(Storage::disk(config('filesystems.default'))->path($backup->filename));
|
||||
|
||||
if(Ninja::isHosted())
|
||||
$html_backup = file_get_contents(Storage::disk(config('filesystems.default'))->url($backup->filename));
|
||||
else
|
||||
$html_backup = file_get_contents(Storage::disk(config('filesystems.default'))->path($backup->filename));
|
||||
|
||||
}
|
||||
elseif($backup && $backup->html_backup){ //db
|
||||
$html_backup = $backup->html_backup;
|
||||
|
@ -41,7 +41,16 @@ class ContactLoginController extends Controller
|
||||
// $company = null;
|
||||
// }else
|
||||
|
||||
if (strpos($request->getHost(), 'invoicing.co') !== false) {
|
||||
$company = false;
|
||||
|
||||
if($request->has('company_key')){
|
||||
MultiDB::findAndSetDbByCompanyKey($request->input('company_key'));
|
||||
|
||||
$company = Company::where('company_key', $request->input('company_key'))->first();
|
||||
|
||||
}
|
||||
|
||||
if (!$company && strpos($request->getHost(), 'invoicing.co') !== false) {
|
||||
$subdomain = explode('.', $request->getHost())[0];
|
||||
|
||||
MultiDB::findAndSetDbByDomain(['subdomain' => $subdomain]);
|
||||
@ -72,8 +81,8 @@ class ContactLoginController extends Controller
|
||||
{
|
||||
Auth::shouldUse('contact');
|
||||
|
||||
if(Ninja::isHosted() && $request->has('db'))
|
||||
MultiDB::setDb($request->input('db'));
|
||||
if(Ninja::isHosted() && $request->has('company_key'))
|
||||
MultiDB::findAndSetDbByCompanyKey($request->input('company_key'));
|
||||
|
||||
$this->validateLogin($request);
|
||||
// If the class is using the ThrottlesLogins trait, we can automatically throttle
|
||||
|
@ -27,7 +27,7 @@ class SwitchCompanyController extends Controller
|
||||
->where('id', $this->transformKeys($contact))
|
||||
->first();
|
||||
|
||||
auth()->guard('contact')->user()->login($client_contact, true);
|
||||
auth()->guard('contact')->login($client_contact, true);
|
||||
|
||||
return redirect('/client/dashboard');
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ class CompanyController extends BaseController
|
||||
/*
|
||||
* Create token
|
||||
*/
|
||||
$user_agent = request()->input('token_name') ?: request()->server('HTTP_USER_AGENT');
|
||||
$user_agent = request()->has('token_name') ? request()->input('token_name') : request()->server('HTTP_USER_AGENT');
|
||||
|
||||
$company_token = CreateCompanyToken::dispatchNow($company, auth()->user(), $user_agent);
|
||||
|
||||
|
@ -683,8 +683,6 @@ class PaymentController extends BaseController
|
||||
{
|
||||
$payment = $request->payment();
|
||||
|
||||
// nlog($request->all());
|
||||
|
||||
$payment = $payment->refund($request->all());
|
||||
|
||||
return $this->itemResponse($payment);
|
||||
|
@ -42,6 +42,9 @@ class StoreRecurringExpenseRequest extends Request
|
||||
$rules['client_id'] = 'bail|sometimes|exists:clients,id,company_id,'.auth()->user()->company()->id;
|
||||
|
||||
$rules['frequency_id'] = 'required|integer|digits_between:1,12';
|
||||
$rules['tax_amount1'] = 'numeric';
|
||||
$rules['tax_amount2'] = 'numeric';
|
||||
$rules['tax_amount3'] = 'numeric';
|
||||
|
||||
return $this->globalRules($rules);
|
||||
}
|
||||
|
@ -43,6 +43,10 @@ class UpdateRecurringExpenseRequest extends Request
|
||||
$rules['number'] = Rule::unique('recurring_expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->recurring_expense->id);
|
||||
}
|
||||
|
||||
$rules['tax_amount1'] = 'numeric';
|
||||
$rules['tax_amount2'] = 'numeric';
|
||||
$rules['tax_amount3'] = 'numeric';
|
||||
|
||||
return $this->globalRules($rules);
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,10 @@ class UpdateTaskStatusRequest extends Request
|
||||
{
|
||||
$rules = [];
|
||||
|
||||
if ($this->input('name')) {
|
||||
$rules['name'] = Rule::unique('task_statuses')->where('company_id', auth()->user()->company()->id)->ignore($this->task_status->id);
|
||||
}
|
||||
// 26/10/2021 we disable this as it prevent updating existing task status meta data where the same name already exists
|
||||
// if ($this->input('name')) {
|
||||
// $rules['name'] = Rule::unique('task_statuses')->where('company_id', auth()->user()->company()->id)->ignore($this->task_status->id);
|
||||
// }
|
||||
|
||||
|
||||
return $rules;
|
||||
|
@ -51,7 +51,7 @@ class PaymentAppliedValidAmount implements Rule
|
||||
$payment_amounts = 0;
|
||||
$invoice_amounts = 0;
|
||||
|
||||
$payment_amounts = $payment->amount - $payment->applied;
|
||||
$payment_amounts = $payment->amount - $payment->refunded - $payment->applied;
|
||||
|
||||
if (request()->input('credits') && is_array(request()->input('credits'))) {
|
||||
foreach (request()->input('credits') as $credit) {
|
||||
|
@ -26,7 +26,10 @@ class ValidAmount implements Rule
|
||||
*/
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
return trim($value, '-1234567890.,') === '';
|
||||
return is_numeric((string)$value);
|
||||
//return filter_var((string)$value, FILTER_VALIDATE_FLOAT);
|
||||
// return preg_match('^(?=.)([+-]?([0-9]*)(\.([0-9]+))?)$^', (string)$value);
|
||||
// return trim($value, '-1234567890.,') === '';
|
||||
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ class RecurringInvoicesCron
|
||||
SendRecurring::dispatchNow($recurring_invoice, $recurring_invoice->company->db);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog("Unable to sending recurring invoice {$recurring_invoice->id}");
|
||||
nlog("Unable to sending recurring invoice {$recurring_invoice->id} ". $e->getMessage());
|
||||
}
|
||||
|
||||
});
|
||||
@ -107,7 +107,7 @@ class RecurringInvoicesCron
|
||||
SendRecurring::dispatchNow($recurring_invoice, $recurring_invoice->company->db);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog("Unable to sending recurring invoice {$recurring_invoice->id}");
|
||||
nlog("Unable to sending recurring invoice {$recurring_invoice->id} ". $e->getMessage());
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -15,6 +15,7 @@ use App\Jobs\Mail\NinjaMailer;
|
||||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Mail\Admin\ClientPaymentFailureObject;
|
||||
use App\Mail\Admin\EntityNotificationMailer;
|
||||
use App\Mail\Admin\PaymentFailureObject;
|
||||
use App\Models\Client;
|
||||
@ -102,6 +103,24 @@ class PaymentFailedMailer implements ShouldQueue
|
||||
});
|
||||
|
||||
//add client payment failures here.
|
||||
nlog("pre client failure email");
|
||||
|
||||
if($contact = $this->client->primary_contact()->first())
|
||||
{
|
||||
|
||||
nlog("inside failure");
|
||||
|
||||
$mail_obj = (new ClientPaymentFailureObject($this->client, $this->error, $this->company, $this->payment_hash))->build();
|
||||
|
||||
$nmo = new NinjaMailerObject;
|
||||
$nmo->mailable = new NinjaMailer($mail_obj);
|
||||
$nmo->company = $this->company;
|
||||
$nmo->to_user = $contact;
|
||||
$nmo->settings = $settings;
|
||||
|
||||
NinjaMailerJob::dispatch($nmo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,13 +73,14 @@ class SendRecurring implements ShouldQueue
|
||||
$invoice->date = now()->format('Y-m-d');
|
||||
$invoice->due_date = $this->recurring_invoice->calculateDueDate(now()->format('Y-m-d'));
|
||||
$invoice->recurring_id = $this->recurring_invoice->id;
|
||||
$invoice->saveQuietly();
|
||||
|
||||
if($invoice->client->getSetting('auto_email_invoice'))
|
||||
{
|
||||
$invoice = $invoice->service()
|
||||
->markSent()
|
||||
->applyNumber()
|
||||
// ->createInvitations() //need to only link invitations to those in the recurring invoice
|
||||
//->createInvitations() //need to only link invitations to those in the recurring invoice
|
||||
->fillDefaults()
|
||||
->save();
|
||||
|
||||
|
@ -14,7 +14,6 @@ namespace App\Mail\Admin;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Number;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use stdClass;
|
||||
@ -91,7 +90,7 @@ class ClientPaymentFailureObject
|
||||
return
|
||||
ctrans(
|
||||
'texts.notification_invoice_payment_failed_subject',
|
||||
['invoice' => $this->client->present()->name()]
|
||||
['invoice' => implode(",", $this->invoices->pluck('number')->toArray())]
|
||||
);
|
||||
|
||||
}
|
||||
@ -110,7 +109,7 @@ class ClientPaymentFailureObject
|
||||
]
|
||||
),
|
||||
'greeting' => ctrans('texts.email_salutation', ['name' => $this->client->present()->name]),
|
||||
'message' => $this->error,
|
||||
'message' => ctrans('texts.client_payment_failure_body', ['invoice' => implode(",", $this->invoices->pluck('number')->toArray()), 'amount' => $this->getAmount()]),
|
||||
'signature' => $signature,
|
||||
'logo' => $this->company->present()->logo(),
|
||||
'settings' => $this->client->getMergedSettings(),
|
||||
|
@ -92,7 +92,7 @@ class ClientContact extends Authenticatable implements HasLocalePreference
|
||||
'custom_value4',
|
||||
'email',
|
||||
'is_primary',
|
||||
// 'client_id',
|
||||
'send_email',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -145,7 +145,9 @@ class Gateway extends StaticModel
|
||||
GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||
GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||
GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||
GatewayType::BECS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||
GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||
GatewayType::ACSS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||
];
|
||||
break;
|
||||
case 57:
|
||||
|
@ -84,7 +84,7 @@ class GatewayType extends StaticModel
|
||||
case self::EPS:
|
||||
return ctrans('texts.eps');
|
||||
case self::BECS:
|
||||
return ctrans('tets.becs');
|
||||
return ctrans('texts.becs');
|
||||
case self::ACSS:
|
||||
return ctrans('texts.acss');
|
||||
case self::DIRECT_DEBIT:
|
||||
|
@ -221,6 +221,19 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
{
|
||||
$this->confirmGatewayFee();
|
||||
|
||||
/*Never create a payment with a duplicate transaction reference*/
|
||||
if(array_key_exists('transaction_reference', $data)){
|
||||
|
||||
$_payment = Payment::where('transaction_reference', $data['transaction_reference'])
|
||||
->where('client_id', $this->client->id)
|
||||
->first();
|
||||
|
||||
if($_payment)
|
||||
return $_payment;
|
||||
|
||||
}
|
||||
|
||||
|
||||
$payment = PaymentFactory::create($this->client->company->id, $this->client->user->id);
|
||||
$payment->client_id = $this->client->id;
|
||||
$payment->company_gateway_id = $this->company_gateway->id;
|
||||
|
@ -13,7 +13,6 @@ namespace App\PaymentDrivers\Braintree;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
@ -23,6 +22,7 @@ use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\BraintreePaymentDriver;
|
||||
use App\PaymentDrivers\Common\MethodInterface;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ACH implements MethodInterface
|
||||
{
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
@ -27,7 +25,6 @@ use App\PaymentDrivers\Braintree\CreditCard;
|
||||
use App\PaymentDrivers\Braintree\PayPal;
|
||||
use Braintree\Gateway;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BraintreePaymentDriver extends BaseDriver
|
||||
{
|
||||
@ -40,7 +37,7 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
/**
|
||||
* @var Gateway;
|
||||
*/
|
||||
public $gateway;
|
||||
public Gateway $gateway;
|
||||
|
||||
public static $methods = [
|
||||
GatewayType::CREDIT_CARD => CreditCard::class,
|
||||
@ -118,8 +115,7 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
]);
|
||||
|
||||
if ($result->success) {
|
||||
|
||||
$address = $this->gateway->address()->create([
|
||||
$address = $this->gateway->address()->create([
|
||||
'customerId' => $result->customer->id,
|
||||
'firstName' => $this->client->present()->name,
|
||||
'streetAddress' => $this->client->address1,
|
||||
@ -135,12 +131,9 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
{
|
||||
$this->init();
|
||||
|
||||
try{
|
||||
|
||||
try {
|
||||
$response = $this->gateway->transaction()->refund($payment->transaction_reference, $amount);
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
||||
$data = [
|
||||
'transaction_reference' => null,
|
||||
'transaction_response' => json_encode($e->getMessage()),
|
||||
@ -154,24 +147,19 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
return $data;
|
||||
}
|
||||
|
||||
if($response->success)
|
||||
{
|
||||
|
||||
if ($response->success) {
|
||||
$data = [
|
||||
'transaction_reference' => $response->id,
|
||||
'transaction_reference' => $payment->transaction_reference,
|
||||
'transaction_response' => json_encode($response),
|
||||
'success' => (bool)$response->success,
|
||||
'description' => $response->status,
|
||||
'success' => (bool) $response->success,
|
||||
'description' => ctrans('texts.plan_refunded'),
|
||||
'code' => 0,
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(['server_response' => $response, 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_BRAINTREE, $this->client, $this->client->company);
|
||||
|
||||
return $data;
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
} else {
|
||||
$error = $response->errors->deepAll()[0];
|
||||
|
||||
$data = [
|
||||
@ -185,7 +173,6 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
SystemLogger::dispatch(['server_response' => $response, 'data' => $data], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_BRAINTREE, $this->client, $this->client->company);
|
||||
|
||||
return $data;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace App\PaymentDrivers\CheckoutCom;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\PaymentDrivers\CheckoutComPaymentDriver;
|
||||
@ -112,7 +112,7 @@ class CreditCard implements MethodInterface
|
||||
$data['currency'] = $this->checkout->client->getCurrencyCode();
|
||||
$data['value'] = $this->checkout->convertToCheckoutAmount($data['total']['amount_with_fee'], $this->checkout->client->getCurrencyCode());
|
||||
$data['raw_value'] = $data['total']['amount_with_fee'];
|
||||
$data['customer_email'] = $this->checkout->client->present()->email;
|
||||
$data['customer_email'] = $this->checkout->client->present()->email();
|
||||
|
||||
return render('gateways.checkout.credit_card.pay', $data);
|
||||
}
|
||||
@ -173,6 +173,10 @@ class CreditCard implements MethodInterface
|
||||
$payment = new Payment($method, $this->checkout->payment_hash->data->currency);
|
||||
$payment->amount = $this->checkout->payment_hash->data->value;
|
||||
$payment->reference = $this->checkout->getDescription();
|
||||
$payment->customer = [
|
||||
'name' => $this->checkout->client->present()->name() ,
|
||||
'email' => $this->checkout->client->present()->email(),
|
||||
];
|
||||
|
||||
$this->checkout->payment_hash->data = array_merge((array)$this->checkout->payment_hash->data, ['checkout_payment_ref' => $payment]);
|
||||
$this->checkout->payment_hash->save();
|
||||
|
@ -84,8 +84,7 @@ trait Utilities
|
||||
|
||||
public function processUnsuccessfulPayment(Payment $_payment, $throw_exception = true)
|
||||
{
|
||||
|
||||
$this->getParent()->sendFailureMail($_payment->status . " " . $_payment->response_summary);
|
||||
$this->getParent()->sendFailureMail($_payment->status . " " . optional($_payment)->response_summary);
|
||||
|
||||
$message = [
|
||||
'server_response' => $_payment,
|
||||
@ -102,7 +101,7 @@ trait Utilities
|
||||
);
|
||||
|
||||
if ($throw_exception) {
|
||||
throw new PaymentFailed($_payment->status . " " . $_payment->response_summary, $_payment->http_code);
|
||||
throw new PaymentFailed($_payment->status . " " . optional($_payment)->response_summary, $_payment->http_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +338,9 @@ class CheckoutComPaymentDriver extends BaseDriver
|
||||
$this->setPaymentHash($request->getPaymentHash());
|
||||
|
||||
try {
|
||||
$payment = $this->gateway->payments()->details($request->query('cko-session-id'));
|
||||
$payment = $this->gateway->payments()->details(
|
||||
$request->query('cko-session-id')
|
||||
);
|
||||
|
||||
if ($payment->approved) {
|
||||
return $this->processSuccessfulPayment($payment);
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace App\PaymentDrivers\Common;
|
||||
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
interface MethodInterface
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace App\PaymentDrivers\GoCardless;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
|
@ -14,7 +14,7 @@ namespace App\PaymentDrivers\GoCardless;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
|
@ -14,7 +14,7 @@ namespace App\PaymentDrivers\GoCardless;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
|
@ -13,7 +13,7 @@
|
||||
namespace App\PaymentDrivers\Mollie;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
|
@ -14,7 +14,7 @@ namespace App\PaymentDrivers\Mollie;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
|
@ -14,7 +14,7 @@ namespace App\PaymentDrivers\Mollie;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
|
@ -13,7 +13,7 @@
|
||||
namespace App\PaymentDrivers\Mollie;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
|
@ -93,7 +93,7 @@ class PayPalExpressPaymentDriver extends BaseDriver
|
||||
return $response->redirect();
|
||||
}
|
||||
|
||||
$this->sendFailureMail($response->getData());
|
||||
$this->sendFailureMail($response->getMessage());
|
||||
|
||||
$message = [
|
||||
'server_response' => $response->getMessage(),
|
||||
|
@ -15,7 +15,7 @@ namespace App\PaymentDrivers\Razorpay;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
|
@ -13,16 +13,20 @@
|
||||
namespace App\PaymentDrivers\Square;
|
||||
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentType;
|
||||
use App\PaymentDrivers\Common\MethodInterface;
|
||||
use App\PaymentDrivers\SquarePaymentDriver;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\View;
|
||||
use Square\Http\ApiResponse;
|
||||
|
||||
class CreditCard
|
||||
class CreditCard implements MethodInterface
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
@ -34,90 +38,27 @@ class CreditCard
|
||||
$this->square_driver->init();
|
||||
}
|
||||
|
||||
public function authorizeView($data)
|
||||
/**
|
||||
* Authorization page for credit card.
|
||||
*
|
||||
* @param array $data
|
||||
* @return View
|
||||
*/
|
||||
public function authorizeView($data): View
|
||||
{
|
||||
$data['gateway'] = $this->square_driver;
|
||||
|
||||
return render('gateways.square.credit_card.authorize', $data);
|
||||
}
|
||||
|
||||
public function authorizeResponse($request)
|
||||
/**
|
||||
* Handle authorization for credit card.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function authorizeResponse($request): RedirectResponse
|
||||
{
|
||||
/* Step one - process a $1 payment - but don't complete it*/
|
||||
$payment = false;
|
||||
|
||||
$amount_money = new \Square\Models\Money();
|
||||
$amount_money->setAmount(100); //amount in cents
|
||||
$amount_money->setCurrency($this->square_driver->client->currency()->code);
|
||||
|
||||
$body = new \Square\Models\CreatePaymentRequest(
|
||||
$request->sourceId,
|
||||
Str::random(32),
|
||||
$amount_money
|
||||
);
|
||||
|
||||
$body->setAutocomplete(false);
|
||||
$body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId'));
|
||||
$body->setReferenceId(Str::random(16));
|
||||
|
||||
$api_response = $this->square_driver->square->getPaymentsApi()->createPayment($body);
|
||||
|
||||
if ($api_response->isSuccess()) {
|
||||
$result = $api_response->getBody();
|
||||
$payment = json_decode($result);
|
||||
} else {
|
||||
$errors = $api_response->getErrors();
|
||||
return $this->processUnsuccessfulPayment($errors);
|
||||
}
|
||||
|
||||
|
||||
/* Step 3 create the card */
|
||||
$card = new \Square\Models\Card();
|
||||
$card->setCardholderName($this->square_driver->client->present()->name());
|
||||
// $card->setBillingAddress($billing_address);
|
||||
$card->setCustomerId($this->findOrCreateClient());
|
||||
$card->setReferenceId(Str::random(8));
|
||||
|
||||
$body = new \Square\Models\CreateCardRequest(
|
||||
Str::random(32),
|
||||
$payment->payment->id,
|
||||
$card
|
||||
);
|
||||
|
||||
$api_response = $this->square_driver
|
||||
->square
|
||||
->getCardsApi()
|
||||
->createCard($body);
|
||||
|
||||
$card = false;
|
||||
|
||||
if ($api_response->isSuccess()) {
|
||||
$card = $api_response->getBody();
|
||||
$card = json_decode($card);
|
||||
} else {
|
||||
$errors = $api_response->getErrors();
|
||||
|
||||
return $this->processUnsuccessfulPayment($errors);
|
||||
}
|
||||
|
||||
/* Create the token in Invoice Ninja*/
|
||||
$cgt = [];
|
||||
$cgt['token'] = $card->card->id;
|
||||
$cgt['payment_method_id'] = GatewayType::CREDIT_CARD;
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->exp_month = $card->card->exp_month;
|
||||
$payment_meta->exp_year = $card->card->exp_year;
|
||||
$payment_meta->brand = $card->card->card_brand;
|
||||
$payment_meta->last4 = $card->card->last_4;
|
||||
$payment_meta->type = GatewayType::CREDIT_CARD;
|
||||
|
||||
$cgt['payment_meta'] = $payment_meta;
|
||||
|
||||
$token = $this->square_driver->storeGatewayToken($cgt, [
|
||||
'gateway_customer_reference' => $this->findOrCreateClient(),
|
||||
]);
|
||||
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
|
||||
@ -170,8 +111,9 @@ class CreditCard
|
||||
$body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId'));
|
||||
$body->setReferenceId(Str::random(16));
|
||||
|
||||
if($request->has('verificationToken') && $request->input('verificationToken'))
|
||||
if ($request->has('verificationToken') && $request->input('verificationToken')) {
|
||||
$body->setVerificationToken($request->input('verificationToken'));
|
||||
}
|
||||
|
||||
if ($request->shouldUseToken()) {
|
||||
$body->setCustomerId($cgt->gateway_customer_reference);
|
||||
@ -181,66 +123,12 @@ class CreditCard
|
||||
$response = $this->square_driver->square->getPaymentsApi()->createPayment($body);
|
||||
|
||||
if ($response->isSuccess()) {
|
||||
if ($request->shouldStoreToken()) {
|
||||
$this->storePaymentMethod($response);
|
||||
}
|
||||
|
||||
return $this->processSuccessfulPayment($response);
|
||||
}
|
||||
|
||||
return $this->processUnsuccessfulPayment($response);
|
||||
}
|
||||
|
||||
private function storePaymentMethod(ApiResponse $response)
|
||||
{
|
||||
$payment = \json_decode($response->getBody());
|
||||
|
||||
$billing_address = new \Square\Models\Address();
|
||||
$billing_address->setAddressLine1($this->square_driver->client->address1);
|
||||
$billing_address->setAddressLine2($this->square_driver->client->address2);
|
||||
$billing_address->setLocality($this->square_driver->client->city);
|
||||
$billing_address->setAdministrativeDistrictLevel1($this->square_driver->client->state);
|
||||
$billing_address->setPostalCode($this->square_driver->client->postal_code);
|
||||
$billing_address->setCountry($this->square_driver->client->country->iso_3166_2);
|
||||
|
||||
$card = new \Square\Models\Card();
|
||||
$card->setCardholderName($this->square_driver->client->present()->first_name(). " " .$this->square_driver->client->present()->last_name());
|
||||
$card->setCustomerId($this->findOrCreateClient());
|
||||
$card->setReferenceId(Str::random(8));
|
||||
$card->setBillingAddress($billing_address);
|
||||
|
||||
$body = new \Square\Models\CreateCardRequest(Str::random(32), $payment->payment->id, $card);
|
||||
|
||||
/** @var ApiResponse */
|
||||
$api_response = $this->square_driver
|
||||
->square
|
||||
->getCardsApi()
|
||||
->createCard($body);
|
||||
|
||||
if (!$api_response->isSuccess()) {
|
||||
return $this->processUnsuccessfulPayment($api_response);
|
||||
}
|
||||
|
||||
$card = \json_decode($api_response->getBody());
|
||||
|
||||
$cgt = [];
|
||||
$cgt['token'] = $card->card->id;
|
||||
$cgt['payment_method_id'] = GatewayType::CREDIT_CARD;
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->exp_month = $card->card->exp_month;
|
||||
$payment_meta->exp_year = $card->card->exp_year;
|
||||
$payment_meta->brand = $card->card->card_brand;
|
||||
$payment_meta->last4 = $card->card->last_4;
|
||||
$payment_meta->type = GatewayType::CREDIT_CARD;
|
||||
|
||||
$cgt['payment_meta'] = $payment_meta;
|
||||
|
||||
$this->square_driver->storeGatewayToken($cgt, [
|
||||
'gateway_customer_reference' => $this->findOrCreateClient(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function processSuccessfulPayment(ApiResponse $response)
|
||||
{
|
||||
$body = json_decode($response->getBody());
|
||||
@ -301,9 +189,9 @@ class CreditCard
|
||||
$customers = $api_response->getBody();
|
||||
$customers = json_decode($customers);
|
||||
|
||||
if(count(array($api_response->getBody(),1)) == 0)
|
||||
if (count([$api_response->getBody(),1]) == 0) {
|
||||
$customers = false;
|
||||
|
||||
}
|
||||
} else {
|
||||
$errors = $api_response->getErrors();
|
||||
}
|
||||
|
@ -141,8 +141,8 @@ class BECS
|
||||
$method = $this->stripe->getStripePaymentMethod($intent->payment_method);
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->brand = (string) \sprintf('%s (%s)', $method->sepa_debit->bank_code, ctrans('texts.becs'));
|
||||
$payment_meta->last4 = (string) $method->sepa_debit->last4;
|
||||
$payment_meta->brand = (string) \sprintf('%s (%s)', $method->au_becs_debit->bank_code, ctrans('texts.becs'));
|
||||
$payment_meta->last4 = (string) $method->au_becs_debit->last4;
|
||||
$payment_meta->state = 'authorized';
|
||||
$payment_meta->type = GatewayType::BECS;
|
||||
|
||||
|
@ -208,7 +208,7 @@ class StripePaymentDriver extends BaseDriver
|
||||
&& $this->client->currency()
|
||||
&& ($this->client->currency()->code == 'AUD')
|
||||
&& isset($this->client->country)
|
||||
&& in_array($this->client->country->iso_3166_3, ["AUS", "DEU"]))
|
||||
&& in_array($this->client->country->iso_3166_3, ['AUS']))
|
||||
$types[] = GatewayType::BECS;
|
||||
|
||||
if ($this->client
|
||||
|
@ -185,7 +185,7 @@ class WePayPaymentDriver extends BaseDriver
|
||||
}
|
||||
|
||||
if (! isset($objectType)) {
|
||||
throw new Exception('Could not find object id parameter');
|
||||
throw new \Exception('Could not find object id parameter');
|
||||
}
|
||||
|
||||
if ($objectType == 'credit_card') {
|
||||
|
@ -113,25 +113,26 @@ class BaseRepository
|
||||
* @param $action
|
||||
*
|
||||
* @return int
|
||||
* @deprecated - this doesn't appear to be used anywhere?
|
||||
*/
|
||||
public function bulk($ids, $action)
|
||||
{
|
||||
if (! $ids) {
|
||||
return 0;
|
||||
}
|
||||
// public function bulk($ids, $action)
|
||||
// {
|
||||
// if (! $ids) {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
$ids = $this->transformKeys($ids);
|
||||
// $ids = $this->transformKeys($ids);
|
||||
|
||||
$entities = $this->findByPublicIdsWithTrashed($ids);
|
||||
// $entities = $this->findByPublicIdsWithTrashed($ids);
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
if (auth()->user()->can('edit', $entity)) {
|
||||
$this->$action($entity);
|
||||
}
|
||||
}
|
||||
// foreach ($entities as $entity) {
|
||||
// if (auth()->user()->can('edit', $entity)) {
|
||||
// $this->$action($entity);
|
||||
// }
|
||||
// }
|
||||
|
||||
return count($entities);
|
||||
}
|
||||
// return count($entities);
|
||||
// }
|
||||
|
||||
/* Returns an invoice if defined as a key in the $resource array*/
|
||||
public function getInvitation($invitation, $resource)
|
||||
|
@ -65,7 +65,7 @@ class ClientRepository extends BaseRepository
|
||||
$client->fill($data);
|
||||
$client->save();
|
||||
|
||||
if (!isset($client->number) || empty($client->number)) {
|
||||
if (!isset($client->number) || empty($client->number) || strlen($client->number) == 0) {
|
||||
$client->number = $this->getNextClientNumber($client);
|
||||
}
|
||||
|
||||
|
@ -134,9 +134,9 @@ class InvoiceService
|
||||
*
|
||||
* @return InvoiceService Parent class object
|
||||
*/
|
||||
public function updateBalance($balance_adjustment)
|
||||
public function updateBalance($balance_adjustment, bool $is_draft = false)
|
||||
{
|
||||
$this->invoice = (new UpdateBalance($this->invoice, $balance_adjustment))->run();
|
||||
$this->invoice = (new UpdateBalance($this->invoice, $balance_adjustment, $is_draft))->run();
|
||||
|
||||
if ((int)$this->invoice->balance == 0) {
|
||||
$this->invoice->next_send_date = null;
|
||||
@ -339,6 +339,10 @@ class InvoiceService
|
||||
|
||||
public function removeUnpaidGatewayFees()
|
||||
{
|
||||
//return early if type three does not exist.
|
||||
if(!collect($this->invoice->line_items)->contains('type_id', 3))
|
||||
return $this;
|
||||
|
||||
$this->invoice->line_items = collect($this->invoice->line_items)
|
||||
->reject(function ($item) {
|
||||
return $item->type_id == '3';
|
||||
|
@ -33,7 +33,7 @@ class MarkSent extends AbstractService
|
||||
{
|
||||
|
||||
/* Return immediately if status is not draft */
|
||||
if ($this->invoice->fresh()->status_id != Invoice::STATUS_DRAFT) {
|
||||
if ($this->invoice && $this->invoice->fresh()->status_id != Invoice::STATUS_DRAFT) {
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ class MarkSent extends AbstractService
|
||||
->service()
|
||||
->applyNumber()
|
||||
->setDueDate()
|
||||
->updateBalance($this->invoice->amount)
|
||||
->updateBalance($this->invoice->amount, true)
|
||||
->deletePdf()
|
||||
->setReminder()
|
||||
->save();
|
||||
|
@ -20,10 +20,13 @@ class UpdateBalance extends AbstractService
|
||||
|
||||
public $balance_adjustment;
|
||||
|
||||
public function __construct($invoice, $balance_adjustment)
|
||||
private $is_draft;
|
||||
|
||||
public function __construct($invoice, $balance_adjustment, bool $is_draft)
|
||||
{
|
||||
$this->invoice = $invoice;
|
||||
$this->balance_adjustment = $balance_adjustment;
|
||||
$this->is_draft = $is_draft;
|
||||
}
|
||||
|
||||
public function run()
|
||||
@ -34,7 +37,7 @@ class UpdateBalance extends AbstractService
|
||||
|
||||
$this->invoice->balance += floatval($this->balance_adjustment);
|
||||
|
||||
if ($this->invoice->balance == 0) {
|
||||
if ($this->invoice->balance == 0 && !$this->is_draft) {
|
||||
$this->invoice->status_id = Invoice::STATUS_PAID;
|
||||
}
|
||||
|
||||
|
@ -115,15 +115,22 @@ class DeletePayment
|
||||
->updatePaidToDate($net_deletable * -1)
|
||||
->save();
|
||||
|
||||
// $paymentable_invoice->client
|
||||
// ->service()
|
||||
// ->updatePaidToDate($net_deletable * -1)
|
||||
// ->save();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
||||
/* If there are no invoices - then we need to still adjust the total client->paid_to_date amount*/
|
||||
|
||||
$this->payment
|
||||
->client
|
||||
->service()
|
||||
->updatePaidToDate(($this->payment->amount - $this->payment->applied)*-1)
|
||||
->save();
|
||||
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -267,9 +267,17 @@ class RefundPayment
|
||||
// $this->credit_note->ledger()->updateCreditBalance($adjustment_amount, $ledger_string);
|
||||
|
||||
$client = $this->payment->client->fresh();
|
||||
//$client->service()->updatePaidToDate(-1 * $this->total_refund)->save();
|
||||
|
||||
$client->service()->updatePaidToDate(-1 * $refunded_invoice['amount'])->save();
|
||||
}
|
||||
else{
|
||||
//if we are refunding and no payments have been tagged, then we need to decrement the client->paid_to_date by the total refund amount.
|
||||
|
||||
$client = $this->payment->client->fresh();
|
||||
|
||||
$client->service()->updatePaidToDate(-1 * $this->total_refund)->save();
|
||||
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.3.27',
|
||||
'app_tag' => '5.3.27',
|
||||
'app_version' => '5.3.29',
|
||||
'app_tag' => '5.3.29',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=019831a9b0c0aff43c7f",
|
||||
"/css/app.css": "/css/app.css?id=df1ea83ea621533ac837",
|
||||
"/js/app.js": "/js/app.js?id=696e8203d5e8e7cf5ff5",
|
||||
"/css/app.css": "/css/app.css?id=f7f7b35aa3f417a3eca3",
|
||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=a09bb529b8e1826f13b4",
|
||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7",
|
||||
@ -17,7 +17,7 @@
|
||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=73b66e88e2daabcd6549",
|
||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=c2b5f7831e1a46dd5fb2",
|
||||
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=817ab3b2b94ee37b14eb",
|
||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=070c86b293b532c5a56c",
|
||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=13ea3ff41d9417ef0140",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=81c2623fc1e5769b51c7",
|
||||
"/js/clients/payments/stripe-acss.js": "/js/clients/payments/stripe-acss.js?id=4a85142c085723991d28",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=665ddf663500767f1a17",
|
||||
@ -36,6 +36,6 @@
|
||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=5c35d28cf0a3286e7c45",
|
||||
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=2a99d83305ba87bfa6cc",
|
||||
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=ca3ec4cea0de824f3a36",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=03ea88a737e59eb2bd5a",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=8d454e7090f119552a6c",
|
||||
"/css/card-js.min.css": "/css/card-js.min.css?id=62afeb675235451543ad"
|
||||
}
|
||||
|
@ -43,57 +43,39 @@ class SquareCreditCard {
|
||||
}
|
||||
}
|
||||
|
||||
// ,
|
||||
// function(err,verification) {
|
||||
// if (err == null) {
|
||||
// console.log("no error");
|
||||
// console.log(verification);
|
||||
// verificationToken = verificationResults.token;
|
||||
|
||||
// }
|
||||
|
||||
// console.log(err);
|
||||
|
||||
// die("verify buyer");
|
||||
// }
|
||||
|
||||
|
||||
async completePaymentWithoutToken(e) {
|
||||
document.getElementById('errors').hidden = true;
|
||||
e.target.parentElement.disabled = true;
|
||||
|
||||
let result = await this.card.tokenize();
|
||||
|
||||
console.log("square token = " + result.token);
|
||||
|
||||
/* SCA */
|
||||
let verificationToken;
|
||||
let verificationToken;
|
||||
|
||||
try {
|
||||
const verificationDetails = {
|
||||
amount: document.querySelector('meta[name=amount]').content,
|
||||
billingContact: JSON.parse(document.querySelector('meta[name=square_contact]').content),
|
||||
currencyCode: document.querySelector('meta[name=currencyCode]').content,
|
||||
intent: 'CHARGE'
|
||||
};
|
||||
|
||||
console.log(verificationDetails);
|
||||
try {
|
||||
const verificationDetails = {
|
||||
amount: document.querySelector('meta[name=amount]').content,
|
||||
billingContact: JSON.parse(
|
||||
document.querySelector('meta[name=square_contact]').content
|
||||
),
|
||||
currencyCode: document.querySelector('meta[name=currencyCode]')
|
||||
.content,
|
||||
intent: 'CHARGE',
|
||||
};
|
||||
|
||||
const verificationResults = await this.payments.verifyBuyer(
|
||||
result.token,
|
||||
verificationDetails
|
||||
result.token,
|
||||
verificationDetails
|
||||
);
|
||||
|
||||
verificationToken = verificationResults.token;
|
||||
}
|
||||
catch(typeError){
|
||||
console.log(typeError);
|
||||
} catch (typeError) {
|
||||
e.target.parentElement.disabled = true
|
||||
}
|
||||
|
||||
console.debug('Verification Token:', verificationToken);
|
||||
|
||||
document.querySelector('input[name="verificationToken"]').value =
|
||||
verificationToken;
|
||||
document.querySelector(
|
||||
'input[name="verificationToken"]'
|
||||
).value = verificationToken;
|
||||
|
||||
if (result.status === 'OK') {
|
||||
document.getElementById('sourceId').value = result.token;
|
||||
@ -125,23 +107,20 @@ class SquareCreditCard {
|
||||
|
||||
/* SCA */
|
||||
async verifyBuyer(token) {
|
||||
|
||||
console.log("in verify buyer");
|
||||
|
||||
const verificationDetails = {
|
||||
amount: document.querySelector('meta[name=amount]').content,
|
||||
billingContact: document.querySelector('meta[name=square_contact]').content,
|
||||
currencyCode: document.querySelector('meta[name=currencyCode]').content,
|
||||
intent: 'CHARGE'
|
||||
amount: document.querySelector('meta[name=amount]').content,
|
||||
billingContact: document.querySelector('meta[name=square_contact]')
|
||||
.content,
|
||||
currencyCode: document.querySelector('meta[name=currencyCode]')
|
||||
.content,
|
||||
intent: 'CHARGE',
|
||||
};
|
||||
|
||||
const verificationResults = await this.payments.verifyBuyer(
|
||||
token,
|
||||
verificationDetails
|
||||
token,
|
||||
verificationDetails
|
||||
);
|
||||
|
||||
console.log(" verification toke = " + verificationResults.token);
|
||||
|
||||
return verificationResults.token;
|
||||
}
|
||||
|
||||
|
@ -1400,7 +1400,7 @@ $LANG = array(
|
||||
'more_options' => 'More options',
|
||||
'credit_card' => 'Credit Card',
|
||||
'bank_transfer' => 'Bank Transfer',
|
||||
'no_transaction_reference' => 'We did not recieve a payment transaction reference from the gateway.',
|
||||
'no_transaction_reference' => 'We did not receive a payment transaction reference from the gateway.',
|
||||
'use_bank_on_file' => 'Use Bank on File',
|
||||
'auto_bill_email_message' => 'This invoice will automatically be billed to the payment method on file on the due date.',
|
||||
'bitcoin' => 'Bitcoin',
|
||||
@ -4328,13 +4328,14 @@ $LANG = array(
|
||||
'giropay_law' => 'By entering your Customer information (such as name, sort code and account number) you (the Customer) agree that this information is given voluntarily.',
|
||||
'eps' => 'EPS',
|
||||
'becs' => 'BECS Direct Debit',
|
||||
'becs_mandate' => 'By providing your bank account details, you agree to this <a href="https://stripe.com/au-becs-dd-service-agreement/legal">Direct Debit Request and the Direct Debit Request service agreement</a>, and authorise Stripe Payments Australia Pty Ltd ACN 160 180 343 Direct Debit User ID number 507156 (“Stripe”) to debit your account through the Bulk Electronic Clearing System (BECS) on behalf of :company (the “Merchant”) for any amounts separately communicated to you by the Merchant. You certify that you are either an account holder or an authorised signatory on the account listed above.',
|
||||
'becs_mandate' => 'By providing your bank account details, you agree to this <a class="underline" href="https://stripe.com/au-becs-dd-service-agreement/legal">Direct Debit Request and the Direct Debit Request service agreement</a>, and authorise Stripe Payments Australia Pty Ltd ACN 160 180 343 Direct Debit User ID number 507156 (“Stripe”) to debit your account through the Bulk Electronic Clearing System (BECS) on behalf of :company (the “Merchant”) for any amounts separately communicated to you by the Merchant. You certify that you are either an account holder or an authorised signatory on the account listed above.',
|
||||
'you_need_to_accept_the_terms_before_proceeding' => 'You need to accept the terms before proceeding.',
|
||||
'direct_debit' => 'Direct Debit',
|
||||
'clone_to_expense' => 'Clone to expense',
|
||||
'checkout' => 'Checkout',
|
||||
'acss' => 'Pre-authorized debit payments',
|
||||
'invalid_amount' => 'Invalid amount. Number/Decimal values only.'
|
||||
'invalid_amount' => 'Invalid amount. Number/Decimal values only.',
|
||||
'client_payment_failure_body' => 'Payment for Invoice :invoice for amount :amount failed.',
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -1,37 +1,7 @@
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title'
|
||||
=> ctrans('texts.payment_type_credit_card')])
|
||||
|
||||
@section('gateway_head')
|
||||
<meta name="square-appId" content="{{ $gateway->company_gateway->getConfigField('applicationId') }}">
|
||||
<meta name="square-locationId" content="{{ $gateway->company_gateway->getConfigField('locationId') }}">
|
||||
<meta name="square-authorize" content="true">
|
||||
@endsection
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' => ctrans('texts.credit_card')])
|
||||
|
||||
@section('gateway_content')
|
||||
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::CREDIT_CARD]) }}"
|
||||
method="post" id="server_response">
|
||||
@csrf
|
||||
<input type="text" name="sourceId" id="sourceId" hidden>
|
||||
</form>
|
||||
|
||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element-single')
|
||||
<div id="card-container"></div>
|
||||
<div id="payment-status-container"></div>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.gateways.includes.pay_now', ['id' => 'authorize-card'])
|
||||
{{ ctrans('texts.add_payment_method') }}
|
||||
{{ __('texts.payment_method_cannot_be_preauthorized') }}
|
||||
@endcomponent
|
||||
@endsection
|
||||
|
||||
@section('gateway_footer')
|
||||
@if ($gateway->company_gateway->getConfigField('testMode'))
|
||||
<script type="text/javascript" src="https://sandbox.web.squarecdn.com/v1/square.js"></script>
|
||||
@else
|
||||
<script type="text/javascript" src="https://web.squarecdn.com/v1/square.js"></script>
|
||||
@endif
|
||||
|
||||
<script src="{{ asset('js/clients/payments/square-credit-card.js') }}"></script>
|
||||
@endsection
|
||||
|
@ -12,17 +12,20 @@
|
||||
<label for="becs-name">
|
||||
<input class="input w-full" id="becs-name" type="text" placeholder="{{ ctrans('texts.bank_account_holder') }}" required>
|
||||
</label>
|
||||
<label for="becs-email" >
|
||||
|
||||
<label for="becs-email">
|
||||
<input class="input w-full" id="becs-email-address" type="email" placeholder="{{ ctrans('texts.email') }}" required>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<div class="border p-4 rounded">
|
||||
<div class="border p-4 rounded mt-2">
|
||||
<div id="becs-iban"></div>
|
||||
</div>
|
||||
</label>
|
||||
<div id="mandate-acceptance">
|
||||
|
||||
<div id="mandate-acceptance" class="mt-2">
|
||||
<input type="checkbox" id="becs-mandate-acceptance" class="input mr-4">
|
||||
<label for="becs-mandate-acceptance">{{ctrans('texts.becs_mandat')}}</label>
|
||||
<label for="becs-mandate-acceptance">{!! ctrans('texts.becs_mandate') !!}</label>
|
||||
</div>
|
||||
</form>
|
||||
@endcomponent
|
||||
|
103
tests/Feature/Payments/UnappliedPaymentDeleteTest.php
Normal file
103
tests/Feature/Payments/UnappliedPaymentDeleteTest.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
namespace Tests\Feature\Payments;
|
||||
|
||||
|
||||
use App\Models\Payment;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\MockUnitData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class UnappliedPaymentDeleteTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use DatabaseTransactions;
|
||||
use MockUnitData;
|
||||
use WithoutEvents;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->makeTestData();
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
}
|
||||
|
||||
public function testUnappliedPaymentDelete()
|
||||
{
|
||||
|
||||
$data = [
|
||||
'amount' => 1000,
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'invoices' => [
|
||||
],
|
||||
'date' => '2020/12/12',
|
||||
|
||||
];
|
||||
|
||||
$response = null;
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/payments', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
if ($response){
|
||||
$arr = $response->json();
|
||||
$response->assertStatus(200);
|
||||
|
||||
|
||||
$payment_id = $arr['data']['id'];
|
||||
$payment = Payment::with('client')->find($this->decodePrimaryKey($payment_id));
|
||||
|
||||
$this->assertEquals(1000, $payment->amount);
|
||||
$this->assertEquals(1000, $payment->client->paid_to_date);
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->delete('/api/v1/payments/'. $payment_id);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$this->assertEquals(0, $this->client->fresh()->paid_to_date);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
110
tests/Feature/Payments/UnappliedPaymentRefundTest.php
Normal file
110
tests/Feature/Payments/UnappliedPaymentRefundTest.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
namespace Tests\Feature\Payments;
|
||||
|
||||
|
||||
use App\Models\Payment;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Foundation\Testing\WithoutEvents;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\MockUnitData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class UnappliedPaymentRefundTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use DatabaseTransactions;
|
||||
use MockUnitData;
|
||||
use WithoutEvents;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
$this->makeTestData();
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
}
|
||||
|
||||
public function testUnappliedPaymentRefund()
|
||||
{
|
||||
|
||||
$data = [
|
||||
'amount' => 1000,
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'invoices' => [
|
||||
],
|
||||
'date' => '2020/12/12',
|
||||
|
||||
];
|
||||
|
||||
$response = null;
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/payments', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
if ($response){
|
||||
$arr = $response->json();
|
||||
$response->assertStatus(200);
|
||||
|
||||
$this->assertEquals(1000, $this->client->fresh()->paid_to_date);
|
||||
|
||||
$payment_id = $arr['data']['id'];
|
||||
|
||||
$this->assertEquals(1000, $arr['data']['amount']);
|
||||
|
||||
$payment = Payment::whereId($this->decodePrimaryKey($payment_id))->first();
|
||||
|
||||
$data = [
|
||||
'id' => $this->encodePrimaryKey($payment->id),
|
||||
'amount' => 500,
|
||||
'date' => '2020/12/12',
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/payments/refund', $data);
|
||||
} catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$this->assertEquals(500, $this->client->fresh()->paid_to_date);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -32,6 +32,10 @@ class DownloadHistoricalInvoiceTest extends TestCase
|
||||
parent::setUp();
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
if (config('ninja.testvars.travis') !== false) {
|
||||
$this->markTestSkipped('Skip test for Travis');
|
||||
}
|
||||
}
|
||||
|
||||
private function mockActivity()
|
||||
|
@ -10,6 +10,7 @@
|
||||
*/
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Utils\Traits\UserSessionAttributes;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Tests\TestCase;
|
||||
@ -19,13 +20,10 @@ use Tests\TestCase;
|
||||
*/
|
||||
class CollectionMergingTest extends TestCase
|
||||
{
|
||||
use UserSessionAttributes;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Session::start();
|
||||
}
|
||||
|
||||
public function testUniqueValues()
|
||||
@ -62,4 +60,21 @@ class CollectionMergingTest extends TestCase
|
||||
$intersect = $collection->intersectByKeys($collection->flatten(1)->unique());
|
||||
$this->assertEquals(11, $intersect->count());
|
||||
}
|
||||
|
||||
public function testExistenceInCollection()
|
||||
{
|
||||
|
||||
$items = InvoiceItemFactory::generate(5);
|
||||
|
||||
$this->assertFalse(collect($items)->contains('type_id', "3"));
|
||||
$this->assertFalse(collect($items)->contains('type_id', 3));
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->type_id = "3";
|
||||
$items[] = $item;
|
||||
|
||||
$this->assertTrue(collect($items)->contains('type_id', "3"));
|
||||
$this->assertTrue(collect($items)->contains('type_id', 3));
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user