1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-11 05:32:39 +01:00

Merge pull request #8994 from turbo124/v5-develop

PayPal PPCP
This commit is contained in:
David Bomba 2023-11-26 16:30:42 +11:00 committed by GitHub
commit d726f85689
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 1730 additions and 291 deletions

View File

@ -25,6 +25,7 @@ use App\Models\Account;
use App\Models\Company; use App\Models\Company;
use App\Models\Country; use App\Models\Country;
use App\Models\Expense; use App\Models\Expense;
use App\Models\Gateway;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Product; use App\Models\Product;
use App\Models\Project; use App\Models\Project;

View File

@ -92,6 +92,11 @@ class EmailTemplateDefaults
case 'email_subject_custom3': case 'email_subject_custom3':
return self::emailInvoiceSubject(); return self::emailInvoiceSubject();
case 'email_vendor_notification_subject':
return self::emailVendorNotificationSubject();
case 'email_vendor_notification_body':
return self::emailVendorNotificationBody();
default: default:
return self::emailInvoiceTemplate(); return self::emailInvoiceTemplate();
@ -99,6 +104,16 @@ class EmailTemplateDefaults
} }
} }
public static function emailVendorNotificationSubject()
{
return self::transformText('vendor_notification_subject');
}
public static function emailVendorNotificationBody()
{
return self::transformText('vendor_notification_body');
}
public static function emailInvoiceSubject() public static function emailInvoiceSubject()
{ {
return ctrans('texts.invoice_subject', ['number'=>'$number', 'account'=>'$company.name']); return ctrans('texts.invoice_subject', ['number'=>'$number', 'account'=>'$company.name']);

View File

@ -11,16 +11,17 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Libraries\MultiDB;
use App\Models\Client;
use App\Models\Company;
use App\Transformers\ClientContactTransformer;
use App\Transformers\ClientTransformer;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Number; use App\Utils\Number;
use Illuminate\Database\Eloquent\Builder; use App\Models\Client;
use Illuminate\Support\Facades\App;
use League\Csv\Writer; use League\Csv\Writer;
use App\Models\Company;
use App\Libraries\MultiDB;
use Illuminate\Support\Facades\App;
use App\Export\Decorators\Decorator;
use App\Transformers\ClientTransformer;
use Illuminate\Database\Eloquent\Builder;
use App\Transformers\ClientContactTransformer;
class ClientExport extends BaseExport class ClientExport extends BaseExport
{ {
@ -32,6 +33,8 @@ class ClientExport extends BaseExport
public string $date_key = 'created_at'; public string $date_key = 'created_at';
private Decorator $decorator;
public array $entity_keys = [ public array $entity_keys = [
'address1' => 'client.address1', 'address1' => 'client.address1',
'address2' => 'client.address2', 'address2' => 'client.address2',
@ -84,6 +87,8 @@ class ClientExport extends BaseExport
$this->input = $input; $this->input = $input;
$this->client_transformer = new ClientTransformer(); $this->client_transformer = new ClientTransformer();
$this->contact_transformer = new ClientContactTransformer(); $this->contact_transformer = new ClientContactTransformer();
$this->decorator = new Decorator();
} }
public function returnJson() public function returnJson()

View File

@ -11,14 +11,15 @@
namespace App\Export\CSV; namespace App\Export\CSV;
use App\Libraries\MultiDB; use App\Utils\Ninja;
use League\Csv\Writer;
use App\Models\Company; use App\Models\Company;
use App\Models\Payment; use App\Models\Payment;
use App\Transformers\PaymentTransformer; use App\Libraries\MultiDB;
use App\Utils\Ninja;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use League\Csv\Writer; use App\Transformers\PaymentTransformer;
use Illuminate\Database\Eloquent\Builder;
use App\Export\Decorators\Decorator;
class PaymentExport extends BaseExport class PaymentExport extends BaseExport
{ {
@ -28,11 +29,14 @@ class PaymentExport extends BaseExport
public Writer $csv; public Writer $csv;
private Decorator $decorator;
public function __construct(Company $company, array $input) public function __construct(Company $company, array $input)
{ {
$this->company = $company; $this->company = $company;
$this->input = $input; $this->input = $input;
$this->entity_transformer = new PaymentTransformer(); $this->entity_transformer = new PaymentTransformer();
$this->decorator = new Decorator();
} }
private function init(): Builder private function init(): Builder
@ -113,6 +117,8 @@ class PaymentExport extends BaseExport
} elseif (array_key_exists($key, $transformed_entity)) { } elseif (array_key_exists($key, $transformed_entity)) {
$entity[$key] = $transformed_entity[$key]; $entity[$key] = $transformed_entity[$key];
} else { } else {
// $entity[$key] = $this->decorator->transform($key, $payment);
$entity[$key] = $this->resolveKey($key, $payment, $this->entity_transformer); $entity[$key] = $this->resolveKey($key, $payment, $this->entity_transformer);
} }

View File

@ -11,10 +11,165 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
class ClientDecorator implements DecoratorInterface use App\Models\Client;
class ClientDecorator extends Decorator implements DecoratorInterface
{ {
public function transform(): string private $entity_key = 'client';
public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; $client = false;
if($entity instanceof Client){
$client = $entity;
}
elseif($entity->client) {
$client = $entity->client;
}
if($client && method_exists($this, $key)) {
return $this->{$key}($client);
}
return '';
} }
public function name(Client $client) {
return $client->present()->name();
}
public function number(Client $client) {
return $client->number ?? '';
}
public function user(Client $client) {
return $client->user->present()->name();
}
public function assigned_user(Client $client) {
return $client->assigned_user ? $client->user->present()->name() : '';
}
public function balance(Client $client) {
return $client->balance ?? 0;
}
public function paid_to_date(Client $client) {
return $client->paid_to_date ?? 0;
}
public function currency_id(Client $client) {
return $client->currency() ? $client->currency()->code : $client->company->currency()->code;
}
public function website(Client $client) {
return $client->website ?? '';
}
public function private_notes(Client $client) {
return $client->private_notes ?? '';
}
public function industry_id(Client $client) {
return $client->industry ? ctrans("texts.industry_{$client->industry->name}") : '';
}
public function size_id(Client $client) {
return $client->size ? ctrans("texts.size_{$client->size->name}") : '';
}
public function phone(Client $client) {
return $client->phone ?? '';
}
public function address1(Client $client) {
return $client->address1 ?? '';
}
public function address2(Client $client) {
return $client->address2 ?? '';
}
public function city(Client $client) {
return $client->city ?? '';
}
public function state(Client $client) {
return $client->state ?? '';
}
public function postal_code(Client $client) {
return $client->postal_code ?? '';
}
public function country_id(Client $client) {
return $client->country ? ctrans("texts.country_{$client->country->name}") : '';
}
public function shipping_address1(Client $client) {
return $client->shipping_address1 ?? '';
}
public function shipping_address2(Client $client) {
return $client->shipping_address2 ?? '';
}
public function shipping_city(Client $client) {
return $client->shipping_city ?? '';
}
public function shipping_state(Client $client) {
return $client->shipping_state ?? '';
}
public function shipping_postal_code(Client $client) {
return $client->shipping_postal_code ?? '';
}
public function shipping_country_id(Client $client) {
return $client->shipping_country ? ctrans("texts.country_{$client->shipping_country->name}") : '';
}
public function payment_terms(Client $client) {
return $client?->settings?->payment_terms ?? $client->company->settings->payment_terms;
}
public function vat_number(Client $client) {
return $client->vat_number ?? '';
}
public function id_number(Client $client) {
return $client->id_number ?? '';
}
public function public_notes(Client $client) {
return $client->public_notes ?? '';
}
public function custom_value1(Client $client) {
return $client->custom_value1 ?? '';
}
public function custom_value2(Client $client) {
return $client->custom_value2 ?? '';
}
public function custom_value3(Client $client) {
return $client->custom_value3 ?? '';
}
public function custom_value4(Client $client) {
return $client->custom_value4 ?? '';
}
public function payment_balance(Client $client) {
return $client->payment_balance ?? 0;
}
public function credit_balance(Client $client) {
return $client->credit_balance ?? 0;
}
public function classification(Client $client) {
ctrans("texts.{$client->classification}") ?? '';
}
////////contact details/////////////////
/*
public function phone(Client $client) {
}
public function first_name(Client $client) {
}
public function last_name(Client $client) {
}
public function email(Client $client) {
}
public function custom_value1(Client $client) {
}
public function custom_value2(Client $client) {
}
public function custom_value3(Client $client) {
}
public function custom_value4(Client $client) {
}
*/
} }

View File

@ -0,0 +1,20 @@
<?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\Export\Decorators;
class ContactDecorator implements DecoratorInterface
{
public function transform(string $key, mixed $entity): mixed
{
return 'Payment Decorator';
}
}

View File

@ -13,7 +13,7 @@ namespace App\Export\Decorators;
class CreditDecorator implements DecoratorInterface class CreditDecorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -24,28 +24,97 @@ use App\Models\Product;
use App\Models\Project; use App\Models\Project;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\Export\Decorators\DecoratorInterface;
class Decorator { class Decorator implements DecoratorInterface{
public function __invoke(mixed $entity, string $key) public function __construct()
{ {
return match($entity){
($entity instanceof Client) => $value = (new ClientDecorator($entity, $key))->transform(),
($entity instanceof Payment) => $value = (new PaymentDecorator($entity, $key))->transform(),
($entity instanceof Invoice) => $value = (new InvoiceDecorator($entity, $key))->transform(),
($entity instanceof RecurringInvoice) => $value = (new RecurringInvoiceDecorator($entity, $key))->transform(),
($entity instanceof Credit) => $value = (new CreditDecorator($entity, $key))->transform(),
($entity instanceof Quote) => $value = (new QuoteDecorator($entity, $key))->transform(),
($entity instanceof Task) => $value = (new TaskDecorator($entity, $key))->transform(),
($entity instanceof Expense) => $value = (new ExpenseDecorator($entity, $key))->transform(),
($entity instanceof Project) => $value = (new ProjectDecorator($entity, $key))->transform(),
($entity instanceof Product) => $value = (new ProductDecorator($entity, $key))->transform(),
($entity instanceof Vendor) => $value = (new VendorDecorator($entity, $key))->transform(),
($entity instanceof PurchaseOrder) => $value = (new PurchaseOrderDecorator($entity, $key))->transform(),
default => $value = '',
};
return $value;
} }
public function transform(string $key, mixed $entity): mixed
{
$index = $this->getKeyPart(0, $key);
$column = $this->getKeyPart(1, $key);
return $this->{$index}()->transform($column, $entity);
}
public function invoice(): InvoiceDecorator
{
return new InvoiceDecorator();
}
public function client(): ClientDecorator
{
return new ClientDecorator();
}
public function contact(): ContactDecorator
{
return new ContactDecorator();
}
public function vendor_contact(): VendorContactDecorator
{
return new VendorContactDecorator();
}
public function payment(): PaymentDecorator
{
return new PaymentDecorator();
}
public function credit(): CreditDecorator
{
return new CreditDecorator();
}
public function vendor(): VendorDecorator
{
return new VendorDecorator();
}
public function expense(): ExpenseDecorator
{
return new ExpenseDecorator();
}
public function product(): ProductDecorator
{
return new ProductDecorator();
}
public function project(): ProjectDecorator
{
return new ProjectDecorator();
}
public function task(): TaskDecorator
{
return new TaskDecorator();
}
public function quote(): QuoteDecorator
{
return new QuoteDecorator();
}
public function recurring_invoice(): RecurringInvoiceDecorator
{
return new RecurringInvoiceDecorator();
}
public function purchase_order(): PurchaseOrderDecorator
{
return new PurchaseOrderDecorator();
}
public function getKeyPart(int $index, string $key): string
{
$parts = explode('.', $key);
return $parts[$index];
}
} }

View File

@ -12,5 +12,5 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
interface DecoratorInterface { interface DecoratorInterface {
public function transform(): string; public function transform(string $key, mixed $entity): mixed;
} }

View File

@ -13,7 +13,7 @@ namespace App\Export\Decorators;
class ExpenseDecorator implements DecoratorInterface class ExpenseDecorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -11,9 +11,9 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
class InvoiceDecorator implements DecoratorInterface class InvoiceDecorator extends Decorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -11,10 +11,132 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
class PaymentDecorator implements DecoratorInterface{ use App\Models\Payment;
public function transform(): string class PaymentDecorator extends Decorator implements DecoratorInterface{
private $entity_key = 'payment';
public function transform(string $key, $entity): mixed
{ {
return 'Payment Decorator'; $payment = false;
if($entity instanceof Payment){
$payment = $entity;
}
elseif($entity->payment) {
$payment = $entity->payment;
}
if($key == 'amount' && (!$entity instanceof Payment)){
return $entity->payments()->exists() ? $entity->payments()->withoutTrashed()->sum('paymentables.amount') : ctrans('texts.unpaid');
}
elseif($key == 'refunded' && (!$entity instanceof Payment)) {
return $entity->payments()->exists() ? $entity->payments()->withoutTrashed()->sum('paymentables.refunded') : '';
}
elseif($key == 'applied' && (!$entity instanceof Payment)) {
$refunded = $entity->payments()->withoutTrashed()->sum('paymentables.refunded');
$amount = $entity->payments()->withoutTrashed()->sum('paymentables.amount');
return $entity->payments()->withoutTrashed()->exists() ? ($amount - $refunded) : '';
}
if($payment && method_exists($this, $key)) {
return $this->{$key}($payment);
}
return '';
} }
public function date(Payment $payment) {
return $payment->date ?? '';
}
public function amount(Payment $payment) {
return $payment->amount ?? '';
}
public function refunded(Payment $payment) {
return $payment->refunded ?? '';
}
public function applied(Payment $payment) {
return $payment->applied ?? '';
}
public function transaction_reference(Payment $payment) {
return $payment->transaction_reference ?? '';
}
public function currency(Payment $payment) {
return $payment->currency()->exists() ? $payment->currency->code : $payment->company->currency()->code;
}
public function exchange_rate(Payment $payment) {
return $payment->exchange_rate ?? 1;
}
public function number(Payment $payment) {
return $payment->number ?? '';
}
public function method(Payment $payment) {
return $payment->translatedType();
}
public function status(Payment $payment) {
return $payment->stringStatus($payment->status_id);
}
public function private_notes(Payment $payment) {
return strip_tags($payment->private_notes) ?? '';
}
public function custom_value1(Payment $payment) {
return $payment->custom_value1 ?? '';
}
public function custom_value2(Payment $payment) {
return $payment->custom_value2 ?? '';
}
public function custom_value3(Payment $payment) {
return $payment->custom_value3 ?? '';
}
public function custom_value4(Payment $payment) {
return $payment->custom_value4 ?? '';
}
public function user_id(Payment $payment) {
return $payment->user ? $payment->user->present()->name() : '';
}
public function assigned_user_id(Payment $payment) {
return $payment->assigned_user ? $payment->assigned_user->present()->name() : '';
}
public function project_id(Payment $payment) {
return $payment->project()->exists() ? $payment->project->name : '';
}
///////////////////////////////////////////////////
public function vendor_id(Payment $payment){
return $payment->vendor()->exists() ? $payment->vendor->name : '';
}
public function exchange_currency(Payment $payment){
return $payment->exchange_currency()->exists() ? $payment->exchange_currency->code : '';
}
public function gateway_type_id(Payment $payment) {
return $payment->gateway_type ? $payment->gateway_type->name : 'Unknown Type';
}
public function client_id(Payment $payment) {
return $payment->client->present()->name();
}
public function type_id(Payment $payment) {
return $payment->translatedType();
}
} }

View File

@ -13,7 +13,7 @@ namespace App\Export\Decorators;
class ProductDecorator implements DecoratorInterface class ProductDecorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -13,7 +13,7 @@ namespace App\Export\Decorators;
class ProjectDecorator implements DecoratorInterface class ProjectDecorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -11,9 +11,9 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
class PurchaseOrderDecorator implements DecoratorInterface class PurchaseOrderDecorator extends Decorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -11,9 +11,9 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
class QuoteDecorator implements DecoratorInterface class QuoteDecorator extends Decorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -11,9 +11,9 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
class RecurringInvoiceDecorator implements DecoratorInterface class RecurringInvoiceDecorator extends Decorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -11,9 +11,9 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
class TaskDecorator implements DecoratorInterface class TaskDecorator extends Decorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -0,0 +1,20 @@
<?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\Export\Decorators;
class VendorContactDecorator implements DecoratorInterface
{
public function transform(string $key, mixed $entity): mixed
{
return 'Payment Decorator';
}
}

View File

@ -11,9 +11,9 @@
namespace App\Export\Decorators; namespace App\Export\Decorators;
class VendorDecorator implements DecoratorInterface class VendorDecorator extends Decorator implements DecoratorInterface
{ {
public function transform(): string public function transform(string $key, mixed $entity): mixed
{ {
return 'Payment Decorator'; return 'Payment Decorator';
} }

View File

@ -86,7 +86,10 @@ class NinjaPlanController extends Controller
public function trial_confirmation(Request $request) public function trial_confirmation(Request $request)
{ {
$trial_started = "Trial Started @ ".now()->format('Y-m-d H:i:s');
$client = auth()->guard('contact')->user()->client; $client = auth()->guard('contact')->user()->client;
$client->private_notes = $trial_started;
$client->fill($request->all()); $client->fill($request->all());
$client->save(); $client->save();
@ -150,6 +153,7 @@ class NinjaPlanController extends Controller
$account->plan_expires = now()->addDays(14); $account->plan_expires = now()->addDays(14);
$account->is_trial=true; $account->is_trial=true;
$account->hosted_company_count = 10; $account->hosted_company_count = 10;
$account->trial_started = now();
$account->save(); $account->save();
} }

View File

@ -194,21 +194,27 @@ class CompanyGatewayController extends BaseController
*/ */
public function store(StoreCompanyGatewayRequest $request) public function store(StoreCompanyGatewayRequest $request)
{ {
$company_gateway = CompanyGatewayFactory::create(auth()->user()->company()->id, auth()->user()->id); /** @var \App\Models\User $user */
$user = auth()->user();
$company_gateway = CompanyGatewayFactory::create($user->company()->id, $user->id);
$company_gateway->fill($request->all()); $company_gateway->fill($request->all());
$company_gateway->save(); $company_gateway->save();
/*Always ensure at least one fees and limits object is set per gateway*/ /*Always ensure at least one fees and limits object is set per gateway*/
if (! isset($company_gateway->fees_and_limits)) { $gateway_types = $company_gateway->driver(new Client)->getAvailableMethods();
$gateway_types = $company_gateway->driver(new Client)->gatewayTypes();
$fees_and_limits = new \stdClass; $fees_and_limits = $company_gateway->fees_and_limits;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
$company_gateway->fees_and_limits = $fees_and_limits; foreach($gateway_types as $key => $gateway_type)
$company_gateway->save(); {
if(!property_exists($fees_and_limits, $key))
$fees_and_limits->{$key} = new FeesAndLimits;
} }
$company_gateway->fees_and_limits = $fees_and_limits;
$company_gateway->save();
ApplePayDomain::dispatch($company_gateway, $company_gateway->company->db); ApplePayDomain::dispatch($company_gateway, $company_gateway->company->db);
if (in_array($company_gateway->gateway_key, $this->stripe_keys)) { if (in_array($company_gateway->gateway_key, $this->stripe_keys)) {
@ -381,10 +387,18 @@ class CompanyGatewayController extends BaseController
{ {
$company_gateway->fill($request->all()); $company_gateway->fill($request->all());
if (! $request->has('fees_and_limits')) { /*Always ensure at least one fees and limits object is set per gateway*/
$company_gateway->fees_and_limits = ''; $gateway_types = $company_gateway->driver(new Client)->getAvailableMethods();
$fees_and_limits = $company_gateway->fees_and_limits;
foreach($gateway_types as $key => $gateway_type) {
if(!property_exists($fees_and_limits, $key)) {
$fees_and_limits->{$key} = new FeesAndLimits;
}
} }
$company_gateway->fees_and_limits = $fees_and_limits;
$company_gateway->save(); $company_gateway->save();
if($company_gateway->gateway_key == $this->checkout_key) { if($company_gateway->gateway_key == $this->checkout_key) {

View File

@ -11,6 +11,7 @@
namespace App\Http\Requests\CompanyGateway; namespace App\Http\Requests\CompanyGateway;
use App\DataMapper\FeesAndLimits;
use App\Http\Requests\Request; use App\Http\Requests\Request;
use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule; use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule;
use App\Models\Gateway; use App\Models\Gateway;
@ -28,7 +29,10 @@ class StoreCompanyGatewayRequest extends Request
*/ */
public function authorize() : bool public function authorize() : bool
{ {
return auth()->user()->isAdmin(); /** @var \App\Models\User $user */
$user = auth()->user();
return $user->isAdmin();
} }
public function rules() public function rules()
@ -64,6 +68,7 @@ class StoreCompanyGatewayRequest extends Request
if (isset($input['fees_and_limits'])) { if (isset($input['fees_and_limits'])) {
$input['fees_and_limits'] = $this->cleanFeesAndLimits($input['fees_and_limits']); $input['fees_and_limits'] = $this->cleanFeesAndLimits($input['fees_and_limits']);
} }
} }
$this->replace($input); $this->replace($input);

View File

@ -27,7 +27,10 @@ class UpdateCompanyGatewayRequest extends Request
*/ */
public function authorize() public function authorize()
{ {
return auth()->user()->isAdmin(); /** @var \App\Models\User $user */
$user = auth()->user();
return $user->isAdmin();
} }
public function rules() public function rules()

View File

@ -92,6 +92,8 @@ class CreateAccount
$spaa9f78 = (new CreateUser($this->request, $sp794f3f, $sp035a66, true))->handle(); $spaa9f78 = (new CreateUser($this->request, $sp794f3f, $sp035a66, true))->handle();
$sp035a66->service()->localizeCompany($spaa9f78);
(new CreateCompanyPaymentTerms($sp035a66, $spaa9f78))->handle(); (new CreateCompanyPaymentTerms($sp035a66, $spaa9f78))->handle();
(new CreateCompanyTaskStatuses($sp035a66, $spaa9f78))->handle(); (new CreateCompanyTaskStatuses($sp035a66, $spaa9f78))->handle();
@ -124,8 +126,6 @@ class CreateAccount
NinjaMailerJob::dispatch($nmo, true); NinjaMailerJob::dispatch($nmo, true);
// \Modules\Admin\Jobs\Account\NinjaUser::dispatch([], $sp035a66);
(new \Modules\Admin\Jobs\Account\NinjaUser([], $sp035a66))->handle(); (new \Modules\Admin\Jobs\Account\NinjaUser([], $sp035a66))->handle();
} }

View File

@ -84,6 +84,7 @@ class CreateCompany
match($settings->country_id) { match($settings->country_id) {
'724' => $company = $this->spanishSetup($company), '724' => $company = $this->spanishSetup($company),
'36' => $company = $this->australiaSetup($company), '36' => $company = $this->australiaSetup($company),
'710' => $company = $this->southAfticaSetup($company),
default => $company->save(), default => $company->save(),
}; };
@ -103,7 +104,7 @@ class CreateCompany
if(request()->hasHeader('cf-ipcountry')) { if(request()->hasHeader('cf-ipcountry')) {
$c = Country::where('iso_3166_2', request()->header('cf-ipcountry'))->first(); $c = Country::query()->where('iso_3166_2', request()->header('cf-ipcountry'))->first();
if($c) { if($c) {
return (string)$c->id; return (string)$c->id;
@ -115,7 +116,7 @@ class CreateCompany
if($details && property_exists($details, 'countryCode')) { if($details && property_exists($details, 'countryCode')) {
$c = Country::where('iso_3166_2', $details->countryCode)->first(); $c = Country::query()->where('iso_3166_2', $details->countryCode)->first();
if($c) { if($c) {
return (string)$c->id; return (string)$c->id;
@ -153,15 +154,6 @@ class CreateCompany
$company->save(); $company->save();
//user does not exist yet.
// MultiDB::setDb($company->db);
// $user = \App\Models\User::where('account_id', $company->account_id)->first();
// $tax_rate = TaxRateFactory::create($company->id, $user->id);
// $tax_rate->name = $company->tax_data->regions->EU->subregions->ES->tax_name;
// $tax_rate->rate = $company->tax_data->regions->EU->subregions->ES->tax_rate;
// $tax_rate->save();
return $company; return $company;
} catch(\Exception $e) { } catch(\Exception $e) {
@ -174,6 +166,40 @@ class CreateCompany
} }
private function southAfticaSetup(Company $company): Company
{
try {
$company->enabled_item_tax_rates = 1;
$company->enabled_tax_rates = 1;
$translations = new \stdClass;
$translations->invoice = "Tax Invoice";
$settings = $company->settings;
$settings->currency_id = '4';
$settings->timezone_id = '56';
$settings->translations = $translations;
$company->settings = $settings;
$company->save();
return $company;
} catch(\Exception $e) {
nlog($e->getMessage());
nlog("SETUP: could not complete setup for South African Locale");
}
$company->save();
return $company;
}
private function australiaSetup(Company $company): Company private function australiaSetup(Company $company): Company
{ {
try { try {
@ -193,17 +219,6 @@ class CreateCompany
$company->save(); $company->save();
//$user = $company->account->users()->first();
//user does not exist yet.
// MultiDB::setDb($company->db);
// $user = \App\Models\User::where('account_id', $company->account_id)->first();
// $tax_rate = TaxRateFactory::create($company->id, $user->id);
// $tax_rate->name = $company->tax_data->regions->AU->subregions->AU->tax_name;
// $tax_rate->rate = $company->tax_data->regions->AU->subregions->AU->tax_rate;
// $tax_rate->save();
return $company; return $company;
} catch(\Exception $e) { } catch(\Exception $e) {

View File

@ -0,0 +1,99 @@
<?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\Jobs\Expense;
use App\Utils\Ninja;
use App\Utils\Number;
use App\Models\Expense;
use App\Models\Activity;
use App\Libraries\MultiDB;
use App\Models\VendorContact;
use App\Services\Email\Email;
use Illuminate\Bus\Queueable;
use App\Services\Email\EmailObject;
use Illuminate\Queue\SerializesModels;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesDates;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class VendorExpenseNotify implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesDates;
public $tries = 1;
public function __construct(private Expense $expense, private string $db)
{
}
public function handle()
{
MultiDB::setDB($this->db);
$this->expense->vendor->contacts->filter(function(VendorContact $contact){
return $contact->send_email && $contact->email;
})->each(function(VendorContact $contact){
$this->notify($contact);
});
}
private function notify(VendorContact $contact)
{
$mo = new EmailObject;
$mo->contact = $contact;
$mo->vendor_contact_id = $contact->id;
$mo->user_id = $this->expense->user_id;
$mo->company_key = $this->expense->company->company_key;
$mo->subject = ctrans('texts.vendor_notification_subject', [
'amount' => Number::formatMoney($this->expense->amount, $contact->vendor),
'vendor' => $contact->vendor->present()->name(),
]);
$mo->body = ctrans('texts.vendor_notification_body', [
'vendor' => $this->expense->vendor->present()->name(),
'amount' => Number::formatMoney($this->expense->amount, $contact->vendor),
'contact' => $contact->present()->name(),
'payment_date' => $this->translateDate($this->expense->payment_date, $this->expense->company->date_format(), $this->expense->vendor->locale()),
'transaction_reference' => $this->expense->transaction_reference ?? '',
'number' => $this->expense->number,
]);
$mo->template = '';
$mo->email_template_body = 'vendor_notification_subject';
$mo->email_template_subject = 'vendor_notification_body';
$mo->vendor_id = $contact->vendor_id ?? null;
$mo->variables = [
'amount' => Number::formatMoney($this->expense->amount, $contact->vendor),
'contact' => $contact->present()->name(),
'vendor' => $contact->vendor->present()->name(),
'payment_date' => $this->translateDate($this->expense->payment_date, $this->expense->company->date_format(), $this->expense->vendor->locale()),
'transaction_reference' => $this->expense->transaction_reference ?? '',
'number' => $this->expense->number,
];
Email::dispatch($mo, $this->expense->company);
$fields = new \stdClass();
$fields->expense_id = $this->expense->id;
$fields->vendor_id = $contact->vendor_id;
$fields->vendor_contact_id = $contact->id;
$fields->user_id = $this->expense->user_id;
$fields->company_id = $contact->company_id;
$fields->activity_type_id = Activity::VENDOR_NOTIFICATION_EMAIL;
$fields->account_id = $this->expense->company->account_id;
$activity_repo = new ActivityRepository();
$activity_repo->save($fields, $this->expense, Ninja::eventVars());
}
}

View File

@ -0,0 +1,43 @@
<?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\Listeners;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Http\Client\Events\RequestSending;
use Illuminate\Queue\SerializesModels;
class LogRequestSending
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
public function handle(RequestSending $event)
{
nlog("Request");
nlog($event->request->headers());
nlog($event->request->url());
nlog(json_encode($event->request->headers()));
nlog($event->request->body());
}
}

View File

@ -0,0 +1,56 @@
<?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\Listeners;
use App\Utils\Ninja;
use App\Libraries\MultiDB;
use App\Mail\User\UserAdded;
use Illuminate\Support\Carbon;
use App\Jobs\Mail\NinjaMailerJob;
use Illuminate\Support\Facades\App;
use App\Jobs\Mail\NinjaMailerObject;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Http\Client\Events\ResponseReceived;
class LogResponseReceived
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
public function handle(ResponseReceived $event)
{
nlog("Request");
nlog($event->request->headers());
nlog($event->request->url());
nlog(json_encode($event->request->headers()));
nlog($event->request->body());
nlog("Response");
nlog($event->response->headers());
nlog(json_encode($event->response->headers()));
nlog($event->response->body());
nlog($event->response->json());
}
}

View File

@ -257,6 +257,8 @@ class Activity extends StaticModel
const PAYMENT_EMAILED = 138; const PAYMENT_EMAILED = 138;
const VENDOR_NOTIFICATION_EMAIL = 139;
protected $casts = [ protected $casts = [
'is_system' => 'boolean', 'is_system' => 'boolean',
'updated_at' => 'timestamp', 'updated_at' => 'timestamp',

View File

@ -23,6 +23,7 @@ use Laracasts\Presenter\PresentableTrait;
use App\Utils\Traits\CompanySettingsSaver; use App\Utils\Traits\CompanySettingsSaver;
use Illuminate\Notifications\Notification; use Illuminate\Notifications\Notification;
use App\Models\Presenters\CompanyPresenter; use App\Models\Presenters\CompanyPresenter;
use App\Services\Company\CompanyService;
use App\Services\Notification\NotificationService; use App\Services\Notification\NotificationService;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -974,4 +975,9 @@ class Company extends BaseModel
return $this->e_invoice_certificate_passphrase; return $this->e_invoice_certificate_passphrase;
} }
public function service(): CompanyService
{
return new CompanyService($this);
}
} }

View File

@ -117,7 +117,6 @@ class CompanyGateway extends BaseModel
16 => ['card' => 'images/credit_cards/Test-Discover-Icon.png', 'text' => 'Discover'], 16 => ['card' => 'images/credit_cards/Test-Discover-Icon.png', 'text' => 'Discover'],
]; ];
// const TYPE_PAYPAL = 300; // const TYPE_PAYPAL = 300;
// const TYPE_STRIPE = 301; // const TYPE_STRIPE = 301;
// const TYPE_LEDGER = 302; // const TYPE_LEDGER = 302;
@ -132,6 +131,7 @@ class CompanyGateway extends BaseModel
// const TYPE_MOLLIE = 312; // const TYPE_MOLLIE = 312;
// const TYPE_EWAY = 313; // const TYPE_EWAY = 313;
// const TYPE_FORTE = 314; // const TYPE_FORTE = 314;
// const PAYPAL_PPCP = 323;
public $gateway_consts = [ public $gateway_consts = [
'38f2c48af60c7dd69e04248cbb24c36e' => 300, '38f2c48af60c7dd69e04248cbb24c36e' => 300,
@ -150,6 +150,7 @@ class CompanyGateway extends BaseModel
'65faab2ab6e3223dbe848b1686490baz' => 320, '65faab2ab6e3223dbe848b1686490baz' => 320,
'b9886f9257f0c6ee7c302f1c74475f6c' => 321, 'b9886f9257f0c6ee7c302f1c74475f6c' => 321,
'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9' => 322, 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9' => 322,
'80af24a6a691230bbec33e930ab40666' => 323,
]; ];
protected $touches = []; protected $touches = [];

View File

@ -90,7 +90,7 @@ class Gateway extends StaticModel
if ($this->id == 1) { if ($this->id == 1) {
$link = 'http://reseller.authorize.net/application/?id=5560364'; $link = 'http://reseller.authorize.net/application/?id=5560364';
} elseif ($this->id == 15) { } elseif (in_array($this->id,[15,60,61])) {
$link = 'https://www.paypal.com/us/cgi-bin/webscr?cmd=_login-api-run'; $link = 'https://www.paypal.com/us/cgi-bin/webscr?cmd=_login-api-run';
} elseif ($this->id == 24) { } elseif ($this->id == 24) {
$link = 'https://www.2checkout.com/referral?r=2c37ac2298'; $link = 'https://www.2checkout.com/referral?r=2c37ac2298';
@ -202,7 +202,19 @@ class Gateway extends StaticModel
// GatewayType::PRZELEWY24 => ['refund' => false, 'token_billing' => false], // GatewayType::PRZELEWY24 => ['refund' => false, 'token_billing' => false],
// GatewayType::SOFORT => ['refund' => false, 'token_billing' => false], // GatewayType::SOFORT => ['refund' => false, 'token_billing' => false],
]; //Paypal ]; //Paypal
case 61:
return [
GatewayType::PAYPAL => ['refund' => false, 'token_billing' => false],
GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false],
GatewayType::VENMO => ['refund' => false, 'token_billing' => false],
// GatewayType::SEPA => ['refund' => false, 'token_billing' => false],
// GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false],
// GatewayType::EPS => ['refund' => false, 'token_billing' => false],
// GatewayType::MYBANK => ['refund' => false, 'token_billing' => false],
// GatewayType::PAYLATER => ['refund' => false, 'token_billing' => false],
// GatewayType::PRZELEWY24 => ['refund' => false, 'token_billing' => false],
// GatewayType::SOFORT => ['refund' => false, 'token_billing' => false],
]; //Paypal PPCP
default: default:
return []; return [];
} }

View File

@ -110,6 +110,11 @@ class ClientPresenter extends EntityPresenter
return $str; return $str;
} }
public function shipping_country_code(): string
{
return $this->entity->shipping_country ? $this->entity->shipping_country->iso_3166_2 : $this->entity->country->iso_3166_2;
}
public function phone() public function phone()
{ {
return $this->entity->phone ?: ''; return $this->entity->phone ?: '';

View File

@ -148,6 +148,8 @@ class SystemLog extends Model
const TYPE_RAZORPAY = 322; const TYPE_RAZORPAY = 322;
const TYPE_PAYPAL_PPCP = 323;
const TYPE_QUOTA_EXCEEDED = 400; const TYPE_QUOTA_EXCEEDED = 400;
const TYPE_UPSTREAM_FAILURE = 401; const TYPE_UPSTREAM_FAILURE = 401;

View File

@ -13,6 +13,7 @@ namespace App\Models;
use App\DataMapper\CompanySettings; use App\DataMapper\CompanySettings;
use App\Models\Presenters\VendorPresenter; use App\Models\Presenters\VendorPresenter;
use App\Services\Vendor\VendorService;
use App\Utils\Traits\AppSetup; use App\Utils\Traits\AppSetup;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -280,4 +281,9 @@ class Vendor extends BaseModel
{ {
return $this->company->company_key.'/'.$this->vendor_hash.'/backups'; return $this->company->company_key.'/'.$this->vendor_hash.'/backups';
} }
public function service()
{
return new VendorService($this);
}
} }

View File

@ -108,6 +108,11 @@ class BaseDriver extends AbstractPaymentDriver
return $this; return $this;
} }
public function getAvailableMethods(): array
{
return self::$methods;
}
/** /**
* Required fields for client to fill, to proceed with gateway actions. * Required fields for client to fill, to proceed with gateway actions.
* *

View File

@ -263,6 +263,16 @@ class CreditCard implements MethodInterface
if (is_array($error_details)) { if (is_array($error_details)) {
$error_details = end($e->error_details['error_codes']); $error_details = end($e->error_details['error_codes']);
SystemLogger::dispatch(
$error_details,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_ERROR,
SystemLog::TYPE_CHECKOUT,
$this->checkout->client,
$this->checkout->client->company,
);
} }
$this->checkout->unWindGatewayFees($this->checkout->payment_hash); $this->checkout->unWindGatewayFees($this->checkout->payment_hash);
@ -294,7 +304,7 @@ class CreditCard implements MethodInterface
); );
return new PaymentFailed($e->getMessage(), $e->getCode()); return new PaymentFailed($e->getMessage(), $e->getCode());
// return $this->checkout->processInternallyFailedPayment($this->checkout, $human_exception);
} catch (CheckoutAuthorizationException $e) { } catch (CheckoutAuthorizationException $e) {
// Bad Invalid authorization // Bad Invalid authorization

View File

@ -415,7 +415,8 @@ class CheckoutComPaymentDriver extends BaseDriver
SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_CHECKOUT, SystemLog::TYPE_CHECKOUT,
$this->client $this->client,
$this->client->company,
); );
return $payment; return $payment;
@ -436,7 +437,8 @@ class CheckoutComPaymentDriver extends BaseDriver
SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_CHECKOUT, SystemLog::TYPE_CHECKOUT,
$this->client $this->client,
$this->client->company
); );
return false; return false;

View File

@ -0,0 +1,484 @@
<?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\PaymentDrivers;
use App\Exceptions\PaymentFailed;
use App\Jobs\Util\SystemLogger;
use App\Models\GatewayType;
use App\Models\Invoice;
use App\Models\PaymentType;
use App\Models\SystemLog;
use App\Utils\Traits\MakesHash;
use Carbon\Carbon;
use Illuminate\Support\Facades\Http;
use Omnipay\Omnipay;
use Str;
class PayPalPPCPPaymentDriver extends BaseDriver
{
use MakesHash;
public $token_billing = false;
public $can_authorise_credit_card = false;
private $omnipay_gateway;
private float $fee = 0;
public const SYSTEM_LOG_TYPE = SystemLog::TYPE_PAYPAL_PPCP;
private string $api_endpoint_url = '';
private string $paypal_payment_method = '';
private ?int $gateway_type_id = null;
protected mixed $access_token = null;
protected ?Carbon $token_expiry = null;
private array $funding_options = [
3 => 'paypal',
1 => 'card',
25 => 'venmo',
// 9 => 'sepa',
// 12 => 'bancontact',
// 17 => 'eps',
// 15 => 'giropay',
// 13 => 'ideal',
// 26 => 'mercadopago',
// 27 => 'mybank',
// 28 => 'paylater',
// 16 => 'p24',
// 7 => 'sofort'
];
/**
* Return an array of
* enabled gateway payment methods
*
* @return array
*/
public function gatewayTypes(): array
{
return collect($this->company_gateway->fees_and_limits)
->filter(function ($fee){
return $fee->is_enabled;
})->map(function ($fee, $key){
return (int)$key;
})->toArray();
}
private function getPaymentMethod($gateway_type_id): int
{
$method = PaymentType::PAYPAL;
match($gateway_type_id){
"1" => $method = PaymentType::CREDIT_CARD_OTHER,
"3" => $method = PaymentType::PAYPAL,
"25" => $method = PaymentType::VENMO,
};
return $method;
}
private function getFundingOptions():string
{
$enums = [
1 => 'card',
3 => 'paypal',
25 => 'venmo',
// 9 => 'sepa',
// 12 => 'bancontact',
// 17 => 'eps',
// 15 => 'giropay',
// 13 => 'ideal',
// 26 => 'mercadopago',
// 27 => 'mybank',
// 28 => 'paylater',
// 16 => 'p24',
// 7 => 'sofort'
];
$funding_options = '';
foreach($this->company_gateway->fees_and_limits as $key => $value) {
if($value->is_enabled) {
$funding_options .=$enums[$key].',';
}
}
return rtrim($funding_options, ',');
}
/**
* Initialize the Paypal gateway.
*
* Attempt to generate and return the access token.
*
* @return self
*/
public function init(): self
{
$this->api_endpoint_url = $this->company_gateway->getConfigField('testMode') ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';
$secret = config('ninja.paypal.secret');
$client_id = config('ninja.paypal.client_id');
if($this->access_token && $this->token_expiry && $this->token_expiry->isFuture())
return $this;
$response = Http::withBasicAuth($client_id, $secret)
->withHeaders(['Content-Type' => 'application/x-www-form-urlencoded'])
->withQueryParameters(['grant_type' => 'client_credentials'])
->post("{$this->api_endpoint_url}/v1/oauth2/token");
if($response->successful()) {
$this->access_token = $response->json()['access_token'];
$this->token_expiry = now()->addSeconds($response->json()['expires_in'] - 60);
} else {
throw new PaymentFailed('Unable to gain access token from Paypal. Check your configuration', 401);
}
return $this;
}
public function setPaymentMethod($payment_method_id)
{
if(!$payment_method_id) {
return $this;
}
$this->gateway_type_id = $payment_method_id;
$this->paypal_payment_method = $this->funding_options[$payment_method_id];
return $this;
}
public function authorizeView($payment_method)
{
// PayPal doesn't support direct authorization.
return $this;
}
public function authorizeResponse($request)
{
// PayPal doesn't support direct authorization.
return $this;
}
private function checkPaymentsReceivable(): self
{
if($this->company_gateway->getConfigField('status') != 'activated'){
if (class_exists(\Modules\Admin\Services\PayPal\PayPalService::class)) {
$pp = new \Modules\Admin\Services\PayPal\PayPalService($this->company_gateway->company, $this->company_gateway->user);
$pp->updateMerchantStatus($this->company_gateway);
$this->company_gateway = $this->company_gateway->fresh();
$config = $this->company_gateway->getConfig();
if($config->status == 'activated')
return $this;
}
throw new PaymentFailed('Unable to accept payments at this time, please contact PayPal for more information.', 401);
}
return $this;
}
public function processPaymentView($data)
{
$this->init()->checkPaymentsReceivable();
$data['gateway'] = $this;
$this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['total']['amount_with_fee']]);
$this->payment_hash->save();
$data['client_id'] = config('ninja.paypal.client_id');
$data['token'] = $this->getClientToken();
$data['order_id'] = $this->createOrder($data);
$data['funding_source'] = $this->paypal_payment_method;
$data['gateway_type_id'] = $this->gateway_type_id;
$data['merchantId'] = $this->company_gateway->getConfigField('merchantId');
// nlog($data['merchantId']);
return render('gateways.paypal.ppcp.pay', $data);
}
private function getClientToken(): string
{
$r = $this->gatewayRequest('/v1/identity/generate-token', 'post', ['body' => '']);
if($r->successful())
return $r->json()['client_token'];
throw new PaymentFailed('Unable to gain client token from Paypal. Check your configuration', 401);
}
public function processPaymentResponse($request)
{
$request['gateway_response'] = str_replace("Error: ", "", $request['gateway_response']);
$response = json_decode($request['gateway_response'], true);
if(isset($response['status']) && $response['status'] == 'COMPLETED' && isset($response['purchase_units'])) {
$data = [
'payment_type' => $this->getPaymentMethod($request->gateway_type_id),
'amount' => $response['purchase_units'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => GatewayType::PAYPAL,
];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL,
$this->client,
$this->client->company,
);
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
} else {
if(isset($response['headers']) ?? false)
unset($response['headers']);
SystemLogger::dispatch(
['response' => $response],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_PAYPAL,
$this->client,
$this->client->company,
);
$message = $response['body']['details'][0]['description'] ?? 'Payment failed. Please try again.';
throw new PaymentFailed($message, 400);
}
}
private function paymentSource(): array
{
/** we only need to support paypal as payment source until as we are only using hosted payment buttons */
return $this->injectPayPalPaymentSource();
}
/**@deprecated v5.7.54 */
private function injectVenmoPaymentSource(): array
{
return [
"venmo" => [
"email_address" => $this->client->present()->email(),
],
];
}
/**@deprecated v5.7.54 */
private function injectCardPaymentSource(): array
{
return [
"card" => [
"name" => $this->client->present()->name(),
"email_address" => $this->client->present()->email(),
"billing_address" => $this->getBillingAddress(),
"experience_context"=> [
"user_action" => "PAY_NOW"
],
],
];
}
private function injectPayPalPaymentSource(): array
{
return [
"paypal" => [
"name" => [
"given_name" => $this->client->present()->first_name(),
"surname" => $this->client->present()->last_name(),
],
"email_address" => $this->client->present()->email(),
"address" => $this->getBillingAddress(),
"experience_context"=> [
"user_action" => "PAY_NOW"
],
],
];
}
private function createOrder(array $data): string
{
$_invoice = collect($this->payment_hash->data->invoices)->first();
$invoice = Invoice::withTrashed()->find($this->decodePrimaryKey($_invoice->invoice_id));
$description = collect($invoice->line_items)->map(function ($item){
return $item->notes;
})->implode("\n");
$order = [
"intent" => "CAPTURE",
"payment_source" => $this->paymentSource(),
"purchase_units" => [
[
"description" =>ctrans('texts.invoice_number').'# '.$invoice->number,
"invoice_id" => $invoice->number,
"payee" => [
"merchant_id" => $this->company_gateway->getConfigField('merchantId'),
],
"payment_instruction" => [
"disbursement_mode" => "INSTANT",
],
$this->getShippingAddress(),
"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,
"description" => substr($description, 0, 127),
"quantity" => "1",
"unit_amount" => [
"currency_code" => $this->client->currency()->code,
"value" => (string)$data['amount_with_fee']
],
],
],
],
]
];
if($shipping = $this->getShippingAddress()){
$order['purchase_units'][0] = $shipping;
}
$r = $this->gatewayRequest('/v2/checkout/orders', 'post', $order);
nlog($r->json());
return $r->json()['id'];
}
private function getBillingAddress(): array
{
return
[
"address_line_1" => $this->client->address1,
"address_line_2" => $this->client->address2,
"admin_area_2" => $this->client->city,
"admin_area_1" => $this->client->state,
"postal_code" => $this->client->postal_code,
"country_code" => $this->client->country->iso_3166_2,
];
}
private function getShippingAddress(): ?array
{
return $this->company_gateway->require_shipping_address ?
[
"shipping" => [
"address" =>
[
"address_line_1" => $this->client->shipping_address1,
"address_line_2" => $this->client->shipping_address2,
"admin_area_2" => $this->client->shipping_city,
"admin_area_1" => $this->client->shipping_state,
"postal_code" => $this->client->shipping_postal_code,
"country_code" => $this->client->present()->shipping_country_code(),
],
]
]
: null;
}
public function gatewayRequest(string $uri, string $verb, array $data, ?array $headers = [])
{
$this->init();
$r = Http::withToken($this->access_token)
->withHeaders($this->getHeaders($headers))
->{$verb}("{$this->api_endpoint_url}{$uri}", $data);
if($r->successful()) {
return $r;
}
throw new PaymentFailed("Gateway failure - {$r->body()}", 401);
}
private function getHeaders(array $headers = []): array
{
return array_merge([
'Accept' => 'application/json',
'Content-type' => 'application/json',
'Accept-Language' => 'en_US',
'PayPal-Partner-Attribution-Id' => 'invoiceninja_SP_PPCP',
'PayPal-Request-Id' => Str::uuid()->toString(),
], $headers);
}
private function feeCalc($invoice, $invoice_total)
{
}
}

