create([ 'paddle_price_id' => 'pri_test', 'price' => 100, ]); $coupon = Coupon::factory()->create([ 'code' => 'SAVE20', 'paddle_discount_id' => 'dsc_123', 'per_customer_limit' => null, ]); $coupon->packages()->attach($package); $this->instance(PaddleDiscountService::class, Mockery::mock(PaddleDiscountService::class, function ($mock) { $mock->shouldReceive('previewDiscount')->andReturn([ 'totals' => [ 'currency_code' => 'EUR', 'subtotal' => 10000, 'discount' => 2000, 'tax' => 0, 'total' => 8000, ], ]); })); $response = $this->postJson(route('api.v1.marketing.coupons.preview'), [ 'package_id' => $package->id, 'code' => 'save20', ]); $response->assertOk() ->assertJsonPath('coupon.code', 'SAVE20'); $this->assertEquals(80.0, (float) $response->json('pricing.total')); } public function test_invalid_coupon_returns_validation_error(): void { $package = Package::factory()->create([ 'paddle_price_id' => 'pri_test_invalid', ]); $this->postJson(route('api.v1.marketing.coupons.preview'), [ 'package_id' => $package->id, 'code' => 'UNKNOWN', ])->assertUnprocessable() ->assertJsonValidationErrors('code'); } }