## $Id: interfaces.py 12319 2014-12-26 08:37:55Z 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.interface import Interface 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, 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. """ 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 IPayment(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'. """ payment_id = schema.TextLine( title=u'Payment Identifier', default=None, required=True, ) payer_id = schema.TextLine( title=u'Payer', default=None, required=True, ) payed_item_id = schema.TextLine( title=u'Payed Item ID', default=None, required=True, ) 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, ) amount = schema.Decimal( title=_(u'Amount'), description=_( 'The overall sum payed, including all taxes fees, etc.'), default=decimal.Decimal("0.00"), required=True, readonly=False, ) 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. """ class IOnlinePayment(IPayment): """A payment via payment gateways. """ ac = schema.TextLine( title=_(u'Activation Code'), default=None, required=False, readonly=False, ) r_amount_approved = schema.Float( title=_(u'Response Amount Approved'), default=0.0, required=False, readonly=False, ) r_code = schema.TextLine( title=_(u'Response Code'), default=None, required=False, readonly=False, ) r_desc = schema.TextLine( title=_(u'Response Description'), default=None, required=False, readonly=False, ) def approve(): "Approve an online payment and set to paid." 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 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 ) 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'), ) currency = schema.Choice( title=u'Currency', source=ISO_4217_CURRENCIES_VOCAB, required=True, default='USD', )