fawry 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fbda1f1ab11ae04767a26c8989237f7ce246a3de49aaa4032ec43504b8e5779c
4
- data.tar.gz: cf4891b451a00c47d74254c1e065512572f4e5f19c94db7956b2e94dc210d538
3
+ metadata.gz: 34dc9f1782c59c274ae83ab7cb5bf7542c02df23f12d3343c0bacc06d0385acf
4
+ data.tar.gz: 1e902699e6671b59e4d83ab246c6811fe4472c2b370843ce2b614e5e74811e80
5
5
  SHA512:
6
- metadata.gz: 2f0571abf34444cb9343f603e0b195ccb6ce683f2d5d4d5e82515a8058e361095aa4af21df17cd15db1ed0fe16195b354d1d708a9855e9c11d9e8eea151cfaca
7
- data.tar.gz: 3414b7912f9eab50220ae66ac0d5010b2ecb9b6d359d25929ed7effe671128030d19928a7d1c57107f6ed467dfc315b95b79ad0199ac8f033f4a3e817538e83c
6
+ metadata.gz: e18d4c44a20192fafd829aae6b9726bdbef550f1f5a32fc28865d61bf7336f93d86c2eec07605eea53d29990ef45eabfd175c29e3e8425ca230d4f0ccd195d63
7
+ data.tar.gz: 4eed6906aa47aa7e45d7b18fecf2ff2878aca3939e49f071f0e0ce16ffbc2278e0b204261cd03dbe5009f5c5c97bec7b08cc57f8faae52880229e57225fd9ecb
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fawry (1.0.0)
4
+ fawry (1.1.1)
5
5
  dry-validation (~> 1.3, >= 1.3.1)
6
6
  faraday (~> 0.17.0)
7
7
 
@@ -12,13 +12,14 @@ GEM
12
12
  public_suffix (>= 2.0.2, < 5.0)
13
13
  ast (2.4.0)
14
14
  byebug (11.0.1)
15
- concurrent-ruby (1.1.5)
15
+ concurrent-ruby (1.1.7)
16
16
  crack (0.4.3)
17
17
  safe_yaml (~> 1.0.0)
18
18
  diff-lcs (1.3)
19
- dry-configurable (0.9.0)
19
+ dry-configurable (0.11.6)
20
20
  concurrent-ruby (~> 1.0)
21
21
  dry-core (~> 0.4, >= 0.4.7)
22
+ dry-equalizer (~> 0.2)
22
23
  dry-container (0.7.2)
23
24
  concurrent-ruby (~> 1.0)
24
25
  dry-configurable (~> 0.1, >= 0.1.3)
@@ -26,33 +27,33 @@ GEM
26
27
  concurrent-ruby (~> 1.0)
27
28
  dry-equalizer (0.3.0)
28
29
  dry-inflector (0.2.0)
29
- dry-initializer (3.0.2)
30
- dry-logic (1.0.5)
30
+ dry-initializer (3.0.4)
31
+ dry-logic (1.0.8)
31
32
  concurrent-ruby (~> 1.0)
32
33
  dry-core (~> 0.2)
33
34
  dry-equalizer (~> 0.2)
34
- dry-schema (1.4.2)
35
+ dry-schema (1.5.5)
35
36
  concurrent-ruby (~> 1.0)
36
37
  dry-configurable (~> 0.8, >= 0.8.3)
37
38
  dry-core (~> 0.4)
38
39
  dry-equalizer (~> 0.2)
39
40
  dry-initializer (~> 3.0)
40
41
  dry-logic (~> 1.0)
41
- dry-types (~> 1.2)
42
- dry-types (1.2.2)
42
+ dry-types (~> 1.4)
43
+ dry-types (1.4.0)
43
44
  concurrent-ruby (~> 1.0)
44
45
  dry-container (~> 0.3)
45
46
  dry-core (~> 0.4, >= 0.4.4)
46
47
  dry-equalizer (~> 0.3)
47
48
  dry-inflector (~> 0.1, >= 0.1.2)
48
49
  dry-logic (~> 1.0, >= 1.0.2)
49
- dry-validation (1.4.0)
50
+ dry-validation (1.5.6)
50
51
  concurrent-ruby (~> 1.0)
51
52
  dry-container (~> 0.7, >= 0.7.1)
52
53
  dry-core (~> 0.4)
53
54
  dry-equalizer (~> 0.2)
54
55
  dry-initializer (~> 3.0)
55
- dry-schema (~> 1.0, >= 1.3.1)
56
+ dry-schema (~> 1.5, >= 1.5.2)
56
57
  faraday (0.17.1)
57
58
  multipart-post (>= 1.2, < 3)
58
59
  hashdiff (1.0.0)
@@ -63,7 +64,7 @@ GEM
63
64
  ast (~> 2.4.0)
64
65
  public_suffix (4.0.1)
65
66
  rainbow (3.0.0)
66
- rake (10.5.0)
67
+ rake (13.0.1)
67
68
  rspec (3.9.0)
68
69
  rspec-core (~> 3.9.0)
69
70
  rspec-expectations (~> 3.9.0)
@@ -101,11 +102,11 @@ DEPENDENCIES
101
102
  bundler (~> 2.0)
102
103
  byebug (~> 11.0, >= 11.0.1)
103
104
  fawry!
104
- rake (~> 10.0)
105
+ rake (~> 13.0)
105
106
  rspec (~> 3.0)
106
107
  rspec_junit_formatter
107
108
  rubocop (~> 0.76.0)
108
109
  webmock (~> 3.7, >= 3.7.6)
109
110
 
110
111
  BUNDLED WITH
