## $Id: interfaces.py 12703 2015-03-09 06:18:33Z uli $ ## ## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## import decimal from zc.sourcefactory.basic import BasicSourceFactory from zope import schema from zope.component import getUtilitiesFor from zope.container.interfaces import IContainer from zope.container.constraints import contains from zope.interface import Interface, Attribute from waeup.ikoba.interfaces import ( IIkobaObject, SimpleIkobaVocabulary, ContextualDictSourceFactoryBase) from waeup.ikoba.interfaces import MessageFactory as _ from waeup.ikoba.payments.currencies import ISO_4217_CURRENCIES_VOCAB #: Possible states of payments STATE_UNPAID = 1 STATE_PAID = 2 STATE_FAILED = 4 payment_states = SimpleIkobaVocabulary( (_('Not yet paid'), STATE_UNPAID), (_('Paid'), STATE_PAID), (_('Failed'), STATE_FAILED), ) class PaymentGatewayServicesSource(BasicSourceFactory): """A source that lists available payment services. Suitable for forms etc. Token and value correspond to the name the respective IPaymentGatewayService utility is registered with. """ _services = None @classmethod def services(cls): """Cache the services registered on startup. We assume that services do not change after startup. """ if cls._services is None: cls._services = dict(getUtilitiesFor(IPaymentGatewayService)) return cls._services def getValues(self): """Get payment gateway registration names. """ return sorted(PaymentGatewayServicesSource.services().keys()) def getTitle(self, value): """Get title of the respective service, if it exists. """ service = PaymentGatewayServicesSource.services().get(value, None) if service is not None: return service.title class IPaymentGatewayService(Interface): """A financial gateway service. Any gateway provider might provide several services. For instance payments by credit card, scratch card, bank transfer, etc. An `IPaymentGatewayService` represents one of those services. Payment services are normally registered as a named global utility. """ title = schema.TextLine( title=u'Title', description=u'Human readable name of gateway service.', required=True, ) def create_payment(payer, payment_item_list, payee): """Create a payment. For all parameters we expect an object, that implements `IPayer`, `IPaymentItem`, or `IPayee` respectively. If not, then the given objects must be at least adaptable to the respective interface. Therfore you can pass in some `Customer` as long as there is some `IPayer` adapter for `Customer` objects defined. Returns an `IPayment` object. """ def next_step(payment_id): """Returns a payment (as context) and a view name. May result in (None, None). """ class IPaymentGatewayServicesLister(Interface): """A utility that lists all valid payment gateways. This is a subset of the available payment methods, as some might be disabled in some site. Register your own lister in customized sites! """ class PaymentCategorySource(ContextualDictSourceFactoryBase): """A payment category source delivers all categories of payments. """ #: name of dict to deliver from ikoba utils. DICT_NAME = 'PAYMENT_CATEGORIES' class IPaymentsContainer(IIkobaObject): """A container for all kind of payment objects. """ class ICreditCard(Interface): """A credit card. A credit card is connected to a Payer. """ credit_card_id = schema.TextLine( title=u'Internal Credit Card ID', required=True, ) class IPaymentItem(Interface): """Something to sell. """ item_id = schema.TextLine( title=u'Payment Item ID', required=True, ) title = schema.TextLine( title=u'Title', description=u'A short title of the good sold.', required=True, default=u'Unnamed' ) amount = schema.Decimal( title=u'Amount', description=u'Total amount, includung any taxes, fees, etc.', required=True, default=decimal.Decimal('0.00'), ) class IPayment(IContainer, IIkobaObject): """A base representation of payments. In a payment, a payer payes someone (the payee) for something, the item to pay. We currently support only the case where one payer pays one payee for one item. The item might include taxes, handling, shipping, etc. As in RL any payment is actually performed by some financial service provider (like paypal, interswitch, etc.), each of which might provide several types of payments (credit card, scratch card, you name it). In Ikoba we call financial service providers 'gateway' and their types of services are handled as gateway types. Therefore PayPal handling a credit card payment is different from PayPal handling a regular PayPal account transaction. A payment can be approve()d, which means the act of paying was really performed. It can also fail for any reason, in which case we mark the payment 'failed'. """ contains(IPaymentItem) payment_id = schema.TextLine( title=u'Payment Identifier', default=None, required=True, ) payer_id = schema.TextLine( title=u'Payer', default=None, required=True, ) payee_id = schema.TextLine( title=u'Payee', default=None, required=False, ) gateway_service = schema.Choice( title=u'Payment Gateway', description=u'Payment gateway that handles this transaction.', source=PaymentGatewayServicesSource(), default=None, required=True, ) state = schema.Choice( title=_(u'Payment State'), default=STATE_UNPAID, vocabulary=payment_states, required=True, ) creation_date = schema.Datetime( title=_(u'Creation Datetime'), readonly=False, required=False, ) payment_date = schema.Datetime( title=_(u'Payment Datetime'), required=False, readonly=False, ) currency = schema.Choice( title=u'Currency', source=ISO_4217_CURRENCIES_VOCAB, required=True, default='USD', ) amount = Attribute("Sum of amounts of items contained") def approve(): """Approve a payment. The payment was approved and can now be considered payed. This kind of approvement means the final one (in case there are several instances to ask). """ def mark_failed(reason=None): """Mark the payment as failed. A failed payment was canceled due to technical problems, insufficient funds, etc. """ def add_payment_item(item): """Payments contain payment items. Add one """ class IPayer(Interface): """A payer. """ payer_id = schema.TextLine( title=u'Payer ID', required=True, ) first_name = schema.TextLine( title=u'First Name', required=True, ) last_name = schema.TextLine( title=u'Last Name', required=True, ) class IPayee(Interface): """A person or institution being paid. """ payee_id = schema.TextLine( title=u'Payee ID', required=True )