Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GCW-3407 Gogox Gem Integration and Transport APIs #1195

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,9 @@ STOCKIT_API_TOKEN=

SLACK_API_TOKEN=
SLACK_PIN_CHANNEL=

GOGOX_CLIENT_ID=
GOGOX_CLIENT_SECRET=
GOGOX_GRANT_TYPE=
GOGOX_HOST=
GOGOX_PAYMENT_METHOD=
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ gem 'easyzpl', git: 'https://github.com/crossroads/easyzpl.git'
gem 'factory_bot_rails' # used in rake db:seed in production
gem 'fake_email_validator'
gem 'ffaker'
gem 'go_go_van_api', git: '[email protected]:crossroads/go_go_van_api.git', branch: 'master'
gem 'go_go_van_api', git: '[email protected]:crossroads/go_go_van_api.git', branch: 'GCW-3407'
gem 'guid'
gem 'http_accept_language'
gem 'jwt', '~> 2.2.2'
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
GIT
remote: [email protected]:crossroads/go_go_van_api.git
revision: 3cbc5590e2a11a7903483de276bc668be88843cb
branch: master
revision: 7c0794f1c9eebcf0d44b8a4341f26ea8bdf259c9
branch: GCW-3407
specs:
go_go_van_api (0.0.1)
nestful (~> 1)
Expand Down
71 changes: 71 additions & 0 deletions app/controllers/api/v1/transports_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
module Api
module V1
class TransportsController < Api::V1::ApiController

skip_authorization_check
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved

api :GET, '/v1/transports/providers', "List all GoodCity Tranports Options."
def providers
render json: TransportProvider.all.cached_json
end

api :POST, '/v1/transports/quotation', "Get provider quotation"
param :provider, String, desc: "Provider selected for transport"
param :vehicle_type, String, desc: "Transport vehicle-type"
param :offer_id, String, desc: "Id of the offer"
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
param :schedule_at, String, desc: "Scheduled time for delivery"
param :district_id, String, desc: "Id of the district"
def quotation
order_price = TransportService.new(transport_params.to_h).quotation
render json: order_price.to_json
end

api :POST, '/v1/transports/quotation', "Book transport"
param :provider, String, desc: "Provider selected for transport"
param :vehicle_type, String, desc: "Transport vehicle-type"
param :offer_id, String, desc: "Id of the offer"
param :schedule_at, String, desc: "Scheduled time for delivery"
param :district_id, String, desc: "Id of the district"
param :pickup_contact_name, String, desc: "Contact Person Name"
param :pickup_contact_phone, String, desc: "Contact Person Mobile"
param :pickup_street_address, Hash, desc: "Pickup Address"
def book
order_info = TransportService.new(transport_params.to_h).book
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
render json: order_info.to_json
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
end

api :GET, '/v1/transports/:id/order_details', "Get GoodCity Tranport order details."
def order_details
order_info = TransportService.new({booking_id: params[:id]}).status
render json: order_info.to_json
end

api :POST, '/v1/transports/:id/cancel_order', "Cancel GoodCity Tranport order."
def cancel_order
order_info = TransportService.new({booking_id: params[:id]}).cancel
render json: order_info.to_json
end

api :POST, '/v1/transports/update_gogox_order', "Webhook to update GOGOX order status"
def update_gogox_order
# setup ngrok and inspect response
# response details are not yet available from Gogox Provider
end

private

def transport_params
set_district_id unless params["district_id"].presence
params.permit([
"scheduled_at", "district_id", "offer_id", "provider", "vehicle_type",
"pickup_street_address", "pickup_contact_name", "pickup_contact_phone"
])
end

def set_district_id
params["district_id"] = User.current_user.address.district_id
end

end
end
end
3 changes: 3 additions & 0 deletions app/models/transport_provider.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class TransportProvider < ApplicationRecord
include CacheableJson
end
2 changes: 2 additions & 0 deletions app/models/transport_provider_order.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class TransportProviderOrder < ApplicationRecord
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
end
5 changes: 5 additions & 0 deletions app/serializers/api/v1/transport_provider_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Api::V1
class TransportProviderSerializer < ApplicationSerializer
attributes :id, :name, :logo, :description, :metadata
end
end
127 changes: 127 additions & 0 deletions app/services/gogox.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
class Gogox
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved

attr_accessor :params, :time, :vehicle, :district_id

VEHICLE_TYPES = ["van", "mudou", "mudou9"]

def initialize(options = {})
@params = options
@time = parse_pickup_time(options[:scheduled_at])
@vehicle = options[:vehicle]
@district_id = options[:district_id]
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
end

# Rsponse
# {
# "uuid" => "2f859363-5c43-4fe2-9b91-6c6c43d610d2",
# "status" => "pending",
# "vehicle_type" => "van",
# "payment_method" => "prepaid_wallet",
# "courier" => {},
# "pickup" => {
# "name" => "Swati J",
# "street_address" => "123",
# "floor_or_unit_number" => nil,
# "schedule_at" => 1609242940,
# "location" => {"lat" => 22.5029632, "lng" => 114.1277213},
# "contact" => {
# "name" => "Swati J",
# "phone_number" => "+85251111113",
# "phone_extension" => nil
# }
# },
# "destinations" => [{
# "name" => "Steve Kenworthy",
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
# "street_address" => "Castle Peak Rd (So Kwun Wat)",
# "floor_or_unit_number" => nil,
# "location" => {"lat" => 22.3748365, "lng" => 113.9931416},
# "contact" => {
# "name" => "Steve Kenworthy",
# "phone_number" => "+85251111111"
# }
# }],
# "note_to_courier" => nil,
# "price" => {"amount" => 15000, "currency" => "HKD"},
# "price_breakdown" => [{"key" => "fee", "amount" => 15000}]
# }
def book
GogoxApi::Transport.new(order_attributes).order
end

