From b19af913b2be91746b6d2995ca1ef79a730daddb Mon Sep 17 00:00:00 2001 From: leonardo albuquerque Date: Thu, 19 Jul 2018 10:23:18 -0300 Subject: [PATCH 01/37] =?UTF-8?q?#11177=20Iniciado=20cria=C3=A7=C3=A3o=20d?= =?UTF-8?q?o=20meio=20de=20pagamento=20por=20cart=C3=A3o=20de=20cr=C3=A9di?= =?UTF-8?q?to?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 - .../Vindi/Payment/Controller/Index/Index.php | 25 + app/code/Vindi/Payment/Model/Api.php | 706 ++++++++++++++++++ .../Payment/Model/Payment/CreditCard.php | 325 ++++++++ .../Vindi/Payment/Model/Payment/Vindi.php | 322 ++++++++ .../Vindi/Payment/etc/adminhtml/system.xml | 56 ++ app/code/Vindi/Payment/etc/config.xml | 16 + .../Vindi/Payment/etc/frontend/routes.xml | 8 + app/code/Vindi/Payment/etc/module.xml | 5 + app/code/Vindi/Payment/etc/payment.xml | 14 + app/code/Vindi/Payment/registration.php | 6 + .../frontend/layout/checkout_index_index.xml | 46 ++ .../payment/method-renderer/vindi-method.js | 16 + .../frontend/web/js/view/payment/vindi.js | 19 + .../web/template/payment/cc-form.html | 107 +++ .../frontend/web/template/payment/vindi.html | 50 ++ 16 files changed, 1721 insertions(+), 1 deletion(-) delete mode 100644 README.md create mode 100644 app/code/Vindi/Payment/Controller/Index/Index.php create mode 100644 app/code/Vindi/Payment/Model/Api.php create mode 100644 app/code/Vindi/Payment/Model/Payment/CreditCard.php create mode 100644 app/code/Vindi/Payment/Model/Payment/Vindi.php create mode 100644 app/code/Vindi/Payment/etc/adminhtml/system.xml create mode 100644 app/code/Vindi/Payment/etc/config.xml create mode 100644 app/code/Vindi/Payment/etc/frontend/routes.xml create mode 100644 app/code/Vindi/Payment/etc/module.xml create mode 100644 app/code/Vindi/Payment/etc/payment.xml create mode 100644 app/code/Vindi/Payment/registration.php create mode 100644 app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml create mode 100644 app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js create mode 100644 app/code/Vindi/Payment/view/frontend/web/js/view/payment/vindi.js create mode 100644 app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html create mode 100644 app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html diff --git a/README.md b/README.md deleted file mode 100644 index 83f0885e..00000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# vindi-magento2 diff --git a/app/code/Vindi/Payment/Controller/Index/Index.php b/app/code/Vindi/Payment/Controller/Index/Index.php new file mode 100644 index 00000000..f59a2c10 --- /dev/null +++ b/app/code/Vindi/Payment/Controller/Index/Index.php @@ -0,0 +1,25 @@ +_pageFactory = $pageFactory; + $this->api = $api; + return parent::__construct($context); + } + + public function execute() + { + return $this->_pageFactory->create(); + } +} \ No newline at end of file diff --git a/app/code/Vindi/Payment/Model/Api.php b/app/code/Vindi/Payment/Model/Api.php new file mode 100644 index 00000000..7b36957b --- /dev/null +++ b/app/code/Vindi/Payment/Model/Api.php @@ -0,0 +1,706 @@ +scopeConfig = $scopeConfig; + $this->logger = $logger; + $this->cacheType = $cacheType; + $this->message = $message; + + $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; + $isSandBox = $this->scopeConfig->getValue('payment/vindi/sandboxmode', $storeScope); + + if ($isSandBox) { + $this->base_path = 'https://sandbox-app.vindi.com.br/api/v1/'; + } else { + $this->base_path = 'https://app.vindi.com.br/api/v1/'; + } + + $moduleInfo = $moduleList->getOne('Vindi_Payment'); + $this->version = $moduleInfo['setup_version']; + $this->key = $this->scopeConfig->getValue('payment/vindi/key', $storeScope); + } + + + public function execute(Observer $observer) + { + $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; + $notifyEmail = $this->scopeConfig->getValue(self::BASEPATH, $storeScope); + + echo $notifyEmail; + } + + /** + * @param string $message + * @param int|null $level + */ + private function log($message) + { + $this->logger->warning($message); + } + + /** + * @return \Zend_Cache_Core + */ + private function cache() + { + return $this->cacheType; + } + + /** + * Build HTTP Query. + * + * @param array $data + * + * @return string + */ + private function buildBody($data) + { + $body = null; + if (!empty($data)) { + $body = json_encode($data); + } + return $body; + } + + /** + * @param array $error + * @param $endpoint + * + * @return string + */ + private function getErrorMessage($error, $endpoint) + { + return "Erro em $endpoint: {$error['id']}: {$error['parameter']} - {$error['message']}"; + } + + /** + * @param array $response + * @param $endpoint + * + * @return bool + */ + private function checkResponse($response, $endpoint) + { + if (isset($response['errors']) && !empty($response['errors'])) { + foreach ($response['errors'] as $error) { + $message = $this->getErrorMessage($error, $endpoint); + $this->message->addErrorMessage($message); + $this->lastError = $message; + } + return false; + } + $this->lastError = ''; + return true; + } + + /** + * Perform request to API. + * + * @param string $endpoint + * @param string $method + * @param array $data + * @param null $dataToLog + * + * @return array|bool|mixed + */ + private function request($endpoint, $method = 'POST', $data = [], $dataToLog = null) + { + if (!$this->key) { + return false; + } + $url = $this->base_path . $endpoint; + $body = $this->buildBody($data); + $requestId = rand(); + $dataToLog = null !== $dataToLog ? $this->buildBody($dataToLog) : $body; + $this->log(sprintf("[Request #%s]: Novo Request para a API.\n%s %s\n%s", $requestId, $method, $url, + $dataToLog)); + $ch = curl_init(); + $ch_options = [ + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + ], + CURLOPT_TIMEOUT => 60, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_HEADER => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_USERAGENT => 'Vindi-Magento/' . $this->version, + CURLOPT_SSLVERSION => 'CURL_SSLVERSION_TLSv1_2', + CURLOPT_USERPWD => $this->key . ':', + CURLOPT_URL => $url, + CURLOPT_CUSTOMREQUEST => $method + ]; + if (!empty($body)) { + $ch_options[CURLOPT_POSTFIELDS] = $body; + } + curl_setopt_array($ch, $ch_options); + $response = curl_exec($ch); + $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $body = substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE)); + if (curl_errno($ch) || $response === false) { + $this->log(sprintf("[Request #%s]: Erro ao fazer request!\n%s", $requestId, print_r($response, true))); + return false; + } + curl_close($ch); + $status = "HTTP Status: $statusCode"; + $this->log(sprintf("[Request #%s]: Nova Resposta da API.\n%s\n%s", $requestId, $status, $body)); + $responseBody = json_decode($body, true); + if (!$responseBody) { + $this->log(sprintf('[Request #%s]: Erro ao recuperar corpo do request! %s', $requestId, + print_r($body, true))); + return false; + } + if (!$this->checkResponse($responseBody, $endpoint)) { + return false; + } + return $responseBody; + } + + /** + * Make an API request to create a Customer. + * + * @param array $body (name, email, code) + * + * @return array|bool|mixed + */ + public function createCustomer($body) + { + if ($response = $this->request('customers', 'POST', $body)) { + return $response['customer']['id']; + } + return false; + } + + /** + * Make an API request to retrieve an existing Customer. + * + * @param string $code + * + * @return array|bool|mixed + */ + public function findCustomerByCode($code) + { + $customerId = $this->cache()->load("vindi_customer_by_code_{$code}"); + if ($customerId === false) { + $response = $this->request("customers/search?code={$code}", 'GET'); + if ($response && (1 === count($response['customers'])) && isset($response['customers'][0]['id'])) { + $customerId = $response['customers'][0]['id']; + $this->cache()->save(serialize($customerId), "vindi_customer_by_code_{$code}", ['vindi_cache'], + 5 * 60); // 5 minutes + } + } else { + $customerId = unserialize($customerId); + } + return $customerId; + } + + /** + * Make an API request to retrieve an existing Customer or to create one if not found. + * + * @param array $body (name, email, code) + * + * @return array|bool|mixed + */ + public function findOrCreateCustomer($body) + { + $customerId = $this->findCustomerByCode($body['code']); + // TODO update information + if (false === $customerId) { + return $this->createCustomer($body); + } + return $customerId; + } + + /** + * Make an API request to create a Payment Profile to a Customer. + * + * @param $body (holder_name, card_expiration, card_number, card_cvv, customer_id) + * + * @return array|bool|mixed + */ + public function createCustomerPaymentProfile($body) + { + // Protect credit card number. + $dataToLog = $body; + $dataToLog['card_number'] = '**** *' . substr($dataToLog['card_number'], -3); + $dataToLog['card_cvv'] = '***'; + $customerId = $body['customer_id']; + $this->cache()->remove("vindi_payment_profile_{$customerId}"); + return $this->request('payment_profiles', 'POST', $body, $dataToLog); + } + + /** + * Make an API request to verify a Payment Profile to a Customer. + * + * @param $id integer + * + * @return array|bool|mixed + */ + public function verifyCustomerPaymentProfile($id) + { + return $this->request('payment_profiles/' . $id . '/verify', 'POST'); + } + + /** + * @param $userCode + * + * @return bool + */ + public function getCustomerPaymentProfile($userCode, $type = "CreditCard") + { + $customerId = $this->findCustomerByCode($userCode); + if (false === $customerId) { + return false; + } + $paymentProfile = $this->cache()->load("vindi_payment_profile_{$customerId}"); + if ($paymentProfile === false || strpos($paymentProfile, $type) === false) { + $endpoint = 'payment_profiles?query=customer_id%3D' . $customerId + . '%20status%3Dactive%20type%3DPaymentProfile%3A%3A' . $type; + $response = $this->request($endpoint, 'GET'); + if ($response && $response['payment_profiles'] && count($response['payment_profiles'])) { + $paymentProfile = $response['payment_profiles'][0]; + $this->cache()->save(serialize($paymentProfile), "vindi_payment_profile_{$customerId}", ['vindi_cache'], + 5 * 60); // 5 minutes + } else { + $paymentProfile = false; + } + } else { + $paymentProfile = unserialize($paymentProfile); + } + return $paymentProfile; + } + + /** + * Make an API request to create a Subscription. + * + * @param $body (plan_id, customer_id, payment_method_code, product_items[{product_id}]) + * + * @return array + */ + public function createSubscription($body) + { + if (($response = $this->request('subscriptions', 'POST', $body)) && isset($response['subscription']['id'])) { + $subscription = $response['subscription']; + $subscription['bill'] = $response['bill']; + return $subscription; + } + return false; + } + + /** + * Make an API request to retrieve Payment Methods. + * + * @return array|bool + */ + public function getPaymentMethods() + { + $paymentMethods = $this->cache()->load('vindi_payment_methods'); + if ($paymentMethods === false) { + $paymentMethods = [ + 'credit_card' => [], + 'debit_card' => [], + 'bank_slip' => false, + ]; + $response = $this->request('payment_methods', 'GET'); + if (false === $response) { + return $this->acceptBankSlip = false; + } + foreach ($response['payment_methods'] as $method) { + if ('active' !== $method['status']) { + continue; + } + if ('PaymentMethod::CreditCard' === $method['type']) { + $paymentMethods['credit_card'] = array_merge( + $paymentMethods['credit_card'], + $method['payment_companies'] + ); + } elseif ('PaymentMethod::DebitCard' === $method['type']) { + $paymentMethods['debit_card'] = array_merge( + $paymentMethods['debit_card'], + $method['payment_companies'] + ); + } elseif ('PaymentMethod::BankSlip' === $method['type']) { + $paymentMethods['bank_slip'] = true; + } + } + $this->cache()->save(serialize($paymentMethods), 'vindi_payment_methods', ['vindi_cache'], + 12 * 60 * 60); // 12 hours + } else { + $paymentMethods = unserialize($paymentMethods); + } + $this->acceptBankSlip = $paymentMethods['bank_slip']; + return $paymentMethods; + } + + /** + * Retrieve Credit Card Types from Payment Methods. + * + * @return array + */ + public function getCreditCardTypes() + { + $methods = $this->getPaymentMethods(); + $types = []; + foreach ($methods['credit_card'] as $type) { + $types[$type['code']] = $type['name']; + } + return $types; + } + + /** + * Retrieve Debit Card Types from Payment Methods. + * + * @return array + */ + public function getDebitCardTypes() + { + $methods = $this->getPaymentMethods(); + $types = []; + foreach ($methods['debit_card'] as $type) { + $types[$type['code']] = $type['name']; + } + return $types; + } + + /** + * @return bool|null + */ + public function acceptBankSlip() + { + if (null === $this->acceptBankSlip) { + $this->getPaymentMethods(); + } + return $this->acceptBankSlip; + } + + /** + * @param array $body + * + * @return int|bool + */ + public function createBill($body) + { + if ($response = $this->request('bills', 'POST', $body)) { + return $response['bill']; + } + return false; + } + + /** + * @param $billId + * + * @return array|bool|mixed + */ + public function approveBill($billId) + { + $response = $this->request("bills/{$billId}", 'GET'); + if (false === $response || !isset($response['bill'])) { + return false; + } + $bill = $response['bill']; + if ('review' !== $bill['status']) { + return true; + } + return $this->request("bills/{$billId}/approve", 'POST'); + } + + /** + * @param $billId + */ + public function deleteBill($billId) + { + $this->request("bills/{$billId}", 'DELETE'); + } + + /** + * @param $billId + * + * @return string + */ + public function getBankSlipDownload($billId) + { + $response = $this->request("bills/{$billId}", 'GET'); + if (false === $response) { + return false; + } + return $response['bill']['charges'][0]['print_url']; + } + + /** + * @return array + */ + public function getProducts() + { + $list = []; + $response = $this->request('products?query=status:active', 'GET'); + if ($products = $response['products']) { + foreach ($products as $product) { + $list[$product['id']] = "{$product['name']} ({$product['pricing_schema']['short_format']})"; + } + } + return $list; + } + + /** + * @param int $id + * + * @return array + */ + public function getPlanItems($id) + { + $list = []; + $response = $this->request("plans/{$id}", 'GET'); + if ($plan = $response['plan']) { + foreach ($plan['plan_items'] as $item) { + if (isset($item['product'])) { + $list[] = $item['product']['id']; + } + } + } + return $list; + } + + /** + * @param Mage_Sales_Model_Order $order + * + * @return array + */ + public function buildPlanItemsForSubscription($order) + { + $list = []; + $orderItems = $order->getItemsCollection(); + $orderSubtotal = $order->getQuote()->getSubtotal(); + $orderDiscount = $order->getDiscountAmount() * -1; + $discount = null; + if (!empty($orderDiscount)) { + $discountPercentage = $orderDiscount * 100 / $orderSubtotal; + $discountPercentage = number_format(floor($discountPercentage * 100) / 100, 2); + $discount = [[ + 'discount_type' => 'percentage', + 'percentage' => $discountPercentage + ]]; + } + foreach ($orderItems as $item) { + $product = Mage::getModel('catalog/product')->load($item->getProductId()); + if ($product->getTypeID() !== 'subscription') { + throw new \Exception("O produto {$item->getName()} não é uma assinatura."); + return false; + } + $productVindiId = $this->findOrCreateProduct(array('sku' => $item->getSku(), 'name' => $item->getName())); + for ($i = 1; $i <= $item->getQtyOrdered(); $i++) { + $list[] = [ + 'product_id' => $productVindiId, + 'pricing_schema' => ['price' => $item->getPrice()], + 'discounts' => $discount, + ]; + } + } + // Create product for shipping + $productVindiId = $this->findOrCreateProduct(array('sku' => 'frete', 'name' => 'Frete')); + $list[] = [ + 'product_id' => $productVindiId, + 'pricing_schema' => ['price' => $order->getShippingAmount()], + ]; + return $list; + } + + /** + * @return array + */ + public function getPlans() + { + $list = $this->cache()->load('vindi_plans'); + if (($list === false) || !count($list = unserialize($list))) { + $list = []; + $response = $this->request('plans?query=status:active', 'GET'); + if ($plans = $response['plans']) { + foreach ($plans as $plan) { + $list[$plan['id']] = $plan['name']; + } + } + $this->cache()->save(serialize($list), 'vindi_plans', ['vindi_cache'], 10 * 60); // 10 minutes + } + return $list; + } + + public function getPlanInstallments($id) + { + $response = $this->request("plans/{$id}", 'GET'); + $plan = $response['plan']; + $installments = $plan['installments']; + return $installments; + } + + /** + * Make an API request to create a Product. + * + * @param array $body (name, code, status, pricing_schema (price)) + * + * @return array|bool|mixed + */ + public function createProduct($body) + { + if ($response = $this->request('products', 'POST', $body)) { + return $response['product']['id']; + } + return false; + } + + /** + * Make an API request to retrieve an existing Product. + * + * @param string $code + * + * @return array|bool|mixed + */ + public function findProductByCode($code) + { + $response = $this->request("products?query=code%3D{$code}", 'GET'); + if ($response && (1 === count($response['products'])) && isset($response['products'][0]['id'])) { + return $response['products'][0]['id']; + } + return false; + } + + /** + * Make an API request to retrieve the Unique Payment Product or to create it if not found. + * + * @return array|bool|mixed + */ + public function findOrCreateUniquePaymentProduct() + { + $productId = $this->findProductByCode('mag-pagtounico'); + if (false === $productId) { + return $this->createProduct([ + 'name' => 'Pagamento Único (não remover)', + 'code' => 'mag-pagtounico', + 'status' => 'active', + 'pricing_schema' => [ + 'price' => 0, + ], + ]); + } + return $productId; + } + + /** + * Make an API request to retrieve a Product or to create it if not found. + * @param array $product + * + * @return array|bool|mixed + */ + public function findOrCreateProduct($product) + { + // + $productId = $this->findProductByCode($product['sku']); + if (false === $productId) { + return $this->createProduct([ + 'name' => $product['name'], + 'code' => $product['sku'], + 'status' => 'active', + 'pricing_schema' => [ + 'price' => 0, + ], + ]); + } + return $productId; + } + + /** + * Make an API request to retrieve information about the Merchant. + * + * @return array|bool|mixed + */ + public function getMerchant() + { + $merchant = $this->cache()->load('vindi_merchant'); + if ($merchant === false) { + $response = $this->request('merchant', 'GET'); + if (!$response || !isset($response['merchant'])) { + return false; + } + $merchant = $response['merchant']; + $this->cache()->save(serialize($merchant), 'vindi_merchant', ['vindi_cache'], 1 * 60 * 60); // 1 hour + } else { + $merchant = unserialize($merchant); + } + return $merchant; + } + + /** + * Check to see if Merchant Status is Trial. + * + * @return boolean + */ + public function isMerchantStatusTrial() + { + if ($merchant = $this->getMerchant()) { + return 'trial' === $merchant['status']; + } + return false; + } + + /** + * @param $billId + * + * @return array|bool + */ + public function getBill($billId) + { + $response = $this->request("bills/{$billId}", 'GET'); + if (!$response || !isset($response['bill'])) { + return false; + } + return $response['bill']; + } + + public function getDebitCardRedirectUrl($billId) + { + $bill = $this->request('bills/' . $billId, 'GET'); + $chargeId = $bill['bill']['charges'][0]['id']; + $charged = $this->request('charges/' . $chargeId . '/charge', 'POST', [ + 'id' => $bill['bill']['payment_profile']['id'] + ]); + return $charged['charge']['last_transaction']['gateway_response_fields']['authorization_url']; + } +} \ No newline at end of file diff --git a/app/code/Vindi/Payment/Model/Payment/CreditCard.php b/app/code/Vindi/Payment/Model/Payment/CreditCard.php new file mode 100644 index 00000000..88b1ba8d --- /dev/null +++ b/app/code/Vindi/Payment/Model/Payment/CreditCard.php @@ -0,0 +1,325 @@ +getInfoInstance(); + $quote = $info->getQuote(); + + $info->setAdditionalInformation('installments', $data->getCcInstallments()); + + if ($data->getCcChoice() === 'saved') { + $info->setAdditionalInformation('PaymentMethod', $this->_code) + ->setAdditionalInformation('use_saved_cc', true); + + return $this; + } + + $info->setCcType($data->getCcType()) + ->setCcOwner($data->getCcOwner()) + ->setCcLast4(substr($data->getCcNumber(), -4)) + ->setCcNumber($data->getCcNumber()) + ->setCcCid($data->getCcCid()) + ->setCcExpMonth($data->getCcExpMonth()) + ->setCcExpYear($data->getCcExpYear()) + ->setCcSsIssue($data->getCcSsIssue()) + ->setCcSsStartMonth($data->getCcSsStartMonth()) + ->setCcSsStartYear($data->getCcSsStartYear()) + ->setAdditionalInformation('PaymentMethod', $this->_code) + ->setAdditionalInformation('use_saved_cc', false); + + return $this; + } + + /** + * @param string $paymentAction + * @param object $stateObject + * + * @return bool|Mage_Payment_Model_Method_Abstract + */ + protected function processNewOrder($paymentAction, $stateObject) + { + $payment = $this->getInfoInstance(); + $order = $payment->getOrder(); + + $customer = Mage::getModel('customer/customer'); + + $customerId = $this->createCustomer($order, $customer); + $customerVindiId = $customer->getVindiUserCode(); + + if (!$payment->getAdditionalInformation('use_saved_cc')) { + $this->createPaymentProfile($customerId); + } else { + $this->assignDataFromPreviousPaymentProfile($customerVindiId); + } + + if ($this->isSingleOrder($order)) { + $result = $this->processSinglePayment($payment, $order, $customerId); + } else { + $result = $this->processSubscription($payment, $order, $customerId); + } + + if (!$result) { + return false; + } + + $billData = $this->api()->getBill($result); + $installments = $billData['installments']; + $response_fields = $billData['charges'][0]['last_transaction']['gateway_response_fields']; + $possible = ['nsu', 'proof_of_sale']; + $nsu = ''; + foreach ($possible as $nsu_field) { + if ($response_fields[$nsu_field]) { + $nsu = $response_fields[$nsu_field]; + } + } + + $this->getInfoInstance()->setAdditionalInformation( + [ + 'installments' => $installments, + 'nsu' => $nsu + ] + ); + + $stateObject->setStatus(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT) + ->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT); + + return $this; + } + + /** + * @param int $customerId + * + * @return array|bool + */ + protected function createPaymentProfile($customerId) + { + $payment = $this->getInfoInstance(); + + $creditCardData = [ + 'holder_name' => $payment->getCcOwner(), + 'card_expiration' => str_pad($payment->getCcExpMonth(), 2, '0', STR_PAD_LEFT) + . '/' . $payment->getCcExpYear(), + 'card_number' => $payment->getCcNumber(), + 'card_cvv' => $payment->getCcCid() ?: '000', + 'customer_id' => $customerId, + 'payment_company_code' => $payment->getCcType(), + 'payment_method_code' => $this->getPaymentMethodCode() + ]; + + $paymentProfile = $this->api()->createCustomerPaymentProfile($creditCardData); + + if ($paymentProfile === false) { + Mage::throwException('Erro ao informar os dados de cartão de crédito. Verifique os dados e tente novamente!'); + + return false; + } + + $verifyMethod = Mage::getStoreConfig('vindi_subscription/general/verify_method'); + + if ($verifyMethod && !$this->verifyPaymentProfile($paymentProfile['payment_profile']['id'])) { + Mage::throwException('Não foi possível realizar a verificação do seu cartão de crédito!'); + return false; + } + return $paymentProfile; + } + + /** + * @param int $paymentProfileId + * + * @return array|bool + */ + public function verifyPaymentProfile($paymentProfileId) + { + $verify_status = $this->api()->verifyCustomerPaymentProfile($paymentProfileId); + return ($verify_status['transaction']['status'] === 'success'); + } + + /** + * @param int $customerVindiId + */ + protected function assignDataFromPreviousPaymentProfile($customerVindiId) + { + $api = Mage::helper('vindi_subscription/api'); + $savedCc = $api->getCustomerPaymentProfile($customerVindiId); + $info = $this->getInfoInstance(); + + $info->setCcType($savedCc['payment_company']['code']) + ->setCcOwner($savedCc['holder_name']) + ->setCcLast4($savedCc['card_number_last_four']) + ->setCcNumber($savedCc['card_number_last_four']) + ->setAdditionalInformation('use_saved_cc', true); + } + + /** + * Check whether payment method can be used + * + * @param Mage_Sales_Model_Quote|null $quote + * + * @return bool + */ + public function isAvailable($quote = null) + { + return Mage::getStoreConfig('payment/vindi_creditcard/active') + && Mage::helper('vindi_subscription')->getKey(); + } + + /** + * Validate payment method information object + * + * @return Mage_Payment_Model_Method_Abstract + */ + public function validate() + { + $info = $this->getInfoInstance(); + + $quote = $info->getQuote(); + + $maxInstallmentsNumber = Mage::getStoreConfig('payment/vindi_creditcard/max_installments_number'); + + if ($this->isSingleOrder($quote) && ($maxInstallmentsNumber > 1)) { + if (!$installments = $info->getAdditionalInformation('installments')) { + return $this->error('Você deve informar o número de parcelas.'); + } + + if ($installments > $maxInstallmentsNumber) { + return $this->error('O número de parcelas selecionado é inválido.'); + } + + $minInstallmentsValue = Mage::getStoreConfig('payment/vindi_creditcard/min_installment_value'); + $installmentValue = ceil($quote->getGrandTotal() / $installments * 100) / 100; + + if (($installmentValue < $minInstallmentsValue) && ($installments > 1)) { + return $this->error('O número de parcelas selecionado é inválido.'); + } + } + + if ($info->getAdditionalInformation('use_saved_cc')) { + return $this; + } + + $availableTypes = $this->api()->getCreditCardTypes(); + + $ccNumber = $info->getCcNumber(); + + // remove credit card non-numbers + $ccNumber = preg_replace('/\D/', '', $ccNumber); + + $info->setCcNumber($ccNumber); + + if (!$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) { + return $this->error(Mage::helper('payment')->__('Incorrect credit card expiration date.')); + } + + if (!array_key_exists($info->getCcType(), $availableTypes)) { + return $this->error(Mage::helper('payment')->__('Credit card type is not allowed for this payment method.')); + } + + return $this; + } + + /** + * @param string $errorMsg + * + * @return bool + * @throws \Mage_Core_Exception + */ + private function error($errorMsg) + { + Mage::throwException($errorMsg); + + return false; + } + + /** + * @return string + */ + protected function getPaymentMethodCode() + { + // TODO fix it to proper method code + return 'credit_card'; + } +} diff --git a/app/code/Vindi/Payment/Model/Payment/Vindi.php b/app/code/Vindi/Payment/Model/Payment/Vindi.php new file mode 100644 index 00000000..b75a61a2 --- /dev/null +++ b/app/code/Vindi/Payment/Model/Payment/Vindi.php @@ -0,0 +1,322 @@ +getInfoInstance(); + $quote = $info->getQuote(); + + $info->setAdditionalInformation('installments', $data->getCcInstallments()); + + if ($data->getCcChoice() === 'saved') { + $info->setAdditionalInformation('PaymentMethod', $this->_code) + ->setAdditionalInformation('use_saved_cc', true); + + return $this; + } + + $info->setCcType($data->getCcType()) + ->setCcOwner($data->getCcOwner()) + ->setCcLast4(substr($data->getCcNumber(), -4)) + ->setCcNumber($data->getCcNumber()) + ->setCcCid($data->getCcCid()) + ->setCcExpMonth($data->getCcExpMonth()) + ->setCcExpYear($data->getCcExpYear()) + ->setCcSsIssue($data->getCcSsIssue()) + ->setCcSsStartMonth($data->getCcSsStartMonth()) + ->setCcSsStartYear($data->getCcSsStartYear()) + ->setAdditionalInformation('PaymentMethod', $this->_code) + ->setAdditionalInformation('use_saved_cc', false); + + return $this; + } + + /** + * @param string $paymentAction + * @param object $stateObject + * + * @return bool|Mage_Payment_Model_Method_Abstract + */ + protected function processNewOrder($paymentAction, $stateObject) + { + $payment = $this->getInfoInstance(); + $order = $payment->getOrder(); + + $customer = Mage::getModel('customer/customer'); + + $customerId = $this->createCustomer($order, $customer); + $customerVindiId = $customer->getVindiUserCode(); + + if (!$payment->getAdditionalInformation('use_saved_cc')) { + $this->createPaymentProfile($customerId); + } else { + $this->assignDataFromPreviousPaymentProfile($customerVindiId); + } + + if ($this->isSingleOrder($order)) { + $result = $this->processSinglePayment($payment, $order, $customerId); + } else { + $result = $this->processSubscription($payment, $order, $customerId); + } + + if (!$result) { + return false; + } + + $billData = $this->api()->getBill($result); + $installments = $billData['installments']; + $response_fields = $billData['charges'][0]['last_transaction']['gateway_response_fields']; + $possible = ['nsu', 'proof_of_sale']; + $nsu = ''; + foreach ($possible as $nsu_field) { + if ($response_fields[$nsu_field]) { + $nsu = $response_fields[$nsu_field]; + } + } + + $this->getInfoInstance()->setAdditionalInformation( + [ + 'installments' => $installments, + 'nsu' => $nsu + ] + ); + + $stateObject->setStatus(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT) + ->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT); + + return $this; + } + + /** + * @param int $customerId + * + * @return array|bool + */ + protected function createPaymentProfile($customerId) + { + $payment = $this->getInfoInstance(); + + $creditCardData = [ + 'holder_name' => $payment->getCcOwner(), + 'card_expiration' => str_pad($payment->getCcExpMonth(), 2, '0', STR_PAD_LEFT) + . '/' . $payment->getCcExpYear(), + 'card_number' => $payment->getCcNumber(), + 'card_cvv' => $payment->getCcCid() ?: '000', + 'customer_id' => $customerId, + 'payment_company_code' => $payment->getCcType(), + 'payment_method_code' => $this->getPaymentMethodCode() + ]; + + $paymentProfile = $this->api()->createCustomerPaymentProfile($creditCardData); + + if ($paymentProfile === false) { + Mage::throwException('Erro ao informar os dados de cartão de crédito. Verifique os dados e tente novamente!'); + + return false; + } + + $verifyMethod = Mage::getStoreConfig('vindi_subscription/general/verify_method'); + + if ($verifyMethod && !$this->verifyPaymentProfile($paymentProfile['payment_profile']['id'])) { + Mage::throwException('Não foi possível realizar a verificação do seu cartão de crédito!'); + return false; + } + return $paymentProfile; + } + + /** + * @param int $paymentProfileId + * + * @return array|bool + */ + public function verifyPaymentProfile($paymentProfileId) + { + $verify_status = $this->api()->verifyCustomerPaymentProfile($paymentProfileId); + return ($verify_status['transaction']['status'] === 'success'); + } + + /** + * @param int $customerVindiId + */ + protected function assignDataFromPreviousPaymentProfile($customerVindiId) + { + $api = Mage::helper('vindi_subscription/api'); + $savedCc = $api->getCustomerPaymentProfile($customerVindiId); + $info = $this->getInfoInstance(); + + $info->setCcType($savedCc['payment_company']['code']) + ->setCcOwner($savedCc['holder_name']) + ->setCcLast4($savedCc['card_number_last_four']) + ->setCcNumber($savedCc['card_number_last_four']) + ->setAdditionalInformation('use_saved_cc', true); + } + + /** + * Validate payment method information object + * + * @return Mage_Payment_Model_Method_Abstract + */ + public function validate() + { + $info = $this->getInfoInstance(); + + $quote = $info->getQuote(); + + $maxInstallmentsNumber = Mage::getStoreConfig('payment/vindi_creditcard/max_installments_number'); + + if ($this->isSingleOrder($quote) && ($maxInstallmentsNumber > 1)) { + if (!$installments = $info->getAdditionalInformation('installments')) { + return $this->error('Você deve informar o número de parcelas.'); + } + + if ($installments > $maxInstallmentsNumber) { + return $this->error('O número de parcelas selecionado é inválido.'); + } + + $minInstallmentsValue = Mage::getStoreConfig('payment/vindi_creditcard/min_installment_value'); + $installmentValue = ceil($quote->getGrandTotal() / $installments * 100) / 100; + + if (($installmentValue < $minInstallmentsValue) && ($installments > 1)) { + return $this->error('O número de parcelas selecionado é inválido.'); + } + } + + if ($info->getAdditionalInformation('use_saved_cc')) { + return $this; + } + + $availableTypes = $this->api()->getCreditCardTypes(); + + $ccNumber = $info->getCcNumber(); + + // remove credit card non-numbers + $ccNumber = preg_replace('/\D/', '', $ccNumber); + + $info->setCcNumber($ccNumber); + + if (!$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) { + return $this->error(Mage::helper('payment')->__('Incorrect credit card expiration date.')); + } + + if (!array_key_exists($info->getCcType(), $availableTypes)) { + return $this->error(Mage::helper('payment')->__('Credit card type is not allowed for this payment method.')); + } + + return $this; + } + + /** + * @param string $errorMsg + * + * @return bool + * @throws \Mage_Core_Exception + */ + private function error($errorMsg) + { + Mage::throwException($errorMsg); + + return false; + } + + /** + * @return string + */ + protected function getPaymentMethodCode() + { + return 'credit_card'; + } +} diff --git a/app/code/Vindi/Payment/etc/adminhtml/system.xml b/app/code/Vindi/Payment/etc/adminhtml/system.xml new file mode 100644 index 00000000..82844330 --- /dev/null +++ b/app/code/Vindi/Payment/etc/adminhtml/system.xml @@ -0,0 +1,56 @@ + + + +
+ + + + + Magento\Config\Model\Config\Source\Yesno + + + + + + + + Magento\Config\Model\Config\Source\Yesno + + + + + + + + Magento\Sales\Model\Config\Source\Order\Status\NewStatus + + + + Magento\Payment\Model\Config\Source\Allspecificcountries + + + + Magento\Directory\Model\Config\Source\Country + 1 + + + + + + + + +
+
+
diff --git a/app/code/Vindi/Payment/etc/config.xml b/app/code/Vindi/Payment/etc/config.xml new file mode 100644 index 00000000..8df8ef3f --- /dev/null +++ b/app/code/Vindi/Payment/etc/config.xml @@ -0,0 +1,16 @@ + + + + + + 1 + Vindi\Payment\Model\Payment\Vindi + pending + Vindi + 0 + offline + + + + diff --git a/app/code/Vindi/Payment/etc/frontend/routes.xml b/app/code/Vindi/Payment/etc/frontend/routes.xml new file mode 100644 index 00000000..3effe552 --- /dev/null +++ b/app/code/Vindi/Payment/etc/frontend/routes.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/code/Vindi/Payment/etc/module.xml b/app/code/Vindi/Payment/etc/module.xml new file mode 100644 index 00000000..ce0cf03b --- /dev/null +++ b/app/code/Vindi/Payment/etc/module.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/code/Vindi/Payment/etc/payment.xml b/app/code/Vindi/Payment/etc/payment.xml new file mode 100644 index 00000000..84ca3481 --- /dev/null +++ b/app/code/Vindi/Payment/etc/payment.xml @@ -0,0 +1,14 @@ + + + + + + + + + + 1 + + + diff --git a/app/code/Vindi/Payment/registration.php b/app/code/Vindi/Payment/registration.php new file mode 100644 index 00000000..8d120c87 --- /dev/null +++ b/app/code/Vindi/Payment/registration.php @@ -0,0 +1,6 @@ + + + + + + + + + + + + + + + + + + + + Vindi_Payment/js/view/payment/vindi + + + + true + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js new file mode 100644 index 00000000..51ab10f0 --- /dev/null +++ b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js @@ -0,0 +1,16 @@ +define( + [ + 'Magento_Checkout/js/view/payment/default' + ], + function (Component) { + 'use strict'; + return Component.extend({ + defaults: { + template: 'Vindi_Payment/payment/vindi' + }, + getMailingAddress: function () { + return window.checkoutConfig.payment.checkmo.mailingAddress; + }, + }); + } +); diff --git a/app/code/Vindi/Payment/view/frontend/web/js/view/payment/vindi.js b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/vindi.js new file mode 100644 index 00000000..26293a5e --- /dev/null +++ b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/vindi.js @@ -0,0 +1,19 @@ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/payment/renderer-list' + ], + function ( + Component, + rendererList + ) { + 'use strict'; + rendererList.push( + { + type: 'vindi', + component: 'Vindi_Payment/js/view/payment/method-renderer/vindi-method' + } + ); + return Component.extend({}); + } +); \ No newline at end of file diff --git a/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html b/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html new file mode 100644 index 00000000..fdf6e030 --- /dev/null +++ b/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html @@ -0,0 +1,107 @@ +
+ + +
+
+
+
    + +
  • +
  • + +
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+ +
+ +
+ + + +
+
+
+ +
\ No newline at end of file diff --git a/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html b/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html new file mode 100644 index 00000000..4a4545be --- /dev/null +++ b/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html @@ -0,0 +1,50 @@ + +
+
+ + +
+
+ + + +
+ + + +
+ +
+ +
+ +
+ + + +
+
+
+ +
+
+
+
From 63e2baef19789194f2c3f6f3c097a4994f150dcd Mon Sep 17 00:00:00 2001 From: leonardo albuquerque Date: Tue, 24 Jul 2018 16:13:57 -0300 Subject: [PATCH 02/37] #11177 adicionado estrutura base --- README.md | 1 - .../Vindi/Payment/Controller/Index/Index.php | 25 +++++++++ app/code/Vindi/Payment/Model/Payment/.gitkeep | 0 .../Vindi/Payment/etc/adminhtml/system.xml | 56 +++++++++++++++++++ app/code/Vindi/Payment/etc/config.xml | 16 ++++++ .../Vindi/Payment/etc/frontend/routes.xml | 8 +++ app/code/Vindi/Payment/etc/module.xml | 5 ++ app/code/Vindi/Payment/etc/payment.xml | 14 +++++ app/code/Vindi/Payment/registration.php | 6 ++ .../frontend/layout/checkout_index_index.xml | 46 +++++++++++++++ .../payment/method-renderer/vindi-method.js | 16 ++++++ .../frontend/web/js/view/payment/vindi.js | 19 +++++++ .../frontend/web/template/payment/vindi.html | 50 +++++++++++++++++ 13 files changed, 261 insertions(+), 1 deletion(-) delete mode 100644 README.md create mode 100644 app/code/Vindi/Payment/Controller/Index/Index.php create mode 100644 app/code/Vindi/Payment/Model/Payment/.gitkeep create mode 100644 app/code/Vindi/Payment/etc/adminhtml/system.xml create mode 100644 app/code/Vindi/Payment/etc/config.xml create mode 100644 app/code/Vindi/Payment/etc/frontend/routes.xml create mode 100644 app/code/Vindi/Payment/etc/module.xml create mode 100644 app/code/Vindi/Payment/etc/payment.xml create mode 100644 app/code/Vindi/Payment/registration.php create mode 100644 app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml create mode 100644 app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js create mode 100644 app/code/Vindi/Payment/view/frontend/web/js/view/payment/vindi.js create mode 100644 app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html diff --git a/README.md b/README.md deleted file mode 100644 index 83f0885e..00000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# vindi-magento2 diff --git a/app/code/Vindi/Payment/Controller/Index/Index.php b/app/code/Vindi/Payment/Controller/Index/Index.php new file mode 100644 index 00000000..f59a2c10 --- /dev/null +++ b/app/code/Vindi/Payment/Controller/Index/Index.php @@ -0,0 +1,25 @@ +_pageFactory = $pageFactory; + $this->api = $api; + return parent::__construct($context); + } + + public function execute() + { + return $this->_pageFactory->create(); + } +} \ No newline at end of file diff --git a/app/code/Vindi/Payment/Model/Payment/.gitkeep b/app/code/Vindi/Payment/Model/Payment/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/app/code/Vindi/Payment/etc/adminhtml/system.xml b/app/code/Vindi/Payment/etc/adminhtml/system.xml new file mode 100644 index 00000000..82844330 --- /dev/null +++ b/app/code/Vindi/Payment/etc/adminhtml/system.xml @@ -0,0 +1,56 @@ + + + +
+ + + + + Magento\Config\Model\Config\Source\Yesno + + + + + + + + Magento\Config\Model\Config\Source\Yesno + + + + + + + + Magento\Sales\Model\Config\Source\Order\Status\NewStatus + + + + Magento\Payment\Model\Config\Source\Allspecificcountries + + + + Magento\Directory\Model\Config\Source\Country + 1 + + + + + + + + +
+
+
diff --git a/app/code/Vindi/Payment/etc/config.xml b/app/code/Vindi/Payment/etc/config.xml new file mode 100644 index 00000000..8df8ef3f --- /dev/null +++ b/app/code/Vindi/Payment/etc/config.xml @@ -0,0 +1,16 @@ + + + + + + 1 + Vindi\Payment\Model\Payment\Vindi + pending + Vindi + 0 + offline + + + + diff --git a/app/code/Vindi/Payment/etc/frontend/routes.xml b/app/code/Vindi/Payment/etc/frontend/routes.xml new file mode 100644 index 00000000..3effe552 --- /dev/null +++ b/app/code/Vindi/Payment/etc/frontend/routes.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/code/Vindi/Payment/etc/module.xml b/app/code/Vindi/Payment/etc/module.xml new file mode 100644 index 00000000..ce0cf03b --- /dev/null +++ b/app/code/Vindi/Payment/etc/module.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/code/Vindi/Payment/etc/payment.xml b/app/code/Vindi/Payment/etc/payment.xml new file mode 100644 index 00000000..84ca3481 --- /dev/null +++ b/app/code/Vindi/Payment/etc/payment.xml @@ -0,0 +1,14 @@ + + + + + + + + + + 1 + + + diff --git a/app/code/Vindi/Payment/registration.php b/app/code/Vindi/Payment/registration.php new file mode 100644 index 00000000..8d120c87 --- /dev/null +++ b/app/code/Vindi/Payment/registration.php @@ -0,0 +1,6 @@ + + + + + + + + + + + + + + + + + + + + Vindi_Payment/js/view/payment/vindi + + + + true + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js new file mode 100644 index 00000000..51ab10f0 --- /dev/null +++ b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js @@ -0,0 +1,16 @@ +define( + [ + 'Magento_Checkout/js/view/payment/default' + ], + function (Component) { + 'use strict'; + return Component.extend({ + defaults: { + template: 'Vindi_Payment/payment/vindi' + }, + getMailingAddress: function () { + return window.checkoutConfig.payment.checkmo.mailingAddress; + }, + }); + } +); diff --git a/app/code/Vindi/Payment/view/frontend/web/js/view/payment/vindi.js b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/vindi.js new file mode 100644 index 00000000..26293a5e --- /dev/null +++ b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/vindi.js @@ -0,0 +1,19 @@ +define( + [ + 'uiComponent', + 'Magento_Checkout/js/model/payment/renderer-list' + ], + function ( + Component, + rendererList + ) { + 'use strict'; + rendererList.push( + { + type: 'vindi', + component: 'Vindi_Payment/js/view/payment/method-renderer/vindi-method' + } + ); + return Component.extend({}); + } +); \ No newline at end of file diff --git a/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html b/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html new file mode 100644 index 00000000..4a4545be --- /dev/null +++ b/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html @@ -0,0 +1,50 @@ + +
+
+ + +
+
+ + + +
+ + + +
+ +
+ +
+ +
+ + + +
+
+
+ +
+
+
+
From b157a82a64cfa34a730ff3de402e5e28e6f4ff96 Mon Sep 17 00:00:00 2001 From: leonardo albuquerque Date: Tue, 24 Jul 2018 16:34:13 -0300 Subject: [PATCH 03/37] #11177 adicionada estrutura base --- .../Vindi/Payment/Model/Payment/Vindi.php | 307 +----------------- app/code/Vindi/Payment/composer.json | 22 ++ .../Vindi/Payment/etc/adminhtml/system.xml | 88 ++--- app/code/Vindi/Payment/etc/config.xml | 27 +- app/code/Vindi/Payment/etc/module.xml | 5 +- app/code/Vindi/Payment/etc/payment.xml | 23 +- .../frontend/layout/checkout_index_index.xml | 83 +++-- .../frontend/web/template/payment/vindi.html | 8 +- 8 files changed, 124 insertions(+), 439 deletions(-) create mode 100644 app/code/Vindi/Payment/composer.json diff --git a/app/code/Vindi/Payment/Model/Payment/Vindi.php b/app/code/Vindi/Payment/Model/Payment/Vindi.php index b75a61a2..cc3c19d1 100644 --- a/app/code/Vindi/Payment/Model/Payment/Vindi.php +++ b/app/code/Vindi/Payment/Model/Payment/Vindi.php @@ -3,10 +3,6 @@ namespace Vindi\Payment\Model\Payment; -use Magento\Framework\DataObject; -use Magento\Quote\Api\Data\CartInterface; -use Vindi\Payment\Model\Api; - class Vindi extends \Magento\Payment\Model\Method\AbstractMethod { @@ -15,308 +11,7 @@ class Vindi extends \Magento\Payment\Model\Method\AbstractMethod public function isAvailable( \Magento\Quote\Api\Data\CartInterface $quote = null - ) - { + ) { return parent::isAvailable($quote); } - - /** - * @var bool - */ - protected $_isGateway = true; - - /** - * @var bool - */ - protected $_canAuthorize = true; - - /** - * @var bool - */ - protected $_canCapture = true; - - /** - * @var bool - */ - protected $_canCapturePartial = false; - - /** - * @var bool - */ - protected $_canRefund = false; - - /** - * @var bool - */ - protected $_canVoid = false; - - /** - * @var bool - */ - protected $_canUseInternal = true; - - /** - * @var bool - */ - protected $_canUseCheckout = true; - - /** - * @var bool - */ - protected $_canUseForMultishipping = false; - - /** - * @var bool - */ - protected $_isInitializeNeeded = true; - - /** - * @var bool - */ - protected $_canSaveCc = false; - - /** - * @var string - */ - protected $_formBlockType = 'vindi_subscription/form_cc'; - - /** - * @var string - */ - protected $_infoBlockType = 'vindi_subscription/info_cc'; - - /** - * Assign data to info model instance - * - * @param mixed $data - * - * @return Mage_Payment_Model_Method_Abstract - */ - public function assignData(DataObject $data) - { - if (!($data instanceof Varien_Object)) { - $data = new Varien_Object($data); - } - $info = $this->getInfoInstance(); - $quote = $info->getQuote(); - - $info->setAdditionalInformation('installments', $data->getCcInstallments()); - - if ($data->getCcChoice() === 'saved') { - $info->setAdditionalInformation('PaymentMethod', $this->_code) - ->setAdditionalInformation('use_saved_cc', true); - - return $this; - } - - $info->setCcType($data->getCcType()) - ->setCcOwner($data->getCcOwner()) - ->setCcLast4(substr($data->getCcNumber(), -4)) - ->setCcNumber($data->getCcNumber()) - ->setCcCid($data->getCcCid()) - ->setCcExpMonth($data->getCcExpMonth()) - ->setCcExpYear($data->getCcExpYear()) - ->setCcSsIssue($data->getCcSsIssue()) - ->setCcSsStartMonth($data->getCcSsStartMonth()) - ->setCcSsStartYear($data->getCcSsStartYear()) - ->setAdditionalInformation('PaymentMethod', $this->_code) - ->setAdditionalInformation('use_saved_cc', false); - - return $this; - } - - /** - * @param string $paymentAction - * @param object $stateObject - * - * @return bool|Mage_Payment_Model_Method_Abstract - */ - protected function processNewOrder($paymentAction, $stateObject) - { - $payment = $this->getInfoInstance(); - $order = $payment->getOrder(); - - $customer = Mage::getModel('customer/customer'); - - $customerId = $this->createCustomer($order, $customer); - $customerVindiId = $customer->getVindiUserCode(); - - if (!$payment->getAdditionalInformation('use_saved_cc')) { - $this->createPaymentProfile($customerId); - } else { - $this->assignDataFromPreviousPaymentProfile($customerVindiId); - } - - if ($this->isSingleOrder($order)) { - $result = $this->processSinglePayment($payment, $order, $customerId); - } else { - $result = $this->processSubscription($payment, $order, $customerId); - } - - if (!$result) { - return false; - } - - $billData = $this->api()->getBill($result); - $installments = $billData['installments']; - $response_fields = $billData['charges'][0]['last_transaction']['gateway_response_fields']; - $possible = ['nsu', 'proof_of_sale']; - $nsu = ''; - foreach ($possible as $nsu_field) { - if ($response_fields[$nsu_field]) { - $nsu = $response_fields[$nsu_field]; - } - } - - $this->getInfoInstance()->setAdditionalInformation( - [ - 'installments' => $installments, - 'nsu' => $nsu - ] - ); - - $stateObject->setStatus(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT) - ->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT); - - return $this; - } - - /** - * @param int $customerId - * - * @return array|bool - */ - protected function createPaymentProfile($customerId) - { - $payment = $this->getInfoInstance(); - - $creditCardData = [ - 'holder_name' => $payment->getCcOwner(), - 'card_expiration' => str_pad($payment->getCcExpMonth(), 2, '0', STR_PAD_LEFT) - . '/' . $payment->getCcExpYear(), - 'card_number' => $payment->getCcNumber(), - 'card_cvv' => $payment->getCcCid() ?: '000', - 'customer_id' => $customerId, - 'payment_company_code' => $payment->getCcType(), - 'payment_method_code' => $this->getPaymentMethodCode() - ]; - - $paymentProfile = $this->api()->createCustomerPaymentProfile($creditCardData); - - if ($paymentProfile === false) { - Mage::throwException('Erro ao informar os dados de cartão de crédito. Verifique os dados e tente novamente!'); - - return false; - } - - $verifyMethod = Mage::getStoreConfig('vindi_subscription/general/verify_method'); - - if ($verifyMethod && !$this->verifyPaymentProfile($paymentProfile['payment_profile']['id'])) { - Mage::throwException('Não foi possível realizar a verificação do seu cartão de crédito!'); - return false; - } - return $paymentProfile; - } - - /** - * @param int $paymentProfileId - * - * @return array|bool - */ - public function verifyPaymentProfile($paymentProfileId) - { - $verify_status = $this->api()->verifyCustomerPaymentProfile($paymentProfileId); - return ($verify_status['transaction']['status'] === 'success'); - } - - /** - * @param int $customerVindiId - */ - protected function assignDataFromPreviousPaymentProfile($customerVindiId) - { - $api = Mage::helper('vindi_subscription/api'); - $savedCc = $api->getCustomerPaymentProfile($customerVindiId); - $info = $this->getInfoInstance(); - - $info->setCcType($savedCc['payment_company']['code']) - ->setCcOwner($savedCc['holder_name']) - ->setCcLast4($savedCc['card_number_last_four']) - ->setCcNumber($savedCc['card_number_last_four']) - ->setAdditionalInformation('use_saved_cc', true); - } - - /** - * Validate payment method information object - * - * @return Mage_Payment_Model_Method_Abstract - */ - public function validate() - { - $info = $this->getInfoInstance(); - - $quote = $info->getQuote(); - - $maxInstallmentsNumber = Mage::getStoreConfig('payment/vindi_creditcard/max_installments_number'); - - if ($this->isSingleOrder($quote) && ($maxInstallmentsNumber > 1)) { - if (!$installments = $info->getAdditionalInformation('installments')) { - return $this->error('Você deve informar o número de parcelas.'); - } - - if ($installments > $maxInstallmentsNumber) { - return $this->error('O número de parcelas selecionado é inválido.'); - } - - $minInstallmentsValue = Mage::getStoreConfig('payment/vindi_creditcard/min_installment_value'); - $installmentValue = ceil($quote->getGrandTotal() / $installments * 100) / 100; - - if (($installmentValue < $minInstallmentsValue) && ($installments > 1)) { - return $this->error('O número de parcelas selecionado é inválido.'); - } - } - - if ($info->getAdditionalInformation('use_saved_cc')) { - return $this; - } - - $availableTypes = $this->api()->getCreditCardTypes(); - - $ccNumber = $info->getCcNumber(); - - // remove credit card non-numbers - $ccNumber = preg_replace('/\D/', '', $ccNumber); - - $info->setCcNumber($ccNumber); - - if (!$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) { - return $this->error(Mage::helper('payment')->__('Incorrect credit card expiration date.')); - } - - if (!array_key_exists($info->getCcType(), $availableTypes)) { - return $this->error(Mage::helper('payment')->__('Credit card type is not allowed for this payment method.')); - } - - return $this; - } - - /** - * @param string $errorMsg - * - * @return bool - * @throws \Mage_Core_Exception - */ - private function error($errorMsg) - { - Mage::throwException($errorMsg); - - return false; - } - - /** - * @return string - */ - protected function getPaymentMethodCode() - { - return 'credit_card'; - } } diff --git a/app/code/Vindi/Payment/composer.json b/app/code/Vindi/Payment/composer.json new file mode 100644 index 00000000..434f78fa --- /dev/null +++ b/app/code/Vindi/Payment/composer.json @@ -0,0 +1,22 @@ +{ + "name": "vindi/module-payment", + "description": "", + "type": "magento2-module", + "license": "proprietary", + "authors": [ + { + "email": "info@mage2gen.com", + "name": "Mage2Gen" + } + ], + "minimum-stability": "dev", + "require": {}, + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Vindi\\Payment\\": "" + } + } +} \ No newline at end of file diff --git a/app/code/Vindi/Payment/etc/adminhtml/system.xml b/app/code/Vindi/Payment/etc/adminhtml/system.xml index 82844330..18e6dc33 100644 --- a/app/code/Vindi/Payment/etc/adminhtml/system.xml +++ b/app/code/Vindi/Payment/etc/adminhtml/system.xml @@ -1,56 +1,36 @@ - - -
- - - - - Magento\Config\Model\Config\Source\Yesno - - - - - - - - Magento\Config\Model\Config\Source\Yesno - - - - - - - - Magento\Sales\Model\Config\Source\Order\Status\NewStatus - - - - Magento\Payment\Model\Config\Source\Allspecificcountries - - - - Magento\Directory\Model\Config\Source\Country - 1 - - - - - - - - -
-
+ + +
+ + + + + Magento\Config\Model\Config\Source\Yesno + + + + + + + Magento\Sales\Model\Config\Source\Order\Status\NewStatus + + + + Magento\Payment\Model\Config\Source\Allspecificcountries + + + + Magento\Directory\Model\Config\Source\Country + 1 + + + + + + + + +
+
diff --git a/app/code/Vindi/Payment/etc/config.xml b/app/code/Vindi/Payment/etc/config.xml index 8df8ef3f..17583699 100644 --- a/app/code/Vindi/Payment/etc/config.xml +++ b/app/code/Vindi/Payment/etc/config.xml @@ -1,16 +1,15 @@ - - - - - 1 - Vindi\Payment\Model\Payment\Vindi - pending - Vindi - 0 - offline - - - + + + + + 1 + Vindi\Payment\Model\Payment\Vindi + pending + Vindi + 0 + offline + + + diff --git a/app/code/Vindi/Payment/etc/module.xml b/app/code/Vindi/Payment/etc/module.xml index ce0cf03b..d9645236 100644 --- a/app/code/Vindi/Payment/etc/module.xml +++ b/app/code/Vindi/Payment/etc/module.xml @@ -1,5 +1,4 @@ - - + + diff --git a/app/code/Vindi/Payment/etc/payment.xml b/app/code/Vindi/Payment/etc/payment.xml index 84ca3481..cbe2c415 100644 --- a/app/code/Vindi/Payment/etc/payment.xml +++ b/app/code/Vindi/Payment/etc/payment.xml @@ -1,14 +1,13 @@ - - - - - - - - - 1 - - + + + + + + + + + 1 + + diff --git a/app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml b/app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml index 11ff49eb..01dbadc4 100644 --- a/app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml @@ -1,46 +1,41 @@ - - - - - - - - - - - - - - - - - - - Vindi_Payment/js/view/payment/vindi - - - - true - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + Vindi_Payment/js/view/payment/vindi + + + true + + + + + + + + + + + + + + + + + + diff --git a/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html b/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html index 4a4545be..cebbb9ac 100644 --- a/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html +++ b/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html @@ -21,14 +21,9 @@ - -
- -
-
- +
@@ -48,3 +43,4 @@
+ \ No newline at end of file From 4c6f977d21461e2267485b32c732d87a32d7128e Mon Sep 17 00:00:00 2001 From: leonardo albuquerque Date: Tue, 24 Jul 2018 16:42:16 -0300 Subject: [PATCH 04/37] =?UTF-8?q?#11177=20removido=20arquivos=20n=C3=A3o?= =?UTF-8?q?=20necess=C3=A1rios=20para=20esta=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/code/Vindi/Payment/Model/Api.php | 706 ------------------ .../Payment/Model/Payment/CreditCard.php | 325 -------- .../web/template/payment/cc-form.html | 107 --- 3 files changed, 1138 deletions(-) delete mode 100644 app/code/Vindi/Payment/Model/Api.php delete mode 100644 app/code/Vindi/Payment/Model/Payment/CreditCard.php delete mode 100644 app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html diff --git a/app/code/Vindi/Payment/Model/Api.php b/app/code/Vindi/Payment/Model/Api.php deleted file mode 100644 index 7b36957b..00000000 --- a/app/code/Vindi/Payment/Model/Api.php +++ /dev/null @@ -1,706 +0,0 @@ -scopeConfig = $scopeConfig; - $this->logger = $logger; - $this->cacheType = $cacheType; - $this->message = $message; - - $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; - $isSandBox = $this->scopeConfig->getValue('payment/vindi/sandboxmode', $storeScope); - - if ($isSandBox) { - $this->base_path = 'https://sandbox-app.vindi.com.br/api/v1/'; - } else { - $this->base_path = 'https://app.vindi.com.br/api/v1/'; - } - - $moduleInfo = $moduleList->getOne('Vindi_Payment'); - $this->version = $moduleInfo['setup_version']; - $this->key = $this->scopeConfig->getValue('payment/vindi/key', $storeScope); - } - - - public function execute(Observer $observer) - { - $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; - $notifyEmail = $this->scopeConfig->getValue(self::BASEPATH, $storeScope); - - echo $notifyEmail; - } - - /** - * @param string $message - * @param int|null $level - */ - private function log($message) - { - $this->logger->warning($message); - } - - /** - * @return \Zend_Cache_Core - */ - private function cache() - { - return $this->cacheType; - } - - /** - * Build HTTP Query. - * - * @param array $data - * - * @return string - */ - private function buildBody($data) - { - $body = null; - if (!empty($data)) { - $body = json_encode($data); - } - return $body; - } - - /** - * @param array $error - * @param $endpoint - * - * @return string - */ - private function getErrorMessage($error, $endpoint) - { - return "Erro em $endpoint: {$error['id']}: {$error['parameter']} - {$error['message']}"; - } - - /** - * @param array $response - * @param $endpoint - * - * @return bool - */ - private function checkResponse($response, $endpoint) - { - if (isset($response['errors']) && !empty($response['errors'])) { - foreach ($response['errors'] as $error) { - $message = $this->getErrorMessage($error, $endpoint); - $this->message->addErrorMessage($message); - $this->lastError = $message; - } - return false; - } - $this->lastError = ''; - return true; - } - - /** - * Perform request to API. - * - * @param string $endpoint - * @param string $method - * @param array $data - * @param null $dataToLog - * - * @return array|bool|mixed - */ - private function request($endpoint, $method = 'POST', $data = [], $dataToLog = null) - { - if (!$this->key) { - return false; - } - $url = $this->base_path . $endpoint; - $body = $this->buildBody($data); - $requestId = rand(); - $dataToLog = null !== $dataToLog ? $this->buildBody($dataToLog) : $body; - $this->log(sprintf("[Request #%s]: Novo Request para a API.\n%s %s\n%s", $requestId, $method, $url, - $dataToLog)); - $ch = curl_init(); - $ch_options = [ - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/json', - ], - CURLOPT_TIMEOUT => 60, - CURLOPT_SSL_VERIFYPEER => true, - CURLOPT_HEADER => true, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_USERAGENT => 'Vindi-Magento/' . $this->version, - CURLOPT_SSLVERSION => 'CURL_SSLVERSION_TLSv1_2', - CURLOPT_USERPWD => $this->key . ':', - CURLOPT_URL => $url, - CURLOPT_CUSTOMREQUEST => $method - ]; - if (!empty($body)) { - $ch_options[CURLOPT_POSTFIELDS] = $body; - } - curl_setopt_array($ch, $ch_options); - $response = curl_exec($ch); - $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $body = substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE)); - if (curl_errno($ch) || $response === false) { - $this->log(sprintf("[Request #%s]: Erro ao fazer request!\n%s", $requestId, print_r($response, true))); - return false; - } - curl_close($ch); - $status = "HTTP Status: $statusCode"; - $this->log(sprintf("[Request #%s]: Nova Resposta da API.\n%s\n%s", $requestId, $status, $body)); - $responseBody = json_decode($body, true); - if (!$responseBody) { - $this->log(sprintf('[Request #%s]: Erro ao recuperar corpo do request! %s', $requestId, - print_r($body, true))); - return false; - } - if (!$this->checkResponse($responseBody, $endpoint)) { - return false; - } - return $responseBody; - } - - /** - * Make an API request to create a Customer. - * - * @param array $body (name, email, code) - * - * @return array|bool|mixed - */ - public function createCustomer($body) - { - if ($response = $this->request('customers', 'POST', $body)) { - return $response['customer']['id']; - } - return false; - } - - /** - * Make an API request to retrieve an existing Customer. - * - * @param string $code - * - * @return array|bool|mixed - */ - public function findCustomerByCode($code) - { - $customerId = $this->cache()->load("vindi_customer_by_code_{$code}"); - if ($customerId === false) { - $response = $this->request("customers/search?code={$code}", 'GET'); - if ($response && (1 === count($response['customers'])) && isset($response['customers'][0]['id'])) { - $customerId = $response['customers'][0]['id']; - $this->cache()->save(serialize($customerId), "vindi_customer_by_code_{$code}", ['vindi_cache'], - 5 * 60); // 5 minutes - } - } else { - $customerId = unserialize($customerId); - } - return $customerId; - } - - /** - * Make an API request to retrieve an existing Customer or to create one if not found. - * - * @param array $body (name, email, code) - * - * @return array|bool|mixed - */ - public function findOrCreateCustomer($body) - { - $customerId = $this->findCustomerByCode($body['code']); - // TODO update information - if (false === $customerId) { - return $this->createCustomer($body); - } - return $customerId; - } - - /** - * Make an API request to create a Payment Profile to a Customer. - * - * @param $body (holder_name, card_expiration, card_number, card_cvv, customer_id) - * - * @return array|bool|mixed - */ - public function createCustomerPaymentProfile($body) - { - // Protect credit card number. - $dataToLog = $body; - $dataToLog['card_number'] = '**** *' . substr($dataToLog['card_number'], -3); - $dataToLog['card_cvv'] = '***'; - $customerId = $body['customer_id']; - $this->cache()->remove("vindi_payment_profile_{$customerId}"); - return $this->request('payment_profiles', 'POST', $body, $dataToLog); - } - - /** - * Make an API request to verify a Payment Profile to a Customer. - * - * @param $id integer - * - * @return array|bool|mixed - */ - public function verifyCustomerPaymentProfile($id) - { - return $this->request('payment_profiles/' . $id . '/verify', 'POST'); - } - - /** - * @param $userCode - * - * @return bool - */ - public function getCustomerPaymentProfile($userCode, $type = "CreditCard") - { - $customerId = $this->findCustomerByCode($userCode); - if (false === $customerId) { - return false; - } - $paymentProfile = $this->cache()->load("vindi_payment_profile_{$customerId}"); - if ($paymentProfile === false || strpos($paymentProfile, $type) === false) { - $endpoint = 'payment_profiles?query=customer_id%3D' . $customerId - . '%20status%3Dactive%20type%3DPaymentProfile%3A%3A' . $type; - $response = $this->request($endpoint, 'GET'); - if ($response && $response['payment_profiles'] && count($response['payment_profiles'])) { - $paymentProfile = $response['payment_profiles'][0]; - $this->cache()->save(serialize($paymentProfile), "vindi_payment_profile_{$customerId}", ['vindi_cache'], - 5 * 60); // 5 minutes - } else { - $paymentProfile = false; - } - } else { - $paymentProfile = unserialize($paymentProfile); - } - return $paymentProfile; - } - - /** - * Make an API request to create a Subscription. - * - * @param $body (plan_id, customer_id, payment_method_code, product_items[{product_id}]) - * - * @return array - */ - public function createSubscription($body) - { - if (($response = $this->request('subscriptions', 'POST', $body)) && isset($response['subscription']['id'])) { - $subscription = $response['subscription']; - $subscription['bill'] = $response['bill']; - return $subscription; - } - return false; - } - - /** - * Make an API request to retrieve Payment Methods. - * - * @return array|bool - */ - public function getPaymentMethods() - { - $paymentMethods = $this->cache()->load('vindi_payment_methods'); - if ($paymentMethods === false) { - $paymentMethods = [ - 'credit_card' => [], - 'debit_card' => [], - 'bank_slip' => false, - ]; - $response = $this->request('payment_methods', 'GET'); - if (false === $response) { - return $this->acceptBankSlip = false; - } - foreach ($response['payment_methods'] as $method) { - if ('active' !== $method['status']) { - continue; - } - if ('PaymentMethod::CreditCard' === $method['type']) { - $paymentMethods['credit_card'] = array_merge( - $paymentMethods['credit_card'], - $method['payment_companies'] - ); - } elseif ('PaymentMethod::DebitCard' === $method['type']) { - $paymentMethods['debit_card'] = array_merge( - $paymentMethods['debit_card'], - $method['payment_companies'] - ); - } elseif ('PaymentMethod::BankSlip' === $method['type']) { - $paymentMethods['bank_slip'] = true; - } - } - $this->cache()->save(serialize($paymentMethods), 'vindi_payment_methods', ['vindi_cache'], - 12 * 60 * 60); // 12 hours - } else { - $paymentMethods = unserialize($paymentMethods); - } - $this->acceptBankSlip = $paymentMethods['bank_slip']; - return $paymentMethods; - } - - /** - * Retrieve Credit Card Types from Payment Methods. - * - * @return array - */ - public function getCreditCardTypes() - { - $methods = $this->getPaymentMethods(); - $types = []; - foreach ($methods['credit_card'] as $type) { - $types[$type['code']] = $type['name']; - } - return $types; - } - - /** - * Retrieve Debit Card Types from Payment Methods. - * - * @return array - */ - public function getDebitCardTypes() - { - $methods = $this->getPaymentMethods(); - $types = []; - foreach ($methods['debit_card'] as $type) { - $types[$type['code']] = $type['name']; - } - return $types; - } - - /** - * @return bool|null - */ - public function acceptBankSlip() - { - if (null === $this->acceptBankSlip) { - $this->getPaymentMethods(); - } - return $this->acceptBankSlip; - } - - /** - * @param array $body - * - * @return int|bool - */ - public function createBill($body) - { - if ($response = $this->request('bills', 'POST', $body)) { - return $response['bill']; - } - return false; - } - - /** - * @param $billId - * - * @return array|bool|mixed - */ - public function approveBill($billId) - { - $response = $this->request("bills/{$billId}", 'GET'); - if (false === $response || !isset($response['bill'])) { - return false; - } - $bill = $response['bill']; - if ('review' !== $bill['status']) { - return true; - } - return $this->request("bills/{$billId}/approve", 'POST'); - } - - /** - * @param $billId - */ - public function deleteBill($billId) - { - $this->request("bills/{$billId}", 'DELETE'); - } - - /** - * @param $billId - * - * @return string - */ - public function getBankSlipDownload($billId) - { - $response = $this->request("bills/{$billId}", 'GET'); - if (false === $response) { - return false; - } - return $response['bill']['charges'][0]['print_url']; - } - - /** - * @return array - */ - public function getProducts() - { - $list = []; - $response = $this->request('products?query=status:active', 'GET'); - if ($products = $response['products']) { - foreach ($products as $product) { - $list[$product['id']] = "{$product['name']} ({$product['pricing_schema']['short_format']})"; - } - } - return $list; - } - - /** - * @param int $id - * - * @return array - */ - public function getPlanItems($id) - { - $list = []; - $response = $this->request("plans/{$id}", 'GET'); - if ($plan = $response['plan']) { - foreach ($plan['plan_items'] as $item) { - if (isset($item['product'])) { - $list[] = $item['product']['id']; - } - } - } - return $list; - } - - /** - * @param Mage_Sales_Model_Order $order - * - * @return array - */ - public function buildPlanItemsForSubscription($order) - { - $list = []; - $orderItems = $order->getItemsCollection(); - $orderSubtotal = $order->getQuote()->getSubtotal(); - $orderDiscount = $order->getDiscountAmount() * -1; - $discount = null; - if (!empty($orderDiscount)) { - $discountPercentage = $orderDiscount * 100 / $orderSubtotal; - $discountPercentage = number_format(floor($discountPercentage * 100) / 100, 2); - $discount = [[ - 'discount_type' => 'percentage', - 'percentage' => $discountPercentage - ]]; - } - foreach ($orderItems as $item) { - $product = Mage::getModel('catalog/product')->load($item->getProductId()); - if ($product->getTypeID() !== 'subscription') { - throw new \Exception("O produto {$item->getName()} não é uma assinatura."); - return false; - } - $productVindiId = $this->findOrCreateProduct(array('sku' => $item->getSku(), 'name' => $item->getName())); - for ($i = 1; $i <= $item->getQtyOrdered(); $i++) { - $list[] = [ - 'product_id' => $productVindiId, - 'pricing_schema' => ['price' => $item->getPrice()], - 'discounts' => $discount, - ]; - } - } - // Create product for shipping - $productVindiId = $this->findOrCreateProduct(array('sku' => 'frete', 'name' => 'Frete')); - $list[] = [ - 'product_id' => $productVindiId, - 'pricing_schema' => ['price' => $order->getShippingAmount()], - ]; - return $list; - } - - /** - * @return array - */ - public function getPlans() - { - $list = $this->cache()->load('vindi_plans'); - if (($list === false) || !count($list = unserialize($list))) { - $list = []; - $response = $this->request('plans?query=status:active', 'GET'); - if ($plans = $response['plans']) { - foreach ($plans as $plan) { - $list[$plan['id']] = $plan['name']; - } - } - $this->cache()->save(serialize($list), 'vindi_plans', ['vindi_cache'], 10 * 60); // 10 minutes - } - return $list; - } - - public function getPlanInstallments($id) - { - $response = $this->request("plans/{$id}", 'GET'); - $plan = $response['plan']; - $installments = $plan['installments']; - return $installments; - } - - /** - * Make an API request to create a Product. - * - * @param array $body (name, code, status, pricing_schema (price)) - * - * @return array|bool|mixed - */ - public function createProduct($body) - { - if ($response = $this->request('products', 'POST', $body)) { - return $response['product']['id']; - } - return false; - } - - /** - * Make an API request to retrieve an existing Product. - * - * @param string $code - * - * @return array|bool|mixed - */ - public function findProductByCode($code) - { - $response = $this->request("products?query=code%3D{$code}", 'GET'); - if ($response && (1 === count($response['products'])) && isset($response['products'][0]['id'])) { - return $response['products'][0]['id']; - } - return false; - } - - /** - * Make an API request to retrieve the Unique Payment Product or to create it if not found. - * - * @return array|bool|mixed - */ - public function findOrCreateUniquePaymentProduct() - { - $productId = $this->findProductByCode('mag-pagtounico'); - if (false === $productId) { - return $this->createProduct([ - 'name' => 'Pagamento Único (não remover)', - 'code' => 'mag-pagtounico', - 'status' => 'active', - 'pricing_schema' => [ - 'price' => 0, - ], - ]); - } - return $productId; - } - - /** - * Make an API request to retrieve a Product or to create it if not found. - * @param array $product - * - * @return array|bool|mixed - */ - public function findOrCreateProduct($product) - { - // - $productId = $this->findProductByCode($product['sku']); - if (false === $productId) { - return $this->createProduct([ - 'name' => $product['name'], - 'code' => $product['sku'], - 'status' => 'active', - 'pricing_schema' => [ - 'price' => 0, - ], - ]); - } - return $productId; - } - - /** - * Make an API request to retrieve information about the Merchant. - * - * @return array|bool|mixed - */ - public function getMerchant() - { - $merchant = $this->cache()->load('vindi_merchant'); - if ($merchant === false) { - $response = $this->request('merchant', 'GET'); - if (!$response || !isset($response['merchant'])) { - return false; - } - $merchant = $response['merchant']; - $this->cache()->save(serialize($merchant), 'vindi_merchant', ['vindi_cache'], 1 * 60 * 60); // 1 hour - } else { - $merchant = unserialize($merchant); - } - return $merchant; - } - - /** - * Check to see if Merchant Status is Trial. - * - * @return boolean - */ - public function isMerchantStatusTrial() - { - if ($merchant = $this->getMerchant()) { - return 'trial' === $merchant['status']; - } - return false; - } - - /** - * @param $billId - * - * @return array|bool - */ - public function getBill($billId) - { - $response = $this->request("bills/{$billId}", 'GET'); - if (!$response || !isset($response['bill'])) { - return false; - } - return $response['bill']; - } - - public function getDebitCardRedirectUrl($billId) - { - $bill = $this->request('bills/' . $billId, 'GET'); - $chargeId = $bill['bill']['charges'][0]['id']; - $charged = $this->request('charges/' . $chargeId . '/charge', 'POST', [ - 'id' => $bill['bill']['payment_profile']['id'] - ]); - return $charged['charge']['last_transaction']['gateway_response_fields']['authorization_url']; - } -} \ No newline at end of file diff --git a/app/code/Vindi/Payment/Model/Payment/CreditCard.php b/app/code/Vindi/Payment/Model/Payment/CreditCard.php deleted file mode 100644 index 88b1ba8d..00000000 --- a/app/code/Vindi/Payment/Model/Payment/CreditCard.php +++ /dev/null @@ -1,325 +0,0 @@ -getInfoInstance(); - $quote = $info->getQuote(); - - $info->setAdditionalInformation('installments', $data->getCcInstallments()); - - if ($data->getCcChoice() === 'saved') { - $info->setAdditionalInformation('PaymentMethod', $this->_code) - ->setAdditionalInformation('use_saved_cc', true); - - return $this; - } - - $info->setCcType($data->getCcType()) - ->setCcOwner($data->getCcOwner()) - ->setCcLast4(substr($data->getCcNumber(), -4)) - ->setCcNumber($data->getCcNumber()) - ->setCcCid($data->getCcCid()) - ->setCcExpMonth($data->getCcExpMonth()) - ->setCcExpYear($data->getCcExpYear()) - ->setCcSsIssue($data->getCcSsIssue()) - ->setCcSsStartMonth($data->getCcSsStartMonth()) - ->setCcSsStartYear($data->getCcSsStartYear()) - ->setAdditionalInformation('PaymentMethod', $this->_code) - ->setAdditionalInformation('use_saved_cc', false); - - return $this; - } - - /** - * @param string $paymentAction - * @param object $stateObject - * - * @return bool|Mage_Payment_Model_Method_Abstract - */ - protected function processNewOrder($paymentAction, $stateObject) - { - $payment = $this->getInfoInstance(); - $order = $payment->getOrder(); - - $customer = Mage::getModel('customer/customer'); - - $customerId = $this->createCustomer($order, $customer); - $customerVindiId = $customer->getVindiUserCode(); - - if (!$payment->getAdditionalInformation('use_saved_cc')) { - $this->createPaymentProfile($customerId); - } else { - $this->assignDataFromPreviousPaymentProfile($customerVindiId); - } - - if ($this->isSingleOrder($order)) { - $result = $this->processSinglePayment($payment, $order, $customerId); - } else { - $result = $this->processSubscription($payment, $order, $customerId); - } - - if (!$result) { - return false; - } - - $billData = $this->api()->getBill($result); - $installments = $billData['installments']; - $response_fields = $billData['charges'][0]['last_transaction']['gateway_response_fields']; - $possible = ['nsu', 'proof_of_sale']; - $nsu = ''; - foreach ($possible as $nsu_field) { - if ($response_fields[$nsu_field]) { - $nsu = $response_fields[$nsu_field]; - } - } - - $this->getInfoInstance()->setAdditionalInformation( - [ - 'installments' => $installments, - 'nsu' => $nsu - ] - ); - - $stateObject->setStatus(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT) - ->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT); - - return $this; - } - - /** - * @param int $customerId - * - * @return array|bool - */ - protected function createPaymentProfile($customerId) - { - $payment = $this->getInfoInstance(); - - $creditCardData = [ - 'holder_name' => $payment->getCcOwner(), - 'card_expiration' => str_pad($payment->getCcExpMonth(), 2, '0', STR_PAD_LEFT) - . '/' . $payment->getCcExpYear(), - 'card_number' => $payment->getCcNumber(), - 'card_cvv' => $payment->getCcCid() ?: '000', - 'customer_id' => $customerId, - 'payment_company_code' => $payment->getCcType(), - 'payment_method_code' => $this->getPaymentMethodCode() - ]; - - $paymentProfile = $this->api()->createCustomerPaymentProfile($creditCardData); - - if ($paymentProfile === false) { - Mage::throwException('Erro ao informar os dados de cartão de crédito. Verifique os dados e tente novamente!'); - - return false; - } - - $verifyMethod = Mage::getStoreConfig('vindi_subscription/general/verify_method'); - - if ($verifyMethod && !$this->verifyPaymentProfile($paymentProfile['payment_profile']['id'])) { - Mage::throwException('Não foi possível realizar a verificação do seu cartão de crédito!'); - return false; - } - return $paymentProfile; - } - - /** - * @param int $paymentProfileId - * - * @return array|bool - */ - public function verifyPaymentProfile($paymentProfileId) - { - $verify_status = $this->api()->verifyCustomerPaymentProfile($paymentProfileId); - return ($verify_status['transaction']['status'] === 'success'); - } - - /** - * @param int $customerVindiId - */ - protected function assignDataFromPreviousPaymentProfile($customerVindiId) - { - $api = Mage::helper('vindi_subscription/api'); - $savedCc = $api->getCustomerPaymentProfile($customerVindiId); - $info = $this->getInfoInstance(); - - $info->setCcType($savedCc['payment_company']['code']) - ->setCcOwner($savedCc['holder_name']) - ->setCcLast4($savedCc['card_number_last_four']) - ->setCcNumber($savedCc['card_number_last_four']) - ->setAdditionalInformation('use_saved_cc', true); - } - - /** - * Check whether payment method can be used - * - * @param Mage_Sales_Model_Quote|null $quote - * - * @return bool - */ - public function isAvailable($quote = null) - { - return Mage::getStoreConfig('payment/vindi_creditcard/active') - && Mage::helper('vindi_subscription')->getKey(); - } - - /** - * Validate payment method information object - * - * @return Mage_Payment_Model_Method_Abstract - */ - public function validate() - { - $info = $this->getInfoInstance(); - - $quote = $info->getQuote(); - - $maxInstallmentsNumber = Mage::getStoreConfig('payment/vindi_creditcard/max_installments_number'); - - if ($this->isSingleOrder($quote) && ($maxInstallmentsNumber > 1)) { - if (!$installments = $info->getAdditionalInformation('installments')) { - return $this->error('Você deve informar o número de parcelas.'); - } - - if ($installments > $maxInstallmentsNumber) { - return $this->error('O número de parcelas selecionado é inválido.'); - } - - $minInstallmentsValue = Mage::getStoreConfig('payment/vindi_creditcard/min_installment_value'); - $installmentValue = ceil($quote->getGrandTotal() / $installments * 100) / 100; - - if (($installmentValue < $minInstallmentsValue) && ($installments > 1)) { - return $this->error('O número de parcelas selecionado é inválido.'); - } - } - - if ($info->getAdditionalInformation('use_saved_cc')) { - return $this; - } - - $availableTypes = $this->api()->getCreditCardTypes(); - - $ccNumber = $info->getCcNumber(); - - // remove credit card non-numbers - $ccNumber = preg_replace('/\D/', '', $ccNumber); - - $info->setCcNumber($ccNumber); - - if (!$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) { - return $this->error(Mage::helper('payment')->__('Incorrect credit card expiration date.')); - } - - if (!array_key_exists($info->getCcType(), $availableTypes)) { - return $this->error(Mage::helper('payment')->__('Credit card type is not allowed for this payment method.')); - } - - return $this; - } - - /** - * @param string $errorMsg - * - * @return bool - * @throws \Mage_Core_Exception - */ - private function error($errorMsg) - { - Mage::throwException($errorMsg); - - return false; - } - - /** - * @return string - */ - protected function getPaymentMethodCode() - { - // TODO fix it to proper method code - return 'credit_card'; - } -} diff --git a/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html b/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html deleted file mode 100644 index fdf6e030..00000000 --- a/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html +++ /dev/null @@ -1,107 +0,0 @@ -
- - -
-
-
-
    - -
  • -
  • - -
