mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-11 13:42:49 +01:00
commit
7791110bac
@ -1 +1 @@
|
||||
5.3.41
|
||||
5.3.42
|
103
app/Http/Controllers/ClientPortal/ApplePayDomainController.php
Normal file
103
app/Http/Controllers/ClientPortal/ApplePayDomainController.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://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\ClientPortal;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ApplePayDomainController extends Controller
|
||||
{
|
||||
|
||||
private array $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23'];
|
||||
|
||||
public function showAppleMerchantId(Request $request)
|
||||
{
|
||||
|
||||
/* Self Host */
|
||||
|
||||
if(Ninja::isSelfHost()){
|
||||
|
||||
$cgs = CompanyGateway::whereIn('gateway_key', $this->stripe_keys)
|
||||
->where('is_deleted', false)
|
||||
->get();
|
||||
|
||||
foreach($cgs as $cg)
|
||||
{
|
||||
|
||||
if($cg->getConfigField('appleDomainVerification')){
|
||||
return response($cg->getConfigField('appleDomainVerification'),200);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return response('', 400);
|
||||
}
|
||||
|
||||
/* Hosted */
|
||||
|
||||
$domain_name = $request->getHost();
|
||||
|
||||
if (strpos($domain_name, 'invoicing.co') !== false)
|
||||
{
|
||||
$subdomain = explode('.', $domain_name)[0];
|
||||
|
||||
$query = [
|
||||
'subdomain' => $subdomain,
|
||||
'portal_mode' => 'subdomain',
|
||||
];
|
||||
|
||||
if($company = MultiDB::findAndSetDbByDomain($query)){
|
||||
return $this->resolveAppleMerchantId($company);
|
||||
}
|
||||
}
|
||||
|
||||
$query = [
|
||||
'portal_domain' => $request->getSchemeAndHttpHost(),
|
||||
'portal_mode' => 'domain',
|
||||
];
|
||||
|
||||
if($company = MultiDB::findAndSetDbByDomain($query)){
|
||||
return $this->resolveAppleMerchantId($company);
|
||||
}
|
||||
|
||||
return response('', 400);
|
||||
|
||||
}
|
||||
|
||||
private function resolveAppleMerchantId($company)
|
||||
{
|
||||
|
||||
$cgs = $company->company_gateways()
|
||||
->whereIn('gateway_key', $this->stripe_keys)
|
||||
->where('is_deleted', false)
|
||||
->get();
|
||||
|
||||
foreach($cgs as $cg)
|
||||
{
|
||||
|
||||
if($cg->getConfigField('appleDomainVerification')){
|
||||
return response($cg->getConfigField('appleDomainVerification'),200);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return response('', 400);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,13 @@
|
||||
<?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 App\Http\Controllers\ClientPortal;
|
||||
|
||||
|
@ -31,6 +31,7 @@ use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use ZipStream\Option\Archive;
|
||||
use ZipStream\ZipStream;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class QuoteController extends Controller
|
||||
{
|
||||
@ -54,7 +55,9 @@ class QuoteController extends Controller
|
||||
* @return Factory|View|BinaryFileResponse
|
||||
*/
|
||||
public function show(ShowQuoteRequest $request, Quote $quote)
|
||||
{
|
||||
{
|
||||
/* If the quote is expired, convert the status here */
|
||||
|
||||
$data = [
|
||||
'quote' => $quote,
|
||||
];
|
||||
|
@ -20,6 +20,7 @@ use App\Http\Requests\CompanyGateway\EditCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\ShowCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\StoreCompanyGatewayRequest;
|
||||
use App\Http\Requests\CompanyGateway\UpdateCompanyGatewayRequest;
|
||||
use App\Jobs\Util\ApplePayDomain;
|
||||
use App\Models\Client;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Repositories\CompanyRepository;
|
||||
@ -45,6 +46,9 @@ class CompanyGatewayController extends BaseController
|
||||
|
||||
public $forced_includes = [];
|
||||
|
||||
private array $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23'];
|
||||
|
||||
|
||||
/**
|
||||
* CompanyGatewayController constructor.
|
||||
* @param CompanyRepository $company_repo
|
||||
@ -206,6 +210,8 @@ class CompanyGatewayController extends BaseController
|
||||
$company_gateway->save();
|
||||
}
|
||||
|
||||
ApplePayDomain::dispatch($company_gateway, $company_gateway->company->db);
|
||||
|
||||
return $this->itemResponse($company_gateway);
|
||||
}
|
||||
|
||||
@ -379,6 +385,8 @@ class CompanyGatewayController extends BaseController
|
||||
|
||||
$company_gateway->save();
|
||||
|
||||
ApplePayDomain::dispatch($company_gateway, $company_gateway->company->db);
|
||||
|
||||
return $this->itemResponse($company_gateway);
|
||||
}
|
||||
|
||||
|
@ -304,6 +304,7 @@ class MigrationController extends BaseController
|
||||
App::forgetInstance('translator');
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($user->account->companies()->first()->settings));
|
||||
App::setLocale($user->account->companies()->first()->getLocale());
|
||||
|
||||
if(!$existing_company && $company_count >=10) {
|
||||
|
||||
|
@ -20,6 +20,8 @@ use App\Models\InvoiceInvitation;
|
||||
use App\Models\QuoteInvitation;
|
||||
use App\Models\RecurringInvoiceInvitation;
|
||||
use App\Models\SystemLog;
|
||||
use App\Notifications\Ninja\EmailBounceNotification;
|
||||
use App\Notifications\Ninja\EmailSpamNotification;
|
||||
use Illuminate\Http\Request;
|
||||
use Turbo124\Beacon\Facades\LightLogs;
|
||||
|
||||
@ -173,6 +175,10 @@ class PostMarkController extends BaseController
|
||||
LightLogs::create($bounce)->queue();
|
||||
|
||||
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
|
||||
|
||||
if(config('ninja.notification.slack'))
|
||||
$this->invitation->company->notification(new EmailBounceNotification($this->invitation->company->account))->ninja();
|
||||
|
||||
}
|
||||
|
||||
// {
|
||||
@ -215,6 +221,10 @@ class PostMarkController extends BaseController
|
||||
LightLogs::create($spam)->queue();
|
||||
|
||||
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
|
||||
|
||||
if(config('ninja.notification.slack'))
|
||||
$this->invitation->company->notification(new EmailSpamNotification($this->invitation->company->account))->ninja();
|
||||
|
||||
}
|
||||
|
||||
private function discoverInvitation($message_id)
|
||||
|
@ -21,6 +21,7 @@ use App\Http\Requests\Token\StoreTokenRequest;
|
||||
use App\Http\Requests\Token\UpdateTokenRequest;
|
||||
use App\Models\CompanyToken;
|
||||
use App\Repositories\TokenRepository;
|
||||
use App\Transformers\CompanyTokenHashedTransformer;
|
||||
use App\Transformers\CompanyTokenTransformer;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
@ -93,6 +94,8 @@ class TokenController extends BaseController
|
||||
*/
|
||||
public function index(TokenFilters $filters)
|
||||
{
|
||||
$this->entity_transformer = CompanyTokenHashedTransformer::class;
|
||||
|
||||
$tokens = CompanyToken::filter($filters);
|
||||
|
||||
return $this->listResponse($tokens);
|
||||
@ -205,6 +208,8 @@ class TokenController extends BaseController
|
||||
*/
|
||||
public function edit(EditTokenRequest $request, CompanyToken $token)
|
||||
{
|
||||
$this->entity_transformer = CompanyTokenHashedTransformer::class;
|
||||
|
||||
return $this->itemResponse($token);
|
||||
}
|
||||
|
||||
@ -265,6 +270,8 @@ class TokenController extends BaseController
|
||||
return $request->disallowUpdate();
|
||||
}
|
||||
|
||||
$this->entity_transformer = CompanyTokenHashedTransformer::class;
|
||||
|
||||
$token = $this->token_repo->save($request->all(), $token);
|
||||
|
||||
return $this->itemResponse($token->fresh());
|
||||
@ -419,6 +426,8 @@ class TokenController extends BaseController
|
||||
//may not need these destroy routes as we are using actions to 'archive/delete'
|
||||
$token->delete();
|
||||
|
||||
$this->entity_transformer = CompanyTokenHashedTransformer::class;
|
||||
|
||||
return $this->itemResponse($token);
|
||||
}
|
||||
|
||||
@ -475,6 +484,9 @@ class TokenController extends BaseController
|
||||
*/
|
||||
public function bulk()
|
||||
{
|
||||
|
||||
$this->entity_transformer = CompanyTokenHashedTransformer::class;
|
||||
|
||||
$action = request()->input('action');
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
@ -42,13 +42,45 @@ class QuotesTable extends Component
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc');
|
||||
|
||||
if (count($this->status) > 0) {
|
||||
$query = $query->whereIn('status_id', $this->status);
|
||||
|
||||
/* Special filter for expired*/
|
||||
if(in_array("-1", $this->status)){
|
||||
// $query->whereDate('due_date', '<=', now()->startOfDay());
|
||||
|
||||
$query->where(function ($query){
|
||||
$query->whereDate('due_date', '<=', now()->startOfDay())
|
||||
->whereNotNull('due_date')
|
||||
->where('status_id', '<>', Quote::STATUS_CONVERTED);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if(in_array("2", $this->status)){
|
||||
|
||||
$query->where(function ($query){
|
||||
$query->whereDate('due_date', '>=', now()->startOfDay())
|
||||
->orWhereNull('due_date');
|
||||
})->where('status_id', Quote::STATUS_SENT);
|
||||
|
||||
}
|
||||
|
||||
if(in_array("3", $this->status)){
|
||||
$query->whereIn('status_id', [Quote::STATUS_APPROVED, Quote::STATUS_CONVERTED]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$query = $query
|
||||
->where('company_id', $this->company->id)
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('status_id', '<>', Quote::STATUS_DRAFT)
|
||||
// ->where(function ($query){
|
||||
// $query->whereDate('due_date', '>=', now())
|
||||
// ->orWhereNull('due_date');
|
||||
// })
|
||||
->where('is_deleted', 0)
|
||||
->withTrashed()
|
||||
->paginate($this->per_page);
|
||||
|
@ -47,7 +47,7 @@ class StoreInvoiceRequest extends Request
|
||||
$rules['documents'] = 'file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
|
||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id;
|
||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
// $rules['client_id'] = ['required', Rule::exists('clients')->where('company_id', auth()->user()->company()->id)];
|
||||
|
||||
$rules['invitations.*.client_contact_id'] = 'distinct';
|
||||
|
@ -335,11 +335,12 @@ class CompanyImport implements ShouldQueue
|
||||
}
|
||||
}
|
||||
|
||||
if($this->company->account->isFreeHostedClient() && $client_count = count($this->getObject('clients', true)) > config('ninja.quotas.free.clients')){
|
||||
if($this->company->account->isFreeHostedClient() && (count($this->getObject('clients', true)) > config('ninja.quotas.free.clients')) ){
|
||||
|
||||
nlog("client quota busted");
|
||||
|
||||
$client_limit = config('ninja.quotas.free.clients');
|
||||
$client_count = count($this->getObject('clients', true));
|
||||
|
||||
$this->message = "You are attempting to import ({$client_count}) clients, your current plan allows a total of ({$client_limit})";
|
||||
|
||||
|
@ -135,7 +135,7 @@ class SendRecurring implements ShouldQueue
|
||||
if ($invitation->contact && !$invitation->contact->trashed() && strlen($invitation->contact->email) >=1 && $invoice->client->getSetting('auto_email_invoice')) {
|
||||
|
||||
try{
|
||||
EmailEntity::dispatch($invitation, $invoice->company)->delay(now()->addSeconds(1));
|
||||
EmailEntity::dispatch($invitation, $invoice->company);
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
nlog($e->getMessage());
|
||||
|
100
app/Jobs/Util/ApplePayDomain.php
Normal file
100
app/Jobs/Util/ApplePayDomain.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?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 App\Jobs\Util;
|
||||
|
||||
use App\Jobs\Util\UnlinkFile;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\Account;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ApplePayDomain implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private CompanyGateway $company_gateway;
|
||||
|
||||
private string $db;
|
||||
|
||||
private array $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23'];
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public function __construct(CompanyGateway $company_gateway, string $db)
|
||||
{
|
||||
|
||||
$this->db = $db;
|
||||
|
||||
$this->company_gateway = $company_gateway;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
MultiDB::setDB($this->db);
|
||||
|
||||
if(in_array($this->company_gateway->gateway_key, $this->stripe_keys))
|
||||
{
|
||||
|
||||
$domain = $this->getDomain();
|
||||
|
||||
try{
|
||||
$this->company_gateway->driver()->setApplePayDomain($domain);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog("failed to set Apple Domain with Stripe " . $e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function getDomain()
|
||||
{
|
||||
|
||||
$domain = '';
|
||||
|
||||
if(Ninja::isHosted())
|
||||
{
|
||||
|
||||
if($this->company->portal_mode == 'domain'){
|
||||
$domain = $this->company->portal_domain;
|
||||
}
|
||||
else{
|
||||
$domain = $this->company->subdomain . '.' . config('ninja.app_domain');
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$domain = config('ninja.app_url');
|
||||
}
|
||||
|
||||
$parsed_url = parse_url($domain);
|
||||
|
||||
return $parsed_url['host'];
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -471,8 +471,9 @@ class Import implements ShouldQueue
|
||||
|
||||
}
|
||||
|
||||
if ($key == 'payment_terms' && $key = '') {
|
||||
$value = -1;
|
||||
/* changes $key = '' to $value == '' and changed the return value from -1 to "0" 06/01/2022 */
|
||||
if ($key == 'payment_terms' && $value == '') {
|
||||
$value = "0";
|
||||
}
|
||||
|
||||
$company_settings->{$key} = $value;
|
||||
|
@ -343,7 +343,10 @@ class CompanyGateway extends BaseModel
|
||||
}
|
||||
|
||||
if ($fees_and_limits->fee_percent) {
|
||||
if ($fees_and_limits->adjust_fee_percent) {
|
||||
if($fees_and_limits->fee_percent == 100){ //unusual edge case if the user wishes to charge a fee of 100% 09/01/2022
|
||||
$fee += $amount;
|
||||
}
|
||||
elseif ($fees_and_limits->adjust_fee_percent) {
|
||||
$fee += round(($amount / (1 - $fees_and_limits->fee_percent / 100) - $amount), 2);
|
||||
} else {
|
||||
$fee += round(($amount * $fees_and_limits->fee_percent / 100), 2);
|
||||
@ -383,42 +386,6 @@ class CompanyGateway extends BaseModel
|
||||
return route('payment_webhook', ['company_key' => $this->company->company_key, 'company_gateway_id' => $this->hashed_id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* we need to average out the gateway fees across all the invoices
|
||||
* so lets iterate.
|
||||
*
|
||||
* we MAY need to adjust the final fee to ensure our rounding makes sense!
|
||||
* @param $amount
|
||||
* @param $invoice_count
|
||||
* @return stdClass
|
||||
*/
|
||||
// public function calcGatewayFeeObject($amount, $invoice_count)
|
||||
// {
|
||||
// $total_gateway_fee = $this->calcGatewayFee($amount);
|
||||
|
||||
// $fee_object = new stdClass;
|
||||
|
||||
// $fees_and_limits = $this->getFeesAndLimits();
|
||||
|
||||
// if (! $fees_and_limits) {
|
||||
// return $fee_object;
|
||||
// }
|
||||
|
||||
// $fee_component_amount = $fees_and_limits->fee_amount ?: 0;
|
||||
// $fee_component_percent = $fees_and_limits->fee_percent ? ($amount * $fees_and_limits->fee_percent / 100) : 0;
|
||||
|
||||
// $combined_fee_component = $fee_component_amount + $fee_component_percent;
|
||||
|
||||
// $fee_component_tax_name1 = $fees_and_limits->fee_tax_name1 ?: '';
|
||||
// $fee_component_tax_rate1 = $fees_and_limits->fee_tax_rate1 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate1 / 100) : 0;
|
||||
|
||||
// $fee_component_tax_name2 = $fees_and_limits->fee_tax_name2 ?: '';
|
||||
// $fee_component_tax_rate2 = $fees_and_limits->fee_tax_rate2 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate2 / 100) : 0;
|
||||
|
||||
// $fee_component_tax_name3 = $fees_and_limits->fee_tax_name3 ?: '';
|
||||
// $fee_component_tax_rate3 = $fees_and_limits->fee_tax_rate3 ? ($combined_fee_component * $fees_and_limits->fee_tax_rate3 / 100) : 0;
|
||||
// }
|
||||
|
||||
public function resolveRouteBinding($value, $field = null)
|
||||
{
|
||||
return $this
|
||||
|
@ -101,6 +101,7 @@ class Invoice extends BaseModel
|
||||
'updated_at' => 'timestamp',
|
||||
'created_at' => 'timestamp',
|
||||
'deleted_at' => 'timestamp',
|
||||
'is_deleted' => 'bool',
|
||||
];
|
||||
|
||||
protected $with = [];
|
||||
@ -408,7 +409,19 @@ class Invoice extends BaseModel
|
||||
|
||||
$file_path = $this->client->invoice_filepath($invitation).$this->numberFormatter().'.pdf';
|
||||
|
||||
if(Ninja::isHosted() && $portal && Storage::disk(config('filesystems.default'))->exists($file_path)){
|
||||
$file_exists = false;
|
||||
|
||||
/* Flysystem throws an exception if the path is "corrupted" so lets wrap it in a try catch and return a bool 06/01/2022*/
|
||||
try{
|
||||
$file_exists = Storage::disk(config('filesystems.default'))->exists($file_path);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
nlog($e->getMessage());
|
||||
|
||||
}
|
||||
|
||||
if(Ninja::isHosted() && $portal && $file_exists){
|
||||
return Storage::disk(config('filesystems.default'))->{$type}($file_path);
|
||||
}
|
||||
elseif(Ninja::isHosted()){
|
||||
@ -416,7 +429,16 @@ class Invoice extends BaseModel
|
||||
return Storage::disk(config('filesystems.default'))->{$type}($file_path);
|
||||
}
|
||||
|
||||
if(Storage::disk('public')->exists($file_path))
|
||||
try{
|
||||
$file_exists = Storage::disk('public')->exists($file_path);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
|
||||
nlog($e->getMessage());
|
||||
|
||||
}
|
||||
|
||||
if($file_exists)
|
||||
return Storage::disk('public')->{$type}($file_path);
|
||||
|
||||
$file_path = CreateEntityPdf::dispatchNow($invitation);
|
||||
|
@ -87,6 +87,7 @@ class Quote extends BaseModel
|
||||
'updated_at' => 'timestamp',
|
||||
'created_at' => 'timestamp',
|
||||
'deleted_at' => 'timestamp',
|
||||
'is_deleted' => 'boolean',
|
||||
];
|
||||
|
||||
protected $dates = [];
|
||||
@ -117,6 +118,16 @@ class Quote extends BaseModel
|
||||
return $this->dateMutator($value);
|
||||
}
|
||||
|
||||
public function getStatusIdAttribute($value)
|
||||
{
|
||||
if($this->due_date && !$this->is_deleted && $value == Quote::STATUS_SENT && Carbon::parse($this->due_date)->lte(now()->startOfDay())){
|
||||
return Quote::STATUS_EXPIRED;
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
public function company()
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
|
88
app/Notifications/Ninja/EmailBounceNotification.php
Normal file
88
app/Notifications/Ninja/EmailBounceNotification.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?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 App\Notifications\Ninja;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class EmailBounceNotification extends Notification
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected $account;
|
||||
|
||||
public function __construct($account)
|
||||
{
|
||||
$this->account = $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['slack'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
|
||||
$content = "Email bounce notification for Account {$this->account->key} \n";
|
||||
|
||||
$owner = $this->account->companies()->first()->owner();
|
||||
|
||||
$content .= "Owner {$owner->present()->name() } | {$owner->email}";
|
||||
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->from(ctrans('texts.notification_bot'))
|
||||
->image('https://app.invoiceninja.com/favicon.png')
|
||||
->content($content);
|
||||
}
|
||||
}
|
88
app/Notifications/Ninja/EmailSpamNotification.php
Normal file
88
app/Notifications/Ninja/EmailSpamNotification.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?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 App\Notifications\Ninja;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class EmailSpamNotification extends Notification
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
protected $account;
|
||||
|
||||
public function __construct($account)
|
||||
{
|
||||
$this->account = $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['slack'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
|
||||
$content = "Email SPAM notification for Account {$this->account->key} \n";
|
||||
|
||||
$owner = $this->account->companies()->first()->owner();
|
||||
|
||||
$content .= "Owner {$owner->present()->name() } | {$owner->email}";
|
||||
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->from(ctrans('texts.notification_bot'))
|
||||
->image('https://app.invoiceninja.com/favicon.png')
|
||||
->content($content);
|
||||
}
|
||||
}
|
@ -157,7 +157,8 @@ class AuthorizePaymentMethod
|
||||
$paymentOne->setOpaqueData($op);
|
||||
|
||||
$contact = $this->authorize->client->primary_contact()->first();
|
||||
|
||||
$billto = false;
|
||||
|
||||
if ($contact) {
|
||||
// Create the Bill To info for new payment type
|
||||
$billto = new CustomerAddressType();
|
||||
|
@ -256,13 +256,13 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
$this->payment_hash->payment_id = $payment->id;
|
||||
$this->payment_hash->save();
|
||||
|
||||
$this->attachInvoices($payment, $this->payment_hash);
|
||||
|
||||
if($this->payment_hash->credits_total() > 0)
|
||||
$payment = $payment->service()->applyCredits($this->payment_hash)->save();
|
||||
|
||||
$payment->service()->updateInvoicePayment($this->payment_hash);
|
||||
|
||||
$this->attachInvoices($payment, $this->payment_hash);
|
||||
|
||||
event('eloquent.created: App\Models\Payment', $payment);
|
||||
|
||||
if ($this->client->getSetting('client_online_payment_notification') && in_array($status, [Payment::STATUS_COMPLETED, Payment::STATUS_PENDING]))
|
||||
|
@ -49,7 +49,8 @@ class PayFastPaymentDriver extends BaseDriver
|
||||
{
|
||||
$types = [];
|
||||
|
||||
if($this->client->currency()->code == 'ZAR' || $this->client->currency()->code == 'USD')
|
||||
// if($this->client->currency()->code == 'ZAR' || $this->client->currency()->code == 'USD')
|
||||
if($this->client->currency()->code == 'ZAR')
|
||||
$types[] = GatewayType::CREDIT_CARD;
|
||||
|
||||
return $types;
|
||||
|
@ -725,6 +725,17 @@ class StripePaymentDriver extends BaseDriver
|
||||
return (new Verify($this))->run();
|
||||
}
|
||||
|
||||
public function setApplePayDomain($domain)
|
||||
{
|
||||
|
||||
$this->init();
|
||||
|
||||
\Stripe\ApplePayDomain::create([
|
||||
'domain_name' => $domain,
|
||||
],$this->stripe_connect_auth);
|
||||
|
||||
}
|
||||
|
||||
public function disconnect()
|
||||
{
|
||||
if(!$this->stripe_connect)
|
||||
|
@ -47,9 +47,13 @@ class PaymentRepository extends BaseRepository {
|
||||
*/
|
||||
public function save(array $data, Payment $payment): ?Payment
|
||||
{
|
||||
if ($payment->amount >= 0) {
|
||||
// if ($payment->amount >= 0) {
|
||||
// return $this->applyPayment($data, $payment);
|
||||
// }
|
||||
|
||||
|
||||
return $this->applyPayment($data, $payment);
|
||||
}
|
||||
|
||||
|
||||
return $payment;
|
||||
}
|
||||
@ -80,8 +84,8 @@ class PaymentRepository extends BaseRepository {
|
||||
|
||||
$client->service()->updatePaidToDate($data['amount'])->save();
|
||||
}
|
||||
elseif($data['amount'] >0){
|
||||
|
||||
// elseif($data['amount'] >0){
|
||||
else{
|
||||
//this fixes an edge case with unapplied payments
|
||||
$client->service()->updatePaidToDate($data['amount'])->save();
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ class TriggeredActions extends AbstractService
|
||||
{
|
||||
|
||||
if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') {
|
||||
$this->credit = $this->credit->service()->markSent()->save();
|
||||
$this->sendEmail();
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,7 @@ class AutoBillInvoice extends AbstractService
|
||||
$fee = 0;
|
||||
|
||||
/* Build payment hash */
|
||||
|
||||
$payment_hash = PaymentHash::create([
|
||||
'hash' => Str::random(64),
|
||||
'data' => ['invoices' => [['invoice_id' => $this->invoice->hashed_id, 'amount' => $amount, 'invoice_number' => $this->invoice->number]]],
|
||||
@ -123,7 +124,8 @@ class AutoBillInvoice extends AbstractService
|
||||
->tokenBilling($gateway_token, $payment_hash);
|
||||
}
|
||||
catch(\Exception $e){
|
||||
nlog($e->getMessage());
|
||||
nlog("payment NOT captured for ". $this->invoice->number . " with error " . $e->getMessage());
|
||||
// nlog($e->getMessage());
|
||||
}
|
||||
|
||||
if($payment){
|
||||
|
@ -333,9 +333,10 @@ class InvoiceService
|
||||
|
||||
try{
|
||||
|
||||
Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf');
|
||||
if(Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf'))
|
||||
Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf');
|
||||
|
||||
if(Ninja::isHosted()) {
|
||||
if(Ninja::isHosted() && Storage::disk(config('filesystems.default'))->exists($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf')) {
|
||||
Storage::disk('public')->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf');
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,8 @@ class MarkSent extends AbstractService
|
||||
->service()
|
||||
->applyNumber()
|
||||
->setDueDate()
|
||||
->deletePdf()
|
||||
// ->deletePdf() //08-01-2022
|
||||
->touchPdf() //08-01-2022
|
||||
->setReminder()
|
||||
->save();
|
||||
|
||||
|
@ -49,6 +49,7 @@ class TriggeredActions extends AbstractService
|
||||
}
|
||||
|
||||
if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') {
|
||||
$this->invoice->service()->markSent()->touchPdf()->save();
|
||||
$this->sendEmail();
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ class TriggeredActions extends AbstractService
|
||||
{
|
||||
|
||||
if ($this->request->has('send_email') && $this->request->input('send_email') == 'true') {
|
||||
$this->quote = $this->quote->service()->markSent()->save();
|
||||
$this->sendEmail();
|
||||
}
|
||||
|
||||
|
@ -42,4 +42,5 @@ trait Uploadable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.41',
|
||||
'app_tag' => '5.3.41',
|
||||
'app_version' => '5.3.42',
|
||||
'app_tag' => '5.3.42',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
@ -24,7 +24,7 @@ class StripeConnectGateway extends Migration
|
||||
'provider' => 'StripeConnect',
|
||||
'sort_order' => 1,
|
||||
'key' => 'd14dd26a47cecc30fdd65700bfb67b34',
|
||||
'fields' => '{"account_id":""}'
|
||||
'fields' => '{"account_id":"","appleDomainVerification":""}'
|
||||
];
|
||||
|
||||
Gateway::create($gateway);
|
||||
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Gateway;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddAppDomainIdToGatewaysTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
|
||||
if(Ninja::isHosted()){
|
||||
|
||||
$stripe_connect = Gateway::find(56);
|
||||
|
||||
if($stripe_connect){
|
||||
$stripe_connect->fields = '{"account_id":"", "appleDomainVerification":""}';
|
||||
$stripe_connect->save();
|
||||
}
|
||||
}
|
||||
|
||||
$stripe_connect = Gateway::find(20);
|
||||
|
||||
if($stripe_connect){
|
||||
$stripe_connect->fields = '{"account_id":"", "appleDomainVerification":""}';
|
||||
$stripe_connect->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
}
|
@ -44,7 +44,7 @@ class PaymentLibrariesSeeder extends Seeder
|
||||
['id' => 17, 'name' => 'Pin', 'provider' => 'Pin', 'key' => '0749cb92a6b36c88bd9ff8aabd2efcab', 'fields' => '{"secretKey":"","testMode":false}'],
|
||||
['id' => 18, 'name' => 'SagePay Direct', 'provider' => 'SagePay_Direct', 'key' => '4c8f4e5d0f353a122045eb9a60cc0f2d', 'fields' => '{"vendor":"","testMode":false,"referrerId":""}'],
|
||||
['id' => 19, 'name' => 'SecurePay DirectPost', 'provider' => 'SecurePay_DirectPost', 'key' => '8036a5aadb2bdaafb23502da8790b6a2', 'fields' => '{"merchantId":"","transactionPassword":"","testMode":false,"enable_ach":"","enable_sofort":"","enable_apple_pay":"","enable_alipay":""}'],
|
||||
['id' => 20, 'name' => 'Stripe', 'provider' => 'Stripe', 'sort_order' => 1, 'key' => 'd14dd26a37cecc30fdd65700bfb55b23', 'fields' => '{"publishableKey":"","apiKey":""}'],
|
||||
['id' => 20, 'name' => 'Stripe', 'provider' => 'Stripe', 'sort_order' => 1, 'key' => 'd14dd26a37cecc30fdd65700bfb55b23', 'fields' => '{"publishableKey":"","apiKey":"","appleDomainVerification":""}'],
|
||||
['id' => 21, 'name' => 'TargetPay Direct eBanking', 'provider' => 'TargetPay_Directebanking', 'key' => 'd14dd26a37cdcc30fdd65700bfb55b23', 'fields' => '{"subAccountId":""}'],
|
||||
['id' => 22, 'name' => 'TargetPay Ideal', 'provider' => 'TargetPay_Ideal', 'key' => 'ea3b328bd72d381387281c3bd83bd97c', 'fields' => '{"subAccountId":""}'],
|
||||
['id' => 23, 'name' => 'TargetPay Mr Cash', 'provider' => 'TargetPay_Mrcash', 'key' => 'a0035fc0d87c4950fb82c73e2fcb825a', 'fields' => '{"subAccountId":""}'],
|
||||
|
@ -4342,7 +4342,7 @@ $LANG = array(
|
||||
'payment_type_instant_bank_pay' => 'Instant Bank Pay',
|
||||
'payment_type_iDEAL' => 'iDEAL',
|
||||
'payment_type_Przelewy24' => 'Przelewy24',
|
||||
'payment_type_Mollie Bank Transfer' => 'Bank Transfer',
|
||||
'payment_type_Mollie Bank Transfer' => 'Mollie Bank Transfer',
|
||||
'payment_type_KBC/CBC' => 'KBC/CBC',
|
||||
'payment_type_Instant Bank Pay' => 'Instant Bank Pay',
|
||||
'payment_type_Hosted Page' => 'Hosted Page',
|
||||
|
@ -117,17 +117,22 @@
|
||||
[data-ref="table"] > tbody > tr > td {
|
||||
border-top: 1px solid #d8d8d8;
|
||||
border-bottom: 1px solid #d8d8d8;
|
||||
padding: 1.5rem;
|
||||
padding: 1.5rem 1rem;
|
||||
}
|
||||
|
||||
[data-ref="table"] > tbody > tr > td:first-child {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
[data-ref="table"] > thead > tr > th:last-child,
|
||||
[data-ref="table"] > tbody > tr > td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[data-ref="table"] > thead > tr > th:last-child {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
[data-ref="table"] > tbody > tr:nth-child(odd) {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
@ -208,6 +208,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
||||
Route::resource('subscriptions', 'SubscriptionController');
|
||||
Route::post('subscriptions/bulk', 'SubscriptionController@bulk')->name('subscriptions.bulk');
|
||||
Route::get('statics', 'StaticController');
|
||||
Route::post('apple_pay/upload_file','ApplyPayController@upload');
|
||||
|
||||
});
|
||||
|
||||
|
@ -44,3 +44,4 @@ Route::get('stripe/completed', 'StripeConnectController@completed')->name('strip
|
||||
Route::get('checkout/3ds_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\Checkout3dsController@index')->name('checkout.3ds_redirect');
|
||||
Route::get('mollie/3ds_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\Mollie3dsController@index')->name('mollie.3ds_redirect');
|
||||
Route::get('gocardless/ibp_redirect/{company_key}/{company_gateway_id}/{hash}', 'Gateways\GoCardlessController@ibpRedirect')->name('gocardless.ibp_redirect');
|
||||
Route::get('.well-known/apple-developer-merchantid-domain-association', 'ClientPortal\ApplePayDomainController@showAppleMerchantId');
|
||||
|
92
tests/Feature/ApplePayDomainMerchantUrlTest.php
Normal file
92
tests/Feature/ApplePayDomainMerchantUrlTest.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?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;
|
||||
|
||||
use App\Models\CompanyGateway;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Http\Controllers\ApplePayDomainController
|
||||
*/
|
||||
class ApplePayDomainMerchantUrlTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
use MockAccountData;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
$this->withoutMiddleware(
|
||||
ThrottleRequests::class
|
||||
);
|
||||
}
|
||||
|
||||
public function testMerchantFieldGet()
|
||||
{
|
||||
|
||||
if (! config('ninja.testvars.stripe')) {
|
||||
$this->markTestSkipped('Skip test no company gateways installed');
|
||||
}
|
||||
|
||||
$config = new \stdClass;
|
||||
$config->publishableKey = "pk_test";
|
||||
$config->apiKey = "sk_test";
|
||||
$config->appleDomainVerification = "merchant_id";
|
||||
|
||||
$cg = new CompanyGateway;
|
||||
$cg->company_id = $this->company->id;
|
||||
$cg->user_id = $this->user->id;
|
||||
$cg->gateway_key = 'd14dd26a37cecc30fdd65700bfb55b23';
|
||||
$cg->require_cvv = true;
|
||||
$cg->require_billing_address = true;
|
||||
$cg->require_shipping_address = true;
|
||||
$cg->update_details = true;
|
||||
$cg->config = encrypt(json_encode($config));
|
||||
$cg->fees_and_limits = '';
|
||||
$cg->save();
|
||||
|
||||
$response = $this->withHeaders([])->get('.well-known/apple-developer-merchantid-domain-association');
|
||||
|
||||
$arr = $response->getContent();
|
||||
$response->assertStatus(200);
|
||||
$this->assertEquals("merchant_id", $arr);
|
||||
}
|
||||
|
||||
public function testDomainParsing()
|
||||
{
|
||||
$domain = 'http://ninja.test:8000';
|
||||
|
||||
$parsed = parse_url($domain);
|
||||
|
||||
$this->assertEquals('ninja.test', $parsed['host']);
|
||||
|
||||
$domain = 'ninja.test:8000';
|
||||
|
||||
$parsed = parse_url($domain);
|
||||
|
||||
$this->assertEquals('ninja.test', $parsed['host']);
|
||||
|
||||
$domain = 'http://ninja.test:8000/afadf/dfdfdf/dfdfasf';
|
||||
|
||||
$parsed = parse_url($domain);
|
||||
|
||||
$this->assertEquals('ninja.test', $parsed['host']);
|
||||
|
||||
|
||||
}
|
||||
}
|
78
tests/Feature/ClientDeletedInvoiceCreationTest.php
Normal file
78
tests/Feature/ClientDeletedInvoiceCreationTest.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?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;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Http\Controllers\InvoiceController
|
||||
*/
|
||||
class ClientDeletedInvoiceCreationTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use DatabaseTransactions;
|
||||
use MockAccountData;
|
||||
|
||||
public function setUp() :void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Session::start();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
Model::reguard();
|
||||
|
||||
$this->makeTestData();
|
||||
}
|
||||
|
||||
public function testClientedDeletedAttemptingToCreateInvoice()
|
||||
{
|
||||
/* Test fire new invoice */
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'number' => 'dude',
|
||||
];
|
||||
|
||||
$this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/invoices/', $data)
|
||||
->assertStatus(200);
|
||||
|
||||
$this->client->is_deleted = true;
|
||||
$this->client->save();
|
||||
|
||||
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'number' => 'dude2',
|
||||
];
|
||||
|
||||
$this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/invoices/', $data)
|
||||
->assertStatus(302);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -319,6 +319,71 @@ class CompanyGatewayApiTest extends TestCase
|
||||
$this->assertEquals(10.2, $company_gateway->calcGatewayFee(10, GatewayType::CREDIT_CARD));
|
||||
}
|
||||
|
||||
|
||||
public function testFeesAndLimitsFeePercentAndAmountCalcuationOneHundredPercent()
|
||||
{
|
||||
//{"1":{"min_limit":1,"max_limit":1000000,"fee_amount":10,"fee_percent":2,"fee_tax_name1":"","fee_tax_name2":"","fee_tax_name3":"","fee_tax_rate1":0,"fee_tax_rate2":0,"fee_tax_rate3":0,"fee_cap":10,"adjust_fee_percent":true}}
|
||||
$fee = new FeesAndLimits;
|
||||
$fee->fee_amount = 0;
|
||||
$fee->fee_percent = 100;
|
||||
// $fee->fee_tax_name1 = 'GST';
|
||||
// $fee->fee_tax_rate1 = '10.0';
|
||||
|
||||
$fee_arr[1] = (array) $fee;
|
||||
|
||||
$data = [
|
||||
'config' => 'random config',
|
||||
'gateway_key' => '3b6621f970ab18887c4f6dca78d3f8bb',
|
||||
'fees_and_limits' => $fee_arr,
|
||||
];
|
||||
|
||||
/* POST */
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/company_gateways', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
$id = $this->decodePrimaryKey($arr['data']['id']);
|
||||
|
||||
$company_gateway = CompanyGateway::find($id);
|
||||
|
||||
$this->assertEquals(10, $company_gateway->calcGatewayFee(10, GatewayType::CREDIT_CARD));
|
||||
}
|
||||
|
||||
public function testFeesAndLimitsFeePercentAndAmountCalcuationOneHundredPercentVariationOne()
|
||||
{
|
||||
$fee = new FeesAndLimits;
|
||||
$fee->fee_amount = 0;
|
||||
$fee->fee_percent = 10;
|
||||
|
||||
$fee_arr[1] = (array) $fee;
|
||||
|
||||
$data = [
|
||||
'config' => 'random config',
|
||||
'gateway_key' => '3b6621f970ab18887c4f6dca78d3f8bb',
|
||||
'fees_and_limits' => $fee_arr,
|
||||
];
|
||||
|
||||
/* POST */
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/company_gateways', $data);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$arr = $response->json();
|
||||
$id = $this->decodePrimaryKey($arr['data']['id']);
|
||||
|
||||
$company_gateway = CompanyGateway::find($id);
|
||||
|
||||
$this->assertEquals(1, $company_gateway->calcGatewayFee(10, GatewayType::CREDIT_CARD));
|
||||
}
|
||||
|
||||
|
||||
public function testFeesAndLimitsFeePercentAndAmountAndTaxCalcuation()
|
||||
{
|
||||
//{"1":{"min_limit":1,"max_limit":1000000,"fee_amount":10,"fee_percent":2,"fee_tax_name1":"","fee_tax_name2":"","fee_tax_name3":"","fee_tax_rate1":0,"fee_tax_rate2":0,"fee_tax_rate3":0,"fee_cap":10,"adjust_fee_percent":true}}
|
||||
|
@ -220,4 +220,19 @@ class InvoiceTest extends TestCase
|
||||
])->put('/api/v1/invoices/'.$arr['data']['id'], $data)
|
||||
->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testClientedDeletedAttemptingToCreateInvoice()
|
||||
{
|
||||
/* Test fire new invoice */
|
||||
$data = [
|
||||
'client_id' => $this->client->hashed_id,
|
||||
'number' => 'dude',
|
||||
];
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/invoices/', $data)
|
||||
->assertStatus(200);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user