Paypal Express Recurring Payments 1

Posted by obondar
on Thursday, July 03

This is the extension for activemerchant to work with recurring payments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
include ActiveMerchant::Billing

# simple extension to ActiveMerchant for basic support of recurring payments with Express Checkout API

module ActiveMerchant #:nodoc:

  module Billing #:nodoc:

    class PaypalExpressRecurringGateway < Gateway

      include PaypalCommonAPI
      LIVE_REDIRECT_URL = 'https://www.paypal.com/cgibin/webscr?cmd=_customer-billing-agreement&token='
      TEST_REDIRECT_URL = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_customer-billing-agreement&token='
      def redirect_url
        test? ? TEST_REDIRECT_URL : LIVE_REDIRECT_URL
      end
      def redirect_url_for(token)
        "#{redirect_url}#{token}"
      end

      def setup_agreement(description, return_url, cancel_url)
        commit 'SetCustomerBillingAgreement', build_setup_request(description, return_url, cancel_url)
      end

      def create_profile(token, description, cycles, amount, next_billing_date)
        commit 'CreateRecurringPaymentsProfile', build_create_profile_request(token, description, cycles, amount, next_billing_date)
      end
  
      def update_profile(profile_id, description, amount)
        commit 'UpdateRecurringPaymentsProfile', build_change_profile_request(profile_id, description, amount)
      end

      def cancel_profile(profile_id)
        commit 'ManageRecurringPaymentsProfileStatus', manage_profile_request(profile_id, 'Cancel')
      end

      def get_profile_details(profile_id)
        commit 'GetRecurringPaymentsProfileDetails', build_get_profile_details_request(profile_id)
      end

    private
      def build_setup_request(description, return_url, cancel_url)
        xml = Builder::XmlMarkup.new :indent => 2
        xml.tag! 'SetCustomerBillingAgreementReq', 'xmlns' => PAYPAL_NAMESPACE do
          xml.tag! 'SetCustomerBillingAgreementRequest', 'xmlns:n2' => EBAY_NAMESPACE do
            xml.tag! 'n2:Version', 50
            xml.tag! 'n2:SetCustomerBillingAgreementRequestDetails' do
              xml.tag! 'n2:BillingAgreementDetails' do
                xml.tag! 'n2:BillingType', 'RecurringPayments'
                xml.tag! 'n2:BillingAgreementDescription', description
              end
              xml.tag! 'n2:ReturnURL', return_url
              xml.tag! 'n2:CancelURL', cancel_url
            end
          end
        end
        xml.target!
      end

      def build_create_profile_request(token, description, cycles, amount, billing_start_date, currency='USD')
        xml = Builder::XmlMarkup.new :indent => 2
        xml.tag! 'CreateRecurringPaymentsProfileReq', 'xmlns' => PAYPAL_NAMESPACE do
          xml.tag! 'CreateRecurringPaymentsProfileRequest', 'xmlns:n2' => EBAY_NAMESPACE do
            xml.tag! 'n2:Version', 50
            xml.tag! 'n2:CreateRecurringPaymentsProfileRequestDetails' do
              xml.tag! 'Token', token
              xml.tag! 'n2:RecurringPaymentsProfileDetails' do
                xml.tag! 'n2:BillingStartDate', billing_start_date
              end
              xml.tag! 'n2:ScheduleDetails' do
                xml.tag! 'n2:Description', description
                xml.tag! 'n2:PaymentPeriod' do
                  xml.tag! 'n2:BillingPeriod', 'Month'
                  xml.tag! 'n2:BillingFrequency', cycles
                  xml.tag! 'n2:TotalBillingCycles', 0
                  xml.tag! 'n2:Amount', amount, 'currencyID' => currency
                end
              end
            end
          end
        end
        xml.target!
      end

      def build_change_profile_request(profile_id, description, amount)
        xml = Builder::XmlMarkup.new :indent => 2
        xml.tag! 'UpdateRecurringPaymentsProfileReq', 'xmlns' => PAYPAL_NAMESPACE do
          xml.tag! 'UpdateRecurringPaymentsProfileRequest', 'xmlns:n2' => EBAY_NAMESPACE do
            xml.tag! 'n2:Version', 50
            xml.tag! 'n2:UpdateRecurringPaymentsProfileRequestDetails' do
              xml.tag! 'ProfileID', profile_id
              xml.tag! 'n2:ScheduleDetails' do
                xml.tag! 'n2:Description', description
                xml.tag! 'n2:PaymentPeriod' do
                  xml.tag! 'n2:Amount', amount
                end
              end
            end
          end
        end
        xml.target!
      end
      
      def manage_profile_request(profile_id, action)
        xml = Builder::XmlMarkup.new :indent => 2
        xml.tag! 'ManageRecurringPaymentsProfileStatusReq', 'xmlns' => PAYPAL_NAMESPACE do
          xml.tag! 'ManageRecurringPaymentsProfileStatusRequest', 'xmlns:n2' => EBAY_NAMESPACE do
            xml.tag! 'n2:Version', 50
            xml.tag! 'n2:ManageRecurringPaymentsProfileStatusRequestDetails' do
              xml.tag! 'ProfileID', profile_id
              xml.tag! 'n2:Action', action
            end
          end
        end
        xml.target!
      end

      def build_get_profile_details_request(profile_id)
        xml = Builder::XmlMarkup.new :indent => 2
        xml.tag! 'GetRecurringPaymentsProfileDetailsReq', 'xmlns' => PAYPAL_NAMESPACE do
          xml.tag! 'GetRecurringPaymentsProfileDetailsRequest', 'xmlns:n2' => EBAY_NAMESPACE do
            xml.tag! 'n2:Version', 50
            xml.tag! 'ProfileID', profile_id
          end
        end
        xml.target!
      end

      def build_response(success, message, response, options = {})
        PaypalExpressProfileResponse.new(success, message, response, options)
      end
   end

    class PaypalExpressProfileResponse < PaypalExpressResponse
      def profile_id
        @params['profile_id']
      end

      def next_billing_date
        @params['next_billing_date']
      end

      def active?
         @params["profile_status"]=="ActiveProfile"
      end
    end
  end