- -
-
-
- -
- -
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
- -
- -
- -
- - - -
-
-
- -
\ No newline at end of file From 4f7f874c7238fc22bb8daf9465b4643e2bfd736a Mon Sep 17 00:00:00 2001 From: leonardo albuquerque Date: Tue, 24 Jul 2018 16:50:57 -0300 Subject: [PATCH 05/37] =?UTF-8?q?#11177=20iniciado=20implementa=C3=A7?= =?UTF-8?q?=C3=A3o=20do=20checkout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/code/Vindi/Payment/Model/Api.php | 706 ++++++++++++++++++ .../Payment/Model/Payment/CreditCard.php | 325 ++++++++ .../Vindi/Payment/Model/Payment/Vindi.php | 307 +++++++- .../Vindi/Payment/etc/adminhtml/system.xml | 36 +- app/code/Vindi/Payment/etc/config.xml | 3 +- app/code/Vindi/Payment/etc/module.xml | 3 +- app/code/Vindi/Payment/etc/payment.xml | 3 +- .../frontend/layout/checkout_index_index.xml | 11 +- .../web/template/payment/cc-form.html | 107 +++ .../frontend/web/template/payment/vindi.html | 8 +- 10 files changed, 1492 insertions(+), 17 deletions(-) create mode 100644 app/code/Vindi/Payment/Model/Api.php create mode 100644 app/code/Vindi/Payment/Model/Payment/CreditCard.php create mode 100644 app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html diff --git a/app/code/Vindi/Payment/Model/Api.php b/app/code/Vindi/Payment/Model/Api.php new file mode 100644 index 00000000..7b36957b --- /dev/null +++ b/app/code/Vindi/Payment/Model/Api.php @@ -0,0 +1,706 @@ +scopeConfig = $scopeConfig; + $this->logger = $logger; + $this->cacheType = $cacheType; + $this->message = $message; + + $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; + $isSandBox = $this->scopeConfig->getValue('payment/vindi/sandboxmode', $storeScope); + + if ($isSandBox) { + $this->base_path = 'https://sandbox-app.vindi.com.br/api/v1/'; + } else { + $this->base_path = 'https://app.vindi.com.br/api/v1/'; + } + + $moduleInfo = $moduleList->getOne('Vindi_Payment'); + $this->version = $moduleInfo['setup_version']; + $this->key = $this->scopeConfig->getValue('payment/vindi/key', $storeScope); + } + + + public function execute(Observer $observer) + { + $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; + $notifyEmail = $this->scopeConfig->getValue(self::BASEPATH, $storeScope); + + echo $notifyEmail; + } + + /** + * @param string $message + * @param int|null $level + */ + private function log($message) + { + $this->logger->warning($message); + } + + /** + * @return \Zend_Cache_Core + */ + private function cache() + { + return $this->cacheType; + } + + /** + * Build HTTP Query. + * + * @param array $data + * + * @return string + */ + private function buildBody($data) + { + $body = null; + if (!empty($data)) { + $body = json_encode($data); + } + return $body; + } + + /** + * @param array $error + * @param $endpoint + * + * @return string + */ + private function getErrorMessage($error, $endpoint) + { + return "Erro em $endpoint: {$error['id']}: {$error['parameter']} - {$error['message']}"; + } + + /** + * @param array $response + * @param $endpoint + * + * @return bool + */ + private function checkResponse($response, $endpoint) + { + if (isset($response['errors']) && !empty($response['errors'])) { + foreach ($response['errors'] as $error) { + $message = $this->getErrorMessage($error, $endpoint); + $this->message->addErrorMessage($message); + $this->lastError = $message; + } + return false; + } + $this->lastError = ''; + return true; + } + + /** + * Perform request to API. + * + * @param string $endpoint + * @param string $method + * @param array $data + * @param null $dataToLog + * + * @return array|bool|mixed + */ + private function request($endpoint, $method = 'POST', $data = [], $dataToLog = null) + { + if (!$this->key) { + return false; + } + $url = $this->base_path . $endpoint; + $body = $this->buildBody($data); + $requestId = rand(); + $dataToLog = null !== $dataToLog ? $this->buildBody($dataToLog) : $body; + $this->log(sprintf("[Request #%s]: Novo Request para a API.\n%s %s\n%s", $requestId, $method, $url, + $dataToLog)); + $ch = curl_init(); + $ch_options = [ + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + ], + CURLOPT_TIMEOUT => 60, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_HEADER => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_USERAGENT => 'Vindi-Magento/' . $this->version, + CURLOPT_SSLVERSION => 'CURL_SSLVERSION_TLSv1_2', + CURLOPT_USERPWD => $this->key . ':', + CURLOPT_URL => $url, + CURLOPT_CUSTOMREQUEST => $method + ]; + if (!empty($body)) { + $ch_options[CURLOPT_POSTFIELDS] = $body; + } + curl_setopt_array($ch, $ch_options); + $response = curl_exec($ch); + $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $body = substr($response, curl_getinfo($ch, CURLINFO_HEADER_SIZE)); + if (curl_errno($ch) || $response === false) { + $this->log(sprintf("[Request #%s]: Erro ao fazer request!\n%s", $requestId, print_r($response, true))); + return false; + } + curl_close($ch); + $status = "HTTP Status: $statusCode"; + $this->log(sprintf("[Request #%s]: Nova Resposta da API.\n%s\n%s", $requestId, $status, $body)); + $responseBody = json_decode($body, true); + if (!$responseBody) { + $this->log(sprintf('[Request #%s]: Erro ao recuperar corpo do request! %s', $requestId, + print_r($body, true))); + return false; + } + if (!$this->checkResponse($responseBody, $endpoint)) { + return false; + } + return $responseBody; + } + + /** + * Make an API request to create a Customer. + * + * @param array $body (name, email, code) + * + * @return array|bool|mixed + */ + public function createCustomer($body) + { + if ($response = $this->request('customers', 'POST', $body)) { + return $response['customer']['id']; + } + return false; + } + + /** + * Make an API request to retrieve an existing Customer. + * + * @param string $code + * + * @return array|bool|mixed + */ + public function findCustomerByCode($code) + { + $customerId = $this->cache()->load("vindi_customer_by_code_{$code}"); + if ($customerId === false) { + $response = $this->request("customers/search?code={$code}", 'GET'); + if ($response && (1 === count($response['customers'])) && isset($response['customers'][0]['id'])) { + $customerId = $response['customers'][0]['id']; + $this->cache()->save(serialize($customerId), "vindi_customer_by_code_{$code}", ['vindi_cache'], + 5 * 60); // 5 minutes + } + } else { + $customerId = unserialize($customerId); + } + return $customerId; + } + + /** + * Make an API request to retrieve an existing Customer or to create one if not found. + * + * @param array $body (name, email, code) + * + * @return array|bool|mixed + */ + public function findOrCreateCustomer($body) + { + $customerId = $this->findCustomerByCode($body['code']); + // TODO update information + if (false === $customerId) { + return $this->createCustomer($body); + } + return $customerId; + } + + /** + * Make an API request to create a Payment Profile to a Customer. + * + * @param $body (holder_name, card_expiration, card_number, card_cvv, customer_id) + * + * @return array|bool|mixed + */ + public function createCustomerPaymentProfile($body) + { + // Protect credit card number. + $dataToLog = $body; + $dataToLog['card_number'] = '**** *' . substr($dataToLog['card_number'], -3); + $dataToLog['card_cvv'] = '***'; + $customerId = $body['customer_id']; + $this->cache()->remove("vindi_payment_profile_{$customerId}"); + return $this->request('payment_profiles', 'POST', $body, $dataToLog); + } + + /** + * Make an API request to verify a Payment Profile to a Customer. + * + * @param $id integer + * + * @return array|bool|mixed + */ + public function verifyCustomerPaymentProfile($id) + { + return $this->request('payment_profiles/' . $id . '/verify', 'POST'); + } + + /** + * @param $userCode + * + * @return bool + */ + public function getCustomerPaymentProfile($userCode, $type = "CreditCard") + { + $customerId = $this->findCustomerByCode($userCode); + if (false === $customerId) { + return false; + } + $paymentProfile = $this->cache()->load("vindi_payment_profile_{$customerId}"); + if ($paymentProfile === false || strpos($paymentProfile, $type) === false) { + $endpoint = 'payment_profiles?query=customer_id%3D' . $customerId + . '%20status%3Dactive%20type%3DPaymentProfile%3A%3A' . $type; + $response = $this->request($endpoint, 'GET'); + if ($response && $response['payment_profiles'] && count($response['payment_profiles'])) { + $paymentProfile = $response['payment_profiles'][0]; + $this->cache()->save(serialize($paymentProfile), "vindi_payment_profile_{$customerId}", ['vindi_cache'], + 5 * 60); // 5 minutes + } else { + $paymentProfile = false; + } + } else { + $paymentProfile = unserialize($paymentProfile); + } + return $paymentProfile; + } + + /** + * Make an API request to create a Subscription. + * + * @param $body (plan_id, customer_id, payment_method_code, product_items[{product_id}]) + * + * @return array + */ + public function createSubscription($body) + { + if (($response = $this->request('subscriptions', 'POST', $body)) && isset($response['subscription']['id'])) { + $subscription = $response['subscription']; + $subscription['bill'] = $response['bill']; + return $subscription; + } + return false; + } + + /** + * Make an API request to retrieve Payment Methods. + * + * @return array|bool + */ + public function getPaymentMethods() + { + $paymentMethods = $this->cache()->load('vindi_payment_methods'); + if ($paymentMethods === false) { + $paymentMethods = [ + 'credit_card' => [], + 'debit_card' => [], + 'bank_slip' => false, + ]; + $response = $this->request('payment_methods', 'GET'); + if (false === $response) { + return $this->acceptBankSlip = false; + } + foreach ($response['payment_methods'] as $method) { + if ('active' !== $method['status']) { + continue; + } + if ('PaymentMethod::CreditCard' === $method['type']) { + $paymentMethods['credit_card'] = array_merge( + $paymentMethods['credit_card'], + $method['payment_companies'] + ); + } elseif ('PaymentMethod::DebitCard' === $method['type']) { + $paymentMethods['debit_card'] = array_merge( + $paymentMethods['debit_card'], + $method['payment_companies'] + ); + } elseif ('PaymentMethod::BankSlip' === $method['type']) { + $paymentMethods['bank_slip'] = true; + } + } + $this->cache()->save(serialize($paymentMethods), 'vindi_payment_methods', ['vindi_cache'], + 12 * 60 * 60); // 12 hours + } else { + $paymentMethods = unserialize($paymentMethods); + } + $this->acceptBankSlip = $paymentMethods['bank_slip']; + return $paymentMethods; + } + + /** + * Retrieve Credit Card Types from Payment Methods. + * + * @return array + */ + public function getCreditCardTypes() + { + $methods = $this->getPaymentMethods(); + $types = []; + foreach ($methods['credit_card'] as $type) { + $types[$type['code']] = $type['name']; + } + return $types; + } + + /** + * Retrieve Debit Card Types from Payment Methods. + * + * @return array + */ + public function getDebitCardTypes() + { + $methods = $this->getPaymentMethods(); + $types = []; + foreach ($methods['debit_card'] as $type) { + $types[$type['code']] = $type['name']; + } + return $types; + } + + /** + * @return bool|null + */ + public function acceptBankSlip() + { + if (null === $this->acceptBankSlip) { + $this->getPaymentMethods(); + } + return $this->acceptBankSlip; + } + + /** + * @param array $body + * + * @return int|bool + */ + public function createBill($body) + { + if ($response = $this->request('bills', 'POST', $body)) { + return $response['bill']; + } + return false; + } + + /** + * @param $billId + * + * @return array|bool|mixed + */ + public function approveBill($billId) + { + $response = $this->request("bills/{$billId}", 'GET'); + if (false === $response || !isset($response['bill'])) { + return false; + } + $bill = $response['bill']; + if ('review' !== $bill['status']) { + return true; + } + return $this->request("bills/{$billId}/approve", 'POST'); + } + + /** + * @param $billId + */ + public function deleteBill($billId) + { + $this->request("bills/{$billId}", 'DELETE'); + } + + /** + * @param $billId + * + * @return string + */ + public function getBankSlipDownload($billId) + { + $response = $this->request("bills/{$billId}", 'GET'); + if (false === $response) { + return false; + } + return $response['bill']['charges'][0]['print_url']; + } + + /** + * @return array + */ + public function getProducts() + { + $list = []; + $response = $this->request('products?query=status:active', 'GET'); + if ($products = $response['products']) { + foreach ($products as $product) { + $list[$product['id']] = "{$product['name']} ({$product['pricing_schema']['short_format']})"; + } + } + return $list; + } + + /** + * @param int $id + * + * @return array + */ + public function getPlanItems($id) + { + $list = []; + $response = $this->request("plans/{$id}", 'GET'); + if ($plan = $response['plan']) { + foreach ($plan['plan_items'] as $item) { + if (isset($item['product'])) { + $list[] = $item['product']['id']; + } + } + } + return $list; + } + + /** + * @param Mage_Sales_Model_Order $order + * + * @return array + */ + public function buildPlanItemsForSubscription($order) + { + $list = []; + $orderItems = $order->getItemsCollection(); + $orderSubtotal = $order->getQuote()->getSubtotal(); + $orderDiscount = $order->getDiscountAmount() * -1; + $discount = null; + if (!empty($orderDiscount)) { + $discountPercentage = $orderDiscount * 100 / $orderSubtotal; + $discountPercentage = number_format(floor($discountPercentage * 100) / 100, 2); + $discount = [[ + 'discount_type' => 'percentage', + 'percentage' => $discountPercentage + ]]; + } + foreach ($orderItems as $item) { + $product = Mage::getModel('catalog/product')->load($item->getProductId()); + if ($product->getTypeID() !== 'subscription') { + throw new \Exception("O produto {$item->getName()} não é uma assinatura."); + return false; + } + $productVindiId = $this->findOrCreateProduct(array('sku' => $item->getSku(), 'name' => $item->getName())); + for ($i = 1; $i <= $item->getQtyOrdered(); $i++) { + $list[] = [ + 'product_id' => $productVindiId, + 'pricing_schema' => ['price' => $item->getPrice()], + 'discounts' => $discount, + ]; + } + } + // Create product for shipping + $productVindiId = $this->findOrCreateProduct(array('sku' => 'frete', 'name' => 'Frete')); + $list[] = [ + 'product_id' => $productVindiId, + 'pricing_schema' => ['price' => $order->getShippingAmount()], + ]; + return $list; + } + + /** + * @return array + */ + public function getPlans() + { + $list = $this->cache()->load('vindi_plans'); + if (($list === false) || !count($list = unserialize($list))) { + $list = []; + $response = $this->request('plans?query=status:active', 'GET'); + if ($plans = $response['plans']) { + foreach ($plans as $plan) { + $list[$plan['id']] = $plan['name']; + } + } + $this->cache()->save(serialize($list), 'vindi_plans', ['vindi_cache'], 10 * 60); // 10 minutes + } + return $list; + } + + public function getPlanInstallments($id) + { + $response = $this->request("plans/{$id}", 'GET'); + $plan = $response['plan']; + $installments = $plan['installments']; + return $installments; + } + + /** + * Make an API request to create a Product. + * + * @param array $body (name, code, status, pricing_schema (price)) + * + * @return array|bool|mixed + */ + public function createProduct($body) + { + if ($response = $this->request('products', 'POST', $body)) { + return $response['product']['id']; + } + return false; + } + + /** + * Make an API request to retrieve an existing Product. + * + * @param string $code + * + * @return array|bool|mixed + */ + public function findProductByCode($code) + { + $response = $this->request("products?query=code%3D{$code}", 'GET'); + if ($response && (1 === count($response['products'])) && isset($response['products'][0]['id'])) { + return $response['products'][0]['id']; + } + return false; + } + + /** + * Make an API request to retrieve the Unique Payment Product or to create it if not found. + * + * @return array|bool|mixed + */ + public function findOrCreateUniquePaymentProduct() + { + $productId = $this->findProductByCode('mag-pagtounico'); + if (false === $productId) { + return $this->createProduct([ + 'name' => 'Pagamento Único (não remover)', + 'code' => 'mag-pagtounico', + 'status' => 'active', + 'pricing_schema' => [ + 'price' => 0, + ], + ]); + } + return $productId; + } + + /** + * Make an API request to retrieve a Product or to create it if not found. + * @param array $product + * + * @return array|bool|mixed + */ + public function findOrCreateProduct($product) + { + // + $productId = $this->findProductByCode($product['sku']); + if (false === $productId) { + return $this->createProduct([ + 'name' => $product['name'], + 'code' => $product['sku'], + 'status' => 'active', + 'pricing_schema' => [ + 'price' => 0, + ], + ]); + } + return $productId; + } + + /** + * Make an API request to retrieve information about the Merchant. + * + * @return array|bool|mixed + */ + public function getMerchant() + { + $merchant = $this->cache()->load('vindi_merchant'); + if ($merchant === false) { + $response = $this->request('merchant', 'GET'); + if (!$response || !isset($response['merchant'])) { + return false; + } + $merchant = $response['merchant']; + $this->cache()->save(serialize($merchant), 'vindi_merchant', ['vindi_cache'], 1 * 60 * 60); // 1 hour + } else { + $merchant = unserialize($merchant); + } + return $merchant; + } + + /** + * Check to see if Merchant Status is Trial. + * + * @return boolean + */ + public function isMerchantStatusTrial() + { + if ($merchant = $this->getMerchant()) { + return 'trial' === $merchant['status']; + } + return false; + } + + /** + * @param $billId + * + * @return array|bool + */ + public function getBill($billId) + { + $response = $this->request("bills/{$billId}", 'GET'); + if (!$response || !isset($response['bill'])) { + return false; + } + return $response['bill']; + } + + public function getDebitCardRedirectUrl($billId) + { + $bill = $this->request('bills/' . $billId, 'GET'); + $chargeId = $bill['bill']['charges'][0]['id']; + $charged = $this->request('charges/' . $chargeId . '/charge', 'POST', [ + 'id' => $bill['bill']['payment_profile']['id'] + ]); + return $charged['charge']['last_transaction']['gateway_response_fields']['authorization_url']; + } +} \ No newline at end of file diff --git a/app/code/Vindi/Payment/Model/Payment/CreditCard.php b/app/code/Vindi/Payment/Model/Payment/CreditCard.php new file mode 100644 index 00000000..88b1ba8d --- /dev/null +++ b/app/code/Vindi/Payment/Model/Payment/CreditCard.php @@ -0,0 +1,325 @@ +getInfoInstance(); + $quote = $info->getQuote(); + + $info->setAdditionalInformation('installments', $data->getCcInstallments()); + + if ($data->getCcChoice() === 'saved') { + $info->setAdditionalInformation('PaymentMethod', $this->_code) + ->setAdditionalInformation('use_saved_cc', true); + + return $this; + } + + $info->setCcType($data->getCcType()) + ->setCcOwner($data->getCcOwner()) + ->setCcLast4(substr($data->getCcNumber(), -4)) + ->setCcNumber($data->getCcNumber()) + ->setCcCid($data->getCcCid()) + ->setCcExpMonth($data->getCcExpMonth()) + ->setCcExpYear($data->getCcExpYear()) + ->setCcSsIssue($data->getCcSsIssue()) + ->setCcSsStartMonth($data->getCcSsStartMonth()) + ->setCcSsStartYear($data->getCcSsStartYear()) + ->setAdditionalInformation('PaymentMethod', $this->_code) + ->setAdditionalInformation('use_saved_cc', false); + + return $this; + } + + /** + * @param string $paymentAction + * @param object $stateObject + * + * @return bool|Mage_Payment_Model_Method_Abstract + */ + protected function processNewOrder($paymentAction, $stateObject) + { + $payment = $this->getInfoInstance(); + $order = $payment->getOrder(); + + $customer = Mage::getModel('customer/customer'); + + $customerId = $this->createCustomer($order, $customer); + $customerVindiId = $customer->getVindiUserCode(); + + if (!$payment->getAdditionalInformation('use_saved_cc')) { + $this->createPaymentProfile($customerId); + } else { + $this->assignDataFromPreviousPaymentProfile($customerVindiId); + } + + if ($this->isSingleOrder($order)) { + $result = $this->processSinglePayment($payment, $order, $customerId); + } else { + $result = $this->processSubscription($payment, $order, $customerId); + } + + if (!$result) { + return false; + } + + $billData = $this->api()->getBill($result); + $installments = $billData['installments']; + $response_fields = $billData['charges'][0]['last_transaction']['gateway_response_fields']; + $possible = ['nsu', 'proof_of_sale']; + $nsu = ''; + foreach ($possible as $nsu_field) { + if ($response_fields[$nsu_field]) { + $nsu = $response_fields[$nsu_field]; + } + } + + $this->getInfoInstance()->setAdditionalInformation( + [ + 'installments' => $installments, + 'nsu' => $nsu + ] + ); + + $stateObject->setStatus(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT) + ->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT); + + return $this; + } + + /** + * @param int $customerId + * + * @return array|bool + */ + protected function createPaymentProfile($customerId) + { + $payment = $this->getInfoInstance(); + + $creditCardData = [ + 'holder_name' => $payment->getCcOwner(), + 'card_expiration' => str_pad($payment->getCcExpMonth(), 2, '0', STR_PAD_LEFT) + . '/' . $payment->getCcExpYear(), + 'card_number' => $payment->getCcNumber(), + 'card_cvv' => $payment->getCcCid() ?: '000', + 'customer_id' => $customerId, + 'payment_company_code' => $payment->getCcType(), + 'payment_method_code' => $this->getPaymentMethodCode() + ]; + + $paymentProfile = $this->api()->createCustomerPaymentProfile($creditCardData); + + if ($paymentProfile === false) { + Mage::throwException('Erro ao informar os dados de cartão de crédito. Verifique os dados e tente novamente!'); + + return false; + } + + $verifyMethod = Mage::getStoreConfig('vindi_subscription/general/verify_method'); + + if ($verifyMethod && !$this->verifyPaymentProfile($paymentProfile['payment_profile']['id'])) { + Mage::throwException('Não foi possível realizar a verificação do seu cartão de crédito!'); + return false; + } + return $paymentProfile; + } + + /** + * @param int $paymentProfileId + * + * @return array|bool + */ + public function verifyPaymentProfile($paymentProfileId) + { + $verify_status = $this->api()->verifyCustomerPaymentProfile($paymentProfileId); + return ($verify_status['transaction']['status'] === 'success'); + } + + /** + * @param int $customerVindiId + */ + protected function assignDataFromPreviousPaymentProfile($customerVindiId) + { + $api = Mage::helper('vindi_subscription/api'); + $savedCc = $api->getCustomerPaymentProfile($customerVindiId); + $info = $this->getInfoInstance(); + + $info->setCcType($savedCc['payment_company']['code']) + ->setCcOwner($savedCc['holder_name']) + ->setCcLast4($savedCc['card_number_last_four']) + ->setCcNumber($savedCc['card_number_last_four']) + ->setAdditionalInformation('use_saved_cc', true); + } + + /** + * Check whether payment method can be used + * + * @param Mage_Sales_Model_Quote|null $quote + * + * @return bool + */ + public function isAvailable($quote = null) + { + return Mage::getStoreConfig('payment/vindi_creditcard/active') + && Mage::helper('vindi_subscription')->getKey(); + } + + /** + * Validate payment method information object + * + * @return Mage_Payment_Model_Method_Abstract + */ + public function validate() + { + $info = $this->getInfoInstance(); + + $quote = $info->getQuote(); + + $maxInstallmentsNumber = Mage::getStoreConfig('payment/vindi_creditcard/max_installments_number'); + + if ($this->isSingleOrder($quote) && ($maxInstallmentsNumber > 1)) { + if (!$installments = $info->getAdditionalInformation('installments')) { + return $this->error('Você deve informar o número de parcelas.'); + } + + if ($installments > $maxInstallmentsNumber) { + return $this->error('O número de parcelas selecionado é inválido.'); + } + + $minInstallmentsValue = Mage::getStoreConfig('payment/vindi_creditcard/min_installment_value'); + $installmentValue = ceil($quote->getGrandTotal() / $installments * 100) / 100; + + if (($installmentValue < $minInstallmentsValue) && ($installments > 1)) { + return $this->error('O número de parcelas selecionado é inválido.'); + } + } + + if ($info->getAdditionalInformation('use_saved_cc')) { + return $this; + } + + $availableTypes = $this->api()->getCreditCardTypes(); + + $ccNumber = $info->getCcNumber(); + + // remove credit card non-numbers + $ccNumber = preg_replace('/\D/', '', $ccNumber); + + $info->setCcNumber($ccNumber); + + if (!$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) { + return $this->error(Mage::helper('payment')->__('Incorrect credit card expiration date.')); + } + + if (!array_key_exists($info->getCcType(), $availableTypes)) { + return $this->error(Mage::helper('payment')->__('Credit card type is not allowed for this payment method.')); + } + + return $this; + } + + /** + * @param string $errorMsg + * + * @return bool + * @throws \Mage_Core_Exception + */ + private function error($errorMsg) + { + Mage::throwException($errorMsg); + + return false; + } + + /** + * @return string + */ + protected function getPaymentMethodCode() + { + // TODO fix it to proper method code + return 'credit_card'; + } +} diff --git a/app/code/Vindi/Payment/Model/Payment/Vindi.php b/app/code/Vindi/Payment/Model/Payment/Vindi.php index cc3c19d1..b75a61a2 100644 --- a/app/code/Vindi/Payment/Model/Payment/Vindi.php +++ b/app/code/Vindi/Payment/Model/Payment/Vindi.php @@ -3,6 +3,10 @@ namespace Vindi\Payment\Model\Payment; +use Magento\Framework\DataObject; +use Magento\Quote\Api\Data\CartInterface; +use Vindi\Payment\Model\Api; + class Vindi extends \Magento\Payment\Model\Method\AbstractMethod { @@ -11,7 +15,308 @@ class Vindi extends \Magento\Payment\Model\Method\AbstractMethod public function isAvailable( \Magento\Quote\Api\Data\CartInterface $quote = null - ) { + ) + { return parent::isAvailable($quote); } + + /** + * @var bool + */ + protected $_isGateway = true; + + /** + * @var bool + */ + protected $_canAuthorize = true; + + /** + * @var bool + */ + protected $_canCapture = true; + + /** + * @var bool + */ + protected $_canCapturePartial = false; + + /** + * @var bool + */ + protected $_canRefund = false; + + /** + * @var bool + */ + protected $_canVoid = false; + + /** + * @var bool + */ + protected $_canUseInternal = true; + + /** + * @var bool + */ + protected $_canUseCheckout = true; + + /** + * @var bool + */ + protected $_canUseForMultishipping = false; + + /** + * @var bool + */ + protected $_isInitializeNeeded = true; + + /** + * @var bool + */ + protected $_canSaveCc = false; + + /** + * @var string + */ + protected $_formBlockType = 'vindi_subscription/form_cc'; + + /** + * @var string + */ + protected $_infoBlockType = 'vindi_subscription/info_cc'; + + /** + * Assign data to info model instance + * + * @param mixed $data + * + * @return Mage_Payment_Model_Method_Abstract + */ + public function assignData(DataObject $data) + { + if (!($data instanceof Varien_Object)) { + $data = new Varien_Object($data); + } + $info = $this->getInfoInstance(); + $quote = $info->getQuote(); + + $info->setAdditionalInformation('installments', $data->getCcInstallments()); + + if ($data->getCcChoice() === 'saved') { + $info->setAdditionalInformation('PaymentMethod', $this->_code) + ->setAdditionalInformation('use_saved_cc', true); + + return $this; + } + + $info->setCcType($data->getCcType()) + ->setCcOwner($data->getCcOwner()) + ->setCcLast4(substr($data->getCcNumber(), -4)) + ->setCcNumber($data->getCcNumber()) + ->setCcCid($data->getCcCid()) + ->setCcExpMonth($data->getCcExpMonth()) + ->setCcExpYear($data->getCcExpYear()) + ->setCcSsIssue($data->getCcSsIssue()) + ->setCcSsStartMonth($data->getCcSsStartMonth()) + ->setCcSsStartYear($data->getCcSsStartYear()) + ->setAdditionalInformation('PaymentMethod', $this->_code) + ->setAdditionalInformation('use_saved_cc', false); + + return $this; + } + + /** + * @param string $paymentAction + * @param object $stateObject + * + * @return bool|Mage_Payment_Model_Method_Abstract + */ + protected function processNewOrder($paymentAction, $stateObject) + { + $payment = $this->getInfoInstance(); + $order = $payment->getOrder(); + + $customer = Mage::getModel('customer/customer'); + + $customerId = $this->createCustomer($order, $customer); + $customerVindiId = $customer->getVindiUserCode(); + + if (!$payment->getAdditionalInformation('use_saved_cc')) { + $this->createPaymentProfile($customerId); + } else { + $this->assignDataFromPreviousPaymentProfile($customerVindiId); + } + + if ($this->isSingleOrder($order)) { + $result = $this->processSinglePayment($payment, $order, $customerId); + } else { + $result = $this->processSubscription($payment, $order, $customerId); + } + + if (!$result) { + return false; + } + + $billData = $this->api()->getBill($result); + $installments = $billData['installments']; + $response_fields = $billData['charges'][0]['last_transaction']['gateway_response_fields']; + $possible = ['nsu', 'proof_of_sale']; + $nsu = ''; + foreach ($possible as $nsu_field) { + if ($response_fields[$nsu_field]) { + $nsu = $response_fields[$nsu_field]; + } + } + + $this->getInfoInstance()->setAdditionalInformation( + [ + 'installments' => $installments, + 'nsu' => $nsu + ] + ); + + $stateObject->setStatus(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT) + ->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT); + + return $this; + } + + /** + * @param int $customerId + * + * @return array|bool + */ + protected function createPaymentProfile($customerId) + { + $payment = $this->getInfoInstance(); + + $creditCardData = [ + 'holder_name' => $payment->getCcOwner(), + 'card_expiration' => str_pad($payment->getCcExpMonth(), 2, '0', STR_PAD_LEFT) + . '/' . $payment->getCcExpYear(), + 'card_number' => $payment->getCcNumber(), + 'card_cvv' => $payment->getCcCid() ?: '000', + 'customer_id' => $customerId, + 'payment_company_code' => $payment->getCcType(), + 'payment_method_code' => $this->getPaymentMethodCode() + ]; + + $paymentProfile = $this->api()->createCustomerPaymentProfile($creditCardData); + + if ($paymentProfile === false) { + Mage::throwException('Erro ao informar os dados de cartão de crédito. Verifique os dados e tente novamente!'); + + return false; + } + + $verifyMethod = Mage::getStoreConfig('vindi_subscription/general/verify_method'); + + if ($verifyMethod && !$this->verifyPaymentProfile($paymentProfile['payment_profile']['id'])) { + Mage::throwException('Não foi possível realizar a verificação do seu cartão de crédito!'); + return false; + } + return $paymentProfile; + } + + /** + * @param int $paymentProfileId + * + * @return array|bool + */ + public function verifyPaymentProfile($paymentProfileId) + { + $verify_status = $this->api()->verifyCustomerPaymentProfile($paymentProfileId); + return ($verify_status['transaction']['status'] === 'success'); + } + + /** + * @param int $customerVindiId + */ + protected function assignDataFromPreviousPaymentProfile($customerVindiId) + { + $api = Mage::helper('vindi_subscription/api'); + $savedCc = $api->getCustomerPaymentProfile($customerVindiId); + $info = $this->getInfoInstance(); + + $info->setCcType($savedCc['payment_company']['code']) + ->setCcOwner($savedCc['holder_name']) + ->setCcLast4($savedCc['card_number_last_four']) + ->setCcNumber($savedCc['card_number_last_four']) + ->setAdditionalInformation('use_saved_cc', true); + } + + /** + * Validate payment method information object + * + * @return Mage_Payment_Model_Method_Abstract + */ + public function validate() + { + $info = $this->getInfoInstance(); + + $quote = $info->getQuote(); + + $maxInstallmentsNumber = Mage::getStoreConfig('payment/vindi_creditcard/max_installments_number'); + + if ($this->isSingleOrder($quote) && ($maxInstallmentsNumber > 1)) { + if (!$installments = $info->getAdditionalInformation('installments')) { + return $this->error('Você deve informar o número de parcelas.'); + } + + if ($installments > $maxInstallmentsNumber) { + return $this->error('O número de parcelas selecionado é inválido.'); + } + + $minInstallmentsValue = Mage::getStoreConfig('payment/vindi_creditcard/min_installment_value'); + $installmentValue = ceil($quote->getGrandTotal() / $installments * 100) / 100; + + if (($installmentValue < $minInstallmentsValue) && ($installments > 1)) { + return $this->error('O número de parcelas selecionado é inválido.'); + } + } + + if ($info->getAdditionalInformation('use_saved_cc')) { + return $this; + } + + $availableTypes = $this->api()->getCreditCardTypes(); + + $ccNumber = $info->getCcNumber(); + + // remove credit card non-numbers + $ccNumber = preg_replace('/\D/', '', $ccNumber); + + $info->setCcNumber($ccNumber); + + if (!$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) { + return $this->error(Mage::helper('payment')->__('Incorrect credit card expiration date.')); + } + + if (!array_key_exists($info->getCcType(), $availableTypes)) { + return $this->error(Mage::helper('payment')->__('Credit card type is not allowed for this payment method.')); + } + + return $this; + } + + /** + * @param string $errorMsg + * + * @return bool + * @throws \Mage_Core_Exception + */ + private function error($errorMsg) + { + Mage::throwException($errorMsg); + + return false; + } + + /** + * @return string + */ + protected function getPaymentMethodCode() + { + return 'credit_card'; + } } diff --git a/app/code/Vindi/Payment/etc/adminhtml/system.xml b/app/code/Vindi/Payment/etc/adminhtml/system.xml index 18e6dc33..7ee963c0 100644 --- a/app/code/Vindi/Payment/etc/adminhtml/system.xml +++ b/app/code/Vindi/Payment/etc/adminhtml/system.xml @@ -1,33 +1,53 @@ - +
- + Magento\Config\Model\Config\Source\Yesno - + - + + + + Magento\Config\Model\Config\Source\Yesno + + + + + + Magento\Sales\Model\Config\Source\Order\Status\NewStatus - + Magento\Payment\Model\Config\Source\Allspecificcountries - + Magento\Directory\Model\Config\Source\Country 1 - + - + diff --git a/app/code/Vindi/Payment/etc/config.xml b/app/code/Vindi/Payment/etc/config.xml index 17583699..334d01b2 100644 --- a/app/code/Vindi/Payment/etc/config.xml +++ b/app/code/Vindi/Payment/etc/config.xml @@ -1,5 +1,6 @@ - + diff --git a/app/code/Vindi/Payment/etc/module.xml b/app/code/Vindi/Payment/etc/module.xml index d9645236..a0b5b47b 100644 --- a/app/code/Vindi/Payment/etc/module.xml +++ b/app/code/Vindi/Payment/etc/module.xml @@ -1,4 +1,5 @@ - + diff --git a/app/code/Vindi/Payment/etc/payment.xml b/app/code/Vindi/Payment/etc/payment.xml index cbe2c415..6d8e26e9 100644 --- a/app/code/Vindi/Payment/etc/payment.xml +++ b/app/code/Vindi/Payment/etc/payment.xml @@ -1,5 +1,6 @@ - + diff --git a/app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml b/app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml index 01dbadc4..b25e49d5 100644 --- a/app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Vindi/Payment/view/frontend/layout/checkout_index_index.xml @@ -1,5 +1,6 @@ - + @@ -16,10 +17,14 @@ - Vindi_Payment/js/view/payment/vindi + + Vindi_Payment/js/view/payment/vindi + - true + true + diff --git a/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html b/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html new file mode 100644 index 00000000..fdf6e030 --- /dev/null +++ b/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html @@ -0,0 +1,107 @@ +
+ + +
+
+
+
    + +
  • +
  • + +
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+ +
+ +
+ + + +
+
+
+ +
\ No newline at end of file diff --git a/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html b/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html index cebbb9ac..4a4545be 100644 --- a/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html +++ b/app/code/Vindi/Payment/view/frontend/web/template/payment/vindi.html @@ -21,9 +21,14 @@ + +
+ +
+
- +
@@ -43,4 +48,3 @@
- \ No newline at end of file From 4df926c29bf580fb11838e4d077f8f83c42b1aa9 Mon Sep 17 00:00:00 2001 From: leonardo albuquerque Date: Tue, 24 Jul 2018 18:28:57 -0300 Subject: [PATCH 06/37] =?UTF-8?q?#11177=20iniciado=20cria=C3=A7=C3=A3o=20d?= =?UTF-8?q?a=20op=C3=A7=C3=A3o=20no=20carrinho?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/code/Vindi/Payment/i18n/pt_BR.csv | 1 + .../payment/method-renderer/vindi-method.js | 2 +- .../web/template/payment/cc-form.html | 23 ++++++++++--------- 3 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 app/code/Vindi/Payment/i18n/pt_BR.csv diff --git a/app/code/Vindi/Payment/i18n/pt_BR.csv b/app/code/Vindi/Payment/i18n/pt_BR.csv new file mode 100644 index 00000000..c5ef7807 --- /dev/null +++ b/app/code/Vindi/Payment/i18n/pt_BR.csv @@ -0,0 +1 @@ +'Credit Card Number', 'Cartão de Crédito' \ No newline at end of file diff --git a/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js index 51ab10f0..222cea6e 100644 --- a/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js +++ b/app/code/Vindi/Payment/view/frontend/web/js/view/payment/method-renderer/vindi-method.js @@ -1,6 +1,6 @@ define( [ - 'Magento_Checkout/js/view/payment/default' + 'Magento_Checkout/js/view/payment/default', ], function (Component) { 'use strict'; diff --git a/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html b/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html index fdf6e030..63f5ceb0 100644 --- a/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html +++ b/app/code/Vindi/Payment/view/frontend/web/template/payment/cc-form.html @@ -1,7 +1,8 @@
- -
+ Credit Card Information + +
    @@ -23,8 +24,8 @@
