diff --git a/.gitignore b/.gitignore index 3d742f5..d05c61e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ phpunit.xml build coverage docs +/vendor +/phpunit.xml diff --git a/composer.json b/composer.json index 8414d62..df77e7e 100644 --- a/composer.json +++ b/composer.json @@ -20,29 +20,19 @@ ], "homepage": "https://github.com/asciisd/cashier-tap", "require": { - "php": "^8.2", - "ext-json": "*", - "ext-intl": "*", - "dompdf/dompdf": "^2.0.1", - "illuminate/console": "^9.0|^10.0", - "illuminate/contracts": "^9.0|^10.0", - "illuminate/database": "^9.0|^10.0", - "illuminate/http": "^9.0|^10.0", - "illuminate/log": "^9.0|^10.0", - "illuminate/notifications": "^9.0|^10.0", - "illuminate/routing": "^9.0|^10.0", - "illuminate/support": "^9.0|^10.0", - "illuminate/view": "^9.0|^10.0", + "php": "^8.3", + "dompdf/dompdf": "^2.0", "moneyphp/money": "^4.0", - "nesbot/carbon": "^2.0", - "symfony/http-kernel": "^6.0", - "symfony/polyfill-intl-icu": "^1.22.1", - "asciisd/tap-php": "^2.0" + "asciisd/tap-php": "^2.0", + "ext-intl": "*" }, "require-dev": { + "ext-json": "*", + "laravel/framework": "^10.0|^11.0", "mockery/mockery": "^1.0", - "orchestra/testbench": "^6.0|^7.0", - "phpunit/phpunit": "^9.0|^10.0" + "orchestra/testbench": "^8.18|^9.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.4" }, "suggest": { "ext-intl": "Allows for more locales besides the default \"en\" when formatting money values." @@ -64,12 +54,11 @@ ] } }, - "scripts": { - "test": "vendor/bin/phpunit --colors=always", - "test-coverage": "vendor/bin/phpunit --coverage-html coverage" - }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } }, "minimum-stability": "stable", "prefer-stable": true diff --git a/config/cashier.php b/config/cashier.php index 8c2b031..508ef7d 100644 --- a/config/cashier.php +++ b/config/cashier.php @@ -59,19 +59,6 @@ 'redirect_url' => env('CASHIER_REDIRECT_URL', '/tap/receipt'), - /* - |-------------------------------------------------------------------------- - | Cashier Model - |-------------------------------------------------------------------------- - | - | This is the model in your application that implements the Billable trait - | provided by Cashier. It will serve as the primary model you use while - | interacting with Cashier related methods, subscriptions, and so on. - | - */ - - 'model' => env('CASHIER_MODEL', App\Models\User::class), - /* |-------------------------------------------------------------------------- | Currency Locale diff --git a/database/migrations/2019_05_03_000001_create_customer_columns.php b/database/migrations/2019_05_03_000001_create_customer_columns.php index 71ff4ba..ae4f7ce 100644 --- a/database/migrations/2019_05_03_000001_create_customer_columns.php +++ b/database/migrations/2019_05_03_000001_create_customer_columns.php @@ -4,14 +4,12 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateCustomerColumns extends Migration +return new class extends Migration { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::table('users', function (Blueprint $table) { if (!Schema::hasColumn('users', 'first_name')) { @@ -45,10 +43,8 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::table('users', function (Blueprint $table) { $table->dropColumn([ @@ -59,4 +55,4 @@ public function down() ]); }); } -} +}; diff --git a/database/migrations/2019_05_03_000002_create_subscriptions_table.php b/database/migrations/2019_05_03_000002_create_subscriptions_table.php index a115a29..e63d119 100644 --- a/database/migrations/2019_05_03_000002_create_subscriptions_table.php +++ b/database/migrations/2019_05_03_000002_create_subscriptions_table.php @@ -4,14 +4,12 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateSubscriptionsTable extends Migration +return new class extends Migration { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('subscriptions', function (Blueprint $table) { $table->bigIncrements('id'); @@ -31,11 +29,9 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::dropIfExists('subscriptions'); } -} +}; diff --git a/database/migrations/2019_05_03_000003_create_subscription_items_table.php b/database/migrations/2019_05_03_000003_create_subscription_items_table.php index be4d7db..eb859f2 100644 --- a/database/migrations/2019_05_03_000003_create_subscription_items_table.php +++ b/database/migrations/2019_05_03_000003_create_subscription_items_table.php @@ -4,14 +4,12 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class CreateSubscriptionItemsTable extends Migration +return new class extends Migration { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('subscription_items', function (Blueprint $table) { $table->bigIncrements('id'); @@ -27,11 +25,9 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::dropIfExists('subscription_items'); } -} +}; diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a2eda27..7b52510 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,18 +1,6 @@ - + - - ./tests - ./tests/Unit @@ -24,9 +12,7 @@ - - diff --git a/src/Billable.php b/src/Billable.php index a23b4c7..63f960c 100644 --- a/src/Billable.php +++ b/src/Billable.php @@ -9,20 +9,6 @@ use Asciisd\Cashier\Concerns\ManagesSubscriptions; use Asciisd\Cashier\Concerns\PerformsCharges; -/** - * Trait Billable - * - * @property integer $tap_id - * @property string $email - * @property string $phone - * @property string $phone_code - * @property string $first_name - * @property string $last_name - * @property string $card_brand - * @property string $trial_ends_at - * - * @package Asciisd\Cashier - */ trait Billable { use ManagesCustomer; diff --git a/src/Cashier.php b/src/Cashier.php index 3c3264a..9c6e9b9 100644 --- a/src/Cashier.php +++ b/src/Cashier.php @@ -18,17 +18,13 @@ class Cashier /** * The Cashier library version. - * - * @var string */ - const VERSION = '2.1.1'; + const string VERSION = '3.0.0'; /** * The Tap API version. - * - * @var string */ - const TAP_VERSION = 'v2'; + const string TAP_VERSION = 'v2'; /** * The custom currency formatter. @@ -39,36 +35,33 @@ class Cashier /** * Indicates if Cashier migrations will be run. - * - * @var bool */ public static bool $runsMigrations = true; /** * Indicates if Cashier routes will be registered. - * - * @var bool */ public static bool $registersRoutes = true; + /** + * The default customer model class name. + */ + public static string $customerModel = 'App\\Models\\User'; + + /** * Get the default Tap API options. - * - * @param array $options - * @return array */ public static function tapOptions(array $options = []): array { return array_merge([ - 'api_key' => config('cashier.secret'), + 'api_key' => config('cashier.secret'), 'tap_version' => static::TAP_VERSION, ], $options); } /** * Configure Cashier to not register its migrations. - * - * @return static */ public static function ignoreMigrations(): static { @@ -79,8 +72,6 @@ public static function ignoreMigrations(): static /** * Configure Cashier to not register its routes. - * - * @return static */ public static function ignoreRoutes(): static { @@ -89,13 +80,16 @@ public static function ignoreRoutes(): static return new static; } + /** + * Set the custom currency formatter. + */ + public static function formatCurrencyUsing(callable $callback): void + { + static::$formatCurrencyUsing = $callback; + } + /** * Format the given amount into a displayable currency. - * - * @param int $amount - * @param string|null $currency - * @param int $multiply_by - * @return string */ public static function formatAmount(int $amount, string $currency = null, int $multiply_by = 100): string { @@ -113,20 +107,14 @@ public static function formatAmount(int $amount, string $currency = null, int $m /** * generate receipt link to show the charge receipt on web - * - * @param $receipt_id - * @return string */ public static function receipt($receipt_id): string { - return config('cashier.redirect_url') . '?tap_id=' . $receipt_id; + return config('cashier.redirect_url').'?tap_id='.$receipt_id; } /** * Get the billable entity instance by Stripe ID. - * - * @param string $tapId - * @return ?Billable */ public static function findBillable(string $tapId): ?Billable { @@ -134,8 +122,16 @@ public static function findBillable(string $tapId): ?Billable return null; } - $model = config('cashier.model'); + $model = static::$customerModel; return (new $model)->where('tap_id', $tapId)->first(); } + + /** + * Set the customer model class name. + */ + public static function useCustomerModel(string $customerModel): void + { + static::$customerModel = $customerModel; + } } diff --git a/src/Concerns/ManagesCustomer.php b/src/Concerns/ManagesCustomer.php index ca5830d..4a4bd28 100644 --- a/src/Concerns/ManagesCustomer.php +++ b/src/Concerns/ManagesCustomer.php @@ -47,7 +47,7 @@ protected function assertCustomerExists(): void /** * Create a Tap customer for the given model. * - * @param array $options + * @param array $options * @return TapCustomer * @throws InvalidCustomer */ @@ -76,7 +76,7 @@ public function createAsTapCustomer(array $options = []): TapCustomer /** * Update the underlying Tap customer information for the model. * - * @param array $options + * @param array $options * @return array|TapCustomer|TapObject */ public function updateTapCustomer(array $options = []): TapObject|array|TapCustomer @@ -89,7 +89,7 @@ public function updateTapCustomer(array $options = []): TapObject|array|TapCusto /** * Get the Tap customer instance for the current user or create one. * - * @param array $options + * @param array $options * @return TapCustomer * @throws InvalidCustomer */ @@ -134,7 +134,7 @@ public function tapPhone(): array { return [ 'country_code' => $this->phone_code, - 'number' => $this->phone + 'number' => $this->phone ]; } @@ -161,7 +161,7 @@ public function tapLastName(): string /** * Apply a coupon to the billable entity. * - * @param string $coupon + * @param string $coupon * @return void * @throws InvalidCustomer */ @@ -189,7 +189,7 @@ public function preferredCurrency(): string /** * Get the default Tap API options for the current Billable model. * - * @param array $options + * @param array $options * @return array */ public function tapOptions(array $options = []): array @@ -201,9 +201,9 @@ public function tapCustomerFields(): array { return [ 'first_name' => $this->tapFirstName(), - 'last_name' => $this->tapLastName(), - 'email' => $this->tapEmail(), - 'phone' => $this->tapPhone() + 'last_name' => $this->tapLastName(), + 'email' => $this->tapEmail(), + 'phone' => $this->tapPhone() ]; } } diff --git a/src/Concerns/ManagesInvoices.php b/src/Concerns/ManagesInvoices.php index b14d72d..d1f09e1 100644 --- a/src/Concerns/ManagesInvoices.php +++ b/src/Concerns/ManagesInvoices.php @@ -30,8 +30,7 @@ public function createTapInvoice($amount, $trading_account, $currency = 'KWD', $ [ "amount" => $amount, "currency" => $currency, - "description" => "Deposit on account #" - . $trading_account, + "description" => "Deposit on account #".$trading_account, "name" => "Deposit", "quantity" => 1, ], diff --git a/src/Concerns/ManagesPaymentMethods.php b/src/Concerns/ManagesPaymentMethods.php index bd9ed30..1c7a420 100644 --- a/src/Concerns/ManagesPaymentMethods.php +++ b/src/Concerns/ManagesPaymentMethods.php @@ -15,7 +15,7 @@ trait ManagesPaymentMethods */ public function hasPaymentMethod(): bool { - return (bool)$this->card_brand; + return (bool) $this->card_brand; } /** diff --git a/src/Concerns/ManagesSubscriptions.php b/src/Concerns/ManagesSubscriptions.php index b5e7011..d059c18 100644 --- a/src/Concerns/ManagesSubscriptions.php +++ b/src/Concerns/ManagesSubscriptions.php @@ -6,5 +6,5 @@ trait ManagesSubscriptions { - + // Your implementation here } diff --git a/src/Concerns/PerformsCharges.php b/src/Concerns/PerformsCharges.php index e7ce985..37142fe 100644 --- a/src/Concerns/PerformsCharges.php +++ b/src/Concerns/PerformsCharges.php @@ -60,8 +60,8 @@ public function charge(int $amount, string $paymentMethod, array $options = []): /** * Refund a customer for a charge. * - * @param string $charge - * @param array $options + * @param string $charge + * @param array $options * @return array|Customer|Refund|TapObject */ public function refund(string $charge, array $options = []): TapObject|array|Customer|Refund diff --git a/src/Console/PublishCommand.php b/src/Console/PublishCommand.php index 0bbe67a..b9ac258 100644 --- a/src/Console/PublishCommand.php +++ b/src/Console/PublishCommand.php @@ -28,7 +28,7 @@ class PublishCommand extends Command public function handle() { $this->call('vendor:publish', [ - '--tag' => 'cashier-assets', + '--tag' => 'cashier-assets', '--force' => true, ]); } diff --git a/src/Events/TapChargeHandled.php b/src/Events/TapChargeHandled.php index ef274a0..002fb25 100644 --- a/src/Events/TapChargeHandled.php +++ b/src/Events/TapChargeHandled.php @@ -12,19 +12,17 @@ class TapChargeHandled /** * The webhook payload. - * - * @var array */ - public $payload; + public array $payload; /** * Create a new event instance. * - * @param TapWebhookRequest $payload + * @param TapWebhookRequest $payload * @return void */ public function __construct(TapWebhookRequest $payload) { - $this->payload = $payload; + $this->payload = $payload->toArray(); } } diff --git a/src/Events/TapReceiptSeen.php b/src/Events/TapReceiptSeen.php index 9e54f8b..18c5ad9 100644 --- a/src/Events/TapReceiptSeen.php +++ b/src/Events/TapReceiptSeen.php @@ -13,15 +13,13 @@ class TapReceiptSeen /** * The seen charge. - * - * @var Payment */ - public $payment; + public Payment $payment; /** * Create a new event instance. * - * @param Payment $payment + * @param Payment $payment * @return void */ public function __construct(Payment $payment) diff --git a/src/Events/WebhookHandled.php b/src/Events/WebhookHandled.php index a44bbe6..dcbba34 100644 --- a/src/Events/WebhookHandled.php +++ b/src/Events/WebhookHandled.php @@ -12,19 +12,17 @@ class WebhookHandled /** * The webhook payload. - * - * @var array */ - public $payload; + public array $payload; /** * Create a new event instance. * - * @param TapWebhookRequest $payload + * @param TapWebhookRequest $payload * @return void */ public function __construct(TapWebhookRequest $payload) { - $this->payload = $payload; + $this->payload = $payload->toArray(); } } diff --git a/src/Events/WebhookReceived.php b/src/Events/WebhookReceived.php index e4fc298..06c4f02 100644 --- a/src/Events/WebhookReceived.php +++ b/src/Events/WebhookReceived.php @@ -15,16 +15,16 @@ class WebhookReceived * * @var array */ - public $payload; + public array $payload; /** * Create a new event instance. * - * @param TapWebhookRequest $payload + * @param TapWebhookRequest $payload * @return void */ public function __construct(TapWebhookRequest $payload) { - $this->payload = $payload; + $this->payload = $payload->toArray(); } } diff --git a/src/Exceptions/CustomerAlreadyCreated.php b/src/Exceptions/CustomerAlreadyCreated.php index ecaf73b..bf9fcdb 100644 --- a/src/Exceptions/CustomerAlreadyCreated.php +++ b/src/Exceptions/CustomerAlreadyCreated.php @@ -3,13 +3,14 @@ namespace Asciisd\Cashier\Exceptions; use Exception; +use Illuminate\Database\Eloquent\Model; class CustomerAlreadyCreated extends Exception { /** * Create a new CustomerAlreadyCreated instance. * - * @param \Illuminate\Database\Eloquent\Model $owner + * @param Model $owner * @return static */ public static function exists($owner) diff --git a/src/Exceptions/IncompletePayment.php b/src/Exceptions/IncompletePayment.php index ccb26c6..26b49fa 100644 --- a/src/Exceptions/IncompletePayment.php +++ b/src/Exceptions/IncompletePayment.php @@ -10,18 +10,16 @@ class IncompletePayment extends Exception { /** * The Cashier Payment object. - * - * @var Payment */ - public $payment; + public Payment $payment; /** * Create a new IncompletePayment instance. * - * @param Payment $payment + * @param Payment $payment * @param string $message * @param int $code - * @param Throwable|null $previous + * @param Throwable|null $previous * @return void */ public function __construct(Payment $payment, $message = '', $code = 0, Throwable $previous = null) diff --git a/src/Exceptions/InvalidCustomer.php b/src/Exceptions/InvalidCustomer.php index 2e43739..c08b9fa 100644 --- a/src/Exceptions/InvalidCustomer.php +++ b/src/Exceptions/InvalidCustomer.php @@ -9,23 +9,17 @@ class InvalidCustomer extends Exception { /** * Create a new InvalidTapCustomer instance. - * - * @param Model $owner - * @return static */ - public static function nonCustomer($owner) + public static function nonCustomer(Model $owner): static { - return new static(class_basename($owner) . ' is not a Tap customer. See the createAsTapCustomer method.'); + return new static(class_basename($owner).' is not a Tap customer. See the createAsTapCustomer method.'); } /** * Create a new InvalidTapCustomer instance. - * - * @param Model $owner - * @return static */ - public static function exists($owner) + public static function exists(Model $owner): static { - return new static(class_basename($owner) . " is already a Tap customer with ID {$owner->tap_id}."); + return new static(class_basename($owner)." is already a Tap customer with ID {$owner->tap_id}."); } } diff --git a/src/Exceptions/InvalidPaymentMethod.php b/src/Exceptions/InvalidPaymentMethod.php index 7decd6b..68e3dc3 100644 --- a/src/Exceptions/InvalidPaymentMethod.php +++ b/src/Exceptions/InvalidPaymentMethod.php @@ -2,20 +2,16 @@ namespace Asciisd\Cashier\Exceptions; -use Asciisd\Cashier\PaymentMethod; use Exception; use Illuminate\Database\Eloquent\Model; +use Tap\PaymentMethod; class InvalidPaymentMethod extends Exception { /** * Create a new InvalidPaymentMethod instance. - * - * @param PaymentMethod $paymentMethod - * @param Model $owner - * @return static */ - public static function invalidOwner($paymentMethod, $owner) + public static function invalidOwner(PaymentMethod $paymentMethod, Model $owner): static { return new static( "The payment method `{$paymentMethod->id}` does not belong to this customer `$owner->tap_id`." diff --git a/src/Exceptions/PaymentActionRequired.php b/src/Exceptions/PaymentActionRequired.php index 28dee55..f398295 100644 --- a/src/Exceptions/PaymentActionRequired.php +++ b/src/Exceptions/PaymentActionRequired.php @@ -8,11 +8,8 @@ class PaymentActionRequired extends IncompletePayment { /** * Create a new PaymentActionRequired instance. - * - * @param Payment $payment - * @return static */ - public static function incomplete(Payment $payment) + public static function incomplete(Payment $payment): static { return new static( $payment, diff --git a/src/Exceptions/PaymentFailure.php b/src/Exceptions/PaymentFailure.php index 60ae655..9ccbd16 100644 --- a/src/Exceptions/PaymentFailure.php +++ b/src/Exceptions/PaymentFailure.php @@ -8,11 +8,8 @@ class PaymentFailure extends IncompletePayment { /** * Create a new PaymentFailure instance. - * - * @param Payment $payment - * @return static */ - public static function invalidPaymentMethod(Payment $payment) + public static function invalidPaymentMethod(Payment $payment): static { return new static( $payment, diff --git a/src/Http/Controllers/PaymentController.php b/src/Http/Controllers/PaymentController.php index 481f0a9..9d3e6fb 100644 --- a/src/Http/Controllers/PaymentController.php +++ b/src/Http/Controllers/PaymentController.php @@ -14,14 +14,11 @@ class PaymentController { /** * Display the form to gather additional payment verification for the given payment. - * - * @param Request $request - * @return View */ public function show(Request $request) { return view('cashier::receipt', [ - 'payment' => new Payment( + 'payment' => new Payment( Charge::retrieve($request->tap_id, Cashier::tapOptions()) ), 'redirect' => request('redirect'), diff --git a/src/Http/Controllers/ReceiptController.php b/src/Http/Controllers/ReceiptController.php index b461af3..8b82b57 100644 --- a/src/Http/Controllers/ReceiptController.php +++ b/src/Http/Controllers/ReceiptController.php @@ -14,9 +14,6 @@ class ReceiptController { /** * Display receipt. - * - * @param ReceiptRequest $request - * @return View */ public function show(ReceiptRequest $request) { @@ -24,10 +21,6 @@ public function show(ReceiptRequest $request) Charge::retrieve($request->tap_id, Cashier::tapOptions()) ); -// if ($request->user()->tap_id !== $payment->owner()->tap_id) { -// throw new UnauthorizedException('Sorry! But this invoice did\'t belongs to you.'); -// } - TapReceiptSeen::dispatch($payment); return view('cashier::receipt', ['payment' => $payment] + Cashier::invoiceDataFor($payment->owner())); diff --git a/src/Http/Controllers/WebhookController.php b/src/Http/Controllers/WebhookController.php index 411345e..dbea33e 100644 --- a/src/Http/Controllers/WebhookController.php +++ b/src/Http/Controllers/WebhookController.php @@ -2,7 +2,6 @@ namespace Asciisd\Cashier\Http\Controllers; -use Asciisd\Cashier\Billable; use Asciisd\Cashier\Cashier; use Asciisd\Cashier\Events\TapChargeHandled; use Asciisd\Cashier\Events\WebhookHandled; @@ -34,15 +33,12 @@ public function __construct() /** * Handle a Tap webhook call. - * - * @param TapWebhookRequest $request - * @return Response */ public function handleWebhook(TapWebhookRequest $request) { logger()->info('WebhookController | handleWebhook', request()->all()); - $method = 'handle' . Str::studly($request->input('object')); + $method = 'handle'.Str::studly($request->input('object')); WebhookReceived::dispatch($request); @@ -65,9 +61,6 @@ protected function handleCharge(TapWebhookRequest $request) /** * Handle payment action required for invoice. - * - * @param array $payload - * @return Response */ protected function handleInvoicePaymentActionRequired(array $payload) { @@ -90,9 +83,6 @@ protected function handleInvoicePaymentActionRequired(array $payload) /** * Get the billable entity instance by Tap ID. - * - * @param string|null $tapId - * @return Billable|null */ protected function getUserByTapId($tapId) { @@ -101,9 +91,6 @@ protected function getUserByTapId($tapId) /** * Handle successful calls on the controller. - * - * @param array $parameters - * @return Response */ protected function successMethod($parameters = []) { @@ -112,9 +99,6 @@ protected function successMethod($parameters = []) /** * Handle calls to missing methods on the controller. - * - * @param array $parameters - * @return Response */ protected function missingMethod($parameters = []) { diff --git a/src/Http/Middleware/VerifyWebhookSignature.php b/src/Http/Middleware/VerifyWebhookSignature.php index d581a33..466ba0e 100644 --- a/src/Http/Middleware/VerifyWebhookSignature.php +++ b/src/Http/Middleware/VerifyWebhookSignature.php @@ -5,7 +5,6 @@ use Closure; use Illuminate\Http\Request; -use Illuminate\Http\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Tap\Exception\SignatureVerificationException; use Tap\WebhookSignature; @@ -15,16 +14,12 @@ class VerifyWebhookSignature /** * Handle the incoming request. * - * @param Request $request - * @param Closure $next - * @return Response - * */ public function handle(Request $request, Closure $next) { logger()->info('VerifyWebhookSignature@handle'); - logger()->info('Request headers: ' . json_encode($request->header())); - logger()->info('Request: ' . json_encode($request->all())); + logger()->info('Request headers: '.json_encode($request->header())); + logger()->info('Request: '.json_encode($request->all())); try { WebhookSignature::verifyHeader( diff --git a/src/Http/Requests/ReceiptRequest.php b/src/Http/Requests/ReceiptRequest.php index c919865..bf459bf 100644 --- a/src/Http/Requests/ReceiptRequest.php +++ b/src/Http/Requests/ReceiptRequest.php @@ -8,20 +8,16 @@ class ReceiptRequest extends FormRequest { /** * Determine if the user is authorized to make this request. - * - * @return bool */ - public function authorize() + public function authorize(): bool { return true; } /** * Get the validation rules that apply to the request. - * - * @return array */ - public function rules() + public function rules(): array { return [ 'tap_id' => 'required' diff --git a/src/Http/Requests/TapWebhookRequest.php b/src/Http/Requests/TapWebhookRequest.php index 22937b3..b24be4f 100644 --- a/src/Http/Requests/TapWebhookRequest.php +++ b/src/Http/Requests/TapWebhookRequest.php @@ -21,10 +21,8 @@ class TapWebhookRequest extends FormRequest { /** * Determine if the user is authorized to make this request. - * - * @return bool */ - public function authorize() + public function authorize(): bool { logger('TapWebhookRequest | authorize', request()->all()); @@ -33,20 +31,18 @@ public function authorize() /** * Get the validation rules that apply to the request. - * - * @return array */ - public function rules() + public function rules(): array { logger('TapWebhookRequest | rules', request()->all()); return [ - 'id' => 'required', - 'amount' => 'required', - 'currency' => 'required', - 'reference.gateway' => 'required', - 'reference.payment' => 'required', - 'status' => 'required', + 'id' => 'required', + 'amount' => 'required', + 'currency' => 'required', + 'reference.gateway' => 'required', + 'reference.payment' => 'required', + 'status' => 'required', 'transaction.created' => 'required', ]; } diff --git a/src/Logger.php b/src/Logger.php index a37b322..e4ada56 100644 --- a/src/Logger.php +++ b/src/Logger.php @@ -9,16 +9,11 @@ class Logger implements TapLogger { /** * The Logger instance. - * - * @var LoggerInterface */ protected LoggerInterface $logger; /** * Create a new Logger instance. - * - * @param LoggerInterface $logger - * @return void */ public function __construct(LoggerInterface $logger) { diff --git a/src/Payment.php b/src/Payment.php index 0052936..6614188 100644 --- a/src/Payment.php +++ b/src/Payment.php @@ -11,37 +11,23 @@ use Tap\Charge; use Tap\TapObject; -/** - * Class Payment - * - * @property string id - * @property string status - * @property string currency - * - * @package Asciisd\Cashier - */ class Payment { use Downloadable; - const SUCCESS_RESPONSE = ['CAPTURED']; - const NEED_MORE_ACTION = ['INITIATED']; - const FAILED_RESPONSE = [ + const array SUCCESS_RESPONSE = ['CAPTURED']; + const array NEED_MORE_ACTION = ['INITIATED']; + const array FAILED_RESPONSE = [ 'ABANDONED', 'CANCELLED', 'FAILED', 'DECLINED', 'RESTRICTED', 'VOID', 'TIMEDOUT', 'UNKNOWN', 'NOT CAPTURED' ]; /** * The Tap Charge instance. - * - * @var Charge|TapObject */ protected TapObject|Charge $charge; /** * Create a new Payment instance. - * - * @param TapObject $paymentIntent - * @return void */ public function __construct(TapObject $paymentIntent) { @@ -50,8 +36,6 @@ public function __construct(TapObject $paymentIntent) /** * Get the total amount that will be paid. - * - * @return string */ public function amount(): string { @@ -64,8 +48,6 @@ public function amount(): string /** * Get the raw total amount that will be paid. - * - * @return int */ public function rawAmount(): int { @@ -74,8 +56,6 @@ public function rawAmount(): int /** * Determine if the payment needs an extra action like 3D Secure. - * - * @return bool */ public function requiresAction(): bool { @@ -84,8 +64,6 @@ public function requiresAction(): bool /** * get url of charge action - * - * @return string */ public function actionUrl(): string { @@ -94,8 +72,6 @@ public function actionUrl(): string /** * Determine if the payment was cancelled. - * - * @return bool */ public function isCancelled(): bool { @@ -104,8 +80,6 @@ public function isCancelled(): bool /** * Determine if the payment was successful. - * - * @return bool */ public function isSucceeded(): bool { @@ -114,8 +88,6 @@ public function isSucceeded(): bool /** * Determine if the payment is failed. - * - * @return bool */ public function isFailure(): bool { diff --git a/src/Providers/AppServiceProvider.php b/src/Providers/AppServiceProvider.php index 6ec3116..3acc190 100644 --- a/src/Providers/AppServiceProvider.php +++ b/src/Providers/AppServiceProvider.php @@ -9,31 +9,23 @@ class AppServiceProvider extends ServiceProvider { /** * Your application and company details. - * - * @var array */ - protected $details = []; + protected array $details = []; /** - * All of the application developer e-mail addresses. - * - * @var array + * All the application developer e-mail addresses. */ - protected $developers = []; + protected array $developers = []; /** * The address where customer support e-mails should be sent. - * - * @var string */ - protected $sendSupportEmailsTo = null; + protected ?string $sendSupportEmailsTo = null; /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { Cashier::details($this->details); Cashier::sendSupportEmailsTo($this->sendSupportEmailsTo); @@ -45,8 +37,6 @@ public function boot() /** * Register any application services. - * - * @return void */ public function register() { diff --git a/src/Providers/CashierServiceProvider.php b/src/Providers/CashierServiceProvider.php index c13b313..244478f 100644 --- a/src/Providers/CashierServiceProvider.php +++ b/src/Providers/CashierServiceProvider.php @@ -16,11 +16,9 @@ class CashierServiceProvider extends ServiceProvider { /** * Bootstrap the application services. - * - * @return void * @throws BindingResolutionException */ - public function boot() + public function boot(): void { $this->registerLogger(); $this->registerRoutes(); @@ -37,10 +35,8 @@ public function boot() /** * Register the application services. - * - * @return void */ - public function register() + public function register(): void { $this->configure(); $this->bindLogger(); @@ -53,23 +49,19 @@ class_alias('Asciisd\Cashier\Cashier', 'Cashier'); } /** - * Setup the configuration for Cashier. - * - * @return void + * Set up the configuration for Cashier. */ - protected function configure() + protected function configure(): void { $this->mergeConfigFrom( - __DIR__ . '/../../config/cashier.php', 'cashier' + __DIR__.'/../../config/cashier.php', 'cashier' ); } /** * Bind the Stripe logger interface to the Cashier logger. - * - * @return void */ - protected function bindLogger() + protected function bindLogger(): void { $this->app->bind(LoggerInterface::class, function ($app) { return new Logger( @@ -80,11 +72,9 @@ protected function bindLogger() /** * Register the Tap logger. - * - * @return void * @throws BindingResolutionException */ - protected function registerLogger() + protected function registerLogger(): void { if (config('cashier.logger')) { Tap::setLogger($this->app->make(LoggerInterface::class)); @@ -93,81 +83,71 @@ protected function registerLogger() /** * Register the package routes. - * - * @return void */ - protected function registerRoutes() + protected function registerRoutes(): void { if (Cashier::$registersRoutes) { Route::group([ - 'prefix' => config('cashier.path'), + 'prefix' => config('cashier.path'), 'namespace' => 'Asciisd\Cashier\Http\Controllers', - 'as' => 'cashier.', + 'as' => 'cashier.', ], function () { - $this->loadRoutesFrom(__DIR__ . '/../../routes/web.php'); + $this->loadRoutesFrom(__DIR__.'/../../routes/web.php'); }); } } /** * Register the package resources. - * - * @return void */ - protected function registerResources() + protected function registerResources(): void { - $this->loadJsonTranslationsFrom(__DIR__ . '/../../resources/lang'); - $this->loadViewsFrom(__DIR__ . '/../../resources/views', 'cashier'); + $this->loadJsonTranslationsFrom(__DIR__.'/../../resources/lang'); + $this->loadViewsFrom(__DIR__.'/../../resources/views', 'cashier'); } /** * Register the package migrations. - * - * @return void */ - protected function registerMigrations() + protected function registerMigrations(): void { if (Cashier::$runsMigrations && $this->app->runningInConsole()) { - $this->loadMigrationsFrom(__DIR__ . '/../../database/migrations'); + $this->loadMigrationsFrom(__DIR__.'/../../database/migrations'); } } /** * Register the package's publishable resources. - * - * @return void */ - protected function registerPublishing() + protected function registerPublishing(): void { if ($this->app->runningInConsole()) { $this->publishes([ - __DIR__ . '/../../config/cashier.php' => $this->app->configPath('cashier.php'), + __DIR__.'/../../config/cashier.php' => $this->app->configPath('cashier.php'), ], 'cashier-config'); $this->publishes([ - __DIR__ . '/../../database/migrations' => $this->app->databasePath('migrations'), + __DIR__.'/../../database/migrations' => $this->app->databasePath('migrations'), ], 'cashier-migrations'); $this->publishes([ - __DIR__ . '/../../resources/views' => $this->app->resourcePath('views/vendor/cashier'), + __DIR__.'/../../resources/views' => $this->app->resourcePath('views/vendor/cashier'), ], 'cashier-views'); $this->publishes([ - __DIR__ . '/../../public' => public_path('vendor/cashier'), + __DIR__.'/../../public' => public_path('vendor/cashier'), ], 'cashier-assets'); $this->publishes([ - __DIR__ . '/../../stubs/CashierServiceProvider.stub' => app_path('Providers/CashierServiceProvider.php'), + __DIR__.'/../../stubs/CashierServiceProvider.stub' => app_path('Providers/CashierServiceProvider.php'), ], 'cashier-provider'); } } /** * Register the Horizon Artisan commands. - * - * @return void */ - protected function registerCommands() + protected function registerCommands(): void { if ($this->app->runningInConsole()) { $this->commands([ diff --git a/src/Traits/Downloadable.php b/src/Traits/Downloadable.php index 3bcc92a..7677625 100644 --- a/src/Traits/Downloadable.php +++ b/src/Traits/Downloadable.php @@ -12,27 +12,21 @@ trait Downloadable { /** * Get the View instance for the invoice. - * - * @param array $data - * @return \Illuminate\Contracts\View\View */ - public function view(array $data) + public function view(array $data): \Illuminate\Contracts\View\View { return View::make('cashier::pdf_receipt', array_merge($data, [ 'invoice' => $this, - 'owner' => $this->owner() + 'owner' => $this->owner() ])); } /** * Capture the invoice as a PDF and return the raw bytes. - * - * @param array $data - * @return string */ - public function pdf(array $data) + public function pdf(array $data): string { - if (! defined('DOMPDF_ENABLE_AUTOLOAD')) { + if (!defined('DOMPDF_ENABLE_AUTOLOAD')) { define('DOMPDF_ENABLE_AUTOLOAD', false); } @@ -46,11 +40,8 @@ public function pdf(array $data) /** * Create an invoice download response. - * - * @param array $data - * @return Response */ - public function download(array $data) + public function download(array $data): Response { $filename = $data['product'].'_'.$this->date()->month.'_'.$this->date()->year; @@ -59,19 +50,15 @@ public function download(array $data) /** * Create an invoice download response with a specific filename. - * - * @param string $filename - * @param array $data - * @return Response */ - public function downloadAs(string $filename, array $data) + public function downloadAs(string $filename, array $data): Response { return new Response($this->pdf($data), 200, [ - 'Content-Description' => 'File Transfer', - 'Content-Disposition' => 'attachment; filename="'.$filename.'.pdf"', + 'Content-Description' => 'File Transfer', + 'Content-Disposition' => 'attachment; filename="'.$filename.'.pdf"', 'Content-Transfer-Encoding' => 'binary', - 'Content-Type' => 'application/pdf', - 'X-Vapor-Base64-Encode' => 'True', + 'Content-Type' => 'application/pdf', + 'X-Vapor-Base64-Encode' => 'True', ]); } } diff --git a/src/Traits/ManagesAppDetails.php b/src/Traits/ManagesAppDetails.php index 06a1546..a081fc8 100644 --- a/src/Traits/ManagesAppDetails.php +++ b/src/Traits/ManagesAppDetails.php @@ -6,23 +6,16 @@ trait ManagesAppDetails { /** * The application / product details. - * - * @var array */ public static array $details = []; /** * The e-mail addresses of all the application's developers. - * - * @var array */ public static array $developers = []; /** * Define the application information. - * - * @param array $details - * @return void */ public static function details(array $details): void { @@ -31,8 +24,6 @@ public static function details(array $details): void /** * Get the product name from the application information. - * - * @return string */ public static function product(): string { @@ -41,8 +32,6 @@ public static function product(): string /** * Get the invoice meta information, such as product, etc. - * - * @return array */ public static function generateInvoicesWith(): array { @@ -57,9 +46,6 @@ public static function generateInvoicesWith(): array /** * Get the invoice data payload for the given billable entity. - * - * @param mixed $billable - * @return array */ public static function invoiceDataFor(mixed $billable): array { @@ -71,9 +57,6 @@ public static function invoiceDataFor(mixed $billable): array /** * Determine if the given e-mail address belongs to a developer. - * - * @param string $email - * @return bool */ public static function developer(string $email): bool { @@ -92,9 +75,6 @@ public static function developer(string $email): bool /** * Set the e-mail addresses that are registered to developers. - * - * @param array $developers - * @return void */ public static function developers(array $developers): void { diff --git a/src/Traits/ManagesSupportOptions.php b/src/Traits/ManagesSupportOptions.php index ef62276..934d2b8 100644 --- a/src/Traits/ManagesSupportOptions.php +++ b/src/Traits/ManagesSupportOptions.php @@ -8,15 +8,11 @@ trait ManagesSupportOptions { /** * The e-mail address where customer support e-mails should be sent. - * - * @var string */ public static string $sendsSupportEmailsTo; /** * Determine if a support address has been configured. - * - * @return bool */ public static function hasSupportAddress(): bool { @@ -25,8 +21,6 @@ public static function hasSupportAddress(): bool /** * Get the e-mail address to send customer support e-mails to. - * - * @return string */ public static function supportAddress(): string { @@ -35,9 +29,6 @@ public static function supportAddress(): string /** * Set the e-mail address to send customer support e-mails to. - * - * @param string $address - * @return void */ public static function sendSupportEmailsTo(string $address): void { diff --git a/src/Traits/ManagesTwoFactorOptions.php b/src/Traits/ManagesTwoFactorOptions.php index 2d2050a..b199f74 100644 --- a/src/Traits/ManagesTwoFactorOptions.php +++ b/src/Traits/ManagesTwoFactorOptions.php @@ -8,27 +8,21 @@ trait ManagesTwoFactorOptions { /** * Indicates if two-factor authentication is being offered. - * - * @var bool */ - public static $usesTwoFactorAuth = false; + public static bool $usesTwoFactorAuth = false; /** * Determines if two-factor authentication is being offered. - * - * @return bool */ - public static function usesTwoFactorAuth() + public static function usesTwoFactorAuth(): bool { return static::$usesTwoFactorAuth; } /** * Specifies that two-factor authentication should be offered. - * - * @return void */ - public static function useTwoFactorAuth() + public static function useTwoFactorAuth(): void { static::$usesTwoFactorAuth = true; } diff --git a/stubs/CashierServiceProvider.stub b/stubs/CashierServiceProvider.stub index 4f6c082..94019d6 100644 --- a/stubs/CashierServiceProvider.stub +++ b/stubs/CashierServiceProvider.stub @@ -9,48 +9,37 @@ class CashierServiceProvider extends ServiceProvider { /** * Your application and company details. - * - * @var array */ - protected $details = [ - 'vendor' => 'Your Company', - 'product' => 'Your Product', - 'street' => 'PO Box 111', - 'location' => 'Your Town, NY 12345', - 'phone' => '555-555-5555', - 'email' => 'email@example.com', - 'url' => 'https://asciisd.com', + protected array $details = [ + 'vendor' => 'Your Company', + 'product' => 'Your Product', + 'street' => 'PO Box 111', + 'location' => 'Your Town, NY 12345', + 'phone' => '555-555-5555', + 'email' => 'email@example.com', + 'url' => 'https://asciisd.com', 'primary_color' => '#F04D23' ]; /** * The address where customer support e-mails should be sent. - * - * @var string */ - protected $sendSupportEmailsTo = null; + protected ?string $sendSupportEmailsTo = null; /** * All the application developer e-mail addresses. - * - * @var array */ - protected $developers = [ + protected array $developers = [ // ]; /** * Indicates if the application will expose an API. - * - * @var bool */ protected bool $usesApi = true; /** * Finish configuring Spark for the application. - * - * @param Closure $callback - * @return void */ public function booted(Closure $callback) { @@ -59,8 +48,6 @@ class CashierServiceProvider extends ServiceProvider /** * Register any application services. - * - * @return void */ public function register(): void { diff --git a/tests/Feature/ChargesTest.php b/tests/Feature/ChargesTest.php index 587401e..6674f9b 100644 --- a/tests/Feature/ChargesTest.php +++ b/tests/Feature/ChargesTest.php @@ -14,6 +14,8 @@ public function test_customer_can_be_charged() $token = $this->createToken(); + $this->expectException(PaymentActionRequired::class); + $response = $user->charge(100, $token->id); $this->assertInstanceOf(Payment::class, $response); diff --git a/tests/Feature/FeatureTestCase.php b/tests/Feature/FeatureTestCase.php index c351876..c58f87b 100644 --- a/tests/Feature/FeatureTestCase.php +++ b/tests/Feature/FeatureTestCase.php @@ -4,8 +4,8 @@ use Asciisd\Cashier\Tests\Fixtures\User; use Asciisd\Cashier\Tests\TestCase; -use Illuminate\Database\Eloquent\Model as Eloquent; -use Illuminate\Support\Facades\Config; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Orchestra\Testbench\Concerns\WithLaravelMigrations; use Tap\ApiResource; use Tap\Card; use Tap\Exception\InvalidRequestException; @@ -15,49 +15,48 @@ abstract class FeatureTestCase extends TestCase { + use RefreshDatabase, WithLaravelMigrations; + /** * @var string */ protected static string $tapPrefix = 'cashier-test-'; protected static array $test_card = [ - 'card' => [ - 'number' => '5111111111111118', - 'exp_month' => '05', - 'exp_year' => '21', - 'cvc' => '100', - 'name' => 'Amr Ahmed Asciisd', - 'address' => [ - 'country' => 'Kuwait', - 'line1' => 'Salmiya, 21', - 'city' => 'Kuwait city', - 'street' => 'Salim', - 'avenue' => 'Gulf', - ], + 'card' => [ + 'number' => '5111111111111118', + 'exp_month' => '01', + 'exp_year' => '39', + 'cvc' => '100', + 'name' => 'Amr Ahmed Asciisd', + 'address' => [ + 'country' => 'Kuwait', + 'line1' => 'Salmiya, 21', + 'city' => 'Kuwait city', + 'street' => 'Salim', + 'avenue' => 'Gulf', ], - 'client_ip' => '192.168.1.20' - ]; - - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - Tap::setApiKey(getenv('TAP_API_KEY')); - } + ], + 'client_ip' => '192.168.1.20' + ]; protected function setUp(): void { - // Delay consecutive tests to prevent Tap rate limiting issues. - sleep(2); + if (!getenv('TAP_API_KEY')) { + $this->markTestSkipped('Tap API key not set.'); + } parent::setUp(); - Eloquent::unguard(); - - $this->loadLaravelMigrations(); + // Delay consecutive tests to prevent Tap rate limiting issues. + sleep(2); + } - $this->artisan('migrate')->run(); + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + Tap::setApiKey(getenv('TAP_API_KEY')); } protected static function deleteTapResource(ApiResource $resource) @@ -69,20 +68,21 @@ protected static function deleteTapResource(ApiResource $resource) } } - protected function createCustomer($description = 'aemad'): User + protected function createCustomer($description = 'amr', array $options = []): User { - return User::create([ - 'email' => "{$description}@cashier-test.com", + return User::create(array_merge([ + 'email' => "{$description}@cashier-test.com", 'first_name' => 'Amr', - 'last_name' => 'Ahmed', - 'name' => 'Amr Ahmed', - 'phone' => '010123456789', + 'last_name' => 'Ahmed', + 'name' => 'Amr Ahmed', + 'phone' => '010123456789', 'phone_code' => '002', - 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', - ]); + 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', + ], $options)); } - protected function createCard($customer_id): TapObject { + protected function createCard($customer_id): TapObject + { $token = $this->createToken(); dump("token created : $token->id"); diff --git a/tests/Fixtures/User.php b/tests/Fixtures/User.php index 1848701..9e08dc4 100644 --- a/tests/Fixtures/User.php +++ b/tests/Fixtures/User.php @@ -9,4 +9,6 @@ class User extends Authenticatable implements \Asciisd\Cashier\Contracts\Billable { use Billable, Notifiable; + + protected $guarded = []; } diff --git a/tests/TestCase.php b/tests/TestCase.php index b384ab7..9ae1d29 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,27 +2,33 @@ namespace Asciisd\Cashier\Tests; +use Asciisd\Cashier\Providers\CashierServiceProvider; +use Illuminate\Support\Str; +use InvalidArgumentException; +use Asciisd\Cashier\Cashier; +use Asciisd\Cashier\Tests\Fixtures\User; +use Orchestra\Testbench\Concerns\WithWorkbench; use Orchestra\Testbench\TestCase as OrchestraTestCase; -use Illuminate\Foundation\Application; -/** - * Override the standard PHPUnit testcase with the Testbench testcase - * - * @see https://github.com/orchestral/testbench#usage - */ -class TestCase extends OrchestraTestCase +abstract class TestCase extends OrchestraTestCase { - /** - * Include the package's service provider(s) - * - * @see https://github.com/orchestral/testbench#custom-service-provider - * @param \Illuminate\Foundation\Application $app - * @return array - */ + use WithWorkbench; + protected function getPackageProviders($app) { return [ - \Asciisd\Cashier\Providers\CashierServiceProvider::class + CashierServiceProvider::class, ]; } + + protected function getEnvironmentSetUp($app) + { + $apiKey = config('cashier.secret'); + + if ($apiKey && !Str::startsWith($apiKey, 'sk_test_')) { + throw new InvalidArgumentException('Tests may not be run with a production Stripe key.'); + } + + Cashier::useCustomerModel(User::class); + } }