I ended up just calling the method directly from my app. Here is a
modified version of the cancel method:
def process_recurring_cancel(self, data, testing=False):
"""Post one subscription cancellation request
Expects data to be a dictionary containing the following:
data['subscription'] = {'id': 123} #(this is the orderitem.id)
data['orderpayment'] = {'transaction_id': 4535454}
"""
self.log_extra('Processing arb_cancel for ARB subscription
(satchmo transaction_id): %s', data['orderpayment']['transaction_id'])
settings = self.settings
# set up the base dictionary
if self.is_live():
conn = settings.ARB_CONNECTION.value
self.log_extra('Using live recurring charge connection.')
else:
conn = settings.ARB_CONNECTION_TEST.value
self.log_extra('Using test recurring charge connection.')
shop_config = Config.objects.get_current()
data['connection'] = conn
data['config'] = {
'merchantID' : settings.LOGIN.value,
'transactionKey' : settings.TRANKEY.value,
'shop_name' : shop_config.store_name,
}
t =
loader.get_template('checkout/authorizenet/arb_cancel_subscription.xml')
ctx = Context(data)
request = t.render(ctx)
# no need for redacted post in cancel request...
headers = {'Content-type':'text/xml'}
conn = urllib2.Request(data['connection'], request, headers)
try:
f = urllib2.urlopen(conn)
all_results = f.read()
except urllib2.URLError, ue:
self.log.error("error opening %s\n%s", data['connection'], ue)
return (False, 'ERROR', _('Could not talk to Authorize.net
gateway'))
self.log_extra('Authorize response: %s', all_results)
try:
response = minidom.parseString(all_results)
doc = response.documentElement
reason = doc.getElementsByTagName('code')[0].firstChild.nodeValue
response_text =
doc.getElementsByTagName('text')[0].firstChild.nodeValue
result =
doc.getElementsByTagName('resultCode')[0].firstChild.nodeValue
success = result == "Ok"
# if result is successful, then set expire_date for the order
# this means the user will have no active subscriptions as far as
# satchmo bookeeping is concerned...
# only allow cancellation if subscription is live....
# (True, u'I00001', u'Successful.')
# (True, u'I00002', u'The subscription has already been canceled.')
success_string = unicode('Successful.')
if response_text == success_string:
order =
OrderItem.objects.get(pk=int((data['subscription']['id'])))
order.expire_date = datetime.date.today()
order.save()
except Exception, e:
self.log.error("Error %s\nCould not parse response: %s",
e, all_results)
success = False
reason = "Parse Error"
response_text = "Could not parse response"
return success, reason, response_text
Here is a sample session that cancels an active subscription:
from satchmo.payment.modules.authorizenet.processor import PaymentProcessor
from profiles.models import *
from django.contrib.auth.models import User
user = User.objects.all()[6]
prof = user.get_profile()
from satchmo.configuration import config_get_group
authorize_settings = config_get_group('PAYMENT_AUTHORIZENET')
processor = PaymentProcessor(authorize_settings)
data = {}
data['subscription'] = {'id': prof.satchmo_subscription_id()}
data['orderpayment'] = {'transaction_id': prof.satchmo_transaction_id()}
processor.process_recurring_cancel(data)
# Out[12]: (True, u'I00001', u'Successful.')
On Mon, Dec 29, 2008 at 6:53 PM, Peter Skomoroch
<[email protected]> wrote:
> I'm trying to decipher how Satchmo actually triggers a call to the
> processor.process() method, so I can do something similar for an ARB
> "cancel" method. In our app, a call to
> HttpResponseRedirect('/store/checkout/') kicks off the
> process_recurring_subscription method, but the chain of intermediate
> events in Satchmo after that is a bit hazy for me
>
> if form.is_valid():
> contact = request.user.contact_set.all()[0]
> cart = form.save(contact=contact)
> request.session['cart'] = cart.id
> return HttpResponseRedirect('/store/checkout/')
>
>
> I've added the following cancel hooks in
> payment/modules/authorizenet/processor.py, but need to figure out how
> to execute them from our App. We can lookup the existing subscription
> order within our app and add it to the request.session dictionary,
> that should have the information needed to cancel the subscription.
> Any suggestions on what to other methods to add or where to look in
> Satchmo to hook these to a url?
>
> def cancel(self, testing=False):
> """cancel subscription"""
> # TODO: need to set subscription end_date for the order
> transaction, and ensure that it is
> # initially set to NULL when placing an order
> self.log_extra('cancelling recurring payment')
> recurlist = self.getRecurringChargeData()
>
> if recurlist:
> success, reason, response =
> self.process_recurring_cancel(recurlist, testing)
> if not success:
> self.log_extra('cancel of recurring payment failed,
> aborting the rest of the module')
> return (success, reason, response)
>
> return success, reason, response
>
>
> def process_recurring_cancel(self, data, testing=False):
> """Post one subscription cancellation request"""
> self.log_extra('Processing arb_cancel for subscription: %s',
> data['product'].slug)
>
> t =
> loader.get_template('checkout/authorizenet/arb_cancel_subscription.xml')
> ctx = Context(data)
> request = t.render(ctx)
>
> # no need for redacted post in cancel request...
>
> headers = {'Content-type':'text/xml'}
> conn = urllib2.Request(data['connection'], request, headers)
> try:
> f = urllib2.urlopen(conn)
> all_results = f.read()
> except urllib2.URLError, ue:
> self.log.error("error opening %s\n%s", data['connection'], ue)
> return (False, 'ERROR', _('Could not talk to Authorize.net
> gateway'))
>
> self.log_extra('Authorize response: %s', all_results)
>
> try:
> response = minidom.parseString(all_results)
> doc = response.documentElement
> reason = doc.getElementsByTagName('code')[0].firstChild.nodeValue
> response_text =
> doc.getElementsByTagName('text')[0].firstChild.nodeValue
> result =
> doc.getElementsByTagName('resultCode')[0].firstChild.nodeValue
> success = result == "Ok"
> except Exception, e:
> self.log.error("Error %s\nCould not parse response: %s", e,
> all_results)
> success = False
> reason = "Parse Error"
> response_text = "Could not parse response"
>
> return success, reason, response_text
>
> XML template:
>
> <?xml version="1.0" encoding="utf-8"?>
> <ARBCancelSubscriptionRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
> <merchantAuthentication>
> <name>{{ config.merchantID }}</name>
> <transactionKey>{{ config.transactionKey }}</transactionKey>
> </merchantAuthentication>
> <refId>{{ subscription.id }}</refId>
> <subscriptionId>{{ orderpayment.transaction_id }}</subscriptionId>
> </ARBCancelSubscriptionRequest>
>
>
> On Thu, Dec 18, 2008 at 12:48 PM, Bruce Kroeze <[email protected]> wrote:
>> On Wed, Dec 17, 2008 at 4:38 PM, Pete Skomoroch <[email protected]>
>> wrote:
>>>
>>> Bruce,
>>>
>>> I'd like to take a stab at adding ARB cancel/modify. Do you see any
>>> issues with the following logic?
>>>
>>> Add processor.cancel() and processor.modify_recurring_charge_amount()
>>> methods to payment/modules/authorizenet/processor.py , which will
>>> access the Authorize API the same fashion as the existing
>>> process_recurring_subscription().
>>
>> Looks good to me, except lets keep with the naming convention.
>> "processor.process_type_action"
>> So they'd be:
>> processor.process_recurring_cancel
>> processor.process_recurring_modify
>> --
>> Bruce Kroeze
>> http://solidsitesolutions.com
>> Dynamic Designs, Optimized
>>
>> >>
>>
>
>
>
> --
> Peter N. Skomoroch
> [email protected]
> http://www.datawrangling.com
> http://del.icio.us/pskomoroch
>
--
Peter N. Skomoroch
[email protected]
http://www.datawrangling.com
http://del.icio.us/pskomoroch
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Satchmo users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/satchmo-users?hl=en
-~----------~----~----~----~------~----~------~--~---