# frozen_string_literal: true require 'json' require 'net/http' require 'uri' require_relative '../express_base' module CyberbizExpress module NinjaVan class Api include ::CyberbizExpress::ExpressBase def initialize(tracking_company, logger: nil) @logger = logger || Logger.new($stdout) @tracking_company = tracking_company @access_token = nil end def submit_order(order, shipping_address, shop, options) @access_token ||= fetch_access_token url = URI("#{CyberbizExpress::NinjaVan.api_url}/4.2/orders") https = Net::HTTP.new(url.host, url.port) https.use_ssl = true request = Net::HTTP::Post.new(url) request['Authorization'] = "Bearer #{@access_token}" request['Content-Type'] = 'application/json' request.body = JSON.dump( submit_order_payload( stringify_keys(shop), stringify_keys(order), stringify_keys(shipping_address), stringify_keys(options), ), ) response = https.request(request) record_result('submit_order', request, response) json = JSON.parse(response.body) handle_response(!json['requested_tracking_number'].nil?, json) end def update_order(order_number, _shipping_address) @access_token ||= fetch_access_token url = URI("#{CyberbizExpress::NinjaVan.api_url}/2.0/reports/waybill?tid=#{order_number}") https = Net::HTTP.new(url.host, url.port) https.use_ssl = true request = Net::HTTP::Get.new(url) request['Authorization'] = "Bearer #{@access_token}" response = https.request(request) record_result('update_order', request, response) json = JSON.parse(response.body) handle_response(!json['requested_tracking_number'].nil?, json) end def cancel_order(tracking_number, _order_number, _shop_info, _reason) @access_token ||= fetch_access_token url = URI("#{CyberbizExpress::NinjaVan.api_url}/2.0/2.2/orders/#{tracking_number}") https = Net::HTTP.new(url.host, url.port) https.use_ssl = true request = Net::HTTP::Delete.new(url) request['Authorization'] = "Bearer #{@access_token}" response = https.request(request) record_result('cancel_order', request, response) json = JSON.parse(response.body) handle_response(!json['requested_tracking_number'].nil?, json) end private def fetch_access_token uri = URI.parse("#{CyberbizExpress::NinjaVan.api_url}/2.0/oauth/access_token") https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = true request = Net::HTTP::Post.new(uri) request['Content-Type'] = 'application/json' request.body = JSON.dump(access_token_payload) response = https.request(request) @logger.info("Linex fetch_token response => #{response.body.force_encoding('UTF-8')}") JSON.parse(response.body)['access_token'] end def access_token_payload { client_id: CyberbizExpress::NinjaVan.client_id, client_secret: CyberbizExpress::NinjaVan.client_secret, grant_type: 'client_credentials', } end def record_result(mtehod, request, response) @logger.info("Linex #{mtehod} request json => #{request.body}") @logger.info("Linex #{mtehod} response => #{response.body.force_encoding('UTF-8')}") end def handle_response(success, response) if success response.merge({ success: true }) else response.merge({ success: false }) end end def submit_order_payload(shop, order, shipping_address, options) payload = { service_type: options['service_type'], service_level: 'Standard', requested_tracking_number: "CYB#{shop['id']}O#{order['number']}", reference: { merchant_order_number: "SHIP-CYB#{shop['id']}O#{order['number']}", }, from: { name: shop['name'], phone_number: shop['phone'], email: shop['email'], address: { address1: shop['address'], area: shop['district'], city: shop['city'], state: shop['province'], address_type: 'office', country: shop['location'], postcode: shop['zip_code'], }, }, to: { name: shipping_address['name'], phone_number: shipping_address['phone'], email: order['email'], address: { address1: shipping_address['address1'], address2: shipping_address['address2'], area: shipping_address['district'], city: shipping_address['city'], state: shipping_address['province'], address_type: 'home', country: shipping_address['location'], postcode: shipping_address['zip_code'], }, }, parcel_job: { is_pickup_required: true, pickup_service_type: 'Scheduled', pickup_service_level: 'Standard', pickup_date: options['pickup_date'], pickup_timeslot: { start_time: options['pickup_start_time'], end_time: options['pickup_end_time'], timezone: 'Asia/Kuala_Lumpur', }, pickup_instructions: options['pickup_instructions'], delivery_instructions: options['delivery_instructions'], delivery_start_date: options['delivery_date'], delivery_timeslot: { start_time: options['delivery_start_time'], end_time: options['delivery_end_time'], timezone: 'Asia/Kuala_Lumpur', }, dimensions: { weight: options['total_weight'], }, insured_value: options['insured_value'], items: line_items_hash(order['line_items']), }, } if options['service_type'] == 'Marketplace' payload.merge(marketplace: { seller_id: shop['id'], seller_company_name: shop['name'] }) else payload end end def line_items_hash(line_items) line_items = line_items.map { |item| item.transform_keys(&:to_s) } line_items.map { |item| { item_description: item['name'], quantity: item['quantity'] } } end def stringify_keys(hash) hash.transform_keys(&:to_s) end end end end