""" Stores details about the available payment options. Also stores credit card info in an encrypted format. """ from satchmo.configuration import config_value from Crypto.Cipher import Blowfish from datetime import datetime try: from decimal import Decimal except: from django.utils._decimal import Decimal from django.conf import settings from django.db import models from django.utils.translation import ugettext_lazy as _ #from modules.giftcertificate.utils import generate_certificate_code from satchmo import caching from satchmo.contact.models import Contact, OrderPayment from satchmo.payment.config import payment_choices, credit_choices import base64 import logging log = logging.getLogger('payment.models') 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 = payment_choices(), unique=True, help_text=_("The class name as defined in payment.py")) sortOrder = models.IntegerField(_("Sort Order")) class Admin: list_display = ['optionName','description','active'] ordering = ['sortOrder'] 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(OrderPayment, unique=True, edit_inline=True, num_in_admin=1, max_num_in_admin=1, related_name="creditcards") creditType = models.CharField(_("Credit Card Type"), max_length=16, choices=credit_choices()) displayCC = models.CharField(_("CC Number (Last 4 digits)"), max_length=4, core=True) encryptedCC = models.CharField(_("Encrypted Credit Card"), max_length=40, blank=True, null=True, editable=False) expireMonth = models.IntegerField(_("Expiration Month")) expireYear = models.IntegerField(_("Expiration Year")) def storeCC(self, ccnum): """Take as input a valid cc, encrypt it and store the last 4 digits in a visible form""" # Must remember to save it after calling! secret_key = settings.SECRET_KEY encryption_object = Blowfish.new(secret_key) # block cipher length must be a multiple of 8 padding = '' if (len(ccnum) % 8) <> 0: padding = 'X' * (8 - (len(ccnum) % 8)) self.encryptedCC = base64.b64encode(encryption_object.encrypt(ccnum + padding)) self.displayCC = ccnum[-4:] def setCCV(self, ccv): """Put the CCV in the cache, don't save it for security/legal reasons.""" if not self.encryptedCC: raise ValueError('CreditCardDetail expecting a credit card number to be stored before storing CCV') caching.cache_set(self.encryptedCC, skiplog=True, length=60*60, value=ccv) def getCCV(self): try: ccv = caching.cache_get(self.encryptedCC) except caching.NotCachedError: ccv = "" return ccv ccv = property(fget=getCCV, fset=setCCV) def _decryptCC(self): secret_key = settings.SECRET_KEY encryption_object = Blowfish.new(secret_key) # strip padding from decrypted credit card number ccnum = encryption_object.decrypt(base64.b64decode(self.encryptedCC)).rstrip('X') return (ccnum) decryptedCC = property(_decryptCC) def _expireDate(self): return(str(self.expireMonth) + "/" + str(self.expireYear)) expirationDate = property(_expireDate) class Meta: verbose_name = _("Credit Card") verbose_name_plural = _("Credit Cards")