111
- 2.0.2
112
+ 2.1.4
@@ -0,0 +1,186 @@
1
+ [![CircleCI](https://circleci.com/gh/fawry-api/fawry.svg?style=svg)](https://circleci.com/gh/fawry-api/fawry)
2
+
3
+ # Fawry
4
+
5
+ **تنويه:** نحن لسنا تابعين رسميًا لشركة فوري.
6
+
7
+ مكتبة لتسهيل التعامل مع خدمات الدفع الخاصة بشبكة الدفع الإلكتروني فوري:
8
+
9
+ - [لإجراء عملية دفع](https://github.com/fawry-api/fawry#charge-customers)
10
+ - [لإجراء عملية استرداد](https://github.com/fawry-api/fawry#refund-customers)
11
+ - [حالة الدفع](https://github.com/fawry-api/fawry#get-payment-status)
12
+ - [عرض رموز الكروت](https://github.com/fawry-api/fawry#list-card-tokens)
13
+ - [إضافة رمز كارت](https://github.com/fawry-api/fawry#create-card-token)
14
+ - [حذف رمز كارت](https://github.com/fawry-api/fawry#delete-card-token)
15
+ - [تحليل رد خدمة فوري V2](https://github.com/fawry-api/fawry#parse-fawry-service-callback-v2)
16
+ - [طلب البيانات الخاصة بإعدادات الإستخدام](https://github.com/fawry-api/fawry#configuration-keys-as-environment-variables)
17
+
18
+ _المكتبة تدعم النظام التجريبي لفوري ايضا_
19
+
20
+ ## لإضافة وتشغيل المكتبة
21
+
22
+ أضف هذا السطر إلى ملف Gemfile الخاص بتطبيقك:
23
+
24
+ ```ruby
25
+ gem 'fawry'
26
+ ```
27
+
28
+ ثم نفذ:
29
+
30
+ $ bundle
31
+
32
+ أو قم بتثبيته بنفسك على النحو التالي:
33
+
34
+ $ gem install fawry
35
+
36
+ ## طريقة الإستعمال
37
+
38
+ ### لإجراء عملية دفع
39
+
40
+ ```ruby
41
+ params = { "merchant_code": 'merchant_code',
42
+ "merchant_ref_num": 'io5jxf3jp27kfh8m719arcqgw7izo7db',
43
+ "customer_profile_id": 'ocvsydvbu2gcp528wvl64i9z5srdalg5',
44
+ "customer_mobile": '012345678901',
45
+ "payment_method": 'PAYATFAWRY',
46
+ "currency_code": 'EGP',
47
+ "amount": 20,
48
+ "fawry_secure_key": 'fawry_secure_key',
49
+ "description": 'the charge request description',
50
+ "charge_items": [{ "item_id": 'fk3fn9flk8et9a5t9w3c5h3oc684ivho',
51
+ "description": 'desc', "price": 20, "quantity": 1 }] }
52
+
53
+ # استخدم خيار النظام التجريبي للاتصال بالنظام التجريبي الخاص بفوري
54
+ # sandbox: true
55
+ res = Fawry.charge(params, sandbox: true)
56
+ # => #<Fawry::FawryResponse:0x0000564257d0ea90 @type="ChargeResponse", @reference_number="931600239",
57
+ # @merchant_ref_number="io5jxf3jp27kfh8m719arcqgw7izo7db",
58
+ # @expiration_time=1573153206979, @status_code=200,
59
+ # @status_description="Operation done successfully">
60
+
61
+ res.success? # => true
62
+ res.reference_number # => 931600239
63
+ ```
64
+
65
+ ### لإجراء عملية استرداد
66
+
67
+ ```ruby
68
+ params = { "merchant_code": 'merchant_code',
69
+ "reference_number": '931337410',
70
+ "refund_amount": 20,
71
+ "fawry_secure_key": 'fawry_secure_key' }
72
+
73
+ res = Fawry.refund(params, sandbox: true)
74
+ # => #<Fawry::FawryResponse:0x0000564257d0ea90 @type="ResponseDataModel", @status_code=200,
75
+ # @status_description="Operation done successfully">
76
+
77
+ res.success? # => true
78
+ ```
79
+
80
+ ### حالة الدفع
81
+
82
+ ```ruby
83
+ params = { "merchant_code": 'merchant_code',
84
+ "merchant_ref_number": 'ssshxb98phmyvm434es62kage3nsm2cj',
85
+ "fawry_secure_key": 'fawry_secure_key' }
86
+
87
+ res = Fawry.payment_status(params, sandbox: true)
88
+ # => #<Fawry::FawryResponse:0x0000559974056898 @type="PaymentStatusResponse", @reference_number="931922417",
89
+ # @merchant_ref_number="ssshxb98phmyvm434es62kage3nsm2cj",
90
+ # @expiration_time=1573297736167, @status_code=200,
91
+ # @status_description="Operation done successfully", @payment_amount=20,
92
+ # @payment_method="PAYATFAWRY", @payment_status="UNPAID">
93
+
94
+ res.success? # => true
95
+ res.payment_status # => UNPAID
96
+ ```
97
+
98
+ ### عرض رموز الكروت
99
+
100
+ ```ruby
101
+ params = { "merchant_code": 'merchant_code',
102
+ "customer_profile_id": 'customer_profile_id',
103
+ "fawry_secure_key": 'fawry_secure_key' }
104
+
105
+ res = Fawry.list_tokens(params, sandbox: true)
106
+
107
+ #<Fawry::FawryResponse:0x0000556cb3a31798 @fawry_api_response={"type"=>"CustomerTokensResponse", "cards"=>[{"token"=>"b5sshhdsl98df96200f254c19b2718bfc825a0678888216c28962b3e66a393084ee9aed6", "creationDate"=>1599487402318, "lastFourDigits"=>"4242", "brand"=>"Visa Card"}, {"token"=>"fb98dslsksmkdds7857ed7042ce30a2a5b777e1f1ac6ac58da1c8c0199f61df7a8bc098e96", "creationDate"=>1599489158457, "lastFourDigits"=>"0001", "brand"=>"Visa Card"}, {"token"=>"cc03fwqaacbd94e468a1b756ac1cbb285a41a2428df9f1a727457b41f9447d0058c7c", "creationDate"=>1599584834346, "lastFourDigits"=>"2346", "brand"=>"MasterCard"}, {"token"=>"f04a8bc9c973f900515f4b58e52c9ff03070baf3f534bdfdad0e97679534f60ddkjk13", "creationDate"=>1600260415739, "lastFourDigits"=>"8769", "brand"=>"Visa Card"}], "statusCode"=>200, "statusDescription"=>"Operation done successfully"}, @type="CustomerTokensResponse", @cards=[{"token"=>"b5sshhdsl98df96200f254c19b2718bfc825a0678888216c28962b3e66a393084ee9aed6", "creationDate"=>1599487402318, "lastFourDigits"=>"4242", "brand"=>"Visa Card"}, {"token"=>"fb98dslsksmkdds7857ed7042ce30a2a5b777e1f1ac6ac58da1c8c0199f61df7a8bc098e96", "creationDate"=>1599489158457, "lastFourDigits"=>"0001", "brand"=>"Visa Card"}, {"token"=>"cc03fwqaacbd94e468a1b756ac1cbb285a41a2428df9f1a727457b41f9447d0058c7c", "creationDate"=>1599584834346, "lastFourDigits"=>"2346", "brand"=>"MasterCard"}, {"token"=>"f04a8bc9c973f900515f4b58e52c9ff03070baf3f534bdfdad0e97679534f60ddkjk13", "creationDate"=>1600260415739, "lastFourDigits"=>"8769", "brand"=>"Visa Card"}], @status_code=200, @status_description="Operation done successfully">
108
+
109
+ res.success? # => true
110
+ res.cards # => cards
111
+ ```
112
+
113
+ ### إضافة رمز كارت
114
+
115
+ ```ruby
116
+ params = { "merchant_code" : "merchant_code",
117
+ "customer_profile_id" : "customer_profile_id",
118
+ "customer_mobile" : "customer_mobile",
119
+ "customer_email" : "customer_email",
120
+ "card_number" : "card_number",
121
+ "expiry_year" : "expiry_year",
122
+ "expiry_month" : "expiry_month",
123
+ "cvv" : "cvv" }
124
+ res = Fawry.create_card_token(params, sandbox: true)
125
+ #<Fawry::FawryResponse:0x0000556cb3eb0080 @fawry_api_response={"type"=>"CardTokenResponse", "card"=>{"token"=>"b598f96200f254c19b2718bfc825a063278888216c28962b3e66a393084ee9aed6", "creationDate"=>1607011562353, "lastFourDigits"=>"4242"}, "statusCode"=>200, "statusDescription"=>"Operation done successfully"}, @type="CardTokenResponse", @status_code=200, @status_description="Operation done successfully", @card={"token"=>"b598f96200f254c19b2718bfc825a063278888216c28962b3e66a393084ee9aed6", "creationDate"=>1607011562353, "lastFourDigits"=>"4242"}>
126
+
127
+ res.success?
128
+ res.card
129
+ ```
130
+
131
+ ### حذف رمز كارت
132
+
133
+ ```ruby
134
+ params = { "merchant_code": 'merchant_code',
135
+ "customer_profile_id": 'customer_profile_id',
136
+ "card_token": 'card_token' }
137
+
138
+ res = Fawry.delete_token(params, sandbox: true)
139
+ #<Fawry::FawryResponse:0x0000556cb57c2460 @fawry_api_response={"type"=>"CardTokenResponse", "statusCode"=>200, "statusDescription"=>"Operation done successfully"}, @type="CardTokenResponse", @status_code=200, @status_description="Operation done successfully">
140
+ res.success?
141
+
142
+ ```
143
+
144
+ ### رد اتصال خدمة تحليل فوري v2
145
+
146
+ ```ruby
147
+ # تم إرسال المعلمات من خادم فوري
148
+ callback_params = { "requestId": 'c72827d084ea4b88949d91dd2db4996e', "fawryRefNumber": '970177',
149
+ "merchantRefNumber": '9708f1cea8b5426cb57922df51b7f790',
150
+ "customerMobile": '01004545545', "customerMail": 'fawry@fawry.com',
151
+ "paymentAmount": 152.00, "orderAmount": 150.00, "fawryFees": 2.00,
152
+ "shippingFees": '', "orderStatus": 'NEW', "paymentMethod": 'PAYATFAWRY',
153
+ "messageSignature": 'b0175565323e464b01dc9407160368af5568196997fb6e379374a4f4fbbcf587',
154
+ "orderExpiryDate": 1_533_554_719_314,
155
+ "orderItems": [{ "itemCode": 'e6aacbd5a498487ab1a10ae71061535d', "price": 150.0, "quantity": 1 }] }
156
+
157
+ # FAWRY_SECURE_KEY يجب تعيين متغير البيئة
158
+ fawry_callback = Fawry.parse_callback(callback_params, {})
159
+ # <Fawry::FawryCallback:0x000056339ac43730 @request_id="c72827d084ea4b88949d91dd2db4996e", @fawry_ref_number="970177",
160
+ # @merchant_ref_number="9708f1cea8b5426cb57922df51b7f790", @customer_mobile="01004545545",
161
+ # @customer_mail="fawry@fawry.com", @order_status="NEW", @order_amount=150.0, @fawry_fees=2.0, ...>
162
+
163
+ fawry_callback.fawry_ref_number # => 970177
164
+ fawry_callback.order_status # => NEW
165
+ ```
166
+
167
+ ### طلب البيانات الخاصة بإعدادات الإستخدام
168
+
169
+ يمكن إرسال بيانات تهيئة فوري مثل رمز التاجر ومفتاح الأمان خلال البيانات المعطاه (`merchant_code`, `fawry_secure_key` ) الى **charge**, **refund**, **payment_status** طرق, _أو_ يمكن تعيينها كمتغيرات لنظام التشغيل: (`FAWRY_MERCHANT_CODE`, `FAWRY_SECURE_KEY`).
170
+
171
+ لتحليل fawry معاودة الاتصال ، يجب عليك ضبط متغير البيئة `FAWRY_SECURE_KEY`.
172
+
173
+ ## الخطوات القادمة المطلوب تنفيذها:
174
+
175
+ - إضافة خيار لرفع الاستثناء عند فشل الطلب
176
+
177
+ ## تطوير المكتبة
178
+
179
+ بعد التحقق من الريبو ، قم بتشغيل `bin/setup` لتثبيت التبعيات.
180
+ ثم نفذ الأمر `rake spec` لإجراء الاختبارات. يمكنك أيضا الجري `bin/console` للمطالبة التفاعلية التي تسمح لك بالتجربة.
181
+
182
+ لتثبيت هذه المكتبة على جهازك ، قم بتشغيل `bundle exec rake install`. لإصدار إصدار جديد ، قم بتحديث رقم الإصدار بتنسيق `version.rb`, ثم نفذ الأمر `bundle exec rake release`, الذي سينشئ علامة git للإصدار ، ويدفع التزامات git والعلامات ، ويدفع ملف `.gem` يا صديق [rubygems.org](https://rubygems.org).
183
+
184
+ ## المساهمة
185
+
186
+ يتم الترحيب بتقارير الأخطاء وطلبات السحب على GitHub في https://github.com/amrrbakry/fawry. يهدف هذا المشروع إلى أن يكون مساحة آمنة ومرحبة للتعاون ، ومن المتوقع أن يلتزم المساهمون بـ [Contributor Covenant](http://contributor-covenant.org) القواعد السلوكية.
data/README.md CHANGED
@@ -2,11 +2,18 @@
2
2
 
3
3
  # Fawry
4
4
 
5
+ [README - متوفر باللغة العربية](https://github.com/fawry-api/fawry/blob/master/README-ar.md)
6
+
7
+ **Disclaimer:** we are _not officially affilated_ with the _Fawry_ company.
8
+
5
9
  A plug-and-play library that makes interfacing with Fawry's payment gateway API a breeze:
6
10
 
7
11
  - [Charge customers](https://github.com/fawry-api/fawry#charge-customers)
8
12
  - [Refund customers](https://github.com/fawry-api/fawry#refund-customers)
9
13
  - [Get payment status](https://github.com/fawry-api/fawry#get-payment-status)
14
+ - [List card tokens](https://github.com/fawry-api/fawry#list-card-tokens)
15
+ - [Create card token](https://github.com/fawry-api/fawry#create-card-token)
16
+ - [Delete card token](https://github.com/fawry-api/fawry#delete-card-token)
10
17
  - [Parse Fawry's service callback V2](https://github.com/fawry-api/fawry#parse-fawry-service-callback-v2)
11
18
  - [Configuration keys as environment variables](https://github.com/fawry-api/fawry#configuration-keys-as-environment-variables)
12
19
 
@@ -56,7 +63,7 @@ res.success? # => true
56
63
  res.reference_number # => 931600239
57
64
  ```
58
65
 
59
- ### Refund Customers
66
+ ### Refund Customers
60
67
 
61
68
  ```ruby
62
69
  params = { "merchant_code": 'merchant_code',
@@ -71,7 +78,7 @@ res = Fawry.refund(params, sandbox: true)
71
78
  res.success? # => true
72
79
  ```
73
80
 
74
- ### Get Payment Status
81
+ ### Get Payment Status
75
82
 
76
83
  ```ruby
77
84
  params = { "merchant_code": 'merchant_code',
@@ -89,7 +96,54 @@ res.success? # => true
89
96
  res.payment_status # => UNPAID
90
97
  ```
91
98
 
92
- ### Parse Fawry service callback v2
99
+ ### List Card Tokens
100
+
101
+ ```ruby
102
+ params = { "merchant_code": 'merchant_code',
103
+ "customer_profile_id": 'customer_profile_id',
104
+ "fawry_secure_key": 'fawry_secure_key' }
105
+
106
+ res = Fawry.list_tokens(params, sandbox: true)
107
+ #<Fawry::FawryResponse:0x0000556cb3a31798 @fawry_api_response={"type"=>"CustomerTokensResponse", "cards"=>[{"token"=>"b5sshhdsl98df96200f254c19b2718bfc825a0678888216c28962b3e66a393084ee9aed6", "creationDate"=>1599487402318, "lastFourDigits"=>"4242", "brand"=>"Visa Card"}, {"token"=>"fb98dslsksmkdds7857ed7042ce30a2a5b777e1f1ac6ac58da1c8c0199f61df7a8bc098e96", "creationDate"=>1599489158457, "lastFourDigits"=>"0001", "brand"=>"Visa Card"}, {"token"=>"cc03fwqaacbd94e468a1b756ac1cbb285a41a2428df9f1a727457b41f9447d0058c7c", "creationDate"=>1599584834346, "lastFourDigits"=>"2346", "brand"=>"MasterCard"}, {"token"=>"f04a8bc9c973f900515f4b58e52c9ff03070baf3f534bdfdad0e97679534f60ddkjk13", "creationDate"=>1600260415739, "lastFourDigits"=>"8769", "brand"=>"Visa Card"}], "statusCode"=>200, "statusDescription"=>"Operation done successfully"}, @type="CustomerTokensResponse", @cards=[{"token"=>"b5sshhdsl98df96200f254c19b2718bfc825a0678888216c28962b3e66a393084ee9aed6", "creationDate"=>1599487402318, "lastFourDigits"=>"4242", "brand"=>"Visa Card"}, {"token"=>"fb98dslsksmkdds7857ed7042ce30a2a5b777e1f1ac6ac58da1c8c0199f61df7a8bc098e96", "creationDate"=>1599489158457, "lastFourDigits"=>"0001", "brand"=>"Visa Card"}, {"token"=>"cc03fwqaacbd94e468a1b756ac1cbb285a41a2428df9f1a727457b41f9447d0058c7c", "creationDate"=>1599584834346, "lastFourDigits"=>"2346", "brand"=>"MasterCard"}, {"token"=>"f04a8bc9c973f900515f4b58e52c9ff03070baf3f534bdfdad0e97679534f60ddkjk13", "creationDate"=>1600260415739, "lastFourDigits"=>"8769", "brand"=>"Visa Card"}], @status_code=200, @status_description="Operation done successfully">
108
+
109
+ res.success? # => true
110
+ res.cards # => cards
111
+ ```
112
+
113
+ ### Create Card Token
114
+
115
+ ```ruby
116
+ params = { "merchant_code" : "merchant_code",
117
+ "customer_profile_id" : "customer_profile_id",
118
+ "customer_mobile" : "customer_mobile",
119
+ "customer_email" : "customer_email",
120
+ "card_number" : "card_number",
121
+ "expiry_year" : "expiry_year",
122
+ "expiry_month" : "expiry_month",
123
+ "cvv" : "cvv" }
124
+ res = Fawry.create_card_token(params, sandbox: true)
125
+ #<Fawry::FawryResponse:0x0000556cb3eb0080 @fawry_api_response={"type"=>"CardTokenResponse", "card"=>{"token"=>"b598f96200f254c19b2718bfc825a063278888216c28962b3e66a393084ee9aed6", "creationDate"=>1607011562353, "lastFourDigits"=>"4242"}, "statusCode"=>200, "statusDescription"=>"Operation done successfully"}, @type="CardTokenResponse", @status_code=200, @status_description="Operation done successfully", @card={"token"=>"b598f96200f254c19b2718bfc825a063278888216c28962b3e66a393084ee9aed6", "creationDate"=>1607011562353, "lastFourDigits"=>"4242"}>
126
+
127
+ res.success?
128
+ res.card
129
+ ```
130
+
131
+ ### Delete Card Token
132
+
133
+ ```ruby
134
+ params = { "merchant_code": "merchant_code",
135
+ "customer_profile_id": "customer_profile_id",
136
+ "card_token": "card_token",
137
+ "fawry_secure_key": "fawry_secure_key" }
138
+
139
+ res = Fawry.delete_token(params, sandbox: true)
140
+ #<Fawry::FawryResponse:0x0000556cb57c2460 @fawry_api_response={"type"=>"CardTokenResponse", "statusCode"=>200, "statusDescription"=>"Operation done successfully"}, @type="CardTokenResponse", @status_code=200, @status_description="Operation done successfully">
141
+
142
+ res.success?
143
+
144
+ ```
145
+
146
+ ### Parse Fawry service callback v2
93
147
 
94
148
  ```ruby
95
149
  # params sent from fawry server
@@ -103,7 +157,7 @@ callback_params = { "requestId": 'c72827d084ea4b88949d91dd2db4996e', "fawryRefNu
103
157
  "orderItems": [{ "itemCode": 'e6aacbd5a498487ab1a10ae71061535d', "price": 150.0, "quantity": 1 }] }
104
158
 
105
159
  # FAWRY_SECURE_KEY env var must be set
106
- fawry_callback = Fawry.parse_callback(callback_params, {})
160
+ fawry_callback = Fawry.parse_callback(callback_params)
107
161
  # <Fawry::FawryCallback:0x000056339ac43730 @request_id="c72827d084ea4b88949d91dd2db4996e", @fawry_ref_number="970177",
108
162
  # @merchant_ref_number="9708f1cea8b5426cb57922df51b7f790", @customer_mobile="01004545545",
109
163
  # @customer_mail="fawry@fawry.com", @order_status="NEW", @order_amount=150.0, @fawry_fees=2.0, ...>
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
 
34
34
  spec.add_development_dependency 'bundler', '~> 2.0'
35
35
  spec.add_development_dependency 'byebug', '~> 11.0', '>= 11.0.1'
36
- spec.add_development_dependency 'rake', '~> 10.0'
36
+ spec.add_development_dependency 'rake', '~> 13.0'
37
37
  spec.add_development_dependency 'rspec', '~> 3.0'
38
38
  spec.add_development_dependency 'rspec_junit_formatter'
39
39
  spec.add_development_dependency 'rubocop', '~> 0.76.0'
@@ -10,9 +10,15 @@ require 'fawry/fawry_callback'
10
10
  require 'fawry/requests/charge_request'
11
11
  require 'fawry/requests/refund_request'
12
12
  require 'fawry/requests/payment_status_request'
13
+ require 'fawry/requests/create_card_token_request'
14
+ require 'fawry/requests/list_tokens_request'
15
+ require 'fawry/requests/delete_token_request'
13
16
  require 'fawry/contracts/charge_request_contract'
14
17
  require 'fawry/contracts/refund_request_contract'
15
18
  require 'fawry/contracts/payment_status_request_contract'
19
+ require 'fawry/contracts/create_card_token_request_contract'
20
+ require 'fawry/contracts/list_tokens_request_contract'
21
+ require 'fawry/contracts/delete_token_request_contract'
16
22
 
17
23
  module Fawry
18
24
  class << self
@@ -112,6 +118,92 @@ module Fawry
112
118
  FawryRequest.new('payment_status', params, opts).fire_payment_status_request
113
119
  end
114
120
 
121
+ # Sends a card token request to Fawry API
122
+ # performs param validation and builds
123
+ # the request signature
124
+ #
125
+ # @param params [Hash] list of params to send to fawry
126
+ # required(:customer_profile_id).value(:string)
127
+ # required(:customer_mobile).value(:string)
128
+ # required(:merchant_code).value(:string)
129
+ # required(:customer_email).value(:string)
130
+ # required(:card_number).value(:string)
131
+ # required(:expiry_year).value(:string)
132
+ # required(:expiry_month).value(:string)
133
+ # required(:cvv).value(:string)
134
+ #
135
+ # @param opts [Hash] list of options to
136
+ # configure the request
137
+ # @option opts :sandbox [Boolean] whether to
138
+ # send the request to fawry sandbox env or not
139
+ # false by default
140
+ #
141
+ # @raise [Fawry::InvalidFawryRequestError] raised when one
142
+ # or more of the params are invalid. the message
143
+ # specifices which params and why are they invalid
144
+ #
145
+ # @return [Fawry::FawryResponse] an object that
146
+ # has Fawry API response keys as instance methods
147
+ # plus some convenience methods e.g. success?
148
+
149
+ def create_card_token(params, opts = {})
150
+ FawryRequest.new('create_card_token', params, opts).fire_create_card_token_request
151
+ end
152
+
153
+ # Sends a list tokens request to Fawry API
154
+ # performs param validation and builds
155
+ # the request signature
156
+ #
157
+ # @param params [Hash] list of params to send to fawry
158
+ # required(:merchant_code).value(:string)
159
+ # required(:customer_profile_id).value(:string)
160
+ # optional(:fawry_secure_key).value(:string)
161
+ #
162
+ # @param opts [Hash] list of options to
163
+ # configure the request
164
+ # @option opts :sandbox [Boolean] whether to
165
+ # send the request to fawry sandbox env or not
166
+ # false by default
167
+ #
168
+ # @raise [Fawry::InvalidFawryRequestError] raised when one
169
+ # or more of the params are invalid. the message
170
+ # specifices which params and why are they invalid
171
+ #
172
+ # @return [Fawry::FawryResponse] an object that
173
+ # has Fawry API response keys as instance methods
174
+ # plus some convenience methods e.g. success?
175
+
176
+ def list_tokens(params, opts = {})
177
+ FawryRequest.new('list_tokens', params, opts).fire_list_tokens_request
178
+ end
179
+
180
+ # Sends delete token request to Fawry API
181
+ # performs param validation and builds
182
+ # the request signature
183
+ #
184
+ # @param params [Hash] list of params to send to fawry
185
+ # required(:customer_profile_id).value(:string)
186
+ # optional(:merchant_code).value(:string)
187
+ # optional(:fawry_secure_key).value(:string)
188
+ #
189
+ # @param opts [Hash] list of options to
190
+ # configure the request
191
+ # @option opts :sandbox [Boolean] whether to
192
+ # send the request to fawry sandbox env or not
193
+ # false by default
194
+ #
195
+ # @raise [Fawry::InvalidFawryRequestError] raised when one
196
+ # or more of the params are invalid. the message
197
+ # specifices which params and why are they invalid
198
+ #
199
+ # @return [Fawry::FawryResponse] an object that
200
+ # has Fawry API response keys as instance methods
201
+ # plus some convenience methods e.g. success?
202
+
203
+ def delete_token(params, opts = {})
204
+ FawryRequest.new('delete_token', params, opts).fire_delete_token_request
205
+ end
206
+
115
207
  # Parses Fawry callback v2 into
116
208
  # FawryCallback object with callback
117
209
  # params as instance methods
@@ -5,9 +5,9 @@ require 'json'
5
5
 
6
6
  module Fawry
7
7
  class Connection
8
- FAWRY_BASE_URL = 'https://www.atfawry.com/ECommerceWeb/Fawry/payments/'
8
+ FAWRY_BASE_URL = 'https://www.atfawry.com/ECommerceWeb/Fawry/'
9
9
 
10
- FAWRY_SANDBOX_BASE_URL = 'https://atfawry.fawrystaging.com//ECommerceWeb/Fawry/payments/'
10
+ FAWRY_SANDBOX_BASE_URL = 'https://atfawry.fawrystaging.com//ECommerceWeb/Fawry/'
11
11
 
12
12
  class << self
13
13
  def post(path, params, body, options)
@@ -30,6 +30,17 @@ module Fawry
30
30
  end
31
31
  end
32
32
 
33
+ def delete(path, params, body, options)
34
+ conn = options[:sandbox] ? sandbox_connection : connection
35
+
36
+ conn.delete(path) do |request|
37
+ request.params = params
38
+ request.body = body.to_json
39
+ # Fawry doesn't understand encoded params
40
+ request.options = request.options.merge(params_encoder: ParamsSpecialEncoder)
41
+ end
42
+ end
43
+
33
44
  private
34
45
 
35
46
  def connection
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module Fawry
6
+ module Contracts
7
+ class CreateCardTokenRequestContract < Dry::Validation::Contract
8
+ params do
9
+ required(:customer_profile_id).value(:string)
10
+ required(:customer_mobile).value(:string)
11
+ required(:merchant_code).value(:string)
12
+ required(:customer_email).value(:string)
13
+ required(:card_number).value(:string)
14
+ required(:expiry_year).value(:string)
15
+ required(:expiry_month).value(:string)
16
+ required(:cvv).value(:string)
17
+ end
18
+
19
+ rule(:customer_email) do
20
+ unless /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.match?(value)
21
+ key? && key.failure('has invalid format')
22
+ end
23
+ end
24
+
25
+ rule(:merchant_code) do
26
+ if ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
27
+ key(:merchant_code).failure('fawry merchant code is required as a param or an env var')
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module Fawry
6
+ module Contracts
7
+ class DeleteTokenRequestContract < Dry::Validation::Contract
8
+ params do
9
+ required(:merchant_code).value(:string)
10
+ required(:customer_profile_id).value(:string)
11
+ required(:fawry_secure_key).value(:string)
12
+ required(:card_token).value(:string)
13
+ end
14
+
15
+ rule(:fawry_secure_key) do
16
+ if ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
17
+ key(:fawry_secure_key).failure('fawry secure key is required as a param or an env var')
18
+ end
19
+ end
20
+
21
+ rule(:merchant_code) do
22
+ if ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
23
+ key(:merchant_code).failure('fawry merchant code is required as a param or an env var')
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module Fawry
6
+ module Contracts
7
+ class ListTokensRequestContract < Dry::Validation::Contract
8
+ params do
9
+ required(:merchant_code).value(:string)
10
+ required(:customer_profile_id).value(:string)
11
+ optional(:fawry_secure_key).value(:string)
12
+ end
13
+
14
+ rule(:fawry_secure_key) do
15
+ if ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
16
+ key(:fawry_secure_key).failure('fawry secure key is required as a param or an env var')
17
+ end
18
+ end
19
+
20
+ rule(:merchant_code) do
21
+ if ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
22
+ key(:merchant_code).failure('fawry merchant code is required as a param or an env var')
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -17,6 +17,8 @@ module Fawry
17
17
  private
18
18
 
19
19
  # rubocop:disable Metrics/MethodLength
20
+ # rubocop:disable Metrics/AbcSize
21
+ # rubocop:disable Metrics/CyclomaticComplexity
20
22
  def build_request
21
23
  case action
22
24
  when 'charge'
@@ -31,7 +33,21 @@ module Fawry
31
33
  self.class.include Requests::PaymentStatusRequest
32
34
  validate_payment_status_params!
33
35
  @request = build_payment_status_request
36
+ when 'create_card_token'
37
+ self.class.include Requests::CreateCardTokenRequest
38
+ validate_card_token_params!
39
+ @request = build_create_card_token_request
40
+ when 'list_tokens'
41
+ self.class.include Requests::ListTokensRequest
42
+ validate_list_tokens_params!
43
+ @request = build_list_tokens_request
44
+ when 'delete_token'
45
+ self.class.include Requests::DeleteTokenRequest
46
+ validate_delete_token_params!
47
+ @request = build_delete_token_request
34
48
  end
49
+ # rubocop:enable Metrics/CyclomaticComplexity
50
+ # rubocop:enable Metrics/AbcSize
35
51
  # rubocop:enable Metrics/MethodLength
36
52
  end
37
53
  end
@@ -18,7 +18,7 @@ module Fawry
18
18
 
19
19
  def build_charge_request
20
20
  {
21
- path: 'charge',
21
+ path: 'payments/charge',
22
22
  params: {},
23
23
  body: charge_request_transformed_params,
24
24
  options: options
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Fawry
6
+ module Requests
7
+ module CreateCardTokenRequest
8
+ def fire_create_card_token_request
9
+ fawry_api_response = Connection.post(request[:path], request[:params], request[:body], request[:options])
10
+ response_body = JSON.parse(fawry_api_response.body)
11
+
12
+ FawryResponse.new(response_body)
13
+ end
14
+
15
+ private
16
+
17
+ def build_create_card_token_request
18
+ {
19
+ path: 'cards/cardToken',
20
+ params: {},
21
+ body: create_card_token_request_transformed_params,
22
+ options: options
23
+ }
24
+ end
25
+
26
+ def create_card_token_request
27
+ @create_card_token_request ||= params
28
+ end
29
+
30
+ # rubocop:disable Metrics/AbcSize
31
+ def create_card_token_request_transformed_params
32
+ {
33
+ merchantCode: fawry_merchant_code,
34
+ customerProfileId: create_card_token_request[:customer_profile_id],
35
+ customerMobile: create_card_token_request[:customer_mobile],
36
+ customerEmail: create_card_token_request[:customer_email],
37
+ cardNumber: create_card_token_request[:card_number],
38
+ expiryYear: create_card_token_request[:expiry_year],
39
+ expiryMonth: create_card_token_request[:expiry_month],
40
+ cvv: create_card_token_request[:cvv]
41
+ }.compact
42
+ end
43
+
44
+ # rubocop:enable Metrics/AbcSize
45
+
46
+ def fawry_merchant_code
47
+ ENV.fetch('FAWRY_MERCHANT_CODE') { create_card_token_request[:merchant_code] }
48
+ end
49
+
50
+ def fawry_secure_key
51
+ ENV.fetch('FAWRY_SECURE_KEY') { create_card_token_request[:fawry_secure_key] }
52
+ end
53
+
54
+ def validate_card_token_params!
55
+ contract = Contracts::CreateCardTokenRequestContract.new.call(create_card_token_request)
56
+ raise InvalidFawryRequestError, contract.errors.to_h if contract.failure?
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Fawry
6
+ module Requests
7
+ module DeleteTokenRequest
8
+ def fire_delete_token_request
9
+ fawry_api_response = Connection.delete(request[:path], request[:params], request[:body], request[:options])
10
+ response_body = JSON.parse(fawry_api_response.body)
11
+
12
+ FawryResponse.new(response_body)
13
+ end
14
+
15
+ private
16
+
17
+ def build_delete_token_request
18
+ {
19
+ path: 'cards/cardToken',
20
+ params: {},
21
+ body: delete_token_request_transformed_params,
22
+ options: options
23
+ }
24
+ end
25
+
26
+ def request_params
27
+ @request_params = params
28
+ end
29
+
30
+ def delete_token_request_transformed_params
31
+ {
32
+ merchantCode: fawry_merchant_code,
33
+ customerProfileId: request_params[:customer_profile_id],
34
+ signature: delete_token_request_signature,
35
+ cardToken: request_params[:card_token]
36
+ }.compact
37
+ end
38
+
39
+ def fawry_merchant_code
40
+ ENV.fetch('FAWRY_MERCHANT_CODE') { request_params[:merchant_code] }
41
+ end
42
+
43
+ def fawry_secure_key
44
+ ENV.fetch('FAWRY_SECURE_KEY') { request_params[:fawry_secure_key] }
45
+ end
46
+
47
+ def card_token
48
+ request_params[:card_token]
49
+ end
50
+
51
+ def validate_delete_token_params!
52
+ contract = Contracts::ListTokensRequestContract.new.call(request_params)
53
+ raise InvalidFawryRequestError, contract.errors.to_h if contract.failure?
54
+ end
55
+
56
+ def delete_token_request_signature
57
+ Digest::SHA256.hexdigest("#{fawry_merchant_code}#{request_params[:customer_profile_id]}"\
58
+ "#{card_token}#{fawry_secure_key}")
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+
5
+ module Fawry
6
+ module Requests
7
+ module ListTokensRequest
8
+ def fire_list_tokens_request
9
+ fawry_api_response = Connection.get(request[:path], request[:params], request[:body], request[:options])
10
+ response_body = JSON.parse(fawry_api_response.body)
11
+
12
+ FawryResponse.new(response_body)
13
+ end
14
+
15
+ private
16
+
17
+ def build_list_tokens_request
18
+ {
19
+ path: 'cards/cardToken',
20
+ params: list_tokens_request_transformed_params,
21
+ body: {},
22
+ options: options
23
+ }
24
+ end
25
+
26
+ def request_params
27
+ @request_params = params
28
+ end
29
+
30
+ def list_tokens_request_transformed_params
31
+ {
32
+ merchantCode: fawry_merchant_code,
33
+ customerProfileId: request_params[:customer_profile_id],
34
+ signature: list_tokens_request_signature
35
+ }.compact
36
+ end
37
+
38
+ def fawry_merchant_code
39
+ ENV.fetch('FAWRY_MERCHANT_CODE') { request_params[:merchant_code] }
40
+ end
41
+
42
+ def fawry_secure_key
43
+ ENV.fetch('FAWRY_SECURE_KEY') { request_params[:fawry_secure_key] }
44
+ end
45
+
46
+ def validate_list_tokens_params!
47
+ contract = Contracts::ListTokensRequestContract.new.call(request_params)
48
+ raise InvalidFawryRequestError, contract.errors.to_h if contract.failure?
49
+ end
50
+
51
+ def list_tokens_request_signature
52
+ Digest::SHA256.hexdigest("#{fawry_merchant_code}#{request_params[:customer_profile_id]}"\
53
+ "#{fawry_secure_key}")
54
+ end
55
+ end
56
+ end
57
+ end
@@ -16,7 +16,7 @@ module Fawry
16
16
 
17
17
  def build_payment_status_request
18
18
  {
19
- path: 'status',
19
+ path: 'payments/status',
20
20
  params: payment_status_request_transformed_params,
21
21
  body: {},
22
22
  options: options
@@ -16,7 +16,7 @@ module Fawry
16
16
 
17
17
  def build_refund_request
18
18
  {
19
- path: 'refund',
19
+ path: 'payments/refund',
20
20
  params: {},
21
21
  body: refund_request_transformed_params,
22
22
  options: options
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fawry
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fawry
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amr Bakry
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-26 00:00:00.000000000 Z
11
+ date: 2020-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-validation
@@ -84,14 +84,14 @@ dependencies:
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '10.0'
87
+ version: '13.0'
88
88
  type: :development
89
89
  prerelease: false
90
90
  version_requirements: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - "~>"
93
93
  - !ruby/object:Gem::Version
94
- version: '10.0'
94
+ version: '13.0'
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: rspec
97
97
  requirement: !ruby/object:Gem::Requirement
@@ -154,7 +154,7 @@ dependencies:
154
154
  - - ">="
155
155
  - !ruby/object:Gem::Version
156
156
  version: 3.7.6
157
- description:
157
+ description:
158
158
  email:
159
159
  - amrrbakry17@gmail.com
160
160
  executables: []
@@ -162,7 +162,6 @@ extensions: []
162
162
  extra_rdoc_files: []
163
163
  files:
164
164
  - ".circleci/config.yml"
165
- - ".github/workflows/greetings.yml"
166
165
  - ".gitignore"
167
166
  - ".rspec"
168
167
  - ".rubocop.yml"
@@ -170,6 +169,7 @@ files:
170
169
  - Gemfile
171
170
  - Gemfile.lock
172
171
  - LICENSE.txt
172
+ - README-ar.md
173
173
  - README.md
174
174
  - Rakefile
175
175
  - bin/console
@@ -178,6 +178,9 @@ files:
178
178
  - lib/fawry.rb
179
179
  - lib/fawry/connection.rb
180
180
  - lib/fawry/contracts/charge_request_contract.rb
181
+ - lib/fawry/contracts/create_card_token_request_contract.rb
182
+ - lib/fawry/contracts/delete_token_request_contract.rb
183
+ - lib/fawry/contracts/list_tokens_request_contract.rb
181
184
  - lib/fawry/contracts/payment_status_request_contract.rb
182
185
  - lib/fawry/contracts/refund_request_contract.rb
183
186
  - lib/fawry/errors.rb
@@ -185,6 +188,9 @@ files:
185
188
  - lib/fawry/fawry_request.rb
186
189
  - lib/fawry/fawry_response.rb
187
190
  - lib/fawry/requests/charge_request.rb
191
+ - lib/fawry/requests/create_card_token_request.rb
192
+ - lib/fawry/requests/delete_token_request.rb
193
+ - lib/fawry/requests/list_tokens_request.rb
188
194
  - lib/fawry/requests/payment_status_request.rb
189
195
  - lib/fawry/requests/refund_request.rb
190
196
  - lib/fawry/utils.rb
@@ -195,7 +201,7 @@ licenses:
195
201
  metadata:
196
202
  homepage_uri: https://github.com/amrrbakry/fawry
197
203
  source_code_uri: https://github.com/amrrbakry/fawry
198
- post_install_message:
204
+ post_install_message:
199
205
  rdoc_options: []
200
206
  require_paths:
201
207
  - lib
@@ -210,8 +216,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
216
  - !ruby/object:Gem::Version
211
217
  version: '0'
212
218
  requirements: []
213
- rubygems_version: 3.0.1
214
- signing_key:
219
+ rubygems_version: 3.0.8
220
+ signing_key:
215
221
  specification_version: 4
216
222
  summary: A library to interface with Fawry's payment gateway API (charge, refund,
217
223
  payment status, service callback).
@@ -1,13 +0,0 @@
1
- name: Greetings
2
-
3
- on: [pull_request, issues]
4
-
5
- jobs:
6
- greeting:
7
- runs-on: ubuntu-latest
8
- steps:
9
- - uses: actions/first-interaction@v1
10
- with:
11
- repo-token: ${{ secrets.GITHUB_TOKEN }}
12
- issue-message: "Hello, thanks for taking the time to open this issue. We'll get to it as soon as possible."
13
- pr-message: "Hello, thanks for taking the time to open this PR. We'll get to it as soon as possible."