diff --git a/src/AbstractGateway.php b/src/AbstractGateway.php index 91808800..9d5653e3 100644 --- a/src/AbstractGateway.php +++ b/src/AbstractGateway.php @@ -107,6 +107,7 @@ public function getDefaultParameters() { return array( 'apiKey' => '', + 'stripeVersion' => null ); } @@ -150,6 +151,24 @@ public function setApiKey($value) return $this->setParameter('apiKey', $value); } + /** + * @return string + */ + public function getStripeVersion() + { + return $this->getParameter('stripeVersion'); + } + + /** + * @param string $value + * + * @return Gateway + */ + public function setStripeVersion($value) + { + return $this->setParameter('stripeVersion', $value); + } + /** * Authorize Request. * @@ -263,6 +282,21 @@ public function fetchBalanceTransaction(array $parameters = array()) return $this->createRequest('\Omnipay\Stripe\Message\FetchBalanceTransactionRequest', $parameters); } + // + // Application Fees + // @link https://stripe.com/docs/api#application_fees + // + + /** + * @param array $parameters + * + * @return \Omnipay\Stripe\Message\FetchApplicationFeeRequest + */ + public function fetchApplicationFee(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\FetchApplicationFeeRequest', $parameters); + } + // // Transfers // @link https://stripe.com/docs/api#transfers diff --git a/src/Gateway.php b/src/Gateway.php index 0ed96fae..aca7fe60 100644 --- a/src/Gateway.php +++ b/src/Gateway.php @@ -233,6 +233,17 @@ public function cancelSubscription(array $parameters = array()) return $this->createRequest('\Omnipay\Stripe\Message\CancelSubscriptionRequest', $parameters); } + /** + * Fetch Schedule Subscription + * + * @param array $parameters + * @return \Omnipay\Stripe\Message\FetchSubscriptionSchedulesRequest + */ + public function fetchSubscriptionSchedules(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\FetchSubscriptionSchedulesRequest', $parameters); + } + /** * Fetch Event * @@ -321,13 +332,31 @@ public function createSource(array $parameters = array()) /** * @param array $parameters - * @return \Omnipay\Stripe\Message\CreateSourceRequest + * @return \Omnipay\Stripe\Message\AttachSourceRequest */ public function attachSource(array $parameters = array()) { return $this->createRequest('\Omnipay\Stripe\Message\AttachSourceRequest', $parameters); } + /** + * @param array $parameters + * @return \Omnipay\Stripe\Message\FetchSourceRequest + */ + public function detachSource(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\DetachSourceRequest', $parameters); + } + + /** + * @param array $parameters + * @return \Omnipay\Stripe\Message\FetchSourceRequest + */ + public function fetchSource(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\FetchSourceRequest', $parameters); + } + /** * Create a completePurchase request. * @@ -338,4 +367,54 @@ public function completePurchase(array $parameters = array()) { return $this->createRequest('\Omnipay\Stripe\Message\CompletePurchaseRequest', $parameters); } + + /** + * @param array $parameters + * + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function createCoupon(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\CreateCouponRequest', $parameters); + } + + /** + * @param array $parameters + * + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function fetchCoupon(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\FetchCouponRequest', $parameters); + } + + /** + * @param array $parameters + * + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function deleteCoupon(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\DeleteCouponRequest', $parameters); + } + + /** + * @param array $parameters + * + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function updateCoupon(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\UpdateCouponRequest', $parameters); + } + + /** + * @param array $parameters + * + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function listCoupons(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\ListCouponsRequest', $parameters); + } } diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index 805b2d34..0b0e3038 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -174,6 +174,27 @@ public function setIdempotencyKeyHeader($value) return $this->setParameter('idempotencyKey', $value); } + /** + * @return array + */ + public function getExpand() + { + return $this->getParameter('expand'); + } + + /** + * Specifies which object relations (IDs) in the response should be expanded to include the entire object. + * + * @see https://stripe.com/docs/api/expanding_objects + * + * @param array $value + * @return AbstractRequest + */ + public function setExpand($value) + { + return $this->setParameter('expand', $value); + } + abstract public function getEndpoint(); /** @@ -221,17 +242,42 @@ public function sendData($data) ); $body = $data ? http_build_query($data, '', '&') : null; - $httpResponse = $this->httpClient->request($this->getHttpMethod(), $this->getEndpoint(), $headers, $body); + $httpResponse = $this->httpClient->request( + $this->getHttpMethod(), + $this->getExpandedEndpoint(), + $headers, + $body + ); return $this->createResponse($httpResponse->getBody()->getContents(), $httpResponse->getHeaders()); } + /** + * Appends the `expand` properties to the endpoint as a querystring. + * + * @return string + */ + public function getExpandedEndpoint() + { + $endpoint = $this->getEndpoint(); + $expand = $this->getExpand(); + if (is_array($expand) && count($expand) > 0) { + $queryParams = []; + foreach ($expand as $key) { + $queryParams[] = 'expand[]=' . $key; + } + $queryString = join('&', $queryParams); + $endpoint .= '?' . $queryString; + } + + return $endpoint; + } protected function createResponse($data, $headers = []) { return $this->response = new Response($this, $data, $headers); } - + /** * @return mixed */ @@ -311,17 +357,30 @@ protected function getCardData() $data = array(); $data['object'] = 'card'; + + // If track data is present, only return data relevant to a card present charge + $tracks = $card->getTracks(); + $cvv = $card->getCvv(); + $postcode = $card->getPostcode(); + if (!empty($postcode)) { + $data['address_zip'] = $postcode; + } + if (!empty($cvv)) { + $data['cvc'] = $cvv; + } + if (!empty($tracks)) { + $data['swipe_data'] = $tracks; + return $data; + } + + // If we got here, it's a card not present transaction, so include everything we have $data['number'] = $card->getNumber(); $data['exp_month'] = $card->getExpiryMonth(); $data['exp_year'] = $card->getExpiryYear(); - if ($card->getCvv()) { - $data['cvc'] = $card->getCvv(); - } $data['name'] = $card->getName(); $data['address_line1'] = $card->getAddress1(); $data['address_line2'] = $card->getAddress2(); $data['address_city'] = $card->getCity(); - $data['address_zip'] = $card->getPostcode(); $data['address_state'] = $card->getState(); $data['address_country'] = $card->getCountry(); $data['email'] = $card->getEmail(); diff --git a/src/Message/AttachSourceRequest.php b/src/Message/AttachSourceRequest.php index d81e4651..48e690bd 100644 --- a/src/Message/AttachSourceRequest.php +++ b/src/Message/AttachSourceRequest.php @@ -7,7 +7,7 @@ /** * Class CreateSourceRequest * - * TODO : Add docblock + * @link https://stripe.com/docs/api/sources/attach */ class AttachSourceRequest extends AbstractRequest { diff --git a/src/Message/AuthorizeRequest.php b/src/Message/AuthorizeRequest.php index 2850215e..703a1b56 100644 --- a/src/Message/AuthorizeRequest.php +++ b/src/Message/AuthorizeRequest.php @@ -5,9 +5,11 @@ */ namespace Omnipay\Stripe\Message; +use Money\Formatter\DecimalMoneyFormatter; +use Omnipay\Common\Exception\InvalidRequestException; use Omnipay\Common\ItemBag; +use Omnipay\Stripe\StripeItem; use Omnipay\Stripe\StripeItemBag; -use Money\Formatter\DecimalMoneyFormatter; /** * Stripe Authorize Request. @@ -155,7 +157,7 @@ public function setOnBehalfOf($value) /** * @return string - * @throws \Omnipay\Common\Exception\InvalidRequestException + * @throws InvalidRequestException */ public function getApplicationFee() { @@ -174,7 +176,7 @@ public function getApplicationFee() * Get the payment amount as an integer. * * @return integer - * @throws \Omnipay\Common\Exception\InvalidRequestException + * @throws InvalidRequestException */ public function getApplicationFeeInteger() { @@ -231,7 +233,7 @@ public function setReceiptEmail($email) /** * A list of items in this order * - * @return ItemBag|null A bag containing items in this order + * @return StripeItemBag|StripeItem[]|null A bag containing items in this order */ public function getItems() { @@ -242,6 +244,7 @@ public function getItems() * Set the items in this order * * @param array $items An array of items in this order + * @return AuthorizeRequest */ public function setItems($items) { @@ -265,11 +268,40 @@ public function getData() $data['capture'] = 'false'; if ($items = $this->getItems()) { - $itemDescriptions = []; - foreach ($items as $n => $item) { - $itemDescriptions[] = $item->getDescription(); + if (empty($this->getDescription())) { + $itemDescriptions = []; + foreach ($items as $n => $item) { + $itemDescriptions[] = $item->getDescription(); + } + $data['description'] = implode(" + ", $itemDescriptions); + } + + if ($this->validateLineItemsForLevel3($items)) { + $lineItems = []; + foreach ($items as $item) { + $lineItem = [ + 'product_code' => substr($item->getName(), 0, 12), + 'product_description' => substr($item->getDescription(), 0, 26) + ]; + if ($item->getPrice()) { + $lineItem['unit_cost'] = $this->getAmountWithCurrencyPrecision($item->getPrice()); + } + if ($item->getQuantity()) { + $lineItem['quantity'] = $item->getQuantity(); + } + if ($item->getTaxes()) { + $lineItem['tax_amount'] = $this->getAmountWithCurrencyPrecision($item->getTaxes()); + } + if ($item->getDiscount()) { + $lineItem['discount_amount'] = $this->getAmountWithCurrencyPrecision($item->getDiscount()); + } + $lineItems[] = $lineItem; + } + $data['level3'] = [ + 'merchant_reference' => $this->getTransactionId(), + 'line_items' => $lineItems + ]; } - $data['description'] = implode(" + ", $itemDescriptions); } if ($this->getStatementDescriptor()) { @@ -319,8 +351,29 @@ public function getData() return $data; } + private function getAmountWithCurrencyPrecision($amount) + { + return (int)round($amount * pow(10, $this->getCurrencyDecimalPlaces())); + } + + /** + * For Stripe to accept Level 3 data, the sum of all the line items should equal the request's `amount`. This + * method validates that the summation adds up as expected. + * + * @param StripeItemBag $items + * @return bool + */ + private function validateLineItemsForLevel3(StripeItemBag $items) + { + $actualAmount = 0; + foreach ($items as $item) { + $actualAmount += $item->getQuantity() * $item->getPrice() + $item->getTaxes() - $item->getDiscount(); + } + return (string)$actualAmount == (string)$this->getAmount(); + } + public function getEndpoint() { - return $this->endpoint.'/charges'; + return $this->endpoint . '/charges'; } } diff --git a/src/Message/CreateCouponRequest.php b/src/Message/CreateCouponRequest.php new file mode 100644 index 00000000..d5cb443c --- /dev/null +++ b/src/Message/CreateCouponRequest.php @@ -0,0 +1,201 @@ +getParameter('amount_off'); + } + + /** + * @param int $value + * + * @return CreateCouponRequest + */ + public function setAmountOff($value) + { + return $this->setParameter('amount_off', $value); + } + + /** + * @return int + */ + public function getPercentOff() + { + return $this->getParameter('percent_off'); + } + + /** + * @param int $value + * + * @return CreateCouponRequest + */ + public function setPercentOff($value) + { + return $this->setParameter('percent_off', $value); + } + + /** + * @return int + */ + public function getDurationInMonths() + { + return $this->getParameter('duration_in_months'); + } + + /** + * @param int $value + * + * @return CreateCouponRequest + */ + public function setDurationInMonths($value) + { + return $this->setParameter('duration_in_months', $value); + } + + /** + * @return string + */ + public function getName() + { + return $this->getParameter('name'); + } + + /** + * @param string $value + * + * @return CreateCouponRequest + */ + public function setName($value) + { + return $this->setParameter('name', $value); + } + + /** + * @return int + */ + public function getMaxRedemptions() + { + return $this->getParameter('max_redemptions'); + } + + /** + * @param int $value + * + * @return CreateCouponRequest + */ + public function setMaxRedemptions($value) + { + return $this->setParameter('duration_in_months', $value); + } + + /** + * @return int + */ + public function getRedeemBy() + { + return $this->getParameter('redeem_by'); + } + + /** + * @param int $value + * + * @return CreateCouponRequest + */ + public function setRedeemBy($value) + { + return $this->setParameter('redeem_by', $value); + } + + /** + * @return string + */ + public function getId() + { + return $this->getParameter('id'); + } + + /** + * @param string $value + * + * @return CreateCouponRequest + */ + public function setId($value) + { + return $this->setParameter('id', $value); + } + + /** + * @return string + */ + public function getDuration() + { + return $this->getParameter('duration'); + } + + /** + * @param string $value + * + * @return CreateCouponRequest + */ + public function setDuration($value) + { + return $this->setParameter('duration', $value); + } + + /** + * {@inheritdoc} + */ + public function getData() + { + $this->validate('duration'); + + $amountOff = $this->getAmountOff(); + $percentOff = $this->getPercentOff(); + + if (!isset($amountOff) && !isset($percentOff)) { + throw new InvalidRequestException("Either amount_off or percent_off is required"); + } + + $data = [ + 'id' => $this->getId(), + 'duration' => $this->getDuration(), + 'amount_off' => $this->getAmountOff(), + 'currency' => $this->getCurrency(), + 'duration_in_months' => $this->getDurationInMonths(), + 'name' => $this->getName(), + 'max_redemptions' => $this->getMaxRedemptions(), + 'percent_off' => $this->getPercentOff(), + 'redeem_by' => $this->getRedeemBy(), + ]; + + if ($this->getMetadata()) { + $data['metadata'] = $this->getMetadata(); + } + + return $data; + } + + public function getEndpoint() + { + return $this->endpoint.'/coupons'; + } + + public function getHttpMethod() + { + return 'POST'; + } +} diff --git a/src/Message/CreatePlanRequest.php b/src/Message/CreatePlanRequest.php index ca67730e..a23f68d5 100644 --- a/src/Message/CreatePlanRequest.php +++ b/src/Message/CreatePlanRequest.php @@ -10,7 +10,7 @@ * Stripe Create Plan Request * * @see \Omnipay\Stripe\Gateway - * @link https://stripe.com/docs/api#create_plan + * @link https://stripe.com/docs/api/plans/create */ class CreatePlanRequest extends AbstractRequest { @@ -79,27 +79,30 @@ public function getIntervalCount() /** * Set the plan name + * @deprecated use setNickname() instead * * @param $value * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest */ public function setName($value) { - return $this->setParameter('name', $value); + return $this->setNickname($value); } /** * Get the plan name + * @deprecated use getNickname() instead * * @return string */ public function getName() { - return $this->getParameter('name'); + return $this->getNickname(); } /** * Set the plan statement descriptor + * @deprecated Not used anymore * * @param $planStatementDescriptor * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest @@ -111,6 +114,7 @@ public function setStatementDescriptor($planStatementDescriptor) /** * Get the plan statement descriptor + * @deprecated Not used anymore * * @return string */ @@ -119,6 +123,192 @@ public function getStatementDescriptor() return $this->getParameter('statement_descriptor'); } + /** + * Set the plan product + * + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setProduct($value) + { + return $this->setParameter('product', $value); + } + + /** + * Get the plan product + * + * @return string|array + */ + public function getProduct() + { + return $this->getParameter('product'); + } + + /** + * Set the plan amount + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setAmount($value) + { + return $this->setParameter('amount', (integer)$value); + } + + /** + * Get the plan amount + * + * @return int + */ + public function getAmount() + { + return $this->getParameter('amount'); + } + + /** + * Set the plan tiers + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setTiers($value) + { + return $this->setParameter('tiers', $value); + } + + /** + * Get the plan tiers + * + * @return int + */ + public function getTiers() + { + return $this->getParameter('tiers'); + } + + /** + * Set the plan tiers mode + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setTiersMode($value) + { + return $this->setParameter('tiers_mode', $value); + } + + /** + * Get the plan tiers mode + * + * @return int + */ + public function getTiersMode() + { + return $this->getParameter('tiers_mode'); + } + + /** + * Set the plan nickname + * + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setNickname($value) + { + return $this->setParameter('nickname', $value); + } + + /** + * Get the plan nickname + * + * @return string|array + */ + public function getNickname() + { + return $this->getParameter('nickname'); + } + + /** + * Set the plan metadata + * + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setMetadata($value) + { + return $this->setParameter('metadata', $value); + } + + /** + * Get the plan metadata + * + * @return string|array + */ + public function getMetadata() + { + return $this->getParameter('metadata'); + } + + /** + * Set the plan active + * + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setActive($value) + { + return $this->setParameter('active', $value); + } + + /** + * Get the plan active + * + * @return string|array + */ + public function getActive() + { + return $this->getParameter('active'); + } + + /** + * Set the plan billingScheme + * + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setBillingScheme($value) + { + return $this->setParameter('billing_scheme', $value); + } + + /** + * Get the plan billingScheme + * + * @return string|array + */ + public function getBillingScheme() + { + return $this->getParameter('billing_scheme'); + } + + /** + * Set the plan aggregate usage + * + * @param $planAggregateUsage + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setAggregateUsage($planAggregateUsage) + { + return $this->setParameter('aggregate_usage', $planAggregateUsage); + } + + /** + * Get the plan aggregate usage + * + * @return string + */ + public function getAggregateUsage() + { + return $this->getParameter('aggregate_usage'); + } + /** * Set the plan trial period days * @@ -140,31 +330,114 @@ public function getTrialPeriodDays() return $this->getParameter('trial_period_days'); } + /** + * Set the plan transform usage + * + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setTransformUsage($value) + { + return $this->setParameter('transform_usage', $value); + } + + /** + * Get the plan transform usage + * + * @return int + */ + public function getTransformUsage() + { + return $this->getParameter('transform_usage'); + } + + /** + * Set the plan usage type + * + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|CreatePlanRequest + */ + public function setUsageType($value) + { + return $this->setParameter('usage_type', $value); + } + + /** + * Get the plan usage type + * + * @return int + */ + public function getUsageType() + { + return $this->getParameter('usage_type'); + } + public function getData() { - $this->validate('id', 'amount', 'currency', 'interval', 'name'); + $this->validate('currency', 'interval', 'product'); + + if (null == $this->getBillingScheme() || 'per_unit' == $this->getBillingScheme()) { + $this->validate('amount'); + } elseif ('tiered' == $this->getBillingScheme()) { + $this->validate('tiers', 'tiers_mode'); + } $data = array( - 'id' => $this->getId(), - 'amount' => $this->getAmountInteger(), 'currency' => $this->getCurrency(), 'interval' => $this->getInterval(), - 'name' => $this->getName() + 'product' => $this->getProduct() ); - $intervalCount = $this->getIntervalCount(); - if ($intervalCount != null) { - $data['interval_count'] = $intervalCount; + if (null != $this->getBillingScheme()) { + $data['billing_scheme'] = $this->getBillingScheme(); + } + + if (null != $this->getId()) { + $data['id'] = $this->getId(); + } + + if (null != $this->getAmount()) { + $data['amount'] = $this->getAmount(); + } + + if (null != $this->getNickName()) { + $data['nickname'] = $this->getNickName(); + } + + if (null != $this->getMetadata()) { + $data['metadata'] = $this->getMetadata(); + } + + if (null != $this->getActive()) { + $data['active'] = $this->getActive(); + } + + if (null != $this->getIntervalCount()) { + $data['interval_count'] = $this->getIntervalCount(); + } + + if (null != $this->getAggregateUsage()) { + $data['aggregate_usage'] = $this->getAggregateUsage(); + } + + if (null != $this->getTrialPeriodDays()) { + $data['trial_period_days'] = $this->getTrialPeriodDays(); + } + + if (null != $this->getTransformUsage()) { + $data['transform_usage'] = $this->getTransformUsage(); + } + + if (null != $this->getUsageType()) { + $data['usage_type'] = $this->getUsageType(); } - $statementDescriptor = $this->getStatementDescriptor(); - if ($statementDescriptor != null) { - $data['statement_descriptor'] = $statementDescriptor; + if (null != $this->getTiers()) { + $data['tiers'] = $this->getTiers(); } - $trialPeriodDays = $this->getTrialPeriodDays(); - if ($trialPeriodDays != null) { - $data['trial_period_days'] = $trialPeriodDays; + if (null != $this->getTiersMode()) { + $data['tiers_mode'] = $this->getTiersMode(); } return $data; diff --git a/src/Message/CreateSourceRequest.php b/src/Message/CreateSourceRequest.php index 63cb91f1..a10ca829 100644 --- a/src/Message/CreateSourceRequest.php +++ b/src/Message/CreateSourceRequest.php @@ -9,7 +9,7 @@ /** * Class CreateSourceRequest * - * TODO : Add docblock + * @link https://stripe.com/docs/api/sources/create */ class CreateSourceRequest extends AbstractRequest { diff --git a/src/Message/CreateSubscriptionRequest.php b/src/Message/CreateSubscriptionRequest.php index b3863879..498d7619 100644 --- a/src/Message/CreateSubscriptionRequest.php +++ b/src/Message/CreateSubscriptionRequest.php @@ -45,6 +45,28 @@ public function getTaxPercent() return $this->getParameter('tax_percent'); } + + /** + * Get the the trial end timestamp + * + * @return int + */ + public function getTrialEnd() + { + return $this->getParameter('trial_end'); + } + + /** + * Set the trial end timestamp. + * + * @param int $value + * @return \Omnipay\Common\Message\AbstractRequest|CreateSubscriptionRequest + */ + public function setTrialEnd($value) + { + return $this->setParameter('trial_end', $value); + } + /** * Set the tax percentage * @@ -72,6 +94,9 @@ public function getData() $data['metadata'] = $this->getMetadata(); } + if ($this->getTrialEnd()) { + $data['trial_end'] = $this->getTrialEnd(); + } return $data; } diff --git a/src/Message/DeleteCouponRequest.php b/src/Message/DeleteCouponRequest.php new file mode 100644 index 00000000..b23dfad0 --- /dev/null +++ b/src/Message/DeleteCouponRequest.php @@ -0,0 +1,49 @@ +getParameter('couponId'); + } + + /** + * Set the coupon id. + * + * @param string $value + * + * @return DeleteCouponRequest provides a fluent interface + */ + public function setCouponId($value) + { + return $this->setParameter('couponId', $value); + } + + public function getData() + { + $this->validate('couponId'); + } + + public function getEndpoint() + { + return $this->endpoint.'/coupons/'.$this->getCouponId(); + } + + public function getHttpMethod() + { + return 'DELETE'; + } +} diff --git a/src/Message/DetachSourceRequest.php b/src/Message/DetachSourceRequest.php new file mode 100644 index 00000000..e9e32ef9 --- /dev/null +++ b/src/Message/DetachSourceRequest.php @@ -0,0 +1,34 @@ +validate('customerReference', 'source'); + + return; + } + + public function getEndpoint() + { + return $this->endpoint.'/customers/'.$this->getCustomerReference().'/sources/'.$this->getSource(); + } + + public function getHttpMethod() + { + return 'DELETE'; + } +} diff --git a/src/Message/FetchApplicationFeeRequest.php b/src/Message/FetchApplicationFeeRequest.php new file mode 100644 index 00000000..0f708974 --- /dev/null +++ b/src/Message/FetchApplicationFeeRequest.php @@ -0,0 +1,69 @@ + + * // Fetch the transaction so that details can be found for refund, etc. + * $transaction = $gateway->fetchApplicationFee(); + * $transaction->setApplicationFeeReference($application_fee_id); + * $response = $transaction->send(); + * $data = $response->getData(); + * echo "Gateway fetchApplicationFee response data == " . print_r($data, true) . "\n"; + * + * + * @see \Omnipay\Stripe\Gateway + * + * @link https://stripe.com/docs/api#retrieve_application_fee + */ +class FetchApplicationFeeRequest extends AbstractRequest +{ + /** + * Get the application fee reference + * + * @return string + */ + public function getApplicationFeeReference() + { + return $this->getParameter('applicationFeeReference'); + } + + /** + * Set the application fee reference + * + * @param string $value + * + * @return AbstractRequest provides a fluent interface. + */ + public function setApplicationFeeReference($value) + { + return $this->setParameter('applicationFeeReference', $value); + } + + public function getData() + { + $this->validate('applicationFeeReference'); + + $data = array(); + + return $data; + } + + public function getEndpoint() + { + return $this->endpoint . '/application_fees/' . $this->getApplicationFeeReference(); + } + + public function getHttpMethod() + { + return 'GET'; + } +} diff --git a/src/Message/FetchCouponRequest.php b/src/Message/FetchCouponRequest.php new file mode 100644 index 00000000..7d22eda2 --- /dev/null +++ b/src/Message/FetchCouponRequest.php @@ -0,0 +1,48 @@ +getParameter('couponId'); + } + + /** + * Set the coupon id. + * + * @param string + * @return FetchCouponRequest provides a fluent interface. + */ + public function setCouponId($value) + { + return $this->setParameter('couponId', $value); + } + + public function getData() + { + $this->validate('couponId'); + } + + public function getEndpoint() + { + return $this->endpoint.'/coupons/'.$this->getCouponId(); + } + + public function getHttpMethod() + { + return 'GET'; + } +} diff --git a/src/Message/FetchSourceRequest.php b/src/Message/FetchSourceRequest.php new file mode 100644 index 00000000..cb35b1ee --- /dev/null +++ b/src/Message/FetchSourceRequest.php @@ -0,0 +1,54 @@ +getParameter('clientSecret'); + } + + /** + * @param string $value + * + * @return FetchSourceRequest + */ + public function setClientSecret($value) + { + return $this->setParameter('clientSecret', $value); + } + + public function getData() + { + $this->validate('source'); + $data = array(); + + if ($clientSecret = $this->getClientSecret()) { + $data['client_secret'] = $clientSecret; + } + + return $data; + } + + public function getEndpoint() + { + return $this->endpoint.'/sources/'.$this->getSource(); + } + + public function getHttpMethod() + { + return 'GET'; + } +} diff --git a/src/Message/FetchSubscriptionSchedulesRequest.php b/src/Message/FetchSubscriptionSchedulesRequest.php new file mode 100644 index 00000000..c41006c3 --- /dev/null +++ b/src/Message/FetchSubscriptionSchedulesRequest.php @@ -0,0 +1,53 @@ +getParameter('subscriptionSchedulesReference'); + } + + /** + * Set the subscription reference. + * + * @param $value + * @return \Omnipay\Common\Message\AbstractRequest|FetchSubscriptionRequest + */ + public function setSubscriptionSchedulesReference($value) + { + return $this->setParameter('subscriptionSchedulesReference', $value); + } + + public function getData() + { + $this->validate('subscriptionSchedulesReference'); + + return array(); + } + + public function getEndpoint() + { + return $this->endpoint.'/subscription_schedules/'.$this->getSubscriptionSchedulesReference(); + } + + public function getHttpMethod() + { + return 'GET'; + } +} diff --git a/src/Message/ListCouponsRequest.php b/src/Message/ListCouponsRequest.php new file mode 100644 index 00000000..23aba42c --- /dev/null +++ b/src/Message/ListCouponsRequest.php @@ -0,0 +1,123 @@ +getParameter('created'); + } + + /** + * @param string $value + * + * @return ListCouponsRequest + */ + public function setCreated($value) + { + return $this->setParameter('created', $value); + } + + /** + * @return mixed + */ + public function getLimit() + { + return $this->getParameter('limit'); + } + + /** + * @param string $value + * + * @return ListCouponsRequest + */ + public function setLimit($value) + { + return $this->setParameter('limit', $value); + } + + /** + * A cursor for use in pagination. `ending_before` is an object ID that defines your place in the list. + * For instance, if you make a list request and receive 100 objects, starting with `obj_bar`, your + * subsequent call can include `ending_before=obj_ba`r in order to fetch the previous page of the list. + * + * @return mixed + */ + public function getEndingBefore() + { + return $this->getParameter('endingBefore'); + } + + /** + * A cursor for use in pagination. `starting_after` is an object ID that defines your place in the list. + * For instance, if you make a list request and receive 100 objects, ending with `obj_foo`, your + * subsequent call can include `starting_after=obj_foo` in order to fetch the next page of the list. + * + * @return mixed + */ + public function getStartingAfter() + { + return $this->getParameter('startingAfter'); + } + + /** + * @param string $value + * + * @return \Omnipay\Common\Message\AbstractRequest + */ + public function setStartingAfter($value) + { + return $this->setParameter('startingAfter', $value); + } + + /** + * @param string $value + * + * @return ListCouponsRequest + */ + public function setEndingBefore($value) + { + return $this->setParameter('endingBefore', $value); + } + + public function getData() + { + $data = array(); + + if ($this->getLimit()) { + $data['created'] = $this->getCreated(); + } + if ($this->getLimit()) { + $data['limit'] = $this->getLimit(); + } + + if ($this->getEndingBefore()) { + $data['ending_before'] = $this->getEndingBefore(); + } + + if ($this->getStartingAfter()) { + $data['starting_after'] = $this->getStartingAfter(); + } + + return $data; + } + + public function getEndpoint() + { + return $this->endpoint.'/coupons'; + } + + public function getHttpMethod() + { + return 'GET'; + } +} diff --git a/src/Message/PaymentIntents/AuthorizeRequest.php b/src/Message/PaymentIntents/AuthorizeRequest.php index fe939d1e..5a44bad9 100644 --- a/src/Message/PaymentIntents/AuthorizeRequest.php +++ b/src/Message/PaymentIntents/AuthorizeRequest.php @@ -110,10 +110,11 @@ class AuthorizeRequest extends AbstractRequest * Set the confirm parameter. * * @param $value + * @return AbstractRequest provides a fluent interface. */ public function setConfirm($value) { - $this->setParameter('confirm', $value); + return $this->setParameter('confirm', $value); } /** @@ -286,6 +287,48 @@ public function setReceiptEmail($email) return $this; } + /** + * Set the setup_future_usage parameter. + * + * @param $value + * @return AbstractRequest provides a fluent interface. + */ + public function setSetupFutureUsage($value) + { + return $this->setParameter('setup_future_usage', $value); + } + + /** + * Get the setup_future_usage parameter. + * + * @return mixed + */ + public function getSetupFutureUsage() + { + return $this->getParameter('setup_future_usage'); + } + + /** + * Set the setup_future_usage parameter. + * + * @param $value + * @return AbstractRequest provides a fluent interface. + */ + public function setOffSession($value) + { + return $this->setParameter('off_session', $value); + } + + /** + * Get the setup_future_usage parameter. + * + * @return mixed + */ + public function getOffSession() + { + return $this->getParameter('off_session'); + } + /** * @inheritdoc */ @@ -312,7 +355,7 @@ public function getData() } if ($this->getApplicationFee()) { - $data['application_fee'] = $this->getApplicationFeeInteger(); + $data['application_fee_amount'] = $this->getApplicationFeeInteger(); } if ($this->getTransferGroup()) { @@ -343,15 +386,23 @@ public function getData() $data['customer'] = $this->getCustomerReference(); } + if ($this->getSetupFutureUsage()) { + $data['setup_future_usage'] = $this->getSetupFutureUsage(); + } + + $data['off_session'] = $this->getOffSession() ? 'true' : 'false'; + $data['confirmation_method'] = 'manual'; $data['capture_method'] = 'manual'; $data['confirm'] = $this->getConfirm() ? 'true' : 'false'; - if ($this->getConfirm()) { + if ($this->getConfirm() && !$this->getOffSession()) { $this->validate('returnUrl'); $data['return_url'] = $this->getReturnUrl(); } + $data['off_session'] = $this->getOffSession() ? 'true' : 'false'; + return $data; } diff --git a/src/Message/Response.php b/src/Message/Response.php index 6e5ea959..46d263c0 100644 --- a/src/Message/Response.php +++ b/src/Message/Response.php @@ -100,6 +100,23 @@ public function getTransactionReference() return null; } + /** + * Get the balance transaction reference. + * + * @return string|null + */ + public function getApplicationFeeReference() + { + if (isset($this->data['object']) && 'application_fee' === $this->data['object']) { + return $this->data['id']; + } + if (isset($this->data['error']) && isset($this->data['error']['application_fee'])) { + return $this->data['error']['application_fee']; + } + + return null; + } + /** * Get the balance transaction reference. * @@ -227,6 +244,10 @@ public function getSource() return $this->data['source']; } + if (isset($this->data['object']) && 'source' === $this->data['object']) { + return $this->data; + } + return null; } @@ -244,6 +265,20 @@ public function getSubscriptionReference() return null; } + /** + * Get the subscription schedule reference from the response of FetchSubscriptionSchedulesRequest. + * + * @return array|null + */ + public function getSubscriptionSchedulesReference() + { + if (isset($this->data['object']) && $this->data['object'] == 'subscription_schedule') { + return $this->data['id']; + } + + return null; + } + /** * Get the event reference from the response of FetchEventRequest. * @@ -348,6 +383,20 @@ public function getPlanId() return null; } + /** + * Get plan id + * + * @return string|null + */ + public function getSourceId() + { + if (isset($this->data['object']) && 'source' === $this->data['object']) { + return $this->data['id']; + } + + return null; + } + /** * Get invoice-item reference * @@ -512,4 +561,36 @@ public function getSessionId() return null; } + + /** + * Get the coupon plan from the response of CreateCouponRequest. + * + * @return array|null + */ + public function getCoupon() + { + if (isset($this->data['coupon'])) { + return $this->data['coupon']; + } elseif (array_key_exists('object', $this->data) && $this->data['object'] == 'coupon') { + return $this->data; + } + + return null; + } + + /** + * Get coupon id + * + * @return string|null + */ + public function getCouponId() + { + $coupon = $this->getCoupon(); + + if ($coupon && array_key_exists('id', $coupon)) { + return $coupon['id']; + } + + return null; + } } diff --git a/src/Message/SetupIntents/AbstractRequest.php b/src/Message/SetupIntents/AbstractRequest.php new file mode 100644 index 00000000..246fc1ac --- /dev/null +++ b/src/Message/SetupIntents/AbstractRequest.php @@ -0,0 +1,38 @@ +setParameter('setupIntentReference', $value); + } + + /** + * @return mixed + */ + public function getSetupIntentReference() + { + return $this->getParameter('setupIntentReference'); + } +} diff --git a/src/Message/SetupIntents/CreateSetupIntentRequest.php b/src/Message/SetupIntents/CreateSetupIntentRequest.php new file mode 100644 index 00000000..53eb08b0 --- /dev/null +++ b/src/Message/SetupIntents/CreateSetupIntentRequest.php @@ -0,0 +1,67 @@ + + * + * + * + * @see \Omnipay\Stripe\Message\PaymentIntents\AttachPaymentMethodRequest + * @see \Omnipay\Stripe\Message\PaymentIntents\DetachPaymentMethodRequest + * @see \Omnipay\Stripe\Message\PaymentIntents\UpdatePaymentMethodRequest + * @link https://stripe.com/docs/api/setup_intents/create + */ +class CreateSetupIntentRequest extends AbstractRequest +{ + /** + * @inheritdoc + */ + public function getData() + { + $data = []; + + if ($this->getCustomerReference()) { + $data['customer'] = $this->getCustomerReference(); + } + if ($this->getDescription()) { + $data['description'] = $this->getDescription(); + } + + if ($this->getMetadata()) { + $this['metadata'] = $this->getMetadata(); + } + if ($this->getPaymentMethod()) { + $this['payment_method'] = $this->getPaymentMethod(); + } + + $data['usage'] = 'off_session'; + $data['payment_method_types'][] = 'card'; + + return $data; + } + + /** + * @inheritdoc + */ + public function getEndpoint() + { + return $this->endpoint . '/setup_intents'; + } + + /** + * @inheritdoc + */ + protected function createResponse($data, $headers = []) + { + return $this->response = new Response($this, $data, $headers); + } +} diff --git a/src/Message/SetupIntents/Response.php b/src/Message/SetupIntents/Response.php new file mode 100644 index 00000000..47cc3007 --- /dev/null +++ b/src/Message/SetupIntents/Response.php @@ -0,0 +1,145 @@ +data['object']) && 'setup_intent' === $this->data['object']) { + return $this->data['status']; + } + + return null; + } + + /** + * Return true if the payment intent requires confirmation. + * + * @return bool + */ + public function requiresConfirmation() + { + return $this->getStatus() === 'requires_confirmation'; + } + + /** + * @inheritdoc + */ + public function getClientSecret() + { + if (isset($this->data['object']) && 'setup_intent' === $this->data['object']) { + if (!empty($this->data['client_secret'])) { + return $this->data['client_secret']; + } + } + } + + /** + * @inheritdoc + */ + public function getCustomerReference() + { + + if (isset($this->data['object']) && 'setup_intent' === $this->data['object']) { + if (!empty($this->data['customer'])) { + return $this->data['customer']; + } + } + + return parent::getCustomerReference(); + } + + /** + * @inheritdoc + */ + public function isSuccessful() + { + if (isset($this->data['object']) && 'setup_intent' === $this->data['object']) { + return in_array($this->getStatus(), ['succeeded', 'requires_payment_method']); + } + + return parent::isSuccessful(); + } + + /** + * @inheritdoc + */ + public function isCancelled() + { + if (isset($this->data['object']) && 'setup_intent' === $this->data['object']) { + return $this->getStatus() === 'canceled'; + } + + return parent::isCancelled(); + } + + /** + * @inheritdoc + */ + public function isRedirect() + { + if ($this->getStatus() === 'requires_action' || $this->getStatus() === 'requires_source_action') { + // Currently this gateway supports only manual confirmation, so any other + // next action types pretty much mean a failed transaction for us. + return (!empty($this->data['next_action']) && $this->data['next_action']['type'] === 'redirect_to_url'); + } + + return parent::isRedirect(); + } + + /** + * @inheritdoc + */ + public function getRedirectUrl() + { + return $this->isRedirect() ? $this->data['next_action']['redirect_to_url']['url'] : parent::getRedirectUrl(); + } + + /** + * Get the payment intent reference. + * + * @return string|null + */ + public function getSetupIntentReference() + { + if (isset($this->data['object']) && 'setup_intent' === $this->data['object']) { + return $this->data['id']; + } + + return null; + } + + /** + * Get the payment intent reference. + * + * @return string|null + */ + public function getPaymentMethod() + { + if (isset($this->data['object']) && 'setup_intent' === $this->data['object']) { + return $this->data['payment_method']; + } + + return null; + } +} diff --git a/src/Message/SetupIntents/RetrieveSetupIntentRequest.php b/src/Message/SetupIntents/RetrieveSetupIntentRequest.php new file mode 100644 index 00000000..ab465bd4 --- /dev/null +++ b/src/Message/SetupIntents/RetrieveSetupIntentRequest.php @@ -0,0 +1,55 @@ + + * + * + * + * @see \Omnipay\Stripe\Message\PaymentIntents\AttachPaymentMethodRequest + * @see \Omnipay\Stripe\Message\PaymentIntents\DetachPaymentMethodRequest + * @see \Omnipay\Stripe\Message\PaymentIntents\UpdatePaymentMethodRequest + * @link https://stripe.com/docs/api/setup_intents/create + */ +class RetrieveSetupIntentRequest extends AbstractRequest +{ + /** + * @inheritdoc + */ + public function getData() + { + $this->validate('setupIntentReference'); + + return []; + } + + /** + * @inheritdoc + */ + public function getEndpoint() + { + return $this->endpoint . '/setup_intents/' . $this->getSetupIntentReference(); + } + + public function getHttpMethod() + { + return 'GET'; + } + + /** + * @inheritdoc + */ + protected function createResponse($data, $headers = []) + { + return $this->response = new Response($this, $data, $headers); + } +} diff --git a/src/Message/UpdateCouponRequest.php b/src/Message/UpdateCouponRequest.php new file mode 100644 index 00000000..b709af15 --- /dev/null +++ b/src/Message/UpdateCouponRequest.php @@ -0,0 +1,76 @@ +getParameter('couponId'); + } + + /** + * Set the coupon + * + * @param $value + * @return UpdateCouponRequest + */ + public function setCouponId($value) + { + return $this->setParameter('couponId', $value); + } + + /** + * @return string + */ + public function getName() + { + return $this->getParameter('name'); + } + + /** + * @param string $value + * + * @return UpdateCouponRequest + */ + public function setName($value) + { + return $this->setParameter('name', $value); + } + + public function getData() + { + $data = array(); + + if (null !== $this->getName()) { + $data['name'] = $this->getName(); + } + + if ($this->getMetadata()) { + $data['metadata'] = $this->getMetadata(); + } + + return $data; + } + + public function getEndpoint() + { + return $this->endpoint.'/coupons/'.$this->getCouponId(); + } + + public function getHttpMethod() + { + return 'POST'; + } +} diff --git a/src/PaymentIntentsGateway.php b/src/PaymentIntentsGateway.php index 88e24571..e6ecea2f 100644 --- a/src/PaymentIntentsGateway.php +++ b/src/PaymentIntentsGateway.php @@ -3,9 +3,8 @@ /** * Stripe Payment Intents Gateway. */ -namespace Omnipay\Stripe; -use Omnipay\Stripe\Message\PaymentIntents\Response; +namespace Omnipay\Stripe; /** * Stripe Payment Intents Gateway. @@ -166,4 +165,26 @@ public function deleteCard(array $parameters = array()) { return $this->createRequest('\Omnipay\Stripe\Message\PaymentIntents\DetachPaymentMethodRequest', $parameters); } + + // Setup Intent + + /** + * @inheritdoc + * + * @return \Omnipay\Stripe\Message\SetupIntents\CreateSetupIntentRequest + */ + public function createSetupIntent(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\SetupIntents\CreateSetupIntentRequest', $parameters); + } + + /** + * @inheritdoc + * + * @return \Omnipay\Stripe\Message\SetupIntents\CreateSetupIntentRequest + */ + public function retrieveSetupIntent(array $parameters = array()) + { + return $this->createRequest('\Omnipay\Stripe\Message\SetupIntents\RetrieveSetupIntentRequest', $parameters); + } } diff --git a/src/StripeItem.php b/src/StripeItem.php index 43253b9b..cb8ee8cb 100644 --- a/src/StripeItem.php +++ b/src/StripeItem.php @@ -14,5 +14,23 @@ */ class StripeItem extends Item { + public function getTaxes() + { + return $this->getParameter('taxes'); + } + public function setTaxes($value) + { + $this->setParameter('taxes', $value); + } + + public function getDiscount() + { + return $this->getParameter('discount'); + } + + public function setDiscount($value) + { + $this->setParameter('discount', $value); + } } diff --git a/tests/Message/AbstractRequestTest.php b/tests/Message/AbstractRequestTest.php index 330aea87..9528e6cf 100644 --- a/tests/Message/AbstractRequestTest.php +++ b/tests/Message/AbstractRequestTest.php @@ -8,6 +8,9 @@ class AbstractRequestTest extends TestCase { + /** @var Mockery\Mock|AbstractRequest */ + private $request; + public function setUp() { $this->request = Mockery::mock('\Omnipay\Stripe\Message\AbstractRequest')->makePartial(); @@ -98,7 +101,6 @@ public function testStripeVersion() $this->assertTrue($httpRequest->hasHeader('Stripe-Version')); } - public function testConnectedStripeAccount() { $this->request->setConnectedStripeAccountHeader('ACCOUNT_ID'); @@ -118,4 +120,14 @@ public function testConnectedStripeAccount() $this->assertTrue($httpRequest->hasHeader('Stripe-Account')); } + + public function testExpandedEndpoint() + { + $this->request->shouldReceive('getEndpoint')->andReturn('https://api.stripe.com/v1'); + $this->request->setExpand(['foo', 'bar']); + + $actual = $this->request->getExpandedEndpoint(); + + $this->assertEquals('https://api.stripe.com/v1?expand[]=foo&expand[]=bar', $actual); + } } diff --git a/tests/Message/AuthorizeRequestTest.php b/tests/Message/AuthorizeRequestTest.php index 9999d244..438e1b03 100644 --- a/tests/Message/AuthorizeRequestTest.php +++ b/tests/Message/AuthorizeRequestTest.php @@ -2,6 +2,7 @@ namespace Omnipay\Stripe\Message; +use Omnipay\Common\CreditCard; use Omnipay\Common\ItemBag; use Omnipay\Tests\TestCase; @@ -41,6 +42,82 @@ public function testGetData() $this->assertSame(100, $data['application_fee']); } + public function testDataWithLevel3() + { + $this->request->setItems([ + [ + 'name' => 'Cupcakes', + 'description' => 'Yummy Cupcakes', + 'price' => 4, + 'quantity' => 2, + 'taxes' => 0.4 + ], + [ + 'name' => 'Donuts', + 'description' => 'A dozen donuts', + 'price' => 1.5, + 'quantity' => 12, + 'discount' => 1.8, + 'taxes' => 0.81 + ] + ]); + $this->request->setTransactionId('ORD42-P1'); + $this->request->setAmount(25.41); + + $data = $this->request->getData(); + + $this->assertSame('Order #42', $data['description']); + $expectedLevel3 = [ + 'merchant_reference' => 'ORD42-P1', + 'line_items' => [ + [ + 'product_code' => 'Cupcakes', + 'product_description' => 'Yummy Cupcakes', + 'unit_cost' => 400, + 'quantity' => 2, + 'tax_amount' => 40, + ], + [ + 'product_code' => 'Donuts', + 'product_description' => 'A dozen donuts', + 'unit_cost' => 150, + 'quantity' => 12, + 'discount_amount' => 180, + 'tax_amount' => 81, + ] + ] + ]; + $this->assertEquals($expectedLevel3, $data['level3']); + } + + public function testDataWithInvalidLevel3() + { + $this->request->setItems([ + [ + 'name' => 'Cupcakes', + 'description' => 'Yummy Cupcakes', + 'price' => 4, + 'quantity' => 2, + 'taxes' => 0.4 + ], + [ + 'name' => 'Donuts', + 'description' => 'A dozen donuts', + 'price' => 1.5, + 'quantity' => 12, + 'discount' => 1.8, + 'taxes' => 0.8 + ] + ]); + $this->request->setTransactionId('ORD42-P1'); + $this->request->setAmount(25.41); + + $data = $this->request->getData(); + + $this->assertArrayNotHasKey('level3', $data, + 'should not include level 3 data if the line items do not add up to the amount'); + } + /** * @expectedException \Omnipay\Common\Exception\InvalidRequestException * @expectedExceptionMessage The source parameter is required @@ -107,6 +184,48 @@ public function testDataWithCard() $this->assertSame($card['number'], $data['source']['number']); } + public function testDataWithTracks() + { + $cardData = $this->getValidCard(); + $tracks = "%25B4242424242424242%5ETESTLAST%2FTESTFIRST%5E1505201425400714000000%3F"; + $cardData['tracks'] = $tracks; + unset($cardData['cvv']); + unset($cardData['billingPostcode']); + $this->request->setCard(new CreditCard($cardData)); + $data = $this->request->getData(); + + $this->assertSame($tracks, $data['source']['swipe_data']); + $this->assertCount(2, $data['source'], "Swipe data should be present. All other fields are not required"); + + // If there is any mismatch between the track data and the parsed data, Stripe rejects the transaction, so it's + // best to suppress fields that is already present in the track data. + $this->assertArrayNotHasKey('number', $data, 'Should not send card number for card present charge'); + $this->assertArrayNotHasKey('exp_month', $data, 'Should not send expiry month for card present charge'); + $this->assertArrayNotHasKey('exp_year', $data, 'Should not send expiry year for card present charge'); + $this->assertArrayNotHasKey('name', $data, 'Should not send name for card present charge'); + + // Billing address is not accepted for card present transactions. + $this->assertArrayNotHasKey('address_line1', $data, 'Should not send billing address for card present charge'); + $this->assertArrayNotHasKey('address_line2', $data, 'Should not send billing address for card present charge'); + $this->assertArrayNotHasKey('address_city', $data, 'Should not send billing address for card present charge'); + $this->assertArrayNotHasKey('address_state', $data, 'Should not send billing address for card present charge'); + + } + + public function testDataWithTracksAndZipCVVManuallyEntered() + { + $cardData = $this->getValidCard(); + $tracks = "%25B4242424242424242%5ETESTLAST%2FTESTFIRST%5E1505201425400714000000%3F"; + $cardData['tracks'] = $tracks; + $this->request->setCard(new CreditCard($cardData)); + $data = $this->request->getData(); + + $this->assertSame($tracks, $data['source']['swipe_data']); + $this->assertSame($cardData['cvv'], $data['source']['cvc']); + $this->assertSame($cardData['billingPostcode'], $data['source']['address_zip']); + $this->assertCount(4, $data['source'], "Swipe data, cvv and zip code should be present"); + } + public function testSendSuccess() { $this->setMockHttpResponse('PurchaseSuccess.txt'); diff --git a/tests/Message/CreateCouponRequestTest.php b/tests/Message/CreateCouponRequestTest.php new file mode 100644 index 00000000..a2f2207e --- /dev/null +++ b/tests/Message/CreateCouponRequestTest.php @@ -0,0 +1,65 @@ +request = new CreateCouponRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setId('50_OFF'); + $this->request->setDuration('repeating'); + $this->request->setCurrency('EUR'); + $this->request->setRedeemBy(1606460031); + $this->request->setPercentOff(50); + $this->request->setDurationInMonths(3); + $this->request->setMaxRedemptions(10); + } + + public function testEndpoint() + { + $this->assertSame('https://api.stripe.com/v1/coupons', $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('CreateCouponSuccess.txt'); + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertSame('50_OFF', $response->getCouponId()); + $this->assertNotNull($response->getCoupon()); + $this->assertNull($response->getMessage()); + } + + /** + * @expectedException \Omnipay\Common\Exception\InvalidRequestException + * @expectedExceptionMessage Either amount_off or percent_off is required + */ + public function testAmountPercentRequired() + { + $this->request->setPercentOff(null); + $this->request->setAmountOff(null); + $this->request->getData(); + } + + + public function testSendError() + { + $this->setMockHttpResponse('CreateCouponFailure.txt'); + $response = $this->request->send(); + $this->assertFalse($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getCoupon()); + $this->assertNull($response->getCouponId()); + $this->assertSame('Coupon already exists.', $response->getMessage()); + } +} diff --git a/tests/Message/CreatePlanRequestTest.php b/tests/Message/CreatePlanRequestTest.php index 45371f00..f07d1bea 100644 --- a/tests/Message/CreatePlanRequestTest.php +++ b/tests/Message/CreatePlanRequestTest.php @@ -18,9 +18,10 @@ public function setUp() $this->request->setAmount('19.00'); $this->request->setCurrency('usd'); $this->request->setInterval('month'); - $this->request->setName('Amazing Gold Plan'); + $this->request->setNickname('Amazing Gold Plan'); + $this->request->setProduct('prod_GWN5y0jpQeU9yj'); $this->request->setIntervalCount(1); - $this->request->setStatementDescriptor('Omnipay Basic Plan'); + $this->request->setActive(false); $this->request->setTrialPeriodDays(3); } @@ -38,6 +39,7 @@ public function testSendSuccess() $this->assertFalse($response->isRedirect()); $this->assertSame('basic', $response->getPlanId()); $this->assertNotNull($response->getPlan()); + $this->assertFalse($response->getPlan()['active']); $this->assertNull($response->getMessage()); } diff --git a/tests/Message/CreateSubscriptionRequestTest.php b/tests/Message/CreateSubscriptionRequestTest.php index 5726c928..199dcc91 100644 --- a/tests/Message/CreateSubscriptionRequestTest.php +++ b/tests/Message/CreateSubscriptionRequestTest.php @@ -13,6 +13,7 @@ public function setUp() { $this->request = new CreateSubscriptionRequest($this->getHttpClient(), $this->getHttpRequest()); $this->request->setCustomerReference('cus_7lqqgOm33t4xSU'); + $this->request->setTrialEnd(1606460031); $this->request->setPlan('basic'); } diff --git a/tests/Message/DeleteCouponRequestTest.php b/tests/Message/DeleteCouponRequestTest.php new file mode 100644 index 00000000..0f0daab8 --- /dev/null +++ b/tests/Message/DeleteCouponRequestTest.php @@ -0,0 +1,41 @@ +request = new DeleteCouponRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setCouponId('50_OFF'); + } + + public function testEndpoint() + { + $this->assertSame('https://api.stripe.com/v1/coupons/50_OFF', $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('DeleteCouponSuccess.txt'); + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getMessage()); + $this->assertTrue($response->getData()['deleted']); + } + + public function testSendFailure() + { + $this->setMockHttpResponse('DeleteCouponFailure.txt'); + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getCouponId()); + $this->assertSame('No such coupon: 30_OFF', $response->getMessage()); + } +} diff --git a/tests/Message/DetachSourceRequestTest.php b/tests/Message/DetachSourceRequestTest.php new file mode 100644 index 00000000..e907698f --- /dev/null +++ b/tests/Message/DetachSourceRequestTest.php @@ -0,0 +1,42 @@ +request = new DetachSourceRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setSource('src_1GyjQZK1civsTrrUGHtiV3AN'); + $this->request->setCustomerReference('cus_HVUs00WcT4j06R'); + } + + public function testEndpoint() + { + $this->assertSame('https://api.stripe.com/v1/customers/cus_HVUs00WcT4j06R/sources/src_1GyjQZK1civsTrrUGHtiV3AN', $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('DetachSourceSuccess.txt'); + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertTrue($response->isRedirect()); + $this->assertNotNull($response->getSource()); + $this->assertNull($response->getMessage()); + } + + public function testSendFailure() + { + $this->setMockHttpResponse('DetachSourceFailure.txt'); + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getSourceId()); + $this->assertSame('No such source: src_1Gyk9dK1civsTrCUNB7v9XoFo', $response->getMessage()); + } +} diff --git a/tests/Message/FetchApplicationFeeTest.php b/tests/Message/FetchApplicationFeeTest.php new file mode 100644 index 00000000..a41e5abf --- /dev/null +++ b/tests/Message/FetchApplicationFeeTest.php @@ -0,0 +1,41 @@ +request = new FetchApplicationFeeRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setApplicationFeeReference('fee_1FITlv123YJsynqe3nOIfake'); + } + + public function testEndpoint() + { + $this->assertSame('https://api.stripe.com/v1/application_fees/fee_1FITlv123YJsynqe3nOIfake', $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('FetchApplicationFeeSuccess.txt'); + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertSame('fee_1FITlv123YJsynqe3nOIfake', $response->getApplicationFeeReference()); + $this->assertNull($response->getMessage()); + } + + public function testSendError() + { + $this->setMockHttpResponse('FetchApplicationFeeFailure.txt'); + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getApplicationFeeReference()); + $this->assertSame('No such application fee: fee_1FITlv123YJsynqe3nOIfake', $response->getMessage()); + } +} diff --git a/tests/Message/FetchCouponRequestTest.php b/tests/Message/FetchCouponRequestTest.php new file mode 100644 index 00000000..79ea7747 --- /dev/null +++ b/tests/Message/FetchCouponRequestTest.php @@ -0,0 +1,42 @@ +request = new FetchCouponRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setCouponId('50_OFF'); + } + + public function testEndpoint() + { + $this->assertSame('https://api.stripe.com/v1/coupons/50_OFF', $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('FetchCouponSuccess.txt'); + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertSame('50_OFF', $response->getCouponId()); + $this->assertNull($response->getMessage()); + } + + public function testSendFailure() + { + $this->setMockHttpResponse('FetchCouponFailure.txt'); + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getCoupon()); + $this->assertNull($response->getCouponId()); + $this->assertSame('No such coupon: 30_OFF', $response->getMessage()); + } +} diff --git a/tests/Message/FetchSourceRequestTest.php b/tests/Message/FetchSourceRequestTest.php new file mode 100644 index 00000000..b21a2798 --- /dev/null +++ b/tests/Message/FetchSourceRequestTest.php @@ -0,0 +1,43 @@ +request = new FetchSourceRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setSource('src_1GyjQZK1civsTrrUGHtiV3AN'); + $this->request->setClientSecret('src_client_secret_kO8U38RMu0NedTxDoTkOJbTc'); + } + + public function testEndpoint() + { + $this->assertSame('https://api.stripe.com/v1/sources/src_1GyjQZK1civsTrrUGHtiV3AN', $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('FetchSourceSuccess.txt'); + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertTrue($response->isRedirect()); + $this->assertSame('src_1GyjQZK1civsTrrUGHtiV3AN', $response->getSourceId()); + $this->assertNull($response->getMessage()); + } + + public function testSendFailure() + { + $this->setMockHttpResponse('FetchSourceFailure.txt'); + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getSource()); + $this->assertNull($response->getSourceId()); + $this->assertSame('No such source: src_1GyjQZK1civsTrrUGHtiV3ANo', $response->getMessage()); + } +} diff --git a/tests/Message/FetchSubscriptionSchedulesRequestTest.php b/tests/Message/FetchSubscriptionSchedulesRequestTest.php new file mode 100644 index 00000000..67d854b3 --- /dev/null +++ b/tests/Message/FetchSubscriptionSchedulesRequestTest.php @@ -0,0 +1,43 @@ +request = new FetchSubscriptionSchedulesRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setSubscriptionSchedulesReference('sub_sched_1GagVZKscivsTrcFhfMufnWP'); + } + + public function testEndpoint() + { + $endpoint = 'https://api.stripe.com/v1/subscription_schedules/sub_sched_1GagVZKscivsTrcFhfMufnWP'; + $this->assertSame($endpoint, $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('FetchSubscriptionSchedulesSuccess.txt'); + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertSame('sub_sched_1GagVZKscivsTrcFhfMufnWP', $response->getSubscriptionSchedulesReference()); + $this->assertNull($response->getMessage()); + } + + public function testSendFailure() + { + $this->setMockHttpResponse('FetchSubscriptionSchedulesFailure.txt'); + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getSubscriptionReference()); + $message = 'No such subscription schedule: sub_sched_1GagVZKscivsTrcFhfMufnWP'; + $this->assertSame($message, $response->getMessage()); + } +} diff --git a/tests/Message/ListCouponsTest.php b/tests/Message/ListCouponsTest.php new file mode 100644 index 00000000..d1d51800 --- /dev/null +++ b/tests/Message/ListCouponsTest.php @@ -0,0 +1,42 @@ +request = new ListCouponsRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setLimit(2); + } + + public function testEndpoint() + { + $this->assertSame('https://api.stripe.com/v1/coupons', $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('ListCouponsSuccess.txt'); + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNotNull($response->getList()); + $this->assertNull($response->getMessage()); + } + + /** + * According to documentation: https://stripe.com/docs/api/coupons/list + * This request should never throw an error. + */ + public function testSendFailure() + { + $this->assertTrue(true); + } +} diff --git a/tests/Message/PaymentIntents/AuthorizeRequestTest.php b/tests/Message/PaymentIntents/AuthorizeRequestTest.php index 9e3b8858..28344ad5 100644 --- a/tests/Message/PaymentIntents/AuthorizeRequestTest.php +++ b/tests/Message/PaymentIntents/AuthorizeRequestTest.php @@ -25,6 +25,8 @@ public function setUp() ), 'applicationFee' => '1.00', 'returnUrl' => 'complete-payment', + 'setup_future_usage' => 'off_session', + 'off_session' => false, 'confirm' => true, ) ); @@ -41,7 +43,9 @@ public function testGetData() $this->assertSame('manual', $data['confirmation_method']); $this->assertSame('pm_valid_payment_method', $data['payment_method']); $this->assertSame(array('foo' => 'bar'), $data['metadata']); - $this->assertSame(100, $data['application_fee']); + $this->assertSame(100, $data['application_fee_amount']); + $this->assertSame('off_session', $data['setup_future_usage']); + $this->assertSame('false', $data['off_session']); } /** diff --git a/tests/Message/PaymentIntents/PurchaseRequestTest.php b/tests/Message/PaymentIntents/PurchaseRequestTest.php index 09af7fae..2f0dda5d 100644 --- a/tests/Message/PaymentIntents/PurchaseRequestTest.php +++ b/tests/Message/PaymentIntents/PurchaseRequestTest.php @@ -39,7 +39,7 @@ public function testGetData() $this->assertSame('manual', $data['confirmation_method']); $this->assertSame('pm_valid_payment_method', $data['payment_method']); $this->assertSame(array('foo' => 'bar'), $data['metadata']); - $this->assertSame(100, $data['application_fee']); + $this->assertSame(100, $data['application_fee_amount']); } public function testSendSuccessAndRequireConfirmation() diff --git a/tests/Message/UpdateCouponRequestTest.php b/tests/Message/UpdateCouponRequestTest.php new file mode 100644 index 00000000..9752df6d --- /dev/null +++ b/tests/Message/UpdateCouponRequestTest.php @@ -0,0 +1,53 @@ +request = new UpdateCouponRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->setCouponId('50_OFF'); + $this->request->setName('50% Discount'); + } + + public function testEndpoint() + { + $endpoint = 'https://api.stripe.com/v1/coupons/50_OFF'; + $this->assertSame($endpoint, $this->request->getEndpoint()); + } + + public function testSendSuccess() + { + $this->setMockHttpResponse('UpdateCouponSuccess.txt'); + /** @var Response */ + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertSame('50_OFF', $response->getCouponId()); + $this->assertNotNull($response->getCoupon()); + $this->assertNull($response->getMessage()); + } + + + public function testSendError() + { + $this->setMockHttpResponse('UpdateCouponFailure.txt'); + + /** @var Response */ + $response = $this->request->send(); + $this->assertFalse($response->isSuccessful()); + $this->assertFalse($response->isRedirect()); + $this->assertNull($response->getCouponId()); + $this->assertNull($response->getCoupon()); + $this->assertSame('No such coupon: 50_OFF', $response->getMessage()); + } +} diff --git a/tests/Mock/CreateCouponFailure.txt b/tests/Mock/CreateCouponFailure.txt new file mode 100644 index 00000000..7dbb55e3 --- /dev/null +++ b/tests/Mock/CreateCouponFailure.txt @@ -0,0 +1,17 @@ +HTTP/1.1 400 Bad Request +Server: nginx +Date: Fri, 11 Feb 2016 19:23:31 GMT +Content-Type: application/json +Content-Length: 96 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "error": { + "code": "resource_already_exists", + "doc_url": "https://stripe.com/docs/error-codes/resource-already-exists", + "message": "Coupon already exists.", + "type": "invalid_request_error" + } +} diff --git a/tests/Mock/CreateCouponSuccess.txt b/tests/Mock/CreateCouponSuccess.txt new file mode 100644 index 00000000..93e01feb --- /dev/null +++ b/tests/Mock/CreateCouponSuccess.txt @@ -0,0 +1,26 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 10:05:26 GMT +Content-Type: application/json +Content-Length: 281 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "id": "50_OFF", + "object": "coupon", + "amount_off": null, + "created": 1593245873, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": false, + "max_redemptions": 10, + "metadata": {}, + "name": "50% off", + "percent_off": 50.0, + "redeem_by": 1606460031, + "times_redeemed": 0, + "valid": true +} diff --git a/tests/Mock/CreatePlanSuccess.txt b/tests/Mock/CreatePlanSuccess.txt index ea4df1db..431682f7 100644 --- a/tests/Mock/CreatePlanSuccess.txt +++ b/tests/Mock/CreatePlanSuccess.txt @@ -10,14 +10,22 @@ Cache-Control: no-cache, no-store { "id": "basic", "object": "plan", + "active": false, + "aggregate_usage": null, "amount": 1900, "created": 1455308594, "currency": "usd", + "amount_decimal": "2000", + "billing_scheme": "per_unit", "interval": "month", "interval_count": 1, "livemode": false, "metadata": {}, - "name": "Amazing Gold Plan", - "statement_descriptor": null, - "trial_period_days": 3 + "nickname": "Amazing Gold Plan", + "product": "prod_GWN5y0jpQeU9yj", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" } diff --git a/tests/Mock/CreateSubscriptionSuccess.txt b/tests/Mock/CreateSubscriptionSuccess.txt index 7b9109ed..9c288128 100644 --- a/tests/Mock/CreateSubscriptionSuccess.txt +++ b/tests/Mock/CreateSubscriptionSuccess.txt @@ -36,6 +36,6 @@ Cache-Control: no-cache, no-store "start": 1453672798, "status": "active", "tax_percent": null, - "trial_end": null, - "trial_start": null -} \ No newline at end of file + "trial_end": 1606460031, + "trial_start": 1593241598 +} diff --git a/tests/Mock/DeleteCouponFailure.txt b/tests/Mock/DeleteCouponFailure.txt new file mode 100644 index 00000000..d89e0360 --- /dev/null +++ b/tests/Mock/DeleteCouponFailure.txt @@ -0,0 +1,18 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 10:05:26 GMT +Content-Type: application/json +Content-Length: 281 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "error": { + "code": "resource_missing", + "doc_url": "https://stripe.com/docs/error-codes/resource-missing", + "message": "No such coupon: 30_OFF", + "param": "coupon", + "type": "invalid_request_error" + } +} diff --git a/tests/Mock/DeleteCouponSuccess.txt b/tests/Mock/DeleteCouponSuccess.txt new file mode 100644 index 00000000..d6e902e5 --- /dev/null +++ b/tests/Mock/DeleteCouponSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 10:05:26 GMT +Content-Type: application/json +Content-Length: 281 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "id": "50_OFF", + "object": "coupon", + "deleted": true +} diff --git a/tests/Mock/DetachSourceFailure.txt b/tests/Mock/DetachSourceFailure.txt new file mode 100644 index 00000000..d270ceeb --- /dev/null +++ b/tests/Mock/DetachSourceFailure.txt @@ -0,0 +1,20 @@ +HTTP/1.1 404 Not Found +Server: nginx +Date: Tue, 26 Feb 2013 16:32:51 GMT +Content-Type: application/json;charset=utf-8 +Content-Length: 131 +Connection: keep-alive +Access-Control-Max-Age: 300 +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + + +{ + "error": { + "code": "resource_missing", + "doc_url": "https://stripe.com/docs/error-codes/resource-missing", + "message": "No such source: src_1Gyk9dK1civsTrCUNB7v9XoFo", + "param": "id", + "type": "invalid_request_error" + } +} diff --git a/tests/Mock/DetachSourceSuccess.txt b/tests/Mock/DetachSourceSuccess.txt new file mode 100644 index 00000000..6c2d85e8 --- /dev/null +++ b/tests/Mock/DetachSourceSuccess.txt @@ -0,0 +1,51 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 21:12:02 GMT +Content-Type: application/json +Content-Length: 943 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "id": "src_1Gyk9dK1civsTrCUNB7v9XoF", + "object": "source", + "amount": null, + "card": { + "exp_month": 6, + "exp_year": 2021, + "last4": "4242", + "country": "US", + "brand": "Visa", + "funding": "credit", + "fingerprint": "f1JoQaLEG7ovd7N4", + "three_d_secure": "optional", + "name": null, + "address_line1_check": null, + "address_zip_check": null, + "cvc_check": null, + "tokenization_method": null, + "dynamic_last4": null + }, + "client_secret": "src_client_secret_ojSdoIOHML61Ar89cb2sXyuo", + "created": 1593287857, + "currency": null, + "flow": "none", + "livemode": false, + "metadata": { + }, + "owner": { + "address": null, + "email": null, + "name": null, + "phone": null, + "verified_address": null, + "verified_email": null, + "verified_name": null, + "verified_phone": null + }, + "statement_descriptor": null, + "status": "consumed", + "type": "card", + "usage": "reusable" +} diff --git a/tests/Mock/FetchApplicationFeeFailure.txt b/tests/Mock/FetchApplicationFeeFailure.txt new file mode 100644 index 00000000..bc5f04f0 --- /dev/null +++ b/tests/Mock/FetchApplicationFeeFailure.txt @@ -0,0 +1,17 @@ +HTTP/1.1 404 Not Found +Server: nginx +Date: Wed, 24 Jul 2013 13:40:31 GMT +Content-Type: application/json;charset=utf-8 +Content-Length: 132 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Access-Control-Max-Age: 300 +Cache-Control: no-cache, no-store + +{ + "error": { + "type": "invalid_request_error", + "message": "No such application fee: fee_1FITlv123YJsynqe3nOIfake", + "param": "id" + } +} diff --git a/tests/Mock/FetchApplicationFeeSuccess.txt b/tests/Mock/FetchApplicationFeeSuccess.txt new file mode 100644 index 00000000..d66dbafe --- /dev/null +++ b/tests/Mock/FetchApplicationFeeSuccess.txt @@ -0,0 +1,32 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Wed, 24 Jul 2013 07:14:02 GMT +Content-Type: application/json;charset=utf-8 +Content-Length: 1092 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Access-Control-Max-Age: 300 +Cache-Control: no-cache, no-store + +{ + "id": "fee_1FITlv123YJsynqe3nOIfake", + "object": "application_fee", + "account": "acct_14901h0a0fh01293", + "amount": 100, + "amount_refunded": 0, + "application": "ca_Fo5xaLt123SEtSKHui0SZOgAiuVwfake", + "balance_transaction": "txn_1FH8W123vYJsynqeQKMWfake", + "charge": "ch_1FIT123rvYJsynqeQpJOFfake", + "created": 1568438771, + "currency": "usd", + "livemode": false, + "originating_transaction": null, + "refunded": false, + "refunds": { + "object": "list", + "data": [], + "has_more": false, + "total_count": 0, + "url": "/v1/application_fees/fee_1FITlvArvYJsynqe3nOIfake/refunds" + } +} \ No newline at end of file diff --git a/tests/Mock/FetchCouponFailure.txt b/tests/Mock/FetchCouponFailure.txt new file mode 100644 index 00000000..d89e0360 --- /dev/null +++ b/tests/Mock/FetchCouponFailure.txt @@ -0,0 +1,18 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 10:05:26 GMT +Content-Type: application/json +Content-Length: 281 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "error": { + "code": "resource_missing", + "doc_url": "https://stripe.com/docs/error-codes/resource-missing", + "message": "No such coupon: 30_OFF", + "param": "coupon", + "type": "invalid_request_error" + } +} diff --git a/tests/Mock/FetchCouponSuccess.txt b/tests/Mock/FetchCouponSuccess.txt new file mode 100644 index 00000000..93e01feb --- /dev/null +++ b/tests/Mock/FetchCouponSuccess.txt @@ -0,0 +1,26 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 10:05:26 GMT +Content-Type: application/json +Content-Length: 281 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "id": "50_OFF", + "object": "coupon", + "amount_off": null, + "created": 1593245873, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": false, + "max_redemptions": 10, + "metadata": {}, + "name": "50% off", + "percent_off": 50.0, + "redeem_by": 1606460031, + "times_redeemed": 0, + "valid": true +} diff --git a/tests/Mock/FetchSourceFailure.txt b/tests/Mock/FetchSourceFailure.txt new file mode 100644 index 00000000..5371c0fd --- /dev/null +++ b/tests/Mock/FetchSourceFailure.txt @@ -0,0 +1,19 @@ +HTTP/1.1 404 Not Found +Server: nginx +Date: Sat, 27 Jun 2020 21:12:02 GMT +Content-Type: application/json +Content-Length: 241 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Access-Control-Max-Age: 300 +Cache-Control: no-cache, no-store + +{ + "error": { + "code": "resource_missing", + "doc_url": "https://stripe.com/docs/error-codes/resource-missing", + "message": "No such source: src_1GyjQZK1civsTrrUGHtiV3ANo", + "param": "", + "type": "invalid_request_error" + } +} diff --git a/tests/Mock/FetchSourceSuccess.txt b/tests/Mock/FetchSourceSuccess.txt new file mode 100644 index 00000000..e9fd4a1d --- /dev/null +++ b/tests/Mock/FetchSourceSuccess.txt @@ -0,0 +1,50 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 21:12:02 GMT +Content-Type: application/json +Content-Length: 943 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "id":"src_1GyjQZK1civsTrrUGHtiV3AN", + "object":"source", + "amount":null, + "card":{ + "exp_month":6, + "exp_year":2021, + "last4":"4242", + "country":"US", + "brand":"Visa", + "funding":"credit", + "fingerprint":"f1JoQaLEG7ovd7N4", + "three_d_secure":"optional", + "name":null, + "address_line1_check":null, + "address_zip_check":null, + "cvc_check":null, + "tokenization_method":null, + "dynamic_last4":null + }, + "client_secret":"src_client_secret_kO8e38RMu0NedTxDoTkOJbTc", + "created":1593285063, + "currency":null, + "flow":"none", + "livemode":false, + "metadata":{}, + "owner":{ + "address":null, + "email":null, + "name":null, + "phone":null, + "verified_address":null, + "verified_email":null, + "verified_name":null, + "verified_phone":null + }, + "statement_descriptor":null, + "status":"chargeable", + "type":"card", + "usage":"reusable" +} diff --git a/tests/Mock/FetchSubscriptionSchedulesFailure.txt b/tests/Mock/FetchSubscriptionSchedulesFailure.txt new file mode 100644 index 00000000..3a0ef437 --- /dev/null +++ b/tests/Mock/FetchSubscriptionSchedulesFailure.txt @@ -0,0 +1,17 @@ +HTTP/1.1 404 Not Found +Server: nginx +Date: Mon, 26 Jun 2020 13:41:33 GMT +Content-Type: application/json +Content-Length: 188 +Connection: keep-alive +Cache-Control: no-cache, no-store + +{ + "error": { + "code": "resource_missing", + "doc_url": "https://stripe.com/docs/error-codes/resource-missing", + "message": "No such subscription schedule: sub_sched_1GagVZKscivsTrcFhfMufnWP", + "param": "id", + "type": "invalid_request_error" + } +} diff --git a/tests/Mock/FetchSubscriptionSchedulesSuccess.txt b/tests/Mock/FetchSubscriptionSchedulesSuccess.txt new file mode 100644 index 00000000..4ad1fc4f --- /dev/null +++ b/tests/Mock/FetchSubscriptionSchedulesSuccess.txt @@ -0,0 +1,68 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Mon, 26 Jun 2020 13:41:33 GMT +Content-Type: application/json +Content-Length: 784 +Connection: keep-alive +Cache-Control: no-cache, no-store + +{ + "id": "sub_sched_1GagVZKscivsTrcFhfMufnWP", + "object": "subscription_schedule", + "canceled_at": null, + "completed_at": null, + "created": 1593158960, + "current_phase": null, + "customer": "cus_7lqqgOm33t4xSU", + "default_settings": { + "billing_thresholds": null, + "collection_method": "charge_automatically", + "default_payment_method": null, + "default_source": null, + "invoice_settings": null, + "transfer_data": null + }, + "end_behavior": "release", + "livemode": false, + "metadata": { + }, + "phases": [ + { + "add_invoice_items": [ + + ], + "application_fee_percent": null, + "billing_thresholds": null, + "collection_method": null, + "coupon": null, + "default_payment_method": null, + "default_tax_rates": [ + + ], + "end_date": 1596960367, + "invoice_settings": null, + "plans": [ + { + "billing_thresholds": null, + "plan": "plan_GXzqnSohdy458I", + "price": "plan_GXzqnSohdy458I", + "quantity": 1, + "tax_rates": [ + + ] + } + ], + "prorate": true, + "proration_behavior": "create_prorations", + "start_date": 1595750767, + "tax_percent": null, + "transfer_data": null, + "trial_end": null + } + ], + "released_at": null, + "released_subscription": null, + "renewal_interval": null, + "status": "not_started", + "subscription": null +} diff --git a/tests/Mock/ListCouponsSuccess.txt b/tests/Mock/ListCouponsSuccess.txt new file mode 100644 index 00000000..0eba7094 --- /dev/null +++ b/tests/Mock/ListCouponsSuccess.txt @@ -0,0 +1,50 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 18:28:24 GMT +Content-Type: application/json +Content-Length: 6247 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "object": "list", + "data": [ + { + "id": "50_OFF", + "object": "coupon", + "amount_off": null, + "created": 1593259732, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": false, + "max_redemptions": 10, + "metadata": {}, + "name": "50% foo", + "percent_off": 50.0, + "redeem_by": 1606460031, + "times_redeemed": 0, + "valid": true + }, + { + "id": "50_OFF_2", + "object": "coupon", + "amount_off": null, + "created": 1593245806, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": false, + "max_redemptions": 10, + "metadata": {}, + "name": "50% off", + "percent_off": 50.0, + "redeem_by": 1606460031, + "times_redeemed": 0, + "valid": true + } + ], + "has_more": true, + "url": "/v1/coupons" +} diff --git a/tests/Mock/UpdateCouponFailure.txt b/tests/Mock/UpdateCouponFailure.txt new file mode 100644 index 00000000..08d02d4f --- /dev/null +++ b/tests/Mock/UpdateCouponFailure.txt @@ -0,0 +1,18 @@ +HTTP/1.1 400 Bad Request +Server: nginx +Date: Fri, 11 Feb 2016 19:23:31 GMT +Content-Type: application/json +Content-Length: 96 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "error": { + "code": "resource_missing", + "doc_url": "https://stripe.com/docs/error-codes/resource-missing", + "message": "No such coupon: 50_OFF", + "param": "coupon", + "type": "invalid_request_error" + } +} diff --git a/tests/Mock/UpdateCouponSuccess.txt b/tests/Mock/UpdateCouponSuccess.txt new file mode 100644 index 00000000..c90a3da8 --- /dev/null +++ b/tests/Mock/UpdateCouponSuccess.txt @@ -0,0 +1,26 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Sat, 27 Jun 2020 10:05:26 GMT +Content-Type: application/json +Content-Length: 281 +Connection: keep-alive +Access-Control-Allow-Credentials: true +Cache-Control: no-cache, no-store + +{ + "id": "50_OFF", + "object": "coupon", + "amount_off": null, + "created": 1593259732, + "currency": null, + "duration": "repeating", + "duration_in_months": 3, + "livemode": false, + "max_redemptions": 10, + "metadata": {}, + "name": "50% Discount", + "percent_off": 50.0, + "redeem_by": 1606460031, + "times_redeemed": 0, + "valid": true +}