PageRenderTime 99ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/satchmo/apps/payment/models.py

https://github.com/Ryati/satchmo
Python | 124 lines | 104 code | 7 blank | 13 comment | 3 complexity | 14167bc5030c7a2b49a273869c9488ff MD5 | raw file
  1. """
  2. Stores details about the available payment options.
  3. Also stores credit card info in an encrypted format.
  4. """
  5. from Crypto.Cipher import Blowfish
  6. from datetime import datetime
  7. from decimal import Decimal
  8. from django.conf import settings
  9. from django.db import models
  10. from django.utils.translation import ugettext_lazy as _
  11. from livesettings import config_value, config_choice_values, SettingNotSet
  12. from payment.fields import PaymentChoiceCharField, CreditChoiceCharField
  13. from satchmo_store.contact.models import Contact
  14. import base64
  15. import config
  16. import keyedcache
  17. import logging
  18. import satchmo_utils.sslurllib
  19. log = logging.getLogger('payment.models')
  20. class PaymentOption(models.Model):
  21. """
  22. If there are multiple options - CC, Cash, COD, etc this class allows
  23. configuration.
  24. """
  25. description = models.CharField(_("Description"), max_length=20)
  26. active = models.BooleanField(_("Active"),
  27. help_text=_("Should this be displayed as an option for the user?"))
  28. optionName = PaymentChoiceCharField(_("Option Name"), max_length=20,
  29. unique=True,
  30. help_text=_("The class name as defined in payment.py"))
  31. sortOrder = models.IntegerField(_("Sort Order"))
  32. class Meta:
  33. verbose_name = _("Payment Option")
  34. verbose_name_plural = _("Payment Options")
  35. class CreditCardDetail(models.Model):
  36. """
  37. Stores an encrypted CC number, its information, and its
  38. displayable number.
  39. """
  40. orderpayment = models.ForeignKey('shop.OrderPayment', unique=True,
  41. related_name="creditcards")
  42. credit_type = CreditChoiceCharField(_("Credit Card Type"), max_length=16)
  43. display_cc = models.CharField(_("CC Number (Last 4 digits)"),
  44. max_length=4, )
  45. encrypted_cc = models.CharField(_("Encrypted Credit Card"),
  46. max_length=40, blank=True, null=True, editable=False)
  47. expire_month = models.IntegerField(_("Expiration Month"))
  48. expire_year = models.IntegerField(_("Expiration Year"))
  49. card_holder = models.CharField(_("card_holder Name"), max_length=60, blank=True)
  50. start_month = models.IntegerField(_("Start Month"), blank=True, null=True)
  51. start_year = models.IntegerField(_("Start Year"), blank=True, null=True)
  52. issue_num = models.CharField(blank=True, null=True, max_length=2)
  53. def storeCC(self, ccnum):
  54. """Take as input a valid cc, encrypt it and store the last 4 digits in a visible form"""
  55. self.display_cc = ccnum[-4:]
  56. encrypted_cc = _encrypt_code(ccnum)
  57. if config_value('PAYMENT', 'STORE_CREDIT_NUMBERS'):
  58. self.encrypted_cc = encrypted_cc
  59. else:
  60. standin = "%s%i%i%i" % (self.display_cc, self.expire_month, self.expire_year, self.orderpayment.id)
  61. self.encrypted_cc = _encrypt_code(standin)
  62. key = _encrypt_code(standin + '-card')
  63. keyedcache.cache_set(key, skiplog=True, length=60*60, value=encrypted_cc)
  64. def setCCV(self, ccv):
  65. """Put the CCV in the cache, don't save it for security/legal reasons."""
  66. if not self.encrypted_cc:
  67. raise ValueError('CreditCardDetail expecting a credit card number to be stored before storing CCV')
  68. keyedcache.cache_set(self.encrypted_cc, skiplog=True, length=60*60, value=ccv)
  69. def getCCV(self):
  70. try:
  71. ccv = keyedcache.cache_get(self.encrypted_cc)
  72. except keyedcache.NotCachedError:
  73. ccv = ""
  74. return ccv
  75. ccv = property(fget=getCCV, fset=setCCV)
  76. def _decryptCC(self):
  77. ccnum = _decrypt_code(self.encrypted_cc)
  78. if not config_value('PAYMENT', 'STORE_CREDIT_NUMBERS'):
  79. try:
  80. key = _encrypt_code(ccnum + '-card')
  81. encrypted_ccnum = keyedcache.cache_get(key)
  82. ccnum = _decrypt_code(encrypted_ccnum)
  83. except keyedcache.NotCachedError:
  84. ccnum = ""
  85. return ccnum
  86. decryptedCC = property(_decryptCC)
  87. def _expireDate(self):
  88. return(str(self.expire_month) + "/" + str(self.expire_year))
  89. expirationDate = property(_expireDate)
  90. class Meta:
  91. verbose_name = _("Credit Card")
  92. verbose_name_plural = _("Credit Cards")
  93. def _decrypt_code(code):
  94. """Decrypt code encrypted by _encrypt_code"""
  95. secret_key = settings.SECRET_KEY
  96. encryption_object = Blowfish.new(secret_key)
  97. # strip padding from decrypted credit card number
  98. return encryption_object.decrypt(base64.b64decode(code)).rstrip('X')
  99. def _encrypt_code(code):
  100. """Quick encrypter for CC codes or code fragments"""
  101. secret_key = settings.SECRET_KEY
  102. encryption_object = Blowfish.new(secret_key)
  103. # block cipher length must be a multiple of 8
  104. padding = ''
  105. if (len(code) % 8) <> 0:
  106. padding = 'X' * (8 - (len(code) % 8))
  107. return base64.b64encode(encryption_object.encrypt(code + padding))