from payflowpro.classes import (CreditCard, Amount, Profile, Address, Tracking, Response, CustomerInfo, AchPayment) from payflowpro.client import PayflowProClient, find_classes_in_list, find_class_in_list #PARTNER_ID = 'Paypal' #VENDOR_ID = 'wiremine' #USERNAME = '******' #PASSWORD = '******' client = PayflowProClient(partner=PARTNER_ID, vendor=VENDOR_ID, username=USERNAME, password=PASSWORD, url_base='https://pilot-payflowpro.paypal.com') credit_card = CreditCard(acct=5555555555554444, expdate="1212") responses, unconsumed_data = client.sale(credit_card, Amount(amt=15, currency="USD"), extras=[Address(street="82 E 38th Street", zip="49423")]) #arc_payment = AchPayment(aba='111111118', acct='1111111111', accttype='S') #customer = CustomerInfo(firstname='Bob Smith') #responses, unconsumed_data = client.sale(arc_payment, Amount(amt=15, currency="USD"), extras=[customer]) print responses[0]
class PaymentProcessor(BasePaymentProcessor): """ PayflowPro payment processing module You must have an account with PayPal in order to use this module. """ def __init__(self, settings): super(PaymentProcessor, self).__init__('payflowpro', settings) partner = self.settings.PARTNER.value vendor = self.settings.VENDOR.value username = self.settings.USER.value password = self.settings.PASSWORD.value testing = not self.settings.LIVE.value if testing: url_base = PayflowProClient.URL_BASE_TEST else: url_base = PayflowProClient.URL_BASE_LIVE self.payflow = PayflowProClient(partner=partner, vendor=vendor, username=username, password=password, url_base=url_base) def get_charge_data(self, amount=None): """ Build the dictionary needed to process a credit card charge. Return: a dictionary with the following key-values: * log_string: the transaction data without the sensible buyer data. Suitable for logs. * credit_card, amount, address, ship_address, customer_info : the payflowpro.classes.* instances to be passed to self.payflow """ order = self.order if amount is None: amount = order.balance balance = trunc_decimal(amount, 2) ret = { 'credit_card': CreditCard( acct=order.credit_card.decryptedCC, expdate="%02d%02d" % (order.credit_card.expire_month, order.credit_card.expire_year % 100), cvv2=order.credit_card.ccv, ), 'amount': Amount(amt=balance,), 'address': Address( street=order.full_bill_street, zip=order.bill_postal_code, city=order.bill_city, state=order.bill_state, country=order.bill_country, ), 'ship_address': ShippingAddress( shiptostreet=order.full_ship_street, shiptocity=order.ship_city, shiptofirstname=order.ship_first_name, shiptolastname=order.ship_last_name, shiptostate=order.ship_state, shiptocountry=order.ship_country, shiptozip=order.ship_postal_code, ), 'customer_info': CustomerInfo( firstname=order.contact.first_name, lastname=order.contact.last_name, ), } redacted_data = ret.copy() redacted_data['credit_card'] = { 'acct': order.credit_card.display_cc, 'expdate': "%d%d" % (order.credit_card.expire_year, order.credit_card.expire_month), 'cvv2': "REDACTED", } dicts = [getattr(d, 'data', d) for d in redacted_data.values()] ret['log_string'] = "\n".join("%s: %s" % (k, v) for d in dicts for k, v in d.items()) return ret def _handle_unconsumed(self, unconsumed_data): """ Handler for when we've got unconsumed data from the response """ if unconsumed_data: self.log.warn("Something went wrong with python-payflowpro. " "We got some unconsumed data: %s" % str(unconsumed_data)) def _log_responses(self, responses): """ Log the responses from PayflowPro for debugging """ self.log_extra("Response variables from payflowpro:") for response in responses: self.log_extra("%(classname)s: %(response_fields)s" % { 'classname': response.__class__.__name__, 'response_fields': "%s" % response.data }) def authorize_payment(self, order=None, amount=None, testing=False): """ Authorize a single payment. Returns: ProcessorResult """ if order: self.prepare_data(order) else: order = self.order if order.paid_in_full: self.log_extra('%s is paid in full, no authorization attempted.', order) result = ProcessorResult(self.key, True, _("No charge needed, paid in full.")) else: self.log_extra('Authorizing payment of %s for %s', amount, order) data = self.get_charge_data(amount=amount) data['extras'] = [data['address'], data['ship_address'], data['customer_info'],] result = self.send_post(data=data, testing=testing, post_func=self.send_authorize_post,) return result def can_authorize(self): return True #def can_recur_bill(self): # return True def capture_authorized_payment(self, authorization, testing=False, order=None, amount=None): """ Capture a single payment """ if order: self.prepare_data(order) else: order = self.order if order.authorized_remaining == Decimal('0.00'): self.log_extra('No remaining authorizations on %s', order) return ProcessorResult(self.key, True, _("Already complete")) self.log_extra('Capturing Authorization #%i for %s', authorization.id, order) data = self.get_charge_data() data['authorization_id'] = authorization.transaction_id result = self.send_post(data=data, testing=testing, post_func=self.send_capture_post,) return result def capture_payment(self, testing=False, order=None, amount=None): """ Process payments without an authorization step. """ if order: self.prepare_data(order) else: order = self.order if order.paid_in_full: self.log_extra('%s is paid in full, no capture attempted.', order) result = ProcessorResult(self.key, True, _("No charge needed, " "paid in full.")) self.record_payment() else: self.log_extra('Capturing payment for %s', order) data = self.get_charge_data(amount=amount) data['extras'] = [data['address'], data['ship_address'], data['customer_info'],] result = self.send_post(data=data, post_func=self.send_sale_post, testing=testing,) return result def release_authorized_payment(self, order=None, auth=None, testing=False): """Release a previously authorized payment.""" if order: self.prepare_data(order) else: order = self.order self.log_extra('Releasing Authorization #%i for %s', auth.id, order) data = self.get_charge_data() data['authorization_id'] = auth.transaction_id result = self.send_post(data=data, post_func=self.send_release_post, testing=testing) if result.success: auth.complete = True auth.save() return result def send_authorize_post(self, data): """ Authorize sell with PayflowPro """ responses, unconsumed_data = self.payflow.authorization( credit_card=data['credit_card'], amount=data['amount'], extras=data['extras']) return responses, unconsumed_data, self.record_authorization def send_capture_post(self, data): """ Capture previously authorized sale """ responses, unconsumed_data = self.payflow.capture( data['authorization_id']) return responses, unconsumed_data, self.record_payment def send_release_post(self, data): """ Release previously authorized sale """ responses, unconsumed_data = self.payflow.void( data['authorization_id']) def nothing(*args, **kwargs): return None return responses, unconsumed_data, nothing def send_sale_post(self, data): """ Immediately charge a credit card """ responses, unconsumed_data = self.payflow.sale( credit_card=data['credit_card'], amount=data['amount'], extras=data['extras']) return responses, unconsumed_data, self.record_payment def send_post(self, data, post_func, testing=False): """ Execute the post to PayflowPro. Params: - data: the argument expected by `post_func`. Usually a dict which this function knows how to use - post_func: a function that takes `data` as argument, and sends the actual request to the PayflowPro Gateway. It should return a 3-tuple (responses, unconsumed_data, record_* function) - testing: if true, then don't record the payment Returns: - ProcessorResult """ self.log_extra("About to send PayflowPro a request: %s", data['log_string']) if 'amount' in data: amount = data['amount'].amt else: amount = self.order.balance responses, unconsumed_data, record_function = post_func(data) self._handle_unconsumed(unconsumed_data) self._log_responses(responses) response = responses[0] success = response.result == '0' transaction_id = response.pnref response_text = response.respmsg reason_code = response.result if success: # success! self.log.info("successful %s for order #%d", post_func.__name__, self.order.id) if not testing: self.log_extra("Success, calling %s", record_function.__name__) payment = record_function( order=self.order, amount=amount, transaction_id=transaction_id, reason_code=reason_code) else: # failure =( self.log.info("failed %s for order #%d", post_func.__name__, self.order.id) if not testing: payment = self.record_failure( amount=amount, transaction_id=transaction_id, reason_code=reason_code, details=response_text) self.log_extra("Returning success=%s, reason=%s, response_text=%s", success, reason_code, response_text) return ProcessorResult(self.key, success, response_text, payment=payment)
class PaymentProcessor(BasePaymentProcessor): """ PayflowPro payment processing module You must have an account with PayPal in order to use this module. """ def __init__(self, settings): super(PaymentProcessor, self).__init__('payflowpro', settings) partner = self.settings.PARTNER.value vendor = self.settings.VENDOR.value username = self.settings.USER.value password = self.settings.PASSWORD.value testing = not self.settings.LIVE.value if testing: url_base = PayflowProClient.URL_BASE_TEST else: url_base = PayflowProClient.URL_BASE_LIVE self.payflow = PayflowProClient(partner=partner, vendor=vendor, username=username, password=password, url_base=url_base) def get_charge_data(self, amount=None): """ Build the dictionary needed to process a credit card charge. Return: a dictionary with the following key-values: * log_string: the transaction data without the sensible buyer data. Suitable for logs. * credit_card, amount, address, ship_address, customer_info : the payflowpro.classes.* instances to be passed to self.payflow """ order = self.order if amount is None: amount = order.balance balance = trunc_decimal(amount, 2) ret = { 'credit_card': CreditCard( acct=order.credit_card.decryptedCC, expdate="%02d%02d" % (order.credit_card.expire_month, order.credit_card.expire_year % 100), cvv2=order.credit_card.ccv, ), 'amount': Amount(amt=balance,), 'address': Address( street=order.full_bill_street, zip=order.bill_postal_code, city=order.bill_city, state=order.bill_state, country=order.bill_country, ), 'ship_address': ShippingAddress( shiptostreet=order.full_ship_street, shiptocity=order.ship_city, shiptofirstname=order.ship_first_name, shiptolastname=order.ship_last_name, shiptostate=order.ship_state, shiptocountry=order.ship_country, shiptozip=order.ship_postal_code, ), 'customer_info': CustomerInfo( firstname=order.bill_first_name, lastname=order.bill_last_name, ), } redacted_data = ret.copy() redacted_data['credit_card'] = { 'acct': order.credit_card.display_cc, 'expdate': "%d%d" % (order.credit_card.expire_year, order.credit_card.expire_month), 'cvv2': "REDACTED", } dicts = [getattr(d, 'data', d) for d in redacted_data.values()] ret['log_string'] = "\n".join("%s: %s" % (k, v) for d in dicts for k, v in d.items()) return ret def _handle_unconsumed(self, unconsumed_data): """ Handler for when we've got unconsumed data from the response """ if unconsumed_data: self.log.warn("Something went wrong with python-payflowpro. " "We got some unconsumed data: %s" % str(unconsumed_data)) def _log_responses(self, responses): """ Log the responses from PayflowPro for debugging """ self.log_extra("Response variables from payflowpro:") for response in responses: self.log_extra("%(classname)s: %(response_fields)s" % { 'classname': response.__class__.__name__, 'response_fields': "%s" % response.data }) def authorize_payment(self, order=None, amount=None, testing=False): """ Authorize a single payment. Returns: ProcessorResult """ if order: self.prepare_data(order) else: order = self.order if order.paid_in_full: self.log_extra('%s is paid in full, no authorization attempted.', order) result = ProcessorResult(self.key, True, _("No charge needed, paid in full.")) else: self.log_extra('Authorizing payment of %s for %s', amount, order) data = self.get_charge_data(amount=amount) data['extras'] = [data['address'], data['ship_address'], data['customer_info'],] result = self.send_post(data=data, testing=testing, post_func=self.send_authorize_post,) return result def can_authorize(self): return True #def can_recur_bill(self): # return True def capture_authorized_payment(self, authorization, testing=False, order=None, amount=None): """ Capture a single payment """ if order: self.prepare_data(order) else: order = self.order if order.authorized_remaining == Decimal('0.00'): self.log_extra('No remaining authorizations on %s', order) return ProcessorResult(self.key, True, _("Already complete")) self.log_extra('Capturing Authorization #%i for %s', authorization.id, order) data = self.get_charge_data() data['authorization_id'] = authorization.transaction_id result = self.send_post(data=data, testing=testing, post_func=self.send_capture_post,) return result def capture_payment(self, testing=False, order=None, amount=None): """ Process payments without an authorization step. """ if order: self.prepare_data(order) else: order = self.order if order.paid_in_full: self.log_extra('%s is paid in full, no capture attempted.', order) result = ProcessorResult(self.key, True, _("No charge needed, " "paid in full.")) self.record_payment() else: self.log_extra('Capturing payment for %s', order) data = self.get_charge_data(amount=amount) data['extras'] = [data['address'], data['ship_address'], data['customer_info'],] result = self.send_post(data=data, post_func=self.send_sale_post, testing=testing,) return result def release_authorized_payment(self, order=None, auth=None, testing=False): """Release a previously authorized payment.""" if order: self.prepare_data(order) else: order = self.order self.log_extra('Releasing Authorization #%i for %s', auth.id, order) data = self.get_charge_data() data['authorization_id'] = auth.transaction_id result = self.send_post(data=data, post_func=self.send_release_post, testing=testing) if result.success: auth.complete = True auth.save() return result def send_authorize_post(self, data): """ Authorize sell with PayflowPro """ responses, unconsumed_data = self.payflow.authorization( credit_card=data['credit_card'], amount=data['amount'], extras=data['extras']) return responses, unconsumed_data, self.record_authorization def send_capture_post(self, data): """ Capture previously authorized sale """ responses, unconsumed_data = self.payflow.capture( data['authorization_id']) return responses, unconsumed_data, self.record_payment def send_release_post(self, data): """ Release previously authorized sale """ responses, unconsumed_data = self.payflow.void( data['authorization_id']) def nothing(*args, **kwargs): return None return responses, unconsumed_data, nothing def send_sale_post(self, data): """ Immediately charge a credit card """ responses, unconsumed_data = self.payflow.sale( credit_card=data['credit_card'], amount=data['amount'], extras=data['extras']) return responses, unconsumed_data, self.record_payment def send_post(self, data, post_func, testing=False): """ Execute the post to PayflowPro. Params: - data: the argument expected by `post_func`. Usually a dict which this function knows how to use - post_func: a function that takes `data` as argument, and sends the actual request to the PayflowPro Gateway. It should return a 3-tuple (responses, unconsumed_data, record_* function) - testing: if true, then don't record the payment Returns: - ProcessorResult """ self.log_extra("About to send PayflowPro a request: %s", data['log_string']) if 'amount' in data: amount = data['amount'].amt else: amount = self.order.balance responses, unconsumed_data, record_function = post_func(data) self._handle_unconsumed(unconsumed_data) self._log_responses(responses) response = responses[0] success = response.result == '0' transaction_id = response.pnref response_text = response.respmsg reason_code = response.result if success: # success! self.log.info("successful %s for order #%d", post_func.__name__, self.order.id) if not testing: self.log_extra("Success, calling %s", record_function.__name__) payment = record_function( order=self.order, amount=amount, transaction_id=transaction_id, reason_code=reason_code) else: # failure =( self.log.info("failed %s for order #%d", post_func.__name__, self.order.id) if not testing: payment = self.record_failure( amount=amount, transaction_id=transaction_id, reason_code=reason_code, details=response_text) self.log_extra("Returning success=%s, reason=%s, response_text=%s", success, reason_code, response_text) return ProcessorResult(self.key, success, response_text, payment=payment)
from payflowpro.classes import (CreditCard, Amount, Profile, Address, Tracking, Response, CustomerInfo, AchPayment) from payflowpro.client import PayflowProClient, find_classes_in_list, find_class_in_list #PARTNER_ID = 'Paypal' #VENDOR_ID = 'wiremine' #USERNAME = '******' #PASSWORD = '******' client = PayflowProClient(partner=PARTNER_ID, vendor=VENDOR_ID, username=USERNAME, password=PASSWORD, url_base='https://pilot-payflowpro.paypal.com') credit_card = CreditCard(acct=5555555555554444, expdate="1212") responses, unconsumed_data = client.sale( credit_card, Amount(amt=15, currency="USD"), extras=[Address(street="82 E 38th Street", zip="49423")]) #arc_payment = AchPayment(aba='111111118', acct='1111111111', accttype='S') #customer = CustomerInfo(firstname='Bob Smith') #responses, unconsumed_data = client.sale(arc_payment, Amount(amt=15, currency="USD"), extras=[customer]) print responses[0]
class PayPalConnection (OnlinePaymentBase): # map codes to exceptions - tuples denote ranges CODE_MAP = OnlinePaymentBase._explode_map({ 1 : OnlinePaymentBase.AuthError, 2 : OnlinePaymentBase.InvalidCardType, 4 : OnlinePaymentBase.AmountInvalid, 12 : OnlinePaymentBase.TransactionDeclined, 23 : OnlinePaymentBase.CardNumberInvalid, 24 : OnlinePaymentBase.CardExpirationInvalid, 26 : OnlinePaymentBase.AuthError, 30 : OnlinePaymentBase.DuplicateTransaction, 33 : OnlinePaymentBase.RecurringOrderDoesNotExist, 50 : OnlinePaymentBase.TransactionDeclined, 51 : OnlinePaymentBase.AmountTooHigh, 102 : OnlinePaymentBase.TryAgainLater, 106 : OnlinePaymentBase.TryAgainLater, 112 : OnlinePaymentBase.AVSFailure, 114 : OnlinePaymentBase.CCVInvalid, (125,128) : OnlinePaymentBase.FraudCheckFailed, }) TRANS_STATES = { 1: 'error', 6: 'settlement pending', 7: 'settlement in progress', 8: 'settlement completed/successfully', 11: 'settlement failed', 14: 'settlement incomplete', } FIELD_MAP = { 'card_num' : 'acct', 'card_code' : 'cvv2', 'exp_date' : 'expdate', 'amount' : 'amt', 'address' : 'street', 'company' : 'companyname', 'description' : 'comment1', 'ship_to_address' : 'shiptostreet', 'ship_to_first_name' : 'shiptofirstname', 'ship_to_last_name' : 'shiptolastname', 'ship_to_country' : 'shiptocountry', 'ship_to_city' : 'shiptocity', 'ship_to_state' : 'shiptostate', 'ship_to_zip' : 'shiptozip', 'first_name' : 'firstname', 'last_name' : 'lastname', 'phone' : 'phonenum', 'invoice_num' : 'ponum', # recurring fields 'recurring_id' : 'profile_id', 'recurring_start' : 'start', 'recurring_period' : 'payperiod', 'recurring_total_occurrences' : 'term', } RECURRING_FIELD_MAPPING = { 'AMT' : 'amount', 'START' : 'start', 'NEXTPAYMENT' : 'next', 'AGGREGATEAMT' : 'total', 'NUMFAILPAYMENTS' : 'failed_payments' } PAY_PERIOD_MAPPING = { 'months': 'MONT', 'weeks' : 'WEEK', } REVERSE_PAY_PERIOD_MAPPING = dict( (v,k) for (k,v) in PAY_PERIOD_MAPPING.items()) def __init__(self, **kwargs): super(PayPalConnection, self).__init__(**kwargs) if not self.debug: logging.getLogger('payflow_pro').setLevel(logging.WARNING) url_base = PayflowProClient.URL_BASE_TEST if self.test_mode \ else PayflowProClient.URL_BASE_LIVE self.cc = PayflowProClient(url_base=url_base, **self.auth) def validate_auth(self, auth): for key in ("partner", "vendor", "username", "password"): if not key in auth: raise InvalidAuthException("Missing required '%s' parameter."\ % key) def authorize(self, **kwargs): (card, amount, extras) = self._process_params(kwargs) sale_result = self.cc.authorization(card, amount, extras=extras) result = self._munge_result(sale_result) self._handle_errors(result) return result def capture(self, **kwargs): trans_id = kwargs['trans_id'] del(kwargs['trans_id']) # card and amount aren't really used here (card, amount, extras) = self._process_params(kwargs) sale_result = self.cc.capture(trans_id, extras=extras) result = self._munge_result(sale_result) self._handle_errors(result) return result def sale(self, **kwargs): (card, amount, extras) = self._process_params(kwargs) sale_result = self.cc.sale(card, amount, extras=extras) result = self._munge_result(sale_result) self._handle_errors(result) return result def void(self, **kwargs): trans_id = kwargs['trans_id'] del(kwargs['trans_id']) # card and amount aren't really used here (card, amount, extras) = self._process_params(kwargs) void_result = self.cc.void(trans_id, extras=extras) result = self._munge_result(void_result) self._handle_errors(result) return result def credit(self, **kwargs): trans_id = kwargs['trans_id'] del(kwargs['trans_id']) # card and amount aren't really used here (card, amount, extras) = self._process_params(kwargs) credit_result = self.cc.credit_referenced(trans_id, extras=extras) result = self._munge_result(credit_result) self._handle_errors(result) return result def inquiry(self, **kwargs): trans_id = kwargs['trans_id'] del(kwargs['trans_id']) inquiry_result = self.cc.inquiry(original_pnref=trans_id) result = self._munge_result(inquiry_result) self._handle_errors(result) return result def recurring_order_create(self, **kwargs): (card, amount, extras) = self._process_params(kwargs) (profile,) = find_classes_in_list(Profile, extras) result = self.cc.profile_add(profile, card, amount, extras=extras) result = self._munge_result(result) self._handle_errors(result) logging.debug('result = %s' % (result,)) return result def recurring_order_update(self, **kwargs): profile_id = kwargs['recurring_id'] del(kwargs['recurring_id']) (card, amount, extras) = self._process_params(kwargs) # everything is an extra for update extras.append(amount) extras.append(card) result = self.cc.profile_modify(profile_id, extras=extras) result = self._munge_result(result) self._handle_errors(result) return result def recurring_order_cancel(self, **kwargs): profile_id = kwargs['recurring_id'] del(kwargs['recurring_id']) result = self.cc.profile_cancel(profile_id) result = self._munge_result(result) self._handle_errors(result) return result def recurring_order_payments(self, **kwargs): profile_id = kwargs['recurring_id'] del(kwargs['recurring_id']) payment_history_only = kwargs.get('payment_history_only', True) result = self.cc.profile_inquiry( profile_id, payment_history_only=payment_history_only) result = self._munge_result(result) self._handle_errors(result) return result def recurring_order_inquiry(self, **kwargs): return \ self.recurring_order_payments(payment_history_only=False, **kwargs) # override process params to build payflow objects after mapping names def _process_params(self, kwargs): # check and process params kwargs = super(PayPalConnection, self)._process_params(kwargs) card = self._build_card(kwargs) amount = self._build_amount(kwargs) extras = self._build_extras(kwargs) # if there's anything left in kwargs it's not getting to # paypal, so log a warning. I'm tempted to make this fatal, # but I imagine in many cases it's not such a big deal - just # a trivial extra field that would be accepted by another # processor that's not applicable to paypal. if len(kwargs): self.log.warning("Extra parameters found: %s" % ','.join(kwargs)) return (card, amount, extras) # Code to build the objects the payflow pro lib uses, only to # flatten them again later. Yeesh. def _build_card(self, param): return CreditCard(acct = param.pop('acct', ''), expdate = param.pop('expdate', ''), cvv2 = param.pop('cvv2', '')) def _build_amount(self, param): return Amount(amt = param.pop('amt', ''), currency = param.pop('currency', 'USD'), taxamt = param.pop('tax','')) def _build_extras(self, param): extras = [] extras.append(self._build_address(param)) extras.append(self._build_tracking(param)) extras.append(self._build_shipping_address(param)) extras.append(self._build_cust_info(param)) extras.append(self._build_purchase_info(param)) extras.append(self._build_recurring_info(param)) return extras def _build_recurring_info(self, param): start = '%s' % param.pop('start', '') if re.match(r'\d{4}-\d{2}-\d{2}', start): start = re.sub(r'^(\d{4})-(\d{2})-(\d{2})', r'\2\3\1', start) profilename = param.pop('profilename', '') if not profilename: profilename = 'Default Profile Name' term = param.pop('term', '0') # default to forever payperiod = param.pop('payperiod', 'MONT') if payperiod in self.PAY_PERIOD_MAPPING: payperiod = self.PAY_PERIOD_MAPPING[payperiod] # For some reason having a blank desc is an error. And it's # only an error on the live server, of course. desc = param.pop('desc', '') if not len(desc): desc = "unused" return Profile( profilename = profilename, start = start, term = term, payperiod = payperiod, maxfailpayments = param.pop('maxfailpayments', ''), desc = desc, optionaltrx = param.pop('optionaltrx', ''), optionaltrxamt = param.pop('optionaltrxamt', ''), status = param.pop('status', ''), paymentsleft = param.pop('paymentsleft', ''), nextpayment = param.pop('nextpayment', ''), end = param.pop('end', ''), numfailpayments = param.pop('numfailpayments', ''), retrynumdays = param.pop('retrynumdays', ''), aggregateamt = param.pop('aggregateamt', ''), aggregateoptionalamt = param.pop('aggregateoptionalamt', '')) def _build_address(self, param): return Address(street = param.pop('street', ''), zip = param.pop('zip', ''), city = param.pop('city', ''), state = param.pop('state', ''), country = param.pop('country', ''), companyname = param.pop('companyname', '')) def _build_tracking(self, param): return Tracking(comment1 = param.pop('comment1',''), comment2 = param.pop('comment2',''), verbosity = param.pop('verbosity','')) def _build_shipping_address(self, param): return ShippingAddress( shiptostreet = param.pop('shiptostreet',''), shiptocity = param.pop('shiptocity',''), shiptofirstname = param.pop('shiptofirstname',''), shiptomiddlename = param.pop('shiptomiddlename',''), shiptolastname = param.pop('shiptolastname',''), shiptostate = param.pop('shiptostate',''), shiptocountry = param.pop('shiptocountry',''), shiptozip = param.pop('shiptozip','')) def _build_cust_info(self, param): return CustomerInfo( custcode = param.pop('custcode',''), email = param.pop('email',''), firstname = param.pop('firstname',''), name = param.pop('name',''), middlename = param.pop('middlename',''), lastname = param.pop('lastname',''), phonenum = param.pop('phonenum','')) def _build_purchase_info(self, param): return PurchaseInfo( ponum = param.pop('ponum','')) def _parse_transaction_time(self, ts): # '24-Nov-09 04:33 AM' parsed = datetime.strptime(ts, '%d-%b-%y %I:%M %p') pacific = pytz.timezone('America/Los_Angeles') return pacific.localize(parsed).astimezone(pytz.utc) # return datetime(utc.year, utc.month, utc.day, utc.hour, utc.second) def _build_recurring_payment(self, payment): return OnlinePaymentRecurringPayment( trans_id = payment.p_pnref, amount = payment.p_amt, trans_timestamp = self._parse_transaction_time(payment.p_transtime), success = payment.p_result == '0', original = payment, ) def _munge_result(self, orig): (response,) = find_classes_in_list([Response],orig[0]) if (self.debug): self.log.debug("Result: %s" % repr(response.__dict__)) result = {} result['code'] = int(response.result) result['message'] = response.respmsg result['success'] = True if result['code'] == 0 else False result['trans_id'] = response.pnref result['orig'] = response # recurring response of some kind (profile_response,) = find_classes_in_list([ProfileResponse], orig[0]) if profile_response: return self._munge_recurring_result(profile_response, result, orig) return OnlinePaymentResult(**result) def _munge_recurring_result(self, profile_response, result, orig): result['trans_id'] = profile_response.rpref if hasattr(profile_response, 'profileid'): result['recurring_id'] = profile_response.profileid else: result['recurring_id'] = None # Profile, means a profile status request? (profile,) = find_classes_in_list([Profile], orig[0]) if profile: payperiod = self.REVERSE_PAY_PERIOD_MAPPING.get( profile.payperiod, profile.payperiod) result['profile'] = OnlinePaymentRecurringProfile( recurring_id = profile_response.profileid, payperiod = payperiod, status = profile.status, start = profile.start, next = profile.nextpayment, amount = '', # profile.amt does not exist, amount not included!? total = profile.aggregateamt, failed_payments = profile.numfailpayments, orig = profile ) # RecurringPayments, means we've got a payment history (profile_payments,) = find_classes_in_list([RecurringPayments], orig[0]) if profile_payments: result['payments'] = [ self._build_recurring_payment(p) for p in profile_payments.payments ] return OnlinePaymentRecurringResult(**result)