-
From 51e58514807f64be81dd2cae41b3933008c7b1a3 Mon Sep 17 00:00:00 2001 From: leonardo albuquerque Date: Tue, 14 Aug 2018 15:57:25 -0300 Subject: [PATCH 18/37] =?UTF-8?q?corrigido=20chamada=20da=20fun=C3=A7?= =?UTF-8?q?=C3=A3o=20createCustomer=20fix=20#30?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Model/Payment/Customer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Model/Payment/Customer.php b/Model/Payment/Customer.php index af6364e4..98b1aaa4 100644 --- a/Model/Payment/Customer.php +++ b/Model/Payment/Customer.php @@ -46,7 +46,7 @@ public function findOrCreate($order) 'address' => $address ]; - $customerId = $this->api->createCustomer($customerVindi); + $customerId = $this->createCustomer($customerVindi); if ($customerId === false) { $this->messageManager->addErrorMessage(__('Fail while registering the user. Verify data and try again')); @@ -65,7 +65,7 @@ public function findOrCreate($order) */ public function createCustomer($body) { - if ($response = $this->request('customers', 'POST', $body)) { + if ($response = $this->api->request('customers', 'POST', $body)) { return $response['customer']['id']; } From 329d88ea9f8f8ff463be265d9bea9617c964a95a Mon Sep 17 00:00:00 2001 From: Cristhian Silveira Silva Date: Fri, 26 Oct 2018 17:51:55 -0300 Subject: [PATCH 19/37] validation for existence of some payment method and validation of filling the token field in the configurations of the module --- Model/Payment/Api.php | 3 +++ Model/Payment/PaymentMethod.php | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Model/Payment/Api.php b/Model/Payment/Api.php index 555ac623..462a8860 100644 --- a/Model/Payment/Api.php +++ b/Model/Payment/Api.php @@ -28,6 +28,9 @@ public function __construct( public function request($endpoint, $method = 'POST', $data = [], $dataToLog = null) { + if (!$this->apiKey) { + return false; + } $url = $this->base_path . $endpoint; $body = json_encode($data); $requestId = number_format(microtime(true), 2, '', ''); diff --git a/Model/Payment/PaymentMethod.php b/Model/Payment/PaymentMethod.php index d8e81a48..da77a6d8 100644 --- a/Model/Payment/PaymentMethod.php +++ b/Model/Payment/PaymentMethod.php @@ -20,8 +20,10 @@ public function getCreditCardTypes() $methods = $this->get(); $types = []; - foreach ($methods['credit_card'] as $type) { - $types[$type['code']] = $type['name']; + if ($methods) { + foreach ($methods['credit_card'] as $type) { + $types[$type['code']] = $type['name']; + } } return $types; From c37b3c5b901d0231e8afa6c91b875a6a37fdb62e Mon Sep 17 00:00:00 2001 From: Gabriel Ranghetti Date: Fri, 17 May 2019 13:59:26 -0300 Subject: [PATCH 20/37] fix ApiKeyValidator Exception Phrase --- Model/Config/Backend/ApiKeyValidator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Model/Config/Backend/ApiKeyValidator.php b/Model/Config/Backend/ApiKeyValidator.php index 197aef81..52506cea 100644 --- a/Model/Config/Backend/ApiKeyValidator.php +++ b/Model/Config/Backend/ApiKeyValidator.php @@ -63,7 +63,7 @@ public function beforeSave() if ($value) { if (!$apiKey) { throw new \Magento\Framework\Exception\LocalizedException( - sprintf(__("The api key was not set on the module basic configuration")) + __("The api key was not set on the module basic configuration") ); } @@ -71,7 +71,7 @@ public function beforeSave() if (isset($data['merchant']['status']) && $data['merchant']['status'] != 'active') { throw new \Magento\Framework\Exception\LocalizedException( - sprintf(__("The api key is invalid or the merchant is inactive")) + __("The api key is invalid or the merchant is inactive") ); } } From da953907733778431628c9140698608b129ee083 Mon Sep 17 00:00:00 2001 From: Maico Date: Fri, 26 Jul 2019 17:39:22 -0300 Subject: [PATCH 21/37] =?UTF-8?q?Envia=20valores=20de=20desconto=20e=20acr?= =?UTF-8?q?=C3=A9scimos=20para=20a=20Vindi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Model/Payment/Product.php | 70 ++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/Model/Payment/Product.php b/Model/Payment/Product.php index 10b7db10..c8586e0d 100644 --- a/Model/Payment/Product.php +++ b/Model/Payment/Product.php @@ -17,6 +17,7 @@ public function __construct( public function findOrCreateProducts($order) { + $list = []; foreach ($order->getItems() as $item) { $productType = $item->getProduct()->getTypeId(); $vindiProductId = $this->findOrCreateProduct($item->getSku(), $item->getName(), $productType); @@ -27,20 +28,17 @@ public function findOrCreateProducts($order) if (false === $itemPrice) continue; - $list[] = [ + array_push($list, [ 'product_id' => $vindiProductId, 'amount' => $itemPrice - ]; + ]); } } - if ($order->getShippingAmount() > 0) { - $shippingId = $this->findOrCreateProduct('frete', 'frete'); - $list[] = [ - 'product_id' => $shippingId, - 'amount' => $order->getShippingAmount() - ]; - } + $list = $this->buildTax($list, $order); + $list = $this->buildDiscount($list, $order); + $list = $this->buildShipping($list, $order); + return $list; } @@ -52,6 +50,60 @@ private function getItemPrice($item, $productType) return $item->getPrice(); } + /** + * @param array $list + * @param $order + * @return array + */ + private function buildTax(array $list, $order) + { + if ($order->getTaxAmount() > 0) { + $productId = $this->findOrCreateProduct('taxa', 'taxa'); + array_push($list, [ + 'product_id' => $productId, + 'amount' => $order->getTaxAmount() + ]); + } + + return $list; + } + + /** + * @param $list + * @param $order + * @return array + */ + private function buildDiscount(array $list, $order) + { + if ($order->getDiscountAmount() < 0) { + $productId = $this->findOrCreateProduct('cupom', 'cupom'); + array_push($list, [ + 'product_id' => $productId, + 'amount' => $order->getDiscountAmount() + ]); + } + + return $list; + } + + /** + * @param array $list + * @param $order + * @return array + */ + private function buildShipping(array $list, $order) + { + if ($order->getShippingAmount() > 0) { + $productId = $this->findOrCreateProduct('frete', 'frete'); + array_push($list, [ + 'product_id' => $productId, + 'amount' => $order->getShippingAmount() + ]); + } + + return $list; + } + private function findOrCreateProduct($itemSku, $itemName, $itemType = 'simple') { $itemName = $itemType == 'configurable' ? $itemSku : $itemName; From 795c32af57e96099f82eeec7de6d290c756a4ae2 Mon Sep 17 00:00:00 2001 From: Maico da Silva Date: Mon, 29 Jul 2019 09:06:17 -0300 Subject: [PATCH 22/37] Update Model/Payment/Product.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Laerte Guimarães <31661772+laerte-guimaraes@users.noreply.github.com> --- Model/Payment/Product.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Payment/Product.php b/Model/Payment/Product.php index c8586e0d..0118f7fc 100644 --- a/Model/Payment/Product.php +++ b/Model/Payment/Product.php @@ -58,7 +58,7 @@ private function getItemPrice($item, $productType) private function buildTax(array $list, $order) { if ($order->getTaxAmount() > 0) { - $productId = $this->findOrCreateProduct('taxa', 'taxa'); + $productId = $this->findOrCreateProduct('taxa', 'Taxa'); array_push($list, [ 'product_id' => $productId, 'amount' => $order->getTaxAmount() From 021ceccb10af5705a777821088281deaf338912f Mon Sep 17 00:00:00 2001 From: Maico da Silva Date: Mon, 29 Jul 2019 09:06:31 -0300 Subject: [PATCH 23/37] Update Model/Payment/Product.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Laerte Guimarães <31661772+laerte-guimaraes@users.noreply.github.com> --- Model/Payment/Product.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Payment/Product.php b/Model/Payment/Product.php index 0118f7fc..6cb822dd 100644 --- a/Model/Payment/Product.php +++ b/Model/Payment/Product.php @@ -76,7 +76,7 @@ private function buildTax(array $list, $order) private function buildDiscount(array $list, $order) { if ($order->getDiscountAmount() < 0) { - $productId = $this->findOrCreateProduct('cupom', 'cupom'); + $productId = $this->findOrCreateProduct('cupom', 'Cupom de Desconto'); array_push($list, [ 'product_id' => $productId, 'amount' => $order->getDiscountAmount() From 3e0f7841690eea54b7db2d9aaec052f7733c5f02 Mon Sep 17 00:00:00 2001 From: Maico da Silva Date: Tue, 30 Jul 2019 10:51:37 -0300 Subject: [PATCH 24/37] Update Model/Payment/Product.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Laerte Guimarães <31661772+laerte-guimaraes@users.noreply.github.com> --- Model/Payment/Product.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Payment/Product.php b/Model/Payment/Product.php index 6cb822dd..020a4c3c 100644 --- a/Model/Payment/Product.php +++ b/Model/Payment/Product.php @@ -25,7 +25,7 @@ public function findOrCreateProducts($order) for ($i = 0; $i < $item->getQtyOrdered(); $i++) { $itemPrice = $this->getItemPrice($item, $productType); - if (false === $itemPrice) + if (! $itemPrice) continue; array_push($list, [ From 88851a7cd2cefda710a845c99d3bd851d14363c9 Mon Sep 17 00:00:00 2001 From: Yauari Vieira Date: Thu, 15 Aug 2019 17:43:40 -0300 Subject: [PATCH 25/37] Inicio dos testes de cupons, taxas e frete --- Test/Unit/OrderTest.php | 160 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 Test/Unit/OrderTest.php diff --git a/Test/Unit/OrderTest.php b/Test/Unit/OrderTest.php new file mode 100644 index 00000000..20533ecb --- /dev/null +++ b/Test/Unit/OrderTest.php @@ -0,0 +1,160 @@ +objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->customerRepositoryInterface = $this->getMockBuilder(\Magento\Customer\Api\CustomerRepositoryInterface::class)->disableOriginalConstructor()->getMock(); + $this->managerInterface = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class)->disableOriginalConstructor()->getMock(); + } + + public function testOrderWithTax() + { + $vindiProductId = 'taxa'; + $amount = 1.00; + + $order = $this->createOrderMock($amount, 0.00, 0.00); + $list = $this->createVindiProductMock($vindiProductId)->findOrCreateProducts($order); + + $this->makeAssertions($list, $vindiProductId, $amount); + } + + public function testOrderWithDiscount() + { + $vindiProductId = 'cupom'; + $amount = -5.00; + + $order = $this->createOrderMock(0.00, $amount, 0.00); + $list = $this->createVindiProductMock($vindiProductId)->findOrCreateProducts($order); + + $this->makeAssertions($list, $vindiProductId, $amount); + } + + public function testOrderWithShipping() + { + $vindiProductId = 'frete'; + $amount = 10.00; + + $order = $this->createOrderMock(0.00, 0.00, $amount); + $list = $this->createVindiProductMock($vindiProductId)->findOrCreateProducts($order); + + $this->makeAssertions($list, $vindiProductId, $amount); + } + + private function makeAssertions($list, $vindiProductId, $amount) + { + $this->assertContains('fake_sku', $list[0]['product_id'], '', true); + $this->assertEquals('9.99', $list[0]['amount']); + + $this->assertEquals($vindiProductId, $list[1]['product_id']); + $this->assertEquals($amount, $list[1]['amount']); + + return true; + } + + private function createApiMock($desiredTestResponse = null) + { + $apiMock = $this->getMockBuilder(\Vindi\Payment\Model\Payment\Api::class) + ->disableOriginalConstructor() + ->getMock(); + + $apiMock->method('request') + ->willReturn( + [ + 'products' => [ + 0 => [ + 'id' => 'fake_sku_123' + ] + ], + 'product' => [ + 'id' => $desiredTestResponse + ] + ]); + + return $apiMock; + } + + private function createVindiProductMock($desiredTestResponse) + { + $product = $this->objectManager->getObject(\Vindi\Payment\Model\Payment\Product::class, [ + 'customerRepository' => $this->customerRepositoryInterface, + 'api' => $this->createApiMock($desiredTestResponse), + 'messageManager' => $this->managerInterface + ]); + + return $product; + } + + private function createOrderMock( + $orderTaxAmount = 0.00, $orderDiscountAmount = 0.00, $orderShippingAmount = 0.00, + $itemQty = 1, $itemType = 'simple', $itemPrice = 9.99 + ) + { + $orderMock = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->getMock(); + + $items = [ + $this->createItemMock($itemQty, $itemType, $itemPrice) + ]; + + $orderMock->method('getItems') + ->willReturn($items); + + $orderMock->method('getTaxAmount') + ->willReturn($orderTaxAmount); + + $orderMock->method('getDiscountAmount') + ->willReturn($orderDiscountAmount); + + $orderMock->method('getShippingAmount') + ->willReturn($orderShippingAmount); + + return $orderMock; + } + + private function createItemMock($qty = 1, $type = 'simple', $price = 10.99) + { + $itemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) + ->disableOriginalConstructor() + ->getMock(); + + $itemMock->method('getQtyOrdered') + ->willReturn($qty); + + $itemMock->method('getSku') + ->willReturn('FAKE_SKU_'. rand(1000, 10000)); + + $itemMock->method('getName') + ->willReturn('FAKE_NAME_'. rand(1000, 10000)); + + $itemMock->method('getPrice') + ->willReturn($price); + + $itemMock->method('getProduct') + ->willReturn($this->createProductMock($type)); + + return $itemMock; + } + + private function createProductMock($type) + { + $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + + $productMock->method('getTypeId') + ->willReturn($type); + + return $productMock; + } + +} \ No newline at end of file From d753896ed0418c70f0839c94985664d8e79dd9ec Mon Sep 17 00:00:00 2001 From: Yauari Vieira Date: Fri, 16 Aug 2019 08:40:06 -0300 Subject: [PATCH 26/37] =?UTF-8?q?Corre=C3=A7=C3=B5es=20nos=20mocks=20das?= =?UTF-8?q?=20respostas=20esperadas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Test/Unit/OrderTest.php | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Test/Unit/OrderTest.php b/Test/Unit/OrderTest.php index 20533ecb..9483831e 100644 --- a/Test/Unit/OrderTest.php +++ b/Test/Unit/OrderTest.php @@ -47,7 +47,7 @@ public function testOrderWithShipping() $list = $this->createVindiProductMock($vindiProductId)->findOrCreateProducts($order); $this->makeAssertions($list, $vindiProductId, $amount); - } + } private function makeAssertions($list, $vindiProductId, $amount) { @@ -66,18 +66,24 @@ private function createApiMock($desiredTestResponse = null) ->disableOriginalConstructor() ->getMock(); + $requestResponses = []; + + $requestResponses[] = [ + 'product' => [ + 'id' => 'fake_sku' + ] + ]; + + $requestResponses[] = [ + 'products' => [ + 0 => [ + 'id' => $desiredTestResponse + ] + ] + ]; + $apiMock->method('request') - ->willReturn( - [ - 'products' => [ - 0 => [ - 'id' => 'fake_sku_123' - ] - ], - 'product' => [ - 'id' => $desiredTestResponse - ] - ]); + ->willReturnOnConsecutiveCalls(false, $requestResponses[0], $requestResponses[1]); return $apiMock; } @@ -131,10 +137,10 @@ private function createItemMock($qty = 1, $type = 'simple', $price = 10.99) ->willReturn($qty); $itemMock->method('getSku') - ->willReturn('FAKE_SKU_'. rand(1000, 10000)); + ->willReturn('FAKE_SKU'); $itemMock->method('getName') - ->willReturn('FAKE_NAME_'. rand(1000, 10000)); + ->willReturn('FAKE_NAME'); $itemMock->method('getPrice') ->willReturn($price); From eeaf8593546df23c83cbb343fae48bfb03652645 Mon Sep 17 00:00:00 2001 From: Yauari Vieira Date: Fri, 16 Aug 2019 12:23:08 -0300 Subject: [PATCH 27/37] Trocar o nome da classe --- Test/Unit/OrderTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Test/Unit/OrderTest.php b/Test/Unit/OrderTest.php index 9483831e..4fb47180 100644 --- a/Test/Unit/OrderTest.php +++ b/Test/Unit/OrderTest.php @@ -1,8 +1,8 @@ Date: Fri, 16 Aug 2019 12:27:24 -0300 Subject: [PATCH 28/37] =?UTF-8?q?Testes=20nas=20mudan=C3=A7as=20de=20statu?= =?UTF-8?q?s=20para=20pedidos=20com=20boletos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Test/Unit/StatusTest.php | 158 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 Test/Unit/StatusTest.php diff --git a/Test/Unit/StatusTest.php b/Test/Unit/StatusTest.php new file mode 100644 index 00000000..8ba9405c --- /dev/null +++ b/Test/Unit/StatusTest.php @@ -0,0 +1,158 @@ +objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->context = $this->getMockBuilder(\Magento\Framework\App\Helper\Context::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->scopeConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + } + + public function testGetStatusToOrderCompleteWithNoStatusConfigured() + { + $this->scopeConfigMock->method('getValue') + ->willReturn(null); + + $this->context->method('getScopeConfig') + ->willReturn($this->scopeConfigMock); + + $helper = $this->objectManager->getObject(\Vindi\Payment\Helper\Data::class, [ + 'context' => $this->context + ]); + + $this->assertEquals(Order::STATE_PROCESSING, $helper->getStatusToOrderComplete()); + } + + public function testGetStatusToOrderCompleteWithPendingStatusConfigured() + { + $this->scopeConfigMock->method('getValue') + ->willReturn('pending'); + + $this->context->method('getScopeConfig') + ->willReturn($this->scopeConfigMock); + + $helper = $this->objectManager->getObject(\Vindi\Payment\Helper\Data::class, [ + 'context' => $this->context + ]); + + $this->assertEquals('pending', $helper->getStatusToOrderComplete()); + } + + public function testSetProcessingOrderStatusOnPlaceCreditCard() + { + $helperMock = $this->getMockBuilder(\Vindi\Payment\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + + $helperMock->method('getStatusToOrderComplete') + ->willReturn(Order::STATE_PROCESSING); + + $plugin = $this->objectManager->getObject(\Vindi\Payment\Plugin\SetOrderStatusOnPlace::class, [ + 'helperData' => $helperMock + ]); + + $paymentMock = $this->createPaymentMock(); + $result = $plugin->afterPlace($paymentMock, 'Expected Result'); + + $this->assertEquals('Expected Result', $result); + $this->assertEquals($paymentMock->getOrder()->getState(), 'new'); + $this->assertEquals(Order::STATE_PROCESSING, $paymentMock->getOrder()->getStatus()); + } + + public function testSetPendingOrderStatusOnPlaceCreditCard() + { + $helperMock = $this->getMockBuilder(\Vindi\Payment\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + + $helperMock->method('getStatusToOrderComplete') + ->willReturn('pending'); + + $plugin = $this->objectManager->getObject(\Vindi\Payment\Plugin\SetOrderStatusOnPlace::class, [ + 'helperData' => $helperMock + ]); + + $paymentMock = $this->createPaymentMock(); + $result = $plugin->afterPlace($paymentMock, 'Expected Result'); + + $this->assertEquals('Expected Result', $result); + $this->assertEquals($paymentMock->getOrder()->getState(), 'new'); + $this->assertEquals('pending', $paymentMock->getOrder()->getStatus()); + } + + public function testSetPendingOrderStatusOnPlaceSlip() + { + $helperMock = $this->getMockBuilder(\Vindi\Payment\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + + $helperMock->method('getStatusToOrderComplete') + ->willReturn('pending'); + + $plugin = $this->objectManager->getObject(\Vindi\Payment\Plugin\SetOrderStatusOnPlace::class, [ + 'helperData' => $helperMock + ]); + + $paymentMock = $this->createPaymentMock(); + $result = $plugin->afterPlace($paymentMock, 'Expected Result'); + + $this->assertEquals('Expected Result', $result); + $this->assertEquals($paymentMock->getOrder()->getState(), 'new'); + $this->assertEquals('pending', $paymentMock->getOrder()->getStatus()); + } + + private function createPaymentMock() + { + $paymentMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class) + ->disableOriginalConstructor() + ->getMock(); + + $paymentMock->method('getOrder') + ->willReturn($this->createOrderMock()); + + $paymentMock->method('getMethod') + ->willReturnOnConsecutiveCalls( + \Vindi\Payment\Model\Payment\Vindi::CODE, + \Vindi\Payment\Model\Payment\Vindi::CODE, + \Vindi\Payment\Model\Payment\BankSlip::CODE + ); + + return $paymentMock; + } + + private function createOrderMock() + { + $orderMock = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->setMethods(array('getState', 'setState', 'addCommentToStatusHistory')) + ->getMock(); + + $orderMock->method('getState') + ->willReturn('new'); + + $orderMock->method('setState') + ->willReturn($orderMock); + + $orderMock->method('addCommentToStatusHistory') + ->willReturn($orderMock); + + return $orderMock; + } + +} \ No newline at end of file From 36f9a349a1e402245a5bc576b0a1f6d7260db36b Mon Sep 17 00:00:00 2001 From: Yauari Vieira Date: Fri, 16 Aug 2019 14:45:25 -0300 Subject: [PATCH 29/37] Testes nos status dos pedidos de acordo com os meios de pagamento --- Test/Unit/StatusTest.php | 154 ++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 75 deletions(-) diff --git a/Test/Unit/StatusTest.php b/Test/Unit/StatusTest.php index 8ba9405c..5ddcf59d 100644 --- a/Test/Unit/StatusTest.php +++ b/Test/Unit/StatusTest.php @@ -8,113 +8,124 @@ class StatusTest extends \PHPUnit\Framework\TestCase { protected $objectManager; - protected $context; - protected $scopeConfigMock; + protected $paymentMock; public function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - - $this->context = $this->getMockBuilder(\Magento\Framework\App\Helper\Context::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->scopeConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $this->paymentMock = $this->createPaymentMock(); } public function testGetStatusToOrderCompleteWithNoStatusConfigured() { - $this->scopeConfigMock->method('getValue') - ->willReturn(null); - - $this->context->method('getScopeConfig') - ->willReturn($this->scopeConfigMock); - - $helper = $this->objectManager->getObject(\Vindi\Payment\Helper\Data::class, [ - 'context' => $this->context - ]); - - $this->assertEquals(Order::STATE_PROCESSING, $helper->getStatusToOrderComplete()); + $this->assertEquals(Order::STATE_PROCESSING, $this->createHelperObjectManager(null)->getStatusToOrderComplete()); } public function testGetStatusToOrderCompleteWithPendingStatusConfigured() { - $this->scopeConfigMock->method('getValue') - ->willReturn('pending'); - - $this->context->method('getScopeConfig') - ->willReturn($this->scopeConfigMock); + $this->assertEquals('pending', $this->createHelperObjectManager('pending')->getStatusToOrderComplete()); + } - $helper = $this->objectManager->getObject(\Vindi\Payment\Helper\Data::class, [ - 'context' => $this->context - ]); + public function testSetProcessingOrderStatusOnPlaceCreditCard() + { + $this->paymentMock->method('getMethod') + ->willReturn( + \Vindi\Payment\Model\Payment\Vindi::CODE + ); + + $result = $this->createPluginObjectManager(Order::STATE_PROCESSING)->afterPlace($this->paymentMock, 'Expected Result'); - $this->assertEquals('pending', $helper->getStatusToOrderComplete()); + $this->assertEquals('Expected Result', $result); + $this->assertEquals($this->paymentMock->getOrder()->getState(), 'new'); + $this->assertEquals(Order::STATE_PROCESSING, $this->paymentMock->getOrder()->getStatus()); } - public function testSetProcessingOrderStatusOnPlaceCreditCard() + public function testSetPendingOrderStatusOnPlaceCreditCard() { - $helperMock = $this->getMockBuilder(\Vindi\Payment\Helper\Data::class) - ->disableOriginalConstructor() - ->getMock(); + $this->paymentMock->method('getMethod') + ->willReturn( + \Vindi\Payment\Model\Payment\Vindi::CODE + ); - $helperMock->method('getStatusToOrderComplete') - ->willReturn(Order::STATE_PROCESSING); + $result = $this->createPluginObjectManager('pending')->afterPlace($this->paymentMock, 'Expected Result'); - $plugin = $this->objectManager->getObject(\Vindi\Payment\Plugin\SetOrderStatusOnPlace::class, [ - 'helperData' => $helperMock - ]); + $this->assertEquals('Expected Result', $result); + $this->assertEquals($this->paymentMock->getOrder()->getState(), 'new'); + $this->assertEquals('pending', $this->paymentMock->getOrder()->getStatus()); + } + + public function testSetPendingOrderStatusOnPlaceSlip() + { + $this->paymentMock->method('getMethod') + ->willReturn( + \Vindi\Payment\Model\Payment\BankSlip::CODE + ); - $paymentMock = $this->createPaymentMock(); - $result = $plugin->afterPlace($paymentMock, 'Expected Result'); + $result = $this->createPluginObjectManager('pending')->afterPlace($this->paymentMock, 'Expected Result'); $this->assertEquals('Expected Result', $result); - $this->assertEquals($paymentMock->getOrder()->getState(), 'new'); - $this->assertEquals(Order::STATE_PROCESSING, $paymentMock->getOrder()->getStatus()); + $this->assertEquals($this->paymentMock->getOrder()->getState(), 'new'); + $this->assertEquals('pending', $this->paymentMock->getOrder()->getStatus()); } - public function testSetPendingOrderStatusOnPlaceCreditCard() - { - $helperMock = $this->getMockBuilder(\Vindi\Payment\Helper\Data::class) - ->disableOriginalConstructor() - ->getMock(); + public function testSetPendingOrderStatusOnPlaceSlip2() + { + $this->paymentMock->method('getMethod') + ->willReturn( + \Vindi\Payment\Model\Payment\BankSlip::CODE + ); - $helperMock->method('getStatusToOrderComplete') - ->willReturn('pending'); + $result = $this->createPluginObjectManager('other')->afterPlace($this->paymentMock, 'Expected Result'); - $plugin = $this->objectManager->getObject(\Vindi\Payment\Plugin\SetOrderStatusOnPlace::class, [ - 'helperData' => $helperMock - ]); + $this->assertEquals('Expected Result', $result); + $this->assertEquals($this->paymentMock->getOrder()->getState(), 'new'); + $this->assertEquals('pending', $this->paymentMock->getOrder()->getStatus()); + } - $paymentMock = $this->createPaymentMock(); - $result = $plugin->afterPlace($paymentMock, 'Expected Result'); + private function createHelperObjectManager($context) + { + return $this->objectManager->getObject(\Vindi\Payment\Helper\Data::class, [ + 'context' => $this->createContextMock($context) + ]); + } - $this->assertEquals('Expected Result', $result); - $this->assertEquals($paymentMock->getOrder()->getState(), 'new'); - $this->assertEquals('pending', $paymentMock->getOrder()->getStatus()); + private function createPluginObjectManager($status) + { + return $this->objectManager->getObject(\Vindi\Payment\Plugin\SetOrderStatusOnPlace::class, [ + 'helperData' => $this->createHelperMock($status) + ]); } - public function testSetPendingOrderStatusOnPlaceSlip() + private function createHelperMock($statusToOrderComplete) { $helperMock = $this->getMockBuilder(\Vindi\Payment\Helper\Data::class) ->disableOriginalConstructor() ->getMock(); $helperMock->method('getStatusToOrderComplete') - ->willReturn('pending'); + ->willReturn($statusToOrderComplete); + + return $helperMock; + } - $plugin = $this->objectManager->getObject(\Vindi\Payment\Plugin\SetOrderStatusOnPlace::class, [ - 'helperData' => $helperMock - ]); + private function createContextMock($expectedValue) + { + $contextMock = $this->getMockBuilder(\Magento\Framework\App\Helper\Context::class) + ->disableOriginalConstructor() + ->getMock(); + + $scopeConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); - $paymentMock = $this->createPaymentMock(); - $result = $plugin->afterPlace($paymentMock, 'Expected Result'); - $this->assertEquals('Expected Result', $result); - $this->assertEquals($paymentMock->getOrder()->getState(), 'new'); - $this->assertEquals('pending', $paymentMock->getOrder()->getStatus()); + $scopeConfigMock->method('getValue') + ->willReturn($expectedValue); + + $contextMock->method('getScopeConfig') + ->willReturn($scopeConfigMock); + + return $contextMock; } private function createPaymentMock() @@ -126,13 +137,6 @@ private function createPaymentMock() $paymentMock->method('getOrder') ->willReturn($this->createOrderMock()); - $paymentMock->method('getMethod') - ->willReturnOnConsecutiveCalls( - \Vindi\Payment\Model\Payment\Vindi::CODE, - \Vindi\Payment\Model\Payment\Vindi::CODE, - \Vindi\Payment\Model\Payment\BankSlip::CODE - ); - return $paymentMock; } From 6da4ea7787edae46530be77846caef64dfb87c15 Mon Sep 17 00:00:00 2001 From: Yauari Vieira Date: Thu, 22 Aug 2019 14:18:34 -0300 Subject: [PATCH 30/37] Ajustes nos testes para conformidade com PR 55 --- Test/Unit/StatusTest.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/Test/Unit/StatusTest.php b/Test/Unit/StatusTest.php index 5ddcf59d..46fbb141 100644 --- a/Test/Unit/StatusTest.php +++ b/Test/Unit/StatusTest.php @@ -37,7 +37,7 @@ public function testSetProcessingOrderStatusOnPlaceCreditCard() $this->assertEquals('Expected Result', $result); $this->assertEquals($this->paymentMock->getOrder()->getState(), 'new'); - $this->assertEquals(Order::STATE_PROCESSING, $this->paymentMock->getOrder()->getStatus()); + $this->assertEquals('pending', $this->paymentMock->getOrder()->getStatus()); } public function testSetPendingOrderStatusOnPlaceCreditCard() @@ -68,20 +68,6 @@ public function testSetPendingOrderStatusOnPlaceSlip() $this->assertEquals('pending', $this->paymentMock->getOrder()->getStatus()); } - public function testSetPendingOrderStatusOnPlaceSlip2() - { - $this->paymentMock->method('getMethod') - ->willReturn( - \Vindi\Payment\Model\Payment\BankSlip::CODE - ); - - $result = $this->createPluginObjectManager('other')->afterPlace($this->paymentMock, 'Expected Result'); - - $this->assertEquals('Expected Result', $result); - $this->assertEquals($this->paymentMock->getOrder()->getState(), 'new'); - $this->assertEquals('pending', $this->paymentMock->getOrder()->getStatus()); - } - private function createHelperObjectManager($context) { return $this->objectManager->getObject(\Vindi\Payment\Helper\Data::class, [ From 135228333b10df940741cabf33e2e564ff4a5978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laerte=20Guimar=C3=A3es?= <31661772+laerte-guimaraes@users.noreply.github.com> Date: Thu, 29 Aug 2019 13:01:23 -0300 Subject: [PATCH 31/37] =?UTF-8?q?Insere=20informa=C3=A7=C3=B5es=20de=20Tes?= =?UTF-8?q?te?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0b537532..e4140b00 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,12 +17,9 @@ Nós valorizamos muito as [**contribuições por Pull Requests (PR)**](https://g - **Clareza** - Além de uma boa descrição sobre a motivação e a solução proposta é possível incluir imagens ou animações que demonstrem quaisquer modificações visuais na interface. Exemplo de **Motivação** com uma **Solução Proposta**: -> Motivação - +> #### Motivação > Fazer com que o pedido seja cancelado, caso o pagamento seja reprovado na primeira tentativa (compras avulsas ou primeiro ciclo de uma assinatura), mas atualmente o cliente recebe a informação que o pedido foi registrado com sucesso, e posteriormente recebe a informação de falha no pagamento no Magento. - -> Solução proposta - +> #### Solução proposta > Adicionar o cancelamento automático de faturas na Vindi após a recusa de uma transação no Magento2, exceto: compras via Boleto ou pendente de revisões do Antifraude. - **Foco** - Um PR deve possuir um único objetivo bem definido. Evite mais de um viés (bug-fix, feature, refactoring) no mesmo PR. @@ -58,6 +55,19 @@ Obs.: Gostamos muito do [PSR-1](https://www.php-fig.org/psr/psr-1/) e [PSR-2](ht 4. [Abra um Pull Request](https://help.github.com/articles/using-pull-requests/) com uma motivação e solução proposta bem claras. +## Qualidade do código + +Para garantir o controle da qualidade do código, disponibilizamos alguns testes via [PHPUnit](https://phpunit.de/) em [Test/Unit](https://github.com/vindi/vindi-magento2/tree/master/Test/Unit). + +#### Se você nunca utilizou o composer, seja bem vindo :tada: :smile: [Aqui está o link do composer](https://getcomposer.org/download/), depois instale as dependências do composer.json. + +#### Se você nunca rodou testes funcionais com PHPUnit, seja bem vindo :tada: :smile: [Aqui está o link da documentação oficial](https://phpunit.readthedocs.io/pt_BR/latest). + +### Rodando os Testes + +``` bash +./vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist app/code/Vindi/Payment +``` ## Revisão da Comunidade From 4b9ef6f9bd8f4db92d6a0c87231c263ebab157c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laerte=20Guimar=C3=A3es?= <31661772+laerte-guimaraes@users.noreply.github.com> Date: Thu, 29 Aug 2019 13:07:24 -0300 Subject: [PATCH 32/37] Ajusta link de download --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebccc1d1..d30608be 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ A integração do módulo da Vindi permite criação e gestão de planos e assin #### Via [git](https://github.com) - Vá até o diretório raíz do Magento e adicione o módulo -> `git clone git@github.com:vindi/vindi-magento2.git app/code/Vindi/Payment/` +> `git clone https://github.com/vindi/vindi-magento2.git app/code/Vindi/Payment/` - Atualize os módulos disponíveis do Magento > `bin/magento setup:upgrade` - O módulo **Vindi_Payment** deverá ser exibido na lista de módulos do Magento From d117f48b5bc37fbab75595572530be2af6c1ab2a Mon Sep 17 00:00:00 2001 From: Maico Date: Sat, 23 May 2020 18:45:11 -0300 Subject: [PATCH 33/37] Atualizando o status da assinatura no Magento --- Helper/WebHookHandlers/Subscription.php | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Helper/WebHookHandlers/Subscription.php b/Helper/WebHookHandlers/Subscription.php index a98d65fb..51fb4c37 100644 --- a/Helper/WebHookHandlers/Subscription.php +++ b/Helper/WebHookHandlers/Subscription.php @@ -6,6 +6,7 @@ use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\OrderFactory; use Psr\Log\LoggerInterface; /** @@ -26,21 +27,28 @@ class Subscription * @var SearchCriteriaBuilder */ private $searchCriteriaBuilder; + /** + * @var OrderFactory + */ + private $orderFactory; /** * Subscription constructor. * @param OrderRepositoryInterface $orderRepository * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param OrderFactory $orderFactory * @param LoggerInterface $logger */ public function __construct( OrderRepositoryInterface $orderRepository, SearchCriteriaBuilder $searchCriteriaBuilder, + OrderFactory $orderFactory, LoggerInterface $logger ) { $this->logger = $logger; $this->orderRepository = $orderRepository; $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->orderFactory = $orderFactory; } /** @@ -62,6 +70,7 @@ public function created($data) /** * @param $data * @return bool + * @throws Exception */ public function canceled($data) { @@ -72,6 +81,8 @@ public function canceled($data) $order->addCommentToStatusHistory(__('The subscription was canceled')->getText()); $this->orderRepository->save($order); + $this->cancel($order->getIncrementId()); + return true; } @@ -114,4 +125,23 @@ private function getOrder($incrementId) return false; } + + /** + * @param $incrementId + * @throws Exception + */ + private function cancel($incrementId) + { + $orderFactory = $this->orderFactory->create(); + $order = $orderFactory->loadByIncrementId($incrementId); + + $order->cancel(); + + if (!$order->canCancel()) { + $order->setState(\Magento\Sales\Model\Order::STATE_CLOSED) + ->setStatus(\Magento\Sales\Model\Order::STATE_CLOSED); + } + + $order->save(); + } } From 7737f361137ccfe20a8a1435d6931147a34f68de Mon Sep 17 00:00:00 2001 From: Maico Date: Sat, 30 May 2020 22:52:06 -0300 Subject: [PATCH 34/37] Possibilidade de associar o produto bundle no Magento a um plano existente na Vindi. --- Model/Config/Source/Plan.php | 65 +++++++++++++++++++++ Model/Payment/AbstractMethod.php | 7 ++- Model/Vindi/PlanManagement.php | 5 ++ Observer/ProductSaveObserver.php | 4 ++ Setup/UpgradeData.php | 43 ++++++++++++++ etc/module.xml | 2 +- i18n/pt_BR.csv | 2 + view/adminhtml/templates/product/plan.phtml | 20 ++++++- 8 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 Model/Config/Source/Plan.php diff --git a/Model/Config/Source/Plan.php b/Model/Config/Source/Plan.php new file mode 100644 index 00000000..96386f06 --- /dev/null +++ b/Model/Config/Source/Plan.php @@ -0,0 +1,65 @@ +api = $api; + } + + /** + * Get all options + * @return array + */ + public function getAllOptions() + { + if ($this->_options === null) { + $this->_options = [ + ['label' => __('Create New Plan'), 'value' => 0] + ]; + + $this->_options = array_merge($this->_options, $this->getAvailablePlans()); + } + + return $this->_options; + } + + /** + * @return array + */ + public function getAvailablePlans() + { + $data = []; + + $result = $this->api->request('plans', 'GET'); + + if (!empty($result) && !empty($result['plans'])) { + foreach ($result['plans'] as $plan) { + $data[] = [ + 'label' => $plan['name'], + 'value' => $plan['id'] + ]; + } + } + + return $data; + } +} diff --git a/Model/Payment/AbstractMethod.php b/Model/Payment/AbstractMethod.php index e3d4763b..8829a775 100644 --- a/Model/Payment/AbstractMethod.php +++ b/Model/Payment/AbstractMethod.php @@ -251,16 +251,17 @@ protected function processPayment(InfoInterface $payment, $amount) /** * @param InfoInterface $payment - * @param OrderItemInterface $plan + * @param OrderItemInterface $orderItem * @return mixed * @throws LocalizedException */ - private function handleSubscriptionOrder(InfoInterface $payment, OrderItemInterface $plan) + private function handleSubscriptionOrder(InfoInterface $payment, OrderItemInterface $orderItem) { /** @var Order $order */ $order = $payment->getOrder(); $customerId = $this->customer->findOrCreate($order); - $planId = $this->planManagement->create($plan->getProductId()); + + $planId = $this->planManagement->create($orderItem->getProductId()); $productItems = $this->productManagement->findOrCreateProductsToSubscription($order); diff --git a/Model/Vindi/PlanManagement.php b/Model/Vindi/PlanManagement.php index 1869180a..252c4343 100644 --- a/Model/Vindi/PlanManagement.php +++ b/Model/Vindi/PlanManagement.php @@ -51,6 +51,11 @@ public function create($productId) throw new LocalizedException(__('Product Type not support to plan')); } + $planId = $product->getVindiPlanId(); + if ($planId) { + return $planId; + } + $data = [ 'name' => $product->getName(), 'code' => Data::sanitizeItemSku($product->getSku()), diff --git a/Observer/ProductSaveObserver.php b/Observer/ProductSaveObserver.php index 1e0b4555..a52ecdfa 100644 --- a/Observer/ProductSaveObserver.php +++ b/Observer/ProductSaveObserver.php @@ -47,6 +47,10 @@ public function execute(Observer $observer) return; } + if ($product->getVindiPlanId() > 0) { + return; + } + $this->plansManagement->create($product->getId()); } } diff --git a/Setup/UpgradeData.php b/Setup/UpgradeData.php index 5debc70e..a72c10b4 100644 --- a/Setup/UpgradeData.php +++ b/Setup/UpgradeData.php @@ -14,6 +14,7 @@ use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory; use Vindi\Payment\Model\Config\Source\BillingCycles; use Vindi\Payment\Model\Config\Source\Interval; +use Vindi\Payment\Model\Config\Source\Plan; use Vindi\Payment\Model\Config\Source\BillingTriggerType; /** @@ -78,6 +79,10 @@ public function upgrade( $this->createPlanAttributeSet(); $this->createProductAttributes(); } + + if (version_compare($context->getVersion(), "1.1.1", "<")) { + $this->addPlanIdFieldProductAttribute(); + } } /** @@ -271,4 +276,42 @@ private function createProductAttributes() ); } } + + private function addPlanIdFieldProductAttribute() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + + $attribute = $eavSetup->getAttribute(Product::ENTITY, 'vindi_plan_id'); + if (!$attribute) { + $eavSetup->addAttribute(Product::ENTITY, 'vindi_plan_id', [ + 'sort_order' => 1, + 'type' => 'varchar', + 'backend' => '', + 'frontend' => '', + 'label' => 'Use Registered Plan in Vindi', + 'input' => 'select', + 'class' => '', + 'source' => Plan::class, + 'global' => ScopedAttributeInterface::SCOPE_GLOBAL, + 'visible' => true, + 'required' => false, + 'user_defined' => true, + 'default' => null, + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'used_in_product_listing' => false, + 'unique' => false + ]); + + $eavSetup->addAttributeToGroup( + Product::ENTITY, + self::VINDI_PLANOS, + self::VINDI_PLAN_SETTINGS, + 'vindi_plan_id' + ); + } + } } diff --git a/etc/module.xml b/etc/module.xml index 9dda4e1f..cf6d3d03 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,7 +1,7 @@ - + diff --git a/i18n/pt_BR.csv b/i18n/pt_BR.csv index 969acb0a..601a052a 100644 --- a/i18n/pt_BR.csv +++ b/i18n/pt_BR.csv @@ -115,3 +115,5 @@ "Cancel Subscription","Cancelar Assinatura" "Something went wrong while cancel the Subscription.","Ocorreu um erro ao cancelar a assinatura." "You canceled the Subscription.","Você cancelou a assinatura." +"Use Registered Plan in Vindi","Usar Plano Criado na Vindi" +"Create New Plan","Criar Novo Plano" \ No newline at end of file diff --git a/view/adminhtml/templates/product/plan.phtml b/view/adminhtml/templates/product/plan.phtml index 1195cddf..32e64785 100644 --- a/view/adminhtml/templates/product/plan.phtml +++ b/view/adminhtml/templates/product/plan.phtml @@ -1,7 +1,8 @@ From 7b9fcfc9da5eaef4e9f02091fb96e690b4742fd8 Mon Sep 17 00:00:00 2001 From: Maico da Silva Date: Mon, 1 Jun 2020 15:52:46 -0300 Subject: [PATCH 35/37] Update Setup/UpgradeData.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laerte Guimarães <31661772+laerte-guimaraes@users.noreply.github.com> --- Setup/UpgradeData.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Setup/UpgradeData.php b/Setup/UpgradeData.php index a72c10b4..726a753d 100644 --- a/Setup/UpgradeData.php +++ b/Setup/UpgradeData.php @@ -289,7 +289,7 @@ private function addPlanIdFieldProductAttribute() 'type' => 'varchar', 'backend' => '', 'frontend' => '', - 'label' => 'Use Registered Plan in Vindi', + 'label' => 'Vindi Plan', 'input' => 'select', 'class' => '', 'source' => Plan::class, From ab8d50a71eceafb7d3b414289d0cb35491a02df4 Mon Sep 17 00:00:00 2001 From: Maico da Silva Date: Mon, 1 Jun 2020 15:52:55 -0300 Subject: [PATCH 36/37] Update i18n/pt_BR.csv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laerte Guimarães <31661772+laerte-guimaraes@users.noreply.github.com> --- i18n/pt_BR.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/pt_BR.csv b/i18n/pt_BR.csv index 601a052a..9d8a900d 100644 --- a/i18n/pt_BR.csv +++ b/i18n/pt_BR.csv @@ -115,5 +115,5 @@ "Cancel Subscription","Cancelar Assinatura" "Something went wrong while cancel the Subscription.","Ocorreu um erro ao cancelar a assinatura." "You canceled the Subscription.","Você cancelou a assinatura." -"Use Registered Plan in Vindi","Usar Plano Criado na Vindi" -"Create New Plan","Criar Novo Plano" \ No newline at end of file +"Vindi Plan","Plano Vindi" +"Create New Plan","Criar Novo Plano" From 98a6aa6fd574f71bf7fd49ec957455c7d4f2b561 Mon Sep 17 00:00:00 2001 From: Maico da Silva Date: Mon, 1 Jun 2020 15:53:13 -0300 Subject: [PATCH 37/37] Update Model/Config/Source/Plan.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laerte Guimarães <31661772+laerte-guimaraes@users.noreply.github.com> --- Model/Config/Source/Plan.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Model/Config/Source/Plan.php b/Model/Config/Source/Plan.php index 96386f06..b13bd4af 100644 --- a/Model/Config/Source/Plan.php +++ b/Model/Config/Source/Plan.php @@ -49,7 +49,7 @@ public function getAvailablePlans() { $data = []; - $result = $this->api->request('plans', 'GET'); + $result = $this->api->request('plans?query=status%3Dactive', 'GET'); if (!empty($result) && !empty($result['plans'])) { foreach ($result['plans'] as $plan) {