cyberbiz_express 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dc5e9e41489058343931fa6caeba2bffc8087089333ed953348839977df651d6
4
+ data.tar.gz: 99eb0c0dfc54aef81d810bb2a1f63ad9a5bcf6f3f49140a9818f058060db2afc
5
+ SHA512:
6
+ metadata.gz: 996afeb26b4c4a1be21d228110187e6796db67da228a327ce7a7845e4890538549a5e1b97949be8cf913da47abeae08fd93687538450cdb5d94c2651665ca98c
7
+ data.tar.gz: 693130bc3872a5e7b915cf91600142bfe6f22256cd7e6712afc7a3b9dee97f2b2a145e14c2b15b75c75119c10c4b6d9cd977803877b9c03058052bb46d485850
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,213 @@
1
+ require:
2
+ - rubocop-rails
3
+ - rubocop-performance
4
+
5
+ AllCops:
6
+ EnabledByDefault: true
7
+ Exclude:
8
+ # route file is DSL
9
+ - 'config/routes.rb'
10
+ - 'config/deploy.rb'
11
+ - 'data/**/*'
12
+ - 'doc/**/*'
13
+ - 'frontend/**/*'
14
+ - 'kubernetes/**/*'
15
+ - 'lib/load_balancer/load_balancer_api/wsdl/**/*'
16
+ - 'nginx/**/*'
17
+ - 'theme_maker/**/*'
18
+ - 'themes_source/**/*'
19
+ - 'tmp/**/*'
20
+ - 'vendor/gems/**/*'
21
+ - !ruby/regexp /\/node_modules\//
22
+ - 'app/assets/**/*'
23
+ TargetRubyVersion: 2.6
24
+ TargetRailsVersion: 5.0
25
+
26
+ # This is not enabled by default because it would mark a lot of offenses unnecessarily.
27
+ Lint/ConstantResolution:
28
+ Enabled: false
29
+
30
+ Lint/NumberConversion:
31
+ Enabled: false
32
+
33
+ Style/GlobalVars:
34
+ AllowedVariables:
35
+ - $redis_lua_hash
36
+
37
+ Style/ConstantVisibility:
38
+ Enabled: false
39
+
40
+ Style/Copyright:
41
+ Enabled: false
42
+ AutocorrectNotice: ""
43
+
44
+ Style/MissingElse:
45
+ Enabled: false
46
+
47
+ Style/InlineComment:
48
+ Enabled: false
49
+
50
+ Style/StringHashKeys:
51
+ Exclude:
52
+ - 'spec/**/*'
53
+
54
+ Rails:
55
+ Enabled: true
56
+
57
+ Rails/UnknownEnv:
58
+ Environments:
59
+ - production
60
+ - staging
61
+ - development
62
+ - test
63
+
64
+ Rails/OrderById:
65
+ Enabled: false
66
+
67
+ Style/MethodCallWithArgsParentheses:
68
+ IgnoredMethods:
69
+ - 'to'
70
+
71
+ # modern editors and terminal fit more than 80 characters.
72
+ Layout/LineLength:
73
+ Max: 120
74
+ Exclude:
75
+ - 'app/models/key_values.rb'
76
+ - 'app/models/key_values/**/**/*.rb'
77
+
78
+ # Class length is not critical to code quality
79
+ Metrics/ClassLength:
80
+ Enabled: false
81
+
82
+ # Block length is ok to be long in DSLs like 'rspec' or 'rake'
83
+ Metrics/BlockLength:
84
+ Enabled: false
85
+
86
+ # defualt '10 line' is too strict to us, and may clutter the class
87
+ Metrics/MethodLength:
88
+ Max: 25
89
+
90
+ Metrics/AbcSize:
91
+ Max: 20
92
+
93
+ # Most Rails generated class are not doced, and not needed
94
+ Style/Documentation:
95
+ Enabled: false
96
+
97
+ Style/DocumentationMethod:
98
+ Enabled: false
99
+
100
+ # 'return' makes code more readable in some cases
101
+ Style/RedundantReturn:
102
+ Enabled: false
103
+
104
+ Style/DisableCopsWithinSourceCodeDirective:
105
+ Enabled: false
106
+
107
+ # Taiwan Greate again
108
+ Style/AsciiComments:
109
+ Enabled: false
110
+
111
+ # Guard is not always good to readablity
112
+ # Note: It does not mean we don't use guard to reduce block levels
113
+ # In short methods, using guard is not necessary, e.g.
114
+ # def foo(x) | def foo(x)
115
+ # if xxx?(x) | return unless xxx?(x)
116
+ # bar(x) | bar(x)
117
+ # end | end
118
+ # end |
119
+ Style/GuardClause:
120
+ Enabled: false
121
+
122
+ # In short blocks, using next is not necessary, e.g.
123
+ # bars.each do |b| | bars.each do |b|
124
+ # do_a | do_a
125
+ # do_b if b.good? | next unless b.good?
126
+ # end |
127
+ # | do_b
128
+ # | end
129
+ Style/Next:
130
+ Enabled: false
131
+
132
+ # The rule expects
133
+ #
134
+ # if xxxxxx
135
+ # a_very_long_method_or_somethings_like_that......
136
+ # end
137
+ #
138
+ # to be
139
+ #
140
+ # a_very_long_method_or_somethings_like_that...... if xxxxxx
141
+ #
142
+ # It is not good looking at all.
143
+ Style/IfUnlessModifier:
144
+ Enabled: false
145
+
146
+ # The rule expects
147
+ #
148
+ # class Admin::MyController
149
+ # end
150
+ #
151
+ # to be
152
+ #
153
+ # module Admin
154
+ # class MyController
155
+ # end
156
+ # end
157
+ #
158
+ # It seems not suitable for our project
159
+ Style/ClassAndModuleChildren:
160
+ Enabled: false
161
+
162
+ # # bad
163
+ # a = [1, 2,]
164
+ #
165
+ # # good
166
+ # a = [
167
+ # 1, 2,
168
+ # 3,
169
+ # ]
170
+ #
171
+ # # good
172
+ # a = [
173
+ # 1,
174
+ # 2,
175
+ # ]
176
+ Style/TrailingCommaInArrayLiteral:
177
+ EnforcedStyleForMultiline: consistent_comma
178
+
179
+ # # good
180
+ # foo(
181
+ # 1,
182
+ # 2,
183
+ # )
184
+ Style/TrailingCommaInArguments:
185
+ EnforcedStyleForMultiline: consistent_comma
186
+
187
+ # # good
188
+ # a = {
189
+ # 1,
190
+ # 2,
191
+ # }
192
+ Style/TrailingCommaInHashLiteral:
193
+ EnforcedStyleForMultiline: consistent_comma
194
+
195
+ # ---- Disable some cop for key values ----
196
+ Layout/ExtraSpacing:
197
+ Exclude:
198
+ - 'app/models/key_values.rb'
199
+ - 'app/models/key_values/**/**/*.rb'
200
+ Layout/SpaceBeforeComma:
201
+ Exclude:
202
+ - 'app/models/key_values.rb'
203
+ - 'app/models/key_values/**/**/*.rb'
204
+ Layout/SpaceInsideHashLiteralBraces:
205
+ Exclude:
206
+ - 'app/models/key_values.rb'
207
+ - 'app/models/key_values/**/**/*.rb'
208
+ Rails/HasManyOrHasOneDependent:
209
+ Exclude:
210
+ - 'app/models/key_values.rb'
211
+ - 'app/models/key_values/**/**/*.rb'
212
+
213
+ # ---- End of Disable some cop for key values ----
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.10
7
+ before_install: gem install bundler -v 1.17.2
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at roelly.wang@cyberbiz.io. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cyberbiz_express (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ cyberbiz_express!
15
+
16
+ BUNDLED WITH
17
+ 1.17.2
data/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # CyberbizExpress
2
+
3
+ Ninja Van API Document:
4
+ https://api-docs.ninjavan.co/en
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'cyberbiz_express'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install cyberbiz_express
21
+
22
+ ## Usage
23
+
24
+ ### Ninja Van
25
+ ### config/initializers/ninja_van.rb
26
+
27
+ ```ruby
28
+ require 'cyberbiz_express/ninja_van/ninja_van'
29
+
30
+ CyberbizExpress::NinjaVan.configure do |config|ÂÂÂÂ
31
+ config.client_id = SecretSetting.ninja_van.client_id
32
+ config.client_secret = SecretSetting.ninja_van.client_secret
33
+ config.api_url =
34
+ if Rails.env.production?
35
+ 'https://api.ninjavan.co/my'
36
+ else
37
+ 'https://api-sandbox.ninjavan.co/sg'
38
+ end
39
+ end
40
+ ```
41
+
42
+ ### submit_order
43
+
44
+ ```ruby
45
+ order = {
46
+ number: '1101',
47
+ email: 'buyer@cyberbiz.io',
48
+ line_items: [{ name: 'test1', quantity: 3 },{ name: 'test2', quantity: 1 }],
49
+ }
50
+ shipping_address = {
51
+ name: 'Jane Doe',
52
+ phone: '+60103067174',
53
+ email: 'sample_to@cyberbiz,io',
54
+ address1: 'Jalan PJU 8/8',
55
+ address2: '',
56
+ district: 'Damansara Perdana',
57
+ city: 'Petaling Jaya',
58
+ province: 'Selangor',
59
+ location: 'MY',
60
+ zip_code: '47820',
61
+ }
62
+ shop = {
63
+ id: 24719,
64
+ name: 'My Shop',
65
+ phone: '+60138201527',
66
+ email: 'sample@cyberbiz,io',
67
+ address: '17 Lorong Jambu 3',
68
+ district: 'Taman Sri Delima',
69
+ city: 'Simpang Ampat',
70
+ province: 'Pulau Pinang',
71
+ location: 'MY',
72
+ zip_code: '51200',
73
+ }
74
+ options = {
75
+ pickup_date: '2024-12-31',
76
+ pickup_start_time: '09:01',
77
+ pickup_end_time: '13:31',
78
+ delivery_date: '2025-01-12',
79
+ delivery_start_time: '09:01',
80
+ delivery_end_time: '13:31',
81
+ total_weight: 4.5,
82
+ }
83
+ CyberbizExpress::NinjaVan::Api.new('ninja_van').submit_order(order, shipping_address, shop, options)
84
+ ```
85
+
86
+ ### update_order
87
+
88
+ ```ruby
89
+ CyberbizExpress::NinjaVan::Api.new('ninja_van').update_order('CYB14530O1103', {})
90
+ ```
91
+
92
+ ### cancel_order
93
+
94
+ ```ruby
95
+ CyberbizExpress::NinjaVan::Api.new('ninja_van').cancel_order('FF0194810413', {}, {}, {})
96
+ ```
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+
5
+ # You can add fixtures and/or initialization code here to make experimenting
6
+ # with your gem easier. You can also use a different console, if you like.
7
+
8
+ # (If you use this, don't forget to add pry to your Gemfile!)
9
+ # require "pry"
10
+ # Pry.start
11
+
12
+ require "irb"
13
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'cyberbiz_express/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'cyberbiz_express'
9
+ spec.version = CyberbizExpress::VERSION
10
+ spec.authors = ['Roelly']
11
+ spec.email = ['roelly.wang@cyberbiz.io']
12
+ spec.summary = 'Use for express service.'
13
+ spec.description = 'Use for get tracking_number, confirm shipping and track shipping status.'
14
+ spec.homepage = 'https://github.com/sinleadpro/cyberbiz_express'
15
+ spec.license = 'Nonstandard'
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files =
20
+ Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ # spec.bindir = 'exe'
24
+ # spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ # spec.require_paths = ['lib']
26
+ # spec.required_ruby_version = '>= 2.6'
27
+
28
+ # spec.add_development_dependency('bundler', '~> 1.17')
29
+ # spec.add_development_dependency('rake', '~> 10.0')
30
+ # spec.add_development_dependency('rspec', '~> 3.0')
31
+ # spec.add_development_dependency('timecop', '~> 0.9.5')
32
+ # spec.add_development_dependency('webmock', '~> 3.14')
33
+ # spec.add_dependency('activesupport')
34
+ spec.metadata['rubygems_mfa_required'] = 'true'
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CyberbizExpress
4
+ module ExpressBase
5
+ def estimate_fee(_order)
6
+ raise(NoMethodError, "There is no estimate_fee API for #{@tracking_company}")
7
+ end
8
+
9
+ def submit_order(_order, _shipping_address, _shop, _options)
10
+ raise(NoMethodError, "There is no submit_order API for #{@tracking_company}")
11
+ end
12
+
13
+ def update_order(_order_number, _shipping_address)
14
+ raise(NoMethodError, "There is no update_order API for #{@tracking_company}")
15
+ end
16
+
17
+ def cancel_order(_tracking_number, _order_number, _shop_info, _reason)
18
+ raise(NoMethodError, "There is no cancel_order API for #{@tracking_company}")
19
+ end
20
+
21
+ def track_status(_order)
22
+ raise(NoMethodError, "There is no track_status API for #{@tracking_company}")
23
+ end
24
+
25
+ def reconcile(_file, _dry_run_mode, _options)
26
+ raise(NoMethodError, "There is no reconcile API for #{@tracking_company}")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
+ require_relative '../express_base'
7
+
8
+ module CyberbizExpress
9
+ module NinjaVan
10
+ class Api
11
+ include ::CyberbizExpress::ExpressBase
12
+
13
+ def initialize(tracking_company, logger: nil)
14
+ @logger = logger || Logger.new($stdout)
15
+ @tracking_company = tracking_company
16
+ @access_token = nil
17
+ end
18
+
19
+ def submit_order(order, shipping_address, shop, options)
20
+ @access_token ||= fetch_access_token
21
+ url = URI("#{CyberbizExpress::NinjaVan.api_url}/4.2/orders")
22
+ https = Net::HTTP.new(url.host, url.port)
23
+ https.use_ssl = true
24
+
25
+ request = Net::HTTP::Post.new(url)
26
+ request['Authorization'] = "Bearer #{@access_token}"
27
+ request['Content-Type'] = 'application/json'
28
+ request.body =
29
+ JSON.dump(submit_order_payload(shop.as_json, order.as_json, shipping_address.as_json, options.as_json))
30
+
31
+ response = https.request(request)
32
+ record_result('submit_order', request, response)
33
+
34
+ json = JSON.parse(response.body)
35
+ handle_response(json['requested_tracking_number'].present?, json)
36
+ end
37
+
38
+ def update_order(order_number, _shipping_address)
39
+ @access_token ||= fetch_access_token
40
+ url = URI("#{CyberbizExpress::NinjaVan.api_url}/2.0/reports/waybill?tid=#{order_number}")
41
+ https = Net::HTTP.new(url.host, url.port)
42
+ https.use_ssl = true
43
+
44
+ request = Net::HTTP::Get.new(url)
45
+ request['Authorization'] = "Bearer #{@access_token}"
46
+
47
+ response = https.request(request)
48
+ record_result('update_order', request, response)
49
+
50
+ json = JSON.parse(response.body)
51
+ handle_response(json['requested_tracking_number'].present?, json)
52
+ end
53
+
54
+ def cancel_order(tracking_number, _order_number, _shop_info, _reason)
55
+ @access_token ||= fetch_access_token
56
+ url = URI("#{CyberbizExpress::NinjaVan.api_url}/2.0/2.2/orders/#{tracking_number}")
57
+ https = Net::HTTP.new(url.host, url.port)
58
+ https.use_ssl = true
59
+
60
+ request = Net::HTTP::Delete.new(url)
61
+ request['Authorization'] = "Bearer #{@access_token}"
62
+
63
+ response = https.request(request)
64
+ record_result('cancel_order', request, response)
65
+
66
+ json = JSON.parse(response.body)
67
+ handle_response(json['requested_tracking_number'].present?, json)
68
+ end
69
+
70
+ private
71
+
72
+ def fetch_access_token
73
+ uri = URI.parse("#{CyberbizExpress::NinjaVan.api_url}/2.0/oauth/access_token")
74
+ https = Net::HTTP.new(uri.host, uri.port)
75
+ https.use_ssl = true
76
+
77
+ request = Net::HTTP::Post.new(uri)
78
+ request['Content-Type'] = 'application/json'
79
+ request.body = JSON.dump(access_token_payload)
80
+
81
+ response = https.request(request)
82
+ @logger.info("Linex fetch_token response => #{response.body.force_encoding('UTF-8')}")
83
+
84
+ JSON.parse(response.body)['access_token']
85
+ end
86
+
87
+ def access_token_payload
88
+ {
89
+ client_id: CyberbizExpress::NinjaVan.client_id,
90
+ client_secret: CyberbizExpress::NinjaVan.client_secret,
91
+ grant_type: 'client_credentials',
92
+ }.as_json
93
+ end
94
+
95
+ def record_result(mtehod, request, response)
96
+ @logger.info("Linex #{mtehod} request json => #{request.body}")
97
+ @logger.info("Linex #{mtehod} response => #{response.body.force_encoding('UTF-8')}")
98
+ end
99
+
100
+ def handle_response(success, response)
101
+ if success
102
+ response.merge({ success: true }.as_json)
103
+ else
104
+ response.merge({ success: false }.as_json)
105
+ end
106
+ end
107
+
108
+ def submit_order_payload(shop, order, shipping_address, options)
109
+ {
110
+ marketplace: {
111
+ seller_id: shop['id'],
112
+ seller_company_name: shop['name'],
113
+ },
114
+ service_type: 'Marketplace',
115
+ service_level: 'Standard',
116
+ requested_tracking_number: "CYB#{shop['id']}O#{order['number']}",
117
+ reference: {
118
+ merchant_order_number: "SHIP-CYB#{shop['id']}O#{order['number']}",
119
+ },
120
+ from: {
121
+ name: shop['name'],
122
+ phone_number: shop['phone'],
123
+ email: shop['email'],
124
+ address: {
125
+ address1: shop['address'],
126
+ area: shop['district'],
127
+ city: shop['city'],
128
+ state: shop['province'],
129
+ address_type: 'office',
130
+ country: shop['location'],
131
+ postcode: shop['zip_code'],
132
+ },
133
+ },
134
+ to: {
135
+ name: shipping_address['name'],
136
+ phone_number: shipping_address['phone'],
137
+ email: order['email'],
138
+ address: {
139
+ address1: shipping_address['address1'],
140
+ address2: shipping_address['address2'],
141
+ area: shipping_address['district'],
142
+ city: shipping_address['city'],
143
+ state: shipping_address['province'],
144
+ address_type: 'home',
145
+ country: shipping_address['country'],
146
+ postcode: shipping_address['zip'],
147
+ },
148
+ },
149
+ parcel_job: {
150
+ is_pickup_required: true,
151
+ pickup_service_type: 'Scheduled',
152
+ pickup_service_level: 'Standard',
153
+ pickup_date: options['pickup_date'],
154
+ pickup_timeslot: {
155
+ start_time: options['pickup_start_time'],
156
+ end_time: options['pickup_end_time'],
157
+ timezone: 'Asia/Kuala_Lumpur',
158
+ },
159
+ delivery_start_date: options['delivery_date'],
160
+ delivery_timeslot: {
161
+ start_time: options['delivery_start_time'],
162
+ end_time: options['delivery_end_time'],
163
+ timezone: 'Asia/Kuala_Lumpur',
164
+ },
165
+ dimensions: {
166
+ weight: options['total_weight'],
167
+ },
168
+ items: order['line_items'].map { |item| { item_description: item['name'], quantity: item['quantity'] } },
169
+ },
170
+ }.as_json
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CyberbizExpress
4
+ module NinjaVan
5
+ autoload :Api, 'cyberbiz_express/ninja_van/api'
6
+ autoload :Webhook, 'cyberbiz_express/ninja_van/webhook'
7
+
8
+ class << self
9
+ attr_accessor :client_id, :client_secret, :api_url
10
+ end
11
+
12
+ def self.configure(&_block)
13
+ yield(CyberbizExpress::NinjaVan)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+ require 'openssl'
5
+
6
+ module CyberbizExpress
7
+ module NinjaVan
8
+ class Webhook
9
+ def decode_webhook_payload(webhook_payload)
10
+ hash = OpenSSL::HMAC.digest('sha256', CyberbizExpress::NinjaVan.client_secret, webhook_payload)
11
+ Base64.encode64(hash)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CyberbizExpress
4
+ VERSION = '0.1.0'
5
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cyberbiz_express
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Roelly
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-11-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Use for get tracking_number, confirm shipping and track shipping status.
14
+ email:
15
+ - roelly.wang@cyberbiz.io
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".rspec"
22
+ - ".rubocop.yml"
23
+ - ".travis.yml"
24
+ - CODE_OF_CONDUCT.md
25
+ - Gemfile
26
+ - Gemfile.lock
27
+ - README.md
28
+ - Rakefile
29
+ - bin/console
30
+ - bin/setup
31
+ - cyberbiz_express.gemspec
32
+ - lib/cyberbiz_express/express_base.rb
33
+ - lib/cyberbiz_express/ninja_van/api.rb
34
+ - lib/cyberbiz_express/ninja_van/ninja_van.rb
35
+ - lib/cyberbiz_express/ninja_van/webhook.rb
36
+ - lib/cyberbiz_express/version.rb
37
+ homepage: https://github.com/sinleadpro/cyberbiz_express
38
+ licenses:
39
+ - Nonstandard
40
+ metadata:
41
+ rubygems_mfa_required: 'true'
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.0.3.1
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Use for express service.
61
+ test_files: []