Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 390
- Log:
Initial import of Canvass, a donations-based poll application.
- Author:
- rool
- Date:
- Mon Mar 21 14:58:04 +0000 2011
- Size:
- 5463 Bytes
1 | ######################################################################## |
2 | # File:: payment_gateway.rb |
3 | # (C):: Hipposoft 2010, 2011 |
4 | # |
5 | # Purpose:: Model class which holds some static information about some |
6 | # payment gateway types. Not an ActiveRecord sub-class. |
7 | # ---------------------------------------------------------------------- |
8 | # 06-Mar-2010 (ADH): Created. |
9 | # 30-Jan-2011 (ADH): Imported from Artisan. |
10 | ######################################################################## |
11 | |
12 | class PaymentGateway |
13 | |
14 | include Singleton |
15 | |
16 | # =========================================================================== |
17 | # CHARACTERISTICS |
18 | # =========================================================================== |
19 | |
20 | # None (this is not an ActiveRecord sub-class). |
21 | |
22 | # =========================================================================== |
23 | # PERMISSIONS |
24 | # =========================================================================== |
25 | |
26 | # N/A |
27 | |
28 | # =========================================================================== |
29 | # GENERAL |
30 | # =========================================================================== |
31 | |
32 | # Return a payment gateway instance based on the "PAYMENT_*" constants - |
33 | # see "config/environments/<environment_in_use>.rb". |
34 | # |
35 | def gateway |
36 | @gateway ||= PAYMENT_CLASS.new( |
37 | :login => PAYMENT_LOGIN, |
38 | :password => PAYMENT_PASSWORD, |
39 | :signature => PAYMENT_SIGNATURE # Ignored for some gateway types; see "config/payment_gateway.yml" |
40 | ) |
41 | end |
42 | |
43 | # It this gateway recognised as only supporting express checkout? Returns |
44 | # 'true' if so, else 'false'. |
45 | # |
46 | def gateway_is_express_only |
47 | PAYMENT_CLASS == ActiveMerchant::Billing::PaypalExpressGateway || |
48 | PAYMENT_CLASS.superclass == ActiveMerchant::Billing::PaypalExpressGateway |
49 | end |
50 | |
51 | # Is this gateway recognised as supporting express checkout via |
52 | # 'gateway.express'? Returns 'true' if so, else 'false'. Note that some |
53 | # gateways *only* support express checkout and would return 'false' from this |
54 | # method; see also 'gateway_is_express_only', which must be checked first. |
55 | # |
56 | def gateway_has_express_support |
57 | gateway().respond_to?( :express ) |
58 | end |
59 | |
60 | # Static list of unique PayPal locales known at the time of writing. See: |
61 | # |
62 | # https://cms.paypal.com/uk/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_WPButtonIntegration#id089QD0O0TX4 |
63 | # |
64 | # ...and search downwards for table 2. The locale list has been sorted and |
65 | # reduced to unique entries. |
66 | |
67 | PAYPAL_LOCALES = [ |
68 | :de_DE, |
69 | :en_AU, |
70 | :en_GB, |
71 | :en_US, |
72 | :es_ES, |
73 | :es_XC, |
74 | :fr_FR, |
75 | :fr_XC, |
76 | :it_IT, |
77 | :ja_JP, |
78 | :nl_NL, |
79 | :pl_PL, |
80 | :zh_CN, |
81 | :zh_XC |
82 | ] |
83 | |
84 | # Bulk payment limit - for PayPal, via the front-end, this is 5000 at the |
85 | # time of writing. We limit it to fewer because attempting 5000 summarised |
86 | # payments in one go would be pretty crazy - the chance of error in marking |
87 | # paid/unpaid items would be huge (unless the payment gateway happens to |
88 | # support fully automatic mass payments). The value is inclusive (so zero |
89 | # would permit no payments and be invalid; 1 would permit just one payment |
90 | # at a time and be pretty pointless). |
91 | |
92 | BULK_PAYMENT_LIMIT = 500 # (sic.) |
93 | |
94 | # Return a PayPal check-out button URL with the best guess mapping between |
95 | # the PAYPAL_LOCALES and the given user's preferred language. |
96 | # |
97 | def self.paypal_get_checkout_url( user ) |
98 | code = user.language.try( :code ) || 'en' |
99 | code.gsub!( /\-/, '_' ) |
100 | |
101 | # Special case - "en" == "en_US"; other simple variants like "fr" need to |
102 | # become "fr_FR" to match PayPal locales. |
103 | |
104 | if ( code == "en" ) |
105 | code = "en_US" |
106 | else |
107 | code = code + "_" + code.upcase unless ( code.include?( "_" ) ) |
108 | end |
109 | |
110 | code = "en_US" unless PAYPAL_LOCALES.include?( code.to_sym ) |
111 | |
112 | return "https://www.paypal.com/#{ code }/i/btn/btn_xpressCheckout.gif" |
113 | end |
114 | |
115 | # Payment gateways may differ in the way that amounts are specified. |
116 | # Some payment gateways, e.g. PayPal, insist on integer hundredths. This |
117 | # class method takes a BigDecimal with currency-rounded integer and fraction |
118 | # parts (e.g. 12 UK pounds and 23.6 pence rounds to 12 pounds 24p, so the |
119 | # BigDecimal would be "12.24") and returns a value appropriate for the |
120 | # payment gateway in use. If you change gateway, you may need to update this. |
121 | # The return type may vary with gateway (for PayPal, it is a Fixnum). |
122 | # |
123 | # To achieve correct currency-specific rounding of the value passed on input, |
124 | # see "Currency#round" along with related methods and data in the Currency |
125 | # model. |
126 | # |
127 | # See also "PaymentGateway::get_amount_for_humans". |
128 | # |
129 | def self.get_amount_for_gateway( currency_rounded_value ) |
130 | |
131 | # PayPal specific: It wants integer hundredths. We always call 'floor' to |
132 | # round down any trailing fractional part. |
133 | |
134 | ( currency_rounded_value * BigDecimal.new( '100' ) ).floor.to_i |
135 | end |
136 | |
137 | # The opposite of "get_amount_for_gateway"; takes the given gateway amount |
138 | # and returns a BigDecimal which may be fractional, depending upon the way |
139 | # that "get_amount_for_gateway" works. Note that the gateway value may have |
140 | # had rounding applied, so while this function does the best it can, there |
141 | # is no way to completely 'undo' any original applied rounding. |
142 | # |
143 | def self.get_amount_for_humans( gateway_value ) |
144 | BigDecimal.new( gateway_value.to_s ) / BigDecimal.new( '100' ) |
145 | end |
146 | |
147 | end |