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

Last change on this file since 14202 was 12796, checked in by Henrik Bettermann, 10 years ago

Use MessageFactory?.

  • Property svn:keywords set to Id
File size: 11.6 KB
Line 
1## $Id: interfaces.py 12796 2015-03-19 15:13:27Z henrik $
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 started 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 IPayerFinder 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    title = schema.TextLine(
212        title=u'Title',
213        description=u'A short title of the good sold.',
214        required=True,
215        default=u'Unnamed'
216        )
217
218    amount = schema.Decimal(
219        title=u'Amount',
220        description=u'Total amount, includung any taxes, fees, etc.',
221        required=True,
222        default=decimal.Decimal('0.00'),
223        )
224
225
226class IPayable(Interface):
227    """Something that can be payed.
228
229    Designed to serve as adapter. IPayables turn arbitrary content
230    objects into something with a standarized interfaces for use with
231    payments.
232
233    While currency is important to tell about the amount currency, the
234    total amount is computed on-demand from payment items.
235    """
236    payable_id = schema.TextLine(
237        title=u'ID of a payable',
238        description=(u'It should be possible to lookup the payable id '
239                     u'by some registered IPayableFinder later on'),
240        required=True,
241        readonly=True,
242        )
243
244    title = schema.TextLine(
245        title=u'Title',
246        description=u'A short description of the payed item.',
247        required=True,
248        default=u'',
249        readonly=True,
250        )
251
252    currency = schema.Choice(
253        title=u'Currency',
254        source=ISO_4217_CURRENCIES_VOCAB,
255        required=True,
256        default='USD',
257        readonly=True,
258        )
259
260    payment_items = schema.Tuple(
261        title=u'Tuple of IPaymentItems.',
262        value_type=schema.Object(
263            title=u'Payment Item',
264            schema=IPaymentItem,
265            ),
266        required=True,
267        default=(),
268        readonly=False,
269        )
270
271
272class IPayment(IIkobaObject):
273    """A base representation of payments.
274
275    In a payment, a payer pays someone (the payee) for something, the
276    item to pay.
277
278    We currently support only the case where one payer pays one payee
279    for one item. The item might include taxes, handling,
280    shipping, etc.
281
282    As in RL any payment is actually performed by some financial
283    service provider (like paypal, interswitch, etc.), each of which
284    might provide several types of payments (credit card, scratch
285    card, you name it).
286
287    In Ikoba we call financial service providers 'gateway' and their
288    types of services are handled as gateway types. Therefore PayPal
289    handling a credit card payment is different from PayPal handling a
290    regular PayPal account transaction.
291
292    A payment can be approve()d, which means the act of paying was
293    really performed. It can also fail for any reason, in which case
294    we mark the payment 'failed'.
295    """
296    payment_id = schema.TextLine(
297        title=_(u'Payment Identifier'),
298        default=None,
299        required=True,
300        )
301
302    title = schema.TextLine(
303        title=_(u'Payment Description'),
304        default=u'',
305        required=True,
306        )
307
308    payer_id = schema.TextLine(
309        title=_(u'Payer'),
310        default=None,
311        required=True,
312        )
313
314    payee_id = schema.TextLine(
315        title=_(u'Payee'),
316        default=None,
317        required=False,
318        )
319
320    payable_id = schema.TextLine(
321        title=_(u'ID of item/good being paid'),
322        default=None,
323        required=False,
324        )
325
326    gateway_service = schema.Choice(
327        title=_(u'Payment Gateway'),
328        description=_(u'Payment gateway that handles this transaction.'),
329        source=PaymentGatewayServicesSource(),
330        default=None,
331        required=True,
332        )
333
334    state = schema.Choice(
335        title=_(u'Payment State'),
336        default=STATE_UNPAID,
337        vocabulary=payment_states,
338        required=True,
339        )
340
341    creation_date = schema.Datetime(
342        title=_(u'Creation Date'),
343        readonly=False,
344        required=False,
345        )
346
347    payment_date = schema.Datetime(
348        title=_(u'Payment Date'),
349        required=False,
350        readonly=False,
351        )
352
353    amount = schema.Decimal(
354        title=_(u'Amount'),
355        description=_(u'Total amount, includung any taxes, fees, etc.'),
356        required=True,
357        readonly=True,
358        default=decimal.Decimal('0.00'),
359        )
360
361    currency = schema.Choice(
362        title=_(u'Currency'),
363        source=ISO_4217_CURRENCIES_VOCAB,
364        required=True,
365        default='USD',
366        )
367
368    payment_items = schema.Tuple(
369        title=_(u'Tuple of IPaymentItems'),
370        value_type=schema.Object(
371            title=_(u'Payment Item'),
372            schema=IPaymentItem,
373            ),
374        required=True,
375        default=(),
376        readonly=False,
377        )
378
379    def approve():
380        """Approve a payment.
381
382        The payment was approved and can now be considered payed. This
383        kind of approvement means the final one (in case there are
384        several instances to ask).
385        """
386
387    def mark_failed(reason=None):
388        """Mark the payment as failed.
389
390        A failed payment was canceled due to technical problems,
391        insufficient funds, etc.
392        """
393
394
395class IPayer(Interface):
396    """A payer.
397    """
398    payer_id = schema.TextLine(
399        title=u'Payer ID',
400        required=True,
401        )
402
403    first_name = schema.TextLine(
404        title=u'First Name',
405        required=True,
406        )
407
408    last_name = schema.TextLine(
409        title=u'Last Name',
410        required=True,
411        )
412
413
414class IPayee(Interface):
415    """A person or institution being paid.
416    """
417    payee_id = schema.TextLine(
418        title=u'Payee ID',
419        required=True
420        )
Note: See TracBrowser for help on using the repository browser.