View File

@ -140,13 +140,13 @@ class StripePaymentDriver extends BaseDriver
return $this; return $this;
} }
/** /**
* Returns the gateway types. * Returns the gateway types.
*/ */
public function gatewayTypes(): array public function gatewayTypes(): array
{ {
$types = [ $types = [
// GatewayType::CRYPTO,
GatewayType::CREDIT_CARD, GatewayType::CREDIT_CARD,
]; ];

View File

@ -182,7 +182,6 @@ use App\Listeners\Mail\MailSentListener;
use App\Listeners\Misc\InvitationViewedListener; use App\Listeners\Misc\InvitationViewedListener;
use App\Listeners\Payment\PaymentBalanceActivity; use App\Listeners\Payment\PaymentBalanceActivity;
use App\Listeners\Payment\PaymentEmailedActivity; use App\Listeners\Payment\PaymentEmailedActivity;
use App\Listeners\Payment\PaymentEmailFailureActivity;
use App\Listeners\Payment\PaymentNotification; use App\Listeners\Payment\PaymentNotification;
use App\Listeners\Payment\PaymentRestoredActivity; use App\Listeners\Payment\PaymentRestoredActivity;
use App\Listeners\PurchaseOrder\CreatePurchaseOrderActivity; use App\Listeners\PurchaseOrder\CreatePurchaseOrderActivity;
@ -281,6 +280,13 @@ class EventServiceProvider extends ServiceProvider
* *
*/ */
protected $listen = [ protected $listen = [
// RequestSending::class => [
// LogRequestSending::class,
// ],
// ResponseReceived::class => [
// LogResponseReceived::class,
// ],
AccountCreated::class => [ AccountCreated::class => [
], ],
MessageSending::class => [ MessageSending::class => [

View File

@ -18,9 +18,10 @@ use App\Factory\ExpenseFactory;
use App\Models\ExpenseCategory; use App\Models\ExpenseCategory;
use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\GeneratesCounter;
use Illuminate\Database\QueryException; use Illuminate\Database\QueryException;
use App\Jobs\Expense\VendorExpenseNotify;
use Illuminate\Database\Eloquent\Collection;
use Carbon\Exceptions\InvalidFormatException; use Carbon\Exceptions\InvalidFormatException;
use App\Libraries\Currency\Conversion\CurrencyApi; use App\Libraries\Currency\Conversion\CurrencyApi;
use Illuminate\Database\Eloquent\Collection;
/** /**
* ExpenseRepository. * ExpenseRepository.
@ -31,6 +32,7 @@ class ExpenseRepository extends BaseRepository
private $completed = true; private $completed = true;
private $notify_vendor = false;
/** /**
* Saves the expense and its contacts. * Saves the expense and its contacts.
* *
@ -41,10 +43,15 @@ class ExpenseRepository extends BaseRepository
*/ */
public function save(array $data, Expense $expense): Expense public function save(array $data, Expense $expense): Expense
{ {
/** @var \App\Models\User $user */
$user = auth()->user();
if(isset($data['payment_date']) && $data['payment_date'] == $expense->payment_date) { if(isset($data['payment_date']) && $data['payment_date'] == $expense->payment_date) {
//do nothing //do nothing
} elseif(isset($data['payment_date']) && strlen($data['payment_date']) > 1 && $expense->company->notify_vendor_when_paid) { }
nlog("NOT SAME"); elseif(isset($data['payment_date']) && strlen($data['payment_date']) > 1 && $user->company()->notify_vendor_when_paid && ($data['vendor_id'] || $expense->vendor_id)) {
nlog("ping");
$this->notify_vendor = true;
} }
$expense->fill($data); $expense->fill($data);
@ -63,6 +70,9 @@ class ExpenseRepository extends BaseRepository
$this->saveDocuments($data['documents'], $expense); $this->saveDocuments($data['documents'], $expense);
} }
if($this->notify_vendor)
VendorExpenseNotify::dispatch($expense, $expense->company->db);
return $expense; return $expense;
} }

View File

@ -0,0 +1,76 @@
<?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\Services\Company;
use App\Models\User;
use App\Models\Company;
use App\Factory\TaxRateFactory;
class CompanyService{
public function __construct(public Company $company)
{
}
public function localizeCompany(User $user)
{
try {
$taxes = [];
switch ($this->company->settings->country_id) {
case '36': // Australia
$taxes[] = ['name' => 'GST', 'rate' => 10];
break;
case '40': // Austria
$taxes[] = ['name' => 'USt', 'rate' => 20];
break;
case '56': // Belgium
$taxes[] = ['name' => 'BTW', 'rate' => 21];
break;
case '100': // Bulgaria
$taxes[] = ['name' => 'ДДС', 'rate' => 20];
break;
case '250': // France
$taxes[] = ['name' => 'TVA', 'rate' => 20];
break;
case '276': // Germany
$taxes[] = ['name' => 'MwSt', 'rate' => 19];
break;
case '554': // New Zealand
$taxes[] = ['name' => 'GST', 'rate' => 15];
break;
case '710': // South Africa
$taxes[] = ['name' => 'VAT', 'rate' => 15];
break;
case '724': // Spain
$taxes[] = ['name' => 'IVA', 'rate' => 21];
break;
default:
return;
}
foreach($taxes as $tax) {
$tax_rate = TaxRateFactory::create($this->company->id, $user->id);
$tax_rate->fill($tax);
$tax_rate->save();
}
}catch(\Exception $e){
nlog($e->getMessage());
}
}
}

View File

@ -166,7 +166,6 @@ class EmailDefaults
if (strlen($this->email->email_object->body) > 3) { if (strlen($this->email->email_object->body) > 3) {
// A Custom Message has been set in the email screen. // A Custom Message has been set in the email screen.
// return $this;
} elseif (strlen($this->email->email_object->settings?->{$this->email->email_object->email_template_body}) > 3) { } elseif (strlen($this->email->email_object->settings?->{$this->email->email_object->email_template_body}) > 3) {
// A body has been saved in the settings. // A body has been saved in the settings.
$this->email->email_object->body = $this->email->email_object->settings?->{$this->email->email_object->email_template_body}; $this->email->email_object->body = $this->email->email_object->settings?->{$this->email->email_object->email_template_body};

21
app/Services/Vendor/VendorService.php vendored Normal file
View File

@ -0,0 +1,21 @@
<?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\Services\Vendor;
use App\Models\Vendor;
class VendorService
{
public function __construct(public Vendor $vendor)
{
}
}

354
composer.lock generated
View File

@ -431,16 +431,16 @@
}, },
{ {
"name": "aws/aws-crt-php", "name": "aws/aws-crt-php",
"version": "v1.2.3", "version": "v1.2.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/awslabs/aws-crt-php.git", "url": "https://github.com/awslabs/aws-crt-php.git",
"reference": "5545a4fa310aec39f54279fdacebcce33b3ff382" "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/5545a4fa310aec39f54279fdacebcce33b3ff382", "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/eb0c6e4e142224a10b08f49ebf87f32611d162b2",
"reference": "5545a4fa310aec39f54279fdacebcce33b3ff382", "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -479,22 +479,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/awslabs/aws-crt-php/issues", "issues": "https://github.com/awslabs/aws-crt-php/issues",
"source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.3" "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.4"
}, },
"time": "2023-10-16T20:10:06+00:00" "time": "2023-11-08T00:42:13+00:00"
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.285.4", "version": "3.288.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "c462af819d81cba49939949032b20799f5ef0fff" "reference": "a1dfa12c7165de0b731ae8074c4ba1f3ae733f89"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c462af819d81cba49939949032b20799f5ef0fff", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a1dfa12c7165de0b731ae8074c4ba1f3ae733f89",
"reference": "c462af819d81cba49939949032b20799f5ef0fff", "reference": "a1dfa12c7165de0b731ae8074c4ba1f3ae733f89",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -574,9 +574,9 @@
"support": { "support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues", "issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.285.4" "source": "https://github.com/aws/aws-sdk-php/tree/3.288.1"
}, },
"time": "2023-11-10T19:25:49+00:00" "time": "2023-11-22T19:35:38+00:00"
}, },
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@ -634,16 +634,16 @@
}, },
{ {
"name": "beganovich/snappdf", "name": "beganovich/snappdf",
"version": "v4.0.2", "version": "v4.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/beganovich/snappdf.git", "url": "https://github.com/beganovich/snappdf.git",
"reference": "afb188d8370a35db3b6ce4b6f2ef2963d7005891" "reference": "ad181634736ca15b7adba1637e982d151165656d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/beganovich/snappdf/zipball/afb188d8370a35db3b6ce4b6f2ef2963d7005891", "url": "https://api.github.com/repos/beganovich/snappdf/zipball/ad181634736ca15b7adba1637e982d151165656d",
"reference": "afb188d8370a35db3b6ce4b6f2ef2963d7005891", "reference": "ad181634736ca15b7adba1637e982d151165656d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -680,9 +680,9 @@
"description": "Convert webpages or HTML into the PDF file using Chromium or Google Chrome.", "description": "Convert webpages or HTML into the PDF file using Chromium or Google Chrome.",
"support": { "support": {
"issues": "https://github.com/beganovich/snappdf/issues", "issues": "https://github.com/beganovich/snappdf/issues",
"source": "https://github.com/beganovich/snappdf/tree/v4.0.2" "source": "https://github.com/beganovich/snappdf/tree/v4.0.3"
}, },
"time": "2023-11-06T21:44:50+00:00" "time": "2023-11-13T17:05:08+00:00"
}, },
{ {
"name": "braintree/braintree_php", "name": "braintree/braintree_php",
@ -1353,16 +1353,16 @@
}, },
{ {
"name": "doctrine/dbal", "name": "doctrine/dbal",
"version": "3.7.1", "version": "3.7.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/dbal.git", "url": "https://github.com/doctrine/dbal.git",
"reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2" "reference": "0ac3c270590e54910715e9a1a044cc368df282b2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/5b7bd66c9ff58c04c5474ab85edce442f8081cb2", "url": "https://api.github.com/repos/doctrine/dbal/zipball/0ac3c270590e54910715e9a1a044cc368df282b2",
"reference": "5b7bd66c9ff58c04c5474ab85edce442f8081cb2", "reference": "0ac3c270590e54910715e9a1a044cc368df282b2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1378,7 +1378,7 @@
"doctrine/coding-standard": "12.0.0", "doctrine/coding-standard": "12.0.0",
"fig/log-test": "^1", "fig/log-test": "^1",
"jetbrains/phpstorm-stubs": "2023.1", "jetbrains/phpstorm-stubs": "2023.1",
"phpstan/phpstan": "1.10.35", "phpstan/phpstan": "1.10.42",
"phpstan/phpstan-strict-rules": "^1.5", "phpstan/phpstan-strict-rules": "^1.5",
"phpunit/phpunit": "9.6.13", "phpunit/phpunit": "9.6.13",
"psalm/plugin-phpunit": "0.18.4", "psalm/plugin-phpunit": "0.18.4",
@ -1446,7 +1446,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/dbal/issues", "issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/3.7.1" "source": "https://github.com/doctrine/dbal/tree/3.7.2"
}, },
"funding": [ "funding": [
{ {
@ -1462,7 +1462,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-10-06T05:06:20+00:00" "time": "2023-11-19T08:06:58+00:00"
}, },
{ {
"name": "doctrine/deprecations", "name": "doctrine/deprecations",
@ -2487,16 +2487,16 @@
}, },
{ {
"name": "google/apiclient-services", "name": "google/apiclient-services",
"version": "v0.324.0", "version": "v0.325.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/googleapis/google-api-php-client-services.git", "url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "585cc823c3d59788e4a0829d5b7e41c76950d801" "reference": "b2d39ef968f0017d6bff3c1da82501a0c575c9ce"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/585cc823c3d59788e4a0829d5b7e41c76950d801", "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/b2d39ef968f0017d6bff3c1da82501a0c575c9ce",
"reference": "585cc823c3d59788e4a0829d5b7e41c76950d801", "reference": "b2d39ef968f0017d6bff3c1da82501a0c575c9ce",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2525,9 +2525,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/googleapis/google-api-php-client-services/issues", "issues": "https://github.com/googleapis/google-api-php-client-services/issues",
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.324.0" "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.325.0"
}, },
"time": "2023-11-13T01:06:14+00:00" "time": "2023-11-18T01:04:14+00:00"
}, },
{ {
"name": "google/auth", "name": "google/auth",
@ -4074,16 +4074,16 @@
}, },
{ {
"name": "josemmo/facturae-php", "name": "josemmo/facturae-php",
"version": "v1.7.8", "version": "v1.7.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/josemmo/Facturae-PHP.git", "url": "https://github.com/josemmo/Facturae-PHP.git",
"reference": "3c490fa60e668a6275ba2fb6c228f1e19216d02e" "reference": "6d5fb5f9b7a7d9ba2b99346af64e3b140b1b51ac"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/josemmo/Facturae-PHP/zipball/3c490fa60e668a6275ba2fb6c228f1e19216d02e", "url": "https://api.github.com/repos/josemmo/Facturae-PHP/zipball/6d5fb5f9b7a7d9ba2b99346af64e3b140b1b51ac",
"reference": "3c490fa60e668a6275ba2fb6c228f1e19216d02e", "reference": "6d5fb5f9b7a7d9ba2b99346af64e3b140b1b51ac",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4125,9 +4125,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/josemmo/Facturae-PHP/issues", "issues": "https://github.com/josemmo/Facturae-PHP/issues",
"source": "https://github.com/josemmo/Facturae-PHP/tree/v1.7.8" "source": "https://github.com/josemmo/Facturae-PHP/tree/v1.7.9"
}, },
"time": "2023-08-06T15:34:37+00:00" "time": "2023-11-19T08:50:33+00:00"
}, },
{ {
"name": "kmukku/php-iso11649", "name": "kmukku/php-iso11649",
@ -4230,16 +4230,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v10.31.0", "version": "v10.33.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "507ce9b28bce4b5e4140c28943092ca38e9a52e4" "reference": "4536872e3e5b6be51b1f655dafd12c9a4fa0cfe8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/507ce9b28bce4b5e4140c28943092ca38e9a52e4", "url": "https://api.github.com/repos/laravel/framework/zipball/4536872e3e5b6be51b1f655dafd12c9a4fa0cfe8",
"reference": "507ce9b28bce4b5e4140c28943092ca38e9a52e4", "reference": "4536872e3e5b6be51b1f655dafd12c9a4fa0cfe8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4340,7 +4340,7 @@
"league/flysystem-sftp-v3": "^3.0", "league/flysystem-sftp-v3": "^3.0",
"mockery/mockery": "^1.5.1", "mockery/mockery": "^1.5.1",
"nyholm/psr7": "^1.2", "nyholm/psr7": "^1.2",
"orchestra/testbench-core": "^8.12", "orchestra/testbench-core": "^8.15.1",
"pda/pheanstalk": "^4.0", "pda/pheanstalk": "^4.0",
"phpstan/phpstan": "^1.4.7", "phpstan/phpstan": "^1.4.7",
"phpunit/phpunit": "^10.0.7", "phpunit/phpunit": "^10.0.7",
@ -4428,7 +4428,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2023-11-07T13:48:30+00:00" "time": "2023-11-21T14:49:31+00:00"
}, },
{ {
"name": "laravel/prompts", "name": "laravel/prompts",
@ -4489,16 +4489,16 @@
}, },
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
"version": "v1.3.2", "version": "v1.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/serializable-closure.git", "url": "https://github.com/laravel/serializable-closure.git",
"reference": "076fe2cf128bd54b4341cdc6d49b95b34e101e4c" "reference": "3dbf8a8e914634c48d389c1234552666b3d43754"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/076fe2cf128bd54b4341cdc6d49b95b34e101e4c", "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754",
"reference": "076fe2cf128bd54b4341cdc6d49b95b34e101e4c", "reference": "3dbf8a8e914634c48d389c1234552666b3d43754",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4545,7 +4545,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues", "issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure" "source": "https://github.com/laravel/serializable-closure"
}, },
"time": "2023-10-17T13:38:16+00:00" "time": "2023-11-08T14:08:06+00:00"
}, },
{ {
"name": "laravel/slack-notification-channel", "name": "laravel/slack-notification-channel",
@ -5225,16 +5225,16 @@
}, },
{ {
"name": "league/flysystem", "name": "league/flysystem",
"version": "3.19.0", "version": "3.21.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/flysystem.git", "url": "https://github.com/thephpleague/flysystem.git",
"reference": "1b2aa10f2326e0351399b8ce68e287d8e9209a83" "reference": "a326d8a2d007e4ca327a57470846e34363789258"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1b2aa10f2326e0351399b8ce68e287d8e9209a83", "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a326d8a2d007e4ca327a57470846e34363789258",
"reference": "1b2aa10f2326e0351399b8ce68e287d8e9209a83", "reference": "a326d8a2d007e4ca327a57470846e34363789258",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5299,7 +5299,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/flysystem/issues", "issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.19.0" "source": "https://github.com/thephpleague/flysystem/tree/3.21.0"
}, },
"funding": [ "funding": [
{ {
@ -5311,20 +5311,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-11-07T09:04:28+00:00" "time": "2023-11-18T13:59:15+00:00"
}, },
{ {
"name": "league/flysystem-aws-s3-v3", "name": "league/flysystem-aws-s3-v3",
"version": "3.19.0", "version": "3.21.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
"reference": "03be643c8ed4dea811d946101be3bc875b5cf214" "reference": "2a1784eec09ee8e190fc27b93e725bc518338929"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/03be643c8ed4dea811d946101be3bc875b5cf214", "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/2a1784eec09ee8e190fc27b93e725bc518338929",
"reference": "03be643c8ed4dea811d946101be3bc875b5cf214", "reference": "2a1784eec09ee8e190fc27b93e725bc518338929",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5365,7 +5365,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues", "issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues",
"source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.19.0" "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.21.0"
}, },
"funding": [ "funding": [
{ {
@ -5377,20 +5377,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-11-06T20:35:28+00:00" "time": "2023-11-14T11:54:45+00:00"
}, },
{ {
"name": "league/flysystem-local", "name": "league/flysystem-local",
"version": "3.19.0", "version": "3.21.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/flysystem-local.git", "url": "https://github.com/thephpleague/flysystem-local.git",
"reference": "8d868217f9eeb4e9a7320db5ccad825e9a7a4076" "reference": "470eb1c09eaabd49ebd908ae06f23983ba3ecfe7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/8d868217f9eeb4e9a7320db5ccad825e9a7a4076", "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/470eb1c09eaabd49ebd908ae06f23983ba3ecfe7",
"reference": "8d868217f9eeb4e9a7320db5ccad825e9a7a4076", "reference": "470eb1c09eaabd49ebd908ae06f23983ba3ecfe7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5425,7 +5425,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/flysystem-local/issues", "issues": "https://github.com/thephpleague/flysystem-local/issues",
"source": "https://github.com/thephpleague/flysystem-local/tree/3.19.0" "source": "https://github.com/thephpleague/flysystem-local/tree/3.21.0"
}, },
"funding": [ "funding": [
{ {
@ -5437,7 +5437,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-11-06T20:35:28+00:00" "time": "2023-11-18T13:41:42+00:00"
}, },
{ {
"name": "league/fractal", "name": "league/fractal",
@ -5923,23 +5923,23 @@
}, },
{ {
"name": "moneyphp/money", "name": "moneyphp/money",
"version": "v4.2.0", "version": "v4.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/moneyphp/money.git", "url": "https://github.com/moneyphp/money.git",
"reference": "f660ab7f1d7a4c2ffdd30f50c55ed2c95c26fc3f" "reference": "50ddfd15b2be01d4bed3bcb0c975a6af5f78a183"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/moneyphp/money/zipball/f660ab7f1d7a4c2ffdd30f50c55ed2c95c26fc3f", "url": "https://api.github.com/repos/moneyphp/money/zipball/50ddfd15b2be01d4bed3bcb0c975a6af5f78a183",
"reference": "f660ab7f1d7a4c2ffdd30f50c55ed2c95c26fc3f", "reference": "50ddfd15b2be01d4bed3bcb0c975a6af5f78a183",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-bcmath": "*", "ext-bcmath": "*",
"ext-filter": "*", "ext-filter": "*",
"ext-json": "*", "ext-json": "*",
"php": "~8.0.0 || ~8.1.0 || ~8.2.0" "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0"
}, },
"require-dev": { "require-dev": {
"cache/taggable-cache": "^1.1.0", "cache/taggable-cache": "^1.1.0",
@ -5954,11 +5954,10 @@
"php-http/message": "^1.11.0", "php-http/message": "^1.11.0",
"php-http/mock-client": "^1.4.1", "php-http/mock-client": "^1.4.1",
"phpbench/phpbench": "^1.2.5", "phpbench/phpbench": "^1.2.5",
"phpspec/phpspec": "^7.3",
"phpunit/phpunit": "^9.5.4", "phpunit/phpunit": "^9.5.4",
"psalm/plugin-phpunit": "^0.18.4", "psalm/plugin-phpunit": "^0.18.4",
"psr/cache": "^1.0.1", "psr/cache": "^1.0.1",
"vimeo/psalm": "~5.3.0" "vimeo/psalm": "~5.15.0"
}, },
"suggest": { "suggest": {
"ext-gmp": "Calculate without integer limits", "ext-gmp": "Calculate without integer limits",
@ -6006,9 +6005,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/moneyphp/money/issues", "issues": "https://github.com/moneyphp/money/issues",
"source": "https://github.com/moneyphp/money/tree/v4.2.0" "source": "https://github.com/moneyphp/money/tree/v4.3.0"
}, },
"time": "2023-08-16T14:31:24+00:00" "time": "2023-11-22T09:46:30+00:00"
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
@ -6648,16 +6647,16 @@
}, },
{ {
"name": "nwidart/laravel-modules", "name": "nwidart/laravel-modules",
"version": "10.0.3", "version": "10.0.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/nWidart/laravel-modules.git", "url": "https://github.com/nWidart/laravel-modules.git",
"reference": "786da1e6dfa2df6caa8718acb9c37a8fe94595b3" "reference": "5a75f90d7d0d2689f1fb08c766f23fd3ee76769e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/nWidart/laravel-modules/zipball/786da1e6dfa2df6caa8718acb9c37a8fe94595b3", "url": "https://api.github.com/repos/nWidart/laravel-modules/zipball/5a75f90d7d0d2689f1fb08c766f23fd3ee76769e",
"reference": "786da1e6dfa2df6caa8718acb9c37a8fe94595b3", "reference": "5a75f90d7d0d2689f1fb08c766f23fd3ee76769e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6717,7 +6716,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/nWidart/laravel-modules/issues", "issues": "https://github.com/nWidart/laravel-modules/issues",
"source": "https://github.com/nWidart/laravel-modules/tree/10.0.3" "source": "https://github.com/nWidart/laravel-modules/tree/10.0.4"
}, },
"funding": [ "funding": [
{ {
@ -6729,20 +6728,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-11-02T17:47:33+00:00" "time": "2023-11-13T22:35:16+00:00"
}, },
{ {
"name": "nyholm/psr7", "name": "nyholm/psr7",
"version": "1.8.0", "version": "1.8.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Nyholm/psr7.git", "url": "https://github.com/Nyholm/psr7.git",
"reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be" "reference": "aa5fc277a4f5508013d571341ade0c3886d4d00e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Nyholm/psr7/zipball/3cb4d163b58589e47b35103e8e5e6a6a475b47be", "url": "https://api.github.com/repos/Nyholm/psr7/zipball/aa5fc277a4f5508013d571341ade0c3886d4d00e",
"reference": "3cb4d163b58589e47b35103e8e5e6a6a475b47be", "reference": "aa5fc277a4f5508013d571341ade0c3886d4d00e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6795,7 +6794,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/Nyholm/psr7/issues", "issues": "https://github.com/Nyholm/psr7/issues",
"source": "https://github.com/Nyholm/psr7/tree/1.8.0" "source": "https://github.com/Nyholm/psr7/tree/1.8.1"
}, },
"funding": [ "funding": [
{ {
@ -6807,7 +6806,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-05-02T11:26:24+00:00" "time": "2023-11-13T09:31:12+00:00"
}, },
{ {
"name": "omnipay/common", "name": "omnipay/common",
@ -8017,16 +8016,16 @@
}, },
{ {
"name": "phpstan/phpdoc-parser", "name": "phpstan/phpdoc-parser",
"version": "1.24.2", "version": "1.24.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git", "url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "bcad8d995980440892759db0c32acae7c8e79442" "reference": "12f01d214f1c73b9c91fdb3b1c415e4c70652083"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/12f01d214f1c73b9c91fdb3b1c415e4c70652083",
"reference": "bcad8d995980440892759db0c32acae7c8e79442", "reference": "12f01d214f1c73b9c91fdb3b1c415e4c70652083",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -8058,9 +8057,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types", "description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": { "support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues", "issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.2" "source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.3"
}, },
"time": "2023-09-26T12:28:12+00:00" "time": "2023-11-18T20:15:32+00:00"
}, },
{ {
"name": "pragmarx/google2fa", "name": "pragmarx/google2fa",
@ -9341,16 +9340,16 @@
}, },
{ {
"name": "sentry/sentry", "name": "sentry/sentry",
"version": "3.22.0", "version": "3.22.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/getsentry/sentry-php.git", "url": "https://github.com/getsentry/sentry-php.git",
"reference": "c0e3df5a5c1d133cd9461e7672568ff07042c19d" "reference": "8859631ba5ab15bc1af420b0eeed19ecc6c9d81d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/c0e3df5a5c1d133cd9461e7672568ff07042c19d", "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/8859631ba5ab15bc1af420b0eeed19ecc6c9d81d",
"reference": "c0e3df5a5c1d133cd9461e7672568ff07042c19d", "reference": "8859631ba5ab15bc1af420b0eeed19ecc6c9d81d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -9425,7 +9424,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/getsentry/sentry-php/issues", "issues": "https://github.com/getsentry/sentry-php/issues",
"source": "https://github.com/getsentry/sentry-php/tree/3.22.0" "source": "https://github.com/getsentry/sentry-php/tree/3.22.1"
}, },
"funding": [ "funding": [
{ {
@ -9437,7 +9436,7 @@
"type": "custom" "type": "custom"
} }
], ],
"time": "2023-10-23T20:34:53+00:00" "time": "2023-11-13T11:47:28+00:00"
}, },
{ {
"name": "sentry/sentry-laravel", "name": "sentry/sentry-laravel",
@ -10104,16 +10103,16 @@
}, },
{ {
"name": "sprain/swiss-qr-bill", "name": "sprain/swiss-qr-bill",
"version": "v4.11", "version": "v4.11.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sprain/php-swiss-qr-bill.git", "url": "https://github.com/sprain/php-swiss-qr-bill.git",
"reference": "dd4d2c1f6ffc14930806f8bdbfd7e5cd7ddf0e20" "reference": "eb68c116bfed96daeb93121809d697f0d324a9d7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sprain/php-swiss-qr-bill/zipball/dd4d2c1f6ffc14930806f8bdbfd7e5cd7ddf0e20", "url": "https://api.github.com/repos/sprain/php-swiss-qr-bill/zipball/eb68c116bfed96daeb93121809d697f0d324a9d7",
"reference": "dd4d2c1f6ffc14930806f8bdbfd7e5cd7ddf0e20", "reference": "eb68c116bfed96daeb93121809d697f0d324a9d7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -10161,7 +10160,7 @@
"description": "A PHP library to create Swiss QR bills", "description": "A PHP library to create Swiss QR bills",
"support": { "support": {
"issues": "https://github.com/sprain/php-swiss-qr-bill/issues", "issues": "https://github.com/sprain/php-swiss-qr-bill/issues",
"source": "https://github.com/sprain/php-swiss-qr-bill/tree/v4.11" "source": "https://github.com/sprain/php-swiss-qr-bill/tree/v4.11.1"
}, },
"funding": [ "funding": [
{ {
@ -10169,7 +10168,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-10-31T06:49:19+00:00" "time": "2023-11-16T17:35:43+00:00"
}, },
{ {
"name": "square/square", "name": "square/square",
@ -10443,7 +10442,7 @@
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
"version": "v3.3.0", "version": "v3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git", "url": "https://github.com/symfony/deprecation-contracts.git",
@ -10490,7 +10489,7 @@
"description": "A generic function and convention to trigger deprecation notices", "description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
}, },
"funding": [ "funding": [
{ {
@ -10664,7 +10663,7 @@
}, },
{ {
"name": "symfony/event-dispatcher-contracts", "name": "symfony/event-dispatcher-contracts",
"version": "v3.3.0", "version": "v3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git", "url": "https://github.com/symfony/event-dispatcher-contracts.git",
@ -10720,7 +10719,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.3.0" "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.0"
}, },
"funding": [ "funding": [
{ {
@ -10959,16 +10958,16 @@
}, },
{ {
"name": "symfony/http-client-contracts", "name": "symfony/http-client-contracts",
"version": "v3.3.0", "version": "v3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/http-client-contracts.git", "url": "https://github.com/symfony/http-client-contracts.git",
"reference": "3b66325d0176b4ec826bffab57c9037d759c31fb" "reference": "1ee70e699b41909c209a0c930f11034b93578654"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/3b66325d0176b4ec826bffab57c9037d759c31fb", "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/1ee70e699b41909c209a0c930f11034b93578654",
"reference": "3b66325d0176b4ec826bffab57c9037d759c31fb", "reference": "1ee70e699b41909c209a0c930f11034b93578654",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -11017,7 +11016,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/http-client-contracts/tree/v3.3.0" "source": "https://github.com/symfony/http-client-contracts/tree/v3.4.0"
}, },
"funding": [ "funding": [
{ {
@ -11033,7 +11032,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-05-23T14:45:45+00:00" "time": "2023-07-30T20:28:31+00:00"
}, },
{ {
"name": "symfony/http-foundation", "name": "symfony/http-foundation",
@ -12737,16 +12736,16 @@
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
"version": "v3.3.0", "version": "v3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/service-contracts.git", "url": "https://github.com/symfony/service-contracts.git",
"reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4" "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", "url": "https://api.github.com/repos/symfony/service-contracts/zipball/b3313c2dbffaf71c8de2934e2ea56ed2291a3838",
"reference": "40da9cc13ec349d9e4966ce18b5fbcd724ab10a4", "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -12799,7 +12798,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.3.0" "source": "https://github.com/symfony/service-contracts/tree/v3.4.0"
}, },
"funding": [ "funding": [
{ {
@ -12815,7 +12814,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-05-23T14:45:45+00:00" "time": "2023-07-30T20:28:31+00:00"
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
@ -13000,16 +12999,16 @@
}, },
{ {
"name": "symfony/translation-contracts", "name": "symfony/translation-contracts",
"version": "v3.3.0", "version": "v3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/translation-contracts.git", "url": "https://github.com/symfony/translation-contracts.git",
"reference": "02c24deb352fb0d79db5486c0c79905a85e37e86" "reference": "dee0c6e5b4c07ce851b462530088e64b255ac9c5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/02c24deb352fb0d79db5486c0c79905a85e37e86", "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/dee0c6e5b4c07ce851b462530088e64b255ac9c5",
"reference": "02c24deb352fb0d79db5486c0c79905a85e37e86", "reference": "dee0c6e5b4c07ce851b462530088e64b255ac9c5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -13058,7 +13057,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/translation-contracts/tree/v3.3.0" "source": "https://github.com/symfony/translation-contracts/tree/v3.4.0"
}, },
"funding": [ "funding": [
{ {
@ -13074,7 +13073,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-05-30T17:17:10+00:00" "time": "2023-07-25T15:08:44+00:00"
}, },
{ {
"name": "symfony/uid", "name": "symfony/uid",
@ -13519,25 +13518,25 @@
}, },
{ {
"name": "twig/intl-extra", "name": "twig/intl-extra",
"version": "v3.7.1", "version": "v3.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/intl-extra.git", "url": "https://github.com/twigphp/intl-extra.git",
"reference": "4f4fe572f635534649cc069e1dafe4a8ad63774d" "reference": "7b3db67c700735f473a265a97e1adaeba3e6ca0c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/intl-extra/zipball/4f4fe572f635534649cc069e1dafe4a8ad63774d", "url": "https://api.github.com/repos/twigphp/intl-extra/zipball/7b3db67c700735f473a265a97e1adaeba3e6ca0c",
"reference": "4f4fe572f635534649cc069e1dafe4a8ad63774d", "reference": "7b3db67c700735f473a265a97e1adaeba3e6ca0c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.1.3", "php": ">=7.2.5",
"symfony/intl": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0|^7.0",
"twig/twig": "^2.7|^3.0" "twig/twig": "^3.0"
}, },
"require-dev": { "require-dev": {
"symfony/phpunit-bridge": "^5.4|^6.3" "symfony/phpunit-bridge": "^6.4|^7.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -13567,7 +13566,7 @@
"twig" "twig"
], ],
"support": { "support": {
"source": "https://github.com/twigphp/intl-extra/tree/v3.7.1" "source": "https://github.com/twigphp/intl-extra/tree/v3.8.0"
}, },
"funding": [ "funding": [
{ {
@ -13579,30 +13578,31 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-29T15:34:56+00:00" "time": "2023-11-21T17:27:48+00:00"
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v3.7.1", "version": "v3.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554" "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
"reference": "a0ce373a0ca3bf6c64b9e3e2124aca502ba39554", "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/polyfill-ctype": "^1.8", "symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3" "symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php80": "^1.22"
}, },
"require-dev": { "require-dev": {
"psr/container": "^1.0|^2.0", "psr/container": "^1.0|^2.0",
"symfony/phpunit-bridge": "^5.4.9|^6.3" "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -13638,7 +13638,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/twigphp/Twig/issues", "issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.7.1" "source": "https://github.com/twigphp/Twig/tree/v3.8.0"
}, },
"funding": [ "funding": [
{ {
@ -13650,7 +13650,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-08-28T11:09:02+00:00" "time": "2023-11-21T18:54:41+00:00"
}, },
{ {
"name": "twilio/sdk", "name": "twilio/sdk",
@ -14825,16 +14825,16 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.38.0", "version": "v3.39.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "7e6070026e76aa09d77a47519625c86593fb8e31" "reference": "857046d26b0d92dc13c4be769309026b100b517e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7e6070026e76aa09d77a47519625c86593fb8e31", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/857046d26b0d92dc13c4be769309026b100b517e",
"reference": "7e6070026e76aa09d77a47519625c86593fb8e31", "reference": "857046d26b0d92dc13c4be769309026b100b517e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -14844,16 +14844,16 @@
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": "^7.4 || ^8.0", "php": "^7.4 || ^8.0",
"sebastian/diff": "^4.0 || ^5.0", "sebastian/diff": "^4.0 || ^5.0",
"symfony/console": "^5.4 || ^6.0", "symfony/console": "^5.4 || ^6.0 || ^7.0",
"symfony/event-dispatcher": "^5.4 || ^6.0", "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0",
"symfony/filesystem": "^5.4 || ^6.0", "symfony/filesystem": "^5.4 || ^6.0 || ^7.0",
"symfony/finder": "^5.4 || ^6.0", "symfony/finder": "^5.4 || ^6.0 || ^7.0",
"symfony/options-resolver": "^5.4 || ^6.0", "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0",
"symfony/polyfill-mbstring": "^1.27", "symfony/polyfill-mbstring": "^1.27",
"symfony/polyfill-php80": "^1.27", "symfony/polyfill-php80": "^1.27",
"symfony/polyfill-php81": "^1.27", "symfony/polyfill-php81": "^1.27",
"symfony/process": "^5.4 || ^6.0", "symfony/process": "^5.4 || ^6.0 || ^7.0",
"symfony/stopwatch": "^5.4 || ^6.0" "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0"
}, },
"require-dev": { "require-dev": {
"facile-it/paraunit": "^1.3 || ^2.0", "facile-it/paraunit": "^1.3 || ^2.0",
@ -14867,8 +14867,8 @@
"phpspec/prophecy": "^1.16", "phpspec/prophecy": "^1.16",
"phpspec/prophecy-phpunit": "^2.0", "phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"symfony/phpunit-bridge": "^6.2.3", "symfony/phpunit-bridge": "^6.2.3 || ^7.0",
"symfony/yaml": "^5.4 || ^6.0" "symfony/yaml": "^5.4 || ^6.0 || ^7.0"
}, },
"suggest": { "suggest": {
"ext-dom": "For handling output formats in XML", "ext-dom": "For handling output formats in XML",
@ -14906,7 +14906,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.38.0" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.39.1"
}, },
"funding": [ "funding": [
{ {
@ -14914,7 +14914,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-11-07T08:44:54+00:00" "time": "2023-11-24T22:59:03+00:00"
}, },
{ {
"name": "hamcrest/hamcrest-php", "name": "hamcrest/hamcrest-php",
@ -15628,16 +15628,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.41", "version": "1.10.44",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "c6174523c2a69231df55bdc65b61655e72876d76" "reference": "bf84367c53a23f759513985c54ffe0d0c249825b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6174523c2a69231df55bdc65b61655e72876d76", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/bf84367c53a23f759513985c54ffe0d0c249825b",
"reference": "c6174523c2a69231df55bdc65b61655e72876d76", "reference": "bf84367c53a23f759513985c54ffe0d0c249825b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -15686,20 +15686,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-11-05T12:57:57+00:00" "time": "2023-11-21T16:30:46+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "10.1.7", "version": "10.1.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e" "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a56a9ab2f680246adcf3db43f38ddf1765774735",
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e", "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -15756,7 +15756,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7" "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.9"
}, },
"funding": [ "funding": [
{ {
@ -15764,7 +15764,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-10-04T15:34:17+00:00" "time": "2023-11-23T12:23:20+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@ -17537,16 +17537,16 @@
}, },
{ {
"name": "theseer/tokenizer", "name": "theseer/tokenizer",
"version": "1.2.1", "version": "1.2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/theseer/tokenizer.git", "url": "https://github.com/theseer/tokenizer.git",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -17575,7 +17575,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": { "support": {
"issues": "https://github.com/theseer/tokenizer/issues", "issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/1.2.1" "source": "https://github.com/theseer/tokenizer/tree/1.2.2"
}, },
"funding": [ "funding": [
{ {
@ -17583,7 +17583,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-07-28T10:34:58+00:00" "time": "2023-11-20T00:12:19+00:00"
} }
], ],
"aliases": [], "aliases": [],

View File

@ -86,6 +86,7 @@ return [
'password' => 'password', 'password' => 'password',
'stripe' => env('STRIPE_KEYS', ''), 'stripe' => env('STRIPE_KEYS', ''),
'paypal' => env('PAYPAL_KEYS', ''), 'paypal' => env('PAYPAL_KEYS', ''),
'ppcp' => env('PPCP_KEYS', ''),
'paypal_rest' => env('PAYPAL_REST_KEYS', ''), 'paypal_rest' => env('PAYPAL_REST_KEYS', ''),
'authorize' => env('AUTHORIZE_KEYS', ''), 'authorize' => env('AUTHORIZE_KEYS', ''),
'checkout' => env('CHECKOUT_KEYS', ''), 'checkout' => env('CHECKOUT_KEYS', ''),
@ -223,4 +224,8 @@ return [
'client_id' => env('SHOPIFY_CLIENT_ID', null), 'client_id' => env('SHOPIFY_CLIENT_ID', null),
'client_secret' => env('SHOPIFY_CLIENT_SECRET', null), 'client_secret' => env('SHOPIFY_CLIENT_SECRET', null),
], ],
'paypal' => [
'secret' => env('PAYPAL_SECRET', null),
'client_id' => env('PAYPAL_CLIENT_ID', null),
]
]; ];

View File

@ -0,0 +1,49 @@
<?php
use App\Utils\Ninja;
use App\Models\Gateway;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if(!Gateway::find(61) && Ninja::isHosted())
{
$fields = new \stdClass;
$fields->clientId = "";
$fields->secret = "";
$fields->testMode = false;
$paypal = new Gateway;
$paypal->id = 61;
$paypal->name = 'PayPal Platform';
$paypal->key = '80af24a6a691230bbec33e930ab40666';
$paypal->provider = 'PayPal_PPCP';
$paypal->is_offsite = false;
$paypal->fields = \json_encode($fields);
$paypal->visible = 1;
$paypal->site_url = 'https://www.paypal.com/';
$paypal->save();
}
Gateway::whereIn('id', [60, 15, 49])->update(['visible' => 0]);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View File

@ -84,6 +84,7 @@ class PaymentLibrariesSeeder extends Seeder
['id' => 58, 'name' => 'Razorpay', 'provider' => 'Razorpay', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9', 'fields' => '{"apiKey":"","apiSecret":""}'], ['id' => 58, 'name' => 'Razorpay', 'provider' => 'Razorpay', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9', 'fields' => '{"apiKey":"","apiSecret":""}'],
['id' => 59, 'name' => 'Forte', 'provider' => 'Forte', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs', 'fields' => '{"testMode":false,"apiLoginId":"","apiAccessId":"","secureKey":"","authOrganizationId":"","organizationId":"","locationId":""}'], ['id' => 59, 'name' => 'Forte', 'provider' => 'Forte', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs', 'fields' => '{"testMode":false,"apiLoginId":"","apiAccessId":"","secureKey":"","authOrganizationId":"","organizationId":"","locationId":""}'],
['id' => 60, 'name' => 'PayPal REST', 'provider' => 'PayPal_Rest', 'key' => '80af24a6a691230bbec33e930ab40665', 'fields' => '{"clientId":"","secret":"","signature":"","testMode":false}'], ['id' => 60, 'name' => 'PayPal REST', 'provider' => 'PayPal_Rest', 'key' => '80af24a6a691230bbec33e930ab40665', 'fields' => '{"clientId":"","secret":"","signature":"","testMode":false}'],
['id' => 61, 'name' => 'PayPal Platform', 'provider' => 'PayPal_PPCP', 'key' => '80af24a6a691230bbec33e930ab40666', 'fields' => '{"testMode":false}'],
]; ];
foreach ($gateways as $gateway) { foreach ($gateways as $gateway) {
@ -103,9 +104,8 @@ class PaymentLibrariesSeeder extends Seeder
Gateway::whereIn('id', [1,3,7,11,15,20,39,46,55,50,57,52,58,59,60])->update(['visible' => 1]); Gateway::whereIn('id', [1,3,7,11,15,20,39,46,55,50,57,52,58,59,60])->update(['visible' => 1]);
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
Gateway::whereIn('id', [20])->update(['visible' => 0]); Gateway::whereIn('id', [20,49])->update(['visible' => 0]);
Gateway::whereIn('id', [56])->update(['visible' => 1]); Gateway::whereIn('id', [56,61])->update(['visible' => 1]);
Gateway::whereIn('id', [49])->update(['visible' => 1]);
} }
Gateway::all()->each(function ($gateway) { Gateway::all()->each(function ($gateway) {

View File

@ -5213,6 +5213,10 @@ $LANG = array(
'payment_email_all_contacts' => 'Payment Email To All Contacts', 'payment_email_all_contacts' => 'Payment Email To All Contacts',
'payment_email_all_contacts_help' => 'Sends the payment email to all contacts when enabled', 'payment_email_all_contacts_help' => 'Sends the payment email to all contacts when enabled',
'add_line' => 'Add Line', 'add_line' => 'Add Line',
'activity_139' => 'Expense :expense notification sent to :contact',
'vendor_notification_subject' => 'Confirmation of payment :amount sent to :vendor',
'vendor_notification_body' => 'Payment processed for :amount dated :payment_date. <br>[Transaction Reference: :transaction_reference]',
); );
return $LANG; return $LANG;

View File

@ -0,0 +1,69 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title' => 'PayPal'])
@section('gateway_head')
<link
rel="stylesheet"
type="text/css"
href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css"
/>
@endsection
@section('gateway_content')
<form action="{{ route('client.payments.response') }}" method="post" id="server_response">
@csrf
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
<input type="hidden" name="gateway_type_id" id="gateway_type_id" value="{{ $gateway_type_id }}">
<input type="hidden" name="gateway_response" id="gateway_response">
<input type="hidden" name="amount_with_fee" id="amount_with_fee" value="{{ $total['amount_with_fee'] }}"/>
</form>
<div class="alert alert-failure mb-4" hidden id="errors"></div>
<div id="paypal-button-container" class="paypal-button-container"></div>
@endsection
@section('gateway_footer')
@endsection
@push('footer')
<script src="https://www.paypal.com/sdk/js?client-id={!! $client_id !!}&merchant-id={!! $merchantId !!}&components=buttons,funding-eligibility&intent=capture" data-partner-attribution-id="invoiceninja_SP_PPCP"></script>
<div id="paypal-button-container"></div>
<script>
//&buyer-country=US&currency=USD&enable-funding=venmo
const fundingSource = "{!! $funding_source !!}";
const testMode = {{ $gateway->company_gateway->getConfigField('testMode') }};
const clientId = "{{ $client_id }}";
const sandbox = { sandbox: clientId };
const production = { production: clientId };
const orderId = "{!! $order_id !!}";
paypal.Buttons({
env: testMode ? 'sandbox' : 'production',
fundingSource: fundingSource,
client: testMode ? sandbox : production,
createOrder: function(data, actions) {
return orderId;
},
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
document.getElementById("gateway_response").value =JSON.stringify( details );
document.getElementById("server_response").submit();
});
},
onCancel: function() {
window.location.href = "/client/invoices/";
},
onError: function(error) {
document.getElementById("gateway_response").value = error;
document.getElementById("server_response").submit();
}
}).render('#paypal-button-container');
</script>
@endpush

View File

@ -11,18 +11,19 @@
namespace Tests\Feature; namespace Tests\Feature;
use App\DataMapper\CompanySettings; use Tests\TestCase;
use App\Http\Middleware\PasswordProtection;
use App\Models\Company; use App\Models\Company;
use App\Models\TaxRate;
use Tests\MockAccountData;
use App\Models\CompanyToken; use App\Models\CompanyToken;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Http\UploadedFile; use Illuminate\Http\UploadedFile;
use App\DataMapper\CompanySettings;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
use Tests\MockAccountData; use App\Http\Middleware\PasswordProtection;
use Tests\TestCase; use Illuminate\Foundation\Testing\DatabaseTransactions;
/** /**
* @test * @test
@ -49,6 +50,18 @@ class CompanyTest extends TestCase
$this->makeTestData(); $this->makeTestData();
} }
public function testCompanyTaxInit()
{
TaxRate::query()->delete();
$settings = $this->company->settings;
$settings->country_id = '40';
$this->company->saveSettings($settings, $this->company);
$this->company->service()->localizeCompany($this->user);
$this->assertEquals(1, TaxRate::count());
}
public function testCompanyLogoInline() public function testCompanyLogoInline()
{ {