# Response:
# {
# "vehicle_type" => "van",
# "estimated_price" => {"amount" => 15000, "currency" => "HKD"},
# "estimated_price_breakdown" => [{"key" => "fee", "amount" => 15000}]
# }
def quotation
GogoxApi::Transport.new(quotation_attributes).quotation
end

class << self

def transport_status(booking_id)
GogoxApi::Transport.new.status(booking_id)
end

# Response
# Response is nil on successful cancellation of GOGOX transport
def cancel_order(booking_id)
response = GogoxApi::Transport.new.cancel(booking_id)
if !response
{
order_uuid: booking_id,
status: "cancelled"
}
end
end

end

private

def order_attributes
{
'vehicle_type': vehicle_type,
"pickup_location": params[:pickup_location],
"pickup_street_address": params[:pickup_street_address],
"scheduled_at": parse_time,
"pickup_contact_name": params[:pickup_contact_name],
"pickup_contact_phone": params[:pickup_contact_phone],
"destination_location": params[:destination_location],
"destination_street_address": params[:destination_street_address],
"destination_contact_name": params[:destination_contact_name],
"destination_contact_phone": params[:destination_contact_phone]
}
end

def quotation_attributes
{
'vehicle_type': vehicle_type,
"scheduled_at": parse_time,
"pickup_location": params[:pickup_location],
"destination_location": params[:destination_location]
}
end

def vehicle_type
if vehicle.blank? || !VEHICLE_TYPES.include?(vehicle)
raise(ValueError, "vehicle should be from #{VEHICLE_TYPES.join(', ')}")
end
vehicle
end

def parse_pickup_time(time = nil)
return time if time.present?

# next available date within next 5 days
next_available_date = DateSet.new(5, 1).available_dates.first
(next_available_date.beginning_of_day + 12.hours)
end

def parse_time
DateTime.parse(@time.to_s).to_i
end

class ValueError < StandardError; end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of just value error defining here, create a error in errors.rb
something like TransportationServiceError

end
124 changes: 124 additions & 0 deletions app/services/transport_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
class TransportService

attr_accessor :provider_name, :params, :provider, :booking_id, :user, :district_id

def initialize(options={})
@params = options
@provider_name = options && options["provider"]
@provider ||= Object::const_get(provider_name)
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
@booking_id = options && options["booking_id"]

fetch_user
fetch_district_id
end

def quotation
@provider.new(params).quotation
end

def book
response = @provider.new(params).book
storeOrderDetails(response)
end

def cancel
response = @provider.cancel_order(booking_id)
if response
updateOrderDetails({
status: "cancelled",
order_uuid: booking_id
})
end
end

def status
response = @provider.transport_status(booking_id)
if response
updateOrderDetails({
status: response["status"],
order_uuid: booking_id,
metadata: response
})
end
end

private

def storeOrderDetails(response)
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
TransportProviderOrder.create(
transport_provider_id: TransportProvider.find_by(name: provider_name).try(:id),
order_uuid: response["uuid"],
status: response["status"],
schedule_at: response["pickup"]["schedule_at"],
metadata: response,
offer_id: @params["offer_id"]
)
end

def updateOrderDetails(response)
order = TransportProviderOrder.find_by(order_uuid: response["order_uuid"])
order.update_attributes(response)
end

def quotation_attributes
{
'vehicle_type': @params["vehicle_type"],
"scheduled_at": @params["scheduled_at"],
"pickup_location": pickup_location,
"destination_location": destination_location
}
end

def pickup_location
pickup_district = District.find(@district_id)
[pickup_district.latitude, pickup_district.longitude]
end

# TODO: Update crossroads geolocation values
def destination_location
[22.3748365, 113.9931416]
end

# TODO: Change
def destination_street_address
"Castle Peak Rd (So Kwun Wat)"
swatijadhav marked this conversation as resolved.
Show resolved Hide resolved
end

# TODO: Change
def destination_contact_name
"Steve Kenworthy"
end

# TODO: Change
def destination_contact_phone
"+85251111111"
end

def order_attributes
{
'vehicle_type': vehicle_type,
"pickup_location": pickup_location,
"pickup_street_address": params[:pickup_street_address],
"scheduled_at": params[:schedule_at],
"pickup_contact_name": params[:pickup_contact_name] || @user.full_name,
"pickup_contact_phone": params[:pickup_contact_phone] || @user.mobile,
"destination_location": destination_location,
"destination_street_address": destination_street_address,
"destination_contact_name": destination_contact_name,
"destination_contact_phone": destination_contact_phone
}
end

def fetch_user
@user ||= if @params["user_id"].present?
User.find_by(id: @params["user_id"])
else
User.current_user
end
end

def fetch_district_id
@district_id ||= @params["district_id"].presence || @user.address.district_id
end

end
12 changes: 12 additions & 0 deletions db/migrate/20201210092143_create_transport_providers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateTransportProviders < ActiveRecord::Migration[5.2]
def change
create_table :transport_providers do |t|
t.string :name
t.string :logo
t.text :description
t.jsonb :metadata, default: '{}'

t.timestamps
end
end
end
14 changes: 14 additions & 0 deletions db/migrate/20210111115250_create_transport_provider_orders.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateTransportProviderOrders < ActiveRecord::Migration[5.2]
def change
create_table :transport_provider_orders do |t|
t.integer :transport_provider_id
t.string :order_uuid
t.string :status
t.datetime :scheduled_at
t.jsonb :metadata
t.integer :offer_id

t.timestamps
end
end
end
Loading