* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * @copyright PayPal */ namespace PaypalAddons\classes\API\Request\V_1; use Address; use Cart; use Context; use Country; use Module; use PayPal; use PayPal\Api\Amount; use PayPal\Api\Details; use PayPal\Api\Item; use PayPal\Api\ItemList; use PayPal\Api\Payer; use PayPal\Api\PayerInfo; use PayPal\Api\Payment; use PayPal\Api\RedirectUrls; use PayPal\Api\ShippingAddress; use PayPal\Api\Transaction; use PaypalAddons\classes\API\Response\Error; use PaypalAddons\classes\API\Response\ResponseOrderCreate; use State; use Tools; class PaypalOrderCreateRequest extends RequestAbstractMB { /** @var Amount */ protected $_amount; /** @var ItemList */ protected $_itemList; /** @var Item[] */ protected $_items; /** @var float */ protected $_itemTotalValue; /** @var float */ protected $_taxTotalValue; /** * @return ResponseOrderCreate */ public function execute() { $response = new ResponseOrderCreate(); if ($this->method->isConfigured() == false) { $error = new Error(); $error->setMessage('Module is not configured'); return $response->setSuccess(false)->setError($error); } $payer = new Payer(); $payer->setPaymentMethod('paypal'); $payer->setPayerInfo($this->getPayerInfo()); // ### Itemized information // (Optional) Lets you specify item wise information $this->_itemList = new ItemList(); $this->_amount = new Amount(); $this->_getPaymentDetails(); if (Context::getContext()->cart->isVirtualCart() === false) { $this->_itemList->setShippingAddress($this->getPayerShippingAddress()); } // ### Transaction // A transaction defines the contract of a // payment - what is the payment for and who // is fulfilling it. $transaction = new Transaction(); $transaction->setAmount($this->_amount) ->setItemList($this->_itemList) ->setDescription('Payment description') ->setInvoiceNumber(uniqid()); if (is_callable([get_class($this->method), 'getIpnUrl'], true)) { $transaction->setNotifyUrl($this->method->getIpnUrl()); } // ### Redirect urls // Set the urls that the buyer must be redirected to after // payment approval/ cancellation. $redirectUrls = new RedirectUrls(); $redirectUrls ->setReturnUrl($this->method->getReturnUrl()) ->setCancelUrl($this->method->getCancelUrl()); // ### Payment // A Payment Resource; create one using // the above types and intent set to 'sale' $payment = new Payment(); $payment->setIntent('sale') ->setPayer($payer) ->setRedirectUrls($redirectUrls) ->setTransactions([$transaction]); // Set application_context $payment->application_context = $this->getApplicationContext(); // ### Create Payment // Create a payment by calling the 'create' method // passing it a valid apiContext. // The return object contains the state and the // url to which the buyer must be redirected to // for payment approval try { $payment->create($this->getApiContext()); } catch (\Exception $e) { $error = new Error(); $error ->setErrorCode($e->getCode()) ->setMessage($e->getMessage()); return $response->setError($error)->setSuccess(false); } return $response ->setApproveLink($payment->getApprovalLink()) ->setPaymentId($payment->getId()) ->setSuccess(true); } protected function getApplicationContext() { if (Context::getContext()->cart->isVirtualCart()) { $applicationContext = [ 'shipping_preference' => 'NO_SHIPPING', ]; } else { $applicationContext = [ 'shipping_preference' => 'SET_PROVIDED_ADDRESS', ]; } return $applicationContext; } /** * @return PayerInfo */ protected function getPayerInfo() { $customer = Context::getContext()->customer; $addressCustomer = new Address(Context::getContext()->cart->id_address_delivery); $countryCustomer = new Country($addressCustomer->id_country); $payerInfo = new PayerInfo(); $payerInfo->setEmail($customer->email); $payerInfo->setFirstName($this->formatter->formatPaypalString($customer->firstname)); $payerInfo->setLastName($this->formatter->formatPaypalString($customer->lastname)); if ($countryCustomer->iso_code == 'BR') { $payerTaxId = str_replace(['.', '-', '/'], '', $addressCustomer->vat_number); $payerInfo->setTaxId($payerTaxId); $payerInfo->setTaxIdType($this->method->getTaxIdType($payerTaxId)); } return $payerInfo; } /** * @return ShippingAddress */ protected function getPayerShippingAddress() { $addressCustomer = new Address(Context::getContext()->cart->id_address_delivery); $payerShippingAddress = new ShippingAddress(); $payerShippingAddress->setCountryCode(Tools::strtoupper(Country::getIsoById($addressCustomer->id_country))); $payerShippingAddress->setCity($this->formatter->formatPaypalString($addressCustomer->city)); $payerShippingAddress->setLine1($this->formatter->formatPaypalString($addressCustomer->address1)); $payerShippingAddress->setPostalCode($addressCustomer->postcode); $payerShippingAddress->setRecipientName($this->formatter->formatPaypalString(implode(' ', [$addressCustomer->firstname, $addressCustomer->lastname]))); if ((int) $addressCustomer->id_state) { $state = new State($addressCustomer->id_state); $payerShippingAddress->setState($this->formatter->formatPaypalString(Tools::strtoupper($state->iso_code))); } return $payerShippingAddress; } protected function _getPaymentDetails() { $paypal = Module::getInstanceByName($this->method->name); $currency = $paypal->getPaymentCurrencyIso(); $this->_getProductsList($currency); $this->_getDiscountsList($currency); $this->_getGiftWrapping($currency); $this->_getHandling($currency); $this->_getPaymentValues($currency); } protected function _getProductsList($currency) { $products = Context::getContext()->cart->getProducts(); foreach ($products as $product) { $product['product_tax'] = $this->method->formatPrice($this->method->formatPrice($product['price_wt']) - $this->method->formatPrice($product['price'])); $item = new Item(); $item->setName($this->formatter->formatPaypalString($product['name'])) ->setCurrency($currency) ->setDescription(isset($product['attributes']) ? $product['attributes'] : '') ->setQuantity($product['quantity']) ->setSku($product['id_product']) // Similar to `item_number` in Classic API ->setPrice($this->method->formatPrice($product['price'])); $this->_items[] = $item; $this->_itemTotalValue += $this->method->formatPrice($product['price']) * $product['quantity']; $this->_taxTotalValue += $this->method->formatPrice($product['product_tax'] * $product['quantity']); } } protected function _getDiscountsList($currency) { $totalDiscounts = Context::getContext()->cart->getOrderTotal(true, Cart::ONLY_DISCOUNTS); if ($totalDiscounts > 0) { $module = Module::getInstanceByName($this->method->name); $discountItem = new Item(); $discountItem->setName($module->l('Total discounts', get_class($this))) ->setCurrency($currency) ->setQuantity(1) ->setSku('discounts') ->setPrice(-1 * $totalDiscounts); $this->_items[] = $discountItem; $this->_itemTotalValue += (-1 * $totalDiscounts); } } protected function _getHandling($currency) { $discounts = Context::getContext()->cart->getCartRules(); if (empty($discounts)) { return; } $module = Module::getInstanceByName($this->method->name); foreach ($discounts as $discount) { if ($discount['value_real'] < 0) { $handlingValue = abs($this->method->formatPrice($discount['value_real'])); $handlingItem = new Item(); $handlingItem->setName($module->l('Handling', get_class($this))) ->setCurrency($currency) ->setQuantity(1) ->setSku('handling') ->setPrice($handlingValue); $this->_items[] = $handlingItem; $this->_itemTotalValue += $handlingValue; } } } protected function _getGiftWrapping($currency) { $wrapping_price = Context::getContext()->cart->gift ? Context::getContext()->cart->getGiftWrappingPrice() : 0; if ($wrapping_price > 0) { $wrapping_price = $this->method->formatPrice($wrapping_price); $item = new Item(); $item->setName('Gift wrapping') ->setCurrency($currency) ->setQuantity(1) ->setSku('wrapping') // Similar to `item_number` in Classic API ->setPrice($wrapping_price); $this->_items[] = $item; $this->_itemTotalValue += $wrapping_price; } } private function _getPaymentValues($currency) { $this->_itemList->setItems($this->_items); $context = Context::getContext(); $cart = $context->cart; $shipping_cost_wt = $cart->getTotalShippingCost(); $shipping = $this->method->formatPrice($shipping_cost_wt); $total = $this->method->formatPrice($cart->getOrderTotal(true, Cart::BOTH)); $summary = $cart->getSummaryDetails(); $subtotal = $this->method->formatPrice($summary['total_products']); $total_tax = number_format($this->_taxTotalValue, Paypal::getDecimal(), '.', ''); // total shipping amount $shippingTotal = $shipping; if ($subtotal != $this->_itemTotalValue) { $subtotal = $this->_itemTotalValue; } //total $total_cart = $shippingTotal + $this->_itemTotalValue + $this->_taxTotalValue; if ($total != $total_cart) { $total = $total_cart; } // ### Additional payment details // Use this optional field to set additional // payment information such as tax, shipping // charges etc. $details = new Details(); $details->setShipping($shippingTotal) ->setTax($total_tax) ->setSubtotal($subtotal); // ### Amount // Lets you specify a payment amount. // You can also specify additional details // such as shipping, tax. $this->_amount->setCurrency($currency) ->setTotal($total) ->setDetails($details); } }