diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index a2af497142a0..54d37fb968ca 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -530,9 +530,11 @@ class Invoice extends BaseModel { return $this->hasOne(Expense::class); } - + /** * Service entry points. + * + * @return InvoiceService */ public function service() :InvoiceService { diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 4ac61df44875..cbe27295b112 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -720,6 +720,27 @@ class BaseDriver extends AbstractPaymentDriver return $types; } + public function getStatementDescriptor(): string + { + App::forgetInstance('translator'); + $t = app('translator'); + $t->replace(Ninja::transformTranslations($this->client->getMergedSettings())); + App::setLocale($this->client->company->locale()); + + if (! $this->payment_hash || !$this->client) + return ' '; + + $invoices_string = \implode(', ', collect($this->payment_hash->invoices())->pluck('invoice_number')->toArray()) ?: null; + + $invoices_string = str_replace(["*","<",">","'",'"'], "-", $invoices_string); + + $invoices_string = substr($invoices_string,0,22); + + $invoices_string = str_pad($invoices_string, 5, "_"); + + return $invoices_string; + + } /** * Generic description handler */ @@ -735,7 +756,7 @@ class BaseDriver extends AbstractPaymentDriver } $invoices_string = \implode(', ', collect($this->payment_hash->invoices())->pluck('invoice_number')->toArray()) ?: null; - $amount = Number::formatMoney($this->payment_hash?->amount_with_fee() ?: 0, $this->client); + $amount = Number::formatMoney($this->payment_hash?->amount_with_fee() ?? 0, $this->client); if($abbreviated && $invoices_string){ return $invoices_string; diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index 631e2a7be670..f39a9e4bbf41 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -201,6 +201,7 @@ class ACH 'payment_hash' => $this->stripe->payment_hash->hash, 'gateway_type_id' => GatewayType::BANK_TRANSFER, ], + 'statement_descriptor' => $this->stripe->getStatementDescriptor(), ] ); } diff --git a/app/Services/Chart/ChartQueries.php b/app/Services/Chart/ChartQueries.php index 5f7bd651b7f1..f4d0fb509d39 100644 --- a/app/Services/Chart/ChartQueries.php +++ b/app/Services/Chart/ChartQueries.php @@ -108,7 +108,7 @@ trait ChartQueries return DB::select(DB::raw(" SELECT sum(invoices.balance) as amount, - count(invoices.id) as outstanding_count, + COUNT(*) as outstanding_count, IFNULL(CAST(JSON_UNQUOTE(JSON_EXTRACT( clients.settings, '$.currency_id' )) AS SIGNED), :company_currency) AS currency_id FROM clients JOIN invoices diff --git a/app/Services/Chart/ChartService.php b/app/Services/Chart/ChartService.php index 080cbb8910f9..52673fe5403b 100644 --- a/app/Services/Chart/ChartService.php +++ b/app/Services/Chart/ChartService.php @@ -93,17 +93,23 @@ class ChartService $data['currencies'] = $this->getCurrencyCodes(); - foreach ($data['currencies'] as $key => $value) { - - $revenue = $this->getRevenue($start_date, $end_date); - $outstanding = $this->getOutstanding($start_date, $end_date); - $expenses = $this->getExpenses($start_date, $end_date); - $invoices = $this->getInvoices($start_date, $end_date); + $revenue = $this->getRevenue($start_date, $end_date); + $outstanding = $this->getOutstanding($start_date, $end_date); + $expenses = $this->getExpenses($start_date, $end_date); + $invoices = $this->getInvoices($start_date, $end_date); + + foreach ($data['currencies'] as $key => $value) { + + $invoices_set = array_search($key, array_column($invoices, 'currency_id')); + $revenue_set = array_search($key, array_column($revenue, 'currency_id')); + $outstanding_set = array_search($key, array_column($outstanding, 'currency_id')); + $expenses_set = array_search($key, array_column($expenses, 'currency_id')); + + $data[$key]['invoices'] = $invoices_set !== false ? $invoices[array_search($key, array_column($invoices, 'currency_id'))] : new \stdClass; + $data[$key]['revenue'] = $revenue_set !== false ? $revenue[array_search($key, array_column($revenue, 'currency_id'))] : new \stdClass; + $data[$key]['outstanding'] = $outstanding_set !== false ? $outstanding[array_search($key, array_column($outstanding, 'currency_id'))] : new \stdClass; + $data[$key]['expenses'] = $expenses_set !== false ? $expenses[array_search($key, array_column($expenses, 'currency_id'))] : new \stdClass; - $data[$key]['invoices'] = count($invoices) > 0 ? $invoices[array_search($key, array_column($invoices, 'currency_id'))] : new \stdClass; - $data[$key]['revenue'] = count($revenue) > 0 ? $revenue[array_search($key, array_column($revenue, 'currency_id'))] : new \stdClass; - $data[$key]['outstanding'] = count($outstanding) > 0 ? $outstanding[array_search($key, array_column($outstanding, 'currency_id'))] : new \stdClass; - $data[$key]['expenses'] = count($expenses) > 0 ? $expenses[array_search($key, array_column($expenses, 'currency_id'))] : new \stdClass; } return $data; diff --git a/app/Services/Invoice/InvoiceService.php b/app/Services/Invoice/InvoiceService.php index 4d13f104d23e..f0dc04a88a26 100644 --- a/app/Services/Invoice/InvoiceService.php +++ b/app/Services/Invoice/InvoiceService.php @@ -48,8 +48,15 @@ class InvoiceService return $this; } - - public function applyPaymentAmount($amount, ?string $reference = null) + + /** + * applyPaymentAmount + * + * @param float $amount + * @param ?string $reference + * @return self + */ + public function applyPaymentAmount($amount, ?string $reference = null): self { $this->invoice = (new ApplyPaymentAmount($this->invoice, $amount, $reference))->run(); diff --git a/composer.json b/composer.json index adf2e9cbe051..404e9f31da19 100644 --- a/composer.json +++ b/composer.json @@ -84,6 +84,7 @@ "shopify/shopify-api": "^4.3", "socialiteproviders/apple": "^5.2", "socialiteproviders/microsoft": "^4.1", + "spatie/laravel-data": "^3.5", "sprain/swiss-qr-bill": "^3.2", "square/square": "13.0.0.20210721", "stripe/stripe-php": "^7.50", diff --git a/composer.lock b/composer.lock index 71488b238373..b550e3685fd4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c5abc776f4fd59ba436de99f6c401429", + "content-hash": "358ef9c0394067f5ea70855a928687cf", "packages": [ { "name": "adrienrn/php-mimetyper", @@ -7594,6 +7594,117 @@ }, "time": "2020-07-07T09:29:14+00:00" }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.7.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "dfc078e8af9c99210337325ff5aa152872c98714" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", + "reference": "dfc078e8af9c99210337325ff5aa152872c98714", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" + }, + "time": "2023-03-27T19:02:04+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.1", @@ -9654,6 +9765,149 @@ }, "time": "2023-03-02T09:58:36+00:00" }, + { + "name": "spatie/laravel-data", + "version": "3.5.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-data.git", + "reference": "4c3c31d7d9a515125bfa219099c4df563e4422a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-data/zipball/4c3c31d7d9a515125bfa219099c4df563e4422a8", + "reference": "4c3c31d7d9a515125bfa219099c4df563e4422a8", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^9.30|^10.0", + "php": "^8.1", + "phpdocumentor/type-resolver": "^1.5", + "spatie/laravel-package-tools": "^1.9.0" + }, + "require-dev": { + "fakerphp/faker": "^1.14", + "friendsofphp/php-cs-fixer": "^3.0", + "inertiajs/inertia-laravel": "^0.6.3", + "nesbot/carbon": "^2.63", + "nette/php-generator": "^3.5", + "nunomaduro/larastan": "^2.0", + "orchestra/testbench": "^7.6|^8.0", + "pestphp/pest": "^1.22", + "pestphp/pest-plugin-laravel": "^1.3", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpunit/phpunit": "^9.3", + "spatie/invade": "^1.0", + "spatie/laravel-typescript-transformer": "^2.1.6", + "spatie/pest-plugin-snapshots": "^1.1", + "spatie/phpunit-snapshot-assertions": "^4.2", + "spatie/test-time": "^1.2" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\LaravelData\\LaravelDataServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\LaravelData\\": "src", + "Spatie\\LaravelData\\Database\\Factories\\": "database/factories" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ruben Van Assche", + "email": "ruben@spatie.be", + "role": "Developer" + } + ], + "description": "Create unified resources and data transfer objects", + "homepage": "https://github.com/spatie/laravel-data", + "keywords": [ + "laravel", + "laravel-data", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-data/issues", + "source": "https://github.com/spatie/laravel-data/tree/3.5.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2023-05-05T15:24:41+00:00" + }, + { + "name": "spatie/laravel-package-tools", + "version": "1.15.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "efab1844b8826443135201c4443690f032c3d533" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/efab1844b8826443135201c4443690f032c3d533", + "reference": "efab1844b8826443135201c4443690f032c3d533", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^9.28|^10.0", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "orchestra/testbench": "^7.7|^8.0", + "pestphp/pest": "^1.22", + "phpunit/phpunit": "^9.5.24", + "spatie/pest-plugin-test-time": "^1.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", + "keywords": [ + "laravel-package-tools", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.15.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2023-04-27T08:09:01+00:00" + }, { "name": "sprain/swiss-qr-bill", "version": "v3.3", @@ -15834,59 +16088,6 @@ }, "time": "2023-02-09T12:12:19+00:00" }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, { "name": "phpdocumentor/reflection-docblock", "version": "5.3.0", @@ -15944,64 +16145,6 @@ }, "time": "2021-10-19T17:43:47+00:00" }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.7.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "dfc078e8af9c99210337325ff5aa152872c98714" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", - "reference": "dfc078e8af9c99210337325ff5aa152872c98714", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.13" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" - }, - "time": "2023-03-27T19:02:04+00:00" - }, { "name": "phpmyadmin/sql-parser", "version": "5.7.0", diff --git a/config/data.php b/config/data.php new file mode 100644 index 000000000000..2095a5d85602 --- /dev/null +++ b/config/data.php @@ -0,0 +1,71 @@ + DATE_ATOM, + + /* + * Global transformers will take complex types and transform them into simple + * types. + */ + 'transformers' => [ + DateTimeInterface::class => \Spatie\LaravelData\Transformers\DateTimeInterfaceTransformer::class, + \Illuminate\Contracts\Support\Arrayable::class => \Spatie\LaravelData\Transformers\ArrayableTransformer::class, + BackedEnum::class => Spatie\LaravelData\Transformers\EnumTransformer::class, + ], + + /* + * Global casts will cast values into complex types when creating a data + * object from simple types. + */ + 'casts' => [ + DateTimeInterface::class => Spatie\LaravelData\Casts\DateTimeInterfaceCast::class, + BackedEnum::class => Spatie\LaravelData\Casts\EnumCast::class, + ], + + /* + * Rule inferrers can be configured here. They will automatically add + * validation rules to properties of a data object based upon + * the type of the property. + */ + 'rule_inferrers' => [ + Spatie\LaravelData\RuleInferrers\SometimesRuleInferrer::class, + Spatie\LaravelData\RuleInferrers\NullableRuleInferrer::class, + Spatie\LaravelData\RuleInferrers\RequiredRuleInferrer::class, + Spatie\LaravelData\RuleInferrers\BuiltInTypesRuleInferrer::class, + Spatie\LaravelData\RuleInferrers\AttributesRuleInferrer::class, + ], + + /** + * Normalizers return an array representation of the payload, or null if + * it cannot normalize the payload. The normalizers below are used for + * every data object, unless overridden in a specific data object class. + */ + 'normalizers' => [ + Spatie\LaravelData\Normalizers\ModelNormalizer::class, + // Spatie\LaravelData\Normalizers\FormRequestNormalizer::class, + Spatie\LaravelData\Normalizers\ArrayableNormalizer::class, + Spatie\LaravelData\Normalizers\ObjectNormalizer::class, + Spatie\LaravelData\Normalizers\ArrayNormalizer::class, + Spatie\LaravelData\Normalizers\JsonNormalizer::class, + ], + + /* + * Data objects can be wrapped into a key like 'data' when used as a resource, + * this key can be set globally here for all data objects. You can pass in + * `null` if you want to disable wrapping. + */ + 'wrap' => null, + + /** + * Adds a specific caster to the Symphony VarDumper component which hides + * some properties from data objects and collections when being dumped + * by `dump` or `dd`. Can be 'enabled', 'disabled' or 'development' + * which will only enable the caster locally. + */ + 'var_dumper_caster_mode' => 'development', +];