mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #9385 from turbo124/v5-develop
Gateway authentication
This commit is contained in:
commit
94d4da8513
@ -499,25 +499,28 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $use_unapplied_payment = 'off'; //always, option, off //@implemented
|
||||
|
||||
public $enable_rappen_rounding = false;
|
||||
|
||||
public static $casts = [
|
||||
'use_unapplied_payment' => 'string',
|
||||
'show_pdfhtml_on_mobile' => 'bool',
|
||||
'payment_email_all_contacts' => 'bool',
|
||||
'statement_design_id' => 'string',
|
||||
'delivery_note_design_id' => 'string',
|
||||
'payment_receipt_design_id' => 'string',
|
||||
'payment_refund_design_id' => 'string',
|
||||
'classification' => 'string',
|
||||
'enable_e_invoice' => 'bool',
|
||||
'classification' => 'string',
|
||||
'default_expense_payment_type_id' => 'string',
|
||||
'e_invoice_type' => 'string',
|
||||
'mailgun_endpoint' => 'string',
|
||||
'client_initiated_payments' => 'bool',
|
||||
'client_initiated_payments_minimum' => 'float',
|
||||
'sync_invoice_quote_columns' => 'bool',
|
||||
'show_task_item_description' => 'bool',
|
||||
'allow_billable_task_items' => 'bool',
|
||||
'enable_rappen_rounding' => 'bool',
|
||||
'use_unapplied_payment' => 'string',
|
||||
'show_pdfhtml_on_mobile' => 'bool',
|
||||
'payment_email_all_contacts' => 'bool',
|
||||
'statement_design_id' => 'string',
|
||||
'delivery_note_design_id' => 'string',
|
||||
'payment_receipt_design_id' => 'string',
|
||||
'payment_refund_design_id' => 'string',
|
||||
'classification' => 'string',
|
||||
'enable_e_invoice' => 'bool',
|
||||
'classification' => 'string',
|
||||
'default_expense_payment_type_id' => 'string',
|
||||
'e_invoice_type' => 'string',
|
||||
'mailgun_endpoint' => 'string',
|
||||
'client_initiated_payments' => 'bool',
|
||||
'client_initiated_payments_minimum' => 'float',
|
||||
'sync_invoice_quote_columns' => 'bool',
|
||||
'show_task_item_description' => 'bool',
|
||||
'allow_billable_task_items' => 'bool',
|
||||
'accept_client_input_quote_approval' => 'bool',
|
||||
'custom_sending_email' => 'string',
|
||||
'show_paid_stamp' => 'bool',
|
||||
|
88398
app/DataProviders/SMSNumbers.php
Normal file
88398
app/DataProviders/SMSNumbers.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -294,6 +294,7 @@ class BaseExport
|
||||
'line_total' => 'item.line_total',
|
||||
'gross_line_total' => 'item.gross_line_total',
|
||||
'tax_amount' => 'item.tax_amount',
|
||||
'product_cost' => 'item.product_cost'
|
||||
];
|
||||
|
||||
protected array $quote_report_keys = [
|
||||
|
@ -58,7 +58,10 @@ class DesignFilters extends QueryFilters
|
||||
|
||||
public function entities(string $entities = ''): Builder
|
||||
{
|
||||
|
||||
|
||||
if(stripos($entities, 'statement') !== false)
|
||||
$entities = 'client';
|
||||
|
||||
if (strlen($entities) == 0 || str_contains($entities, ',')) {
|
||||
return $this->builder;
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ class InvoiceSum
|
||||
|
||||
public InvoiceItemSum $invoice_items;
|
||||
|
||||
private $rappen_rounding = false;
|
||||
/**
|
||||
* Constructs the object with Invoice and Settings object.
|
||||
*
|
||||
@ -63,8 +64,11 @@ class InvoiceSum
|
||||
|
||||
if ($this->invoice->client) {
|
||||
$this->precision = $this->invoice->client->currency()->precision;
|
||||
$this->rappen_rounding = $this->invoice->client->getSetting('enable_rappen_rounding');
|
||||
} else {
|
||||
$this->precision = $this->invoice->vendor->currency()->precision;
|
||||
$this->rappen_rounding = $this->invoice->vendor->getSetting('enable_rappen_rounding');
|
||||
|
||||
}
|
||||
|
||||
$this->tax_map = new Collection();
|
||||
@ -252,11 +256,20 @@ class InvoiceSum
|
||||
/* Set new calculated total */
|
||||
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
|
||||
|
||||
if($this->rappen_rounding)
|
||||
$this->invoice->amount = $this->roundRappen($this->invoice->amount);
|
||||
|
||||
$this->invoice->total_taxes = $this->getTotalTaxes();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
function roundRappen($value): float
|
||||
{
|
||||
return round($value / .05, 0) * .05;
|
||||
}
|
||||
|
||||
public function getSubTotal()
|
||||
{
|
||||
return $this->sub_total;
|
||||
|
@ -47,6 +47,8 @@ class InvoiceSumInclusive
|
||||
|
||||
private $precision;
|
||||
|
||||
private $rappen_rounding = false;
|
||||
|
||||
public InvoiceItemSumInclusive $invoice_items;
|
||||
/**
|
||||
* Constructs the object with Invoice and Settings object.
|
||||
@ -59,8 +61,10 @@ class InvoiceSumInclusive
|
||||
|
||||
if ($this->invoice->client) {
|
||||
$this->precision = $this->invoice->client->currency()->precision;
|
||||
$this->rappen_rounding = $this->invoice->client->getSetting('enable_rappen_rounding');
|
||||
} else {
|
||||
$this->precision = $this->invoice->vendor->currency()->precision;
|
||||
$this->rappen_rounding = $this->invoice->vendor->getSetting('enable_rappen_rounding');
|
||||
}
|
||||
|
||||
$this->tax_map = new Collection();
|
||||
@ -268,12 +272,22 @@ class InvoiceSumInclusive
|
||||
}
|
||||
|
||||
/* Set new calculated total */
|
||||
/** @todo - rappen rounding here */
|
||||
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
|
||||
|
||||
if($this->rappen_rounding) {
|
||||
$this->invoice->amount = $this->roundRappen($this->invoice->amount);
|
||||
}
|
||||
|
||||
$this->invoice->total_taxes = $this->getTotalTaxes();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
function roundRappen($value): float
|
||||
{
|
||||
return round($value / .05, 0) * .05;
|
||||
}
|
||||
|
||||
public function getSubTotal()
|
||||
{
|
||||
|
@ -20,6 +20,7 @@ use App\Http\Requests\CompanyGateway\DestroyCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\EditCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\ShowCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\StoreCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\TestCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\UpdateCompanyGatewayRequest;
|
||||
use App\Jobs\Util\ApplePayDomain;
|
||||
use App\Models\Client;
|
||||
@ -535,4 +536,12 @@ class CompanyGatewayController extends BaseController
|
||||
|
||||
return $this->listResponse(CompanyGateway::withTrashed()->company()->whereIn('id', $request->ids));
|
||||
}
|
||||
|
||||
public function test(TestCompanyGatewayRequest $request, CompanyGateway $company_gateway)
|
||||
{
|
||||
|
||||
return response()->json(['message' => $company_gateway->driver()->auth() ? 'true' : 'false'], 200);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -63,8 +63,12 @@ class LogoutController extends BaseController
|
||||
$ct->company
|
||||
->tokens()
|
||||
->where('is_system', true)
|
||||
->forceDelete();
|
||||
|
||||
->cursor()
|
||||
->each(function ($ct){
|
||||
$ct->token = \Illuminate\Support\Str::random(64);
|
||||
$ct->save();
|
||||
});
|
||||
|
||||
return response()->json(['message' => 'All tokens deleted'], 200);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\CompanyGateway;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class TestCompanyGatewayRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
/** @var \App\Models\User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
return $user->isAdmin();
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
public function prepareForValidation()
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
$this->replace($input);
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
*1`
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
@ -21,6 +21,7 @@ class BlackListRule implements ValidationRule
|
||||
{
|
||||
/** Bad domains +/- dispoable email domains */
|
||||
private array $blacklist = [
|
||||
'wireconnected.com',
|
||||
'secure-coinspot.com',
|
||||
'casasotombo.com',
|
||||
'otpku.com',
|
||||
|
@ -229,8 +229,8 @@ class NinjaMailerJob implements ShouldQueue
|
||||
|
||||
private function incrementEmailCounter(): void
|
||||
{
|
||||
if (in_array($this->mailer, ['default', 'mailgun']))
|
||||
Cache::increment("email_quota" . $this->company->account->key);
|
||||
if(in_array($this->mailer, ['default','mailgun','postmark']))
|
||||
Cache::increment("email_quota".$this->company->account->key);
|
||||
|
||||
}
|
||||
/**
|
||||
|
@ -21,6 +21,7 @@ use Illuminate\Support\Str;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\VendorContact;
|
||||
use App\DataProviders\SMSNumbers;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
@ -537,6 +538,10 @@ class MultiDB
|
||||
|
||||
$current_db = config('database.default');
|
||||
|
||||
if(SMSNumbers::hasNumber($phone)){
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (self::$dbs as $db) {
|
||||
self::setDB($db);
|
||||
if ($exists = Account::where('account_sms_verification_number', $phone)->where('account_sms_verified', true)->exists()) {
|
||||
|
@ -222,8 +222,9 @@ class RequiredClientInfo extends Component
|
||||
$this->show_form = true;
|
||||
|
||||
$hash = Cache::get(request()->input('hash'));
|
||||
$invoice = Invoice::find($this->decodePrimaryKey($hash['invoice_id']));
|
||||
|
||||
$this->invoice_terms = Invoice::find($this->decodePrimaryKey($hash['invoice_id']))->terms;
|
||||
$this->invoice_terms = $invoice->terms;
|
||||
}
|
||||
|
||||
count($this->fields) > 0 || $this->show_terms
|
||||
|
@ -102,7 +102,7 @@ class Account extends BaseModel
|
||||
|
||||
private $free_plan_email_quota = 20;
|
||||
|
||||
private $paid_plan_email_quota = 400;
|
||||
private $paid_plan_email_quota = 300;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@ -503,11 +503,13 @@ class Account extends BaseModel
|
||||
}
|
||||
|
||||
if ($this->isPaid()) {
|
||||
$multiplier = $this->plan == 'enterprise' ? 2 : 1.2;
|
||||
|
||||
$limit = $this->paid_plan_email_quota;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 50;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * (20 * $multiplier);
|
||||
} else {
|
||||
$limit = $this->free_plan_email_quota;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 2;
|
||||
$limit += Carbon::createFromTimestamp($this->created_at)->diffInMonths() * 1.5;
|
||||
}
|
||||
|
||||
return min($limit, 1000);
|
||||
|
@ -485,7 +485,7 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
}
|
||||
|
||||
/*Company Settings*/
|
||||
elseif ((property_exists($this->company->settings, $setting) != false) && (isset($this->company->settings->{$setting}) !== false)) {
|
||||
elseif ((property_exists($this->company->settings, $setting) !== false) && (isset($this->company->settings->{$setting}) !== false)) {
|
||||
return $this->company->settings->{$setting};
|
||||
} elseif (property_exists(CompanySettings::defaults(), $setting)) {
|
||||
return CompanySettings::defaults()->{$setting};
|
||||
|
@ -195,4 +195,9 @@ class AuthorizePaymentDriver extends BaseDriver
|
||||
{
|
||||
return (new AuthorizeCustomer($this))->importCustomers();
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
return $this->init()->getPublicClientKey() ?? false;
|
||||
}
|
||||
}
|
||||
|
@ -806,4 +806,9 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -157,34 +157,6 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
}
|
||||
}
|
||||
|
||||
// public function updateCustomer()
|
||||
// {
|
||||
// $customer = $this->findOrCreateCustomer();
|
||||
|
||||
// $result = $this->gateway->customer()->update(
|
||||
// $customer->id,
|
||||
// [
|
||||
// 'firstName' => $this->client->present()->name(),
|
||||
// 'email' => $this->client->present()->email(),
|
||||
// 'phone' => $this->client->present()->phone(),
|
||||
// 'creditCard' => [
|
||||
// 'billingAddress' => [
|
||||
// 'options' => [
|
||||
// 'updateExisting' => true
|
||||
// ],
|
||||
// 'firstName' => $this->client->present()->first_name() ?: $this->client->present()->name(),
|
||||
// 'lastName' => $this->client->present()->last_name() ?: '',
|
||||
// 'streetAddress' => $this->client->address1 ?: '',
|
||||
// 'extendedAddress' =>$this->client->address2 ?: '',
|
||||
// 'locality' => $this->client->city ?: '',
|
||||
// 'postalCode' => $this->client->postal_code ?: '',
|
||||
// 'countryCodeAlpha2' => $this->client->country ? $this->client->country->iso_3166_2 : 'US',
|
||||
// ],
|
||||
// ],
|
||||
// ]
|
||||
// );
|
||||
// }
|
||||
|
||||
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||
{
|
||||
$this->init();
|
||||
@ -324,13 +296,21 @@ class BraintreePaymentDriver extends BaseDriver
|
||||
|
||||
nlog('braintree webhook');
|
||||
|
||||
// if($webhookNotification)
|
||||
// nlog($webhookNotification->kind);
|
||||
|
||||
// // Example values for webhook notification properties
|
||||
// $message = $webhookNotification->kind; // "subscription_went_past_due"
|
||||
// $message = $webhookNotification->timestamp->format('D M j G:i:s T Y'); // "Sun Jan 1 00:00:00 UTC 2012"
|
||||
|
||||
return response()->json([], 200);
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
|
||||
try {
|
||||
$ct =$this->init()->gateway->clientToken()->generate();
|
||||
nlog($ct);
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -534,4 +534,16 @@ class CheckoutComPaymentDriver extends BaseDriver
|
||||
{
|
||||
// Gateway doesn't support this feature.
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
try{
|
||||
$this->init()->gateway->getCustomersClient('x');
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -211,4 +211,13 @@ class EwayPaymentDriver extends BaseDriver
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
|
||||
$response =$this->init()->eway->queryTransaction('xx');
|
||||
|
||||
return (bool) count($response->getErrors()) == 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -11,13 +11,14 @@
|
||||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\Forte\ACH;
|
||||
use App\PaymentDrivers\Forte\CreditCard;
|
||||
use App\Models\GatewayType;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\PaymentDrivers\Forte\ACH;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use App\PaymentDrivers\Forte\CreditCard;
|
||||
|
||||
class FortePaymentDriver extends BaseDriver
|
||||
{
|
||||
@ -183,6 +184,26 @@ class FortePaymentDriver extends BaseDriver
|
||||
];
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
|
||||
$forte_base_uri = "https://sandbox.forte.net/api/v3/";
|
||||
if ($this->company_gateway->getConfigField('testMode') == false) {
|
||||
$forte_base_uri = "https://api.forte.net/v3/";
|
||||
}
|
||||
$forte_api_access_id = $this->company_gateway->getConfigField('apiAccessId');
|
||||
$forte_secure_key = $this->company_gateway->getConfigField('secureKey');
|
||||
$forte_auth_organization_id = $this->company_gateway->getConfigField('authOrganizationId');
|
||||
$forte_organization_id = $this->company_gateway->getConfigField('organizationId');
|
||||
$forte_location_id = $this->company_gateway->getConfigField('locationId');
|
||||
|
||||
$response = Http::withBasicAuth($forte_api_access_id, $forte_secure_key)
|
||||
->withHeaders(['X-Forte-Auth-Organization-Id' => $forte_organization_id])
|
||||
->get("{$forte_base_uri}/organizations/{$forte_organization_id}/locations/{$forte_location_id}/customers/");
|
||||
|
||||
return $response->successful();
|
||||
|
||||
}
|
||||
// public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||
// {
|
||||
// return $this->payment_method->yourTokenBillingImplmentation();
|
||||
|
@ -558,4 +558,17 @@ class GoCardlessPaymentDriver extends BaseDriver
|
||||
{
|
||||
return render('gateways.gocardless.verification');
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
try {
|
||||
$customers = $this->init()->gateway->customers()->list();
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -420,4 +420,20 @@ class MolliePaymentDriver extends BaseDriver
|
||||
{
|
||||
return \number_format((float) $amount, 2, '.', '');
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
$this->init();
|
||||
|
||||
try {
|
||||
$p = $this->gateway->payments->page();
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -560,5 +560,18 @@ class PayPalPPCPPaymentDriver extends BaseDriver
|
||||
|
||||
PayPalWebhook::dispatch($request->all(), $request->headers->all(), $this->access_token);
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
|
||||
try {
|
||||
$this->init()->getClientToken();
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -81,11 +81,7 @@ class PayPalRestPaymentDriver extends BaseDriver
|
||||
|
||||
public function init()
|
||||
{
|
||||
// $this->omnipay_gateway = Omnipay::create(
|
||||
// $this->company_gateway->gateway->provider
|
||||
// );
|
||||
|
||||
// $this->omnipay_gateway->initialize((array) $this->company_gateway->getConfig());
|
||||
$this->api_endpoint_url = $this->company_gateway->getConfigField('testMode') ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';
|
||||
|
||||
$secret = $this->company_gateway->getConfigField('secret');
|
||||
@ -380,61 +376,6 @@ class PayPalRestPaymentDriver extends BaseDriver
|
||||
|
||||
return $r->json()['id'];
|
||||
|
||||
|
||||
|
||||
// $_invoice = collect($this->payment_hash->data->invoices)->first();
|
||||
|
||||
// $invoice = Invoice::withTrashed()->find($this->decodePrimaryKey($_invoice->invoice_id));
|
||||
|
||||
// $order = [
|
||||
// "intent" => "CAPTURE",
|
||||
// "payer" => [
|
||||
// "name" => [
|
||||
// "given_name" => $this->client->present()->first_name(),
|
||||
// "surname" => $this->client->present()->last_name(),
|
||||
// ],
|
||||
// "email_address" => $this->client->present()->email(),
|
||||
// "address" => [
|
||||
// "address_line_1" => $this->client->address1,
|
||||
// "address_line_2" => $this->client->address2,
|
||||
// "admin_area_1" => $this->client->city,
|
||||
// "admin_area_2" => $this->client->state,
|
||||
// "postal_code" => $this->client->postal_code,
|
||||
// "country_code" => $this->client->country->iso_3166_2,
|
||||
// ]
|
||||
// ],
|
||||
// "purchase_units" => [
|
||||
// [
|
||||
// "description" => ctrans('texts.invoice_number').'# '.$invoice->number,
|
||||
// "invoice_id" => $invoice->number,
|
||||
// "amount" => [
|
||||
// "value" => (string)$data['amount_with_fee'],
|
||||
// "currency_code" => $this->client->currency()->code,
|
||||
// "breakdown" => [
|
||||
// "item_total" => [
|
||||
// "currency_code" => $this->client->currency()->code,
|
||||
// "value" => (string)$data['amount_with_fee']
|
||||
// ]
|
||||
// ]
|
||||
// ],
|
||||
// "items" => [
|
||||
// [
|
||||
// "name" => ctrans('texts.invoice_number').'# '.$invoice->number,
|
||||
// "quantity" => "1",
|
||||
// "unit_amount" => [
|
||||
// "currency_code" => $this->client->currency()->code,
|
||||
// "value" => (string)$data['amount_with_fee']
|
||||
// ],
|
||||
// ],
|
||||
// ],
|
||||
// ]
|
||||
// ]
|
||||
// ];
|
||||
|
||||
// $r = $this->gatewayRequest('/v2/checkout/orders', 'post', $order);
|
||||
|
||||
// return $r->json()['id'];
|
||||
|
||||
}
|
||||
|
||||
private function getShippingAddress(): ?array
|
||||
@ -520,5 +461,17 @@ class PayPalRestPaymentDriver extends BaseDriver
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
|
||||
try {
|
||||
$this->init()->getClientToken();
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -246,4 +246,18 @@ class PaytracePaymentDriver extends BaseDriver
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
try {
|
||||
$this->init()->generateAuthHeaders() && strlen($this->company_gateway->getConfigField('integratorId')) > 2;
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -429,4 +429,17 @@ class SquarePaymentDriver extends BaseDriver
|
||||
|
||||
return $amount;
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
|
||||
$api_response = $this->init()
|
||||
->square
|
||||
->getCustomersApi()
|
||||
->listCustomers();
|
||||
|
||||
|
||||
return (bool) count($api_response->getErrors()) == 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -990,4 +990,20 @@ class StripePaymentDriver extends BaseDriver
|
||||
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UCS-2BE');
|
||||
}, $string);
|
||||
}
|
||||
|
||||
public function auth(): bool
|
||||
{
|
||||
$this->init();
|
||||
|
||||
try {
|
||||
$this->verifyConnect();
|
||||
return true;
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -162,6 +162,7 @@ class Statement
|
||||
$ts->addGlobal(['show_credits' => $this->options['show_credits_table']]);
|
||||
$ts->addGlobal(['show_aging' => $this->options['show_aging_table']]);
|
||||
$ts->addGlobal(['show_payments' => $this->options['show_payments_table']]);
|
||||
$ts->addGlobal(['currency_code' => $this->client->company->currency()->code]);
|
||||
|
||||
$ts->build([
|
||||
'variables' => collect([$variables]),
|
||||
|
@ -250,8 +250,8 @@ class Email implements ShouldQueue
|
||||
|
||||
private function incrementEmailCounter(): void
|
||||
{
|
||||
if (in_array($this->mailer, ['default', 'mailgun']))
|
||||
Cache::increment("email_quota" . $this->company->account->key);
|
||||
if(in_array($this->mailer, ['default','mailgun','postmark']))
|
||||
Cache::increment("email_quota".$this->company->account->key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,24 +113,30 @@ class PdfMock
|
||||
/** @var \App\Models\Invoice | \App\Models\Credit | \App\Models\Quote $entity */
|
||||
$entity = Invoice::factory()->make();
|
||||
$entity->client = Client::factory()->make(['settings' => $settings]);
|
||||
$entity->client->setRelation('company', $this->company);
|
||||
$entity->invitation = InvoiceInvitation::factory()->make();
|
||||
break;
|
||||
case 'quote':
|
||||
/** @var \App\Models\Invoice | \App\Models\Credit | \App\Models\Quote $entity */
|
||||
$entity = Quote::factory()->make();
|
||||
$entity->client = Client::factory()->make(['settings' => $settings]);
|
||||
$entity->client->setRelation('company', $this->company);
|
||||
$entity->invitation = QuoteInvitation::factory()->make();
|
||||
break;
|
||||
case 'credit':
|
||||
/** @var \App\Models\Invoice | \App\Models\Credit | \App\Models\Quote $entity */
|
||||
$entity = Credit::factory()->make();
|
||||
$entity->client = Client::factory()->make(['settings' => $settings]);
|
||||
$entity->client->setRelation('company', $this->company);
|
||||
$entity->invitation = CreditInvitation::factory()->make();
|
||||
break;
|
||||
case 'purchase_order':
|
||||
/** @var \App\Models\Invoice | \App\Models\Credit | \App\Models\Quote $entity */
|
||||
|
||||
/** @var \App\Models\PurchaseOrder $entity */
|
||||
$entity = PurchaseOrder::factory()->make();
|
||||
$entity->client = Client::factory()->make(['settings' => $settings]);
|
||||
// $entity->client = Client::factory()->make(['settings' => $settings]);
|
||||
$entity->vendor = Vendor::factory()->make();
|
||||
$entity->vendor->setRelation('company', $this->company);
|
||||
$entity->invitation = PurchaseOrderInvitation::factory()->make();
|
||||
break;
|
||||
case PurchaseOrder::class:
|
||||
@ -138,17 +144,17 @@ class PdfMock
|
||||
$entity = PurchaseOrder::factory()->make();
|
||||
$entity->invitation = PurchaseOrderInvitation::factory()->make();
|
||||
$entity->vendor = Vendor::factory()->make();
|
||||
$entity->invitation->setRelation('company', $this->company);
|
||||
break;
|
||||
default:
|
||||
$entity = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$entity->tax_map = $this->getTaxMap();
|
||||
$entity->total_tax_map = $this->getTotalTaxMap();
|
||||
$entity->invitation->company = $this->company;
|
||||
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
|
@ -613,8 +613,6 @@ class TemplateService
|
||||
|
||||
$this->payment = $payment;
|
||||
|
||||
$this->addGlobal(['currency_code' => $payment->currency->code ?? $this->company->currency()->code]);
|
||||
|
||||
$credits = $payment->credits->map(function ($credit) use ($payment) {
|
||||
return [
|
||||
'credit' => $credit->number,
|
||||
|
@ -16,7 +16,6 @@ return new class extends Migration
|
||||
$table->decimal('discount', 20, 6)->default(0)->change();
|
||||
});
|
||||
|
||||
|
||||
Schema::table('credits', function (Blueprint $table) {
|
||||
$table->decimal('discount', 20, 6)->default(0)->change();
|
||||
});
|
||||
|
@ -5259,6 +5259,9 @@ $lang = array(
|
||||
'select_email_provider' => 'Set your email as the sending user',
|
||||
'purchase_order_items' => 'Purchase Order Items',
|
||||
'csv_rows_length' => 'No data found in this CSV file',
|
||||
'accept_payments_online' => 'Accept Payments Online',
|
||||
'all_payment_gateways' => 'View all payment gateways',
|
||||
'product_cost' => 'Product cost',
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
@ -460,7 +460,7 @@ $lang = array(
|
||||
'edit_token' => 'Éditer le jeton',
|
||||
'delete_token' => 'Supprimer le jeton',
|
||||
'token' => 'Jeton',
|
||||
'add_gateway' => 'Add Payment Gateway',
|
||||
'add_gateway' => 'Ajouter une passerelle de paiement',
|
||||
'delete_gateway' => 'Supprimer la passerelle',
|
||||
'edit_gateway' => 'Éditer la passerelle',
|
||||
'updated_gateway' => 'La passerelle a été mise à jour',
|
||||
@ -5248,9 +5248,11 @@ Lorsque les montant apparaîtront sur votre relevé, veuillez revenir sur cette
|
||||
'payment_type_help' => 'Définit le <b>type de paiement manuel<b/> par défaut.',
|
||||
'quote_valid_until_help' => 'Le nombre de jours pour lesquels la soumission est valide',
|
||||
'expense_payment_type_help' => 'Le type de paiement de dépenses par défaut à utiliser',
|
||||
'paylater' => 'Pay in 4',
|
||||
'payment_provider' => 'Payment Provider',
|
||||
|
||||
'paylater' => 'Payer en 4',
|
||||
'payment_provider' => 'Fournisseur de paiement',
|
||||
'select_email_provider' => 'Définir le courriel pour l\'envoi',
|
||||
'purchase_order_items' => 'Articles du bon d\'achat',
|
||||
'csv_rows_length' => 'Aucune donnée dans ce fichier CSV',
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
@ -195,7 +195,9 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
|
||||
Route::get('company_ledger', [CompanyLedgerController::class, 'index'])->name('company_ledger.index');
|
||||
|
||||
Route::resource('company_gateways', CompanyGatewayController::class);
|
||||
|
||||
Route::post('company_gateways/bulk', [CompanyGatewayController::class, 'bulk'])->name('company_gateways.bulk');
|
||||
Route::post('company_gateways/{company_gateway}/test', [CompanyGatewayController::class, 'test'])->name('company_gateways.test');
|
||||
|
||||
Route::put('company_users/{user}', [CompanyUserController::class, 'update']);
|
||||
Route::put('company_users/{user}/preferences', [CompanyUserController::class, 'updatePreferences']);
|
||||
|
@ -49,6 +49,88 @@ class InvoiceTest extends TestCase
|
||||
$this->invoice_calc = new InvoiceSum($this->invoice);
|
||||
}
|
||||
|
||||
public function testRappenRounding()
|
||||
{
|
||||
|
||||
$c_settings = $this->client->settings;
|
||||
$c_settings->enable_rappen_rounding = true;
|
||||
|
||||
$c = \App\Models\Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'settings' => $c_settings,
|
||||
]);
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10.01;
|
||||
$item->type_id = '1';
|
||||
$item->tax_id = '1';
|
||||
$line_items[] = $item;
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'discount' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'client_id' => $c->id,
|
||||
'line_items' => $line_items,
|
||||
'status_id' => 1,
|
||||
]);
|
||||
|
||||
$invoice_calc = new InvoiceSum($i);
|
||||
$ii = $invoice_calc->build()->getInvoice();
|
||||
|
||||
$this->assertEquals(10, $ii->amount);
|
||||
|
||||
}
|
||||
|
||||
public function testRappenRoundingUp()
|
||||
{
|
||||
|
||||
$c_settings = $this->client->settings;
|
||||
$c_settings->enable_rappen_rounding = true;
|
||||
|
||||
$c = \App\Models\Client::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'settings' => $c_settings,
|
||||
]);
|
||||
|
||||
$item = InvoiceItemFactory::create();
|
||||
$item->quantity = 1;
|
||||
$item->cost = 10.09;
|
||||
$item->type_id = '1';
|
||||
$item->tax_id = '1';
|
||||
$line_items[] = $item;
|
||||
|
||||
$i = Invoice::factory()->create([
|
||||
'discount' => 0,
|
||||
'tax_name1' => '',
|
||||
'tax_name2' => '',
|
||||
'tax_name3' => '',
|
||||
'tax_rate1' => 0,
|
||||
'tax_rate2' => 0,
|
||||
'tax_rate3' => 0,
|
||||
'user_id' => $this->user->id,
|
||||
'company_id' => $this->company->id,
|
||||
'client_id' => $c->id,
|
||||
'line_items' => $line_items,
|
||||
'status_id' => 1,
|
||||
]);
|
||||
|
||||
$invoice_calc = new InvoiceSum($i);
|
||||
$ii = $invoice_calc->build()->getInvoice();
|
||||
|
||||
$this->assertEquals(10.10, round($ii->amount,2));
|
||||
|
||||
}
|
||||
|
||||
public function testPartialDueDateCast()
|
||||
{
|
||||
$i = Invoice::factory()
|
||||
|
36
tests/Unit/SmsNumberTest.php
Normal file
36
tests/Unit/SmsNumberTest.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?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://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\DataProviders\SMSNumbers;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
class SmsNumberTest extends TestCase
|
||||
{
|
||||
public function testArrayHit()
|
||||
{
|
||||
$this->assertTrue(SMSNumbers::hasNumber("+461614222"));
|
||||
}
|
||||
|
||||
public function testArrayMiss()
|
||||
{
|
||||
$this->assertFalse(SMSNumbers::hasNumber("+5485454"));
|
||||
}
|
||||
|
||||
public function testSmsArrayType()
|
||||
{
|
||||
$this->assertIsArray(SMSNumbers::getNumbers());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user