Package: collective.mollie
Introductioncollective.mollieprovides a wrapper for theMollie iDeal
API. This wrappercanbe used without any further Plone
integration. However, this package also provides:Adaptersto store payment information on objects.Browser viewswhich can be used to have Mollie report back.Aneventwhich can be subscribed to to be notified when payment status has been updated.iDealThe complete iDeal payment process contains the following steps:Request the list of banksRequest a paymentHave the customer do the paymentCheck the paymentCustomer is returning to the siteRequest the list of banksSince the list of banks may change, you always need to retrieve it
before you do the payment:>>> from zope.component import getUtility
>>> from collective.mollie.interfaces import IMollieIdeal
>>> ideal_wrapper = getUtility(IMollieIdeal)
>>> ideal_wrapper.get_banks()
[('0031', 'ABN AMRO'), ...]If theTESTMODEflag is set, you can retrieve a test bank:>>> ideal_wrapper.TESTMODE = True
>>> ideal_wrapper.get_banks()
[('9999', 'TBM Bank')]
>>> ideal_wrapper.TESTMODE = False
>>> ideal_wrapper.get_banks()
[('0031', 'ABN AMRO'), ...]The result of the call is a list of tuples. Each tuple consists of a
bank ID and name. The name can be used to present to the customer so
he/she can choose which bank to use. The ID is needed in the next
step.NoteIf you want to use the test mode from Molllie to test payments,
pleasealsoswitch your Mollie account to test mode otherwise
Mollie will not accept a test payment, even though the URL might
point to the test bank.Request a paymentWhen you know which bank will be used to pay, you can request a
payment with the API:>>> ideal_wrapper.request_payment(partner_id='999999',
...     bank_id='9999', amount='123', message='The message',
...     report_url='http://example.com/report',
...     return_url='http://example.com/return',
...     profile_key='999999')
('123...123', 'http://...')The result is atransaction_id, and a URL to send the customer to
to perform the payment.NoteTheamountof the payment has to be incents. Themessagemay only be 29 characters (any more characters are
ignored). Theprofile_keyparameter is optional. You only need
to use it if you want to use a different payment profile than the
default for the specified account.Have the customer do the paymentThis package does not handle this step. You should redirect the
customer to the URL returned byrequest_payment, and hope he/she
completes the transaction.Check the paymentOnce thereport_url(seeRequest a payment) has been pinged by
Mollie, you can check the status of the payment:>>> ideal_wrapper.check_payment(partner_id='999999',
...                             transaction_id='123...123')
{'transaction_id': '123...123',
 'amount': '123',
 'currency': 'EUR',
 'paid': True,
 'status': 'Success',
 'consumer': {
     'name': 'T. TEST',
     'account': '0123456789',
     'city': 'Testdorp'
 }
}When the state is anything other than “Success”, there will be no data
about the consumer.Customer is returning to the siteThis is where the customer is returned to thereturn_url. However,
this step is not handled by this package. You should use the result
from the previous step (Check the payment) to inform the customer
and present further actions, where appropriate.It may happen that thereport_urlis not yet called and thus the
state of the payment is not yet known. Mollie advises to report to the
customer that the status is unknown but that the payment will be
automatically processed once the status is final.Plone integrationIf you want to integrate iDeal payments in your Plone project, you can
use the iDeal wrapper as defined in theMollieIdealutility which
was described above.AdaptersHowever, you can also use one of the adapters defined in the package:MollieIdealPaymentandMollieIdealMultiplePayments. By using
one of these, information about payments is persistently stored on the
adapted objects.You can adapt any object that implements theIAttributeAnnotatableinterface. For instance:>>> from zope.annotation import IAttributeAnnotatable
>>> from persistent import Persistent
>>> from zope.interface import Interface
>>> class IFoo(Interface):
>>>     pass
>>> class Foo(Persistent):
...     implements(IFoo, IAttributeAnnotatable)If you only want to store a single payment on an object, as is common
for a specific purchase, you can use theIMollieIdealPaymentinterface:>>> from collective.mollie.interfaces import IMollieIdealPayment
>>> purchase = Foo()
>>> purchase_payment = IMollieIdealPayment(purchase)Now you can request banks, a payment URL and the payment status:>>> purchase_payment.get_banks()
[('0031', 'ABN AMRO'), ...]
>>> purchase_payment.get_payment_url(partner_id='999999',
...     bank_id='9999', amount='123', message='The message',
...     report_url='http://example.com/report',
...     return_url='http://example.com/return',
...     profile_key='999999')
'http://....'
>>> purchase_payment.get_payment_status()
'Success'Note that you do not have to repeat thepartner_idortransaction_idwhen requesting the payment status. This
information was stored when you requested the payment url and is reused
for theget_payment_statuscall.As stated earlier, the payment information is stored persistently:>>> purchase_payment.paid
True
>>> purchase_payment.amount
'123'
>>> purchase_payment.consumer
{'name': 'T. TEST',
 'account': '0123456789',
 'city': 'Testdorp'
 }In cases where multiple payments need to be stored on a single object,
