the browser-facing portion of osu!
at master 6.2 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace Tests\Libraries; 7 8use App\Exceptions\InvariantException; 9use App\Libraries\OrderCheckout; 10use App\Models\Country; 11use App\Models\Store\Order; 12use App\Models\Store\OrderItem; 13use App\Models\Store\Product; 14use App\Models\Tournament; 15use Carbon\Carbon; 16use Tests\TestCase; 17 18// TODO: should split into Tournament-specific and generic Checkout tests. 19class OrderCheckoutTest extends TestCase 20{ 21 public function testTournamentBannerWhenAvailable() 22 { 23 $tournament = Tournament::factory()->create(); 24 $product = $this->createTournamentProduct($tournament, Carbon::now()->addDays(1)); 25 $orderItem = OrderItem::factory()->create([ 26 'product_id' => $product, 27 'extra_data' => [ 28 'tournament_id' => $tournament->getKey(), 29 ], 30 ]); 31 $tournament->update(['tournament_banner_product_id' => $product->getKey()]); 32 33 $checkout = new OrderCheckout($orderItem->order); 34 35 $this->assertEmpty($checkout->validate()); 36 } 37 38 public function testTournamentBannerWhenNoEndDate() 39 { 40 $tournament = Tournament::factory()->create(); 41 $product = $this->createTournamentProduct($tournament); 42 $orderItem = OrderItem::factory()->create([ 43 'product_id' => $product, 44 'extra_data' => [ 45 'tournament_id' => $tournament->getKey(), 46 ], 47 ]); 48 $tournament->update(['tournament_banner_product_id' => $product->getKey()]); 49 50 $checkout = new OrderCheckout($orderItem->order); 51 52 $this->assertEmpty($checkout->validate()); 53 } 54 55 public function testTournamentBannerWhenNotAvailable() 56 { 57 $tournament = Tournament::factory()->create(); 58 $product = $this->createTournamentProduct($tournament, Carbon::now()->subDays(1)); 59 $orderItem = OrderItem::factory()->create([ 60 'product_id' => $product, 61 'extra_data' => [ 62 'tournament_id' => $tournament->getKey(), 63 ], 64 ]); 65 $tournament->update(['tournament_banner_product_id' => $product->getKey()]); 66 67 $checkout = new OrderCheckout($orderItem->order); 68 69 $this->assertNotEmpty($checkout->validate()); 70 } 71 72 public function testShippableItemRequiresShopify() 73 { 74 $product = Product::factory()->create(['stock' => 5, 'max_quantity' => 5, 'shopify_id' => null]); 75 $orderItem = OrderItem::factory()->create([ 76 'product_id' => $product, 77 'quantity' => 1, 78 ]); 79 80 $order = Order::factory()->create(); 81 $order->items()->save($orderItem); 82 83 $checkout = new OrderCheckout($order); 84 $result = $checkout->validate(); 85 86 $this->assertSame( 87 [osu_trans('model_validation/store/product.not_available')], 88 array_get($result, "orderItems.{$orderItem->getKey()}") 89 ); 90 } 91 92 public function testShopifyItemDoesNotMix() 93 { 94 $product1 = Product::factory()->create(['stock' => 5, 'max_quantity' => 5, 'shopify_id' => 1]); 95 $product2 = Product::factory()->virtual()->create(['stock' => 5, 'max_quantity' => 5, 'shopify_id' => null]); 96 $orderItem1 = OrderItem::factory()->create([ 97 'product_id' => $product1, 98 'quantity' => 1, 99 ]); 100 101 $orderItem2 = OrderItem::factory()->create([ 102 'product_id' => $product2, 103 'quantity' => 1, 104 ]); 105 106 $order = Order::factory()->create(); 107 $order->items()->save($orderItem1); 108 $order->items()->save($orderItem2); 109 110 $checkout = new OrderCheckout($order); 111 $result = $checkout->validate(); 112 113 $this->assertSame( 114 [osu_trans('model_validation/store/product.must_separate')], 115 array_get($result, "orderItems.{$orderItem2->getKey()}") 116 ); 117 } 118 119 public function testTotalNonZeroDoesNotAllowFreeCheckout() 120 { 121 $product1 = Product::factory()->create(['stock' => 5, 'max_quantity' => 5, 'cost' => 1]); 122 $orderItem1 = OrderItem::factory()->create([ 123 'product_id' => $product1, 124 'quantity' => 1, 125 'cost' => $product1->cost, 126 ]); 127 128 $order = Order::factory()->create(); 129 $order->items()->save($orderItem1); 130 131 $checkout = new OrderCheckout($order, Order::PROVIDER_FREE); 132 $result = $checkout->allowedCheckoutProviders(); 133 134 $this->expectException(InvariantException::class); 135 $checkout->beginCheckout(); 136 137 $this->assertNotContains(Order::PROVIDER_FREE, $result); 138 } 139 140 public function testTotalZeroOnlyAllowsFreeCheckout() 141 { 142 $product1 = Product::factory()->create(['stock' => 5, 'max_quantity' => 5, 'cost' => 0]); 143 $orderItem1 = OrderItem::factory()->create([ 144 'product_id' => $product1, 145 'quantity' => 1, 146 'cost' => $product1->cost, 147 ]); 148 149 $order = Order::factory()->create(); 150 $order->items()->save($orderItem1); 151 $checkout = new OrderCheckout($order, Order::PROVIDER_PAYPAL); 152 $result = $checkout->allowedCheckoutProviders(); 153 154 $this->expectException(InvariantException::class); 155 $checkout->beginCheckout(); 156 157 $this->assertSame([Order::PROVIDER_FREE], $result); 158 } 159 160 private function createTournamentProduct(Tournament $tournament, Carbon $availableUntil = null) 161 { 162 $country = Country::inRandomOrder()->first() ?? Country::factory()->create(); 163 164 $product = Product::factory()->childBanners()->create([ 165 'available_until' => $availableUntil, 166 'name' => "{$tournament->name} Support Banner ({$country->name})", 167 ]); 168 169 $type_mappings_json = [ 170 $product->product_id => [ 171 'country' => $country->acronym, 172 'tournament_id' => $tournament->tournament_id, 173 ], 174 ]; 175 176 $product->type_mappings_json = json_encode($type_mappings_json, JSON_PRETTY_PRINT); 177 $product->saveOrExplode(); 178 179 return $product; 180 } 181}