SubscriptionTest.php 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312
  1. <?php
  2. namespace Test\Integration;
  3. require_once dirname(__DIR__) . '/Setup.php';
  4. use DateTime;
  5. use Test;
  6. use Test\Setup;
  7. use Braintree;
  8. class SubscriptionTest extends Setup
  9. {
  10. public function testCreate_doesNotAcceptBadAttributes()
  11. {
  12. $this->setExpectedException('InvalidArgumentException', 'invalid keys: bad');
  13. $result = Braintree\Subscription::create([
  14. 'bad' => 'value'
  15. ]);
  16. }
  17. public function testCreate_whenSuccessful()
  18. {
  19. $creditCard = SubscriptionHelper::createCreditCard();
  20. $plan = SubscriptionHelper::triallessPlan();
  21. $result = Braintree\Subscription::create([
  22. 'paymentMethodToken' => $creditCard->token,
  23. 'planId' => $plan['id']
  24. ]);
  25. Test\Helper::assertPrintable($result);
  26. $this->assertTrue($result->success);
  27. $subscription = $result->subscription;
  28. $this->assertEquals($creditCard->token, $subscription->paymentMethodToken);
  29. $this->assertEquals(0, $subscription->failureCount);
  30. $this->assertEquals($plan['id'], $subscription->planId);
  31. $this->assertEquals(Test\Helper::defaultMerchantAccountId(), $subscription->merchantAccountId);
  32. $this->assertEquals(Braintree\Subscription::ACTIVE, $subscription->status);
  33. $this->assertEquals('12.34', $subscription->nextBillAmount);
  34. $this->assertEquals('12.34', $subscription->nextBillingPeriodAmount);
  35. $this->assertEquals('0.00', $subscription->balance);
  36. $this->assertEquals(1, $subscription->currentBillingCycle);
  37. $this->assertInstanceOf('DateTime', $subscription->firstBillingDate);
  38. $this->assertInstanceOf('DateTime', $subscription->nextBillingDate);
  39. $this->assertInstanceOf('DateTime', $subscription->billingPeriodStartDate);
  40. $this->assertInstanceOf('DateTime', $subscription->billingPeriodEndDate);
  41. $this->assertInstanceOf('DateTime', $subscription->paidThroughDate);
  42. $this->assertInstanceOf('DateTime', $subscription->updatedAt);
  43. $this->assertInstanceOf('DateTime', $subscription->createdAt);
  44. $this->assertEquals('12.34', $subscription->statusHistory[0]->price);
  45. $this->assertEquals('0.00', $subscription->statusHistory[0]->balance);
  46. $this->assertEquals('USD', $subscription->statusHistory[0]->currencyIsoCode);
  47. $this->assertEquals($plan['id'], $subscription->statusHistory[0]->planId);
  48. $this->assertEquals(Braintree\Subscription::ACTIVE, $subscription->statusHistory[0]->status);
  49. $this->assertEquals(Braintree\Subscription::API, $subscription->statusHistory[0]->subscriptionSource);
  50. }
  51. public function testGatewayCreate_whenSuccessful()
  52. {
  53. $creditCard = SubscriptionHelper::createCreditCard();
  54. $plan = SubscriptionHelper::triallessPlan();
  55. $gateway = new Braintree\Gateway([
  56. 'environment' => 'development',
  57. 'merchantId' => 'integration_merchant_id',
  58. 'publicKey' => 'integration_public_key',
  59. 'privateKey' => 'integration_private_key'
  60. ]);
  61. $result = $gateway->subscription()->create([
  62. 'paymentMethodToken' => $creditCard->token,
  63. 'planId' => $plan['id']
  64. ]);
  65. Test\Helper::assertPrintable($result);
  66. $this->assertTrue($result->success);
  67. $subscription = $result->subscription;
  68. $this->assertEquals($creditCard->token, $subscription->paymentMethodToken);
  69. $this->assertEquals(0, $subscription->failureCount);
  70. $this->assertEquals($plan['id'], $subscription->planId);
  71. $this->assertEquals(Test\Helper::defaultMerchantAccountId(), $subscription->merchantAccountId);
  72. $this->assertEquals(Braintree\Subscription::ACTIVE, $subscription->status);
  73. }
  74. public function testCreate_withPaymentMethodNonce()
  75. {
  76. $customerId = Braintree\Customer::create()->customer->id;
  77. $http = new HttpClientApi(Braintree\Configuration::$global);
  78. $nonce = $http->nonce_for_new_card([
  79. "creditCard" => [
  80. "number" => "4111111111111111",
  81. "expirationMonth" => "11",
  82. "expirationYear" => "2099"
  83. ],
  84. "customerId" => $customerId,
  85. "share" => true
  86. ]);
  87. $plan = SubscriptionHelper::triallessPlan();
  88. $result = Braintree\Subscription::create([
  89. 'paymentMethodNonce' => $nonce,
  90. 'planId' => $plan['id']
  91. ]);
  92. $this->assertTrue($result->success);
  93. $transaction = $result->subscription->transactions[0];
  94. $this->assertEquals("411111", $transaction->creditCardDetails->bin);
  95. $this->assertEquals("1111", $transaction->creditCardDetails->last4);
  96. }
  97. public function testCreate_returnsTransactionWhenTransactionFails()
  98. {
  99. $creditCard = SubscriptionHelper::createCreditCard();
  100. $plan = SubscriptionHelper::triallessPlan();
  101. $result = Braintree\Subscription::create([
  102. 'paymentMethodToken' => $creditCard->token,
  103. 'planId' => $plan['id'],
  104. 'price' => Braintree\Test\TransactionAmounts::$decline
  105. ]);
  106. Test\Helper::assertPrintable($result);
  107. $this->assertFalse($result->success);
  108. $this->assertEquals(Braintree\Transaction::PROCESSOR_DECLINED, $result->transaction->status);
  109. }
  110. public function testCreate_canSetTheId()
  111. {
  112. $creditCard = SubscriptionHelper::createCreditCard();
  113. $newId = strval(rand());
  114. $plan = SubscriptionHelper::triallessPlan();
  115. $result = Braintree\Subscription::create([
  116. 'paymentMethodToken' => $creditCard->token,
  117. 'planId' => $plan['id'],
  118. 'id' => $newId
  119. ]);
  120. $this->assertTrue($result->success);
  121. $subscription = $result->subscription;
  122. $this->assertEquals($newId, $subscription->id);
  123. }
  124. public function testCreate_canSetTheMerchantAccountId()
  125. {
  126. $creditCard = SubscriptionHelper::createCreditCard();
  127. $plan = SubscriptionHelper::triallessPlan();
  128. $result = Braintree\Subscription::create([
  129. 'paymentMethodToken' => $creditCard->token,
  130. 'planId' => $plan['id'],
  131. 'merchantAccountId' => Test\Helper::nonDefaultMerchantAccountId()
  132. ]);
  133. $this->assertTrue($result->success);
  134. $subscription = $result->subscription;
  135. $this->assertEquals(Test\Helper::nonDefaultMerchantAccountId(), $subscription->merchantAccountId);
  136. }
  137. public function testCreate_trialPeriodDefaultsToPlanWithoutTrial()
  138. {
  139. $creditCard = SubscriptionHelper::createCreditCard();
  140. $plan = SubscriptionHelper::triallessPlan();
  141. $result = Braintree\Subscription::create([
  142. 'paymentMethodToken' => $creditCard->token,
  143. 'planId' => $plan['id'],
  144. ]);
  145. $subscription = $result->subscription;
  146. $this->assertFalse($subscription->trialPeriod);
  147. $this->assertNull($subscription->trialDuration);
  148. $this->assertNull($subscription->trialDurationUnit);
  149. }
  150. public function testCreate_trialPeriondDefaultsToPlanWithTrial()
  151. {
  152. $creditCard = SubscriptionHelper::createCreditCard();
  153. $plan = SubscriptionHelper::trialPlan();
  154. $result = Braintree\Subscription::create([
  155. 'paymentMethodToken' => $creditCard->token,
  156. 'planId' => $plan['id'],
  157. ]);
  158. $subscription = $result->subscription;
  159. $this->assertTrue($subscription->trialPeriod);
  160. $this->assertEquals(2, $subscription->trialDuration);
  161. $this->assertEquals('day', $subscription->trialDurationUnit);
  162. }
  163. public function testCreate_alterPlanTrialPeriod()
  164. {
  165. $creditCard = SubscriptionHelper::createCreditCard();
  166. $plan = SubscriptionHelper::trialPlan();
  167. $result = Braintree\Subscription::create([
  168. 'paymentMethodToken' => $creditCard->token,
  169. 'planId' => $plan['id'],
  170. 'trialDuration' => 5,
  171. 'trialDurationUnit' => 'month'
  172. ]);
  173. $subscription = $result->subscription;
  174. $this->assertTrue($subscription->trialPeriod);
  175. $this->assertEquals(5, $subscription->trialDuration);
  176. $this->assertEquals('month', $subscription->trialDurationUnit);
  177. }
  178. public function testCreate_removePlanTrialPeriod()
  179. {
  180. $creditCard = SubscriptionHelper::createCreditCard();
  181. $plan = SubscriptionHelper::trialPlan();
  182. $result = Braintree\Subscription::create([
  183. 'paymentMethodToken' => $creditCard->token,
  184. 'planId' => $plan['id'],
  185. 'trialPeriod' => false,
  186. ]);
  187. $subscription = $result->subscription;
  188. $this->assertFalse($subscription->trialPeriod);
  189. }
  190. public function testCreate_createsATransactionIfNoTrialPeriod()
  191. {
  192. $creditCard = SubscriptionHelper::createCreditCard();
  193. $plan = SubscriptionHelper::triallessPlan();
  194. $result = Braintree\Subscription::create([
  195. 'paymentMethodToken' => $creditCard->token,
  196. 'planId' => $plan['id'],
  197. ]);
  198. $subscription = $result->subscription;
  199. $this->assertEquals(1, sizeof($subscription->transactions));
  200. $transaction = $subscription->transactions[0];
  201. $this->assertInstanceOf('Braintree\Transaction', $transaction);
  202. $this->assertEquals($plan['price'], $transaction->amount);
  203. $this->assertEquals(Braintree\Transaction::SALE, $transaction->type);
  204. $this->assertEquals($subscription->id, $transaction->subscriptionId);
  205. }
  206. public function testCreate_doesNotCreateTransactionIfTrialPeriod()
  207. {
  208. $creditCard = SubscriptionHelper::createCreditCard();
  209. $plan = SubscriptionHelper::trialPlan();
  210. $result = Braintree\Subscription::create([
  211. 'paymentMethodToken' => $creditCard->token,
  212. 'planId' => $plan['id'],
  213. ]);
  214. $subscription = $result->subscription;
  215. $this->assertEquals(0, sizeof($subscription->transactions));
  216. }
  217. public function testCreate_returnsATransactionWithSubscriptionBillingPeriod()
  218. {
  219. $creditCard = SubscriptionHelper::createCreditCard();
  220. $plan = SubscriptionHelper::triallessPlan();
  221. $result = Braintree\Subscription::create([
  222. 'paymentMethodToken' => $creditCard->token,
  223. 'planId' => $plan['id'],
  224. ]);
  225. $subscription = $result->subscription;
  226. $transaction = $subscription->transactions[0];
  227. $this->assertEquals($subscription->billingPeriodStartDate, $transaction->subscriptionDetails->billingPeriodStartDate);
  228. $this->assertEquals($subscription->billingPeriodEndDate, $transaction->subscriptionDetails->billingPeriodEndDate);
  229. }
  230. public function testCreate_priceCanBeOverriden()
  231. {
  232. $creditCard = SubscriptionHelper::createCreditCard();
  233. $plan = SubscriptionHelper::trialPlan();
  234. $result = Braintree\Subscription::create([
  235. 'paymentMethodToken' => $creditCard->token,
  236. 'planId' => $plan['id'],
  237. 'price' => '2.00'
  238. ]);
  239. $subscription = $result->subscription;
  240. $this->assertEquals('2.00', $subscription->price);
  241. }
  242. public function testCreate_billingDayOfMonthIsInheritedFromPlan()
  243. {
  244. $creditCard = SubscriptionHelper::createCreditCard();
  245. $plan = SubscriptionHelper::billingDayOfMonthPlan();
  246. $result = Braintree\Subscription::create([
  247. 'paymentMethodToken' => $creditCard->token,
  248. 'planId' => $plan['id']
  249. ]);
  250. $subscription = $result->subscription;
  251. $this->assertEquals(5, $subscription->billingDayOfMonth);
  252. }
  253. public function testCreate_billingDayOfMonthCanBeOverriden()
  254. {
  255. $creditCard = SubscriptionHelper::createCreditCard();
  256. $plan = SubscriptionHelper::billingDayOfMonthPlan();
  257. $result = Braintree\Subscription::create([
  258. 'paymentMethodToken' => $creditCard->token,
  259. 'planId' => $plan['id'],
  260. 'billingDayOfMonth' => 14
  261. ]);
  262. $subscription = $result->subscription;
  263. $this->assertEquals(14, $subscription->billingDayOfMonth);
  264. }
  265. public function testCreate_billingDayOfMonthCanBeOverridenWithStartImmediately()
  266. {
  267. $creditCard = SubscriptionHelper::createCreditCard();
  268. $plan = SubscriptionHelper::billingDayOfMonthPlan();
  269. $result = Braintree\Subscription::create([
  270. 'paymentMethodToken' => $creditCard->token,
  271. 'planId' => $plan['id'],
  272. 'options' => ['startImmediately' => true]
  273. ]);
  274. $subscription = $result->subscription;
  275. $this->assertEquals(1, sizeof($subscription->transactions));
  276. }
  277. public function testCreate_firstBillingDateCanBeSet()
  278. {
  279. $creditCard = SubscriptionHelper::createCreditCard();
  280. $plan = SubscriptionHelper::billingDayOfMonthPlan();
  281. $tomorrow = new DateTime("now + 1 day");
  282. $tomorrow->setTime(0,0,0);
  283. $result = Braintree\Subscription::create([
  284. 'paymentMethodToken' => $creditCard->token,
  285. 'planId' => $plan['id'],
  286. 'firstBillingDate' => $tomorrow
  287. ]);
  288. $subscription = $result->subscription;
  289. $this->assertEquals($tomorrow, $subscription->firstBillingDate);
  290. $this->assertEquals(Braintree\Subscription::PENDING, $result->subscription->status);
  291. }
  292. public function testCreate_firstBillingDateInThePast()
  293. {
  294. $creditCard = SubscriptionHelper::createCreditCard();
  295. $plan = SubscriptionHelper::billingDayOfMonthPlan();
  296. $past = new DateTime("now - 3 days");
  297. $past->setTime(0,0,0);
  298. $result = Braintree\Subscription::create([
  299. 'paymentMethodToken' => $creditCard->token,
  300. 'planId' => $plan['id'],
  301. 'firstBillingDate' => $past
  302. ]);
  303. $this->assertFalse($result->success);
  304. $errors = $result->errors->forKey('subscription')->onAttribute('firstBillingDate');
  305. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_FIRST_BILLING_DATE_CANNOT_BE_IN_THE_PAST, $errors[0]->code);
  306. }
  307. public function testCreate_numberOfBillingCyclesCanBeOverridden()
  308. {
  309. $creditCard = SubscriptionHelper::createCreditCard();
  310. $plan = SubscriptionHelper::trialPlan();
  311. $result = Braintree\Subscription::create([
  312. 'paymentMethodToken' => $creditCard->token,
  313. 'planId' => $plan['id']
  314. ]);
  315. $subscription = $result->subscription;
  316. $this->assertEquals($plan['numberOfBillingCycles'], $subscription->numberOfBillingCycles);
  317. $result = Braintree\Subscription::create([
  318. 'numberOfBillingCycles' => '10',
  319. 'paymentMethodToken' => $creditCard->token,
  320. 'planId' => $plan['id']
  321. ]);
  322. $subscription = $result->subscription;
  323. $this->assertEquals(10, $subscription->numberOfBillingCycles);
  324. $this->assertFalse($subscription->neverExpires);
  325. }
  326. public function testCreate_numberOfBillingCyclesCanBeOverriddenToNeverExpire()
  327. {
  328. $creditCard = SubscriptionHelper::createCreditCard();
  329. $plan = SubscriptionHelper::trialPlan();
  330. $result = Braintree\Subscription::create([
  331. 'paymentMethodToken' => $creditCard->token,
  332. 'planId' => $plan['id']
  333. ]);
  334. $subscription = $result->subscription;
  335. $this->assertEquals($plan['numberOfBillingCycles'], $subscription->numberOfBillingCycles);
  336. $result = Braintree\Subscription::create([
  337. 'neverExpires' => true,
  338. 'paymentMethodToken' => $creditCard->token,
  339. 'planId' => $plan['id']
  340. ]);
  341. $subscription = $result->subscription;
  342. $this->assertNull($subscription->numberOfBillingCycles);
  343. $this->assertTrue($subscription->neverExpires);
  344. }
  345. public function testCreate_doesNotInheritAddOnsAndDiscountsWhenDoNotInheritAddOnsOrDiscountsIsSet()
  346. {
  347. $creditCard = SubscriptionHelper::createCreditCard();
  348. $plan = SubscriptionHelper::addOnDiscountPlan();
  349. $result = Braintree\Subscription::create([
  350. 'paymentMethodToken' => $creditCard->token,
  351. 'planId' => $plan['id'],
  352. 'options' => ['doNotInheritAddOnsOrDiscounts' => true]
  353. ]);
  354. $subscription = $result->subscription;
  355. $this->assertEquals(0, sizeof($subscription->addOns));
  356. $this->assertEquals(0, sizeof($subscription->discounts));
  357. }
  358. public function testCreate_inheritsAddOnsAndDiscountsFromPlanByDefault()
  359. {
  360. $creditCard = SubscriptionHelper::createCreditCard();
  361. $plan = SubscriptionHelper::addOnDiscountPlan();
  362. $result = Braintree\Subscription::create([
  363. 'paymentMethodToken' => $creditCard->token,
  364. 'planId' => $plan['id'],
  365. ]);
  366. $subscription = $result->subscription;
  367. $this->assertEquals(2, sizeof($subscription->addOns));
  368. $addOns = $subscription->addOns;
  369. SubscriptionHelper::sortModificationsById($addOns);
  370. $this->assertEquals($addOns[0]->amount, "10.00");
  371. $this->assertEquals($addOns[0]->quantity, 1);
  372. $this->assertEquals($addOns[0]->numberOfBillingCycles, null);
  373. $this->assertEquals($addOns[0]->neverExpires, true);
  374. $this->assertEquals($addOns[0]->currentBillingCycle, 0);
  375. $this->assertEquals($addOns[1]->amount, "20.00");
  376. $this->assertEquals($addOns[1]->quantity, 1);
  377. $this->assertEquals($addOns[1]->numberOfBillingCycles, null);
  378. $this->assertEquals($addOns[1]->neverExpires, true);
  379. $this->assertEquals($addOns[1]->currentBillingCycle, 0);
  380. $this->assertEquals(2, sizeof($subscription->discounts));
  381. $discounts = $subscription->discounts;
  382. SubscriptionHelper::sortModificationsById($discounts);
  383. $this->assertEquals($discounts[0]->amount, "11.00");
  384. $this->assertEquals($discounts[0]->quantity, 1);
  385. $this->assertEquals($discounts[0]->numberOfBillingCycles, null);
  386. $this->assertEquals($discounts[0]->neverExpires, true);
  387. $this->assertEquals($discounts[0]->currentBillingCycle, 0);
  388. $this->assertEquals($discounts[1]->amount, "7.00");
  389. $this->assertEquals($discounts[1]->quantity, 1);
  390. $this->assertEquals($discounts[1]->numberOfBillingCycles, null);
  391. $this->assertEquals($discounts[1]->neverExpires, true);
  392. $this->assertEquals($discounts[1]->currentBillingCycle, 0);
  393. }
  394. public function testCreate_allowsOverridingInheritedAddOnsAndDiscounts()
  395. {
  396. $creditCard = SubscriptionHelper::createCreditCard();
  397. $plan = SubscriptionHelper::addOnDiscountPlan();
  398. $result = Braintree\Subscription::create([
  399. 'paymentMethodToken' => $creditCard->token,
  400. 'planId' => $plan['id'],
  401. 'addOns' => [
  402. 'update' => [
  403. [
  404. 'amount' => '50.00',
  405. 'existingId' => 'increase_10',
  406. 'quantity' => 2,
  407. 'numberOfBillingCycles' => 5
  408. ],
  409. [
  410. 'amount' => '60.00',
  411. 'existingId' => 'increase_20',
  412. 'quantity' => 4,
  413. 'numberOfBillingCycles' => 9
  414. ]
  415. ],
  416. ],
  417. 'discounts' => [
  418. 'update' => [
  419. [
  420. 'amount' => '15.00',
  421. 'existingId' => 'discount_7',
  422. 'quantity' => 2,
  423. 'neverExpires' => true
  424. ]
  425. ]
  426. ]
  427. ]);
  428. $subscription = $result->subscription;
  429. $this->assertEquals(2, sizeof($subscription->addOns));
  430. $addOns = $subscription->addOns;
  431. SubscriptionHelper::sortModificationsById($addOns);
  432. $this->assertEquals($addOns[0]->amount, "50.00");
  433. $this->assertEquals($addOns[0]->quantity, 2);
  434. $this->assertEquals($addOns[0]->numberOfBillingCycles, 5);
  435. $this->assertEquals($addOns[0]->neverExpires, false);
  436. $this->assertEquals($addOns[0]->currentBillingCycle, 0);
  437. $this->assertEquals($addOns[1]->amount, "60.00");
  438. $this->assertEquals($addOns[1]->quantity, 4);
  439. $this->assertEquals($addOns[1]->numberOfBillingCycles, 9);
  440. $this->assertEquals($addOns[1]->neverExpires, false);
  441. $this->assertEquals($addOns[1]->currentBillingCycle, 0);
  442. $this->assertEquals(2, sizeof($subscription->discounts));
  443. $discounts = $subscription->discounts;
  444. SubscriptionHelper::sortModificationsById($discounts);
  445. $this->assertEquals($discounts[0]->amount, "11.00");
  446. $this->assertEquals($discounts[0]->quantity, 1);
  447. $this->assertEquals($discounts[0]->numberOfBillingCycles, null);
  448. $this->assertEquals($discounts[0]->neverExpires, true);
  449. $this->assertEquals($discounts[0]->currentBillingCycle, 0);
  450. $this->assertEquals($discounts[1]->amount, "15.00");
  451. $this->assertEquals($discounts[1]->quantity, 2);
  452. $this->assertEquals($discounts[1]->numberOfBillingCycles, null);
  453. $this->assertEquals($discounts[1]->neverExpires, true);
  454. $this->assertEquals($discounts[1]->currentBillingCycle, 0);
  455. }
  456. public function testCreate_allowsRemovalOfInheritedAddOnsAndDiscounts()
  457. {
  458. $creditCard = SubscriptionHelper::createCreditCard();
  459. $plan = SubscriptionHelper::addOnDiscountPlan();
  460. $result = Braintree\Subscription::create([
  461. 'paymentMethodToken' => $creditCard->token,
  462. 'planId' => $plan['id'],
  463. 'addOns' => [
  464. 'remove' => ['increase_10', 'increase_20']
  465. ],
  466. 'discounts' => [
  467. 'remove' => ['discount_7']
  468. ]
  469. ]);
  470. $subscription = $result->subscription;
  471. $this->assertEquals(0, sizeof($subscription->addOns));
  472. $this->assertEquals(1, sizeof($subscription->discounts));
  473. $this->assertEquals($subscription->discounts[0]->amount, "11.00");
  474. $this->assertEquals($subscription->discounts[0]->quantity, 1);
  475. $this->assertEquals($subscription->discounts[0]->numberOfBillingCycles, null);
  476. $this->assertEquals($subscription->discounts[0]->neverExpires, true);
  477. $this->assertEquals($subscription->discounts[0]->currentBillingCycle, 0);
  478. }
  479. public function testCreate_allowsAddingNewAddOnsAndDiscounts()
  480. {
  481. $creditCard = SubscriptionHelper::createCreditCard();
  482. $plan = SubscriptionHelper::addOnDiscountPlan();
  483. $result = Braintree\Subscription::create([
  484. 'paymentMethodToken' => $creditCard->token,
  485. 'planId' => $plan['id'],
  486. 'addOns' => [
  487. 'add' => [
  488. [
  489. 'inheritedFromId' => 'increase_30',
  490. 'amount' => '35.00',
  491. 'neverExpires' => true,
  492. 'quantity' => 2
  493. ],
  494. ],
  495. ],
  496. 'discounts' => [
  497. 'add' => [
  498. [
  499. 'inheritedFromId' => 'discount_15',
  500. 'amount' => '15.50',
  501. 'numberOfBillingCycles' => 10,
  502. 'quantity' => 3
  503. ]
  504. ]
  505. ]
  506. ]);
  507. $subscription = $result->subscription;
  508. $this->assertEquals(3, sizeof($subscription->addOns));
  509. $addOns = $subscription->addOns;
  510. SubscriptionHelper::sortModificationsById($addOns);
  511. $this->assertEquals($addOns[0]->amount, "10.00");
  512. $this->assertEquals($addOns[1]->amount, "20.00");
  513. $this->assertEquals($addOns[2]->id, "increase_30");
  514. $this->assertEquals($addOns[2]->amount, "35.00");
  515. $this->assertEquals($addOns[2]->neverExpires, true);
  516. $this->assertEquals($addOns[2]->numberOfBillingCycles, null);
  517. $this->assertEquals($addOns[2]->quantity, 2);
  518. $this->assertEquals($addOns[2]->currentBillingCycle, 0);
  519. $this->assertEquals(3, sizeof($subscription->discounts));
  520. $discounts = $subscription->discounts;
  521. SubscriptionHelper::sortModificationsById($discounts);
  522. $this->assertEquals($discounts[0]->amount, "11.00");
  523. $this->assertEquals($discounts[1]->amount, "15.50");
  524. $this->assertEquals($discounts[1]->id, "discount_15");
  525. $this->assertEquals($discounts[1]->neverExpires, false);
  526. $this->assertEquals($discounts[1]->numberOfBillingCycles, 10);
  527. $this->assertEquals($discounts[1]->quantity, 3);
  528. $this->assertEquals($discounts[1]->currentBillingCycle, 0);
  529. $this->assertEquals($discounts[2]->amount, "7.00");
  530. }
  531. public function testCreate_properlyParsesValidationErrorsForArrays()
  532. {
  533. $creditCard = SubscriptionHelper::createCreditCard();
  534. $plan = SubscriptionHelper::addOnDiscountPlan();
  535. $result = Braintree\Subscription::create([
  536. 'paymentMethodToken' => $creditCard->token,
  537. 'planId' => $plan['id'],
  538. 'addOns' => [
  539. 'update' => [
  540. [
  541. 'existingId' => 'increase_10',
  542. 'amount' => 'invalid',
  543. ],
  544. [
  545. 'existingId' => 'increase_20',
  546. 'quantity' => -10,
  547. ]
  548. ]
  549. ]
  550. ]);
  551. $this->assertFalse($result->success);
  552. $errors = $result->errors->forKey('subscription')->forKey('addOns')->forKey('update')->forIndex(0)->onAttribute('amount');
  553. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_MODIFICATION_AMOUNT_IS_INVALID, $errors[0]->code);
  554. $errors = $result->errors->forKey('subscription')->forKey('addOns')->forKey('update')->forIndex(1)->onAttribute('quantity');
  555. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_MODIFICATION_QUANTITY_IS_INVALID, $errors[0]->code);
  556. }
  557. public function testCreate_withDescriptor()
  558. {
  559. $creditCard = SubscriptionHelper::createCreditCard();
  560. $plan = SubscriptionHelper::triallessPlan();
  561. $result = Braintree\Subscription::create([
  562. 'paymentMethodToken' => $creditCard->token,
  563. 'planId' => $plan['id'],
  564. 'descriptor' => [
  565. 'name' => '123*123456789012345678',
  566. 'phone' => '3334445555',
  567. 'url' => 'ebay.com'
  568. ]
  569. ]);
  570. $this->assertTrue($result->success);
  571. $subscription = $result->subscription;
  572. $this->assertEquals('123*123456789012345678', $subscription->descriptor->name);
  573. $this->assertEquals('3334445555', $subscription->descriptor->phone);
  574. $this->assertEquals('ebay.com', $subscription->descriptor->url);
  575. $transaction = $subscription->transactions[0];
  576. $this->assertEquals('123*123456789012345678', $transaction->descriptor->name);
  577. $this->assertEquals('3334445555', $transaction->descriptor->phone);
  578. $this->assertEquals('ebay.com', $transaction->descriptor->url);
  579. }
  580. public function testCreate_withDescriptorValidation()
  581. {
  582. $creditCard = SubscriptionHelper::createCreditCard();
  583. $plan = SubscriptionHelper::addOnDiscountPlan();
  584. $result = Braintree\Subscription::create([
  585. 'paymentMethodToken' => $creditCard->token,
  586. 'planId' => $plan['id'],
  587. 'descriptor' => [
  588. 'name' => 'xxxxxx',
  589. 'phone' => 'xxxx',
  590. 'url' => '12345678901234'
  591. ]
  592. ]);
  593. $this->assertFalse($result->success);
  594. $subscription = $result->subscription;
  595. $errors = $result->errors->forKey('subscription')->forKey('descriptor')->onAttribute('name');
  596. $this->assertEquals(Braintree\Error\Codes::DESCRIPTOR_NAME_FORMAT_IS_INVALID, $errors[0]->code);
  597. $errors = $result->errors->forKey('subscription')->forKey('descriptor')->onAttribute('phone');
  598. $this->assertEquals(Braintree\Error\Codes::DESCRIPTOR_PHONE_FORMAT_IS_INVALID, $errors[0]->code);
  599. $errors = $result->errors->forKey('subscription')->forKey('descriptor')->onAttribute('url');
  600. $this->assertEquals(Braintree\Error\Codes::DESCRIPTOR_URL_FORMAT_IS_INVALID, $errors[0]->code);
  601. }
  602. public function testCreate_withDescription()
  603. {
  604. $paymentMethodToken = 'PAYPAL_TOKEN-' . strval(rand());
  605. $customer = Braintree\Customer::createNoValidate();
  606. $plan = SubscriptionHelper::triallessPlan();
  607. $http = new HttpClientApi(Braintree\Configuration::$global);
  608. $nonce = $http->nonceForPayPalAccount([
  609. 'paypal_account' => [
  610. 'consent_code' => 'PAYPAL_CONSENT_CODE',
  611. 'token' => $paymentMethodToken
  612. ]
  613. ]);
  614. $paypalResult = Braintree\PaymentMethod::create([
  615. 'customerId' => $customer->id,
  616. 'paymentMethodNonce' => $nonce
  617. ]);
  618. $result = Braintree\Subscription::create([
  619. 'paymentMethodToken' => $paymentMethodToken,
  620. 'planId' => $plan['id'],
  621. 'options' => [
  622. 'paypal' => [
  623. 'description' => 'A great product'
  624. ]
  625. ]
  626. ]);
  627. $this->assertTrue($result->success);
  628. $subscription = $result->subscription;
  629. $this->assertEquals('A great product', $subscription->description);
  630. $transaction = $subscription->transactions[0];
  631. $this->assertEquals('A great product', $transaction->paypalDetails->description);
  632. }
  633. public function testCreate_fromPayPalACcount()
  634. {
  635. $paymentMethodToken = 'PAYPAL_TOKEN-' . strval(rand());
  636. $customer = Braintree\Customer::createNoValidate();
  637. $plan = SubscriptionHelper::triallessPlan();
  638. $http = new HttpClientApi(Braintree\Configuration::$global);
  639. $nonce = $http->nonceForPayPalAccount([
  640. 'paypal_account' => [
  641. 'consent_code' => 'PAYPAL_CONSENT_CODE',
  642. 'token' => $paymentMethodToken
  643. ]
  644. ]);
  645. $paypalResult = Braintree\PaymentMethod::create([
  646. 'customerId' => $customer->id,
  647. 'paymentMethodNonce' => $nonce
  648. ]);
  649. $subscriptionResult = Braintree\Subscription::create([
  650. 'paymentMethodToken' => $paymentMethodToken,
  651. 'planId' => $plan['id']
  652. ]);
  653. $this->assertTrue($subscriptionResult->success);
  654. $transaction = $subscriptionResult->subscription->transactions[0];
  655. $this->assertEquals('payer@example.com', $transaction->paypalDetails->payerEmail);
  656. }
  657. public function testCreate_fromPayPalACcountDoesNotWorkWithFutureNonce()
  658. {
  659. $plan = SubscriptionHelper::triallessPlan();
  660. $nonce = Braintree\Test\Nonces::$paypalFuturePayment;
  661. $subscriptionResult = Braintree\Subscription::create([
  662. 'paymentMethodNonce' => $nonce,
  663. 'planId' => $plan['id']
  664. ]);
  665. $this->assertFalse($subscriptionResult->success);
  666. $errors = $subscriptionResult->errors->forKey('subscription')->errors;
  667. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_PAYMENT_METHOD_NONCE_IS_INVALID, $errors[0]->code);
  668. }
  669. public function testCreate_fromPayPalACcountDoesNotWorkWithOnetimeNonce()
  670. {
  671. $plan = SubscriptionHelper::triallessPlan();
  672. $nonce = Braintree\Test\Nonces::$paypalOneTimePayment;
  673. $subscriptionResult = Braintree\Subscription::create([
  674. 'paymentMethodNonce' => $nonce,
  675. 'planId' => $plan['id']
  676. ]);
  677. $this->assertFalse($subscriptionResult->success);
  678. $errors = $subscriptionResult->errors->forKey('subscription')->errors;
  679. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_PAYMENT_METHOD_NONCE_IS_INVALID, $errors[0]->code);
  680. }
  681. public function testValidationErrors_hasValidationErrorsOnId()
  682. {
  683. $creditCard = SubscriptionHelper::createCreditCard();
  684. $plan = SubscriptionHelper::triallessPlan();
  685. $result = Braintree\Subscription::create([
  686. 'paymentMethodToken' => $creditCard->token,
  687. 'planId' => $plan['id'],
  688. 'id' => 'invalid token'
  689. ]);
  690. $this->assertFalse($result->success);
  691. $errors = $result->errors->forKey('subscription')->onAttribute('id');
  692. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_TOKEN_FORMAT_IS_INVALID, $errors[0]->code);
  693. }
  694. public function testFind()
  695. {
  696. $creditCard = SubscriptionHelper::createCreditCard();
  697. $plan = SubscriptionHelper::triallessPlan();
  698. $result = Braintree\Subscription::create([
  699. 'paymentMethodToken' => $creditCard->token,
  700. 'planId' => $plan['id']
  701. ]);
  702. $this->assertTrue($result->success);
  703. $subscription = Braintree\Subscription::find($result->subscription->id);
  704. $this->assertEquals($result->subscription->id, $subscription->id);
  705. $this->assertEquals($plan['id'], $subscription->planId);
  706. }
  707. public function testFind_throwsIfNotFound()
  708. {
  709. $this->setExpectedException('Braintree\Exception\NotFound', 'subscription with id does-not-exist not found');
  710. Braintree\Subscription::find('does-not-exist');
  711. }
  712. public function testUpdate_whenSuccessful()
  713. {
  714. $subscription = SubscriptionHelper::createSubscription();
  715. $newId = strval(rand());
  716. $newPlan = SubscriptionHelper::trialPlan();
  717. $result = Braintree\Subscription::update($subscription->id, [
  718. 'id' => $newId,
  719. 'price' => '999.99',
  720. 'planId' => $newPlan['id']
  721. ]);
  722. $this->assertTrue($result->success);
  723. $this->assertEquals($newId, $result->subscription->id);
  724. $this->assertEquals($newPlan['id'], $result->subscription->planId);
  725. $this->assertEquals('999.99', $result->subscription->price);
  726. }
  727. public function testUpdate_doesNotAcceptBadAttributes()
  728. {
  729. $this->setExpectedException('InvalidArgumentException', 'invalid keys: bad');
  730. $result = Braintree\Subscription::update('id', [
  731. 'bad' => 'value'
  732. ]);
  733. }
  734. public function testUpdate_canUpdateNumberOfBillingCycles()
  735. {
  736. $plan = SubscriptionHelper::triallessPlan();
  737. $subscription = SubscriptionHelper::createSubscription();
  738. $this->assertEquals($plan['numberOfBillingCycles'], $subscription->numberOfBillingCycles);
  739. $updatedSubscription = Braintree\Subscription::update($subscription->id, [
  740. 'numberOfBillingCycles' => 15
  741. ])->subscription;
  742. $this->assertEquals(15, $updatedSubscription->numberOfBillingCycles);
  743. }
  744. public function testUpdate_canUpdateNumberOfBillingCyclesToNeverExpire()
  745. {
  746. $plan = SubscriptionHelper::triallessPlan();
  747. $subscription = SubscriptionHelper::createSubscription();
  748. $this->assertEquals($plan['numberOfBillingCycles'], $subscription->numberOfBillingCycles);
  749. $updatedSubscription = Braintree\Subscription::update($subscription->id, [
  750. 'neverExpires' => true
  751. ])->subscription;
  752. $this->assertNull($updatedSubscription->numberOfBillingCycles);
  753. }
  754. public function testUpdate_createsTransactionOnProration()
  755. {
  756. $subscription = SubscriptionHelper::createSubscription();
  757. $result = Braintree\Subscription::update($subscription->id, [
  758. 'price' => $subscription->price + 1,
  759. ]);
  760. $this->assertTrue($result->success);
  761. $this->assertEquals(sizeof($subscription->transactions) + 1, sizeof($result->subscription->transactions));
  762. }
  763. public function testUpdate_createsProratedTransactionWhenFlagIsPassedTrue()
  764. {
  765. $subscription = SubscriptionHelper::createSubscription();
  766. $result = Braintree\Subscription::update($subscription->id, [
  767. 'price' => $subscription->price + 1,
  768. 'options' => ['prorateCharges' => true]
  769. ]);
  770. $this->assertTrue($result->success);
  771. $this->assertEquals(sizeof($subscription->transactions) + 1, sizeof($result->subscription->transactions));
  772. }
  773. public function testUpdate_createsProratedTransactionWhenFlagIsPassedFalse()
  774. {
  775. $subscription = SubscriptionHelper::createSubscription();
  776. $result = Braintree\Subscription::update($subscription->id, [
  777. 'price' => $subscription->price + 1,
  778. 'options' => ['prorateCharges' => false]
  779. ]);
  780. $this->assertTrue($result->success);
  781. $this->assertEquals(sizeof($subscription->transactions), sizeof($result->subscription->transactions));
  782. }
  783. public function testUpdate_DoesNotUpdateSubscriptionWhenProrationTransactionFailsAndRevertIsTrue()
  784. {
  785. $subscription = SubscriptionHelper::createSubscription();
  786. $result = Braintree\Subscription::update($subscription->id, [
  787. 'price' => $subscription->price + 2100,
  788. 'options' => ['prorateCharges' => true, 'revertSubscriptionOnProrationFailure' => true]
  789. ]);
  790. $this->assertFalse($result->success);
  791. $this->assertEquals(sizeof($subscription->transactions) + 1, sizeof($result->subscription->transactions));
  792. $this->assertEquals(Braintree\Transaction::PROCESSOR_DECLINED, $result->subscription->transactions[0]->status);
  793. $this->assertEquals("0.00", $result->subscription->balance);
  794. $this->assertEquals($subscription->price, $result->subscription->price);
  795. }
  796. public function testUpdate_UpdatesSubscriptionWhenProrationTransactionFailsAndRevertIsFalse()
  797. {
  798. $subscription = SubscriptionHelper::createSubscription();
  799. $result = Braintree\Subscription::update($subscription->id, [
  800. 'price' => $subscription->price + 2100,
  801. 'options' => ['prorateCharges' => true, 'revertSubscriptionOnProrationFailure' => false]
  802. ]);
  803. $this->assertTrue($result->success);
  804. $this->assertEquals(sizeof($subscription->transactions) + 1, sizeof($result->subscription->transactions));
  805. $this->assertEquals(Braintree\Transaction::PROCESSOR_DECLINED, $result->subscription->transactions[0]->status);
  806. $this->assertEquals($result->subscription->transactions[0]->amount, $result->subscription->balance);
  807. $this->assertEquals($subscription->price + 2100, $result->subscription->price);
  808. }
  809. public function testUpdate_invalidSubscriptionId()
  810. {
  811. $this->setExpectedException('Braintree\Exception\NotFound');
  812. Braintree\Subscription::update('does-not-exist', []);
  813. }
  814. public function testUpdate_validationErrors()
  815. {
  816. $subscription = SubscriptionHelper::createSubscription();
  817. $result = Braintree\Subscription::update($subscription->id, ['price' => '']);
  818. $this->assertFalse($result->success);
  819. $errors = $result->errors->forKey('subscription')->onAttribute('price');
  820. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_PRICE_CANNOT_BE_BLANK, $errors[0]->code);
  821. }
  822. public function testUpdate_cannotUpdateCanceledSubscription()
  823. {
  824. $subscription = SubscriptionHelper::createSubscription();
  825. Braintree\Subscription::cancel($subscription->id);
  826. $result = Braintree\Subscription::update($subscription->id, ['price' => '1.00']);
  827. $this->assertFalse($result->success);
  828. $errors = $result->errors->forKey('subscription')->onAttribute('base');
  829. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_CANNOT_EDIT_CANCELED_SUBSCRIPTION, $errors[0]->code);
  830. }
  831. public function testUpdate_canUpdatePaymentMethodToken()
  832. {
  833. $oldCreditCard = SubscriptionHelper::createCreditCard();
  834. $plan = SubscriptionHelper::triallessPlan();
  835. $subscription = Braintree\Subscription::create([
  836. 'paymentMethodToken' => $oldCreditCard->token,
  837. 'price' => '54.99',
  838. 'planId' => $plan['id']
  839. ])->subscription;
  840. $newCreditCard = Braintree\CreditCard::createNoValidate([
  841. 'number' => '5105105105105100',
  842. 'expirationDate' => '05/2010',
  843. 'customerId' => $oldCreditCard->customerId
  844. ]);
  845. $result = Braintree\Subscription::update($subscription->id, [
  846. 'paymentMethodToken' => $newCreditCard->token
  847. ]);
  848. $this->assertTrue($result->success);
  849. $this->assertEquals($newCreditCard->token, $result->subscription->paymentMethodToken);
  850. }
  851. public function testUpdate_canUpdatePaymentMethodWithPaymentMethodNonce()
  852. {
  853. $oldCreditCard = SubscriptionHelper::createCreditCard();
  854. $plan = SubscriptionHelper::triallessPlan();
  855. $subscription = Braintree\Subscription::create([
  856. 'paymentMethodToken' => $oldCreditCard->token,
  857. 'price' => '54.99',
  858. 'planId' => $plan['id']
  859. ])->subscription;
  860. $customerId = Braintree\Customer::create()->customer->id;
  861. $http = new HttpClientApi(Braintree\Configuration::$global);
  862. $nonce = $http->nonce_for_new_card([
  863. "creditCard" => [
  864. "number" => "4111111111111111",
  865. "expirationMonth" => "11",
  866. "expirationYear" => "2099"
  867. ],
  868. "customerId" => $oldCreditCard->customerId,
  869. "share" => true
  870. ]);
  871. $result = Braintree\Subscription::update($subscription->id, [
  872. 'paymentMethodNonce' => $nonce
  873. ]);
  874. $this->assertTrue($result->success);
  875. $newCreditCard = Braintree\CreditCard::find($result->subscription->paymentMethodToken);
  876. $this->assertEquals("1111", $newCreditCard->last4);
  877. $this->assertNotEquals($oldCreditCard->last4, $newCreditCard->last4);
  878. }
  879. public function testUpdate_canUpdateAddOnsAndDiscounts()
  880. {
  881. $oldCreditCard = SubscriptionHelper::createCreditCard();
  882. $plan = SubscriptionHelper::addOnDiscountPlan();
  883. $subscription = Braintree\Subscription::create([
  884. 'paymentMethodToken' => $oldCreditCard->token,
  885. 'price' => '54.99',
  886. 'planId' => $plan['id']
  887. ])->subscription;
  888. $result = Braintree\Subscription::update($subscription->id, [
  889. 'addOns' => [
  890. 'update' => [
  891. [
  892. 'amount' => '99.99',
  893. 'existingId' => 'increase_10',
  894. 'quantity' => 99,
  895. 'numberOfBillingCycles' => 99
  896. ],
  897. [
  898. 'amount' => '22.22',
  899. 'existingId' => 'increase_20',
  900. 'quantity' => 22,
  901. 'neverExpires' => true
  902. ]
  903. ],
  904. ],
  905. 'discounts' => [
  906. 'update' => [
  907. [
  908. 'amount' => '33.33',
  909. 'existingId' => 'discount_11',
  910. 'quantity' => 33,
  911. 'numberOfBillingCycles' => 33
  912. ]
  913. ],
  914. ],
  915. ]);
  916. $this->assertTrue($result->success);
  917. $subscription = $result->subscription;
  918. $this->assertEquals(2, sizeof($subscription->addOns));
  919. $addOns = $subscription->addOns;
  920. SubscriptionHelper::sortModificationsById($addOns);
  921. $this->assertEquals($addOns[0]->id, "increase_10");
  922. $this->assertEquals($addOns[0]->amount, "99.99");
  923. $this->assertEquals($addOns[0]->neverExpires, false);
  924. $this->assertEquals($addOns[0]->numberOfBillingCycles, 99);
  925. $this->assertEquals($addOns[0]->quantity, 99);
  926. $this->assertEquals($addOns[1]->id, "increase_20");
  927. $this->assertEquals($addOns[1]->amount, "22.22");
  928. $this->assertEquals($addOns[1]->neverExpires, true);
  929. $this->assertEquals($addOns[1]->numberOfBillingCycles, null);
  930. $this->assertEquals($addOns[1]->quantity, 22);
  931. $this->assertEquals(2, sizeof($subscription->discounts));
  932. $discounts = $subscription->discounts;
  933. SubscriptionHelper::sortModificationsById($discounts);
  934. $this->assertEquals($discounts[0]->id, "discount_11");
  935. $this->assertEquals($discounts[0]->amount, "33.33");
  936. $this->assertEquals($discounts[0]->neverExpires, false);
  937. $this->assertEquals($discounts[0]->numberOfBillingCycles, 33);
  938. $this->assertEquals($discounts[0]->quantity, 33);
  939. }
  940. public function testUpdate_canAddAndRemoveAddOnsAndDiscounts()
  941. {
  942. $oldCreditCard = SubscriptionHelper::createCreditCard();
  943. $plan = SubscriptionHelper::addOnDiscountPlan();
  944. $subscription = Braintree\Subscription::create([
  945. 'paymentMethodToken' => $oldCreditCard->token,
  946. 'price' => '54.99',
  947. 'planId' => $plan['id']
  948. ])->subscription;
  949. $result = Braintree\Subscription::update($subscription->id, [
  950. 'addOns' => [
  951. 'add' => [
  952. [
  953. 'amount' => '33.33',
  954. 'inheritedFromId' => 'increase_30',
  955. 'quantity' => 33,
  956. 'numberOfBillingCycles' => 33
  957. ]
  958. ],
  959. 'remove' => ['increase_10', 'increase_20']
  960. ],
  961. 'discounts' => [
  962. 'add' => [
  963. [
  964. 'inheritedFromId' => 'discount_15',
  965. ]
  966. ],
  967. 'remove' => ['discount_7']
  968. ],
  969. ]);
  970. $this->assertTrue($result->success);
  971. $subscription = $result->subscription;
  972. $this->assertEquals(1, sizeof($subscription->addOns));
  973. $addOns = $subscription->addOns;
  974. SubscriptionHelper::sortModificationsById($addOns);
  975. $this->assertEquals($addOns[0]->id, "increase_30");
  976. $this->assertEquals($addOns[0]->amount, "33.33");
  977. $this->assertEquals($addOns[0]->neverExpires, false);
  978. $this->assertEquals($addOns[0]->numberOfBillingCycles, 33);
  979. $this->assertEquals($addOns[0]->quantity, 33);
  980. $this->assertEquals(2, sizeof($subscription->discounts));
  981. $discounts = $subscription->discounts;
  982. SubscriptionHelper::sortModificationsById($discounts);
  983. $this->assertEquals($discounts[0]->id, "discount_11");
  984. $this->assertEquals($discounts[1]->id, "discount_15");
  985. $this->assertEquals($discounts[1]->amount, "15.00");
  986. $this->assertEquals($discounts[1]->neverExpires, true);
  987. $this->assertNull($discounts[1]->numberOfBillingCycles);
  988. $this->assertEquals($discounts[1]->quantity, 1);
  989. }
  990. public function testUpdate_canReplaceEntireSetOfAddonsAndDiscounts()
  991. {
  992. $oldCreditCard = SubscriptionHelper::createCreditCard();
  993. $plan = SubscriptionHelper::addOnDiscountPlan();
  994. $subscription = Braintree\Subscription::create([
  995. 'paymentMethodToken' => $oldCreditCard->token,
  996. 'price' => '54.99',
  997. 'planId' => $plan['id']
  998. ])->subscription;
  999. $result = Braintree\Subscription::update($subscription->id, [
  1000. 'addOns' => [
  1001. 'add' => [
  1002. ['inheritedFromId' => 'increase_30'],
  1003. ['inheritedFromId' => 'increase_20']
  1004. ]
  1005. ],
  1006. 'discounts' => [
  1007. 'add' => [
  1008. ['inheritedFromId' => 'discount_15']
  1009. ]
  1010. ],
  1011. 'options' => ['replaceAllAddOnsAndDiscounts' => true]
  1012. ]);
  1013. $this->assertTrue($result->success);
  1014. $subscription = $result->subscription;
  1015. $this->assertEquals(2, sizeof($subscription->addOns));
  1016. $addOns = $subscription->addOns;
  1017. SubscriptionHelper::sortModificationsById($addOns);
  1018. $this->assertEquals($addOns[0]->id, "increase_20");
  1019. $this->assertEquals($addOns[1]->id, "increase_30");
  1020. $this->assertEquals(1, sizeof($subscription->discounts));
  1021. $discounts = $subscription->discounts;
  1022. $this->assertEquals($discounts[0]->id, "discount_15");
  1023. }
  1024. public function testUpdate_withDescriptor()
  1025. {
  1026. $creditCard = SubscriptionHelper::createCreditCard();
  1027. $plan = SubscriptionHelper::triallessPlan();
  1028. $subscription = Braintree\Subscription::create([
  1029. 'paymentMethodToken' => $creditCard->token,
  1030. 'planId' => $plan['id'],
  1031. 'descriptor' => [
  1032. 'name' => '123*123456789012345678',
  1033. 'phone' => '3334445555'
  1034. ]
  1035. ])->subscription;
  1036. $result = Braintree\Subscription::update($subscription->id, [
  1037. 'descriptor' => [
  1038. 'name' => '999*9999999',
  1039. 'phone' => '8887776666'
  1040. ]
  1041. ]);
  1042. $updatedSubscription = $result->subscription;
  1043. $this->assertEquals('999*9999999', $updatedSubscription->descriptor->name);
  1044. $this->assertEquals('8887776666', $updatedSubscription->descriptor->phone);
  1045. }
  1046. public function testUpdate_withDescription()
  1047. {
  1048. $paymentMethodToken = 'PAYPAL_TOKEN-' . strval(rand());
  1049. $customer = Braintree\Customer::createNoValidate();
  1050. $plan = SubscriptionHelper::triallessPlan();
  1051. $http = new HttpClientApi(Braintree\Configuration::$global);
  1052. $nonce = $http->nonceForPayPalAccount([
  1053. 'paypal_account' => [
  1054. 'consent_code' => 'PAYPAL_CONSENT_CODE',
  1055. 'token' => $paymentMethodToken
  1056. ]
  1057. ]);
  1058. $paypalResult = Braintree\PaymentMethod::create([
  1059. 'customerId' => $customer->id,
  1060. 'paymentMethodNonce' => $nonce
  1061. ]);
  1062. $subscription = Braintree\Subscription::create([
  1063. 'paymentMethodToken' => $paymentMethodToken,
  1064. 'planId' => $plan['id'],
  1065. 'options' => [
  1066. 'paypal' => [
  1067. 'description' => 'A great product'
  1068. ]
  1069. ]
  1070. ])->subscription;
  1071. $result = Braintree\Subscription::update($subscription->id, [
  1072. 'options' => [
  1073. 'paypal' => [
  1074. 'description' => 'An incredible product'
  1075. ]
  1076. ]
  1077. ]);
  1078. $updatedSubscription = $result->subscription;
  1079. $this->assertEquals('An incredible product', $updatedSubscription->description);
  1080. }
  1081. public function testCancel_returnsSuccessIfCanceled()
  1082. {
  1083. $subscription = SubscriptionHelper::createSubscription();
  1084. $result = Braintree\Subscription::cancel($subscription->id);
  1085. $this->assertTrue($result->success);
  1086. $this->assertEquals(Braintree\Subscription::CANCELED, $result->subscription->status);
  1087. }
  1088. public function testCancel_throwsErrorIfRecordNotFound()
  1089. {
  1090. $this->setExpectedException('Braintree\Exception\NotFound');
  1091. Braintree\Subscription::cancel('non-existing-id');
  1092. }
  1093. public function testCancel_returnsErrorIfCancelingCanceledSubscription()
  1094. {
  1095. $subscription = SubscriptionHelper::createSubscription();
  1096. Braintree\Subscription::cancel($subscription->id);
  1097. $result = Braintree\Subscription::cancel($subscription->id);
  1098. $this->assertFalse($result->success);
  1099. $errors = $result->errors->forKey('subscription')->onAttribute('status');
  1100. $this->assertEquals(Braintree\Error\Codes::SUBSCRIPTION_STATUS_IS_CANCELED, $errors[0]->code);
  1101. }
  1102. public function testRetryCharge_WithoutAmount()
  1103. {
  1104. $subscription = SubscriptionHelper::createSubscription();
  1105. $http = new Braintree\Http(Braintree\Configuration::$global);
  1106. $path = Braintree\Configuration::$global->merchantPath() . '/subscriptions/' . $subscription->id . '/make_past_due';
  1107. $http->put($path);
  1108. $result = Braintree\Subscription::retryCharge($subscription->id);
  1109. $this->assertTrue($result->success);
  1110. $transaction = $result->transaction;
  1111. $this->assertEquals($subscription->price, $transaction->amount);
  1112. $this->assertNotNull($transaction->processorAuthorizationCode);
  1113. $this->assertEquals(Braintree\Transaction::SALE, $transaction->type);
  1114. $this->assertEquals(Braintree\Transaction::AUTHORIZED, $transaction->status);
  1115. }
  1116. public function testRetryCharge_WithAmount()
  1117. {
  1118. $subscription = SubscriptionHelper::createSubscription();
  1119. $http = new Braintree\Http(Braintree\Configuration::$global);
  1120. $path = Braintree\Configuration::$global->merchantPath() . '/subscriptions/' . $subscription->id . '/make_past_due';
  1121. $http->put($path);
  1122. $result = Braintree\Subscription::retryCharge($subscription->id, 1000);
  1123. $this->assertTrue($result->success);
  1124. $transaction = $result->transaction;
  1125. $this->assertEquals(1000, $transaction->amount);
  1126. $this->assertNotNull($transaction->processorAuthorizationCode);
  1127. $this->assertEquals(Braintree\Transaction::SALE, $transaction->type);
  1128. $this->assertEquals(Braintree\Transaction::AUTHORIZED, $transaction->status);
  1129. }
  1130. public function testRetryCharge_WithSubmitForSettlement()
  1131. {
  1132. $subscription = SubscriptionHelper::createSubscription();
  1133. $http = new Braintree\Http(Braintree\Configuration::$global);
  1134. $path = Braintree\Configuration::$global->merchantPath() . '/subscriptions/' . $subscription->id . '/make_past_due';
  1135. $http->put($path);
  1136. $result = Braintree\Subscription::retryCharge($subscription->id, null, true);
  1137. $this->assertTrue($result->success);
  1138. $transaction = $result->transaction;
  1139. $this->assertEquals($subscription->price, $transaction->amount);
  1140. $this->assertNotNull($transaction->processorAuthorizationCode);
  1141. $this->assertEquals(Braintree\Transaction::SALE, $transaction->type);
  1142. $this->assertEquals(Braintree\Transaction::SUBMITTED_FOR_SETTLEMENT, $transaction->status);
  1143. }
  1144. public function testRetryCharge_WithSubmitForSettlementAndAmount()
  1145. {
  1146. $subscription = SubscriptionHelper::createSubscription();
  1147. $http = new Braintree\Http(Braintree\Configuration::$global);
  1148. $path = Braintree\Configuration::$global->merchantPath() . '/subscriptions/' . $subscription->id . '/make_past_due';
  1149. $http->put($path);
  1150. $result = Braintree\Subscription::retryCharge($subscription->id, 1002, true);
  1151. $this->assertTrue($result->success);
  1152. $transaction = $result->transaction;
  1153. $this->assertEquals(1002, $transaction->amount);
  1154. $this->assertNotNull($transaction->processorAuthorizationCode);
  1155. $this->assertEquals(Braintree\Transaction::SALE, $transaction->type);
  1156. $this->assertEquals(Braintree\Transaction::SUBMITTED_FOR_SETTLEMENT, $transaction->status);
  1157. }
  1158. }