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:
- 4631 Bytes
1 | ######################################################################## |
2 | # File:: payment_card.rb |
3 | # (C):: Hipposoft 2010, 2011 |
4 | # |
5 | # Purpose:: Support a payment (credit/debit) card entry form with |
6 | # ActiveRecord-like validations but without needing a database |
7 | # table underneath. |
8 | # ---------------------------------------------------------------------- |
9 | # 23-Mar-2010 (ADH): Created. |
10 | # 30-Jan-2011 (ADH): Imported from Artisan. |
11 | ######################################################################## |
12 | |
13 | class PaymentCard < WithoutTable |
14 | |
15 | # =========================================================================== |
16 | # CHARACTERISTICS |
17 | # =========================================================================== |
18 | |
19 | # This model has no database representation - see "models/without_table.rb". |
20 | |
21 | self.abstract_class = true # Keeps AR quiet but does not prevent instantiation |
22 | |
23 | # Card details |
24 | |
25 | column :card_name, :string |
26 | column :card_type, :string |
27 | column :card_number, :string |
28 | column :card_cvv, :string |
29 | column :card_to, :datetime |
30 | column :card_from, :datetime |
31 | column :card_issue, :string |
32 | |
33 | validates_presence_of :card_name, |
34 | :card_type, |
35 | :card_number |
36 | |
37 | validate :not_expired, |
38 | :valid_number, |
39 | :valid_type, |
40 | :valid_switch_or_solo_attributes, |
41 | :valid_cvv_if_needed |
42 | |
43 | def not_expired |
44 | errors.add( :card_to, :has_expired ) if card.expired? |
45 | end |
46 | |
47 | def valid_number |
48 | # Don't add both "cannot be blank" and "is invalid" errors to the same field |
49 | errors.add( :card_number, :is_invalid ) unless card_number.blank? || ActiveMerchant::Billing::CreditCard.valid_number?( card_number ) |
50 | end |
51 | |
52 | def valid_type |
53 | # Views should use a menu of type options, but this is here in case someone |
54 | # tries to try and hack the site with a custom form request |
55 | errors.add( :card_type, :is_invalid ) unless card_type.blank? || ActiveMerchant::Billing::CreditCard.card_companies.keys.include?( card_type ) |
56 | end |
57 | |
58 | def valid_switch_or_solo_attributes |
59 | if ( %w{ switch solo }.include?( card_type ) ) |
60 | errors.add( :card_issue, :is_invalid ) unless card.valid_issue_number( card_number ) # Very odd API! |
61 | end |
62 | end |
63 | |
64 | def valid_cvv_if_needed |
65 | if ( ActiveMerchant::Billing::CreditCard.requires_verification_value? ) |
66 | errors.add_on_blank :card_cvv |
67 | end |
68 | end |
69 | |
70 | # Overwrite the card number writer method to strip spaces from the |
71 | # value given (ActiveMerchant does not like spaces in card numbers). |
72 | |
73 | def card_number=( value ) |
74 | write_attribute( :card_number, value.gsub( ' ', '' ) ) |
75 | end |
76 | |
77 | # User billing address details |
78 | |
79 | column :address_1, :string |
80 | column :address_2, :string |
81 | column :address_3, :string |
82 | column :city, :string |
83 | column :state, :string |
84 | column :country, :string |
85 | column :postcode, :string |
86 | |
87 | validates_presence_of :address_1, |
88 | :city, |
89 | :country |
90 | |
91 | # Limitations |
92 | |
93 | MAXLEN_ADDRESS_1 = 256 |
94 | MAXLEN_ADDRESS_2 = 256 |
95 | MAXLEN_ADDRESS_3 = 256 |
96 | MAXLEN_CITY = 128 |
97 | MAXLEN_STATE = 128 |
98 | MAXLEN_COUNTRY = 128 |
99 | MAXLEN_POSTCODE = 64 |
100 | |
101 | MAXLEN_CARD_NUMBER = 20 |
102 | MAXLEN_CARD_CVV = 4 |
103 | MAXLEN_CARD_ISSUE = 20 |
104 | |
105 | # =========================================================================== |
106 | # PERMISSIONS |
107 | # =========================================================================== |
108 | |
109 | # N/A |
110 | |
111 | # =========================================================================== |
112 | # GENERAL |
113 | # =========================================================================== |
114 | |
115 | # Read-only accessor style method which defines a credit card with Active |
116 | # Merchant and caches the result internally. Only read the card once you |
117 | # have filled in the various "card_..." column values (see above). |
118 | # |
119 | def card |
120 | names = card_name.try( :split, ' ' ) || [] |
121 | first_name = names.shift |
122 | last_name = names.join( ' ' ) |
123 | |
124 | @card ||= ActiveMerchant::Billing::CreditCard.new( |
125 | :first_name => first_name, |
126 | :last_name => last_name, |
127 | |
128 | :number => card_number, |
129 | :type => card_type, |
130 | :month => card_to.try( :month ).to_s, |
131 | :year => card_to.try( :year ).to_s, |
132 | |
133 | :verification_value => card_cvv, |
134 | |
135 | :start_month => card_from.try( :month ).to_s, |
136 | :start_year => card_from.try( :year ).to_s, |
137 | :issue_number => card_issue |
138 | ) |
139 | end |
140 | end |