在GAE中使用python 2.7进行网上商店的付款处理?

时间:2011-12-25 07:37:03

标签: django google-app-engine e-commerce satchmo webshop

我正在开发一个应该有一些付款方式的小型网上商店。我的平台是Google App Engine和python 2.7。有一个名为satchmo的项目是django / python,我想知道我是否可以使用它的代码? Here是其部分付款模式的开源:

class PaymentOption(models.Model):
    """
    If there are multiple options - CC, Cash, COD, etc this class allows
    configuration.
    """
    description = models.CharField(_("Description"), max_length=20)
    active = models.BooleanField(_("Active"), 
        help_text=_("Should this be displayed as an option for the user?"))
    optionName = models.CharField(_("Option Name"), max_length=20, choices=iterchoices_db(payment.config.labelled_gateway_choices),
        unique=True, 
        help_text=_("The class name as defined in payment.py"))
    sortOrder = models.IntegerField(_("Sort Order"))

    class Meta:
        verbose_name = _("Payment Option")
        verbose_name_plural = _("Payment Options")

class CreditCardDetail(models.Model):
    """
    Stores an encrypted CC number, its information, and its
    displayable number.
    """
    orderpayment = models.ForeignKey('shop.OrderPayment', unique=True, 
        related_name="creditcards")
    credit_type = models.CharField(_("Credit Card Type"), max_length=16, choices=iterchoices_db(payment.config.credit_choices))
    display_cc = models.CharField(_("CC Number (Last 4 digits)"),
        max_length=4, )
    encrypted_cc = models.CharField(_("Encrypted Credit Card"),
        max_length=40, blank=True, null=True, editable=False)
    expire_month = models.IntegerField(_("Expiration Month"))
    expire_year = models.IntegerField(_("Expiration Year"))
    card_holder = models.CharField(_("card_holder Name"), max_length=60, blank=True)
    start_month = models.IntegerField(_("Start Month"), blank=True, null=True)
    start_year = models.IntegerField(_("Start Year"), blank=True, null=True)
    issue_num = models.CharField(blank=True, null=True, max_length=2)

    def storeCC(self, ccnum):
        """Take as input a valid cc, encrypt it and store the last 4 digits in a visible form"""
        self.display_cc = ccnum[-4:]
        encrypted_cc = _encrypt_code(ccnum)
        if config_value('PAYMENT', 'STORE_CREDIT_NUMBERS'):
            self.encrypted_cc = encrypted_cc
        else:
            standin = "%s%i%i%i" % (self.display_cc, self.expire_month, self.expire_year, self.orderpayment.id)
            self.encrypted_cc = _encrypt_code(standin)
            key = _encrypt_code(standin + '-card')
            keyedcache.cache_set(key, skiplog=True, length=60*60, value=encrypted_cc)

    def setCCV(self, ccv):
        """Put the CCV in the cache, don't save it for security/legal reasons."""
        if not self.encrypted_cc:
            raise ValueError('CreditCardDetail expecting a credit card number to be stored before storing CCV')

        keyedcache.cache_set(self.encrypted_cc, skiplog=True, length=60*60, value=ccv)

    def getCCV(self):
        try:
            ccv = keyedcache.cache_get(self.encrypted_cc)
        except keyedcache.NotCachedError:
            ccv = ""

        return ccv

    ccv = property(fget=getCCV, fset=setCCV)

    def _decryptCC(self):
        ccnum = _decrypt_code(self.encrypted_cc)
        if not config_value('PAYMENT', 'STORE_CREDIT_NUMBERS'):
            try:
                key = _encrypt_code(ccnum + '-card')
                encrypted_ccnum = keyedcache.cache_get(key)
                ccnum = _decrypt_code(encrypted_ccnum)
            except keyedcache.NotCachedError:
                ccnum = ""
        return ccnum

    decryptedCC = property(_decryptCC) 

    def _expireDate(self):
        return(str(self.expire_month) + "/" + str(self.expire_year))
    expirationDate = property(_expireDate)

    class Meta:
        verbose_name = _("Credit Card")
        verbose_name_plural = _("Credit Cards")

def _decrypt_code(code):
    """Decrypt code encrypted by _encrypt_code"""
    # In some blowfish implementations, > 56 char keys can cause problems
    secret_key = settings.SECRET_KEY[:56]
    encryption_object = Blowfish.new(secret_key)
    # strip padding from decrypted credit card number
    return encryption_object.decrypt(base64.b64decode(code)).rstrip('X')

def _encrypt_code(code):
    """Quick encrypter for CC codes or code fragments"""
    # In some blowfish implementations, > 56 char keys can cause problems
    secret_key = settings.SECRET_KEY[:56]
    encryption_object = Blowfish.new(secret_key)
    # block cipher length must be a multiple of 8
    padding = ''
    if (len(code) % 8) <> 0:
        padding = 'X' * (8 - (len(code) % 8))
    return base64.b64encode(encryption_object.encrypt(code + padding))

代码看起来可以移植到app引擎,如果我想要,我甚至应该移植这段代码,认为satchmo项目已经解决了我在实现网店时遇到的许多问题?或者我应该得到更多“django友好托管”,如同在类似问题中建议的那样在app引擎上实际运行satchmo?

1 个答案:

答案 0 :(得分:3)

做一些研究,看起来很多人都试过这个并且放弃了。在app引擎上运行satchmo有几个问题 - 大多数都与模型和依赖关系有关,但也存在PCI合规性问题。

我首先要解决PCI问题 - 为了能够存储信用卡数据而不必担心您的商家帐户提供商拔掉您的帐户,您需要遵守PCI DSS。如果您打算与信用卡数据进行交互,它是由律师(ha!)撰写的文件,用于设定安全标准。它是最好的最佳实践,例如从不存储CVV2(卡背面的3位数代码),等等。但是,一个重要方面与所用存储的安全性有关。谷歌并没有宣传这一点,但我相信App Engine及其专有数据库不符合PCI标准。这意味着您在顶部构建的任何内容都不会符合PCI标准。

现在技术方面。根据我的阅读,让这项工作最好的选择是django_nonrel。您将不得不修改某些模型以不依赖外键。还有一些其他依赖项,例如reportlab。以下是关于此事的帖子:http://groups.google.com/group/satchmo-developers/browse_thread/thread/f14053df13232615

最后但并非最不重要的是,这是关于stackoverflow的旧讨论:How to make Satchmo work in Google App Engine

普遍的共识是,satchmo不适合GAE。似乎不是现成的解决方案,但我鼓励您看看Paypal,这是他们的教程:https://www.x.com/devzone/articles/using-paypals-adaptive-payments-and-google-app-engine-build-online-market-python

此外,此代码可能会根据您的需要进行调整。他们正在使用谷歌结账: http://code.google.com/p/chippysshop/

最后,还有Stripe,处理各种信用卡交易,不需要商家帐户:https://stripe.com/

祝你好运!