end

Render partial with gettext problem

Posted by obondar
on Monday, December 10

While rendering some template you can get error message, something like :
ActionView::TemplateError (Couldn't find template file for admin/users/_new_edit_en
The "_en" is added by gettext. To make gettext skip trying to render template that is not exists, I made change in gettext gem:

ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext
line 328 :
return render_file_without_locale(localized_path, use_full_path, local_assigns) if File.exists?(localized_path)

How to install mysql gem without mysql installed

Posted by obondar
on Saturday, November 10
apt-get install libmysqlclient15-dev
gem install mysql

Brainstorm tool

Posted by obondar
on Friday, November 02

The first version of brainstorm application to get right solutions is online. I do not have the name for it now. The challenge is that there are many way to use this application, you can find ideas, solutions, questions. How to give name for all of them? Initially I thought about application for asking questions, but while working on it, I found that there are many other possibilities.

So, what is ready? Now you can:

  • register
  • create new brainstorm round
  • enter suggestions, issues, questions, ideas, whatever it is
  • edit suggestions
  • select suggestion that is really important
  • sort selected suggestions
  • edit name of round
  • browse all rounds
  • close round, so you stop with adding new suggestions
In short time I am planning to add:
  • Sharing
  • Send round to email
  • Invite friend to brainstorm round
  • Start new round from selected suggestion

Do storm!

Please, write a word, comments or suggestion about application. Thank you!

HOW TO DELETE FILE TO RECYCLE BIN USING WIN32API

Posted by obondar
on Sunday, October 28

In current project there is situation when file should not be just deleted but deleted to Recycle Bin. It is possible to do this by executing SHFileOperation. The main problem is how to do this from ruby. This example shows how to execute external method with passing structure as a parameter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
require 'dl/import'
require 'dl/struct'
module User32
      extend DL::Importable
    
      typealias "BOOL", "int"
      typealias "UINT", "unsigned int"
      typealias "PVOID", "void *"
      typealias "LONG", "long"
      typealias "HWND", "void *"
      typealias "LPCTSTR", "char *"
      typealias "LPVOID", "void *"
      typealias "LPCTSTR", "char *"
      typealias "FILEOP_FLAGS", "long"
    
    SHFileOperation = struct [
    "HWND hwnd",
    "UINT wFunc",
    "LPCTSTR pFrom",
    "LPCTSTR pTo",
    "FILEOP_FLAGS fFlags",
    "BOOL fAnyOperationsAborted",
    "LPVOID hNameMappings",
    "LPCTSTR lpszProgressTitle"
    ]
    
    dlload "shell32.dll"
    extern "BOOL SHFileOperation(PVOID)"

        FO_DELETE          = 3;
        FOF_ALLOWUNDO      = 64;
        FOF_NOCONFIRMATION = 16;
        
    def self.trash_file(file)
                file_info = User32::SHFileOperation::malloc
                file_info.wFunc = FO_DELETE
                file_info.pFrom = file
                file_info.pTo = file
                file_info.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION
                file_info.wFunc = FO_DELETE
                puts file_info.pFrom
                if File.readable?(file)
                        sHFileOperation(file_info.to_ptr)
                end
        end
end

How to install nginx

Posted by obondar
on Saturday, October 27

Suppose you are logged in as root.

cd /usr/src/
wget http://sysoev.ru/nginx/nginx-0.5.32.tar.gz
tar -xf nginx-0.5.32.tar.gz
cd nginx-0.5.32
apt-get install libpcre3 libpcre3-dev
./configure
make
make install

Configure nginx now:
/usr/local/nginx/conf/nginx.conf

Example to configure