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

[BOL-10] Order Tracking Service #97

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
57 changes: 57 additions & 0 deletions app/decorators/models/solidus_bolt/shipment_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module SolidusBolt
module ShipmentDecorator
def self.prepended(base)
base.before_save :update_bolt_tracking_info
end

def bolt_items
line_items.map do |line_item|
{
reference: line_item.sku,
name: line_item.name,
description: line_item.description,
total_amount: {
amount: line_item.total,
currency: line_item.currency,
currency_symbol: currency_symbol
},
unit_price: {
amount: line_item.price,
currency: line_item.currency,
currency_symbol: currency_symbol
},
tax_amount: {
amount: line_item.additional_tax_total,
currency: line_item.currency,
currency_symbol: currency_symbol
},
quantity: line_item.quantity,
sku: line_item.sku
}
end
end

private

def currency_symbol
Monetize.from_string(order.total, order.currency).symbol
end

def update_bolt_tracking_info
return if tracking_was.present?
return unless tracking_changed?

payment = order&.payments&.completed&.last
return unless payment&.payment_method.instance_of?(SolidusBolt::PaymentMethod)

transaction_reference = payment&.response_code
return if transaction_reference.blank?

SolidusBolt::ShipmentTrackingJob.perform_later(transaction_reference: transaction_reference, shipment: self)
Copy link
Contributor

Choose a reason for hiding this comment

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

What will happen if the order contains more than one shipment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure yet if Bolt supports multiple shipments like Solidus.

Nothing in the bolt docs points to supporting multiple shipments and also this API returns an error if we have already added one instance of tracking details to the Order on Bolt.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should ask the Bolt team how they would like to handle that part. I don't want to return an error anytime that a user marks the second shipment as shipped.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure

end

Spree::Shipment.prepend(self)
end
end
11 changes: 11 additions & 0 deletions app/jobs/solidus_bolt/shipment_tracking_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module SolidusBolt
class ShipmentTrackingJob < ApplicationJob
queue_as :default

def perform(transaction_reference:, shipment:)
SolidusBolt::Orders::TrackShipmentService.call(transaction_reference: transaction_reference, shipment: shipment)
end
end
end
47 changes: 47 additions & 0 deletions app/services/solidus_bolt/orders/track_shipment_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

module SolidusBolt
module Orders
class TrackShipmentService < SolidusBolt::BaseService
attr_reader :transaction_reference, :shipment

def initialize(transaction_reference:, shipment:)
@transaction_reference = transaction_reference
@shipment = shipment
super
end

def call
track_shipment
end

private

def track_shipment
options = build_options
handle_result(
HTTParty.post(
"#{api_base_url}/#{api_version}/merchant/track_shipment",
options
)
)
end

def build_options
{
body: {
transaction_reference: transaction_reference,
tracking_number: shipment.tracking,
carrier: shipment.shipping_method.name,
items: shipment.bolt_items,
is_non_bolt_order: false
}.to_json,
headers: {
'X-Nonce' => generate_nonce,
'Content-Type' => 'application/json'
}.merge(authentication_header)
}
end
end
end
end
63 changes: 63 additions & 0 deletions spec/decorators/models/solidus_bolt/shipment_decorator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
require 'spec_helper'

RSpec.describe SolidusBolt::ShipmentDecorator do
let(:payment_method) { create(:bolt_payment_method) }
let(:payment_source) { create(:bolt_payment_source) }
let(:payment) do
create(
:payment,
state: 'completed',
source_id: payment_source.id,
source_type: SolidusBolt::PaymentSource,
payment_method_id: payment_method.id,
response_code: 'Doctor Strange'
)
end
let(:order) { payment.order }

describe '#bolt_items' do
it 'returns an array' do
create(:shipment, order: order, id: rand(1..10), tracking: 'MockBolt1678')
order.shipments.reload
shipment = order.shipments.last
items = shipment.bolt_items

expect(items).to be_a(Array)
end

it 'lists all line_items' do
create(:shipment, order: order, id: rand(1..10), tracking: 'MockBolt1678')
order.shipments.reload
shipment = order.shipments.last
items = shipment.bolt_items

expect(items.count).to eq(order.line_items.count)
end
end

describe '#update_bolt_tracking_info' do
before { allow(SolidusBolt::Orders::TrackShipmentService).to receive(:call) }

context 'when tracking is nil' do
it 'enqueues SolidusBolt::ShipmentTrackingJob' do
create(:shipment, order: order, id: rand(1..10), tracking: nil)
order.shipments.reload
shipment = order.shipments.last

shipment.tracking = 'MockBolt1678'
expect { shipment.save }.to have_enqueued_job(SolidusBolt::ShipmentTrackingJob)
end
end

context 'when tracking has a value' do
it 'does not enqueue SolidusBolt::ShipmentTrackingJob' do
create(:shipment, order: order, id: rand(1..10), tracking: 'MockBolt1678')
order.shipments.reload
shipment = order.shipments.last

shipment.tracking = 'MockBolt1123'
expect { shipment.save }.not_to have_enqueued_job(SolidusBolt::ShipmentTrackingJob)
end
end
end
end
Loading