* @copyright PayPal * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) */ namespace PaypalAddons\classes\API\Request\V_1; use Cart; use Configuration; use Context; use \Address; use \Customer; use \Country; use Module; use PayPal; use PayPal\Api\RedirectUrls; use PaypalAddons\classes\API\Response\Error; use PaypalAddons\classes\API\Response\ResponseOrderCreate; use PayPal\Api\Payer; use PayPal\Api\Payment; use PayPal\Api\ItemList; use PayPal\Api\Item; use PayPal\Api\Amount; use PayPal\Api\Transaction; use PayPal\Api\PayerInfo; use PayPal\Api\ShippingAddress; use PayPal\Api\Details; 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(array(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(array($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($customer->firstname); $payerInfo->setLastName($customer->lastname); if ($countryCustomer->iso_code == 'BR') { $payerTaxId = str_replace(array('.', '-', '/'), '', $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($addressCustomer->city); $payerShippingAddress->setLine1($addressCustomer->address1); $payerShippingAddress->setPostalCode($addressCustomer->postcode); $payerShippingAddress->setRecipientName(implode(" ", array($addressCustomer->firstname, $addressCustomer->lastname))); if ((int)$addressCustomer->id_state) { $state = new State($addressCustomer->id_state); $payerShippingAddress->setState(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->_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(Tools::substr($product['name'], 0, 126)) ->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 _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); } }