source: main/waeup.ikoba/trunk/src/waeup/ikoba/payments/interfaces.py @ 12741

Last change on this file since 12741 was 12741, checked in by uli, 10 years ago

Merge changes from uli-payments back into trunk.

  • Property svn:keywords set to Id
File size: 11.3 KB
Line 
1## $Id: interfaces.py 12741 2015-03-12 05:29:43Z uli $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import decimal
19from zc.sourcefactory.basic import BasicSourceFactory
20from zope import schema
21from zope.component import getUtilitiesFor
22from zope.component.interfaces import IObjectEvent
23from zope.interface import Interface, Attribute
24from waeup.ikoba.interfaces import (
25    IIkobaObject, SimpleIkobaVocabulary, ContextualDictSourceFactoryBase)
26from waeup.ikoba.interfaces import MessageFactory as _
27from waeup.ikoba.payments.currencies import ISO_4217_CURRENCIES_VOCAB
28
29#: Possible states of payments
30STATE_UNPAID = 1
31STATE_AWAITING_USER_CONFIRM = 2
32STATE_AWAITING_GATEWAY_CONFIRM = 4
33STATE_PAID = 64
34STATE_FAILED = 128
35
36payment_states = SimpleIkobaVocabulary(
37    (_('Not yet paid'), STATE_UNPAID),
38    (_('Waiting for user confirm'), STATE_AWAITING_USER_CONFIRM),
39    (_('Waiting for verification'), STATE_AWAITING_GATEWAY_CONFIRM),
40    (_('Paid'), STATE_PAID),
41    (_('Failed'), STATE_FAILED),
42    )
43
44
45class IPaymentWaitingForGatewayEvent(IObjectEvent):
46    """Fired when a payment starts waiting for verification.
47    """
48    object = Attribute("""The payment waiting.""")
49
50
51class IPaymentFinishedEvent(IObjectEvent):
52    """Fired when a payment failed or succeeded.
53    """
54    object = Attribute("""The payment finished.""")
55
56
57class IPaymentAborted(IObjectEvent):
58    """Fired when a payment was aborted before external transactions.
59    """
60    object = Attribute("""The payment aborted.""")
61
62
63class PaymentGatewayServicesSource(BasicSourceFactory):
64    """A source that lists available payment services.
65
66    Suitable for forms etc. Token and value correspond to the name the
67    respective IPaymentGatewayService utility is registered with.
68    """
69
70    _services = None
71
72    @classmethod
73    def services(cls):
74        """Cache the services registered on startup.
75
76        We assume that services do not change after startup.
77        """
78        if cls._services is None:
79            cls._services = dict(getUtilitiesFor(IPaymentGatewayService))
80        return cls._services
81
82    def getValues(self):
83        """Get payment gateway registration names.
84        """
85        return sorted(PaymentGatewayServicesSource.services().keys())
86
87    def getTitle(self, value):
88        """Get title of the respective service, if it exists.
89        """
90        service = PaymentGatewayServicesSource.services().get(value, None)
91        if service is not None:
92            return service.title
93
94
95class IPaymentGatewayService(Interface):
96    """A financial gateway service.
97
98    Any gateway provider might provide several services. For instance
99    payments by credit card, scratch card, bank transfer, etc. An
100    `IPaymentGatewayService` represents one of those services.
101
102    Payment services are normally registered as a named global
103    utility.
104    """
105    title = schema.TextLine(
106        title=u'Title',
107        description=u'Human readable name of gateway service.',
108        required=True,
109        )
110
111    def create_payment(payer, payable, payee):
112        """Create a payment.
113
114        For all parameters we expect an object, that implements
115        `IPayer`, `IPayable`, or `IPayee` respectively. If not,
116        then the given objects must be at least adaptable to the
117        respective interface.
118
119        Therfore you can pass in some `Customer` as long as there is
120        some `IPayer` adapter for `Customer` objects defined.
121
122        Returns an `IPayment` object.
123        """
124
125    def next_step(payment_id):
126        """Returns a payment (as context) and a view name.
127
128        May result in (None, None).
129        """
130
131    def store(payment):
132        """Store `payment` in site.
133        """
134
135
136class IPaymentGatewayServicesLister(Interface):
137    """A utility that lists all valid payment gateways.
138
139    This is a subset of the available payment methods, as some might
140    be disabled in some site.
141
142    Register your own lister in customized sites!
143    """
144
145
146class PaymentCategorySource(ContextualDictSourceFactoryBase):
147    """A payment category source delivers all categories of payments.
148
149    """
150    #: name of dict to deliver from ikoba utils.
151    DICT_NAME = 'PAYMENT_CATEGORIES'
152
153
154class IPaymentsContainer(IIkobaObject):
155    """A container for all kind of payment objects.
156
157    """
158
159
160class ICreditCard(Interface):
161    """A credit card.
162
163    A credit card is connected to a Payer.
164    """
165    credit_card_id = schema.TextLine(
166        title=u'Internal Credit Card ID',
167        required=True,
168        )
169
170
171class IPayableFinder(Interface):
172    """Finds payables.
173
174    For each type of content you want to make payable, you should
175    define an IPayableFinder that can lookup payables in the
176    site.
177
178    This enables access from payments (which store payable ids only)
179    to arbitrary content objects (for which a payable finder is
180    registered under some name).
181
182    The other way round (getting an id and other relevant data from
183    any content object) is ensured by IPayable adapters.
184    """
185    def get_payable_by_id(item_id):
186        """Get an item by its Id, or none.
187        """
188
189
190class IPayerFinder(Interface):
191    """Finds payers.
192
193    For each type of content you understand as payer, you should
194    define an IPayrtFinder that can lookup payers in the site.
195
196    This enables access from payments (which store payer ids only)
197    to arbitrary content objects (for which a payer finder is
198    registered under some name.
199
200    The other way round (getting an id and other relevant data from
201    any content object) is ensured by IPayer adapters.
202    """
203    def get_payer_by_id(item_id):
204        """Get a payer by its Id, or none.
205        """
206
207
208class IPaymentItem(Interface):
209    """Something to sell.
210    """
211    item_id = schema.TextLine(
212        title=u'Payment Item ID',
213        required=True,
214        )
215
216    title = schema.TextLine(
217        title=u'Title',
218        description=u'A short title of the good sold.',
219        required=True,
220        default=u'Unnamed'
221        )
222
223    amount = schema.Decimal(
224        title=u'Amount',
225        description=u'Total amount, includung any taxes, fees, etc.',
226        required=True,
227        default=decimal.Decimal('0.00'),
228        )
229
230
231class IPayable(Interface):
232    """Something that can be payed.
233
234    Designed to serve as adapter. IPayables turn arbitrary content
235    objects into something with a standarized interfaces for use with
236    payments.
237
238    While currency is important to tell about the amount currency, the
239    total amount is computed on-demand from payment items.
240    """
241    payable_id = schema.TextLine(
242        title=u'ID of a payable',
243        description=(u'It should be possible to lookup the payable id '
244                     u'by some registered IPayableFinder later on'),
245        required=True,
246        readonly=True,
247        )
248
249    title = schema.TextLine(
250        title=u'Title',
251        description=u'A short description of the payed item.',
252        required=True,
253        default=u'',
254        readonly=True,
255        )
256
257    currency = schema.Choice(
258        title=u'Currency',
259        source=ISO_4217_CURRENCIES_VOCAB,
260        required=True,
261        default='USD',
262        readonly=True,
263        )
264
265    payment_items = schema.Tuple(
266        title=u'Tuple of IPaymentItems.',
267        value_type=schema.Object(
268            title=u'Payment Item',
269            schema=IPaymentItem,
270            ),
271        required=False,
272        default=(),
273        readonly=True,
274        )
275
276
277class IPayment(IIkobaObject):
278    """A base representation of payments.
279
280    In a payment, a payer payes someone (the payee) for something, the
281    item to pay.
282
283    We currently support only the case where one payer pays one payee
284    for one item. The item might include taxes, handling,
285    shipping, etc.
286
287    As in RL any payment is actually performed by some financial
288    service provider (like paypal, interswitch, etc.), each of which
289    might provide several types of payments (credit card, scratch
290    card, you name it).
291
292    In Ikoba we call financial service providers 'gateway' and their
293    types of services are handled as gateway types. Therefore PayPal
294    handling a credit card payment is different from PayPal handling a
295    regular PayPal account transaction.
296
297    A payment can be approve()d, which means the act of paying was
298    really performed. It can also fail for any reason, in which case
299    we mark the payment 'failed'.
300    """
301    payment_id = schema.TextLine(
302        title=u'Payment Identifier',
303        default=None,
304        required=True,
305        )
306
307    title = schema.TextLine(
308        title=u'Payment description.',
309        default=u'',
310        required=True,
311        )
312
313    payer_id = schema.TextLine(
314        title=u'Payer',
315        default=None,
316        required=True,
317        )
318
319    payee_id = schema.TextLine(
320        title=u'Payee',
321        default=None,
322        required=False,
323        )
324
325    payable_id = schema.TextLine(
326        title=u'ID of item/good being paid',
327        default=None,
328        required=False,
329        )
330
331    gateway_service = schema.Choice(
332        title=u'Payment Gateway',
333        description=u'Payment gateway that handles this transaction.',
334        source=PaymentGatewayServicesSource(),
335        default=None,
336        required=True,
337        )
338
339    state = schema.Choice(
340        title=_(u'Payment State'),
341        default=STATE_UNPAID,
342        vocabulary=payment_states,
343        required=True,
344        )
345
346    creation_date = schema.Datetime(
347        title=_(u'Creation Datetime'),
348        readonly=False,
349        required=False,
350        )
351
352    payment_date = schema.Datetime(
353        title=_(u'Payment Datetime'),
354        required=False,
355        readonly=False,
356        )
357
358    currency = schema.Choice(
359        title=u'Currency',
360        source=ISO_4217_CURRENCIES_VOCAB,
361        required=True,
362        default='USD',
363        )
364
365    amount = Attribute("Sum of amounts of items contained")
366
367    def approve():
368        """Approve a payment.
369
370        The payment was approved and can now be considered payed. This
371        kind of approvement means the final one (in case there are
372        several instances to ask).
373        """
374
375    def mark_failed(reason=None):
376        """Mark the payment as failed.
377
378        A failed payment was canceled due to technical problems,
379        insufficient funds, etc.
380        """
381
382
383class IPayer(Interface):
384    """A payer.
385    """
386    payer_id = schema.TextLine(
387        title=u'Payer ID',
388        required=True,
389        )
390
391    first_name = schema.TextLine(
392        title=u'First Name',
393        required=True,
394        )
395
396    last_name = schema.TextLine(
397        title=u'Last Name',
398        required=True,
399        )
400
401
402class IPayee(Interface):
403    """A person or institution being paid.
404    """
405    payee_id = schema.TextLine(
406        title=u'Payee ID',
407        required=True
408        )
Note: See TracBrowser for help on using the repository browser.