def make_secret(form_instance, secret_fields=None): """ Returns a secret for use in a EWP form or an IPN verification based on a selection of variables in params. Should only be used with SSL. """ warn_untested() # @@@ Moved here as temporary fix to avoid dependancy on auth.models. # @@@ amount is mc_gross on the IPN - where should mapping logic go? # @@@ amount / mc_gross is not nessecarily returned as it was sent - how to use it? 10.00 vs. 10.0 # @@@ the secret should be based on the invoice or custom fields as well - otherwise its always the same. # Build the secret with fields availible in both PaymentForm and the IPN. Order matters. if secret_fields is None: secret_fields = ['business', 'item_name'] data = "" for name in secret_fields: if hasattr(form_instance, 'cleaned_data'): if name in form_instance.cleaned_data: data += six.text_type(form_instance.cleaned_data[name]) else: # Initial data passed into the constructor overrides defaults. if name in form_instance.initial: data += six.text_type(form_instance.initial[name]) elif name in form_instance.fields and form_instance.fields[name].initial is not None: data += six.text_type(form_instance.fields[name].initial) secret = get_sha1_hexdigest(settings.SECRET_KEY, data) return secret
def _verify_postback(self): # ### Now we don't really care what result was, just whether a flag was set or not. from paypal.standard.pdt.forms import PayPalPDTForm response_list = self.response.split('\n') response_dict = {} for i, line in enumerate(response_list): unquoted_line = unquote_plus(line).strip() if i == 0: self.st = unquoted_line else: if self.st != "SUCCESS": warn_untested() self.set_flag(line) break try: if not unquoted_line.startswith(' -'): k, v = unquoted_line.split('=') response_dict[k.strip()] = v.strip() except ValueError: pass qd = QueryDict('', mutable=True) qd.update(response_dict) qd.update( dict(ipaddress=self.ipaddress, st=self.st, flag_info=self.flag_info, flag=self.flag, flag_code=self.flag_code)) pdt_form = PayPalPDTForm(qd, instance=self) pdt_form.save(commit=False)
def _verify_postback(self): # ### Now we don't really care what result was, just whether a flag was set or not. from paypal.standard.pdt.forms import PayPalPDTForm response_list = self.response.split('\n') response_dict = {} for i, line in enumerate(response_list): unquoted_line = unquote_plus(line).strip() if i == 0: self.st = unquoted_line else: if self.st != "SUCCESS": warn_untested() self.set_flag(line) break try: if not unquoted_line.startswith(' -'): k, v = unquoted_line.split('=') response_dict[k.strip()] = v.strip() except ValueError: pass qd = QueryDict('', mutable=True) qd.update(response_dict) qd.update(dict(ipaddress=self.ipaddress, st=self.st, flag_info=self.flag_info, flag=self.flag, flag_code=self.flag_code)) pdt_form = PayPalPDTForm(qd, instance=self) pdt_form.save(commit=False)
def set_flag(self, info, code=None): """Sets a flag on the transaction and also sets a reason.""" self.flag = True self.flag_info += info if code is not None: warn_untested() self.flag_code = code
def init(self, request, paypal_request, paypal_response): """Initialize a PayPalNVP instance from a HttpRequest.""" if request is not None: from paypal.pro.helpers import strip_ip_port self.ipaddress = strip_ip_port(request.META.get('REMOTE_ADDR', '')) if hasattr(request, "user") and request.user.is_authenticated(): self.user = request.user else: self.ipaddress = '' # No storing credit card info. query_data = dict((k, v) for k, v in paypal_request.items() if k not in self.RESTRICTED_FIELDS) self.query = urlencode(query_data) self.response = urlencode(paypal_response) # Was there a flag on the play? ack = paypal_response.get('ack', False) if ack != "Success": if ack == "SuccessWithWarning": warn_untested() self.flag_info = paypal_response.get('l_longmessage0', '') else: self.set_flag(paypal_response.get('l_longmessage0', ''), paypal_response.get('l_errorcode', ''))
def clean(self, value): warn_untested() exp = super(CreditCardExpiryField, self).clean(value) if date.today() > exp: raise forms.ValidationError( "The expiration date you entered is in the past.") return exp
def set_flag(self, info, code=None): """Sets a flag on the transaction and also sets a reason.""" self.flag = True self.flag_info += info if code is not None: warn_untested() self.flag_code = code
def make_secret(form_instance, secret_fields=None): """ Returns a secret for use in a EWP form or an IPN verification based on a selection of variables in params. Should only be used with SSL. """ warn_untested() # @@@ Moved here as temporary fix to avoid dependancy on auth.models. # @@@ amount is mc_gross on the IPN - where should mapping logic go? # @@@ amount / mc_gross is not nessecarily returned as it was sent - how to use it? 10.00 vs. 10.0 # @@@ the secret should be based on the invoice or custom fields as well - otherwise its always the same. # Build the secret with fields availible in both PaymentForm and the IPN. Order matters. if secret_fields is None: secret_fields = ['business', 'item_name'] data = "" for name in secret_fields: if hasattr(form_instance, 'cleaned_data'): if name in form_instance.cleaned_data: data += unicode(form_instance.cleaned_data[name]) else: # Initial data passed into the constructor overrides defaults. if name in form_instance.initial: data += unicode(form_instance.initial[name]) elif name in form_instance.fields and form_instance.fields[name].initial is not None: data += unicode(form_instance.fields[name].initial) secret = get_sha1_hexdigest(settings.SECRET_KEY, data) return secret
def response_dict(self): """ Returns a (MultiValueDict) dictionary containing all the parameters returned in the PayPal response. """ # Undo the urlencode done in init warn_untested() return QueryDict(self.response)
def _encrypt(self): """Use your key thing to encrypt things.""" warn_untested() from M2Crypto import BIO, SMIME, X509 # Iterate through the fields and pull out the ones that have a value. plaintext = 'cert_id=%s\n' % self.cert_id for name, field in self.fields.items(): value = None if name in self.initial: value = self.initial[name] elif field.initial is not None: value = field.initial if value is not None: plaintext += u'%s=%s\n' % (name, value) plaintext = plaintext.encode('utf-8') # Begin crypto weirdness. s = SMIME.SMIME() s.load_key_bio(BIO.openfile(self.private_cert), BIO.openfile(self.public_cert)) p7 = s.sign(BIO.MemoryBuffer(plaintext), flags=SMIME.PKCS7_BINARY) x509 = X509.load_cert_bio(BIO.openfile(self.paypal_cert)) sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) s.set_cipher(SMIME.Cipher('des_ede3_cbc')) tmp = BIO.MemoryBuffer() p7.write_der(tmp) p7 = s.encrypt(tmp, flags=SMIME.PKCS7_BINARY) out = BIO.MemoryBuffer() p7.write(out) return out.read()
def __init__(self, private_cert=PAYPAL_PRIVATE_CERT, public_cert=PAYPAL_PUBLIC_CERT, paypal_cert=PAYPAL_CERT, cert_id=PAYPAL_CERT_ID, *args, **kwargs): warn_untested() super(PayPalEncryptedPaymentsForm, self).__init__(*args, **kwargs) self.private_cert = private_cert self.public_cert = public_cert self.paypal_cert = paypal_cert self.cert_id = cert_id
def render_confirm_form(self): """ Second step of ExpressCheckout. Display an order confirmation form which contains hidden fields with the token / PayerID from PayPal. """ warn_untested() initial = dict(token=self.request.GET['token'], PayerID=self.request.GET['PayerID']) self.context[self.form_context_name] = self.confirm_form_cls(initial=initial) return TemplateResponse(self.request, self.confirm_template, self.context)
def check_secret(form_instance, secret): """ Returns true if received `secret` matches expected secret for form_instance. Used to verify IPN. """ warn_untested() # @@@ add invoice & custom # secret_fields = ['business', 'item_name'] return make_secret(form_instance) == secret
def check_secret(form_instance, secret): """ Returns true if received `secret` matches expected secret for form_instance. Used to verify IPN. """ warn_untested() # @@@ add invoice & custom # secret_fields = ['business', 'item_name'] return make_secret(form_instance) == secret
def _postback(self): """ Perform PayPal PDT Postback validation. Sends the transaction ID and business token to PayPal which responses with SUCCESS or FAILED. """ warn_untested() return requests.post(self.get_endpoint(), data=dict(cmd="_notify-synch", at=IDENTITY_TOKEN, tx=self.tx)).content
def render_confirm_form(self): """ Second step of ExpressCheckout. Display an order confirmation form which contains hidden fields with the token / PayerID from PayPal. """ warn_untested() initial = dict(token=self.request.GET['token'], PayerID=self.request.GET['PayerID']) self.context[self.form_context_name] = self.confirm_form_cls( initial=initial) return TemplateResponse(self.request, self.confirm_template, self.context)
def __init__(self, *args, **kwargs): "Make the secret from the form initial data and slip it into the form." warn_untested() from paypal.standard.helpers import make_secret super(PayPalSharedSecretEncryptedPaymentsForm, self).__init__(*args, **kwargs) # @@@ Attach the secret parameter in a way that is safe for other query params. secret_param = "?secret=%s" % make_secret(self) # Initial data used in form construction overrides defaults if 'notify_url' in self.initial: self.initial['notify_url'] += secret_param else: self.fields['notify_url'].initial += secret_param
def __init__(self, *args, **kwargs): "Make the secret from the form initial data and slip it into the form." warn_untested() from paypal.standard.helpers import make_secret super(PayPalSharedSecretEncryptedPaymentsForm, self).__init__(*args, **kwargs) # @@@ Attach the secret parameter in a way that is safe for other query params. secret_param = "?secret=%s" % make_secret(self) # Initial data used in form construction overrides defaults if 'notify_url' in self.initial: self.initial['notify_url'] += secret_param else: self.fields['notify_url'].initial += secret_param
def redirect_to_express(self): """ First step of ExpressCheckout. Redirect the request to PayPal using the data returned from setExpressCheckout. """ wpp = PayPalWPP(self.request) try: nvp_obj = wpp.setExpressCheckout(self.item) except PayPalFailure: warn_untested() self.context['errors'] = self.errors['paypal'] return self.render_payment_form() else: return HttpResponseRedirect(express_endpoint_for_token(nvp_obj.token))
def validate_payment_form(self): """Try to validate and then process the DirectPayment form.""" warn_untested() form = self.payment_form_cls(self.request.POST) if form.is_valid(): success = form.process(self.request, self.item) if success: return HttpResponseRedirect(self.success_url) else: self.context['errors'] = self.errors['processing'] self.context[self.form_context_name] = form self.context.setdefault("errors", self.errors['form']) return TemplateResponse(self.request, self.payment_template, self.context)
def redirect_to_express(self): """ First step of ExpressCheckout. Redirect the request to PayPal using the data returned from setExpressCheckout. """ wpp = PayPalWPP(self.request) try: nvp_obj = wpp.setExpressCheckout(self.item) except PayPalFailure: warn_untested() self.context['errors'] = self.errors['paypal'] return self.render_payment_form() else: return HttpResponseRedirect( express_endpoint_for_token(nvp_obj.token))
def validate_payment_form(self): """Try to validate and then process the DirectPayment form.""" warn_untested() form = self.payment_form_cls(self.request.POST) if form.is_valid(): success = form.process(self.request, self.item) if success: return HttpResponseRedirect(self.success_url) else: self.context['errors'] = self.errors['processing'] self.context[self.form_context_name] = form self.context.setdefault("errors", self.errors['form']) return TemplateResponse(self.request, self.payment_template, self.context)
def compress(self, data_list): warn_untested() if data_list: if data_list[1] in forms.fields.EMPTY_VALUES: error = self.error_messages['invalid_year'] raise forms.ValidationError(error) if data_list[0] in forms.fields.EMPTY_VALUES: error = self.error_messages['invalid_month'] raise forms.ValidationError(error) year = int(data_list[1]) month = int(data_list[0]) # find last day of the month day = monthrange(year, month)[1] return date(year, month, day) return None
def compress(self, data_list): warn_untested() if data_list: if data_list[1] in forms.fields.EMPTY_VALUES: error = self.error_messages['invalid_year'] raise forms.ValidationError(error) if data_list[0] in forms.fields.EMPTY_VALUES: error = self.error_messages['invalid_month'] raise forms.ValidationError(error) year = int(data_list[1]) month = int(data_list[0]) # find last day of the month day = monthrange(year, month)[1] return date(year, month, day) return None
def send_signals(self): """Shout for the world to hear whether a txn was successful.""" if self.flag: invalid_ipn_received.send(sender=self) payment_was_flagged.send(sender=self) return else: valid_ipn_received.send(sender=self) # Transaction signals: if self.is_transaction(): if self.is_refund(): payment_was_refunded.send(sender=self) elif self.is_reversed(): payment_was_reversed.send(sender=self) else: payment_was_successful.send(sender=self) # Recurring payment signals: # XXX: Should these be merged with subscriptions? elif self.is_recurring(): if self.is_recurring_create(): recurring_create.send(sender=self) elif self.is_recurring_payment(): warn_untested() recurring_payment.send(sender=self) elif self.is_recurring_cancel(): recurring_cancel.send(sender=self) elif self.is_recurring_skipped(): recurring_skipped.send(sender=self) elif self.is_recurring_failed(): recurring_failed.send(sender=self) # Subscription signals: else: warn_untested() if self.is_subscription_cancellation(): subscription_cancel.send(sender=self) elif self.is_subscription_signup(): subscription_signup.send(sender=self) elif self.is_subscription_end_of_term(): subscription_eot.send(sender=self) elif self.is_subscription_modified(): subscription_modify.send(sender=self)
def process(self, request, item): """Do a direct payment.""" warn_untested() from paypal.pro.helpers import PayPalWPP wpp = PayPalWPP(request) # Change the model information into a dict that PayPal can understand. params = model_to_dict(self, exclude=self.ADMIN_FIELDS) params['acct'] = self.acct params['creditcardtype'] = self.creditcardtype params['expdate'] = self.expdate params['cvv2'] = self.cvv2 params.update(item) # Create recurring payment: if 'billingperiod' in params: return wpp.createRecurringPaymentsProfile(params, direct=True) # Create single payment: else: return wpp.doDirectPayment(params)
def process(self, request, item): """Do a direct payment.""" warn_untested() from paypal.pro.helpers import PayPalWPP wpp = PayPalWPP(request) # Change the model information into a dict that PayPal can understand. params = model_to_dict(self, exclude=self.ADMIN_FIELDS) params['acct'] = self.acct params['creditcardtype'] = self.creditcardtype params['expdate'] = self.expdate params['cvv2'] = self.cvv2 params.update(item) # Create recurring payment: if 'billingperiod' in params: return wpp.createRecurringPaymentsProfile(params, direct=True) # Create single payment: else: return wpp.doDirectPayment(params)
def validate_confirm_form(self): """ Third and final step of ExpressCheckout. Request has pressed the confirmation but and we can send the final confirmation to PayPal using the data from the POST'ed form. """ wpp = PayPalWPP(self.request) pp_data = dict(token=self.request.POST['token'], payerid=self.request.POST['PayerID']) self.item.update(pp_data) # @@@ This check and call could be moved into PayPalWPP. try: if self.is_recurring(): warn_untested() nvp = wpp.createRecurringPaymentsProfile(self.item) else: nvp = wpp.doExpressCheckoutPayment(self.item) self.handle_nvp(nvp) except PayPalFailure: self.context['errors'] = self.errors['processing'] return self.render_payment_form() else: return HttpResponseRedirect(self.success_url)
def process(self, request, item): """Process a PayPal direct payment.""" warn_untested() from paypal.pro.helpers import PayPalWPP wpp = PayPalWPP(request) params = self.cleaned_data params['creditcardtype'] = self.fields['acct'].card_type params['expdate'] = self.cleaned_data['expdate'].strftime("%m%Y") params['ipaddress'] = request.META.get("REMOTE_ADDR", "") params.update(item) try: # Create single payment: if 'billingperiod' not in params: wpp.doDirectPayment(params) # Create recurring payment: else: wpp.createRecurringPaymentsProfile(params, direct=True) except PayPalFailure: return False return True
def init(self, request, paypal_request, paypal_response): """Initialize a PayPalNVP instance from a HttpRequest.""" if request is not None: from paypal.pro.helpers import strip_ip_port self.ipaddress = strip_ip_port(request.META.get('REMOTE_ADDR', '')) if (hasattr(request, "user") and request.user.is_authenticated): self.user = request.user else: self.ipaddress = '' # No storing credit card info. query_data = dict((k, v) for k, v in paypal_request.items() if k not in self.RESTRICTED_FIELDS) self.query = urlencode(query_data) self.response = urlencode(paypal_response) # Was there a flag on the play? ack = paypal_response.get('ack', False) if ack != "Success": if ack == "SuccessWithWarning": warn_untested() self.flag_info = paypal_response.get('l_longmessage0', '') else: self.set_flag(paypal_response.get('l_longmessage0', ''), paypal_response.get('l_errorcode', ''))
def validate_confirm_form(self): """ Third and final step of ExpressCheckout. Request has pressed the confirmation but and we can send the final confirmation to PayPal using the data from the POST'ed form. """ wpp = PayPalWPP(self.request) pp_data = dict(token=self.request.POST['token'], payerid=self.request.POST['PayerID']) self.item.update(pp_data) # @@@ This check and call could be moved into PayPalWPP. try: if self.is_recurring(): warn_untested() nvp = wpp.createRecurringPaymentsProfile(self.item) else: nvp = wpp.doExpressCheckoutPayment(self.item) self.handle_nvp(nvp) except PayPalFailure: self.context['errors'] = self.errors['processing'] return self.render_payment_form() else: return HttpResponseRedirect(self.success_url)
def process_pdt(request): """ Payment data transfer implementation: https://developer.paypal.com/webapps/developer/docs/classic/products/payment-data-transfer/ This function returns a tuple of (pdt_obj, failed) pdt_obj is an object of type PayPalPDT failed is a flag that is True if the input data didn't pass basic validation. Note: even for failed=False You must still check the pdt_obj is not flagged i.e. pdt_obj.flag == False """ pdt_obj = None txn_id = request.GET.get('tx') failed = False if txn_id is not None: # If an existing transaction with the id tx exists: use it try: pdt_obj = PayPalPDT.objects.get(txn_id=txn_id) except PayPalPDT.DoesNotExist: # This is a new transaction so we continue processing PDT request pass if pdt_obj is None: form = PayPalPDTForm(request.GET) if form.is_valid(): try: pdt_obj = form.save(commit=False) except Exception as e: warn_untested() error = repr(e) failed = True else: warn_untested() error = form.errors failed = True if failed: warn_untested() pdt_obj = PayPalPDT() pdt_obj.set_flag("Invalid form. %s" % error) pdt_obj.initialize(request) if not failed: # The PDT object gets saved during verify pdt_obj.verify() else: pass # we ignore any PDT requests that don't have a transaction id return (pdt_obj, failed)
def process_pdt(request): """ Payment data transfer implementation: https://developer.paypal.com/webapps/developer/docs/classic/products/payment-data-transfer/ This function returns a tuple of (pdt_obj, failed) pdt_obj is an object of type PayPalPDT failed is a flag that is True if the input data didn't pass basic validation. Note: even for failed=False You must still check the pdt_obj is not flagged i.e. pdt_obj.flag == False """ pdt_obj = None txn_id = request.GET.get("tx") failed = False if txn_id is not None: # If an existing transaction with the id tx exists: use it try: pdt_obj = PayPalPDT.objects.get(txn_id=txn_id) except PayPalPDT.DoesNotExist: # This is a new transaction so we continue processing PDT request pass if pdt_obj is None: form = PayPalPDTForm(request.GET) if form.is_valid(): try: pdt_obj = form.save(commit=False) except Exception as e: warn_untested() error = repr(e) failed = True else: warn_untested() error = form.errors failed = True if failed: warn_untested() pdt_obj = PayPalPDT() pdt_obj.set_flag(f"Invalid form. {error}") pdt_obj.initialize(request) if not failed: # The PDT object gets saved during verify pdt_obj.verify() else: pass # we ignore any PDT requests that don't have a transaction id return (pdt_obj, failed)
def is_donation(self): warn_untested() return self.button_type == self.DONATE
def is_subscription_cancellation(self): warn_untested() return self.txn_type == "subscr_cancel"
def is_subscription_end_of_term(self): warn_untested() return self.txn_type == "subscr_eot"
def is_subscription_signup(self): warn_untested() return self.txn_type == "subscr_signup"
def as_p(self): warn_untested() return mark_safe(u""" <input type="hidden" name="cmd" value="_s-xclick" /> <input type="hidden" name="encrypted" value="%s" /> """ % self._encrypt())
def is_recurring_suspended_due_to_max_failed_payment(self): warn_untested() return self.txn_type == "recurring_payment_suspended_due_to_max_failed_payment"
def is_transaction(self): warn_untested() return not self.is_subscription()
def is_donation(self): warn_untested() return self.button_type == self.DONATE
def is_subscription(self): warn_untested() return self.button_type == self.SUBSCRIBE
def clean(self, value): warn_untested() exp = super(CreditCardExpiryField, self).clean(value) if date.today() > exp: raise forms.ValidationError("The expiration date you entered is in the past.") return exp
def ipn(request): """ PayPal IPN endpoint (notify_url). Used by both PayPal Payments Pro and Payments Standard to confirm transactions. http://tinyurl.com/d9vu9d PayPal IPN Simulator: https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session """ # TODO: Clean up code so that we don't need to set None here and have a lot # of if checks just to determine if flag is set. flag = None ipn_obj = None # Avoid the RawPostDataException. See original issue for details: # https://github.com/spookylukey/django-paypal/issues/79 if not request.META.get('CONTENT_TYPE', '').startswith( 'application/x-www-form-urlencoded'): raise AssertionError(CONTENT_TYPE_ERROR) logger.debug("PayPal incoming POST data: %s", request.body) # Clean up the data as PayPal sends some weird values such as "N/A" # Also, need to cope with custom encoding, which is stored in the body (!). # Assuming the tolerant parsing of QueryDict and an ASCII-like encoding, # such as windows-1252, latin1 or UTF8, the following will work: encoding = request.POST.get('charset', None) encoding_missing = encoding is None if encoding_missing: encoding = DEFAULT_ENCODING try: data = QueryDict(request.body, encoding=encoding).copy() except LookupError: warn_untested() data = None flag = "Invalid form - invalid charset" if data is not None: if hasattr(PayPalIPN._meta, 'get_fields'): date_fields = [f.attname for f in PayPalIPN._meta.get_fields() if f.__class__.__name__ == 'DateTimeField'] else: date_fields = [f.attname for f, m in PayPalIPN._meta.get_fields_with_model() if f.__class__.__name__ == 'DateTimeField'] for date_field in date_fields: if data.get(date_field) == 'N/A': del data[date_field] form = PayPalIPNForm(data) if form.is_valid(): try: # When commit = False, object is returned without saving to DB. ipn_obj = form.save(commit=False) except Exception as e: flag = "Exception while processing. (%s)" % e else: formatted_form_errors = ["{0}: {1}".format(k, ", ".join(v)) for k, v in form.errors.items()] flag = "Invalid form. ({0})".format(", ".join(formatted_form_errors)) if ipn_obj is None: ipn_obj = PayPalIPN() # Set query params and sender's IP address ipn_obj.initialize(request) if flag is not None: # We save errors in the flag field ipn_obj.set_flag(flag) else: # Secrets should only be used over SSL. if request.is_secure() and 'secret' in request.GET: warn_untested() ipn_obj.verify_secret(form, request.GET['secret']) else: ipn_obj.verify() ipn_obj.save() ipn_obj.send_signals() if encoding_missing: # Wait until we have an ID to log warning logger.warning("No charset passed with PayPalIPN: %s. Guessing %s", ipn_obj.id, encoding) return HttpResponse("OKAY")
def is_billing_agreement_create(self): warn_untested() return self.txn_type == "mp_signup"
def paypal_time(time_obj=None): """Returns a time suitable for PayPal time fields.""" warn_untested() if time_obj is None: time_obj = time.gmtime() return time.strftime(PayPalNVP.TIMESTAMP_FORMAT, time_obj)
def is_billing_agreement_cancel(self): warn_untested() return self.txn_type == "mp_cancel"
def verify_secret(self, form_instance, secret): """Verifies an IPN payment over SSL using EWP.""" warn_untested() if not check_secret(form_instance, secret): self.set_flag("Invalid secret. (%s)") % secret self.save()
def verify_secret(self, form_instance, secret): """Verifies an IPN payment over SSL using EWP.""" warn_untested() if not check_secret(form_instance, secret): self.set_flag("Invalid secret. (%s)") % secret self.save()
def is_billing_agreement_cancel(self): warn_untested() return self.txn_type == "mp_cancel"
def is_recurring_suspended(self): warn_untested() return self.txn_type == "recurring_payment_suspended"
def is_billing_agreement_create(self): warn_untested() return self.txn_type == "mp_signup"
def is_subscription_modified(self): warn_untested() return self.txn_type == "subscr_modify"
def is_billing_agreement(self): warn_untested() return len(self.mp_id) > 0
def paypal_time(time_obj=None): """Returns a time suitable for PayPal time fields.""" warn_untested() if time_obj is None: time_obj = time.gmtime() return time.strftime(PayPalNVP.TIMESTAMP_FORMAT, time_obj)
def is_recurring_suspended_due_to_max_failed_payment(self): warn_untested() return self.txn_type == "recurring_payment_suspended_due_to_max_failed_payment"
def is_transaction(self): warn_untested() return not self.is_subscription()
def is_billing_agreement(self): warn_untested() return len(self.mp_id) > 0
def is_subscription(self): warn_untested() return self.button_type == self.SUBSCRIBE
def get_sha1_hexdigest(salt, raw_password): warn_untested() return hashlib.sha1(smart_str(salt) + smart_str(raw_password)).hexdigest()