Paypal Express Recurring Payments 0

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

Using the results of victory 0

Posted by obondar
on Tuesday, June 03

Activity should give results that you can own.

Forums on DoStorm 0

Posted by obondar
on Tuesday, June 03

Yesterday I did deployed forulio to dostorm website. Forums are available at forum.dostorm.com.

DoStorm & Forulio.com

Posted by obondar
on Thursday, March 13

Some weeks ago I with my friend Ruslan started weekend project Forulio.com. We are working on it only on weekends and during work week we collect ideas and thoughts in DoStorm. I like how this process looks, DoStorm are good tool for collection ideas and sharing them.

This is how one of our brainstorm looks:

Also while using DoStorm we got some very nice ideas how to improve it. Some of them are:

  • combine with todo functionality
  • add reminders
  • add notes
  • improve interface to easier navigate thought rounds
  • add round result, that should be added when closing round
Actually, we created new brainstorm session for DoStorm improvements ;)

 

Public brainstorms link removed

Posted by obondar
on Sunday, February 24
I decided to remove link to public brainstorms on main page of DoStorm.com. I think that if you want to share your brainstorm round, you can post your link to blog or send it via email, but there is no sense in making public all shared rounds.

DoStorm new design

Posted by obondar
on Thursday, February 21

After short delay I came back to DoStorm. Designer Rustam joined to team so now i am not alone;).

Our new logo:

Very first design draft is here:

There are some new features that we want to implement. In next releases well be added possibility to comment suggestions and chat window on round page. We are thinking about how to display round with expanded suggestions that became new rounds. How to export round in easy to read format.

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)

Rocket's engine

Posted by obondar
on Friday, November 23

I am happy! Rocket's engines here: http://rc-mania.com.ua/rc-mania.php

More powerful - Model Rocket Motors but there they do not deliver outside USA ;(

Also there are engines from China

Brainstorm round for non registered users

Posted by obondar
on Thursday, November 15

Now all users can try to use DoStorm application before registration.

After registration you can:

  • create as many rounds as you need
  • start new rounds from suggestion
  • share your rounds

How to install mysql gem without mysql installed

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

New features for DoStorm.com

Posted by obondar
on Monday, November 05

Sharing.
To share round you only need to click on "Share this round" checkbox.

Starting new round from selected suggestion.
While searching for solution some suggestions may be the start of new brainstorm round. Start it by clicking "+" link near the selected suggestion. When child round is present for suggestion, you will see "#" link that navigates to this round page.

Enjoy!

DoStorm.com

Posted by obondar
on Sunday, November 04
I just got the domain name for brainstorm application, now project has name - DoStorm.com.

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!

UNDEFINED METHOD 'ASSIGN_VARIABLES_FROM_CONTROLLER'

Posted by obondar
on Tuesday, October 30
Undefined method 'assign_variables_from_controller' message can appear when in controller you operate with instance variable @template.

To avoid such message in your controller try to rename instance variable @template in your method to something other, @tmpl for example.

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