you can use theIMollieIdealMultiplePaymentsinterface. For
example if you want to allow multiple people to be able to donate to
some charity:>>> from collective.mollie.interfaces import IMollieIdealMultiplePayments
>>> charity = Foo()
>>> charity_donations = IMollieIdealMultiplePayments(charity)As was previously the case, you can also request the available banks:>>> charity_payment.get_banks()
[('0031', 'ABN AMRO'), ...]When you retrieve a payment URL, you also get a transaction ID:>>> charity_payment.get_payment_url(partner_id='999999',
...     bank_id='9999', amount='123', message='The message',
...     report_url='http://example.com/report',
...     return_url='http://example.com/return',
...     profile_key='999999')
('123...', 'http://....')This transaction ID is required when you want to access the data for a
payment:>>> charity_payment.get_payment_status('123...')
'Success'
>>> payment = charity_payment.get_transaction('123...')
>>> payment['paid']
True
>>> payment['amount']
'123'
>>> payment['consumer']
{'name': 'T. TEST',
 'account': '0123456789',
 'city': 'Testdorp'
 }Note that the way to get to the payment information is also a bit
different than in the single payment case.Browser ViewsAs described in the sectionCheck the payment, you have to wait with
checking the payment status until Mollie has pinged thereport_url.You can write your own view, but you can also use one provided bycollective.mollie: theReportPaymentStatusViewandReportMultiplePaymentsStatusViewclasses. These views checks
whether thetransaction_idfrom the request matches one stored
on the object. If it does, the payment status of the object is checked
immediately.To use the simple payment view, first register it:<browser:page
    for="*"
    class="collective.mollie.browser.report.ReportPaymentStatusView"
    name="report_payment_status"
    permission="zope2.View"
    />Alternatively you can use the multiple payment report view:<browser:page
    for="*"
    class="collective.mollie.browser.report.ReportMultiplePaymentsStatusView"
    name="report_payment_status"
    permission="zope2.View"
    />(You probably should only register the view for specific
interfaces. And obviously you can give it any name you want.)Then use<object>/absolute_url/@@report_payment_statusas thereport_urlwhen requesting the payment URL.EventThe report views also emit an event:MollieIdealPaymentEvent. So
by implementing a subscriber in your own package, you can get a
notification if the payment information of an object is updated and
for instance change the workflow state of the object to “paid”.You can, for example, register a subscriber in yourconfigure.zcml:<subscriber
    for="IFoo
         collective.mollie.interfaces.IMollieIdealPaymentEvent"
    handler=".events.process_payment"
    />And inevents.py:def process_payment(obj, event):
    """Process the payment information."""Whereobjis an instance ofFooandeventis theMollieIdealPaymentEvent.More informationFor details about the Mollie iDeal API, see itsdocumentation.CreditsThis package is inspired bynfg.ideal.Changelog0.3 (2012-10-31)Implement a new report view (ReportMultiplePaymentsStatusView) which
can be used for the report URL for Mollie.
[markvl]Implement a new adapter (MollieIdealMultiplePayments) to register
multiple payments on a single object.
[markvl]Fix FutureWarnings that appeared when running the tests.
[markvl]Improve test coverage by also testing the XML to dict and list
converters.
[marklv]Fix typo in the adapter which defined the _partner_id property a
second time instead of the _profile_key.
[markvl]0.2 (2012-04-05)The MollieIdealPaymentEvent now subclasses the ObjectEvent and
provides the request.
[markvl]0.1 (2012-04-04)Initial release