magento 模块化开发
As a robust eCommerce platform, Magento has long supported integration with a variety of PayPal’s credit card payment solutions. Classy Llama’s newly released PayPal Credit Card Tokenization extension adds a feature that’s been sorely missed by merchants who use PayPal, however: the ability for customers to save a credit card for repeated use.
作为强大的电子商务平台,Magento长期以来一直支持与多种PayPal信用卡支付解决方案集成。 Classy Llama的新发布的PayPal信用卡令牌化扩展功能增加了使用PayPal的商人所无法珍惜的功能:但是,客户可以保存信用卡以备重复使用。
Building this extension was a new experience for Classy Llama in many ways, particularly because we are primarily an agency rather than a distributable extension developer. This was, in fact, our first go at developing an extension for Magento Connect, the platform’s official marketplace. This article offers a brief peek at how the project evolved and a few highlights of the development process.
对于Classy Llama而言,构建此扩展程序是一种新的体验,尤其是因为我们主要是代理商,而不是可分发扩展程序开发人员。 实际上,这是我们首次开发平台官方市场Magento Connect的扩展。 本文简要介绍了该项目的演变过程以及开发过程的一些要点。
失踪的一块 (A Missing Piece)
“But I really need to allow customers to save their credit cards.” We heard this sentiment with some frequency from clients, expressing a major barrier to choosing PayPal over competitor Authorize.Net as their payment gateway or processor.
“但是我确实需要允许客户保存他们的信用卡。” 我们从客户那里经常听到这种情绪,这表明在选择PayPal而非竞争对手Authorize.Net作为其支付网关或处理者方面存在重大障碍。
You see, what we’re talking about isn’t actually stored credit card data at all. The PCI DSS compliance that comes with storing sensitive payment data is unfeasible for many online merchants, and secure token alternatives exist in both PayPal and Authorize.Net API integration. These solutions allow the full experience of saved cards for the customer, while the credit card data itself is stored at the payment provider instead of the merchant site.
您会看到,我们所说的实际上根本不是存储的信用卡数据。 对于许多在线商家而言,存储敏感的支付数据所附带的PCI DSS合规性是不可行的,并且PayPal和Authorize.Net API集成中都存在安全令牌替代方案。 这些解决方案为客户提供了保存卡的完整体验,而信用卡数据本身存储在付款提供商而不是商家站点。
The core Magento codebase, however, has yet to implement support for these features on either service. And while several paid third-party extensions exist to enhance Authorize.Net integration with this functionality, there were thus far no off-the-shelf options for PayPal.
但是,核心的Magento代码库尚未在任一服务上实现对这些功能的支持。 尽管存在一些付费的第三方扩展来增强Authorize.Net与该功能的集成,但是到目前为止,贝宝还没有现成的选择。
Consistently, we found clients unwilling to bear the costs of developing this functionality for their site. When the prospect came up again during planning of a recent client site, we decided to reach out to PayPal: would they be willing to share the cost of developing saved credit card functionality for our new client’s site, if the result was a distributable extension that could add value to PayPal for other merchants as well?
一致地,我们发现客户不愿意承担为其网站开发此功能的费用。 当在最近的客户站点的规划过程中再次出现潜在客户时,我们决定与PayPal接触:如果结果是可分配的扩展,他们愿意为我们的新客户站点开发已保存的信用卡功能的费用吗?是否可以为其他商家增加PayPal的价值?
The response was enthusiastic. The lack of such an extension was strongly felt among the company’s integration specialists and sales force, especially when many merchants inaccurately expected PayPal to have direct control over what was and was not included in Magento (both companies are part of the eBay family of brands).
React热烈。 公司的集成专家和销售人员强烈缺乏这种扩展,特别是当许多商人不正确地期望PayPal直接控制Magento的内容时(两家公司都是eBay品牌家族的一部分) 。
We finally had a viable plan for completing a key piece of functionality that would add a great deal of value for current and future clients. And the best part for merchants: The extension would be completely free, positioning PayPal strongly against the paid Authorize.Net alternatives.
我们终于有了可行的计划来完成一项关键功能,该功能将为当前和未来的客户增加大量价值。 对于商人来说,最好的部分是:扩展将是完全免费的,从而使PayPal相对于付费的Authorize.Net替代产品而言具有强大的优势。
The scope of the work soon took shape, including a few more bells and whistles beyond simple saved credit card functionality. Since we had a specific target client for the initial build, this client’s specific needs partly determined the features that would be included (support for billing agreements with a PayFlow gateway integration is one such feature). This article, however, will focus primarily on the saved credit card functionality.
这项工作的范围很快就形成了,除了简单的保存的信用卡功能之外,还包括了其他一些功能。 由于我们有一个特定的目标客户来进行初始构建,因此该客户的具体需求在一定程度上决定了将要包含的功能(通过PayFlow网关集成来支持计费协议就是其中一种功能)。 但是,本文将主要关注已保存的信用卡功能。
发展历程 (Development)
环境 (Environment)
A few special challenges come with the development of a distributable extension that are not present with typical agency work. As a stand-alone product, only the module itself will go into your VCS, rather than an entire site codebase. Yet you’ll need an active environment integrating your module files during development, without the hassle of copying those files again and again.
可分发扩展的开发面临一些特殊的挑战,而典型的代理工作并不具备这些挑战。 作为独立产品,只有模块本身会进入您的VCS,而不是整个站点代码库。 但是,您将需要一个在开发过程中集成模块文件的活动环境,而不必一次又一次地复制这些文件的麻烦。
Usually, there is also the need for easily testing the code among different versions of the platform routinely during development. These challenges can be met by simply excluding a great many working files from your VCS, but this is not ideal, particularly in Magento, where your custom code must be scattered to some degree among the core directories.
通常,还需要在开发过程中定期轻松地在平台的不同版本之间测试代码。 只需从VCS中排除大量工作文件就可以解决这些挑战,但这并不理想,特别是在Magento中,自定义代码必须在某种程度上散布在核心目录中。
Fortunately, there is a tool available for Linux/Unix or Mac OSX environments to solve these issues with little fuss. Colin Mollenhour’s lightweight and excellent modman script was inspired specifically by Magento development and reduces the work of maintaining a project across multiple working codebases down to a few simple commands (the tool works by keeping your project files in a central hidden directory and placing symlinks in your actual codebase). We had used modman on occasion in the past, and it was the clear choice for managing our development environments for our PayPal extension.
幸运的是,有一个适用于Linux / Unix或Mac OSX环境的工具可以毫不费力地解决这些问题。 Colin Mollenhour的轻量级和出色的modman脚本受Magento开发的特别启发,并将跨多个工作代码库的项目维护工作简化为几个简单的命令(该工具通过将项目文件保存在中央隐藏目录中并在您的计算机中放置符号链接来工作。实际的代码库)。 过去,我们有时会使用modman,这是管理PayPal扩展的开发环境的明确选择。
版本问题 (A Version Problem)
With a good system for version testing in place, which versions would we in fact be supporting with our Credit Card Tokenization extension? The current version of Magento Enterprise at the time was 1.12.0.2; this was the priority not only according to common sense, but because the client site that would enjoy the first fruits of the project was a new build on this version. The project scope was quite clear that compatibility with prior versions, initially, would be limited to those requiring little extra development. After a little analysis, we knew the answer to the question with a rare and unfortunate finality. Our initial extension would not be backward compatible at all, not even to the 1.12.0.0 release.
有了完善的版本测试系统,实际上我们的信用卡令牌化扩展程序将支持哪些版本? Magento Enterprise的当前版本为1.12.0.2; 这不仅是常识上的优先考虑,而且因为将享受该项目最初成果的客户站点是此版本的新版本。 该项目的范围很明确,与最初版本的兼容性最初仅限于那些几乎不需要额外开发的版本。 经过一点分析,我们以罕见和不幸的结局知道了问题的答案。 我们最初的扩展根本不会向后兼容,甚至不兼容1.12.0.0版本。
The reason came down to a recent overhaul of the core Magento configuration options for PayPal integration, which oddly enough had occurred between 1.12.0.0 and 1.12.0.2. In Magento, such settings are defined very easily within an XML file in a particular extension. Ours would naturally need a few of its own integrated with the core PayPal options, and the recent overhaul meant that the XML node structure we must work within was drastically different from any past Magento release.
原因是最近对PayPal集成的Magento核心配置选项进行了全面检查,奇怪的是发生在1.12.0.0和1.1.20.2之间。 在Magento中,可以很容易地在特定扩展名的XML文件中定义此类设置。 我们的自然需要将其自身的一些集成到PayPal核心选项中,并且最近的大修意味着我们必须使用的XML节点结构与任何以前的Magento版本都大不相同。
This was a point where scope creep might have set in quite easily and early. The core code of Magento’s PayPal integration (even the code that actually accessed said configuration options) had varied little in several releases, so there were few other barriers to broader compatibility. However, the additional development of two versions of the extension’s configuration file would likely lead to inflated testing and debugging time as well.
在这一点上,范围蠕变可能很容易且很早就出现了。 Magento的PayPal集成的核心代码(甚至实际上访问了所述配置选项的代码)在几个版本中变化不大,因此,更广泛的兼容性没有其他障碍。 但是,扩展配置文件的两个版本的额外开发也可能导致测试和调试时间过长。
And while version detection would normally be a small feat in application code, configuration XML files are one area in Magento where there’s no real avenue for such a thing; two diverging extension packages, therefore, looked like the likely scenario, adding even more complexity to the prospect.
尽管版本检测通常在应用程序代码中不是一件容易的事,但是配置XML文件是Magento中的一个领域,在这方面没有真正的途径。 因此,两个不同的扩展程序包看起来像是可能的情况,这给潜在客户增加了更多的复杂性。
Faced with all these considerations, much as we would have liked to release with broader compatibility, we stuck to the scope. Our extension would initially support Magento Enterprise 1.12.0.2, the parallel Community 1.7.0.2, and the (at the time) upcoming Enterprise 1.13.0.0. And as a result, we released a functioning extension on time and within budget.
面对所有这些考虑因素,就像我们希望以更广泛的兼容性发布一样,我们坚持了这一范围。 我们的扩展最初将支持Magento Enterprise 1.12.0.2,并行社区1.7.0.2,以及(当时)即将推出的Enterprise 1.13.0.0。 结果,我们在预算范围内按时发布了功能扩展。
基本架构 (Basic Architecture)
Given the simplicity of the scope, there were actually few technical implementation choices to be made with this extension. One of those few involved our approach to user interface and that decision’s implications on code structure. Magento’s core code defines different payment methods and the PHP classes that govern them in one of the system’s many types of config XML files. The PayPal payment methods are no exception:
考虑到范围的简单性,此扩展实际上很少有技术实现选择。 少数几个涉及我们的用户界面方法以及该决定对代码结构的影响。 Magento的核心代码在系统的多种配置XML文件之一中定义了不同的付款方式和管理它们PHP类。 贝宝付款方式也不例外:
<payment>
<paypal_express>
<model>paypal/express</model>
<title>PayPal Express Checkout</title>
...
</paypal_express>
<paypal_direct>
<model>paypal/direct</model>
<title>PayPal Payments Pro</title>
...
</paypal_direct>
...
<verisign>
<model>paypal/payflowpro</model>
<title>Payflow Pro</title>
...
</verisign>
...
<payflow_link>
<model>paypal/payflowlink</model>
...
<title>Credit Card</title>
...
</payflow_link>
<payflow_advanced>
<model>paypal/payflowadvanced</model>
...
<title>Credit Card</title>
...
</payflow_advanced>
...
</payment>
A great deal of XML has been truncated in the above, but what’s left shows how PayPal Express and the four direct credit card solutions supported by the extension are defined. Each node under
corresponds with an item in the radio button list of payment options with which a customer is presented at checkout (excluding PayPal Express, only one of the above would ever actually be enabled at a time, depending on the merchant’s chosen PayPal integration). The
node under each defines the PHP class responsible for the payment method’s behavior.
上面已经截断了很多XML,但是剩下的内容显示了如何定义PayPal Express和扩展支持的四种直接信用卡解决方案。 下的每个节点 对应于付款选项单选按钮列表中的一个项目,在结帐时向客户显示该项目(不包括PayPal Express,根据商家选择的PayPal集成,一次只能同时启用上述之一)。 的 每个节点下的节点定义负责支付方式行为PHP类。
Given this structure of one main class in charge of one payment method, we needed to decide whether it made more sense to override the functionality of the existing payment methods – which would allow a great deal of flexibility for how we presented the saved card interface – or extend them with entirely separate payment methods.
鉴于负责付款方式的一个主要类别的结构,我们需要决定是否有必要改写现有付款方式的功能-这将为我们展示已保存的卡界面提供很大的灵活性-或使用完全独立的付款方式扩展它们。
In the end, the latter made the most sense. Keeping the logic for using a saved card in its own set of classes, and its own collection of config settings tied to them, was a cleaner structure.
最后,后者是最有意义的。 将使用已保存的卡的逻辑保持在自己的一组类中,并将它们自己的配置设置集合绑定到它们上,是一种更简洁的结构。
<payment>
<paypal_direct_customerstored>
<model>cls_paypal/paypal_stored_customerstored_direct</model>
...
<title>Saved Credit Card</title>
...
</paypal_direct_customerstored>
<verisign_customerstored>
<model>cls_paypal/paypal_stored_customerstored_payflowpro</model>
...
<title>Saved Credit Card</title>
...
</verisign_customerstored>
<payflow_link_customerstored>
<model>cls_paypal/paypal_stored_customerstored_payflowlink</model>
...
<title>Saved Credit Card</title>
...
</payflow_link_customerstored>
<payflow_advanced_customerstored>
<model>cls_paypal/paypal_stored_customerstored_payflowadvanced</model>
...
<title>Saved Credit Card</title>
...
</payflow_advanced_customerstored>
...
</payment>
The result for the user interface was a little more rigid, but perfectly clear to the customer: “Saved Credit Card” would appear as a separate option in the radio button list at checkout if the customer had previously chosen to save a card.
用户界面的结果有些僵化,但对客户来说却很清楚:如果客户以前选择保存卡,则“结帐的信用卡”将在结帐时作为单选项显示在单选按钮列表中。
Of course, some overriding of the basic credit card method classes was still necessary. Customers had to be offered the ability to save a card in the first place, after all. But the actual differing payment processing logic would be cleanly separated, without intruding on the core integration’s classes with conditional branching at every turn.
当然,仍然有必要重写一些基本的信用卡方法类。 毕竟,必须为客户提供保存卡的功能。 但是,实际不同的支付处理逻辑将被清晰地分开,而不用动turn按条件分支来干预核心集成的类。
小颠簸 (Minor Bumps)
One issue with the class structure defined just above was a typical inheritance problem. It so happened that the primary classes responsible for three of our four supported solutions – PayFlow Pro, PayFlow Link, and Payments Advanced – already formed an inheritance chain with only slight variations. Our “saved card” versions of all three, naturally, would be nearly identical as well, and we would have liked nothing more than to leverage inheritance for our own logic as well.
上面定义的类结构的一个问题是典型的继承问题。 碰巧的是,负责我们四个受支持解决方案中的三个的主要类(PayFlow Pro,PayFlow Link和Payments Advanced)已经形成了只有很小变化的继承链。 当然,我们所有这三个版本的“保存卡”版本也几乎相同,并且我们只希望将继承用于我们自己的逻辑即可。
Alas, each of our classes needed to extend its counterpart in the core code. The solution we ended up with was something of the best of both worlds, with a core class containing the main processing logic, referenced as a property rather than extended by the payment method classes. Methods on the latter almost universally simply called through to the core class. A truncated example of one of the payment classes should make the gist clear:
las,我们每个类都需要在核心代码中扩展其对应类。 我们最终得到的解决方案是两全其美的,其核心类包含主要处理逻辑,被称为属性,而不是由付款方式类扩展。 后者的方法几乎被普遍地简单地调用到核心类。 一个截短的付款类别示例应清楚说明以下要点:
class CLS_Paypal_Model_Paypal_Stored_Customerstored_Payflowpro extends CLS_Paypal_Model_Paypal_Payflowpro
{
//...
protected $_commonPayflowMethod;
public function __construct()
{
parent::__construct();
// Initialize common method
$this->_commonPayflowMethod = Mage::getModel(
'cls_paypal/paypal_stored_customerstored_payflow',
array(
'caller_method' => $this,
//... various other params
)
);
}
//...
public function authorize(Varien_Object $payment, $amount)
{
return $this->_commonPayflowMethod->authorize($payment, $amount);
}
public function capture(Varien_Object $payment, $amount)
{
return $this->_commonPayflowMethod->capture($payment, $amount);
}
//...
}
Other quandaries surfaced and were conquered here and there, but none of much consequence. In fact, we couldn’t have been happier with how smoothly the extension’s development proceeded. One drawback of the finished extension, however, was the rigidity made necessary by the way information about the various PayPal payment methods was hard-coded in the core module.
其他难题浮出水面,并在这里和那里被征服,但没有太大的后果。 实际上,我们对扩展程序的开发进展感到如此高兴。 但是,完成扩展的一个缺点是,通过在核心模块中硬编码有关各种PayPal支付方式的信息,使得刚性变得必要。
You’ve seen above how easy it is to define new payment methods via XML, and were our new methods truly self-contained, they’d be up and running with little intrusion into core code. Relying as they do on the existing PayPal integration code, however, they are subject to numerous instances of class constants referencing payment methods directly, case statements dictating how config information is to be retrieved, and even hard-coded logic for which countries a payment method supports.
您已经在上面看到了通过XML定义新的付款方式是多么容易,并且我们的新方法是真正独立的,它们可以在不干扰核心代码的情况下启动并运行。 但是,由于它们依赖于现有的PayPal集成代码,因此它们会受到许多类常量实例的直接引用支付方法的约束,说明如何获取配置信息的案例语句,甚至是针对哪个国家/地区的支付方法的硬编码逻辑支持。
Below are a few snippets of our own rewrite of the ubiquitous PayPal Config class, demonstrating a few of the places we were obliged to interject our new payment options:
以下是我们自己重写的无处不在的PayPal Config类的一些摘要,展示了我们不得不使用新的付款方式的一些地方:
class CLS_Paypal_Model_Paypal_Config extends Mage_Paypal_Model_Config
{
//...
// "Customer stored" payment methods
const METHOD_PAYPAL_DIRECT_CUSTOMERSTORED = 'paypal_direct_customerstored';
const METHOD_PAYPAL_PAYFLOWADVANCED_CUSTOMERSTORED = 'payflow_advanced_customerstored';
const METHOD_PAYPAL_PAYFLOWPRO_CUSTOMERSTORED = 'verisign_customerstored';
const METHOD_PAYPAL_PAYFLOWLINK_CUSTOMERSTORED = 'payflow_link_customerstored';
//...
public function getCountryMethods($countryCode = null)
{
//Countries where this method is available
//...
// PayPal Direct 'Stored card' methods
$countriesByMethod[self::METHOD_PAYPAL_DIRECT_CUSTOMERSTORED] = array(
'US',
'CA',
'GB'
);
// PayPal Payflow-based 'Stored card' methods (Payflow Pro defines the list of supported countries)
$countriesByMethod[self::METHOD_PAYPAL_PAYFLOWADVANCED_CUSTOMERSTORED] =
$countriesByMethod[self::METHOD_PAYPAL_PAYFLOWLINK_CUSTOMERSTORED] =
$countriesByMethod[self::METHOD_PAYPAL_PAYFLOWPRO_CUSTOMERSTORED] = array(
'US',
'CA',
'AU',
'NZ'
);
$countryMethods = parent::getCountryMethods($countryCode);
foreach ($countriesByMethod as $methodCode => $countries) {
//Add this method to the list of available methods in appropriate countries
if (is_null($countryCode)) {
foreach ($countries as $country) {
array_push($countryMethods[$country], $methodCode);
}
} elseif (in_array($countryCode, $countries)) {
array_push($countryMethods, $methodCode);
}
}
return $countryMethods;
}
protected function _getSpecificConfigPath($fieldName)
{
$path = parent::_getSpecificConfigPath($fieldName);
if (is_null($path)) {
switch ($this->_methodCode) {
//...
case self::METHOD_PAYPAL_DIRECT_CUSTOMERSTORED:
$path = $this->_mapStoredFieldset($fieldName);
break;
default:
}
}
return $path;
}
public function isMethodAvailable($methodCode = null)
{
$result = parent::isMethodAvailable($methodCode);
if (!$result) {
return false;
}
//...
switch ($methodCode) {
case self::METHOD_PAYPAL_DIRECT_CUSTOMERSTORED:
if (!$this->isMethodActive(self::METHOD_WPP_DIRECT)) {
$result = false;
}
break;
case self::METHOD_PAYPAL_PAYFLOWADVANCED_CUSTOMERSTORED:
if (!$this->isMethodActive(self::METHOD_PAYFLOWADVANCED)) {
$result = false;
}
break;
case self::METHOD_PAYPAL_PAYFLOWLINK_CUSTOMERSTORED:
if (!$this->isMethodActive(self::METHOD_PAYFLOWLINK)) {
$result = false;
}
break;
case self::METHOD_PAYPAL_PAYFLOWPRO_CUSTOMERSTORED:
if (!$this->isMethodActive(self::METHOD_PAYFLOWPRO)) {
$result = false;
}
break;
}
return $result;
}
//...
}
In the end, I can’t say for certain that I could have architected such a complex integration in any more flexible a manner. However that may fall, though, the end result of hard-coded elements like these makes it more likely that minor re-tooling will be required to support future Magento releases.
最后,我不能肯定地说我可以以任何更灵活的方式设计如此复杂的集成。 但是,尽管如此,但是像这样的硬编码元素的最终结果使得更有可能需要进行较小的重新安装即可支持将来的Magento版本。
不用担心API (No API Worries)
Being, as it is, primarily a web service integration, this extension relies on API calls for its core functionality. In this area, however, our task was made extremely easy by the fact that we were merely enhancing an existing integration. Magento’s core had already defined classes for issuing the appropriate requests, and in fact we had no need whatsoever for defining low level code to construct API calls.
实际上,它是主要的Web服务集成,它的核心功能依赖于API调用。 但是,在这一领域,由于我们只是增强了现有的集成,因此使我们的任务变得非常容易。 Magento的核心已经定义了用于发出适当请求的类,实际上,我们根本不需要定义底层代码来构造API调用。
Our extension was concerned with PayPal’s two name-value-pair (NVP) APIs – the direct API and the PayFlow gateway API. Magento’s Mage_Paypal_Model_Api_Nvp class defines the logic for the former, while the latter is handled directly in the PayFlow Pro payment method class and its descendants. A very brief snapshot of some of the direct API class:
我们的扩展涉及PayPal的两个名称/值对(NVP)API –直接API和PayFlow网关API。 Magento的Mage_Paypal_Model_Api_Nvp类定义了前者的逻辑,而后者则直接在PayFlow Pro付款方法类及其后代中处理。 一些直接API类的非常简短的快照:
class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract
{
/**
* Paypal methods definition
*/
const DO_DIRECT_PAYMENT = 'DoDirectPayment';
const DO_CAPTURE = 'DoCapture';
const DO_AUTHORIZATION = 'DoAuthorization';
//... (other constants for API method names)
protected $_globalMap = array(
// each call
'VERSION' => 'version',
'USER' => 'api_username',
'PWD' => 'api_password',
'SIGNATURE' => 'api_signature',
//... (other API parameters and the properties they map to on this class
)
//...
protected $_doAuthorizationRequest = array('TRANSACTIONID', 'AMT', 'CURRENCYCODE');
protected $_doAuthorizationResponse = array('TRANSACTIONID', 'AMT');
//...
public function callDoAuthorization()
{
$request = $this->_exportToRequest($this->_doAuthorizationRequest);
$response = $this->call(self::DO_AUTHORIZATION, $request);
$this->_importFromResponse($this->_paymentInformationResponse, $response);
$this->_importFromResponse($this->_doAuthorizationResponse, $response);
return $this;
}
}
Our chief concern was with what are known as reference transactions, as this is the key tokenization feature of the PayPal API that makes our version of “saved credit cards” work. As it turned out, we were quite fortunate in regard to the direct API at least, because reference transactions were a required component of a feature the core integration already supported: billing agreements.
我们最关心的是所谓的参考交易,因为这是PayPal API的关键标记化功能,使我们的“保存的信用卡”版本有效。 事实证明,至少在直接API方面我们很幸运,因为参考交易是核心集成已支持的功能(计费协议)的必需组成部分。
Delighted to find a callDoReferenceTransaction
method defined on the API class already, we merely needed to set the right properties and call it from within our payment method class:
很高兴找到已经在API类上定义的callDoReferenceTransaction
方法,我们只需要设置正确的属性并从我们的付款方法类中调用它即可:
class CLS_Paypal_Model_Paypal_Stored_Customerstored_Direct extends CLS_Paypal_Model_Paypal_Direct
{
//...
protected function _placeOrder(Mage_Sales_Model_Order_Payment $payment, $amount)
{
// Get Reference ID
$paymentStoredCardId = $this->getInfoInstance()->getData('stored_card_id');
$referenceId = null;
if ($paymentStoredCardId) {
$storedCardModel = Mage::getModel('cls_paypal/customerstored')->load($paymentStoredCardId);
if ($storedCardModel->getId()) {
$referenceId = $storedCardModel->getData('transaction_id');
}
}
//...
$order = $payment->getOrder();
$api = $this->_pro->getApi()
->setReferenceId($referenceId)
->setPaymentAction($this->getConfigData('payment_action'))
->setIpAddress(Mage::app()->getRequest()->getClientIp(false))
->setAmount($amount)
->setCurrencyCode($order->getBaseCurrencyCode())
->setInvNum($order->getIncrementId())
->setEmail($order->getCustomerEmail());
//...
// call api and import transaction and other payment information
$api->callDoReferenceTransaction();
$this->_importResultToPayment($api, $payment);
//...
return $this;
}
}
We anticipated more work for the PayFlow based solutions, but even here things remained fairly simple. The PayFlow API does not, in fact, expect an explicit method name among request parameters. A reference transaction is performed merely by including an ORIGID
value in addition to the transaction type (authorization or capture, for instance).
我们期望基于PayFlow的解决方案能有更多的工作,但即使在这里,事情仍然相当简单。 实际上,PayFlow API并不希望在请求参数中使用明确的方法名称。 仅通过在事务类型(例如,授权或捕获)之外包括ORIGID
值即可执行参考事务。
By fetching and setting the appropriate token, we were in business. The chief class involved was not much longer than this:
通过获取并设置适当的令牌,我们可以开展业务。 所涉及的首席班长不超过此时间:
class CLS_Paypal_Model_Paypal_Stored_Customerstored_Payflow extends CLS_Paypal_Model_Paypal_Stored_Payflow
{
//...
protected function _placeOrder(Mage_Sales_Model_Order_Payment $payment, $amount, $transactionType = self::TRXTYPE_AUTH_ONLY)
{
// Get Reference ID
$paymentStoredCardId = $this->_commonMethod->getInfoInstance()->getData('stored_card_id');
$referenceId = null;
if ($paymentStoredCardId) {
$storedCardModel = Mage::getModel('cls_paypal/customerstored')->load($paymentStoredCardId);
if ($storedCardModel->getId()) {
$referenceId = $storedCardModel->getData('transaction_id');
}
}
//...
// Prepare and run 'Reference Transaction' request
$request = $this->_buildBasicRequest($payment);
$request->setTrxtype($transactionType);
$request->setAmt(round($amount, 2));
$request->setOrigid($referenceId);
$response = $this->_postRequest($request);
$this->_processErrors($response);
//...
return $this;
}
}
In point of fact, we had more API mapping work to do for our PayFlow Pro billing agreement payment method (not the focus of this article) than for any of our saved credit card functionality.
实际上,与任何已保存的信用卡功能相比,我们为PayFlow Pro计费协议付款方式(不是本文重点)要做的API映射工作更多。
前方的路 (The Road Ahead)
Right now, the most glaring limitation of the PayPal Credit Card Tokenization extension is its stringent compatibility requirements. I’m happy to report that we’re already on track to broaden compatibility with previous Magento versions in the near future. (Keep an eye on our blog, if you like, for updates.)
目前,PayPal信用卡令牌化扩展最明显的限制是其严格的兼容性要求。 我很高兴地报告,我们已经在不久的将来扩展与以前的Magento版本的兼容性。 (如果需要,请关注我们的博客以获取更新。)
There are also a slew of other features we’d like to see added in the future. Support for Magento’s recurring payment profiles, for example, would be a natural fit for saved credit cards. We’ll be paying careful attention to the most requested functionality as we plan for the future of the extension.
我们还希望将来增加许多其他功能。 例如,对Magento的定期付款配置文件的支持自然适用于已保存的信用卡。 在计划扩展的未来时,我们将仔细关注最需要的功能。
The development of our first extension for Magento Connect has been a major learning experience for Classy Llama, and an extremely positive one. We’re excited to see the benefit PayPal’s tokenization features can provide for Magento merchants.
我们对Magento Connect的第一个扩展的开发对Classy Llama来说是一次重要的学习经历,也是一次非常积极的经历。 我们很高兴看到PayPal的令牌化功能可以为Magento商家带来好处。
翻译自: https://www.sitepoint.com/paypal-credit-card-tokenization-magento/
magento 模块化开发