diff --git a/app/models/oms/billing_address.rb b/app/models/oms/billing_address.rb new file mode 100644 index 0000000..c66e880 --- /dev/null +++ b/app/models/oms/billing_address.rb @@ -0,0 +1,9 @@ +require "flex_commerce_api/oms/api_base" + +module FlexCommerce + module OMS + class BillingAddress < FlexCommerceApi::OMS::ApiBase + belongs_to :customer_order, class_name: "::FlexCommerce::OMS::CustomerOrder" + end + end +end diff --git a/app/models/oms/customer.rb b/app/models/oms/customer.rb new file mode 100644 index 0000000..49ee4dc --- /dev/null +++ b/app/models/oms/customer.rb @@ -0,0 +1,9 @@ +require "flex_commerce_api/oms/api_base" + +module FlexCommerce + module OMS + class Customer < FlexCommerceApi::OMS::ApiBase + belongs_to :customer_order, class_name: "::FlexCommerce::OMS::CustomerOrder" + end + end +end diff --git a/app/models/oms/customer_order.rb b/app/models/oms/customer_order.rb new file mode 100644 index 0000000..d8c7096 --- /dev/null +++ b/app/models/oms/customer_order.rb @@ -0,0 +1,15 @@ +require "flex_commerce_api/oms/api_base" +require "flex_commerce_api/api_base" +module FlexCommerce + module OMS + class CustomerOrder < FlexCommerceApi::OMS::ApiBase + has_many :payments, class_name: "::FlexCommerce::OMS::Payments" + has_many :line_items, class_name: "::FlexCommerce::OMS::LineItem" + has_many :discounts, class_name: "::FlexCommerce::OMS::Discount" + has_many :shipping_address, class_name: "::FlexCommerce::OMS::Address" + has_one :billing_address, class_name: "::FlexCommerce::OMS::Address" + has_one :customer, class_name: "::FlexCommerce::OMS::Customer" + has_one :shipping_method, class_name: "::FlexCommerce::OMS::ShippingMethod" + end + end +end diff --git a/app/models/oms/discount.rb b/app/models/oms/discount.rb new file mode 100644 index 0000000..9591254 --- /dev/null +++ b/app/models/oms/discount.rb @@ -0,0 +1,9 @@ +require "flex_commerce_api/oms/api_base" + +module FlexCommerce + module OMS + class Discount < FlexCommerceApi::OMS::ApiBase + belongs_to :customer_order, class_name: "::FlexCommerce::OMS::CustomerOrder" + end + end +end diff --git a/app/models/oms/line_item.rb b/app/models/oms/line_item.rb new file mode 100644 index 0000000..e3dfe7c --- /dev/null +++ b/app/models/oms/line_item.rb @@ -0,0 +1,9 @@ +require "flex_commerce_api/oms/api_base" + +module FlexCommerce + module OMS + class LineItem < FlexCommerceApi::OMS::ApiBase + belongs_to :customer_order, class_name: "::FlexCommerce::OMS::CustomerOrder" + end + end +end diff --git a/app/models/oms/payment.rb b/app/models/oms/payment.rb new file mode 100644 index 0000000..a97a7d9 --- /dev/null +++ b/app/models/oms/payment.rb @@ -0,0 +1,9 @@ +require "flex_commerce_api/oms/api_base" + +module FlexCommerce + module OMS + class Payment < FlexCommerceApi::OMS::ApiBase + belongs_to :customer_order, class_name: "::FlexCommerce::OMS::CustomerOrder" + end + end +end diff --git a/app/models/oms/shipping_address.rb b/app/models/oms/shipping_address.rb new file mode 100644 index 0000000..f842598 --- /dev/null +++ b/app/models/oms/shipping_address.rb @@ -0,0 +1,9 @@ +require "flex_commerce_api/oms/api_base" + +module FlexCommerce + module OMS + class ShippingAddress < FlexCommerceApi::OMS::ApiBase + belongs_to :customer_order, class_name: "::FlexCommerce::OMS::CustomerOrder" + end + end +end diff --git a/app/models/oms/shipping_method.rb b/app/models/oms/shipping_method.rb new file mode 100644 index 0000000..c52383b --- /dev/null +++ b/app/models/oms/shipping_method.rb @@ -0,0 +1,9 @@ +require "flex_commerce_api/oms/api_base" + +module FlexCommerce + module OMS + class ShippingMethod < FlexCommerceApi::OMS::ApiBase + belongs_to :customer_order, class_name: "::FlexCommerce::OMS::CustomerOrder" + end + end +end diff --git a/lib/flex_commerce.rb b/lib/flex_commerce.rb index 394ebea..a01dad5 100644 --- a/lib/flex_commerce.rb +++ b/lib/flex_commerce.rb @@ -12,6 +12,18 @@ module V2 autoload :UnallocateOrder, File.join(FlexCommerce.gem_root, "app", "models", "v2", "unallocate_order") end + # OMS + module OMS + autoload :BillingAddress, File.join(FlexCommerce.gem_root, "app", "models", "oms", "billing_address") + autoload :CustomerOrder, File.join(FlexCommerce.gem_root, "app", "models", "oms", "customer_order") + autoload :Customer, File.join(FlexCommerce.gem_root, "app", "models", "oms", "customer") + autoload :Discount, File.join(FlexCommerce.gem_root, "app", "models", "oms", "discount") + autoload :LineItem, File.join(FlexCommerce.gem_root, "app", "models", "oms", "line_item") + autoload :Payment, File.join(FlexCommerce.gem_root, "app", "models", "oms", "payment") + autoload :ShippingAddress, File.join(FlexCommerce.gem_root, "app", "models", "oms", "shipping_address") + autoload :ShippingMethod, File.join(FlexCommerce.gem_root, "app", "models", "oms", "shipping_method") + end + # V1 Models autoload :Address, File.join(gem_root, "app", "models", "address") autoload :AssetFile, File.join(gem_root, "app", "models", "asset_file") diff --git a/lib/flex_commerce_api/oms/api_base.rb b/lib/flex_commerce_api/oms/api_base.rb new file mode 100644 index 0000000..54ade02 --- /dev/null +++ b/lib/flex_commerce_api/oms/api_base.rb @@ -0,0 +1,13 @@ +require "flex_commerce_api/base_resource" + +module FlexCommerceApi + module OMS + class ApiBase < FlexCommerceApi::BaseResource + def self.endpoint_version + "v1/oms" + end + + reconfigure + end + end +end diff --git a/lib/flex_commerce_api/version.rb b/lib/flex_commerce_api/version.rb index aaf7496..4aeddfd 100644 --- a/lib/flex_commerce_api/version.rb +++ b/lib/flex_commerce_api/version.rb @@ -1,3 +1,3 @@ module FlexCommerceApi - VERSION = "0.8.3" + VERSION = "0.8.4" end diff --git a/lib/patches/json_api_client/resource.rb b/lib/patches/json_api_client/resource.rb new file mode 100644 index 0000000..b98a963 --- /dev/null +++ b/lib/patches/json_api_client/resource.rb @@ -0,0 +1,43 @@ +require "json_api_client/version" +if ["1.5.3"].include?(JsonApiClient::VERSION) + require "json_api_client/resource" + module JsonApiClient + class Resource + def save + return false unless valid? + + self.last_result_set = if persisted? + self.class.requestor.update(self) + else + self.class.requestor.create(self) + end + + if last_result_set.has_errors? + fill_errors + false + else + self.errors.clear if self.errors + mark_as_persisted! + if updated = last_result_set.first + self.attributes = updated.attributes + # This line has been added as part of https://github.com/chingor13/json_api_client/pull/238 + self.links.attributes = updated.links.attributes + self.relationships.attributes = updated.relationships.attributes + clear_changes_information + # This line has been added as part of https://github.com/JsonApiClient/json_api_client/pull/285 + self.relationships.clear_changes_information + end + true + end + end + end + end +else + raise %q( + Please check these two PRs: + * https://github.com/chingor13/json_api_client/pull/238 (This was released in version 1.5.0) + * https://github.com/JsonApiClient/json_api_client/pull/285 (This hasn't yet been released at the time of writing this) + If both have been merged into the gem version you are using, remove this file (#{__FILE__}). + If not, add the current version to the allowed array at the top of this file. + ) +end diff --git a/lib/paypal_express/auth.rb b/lib/paypal_express/auth.rb index 9786745..6005edf 100644 --- a/lib/paypal_express/auth.rb +++ b/lib/paypal_express/auth.rb @@ -6,14 +6,14 @@ module FlexCommerce module PaypalExpress # @class Setup - # + # # This service authorises the payment via the Paypal gateway class Auth include ::Retry include ::FlexCommerce::PaypalExpress::Api - + DEFAULT_CURRENCY = "GBP" - + # @initialize # # @param {String} token - Paypal token @@ -29,9 +29,9 @@ def initialize(cart:, token:, payer_id:, payment_transaction:, gateway_class: :: def call process_with_gateway end - + private - + attr_accessor :cart, :token, :payer_id, :payment_transaction, :gateway_class def process_with_gateway @@ -63,7 +63,7 @@ def process_with_gateway def do_express_checkout_payment Retry.call(no_of_retries: no_of_retires, rescue_errors: ::ActiveMerchant::ConnectionError) { ::NewRelic::Agent.increment_metric('Custom/Paypal/Do_Express_Checkout_Payment') if defined?(NewRelic::Agent) - gateway.order(convert_amount(cart.total), token: token, payer_id: payer_id, currency: DEFAULT_CURRENCY) + gateway.order(convert_amount(payment_transaction.amount), token: token, payer_id: payer_id, currency: DEFAULT_CURRENCY) } end @@ -71,7 +71,7 @@ def do_express_checkout_payment def do_authorization(response) Retry.call(no_of_retries: no_of_retires, rescue_errors: ::ActiveMerchant::ConnectionError) { ::NewRelic::Agent.increment_metric('Custom/Paypal/Do_Auhtorization') if defined?(NewRelic::Agent) - gateway.authorize_transaction(response.params["transaction_id"], convert_amount(cart.total), transaction_entity: "Order", currency: DEFAULT_CURRENCY, payer_id: payer_id) + gateway.authorize_transaction(response.params["transaction_id"], convert_amount(payment_transaction.amount), transaction_entity: "Order", currency: DEFAULT_CURRENCY, payer_id: payer_id) } end diff --git a/lib/paypal_express/generate_summary.rb b/lib/paypal_express/generate_summary.rb index 62f6735..5055d89 100644 --- a/lib/paypal_express/generate_summary.rb +++ b/lib/paypal_express/generate_summary.rb @@ -4,22 +4,25 @@ module FlexCommerce module PaypalExpress # @class GenerateSummary - # + # # This class is used while setting up the paypal for FE # It deals with line items total, sub total, tax calculations and # Also deals with discounted line items and discounts inorder to send to paypal - # + # If gift card was used to pay partial amount and subsequently + # gift card amount was passed, it subtracts gift card amount from total + # class GenerateSummary include ::FlexCommerce::PaypalExpress::Api - - def initialize(cart: , use_tax: false) + + def initialize(cart: , use_tax: false, gift_card_amount:) self.cart = cart self.use_tax = use_tax + self.gift_card_amount = gift_card_amount raise "use_tax is not yet supported. FlexCommerce::PaypalExpress::GenerateSummary should support it in the future" if use_tax end # @method call - # + # # @returns an object with subtotal, tax, handling, shipping and items keys def call { @@ -34,35 +37,35 @@ def call private # @method subtotal - # + # # @returns the sum of line items total. This doesnt include any promotions def subtotal items.sum {|i| i[:quantity] * (i[:amount])} end # @method total - # + # # @return amount after converting cart total from pence to pounds def total convert_amount(cart.total) end # @method tax - # + # # @returns the sum of total line items tax def tax items.sum {|i| i[:tax] * i[:quantity]} end # @method handling - # + # # @returns Payment handling charges, which is 0 def handling 0 end # @method shipping - # + # # @returns 0 if cart is eligible for free shipping # @returns cart.shipping_total, if cart is not eligibl for free shipping def shipping @@ -71,14 +74,14 @@ def shipping end # @mthod items - # - # @returns both line items and discounts + # + # @returns both line items and discounts and gift cards def items - normal_items + discount_items + normal_items + discount_items + gift_cards end # @method discounts - # + # # @returns [] if there are no discounts on cart # @returns Array containing about the total discount amount, if any applied. def discount_items @@ -95,8 +98,26 @@ def discount_items ] end + # @method gift_cards + # + # @returns [] if there are no gift cards on cart + # @returns Array containing total gift card amount, if any applied. + def gift_cards + return [] if gift_card_amount.nil? || gift_card_amount.zero? + [ + { + name: "Gift card", + number: "NA", + quantity: 1, + amount: convert_amount(BigDecimal(0) - gift_card_amount), + description: "Gift card", + tax: 0 + } + ] + end + # @method normal_items - # + # # @returns Object, the normal line items added to cart # @note these line items unit prices will be without any discounts def normal_items @@ -112,7 +133,7 @@ def normal_items end end - attr_accessor :cart, :use_tax + attr_accessor :cart, :use_tax, :gift_card_amount end end -end \ No newline at end of file +end diff --git a/lib/paypal_express/process/paypal_params.rb b/lib/paypal_express/process/paypal_params.rb index 5e7923d..3b3d617 100644 --- a/lib/paypal_express/process/paypal_params.rb +++ b/lib/paypal_express/process/paypal_params.rb @@ -9,9 +9,9 @@ class PaypalParams include ::FlexCommerce::PaypalExpress::Api DEFAULT_DESCRIPTION = "Shift Commerce Order".freeze - + # @initialize - # + # # @param {FlexCommerce::PaymentProviderSetup} payment_provider_setup # @param {FlexCommerce::Cart} cart # @param {Paypal Gateway} [gateway_class = ::ActiveMerchant::Billing::PaypalExpressGateway] @@ -23,8 +23,9 @@ class PaypalParams # @param {FlexCommerce::ShippingMethod} shipping_method_model = FlexCommerce::ShippingMethod # @param {boolean} [use_mobile_payments = false] # @param {String} [description] - # - def initialize(cart:,success_url:, cancel_url:, ip_address:, allow_shipping_change: true, callback_url:, shipping_method_model: FlexCommerce::ShippingMethod, use_mobile_payments: false, description:) + # @param {BigDecimal} [gift_card_amount] + # + def initialize(cart:,success_url:, cancel_url:, ip_address:, allow_shipping_change: true, callback_url:, shipping_method_model: FlexCommerce::ShippingMethod, use_mobile_payments: false, description:, gift_card_amount: nil) self.cart = cart self.allow_shipping_change = allow_shipping_change self.success_url = success_url @@ -34,6 +35,7 @@ def initialize(cart:,success_url:, cancel_url:, ip_address:, allow_shipping_chan self.shipping_method_model = shipping_method_model self.use_mobile_payments = use_mobile_payments self.description = description + self.gift_card_amount = gift_card_amount end def call @@ -44,7 +46,7 @@ def call .merge(shipping_options_params) end - attr_accessor :description, :cart, :success_url, :cancel_url, :ip_address, :allow_shipping_change, :callback_url, :shipping_method_model, :use_mobile_payments + attr_accessor :description, :cart, :success_url, :cancel_url, :ip_address, :allow_shipping_change, :callback_url, :shipping_method_model, :use_mobile_payments, :gift_card_amount private @@ -87,16 +89,16 @@ def paypal_items def ui_callback_params return {} unless allow_shipping_change && shipping_methods.count > 0 - { + { callback_url: callback_url, callback_timeout: 6, callback_version: 95, - max_amount: convert_amount((cart.total * 1.2) + shipping_methods.last.total + shipping_methods.last.tax) + max_amount: convert_amount((cart.total * 1.2) + shipping_methods.last.total + shipping_methods.last.tax) } end # @method shipping_methods - # + # # @returns shipping methods with promotions applied def shipping_methods @shipping_methods ||= ShippingMethodsForCart.new(cart: cart, shipping_methods: shipping_method_model.all).call.sort_by(&:total) @@ -115,9 +117,9 @@ def shipping_options_params end def summary - @summary ||= GenerateSummary.new(cart: cart).call + @summary ||= GenerateSummary.new(cart: cart, gift_card_amount: gift_card_amount).call end end end end -end \ No newline at end of file +end diff --git a/lib/paypal_express/process/response_parser.rb b/lib/paypal_express/process/response_parser.rb index c2129c1..338f96d 100644 --- a/lib/paypal_express/process/response_parser.rb +++ b/lib/paypal_express/process/response_parser.rb @@ -19,7 +19,8 @@ def call shipping_method_id: get_shipping_method_details, email: get_email_address, shipping_address_attributes: get_shipping_address_attributes, - billing_address_attributes: get_billing_address_attributes + billing_address_attributes: get_billing_address_attributes, + payment_details: response.params["PaymentDetails"] } end diff --git a/lib/paypal_express/setup.rb b/lib/paypal_express/setup.rb index 726e040..0340cb2 100644 --- a/lib/paypal_express/setup.rb +++ b/lib/paypal_express/setup.rb @@ -4,14 +4,14 @@ module FlexCommerce module PaypalExpress # @class Setup - # + # # This is the main class, which talks to ActiveMerchant gem to initiate a transaction using Paypal class Setup include ::FlexCommerce::PaypalExpress::Api - + # @initialize - # + # # @param {FlexCommerce::PaymentProviderSetup} payment_provider_setup # @param {FlexCommerce::Cart} cart # @param {Paypal Gateway} [gateway_class = ::ActiveMerchant::Billing::PaypalExpressGateway] @@ -23,12 +23,12 @@ class Setup # @param {FlexCommerce::ShippingMethod} shipping_method_model = FlexCommerce::ShippingMethod # @param {boolean} [use_mobile_payments = false] # @param {String} [description = nil] - # + # # @note: # For `::ActiveMerchant::Billing::PaypalExpressGateway` to work # rails-site should include active merchant gem. Ideally this gem should be included in the gemspec. # But as we are using custom gem, which is not published to ruby gems, there is no way of including it within this gem dependency - def initialize(cart:, gateway_class: ::ActiveMerchant::Billing::PaypalExpressGateway, success_url:, cancel_url:, ip_address:, allow_shipping_change: true, callback_url:, shipping_method_model: FlexCommerce::ShippingMethod, use_mobile_payments: false, description: nil) + def initialize(cart:, gateway_class: ::ActiveMerchant::Billing::PaypalExpressGateway, success_url:, cancel_url:, ip_address:, allow_shipping_change: true, callback_url:, shipping_method_model: FlexCommerce::ShippingMethod, use_mobile_payments: false, description: nil, gift_card_amount: BigDecimal(0)) self.gateway_class = gateway_class self.cart = cart self.allow_shipping_change = allow_shipping_change @@ -39,12 +39,13 @@ def initialize(cart:, gateway_class: ::ActiveMerchant::Billing::PaypalExpressGat self.shipping_method_model = shipping_method_model self.use_mobile_payments = use_mobile_payments self.description = description + self.gift_card_amount = gift_card_amount end def call validate_shipping_method - - response = gateway.setup_order(convert_amount(cart.total), paypal_params) + total_amount = cart.total - gift_card_amount + response = gateway.setup_order(convert_amount(total_amount), paypal_params) # If paypal setup went fine, redirect to the paypal page if response.success? PaypalSetup.new(setup_type: "redirect", redirect_url: gateway.redirect_url_for(response.token, mobile: use_mobile_payments)) @@ -59,7 +60,7 @@ def call private - attr_accessor :description, :cart, :gateway_class, :success_url, :cancel_url, :ip_address, :allow_shipping_change, :callback_url, :shipping_method_model, :use_mobile_payments + attr_accessor :description, :cart, :gateway_class, :success_url, :cancel_url, :ip_address, :allow_shipping_change, :callback_url, :shipping_method_model, :use_mobile_payments, :gift_card_amount def paypal_params Process::PaypalParams.new( @@ -71,12 +72,13 @@ def paypal_params callback_url: callback_url, shipping_method_model: shipping_method_model, use_mobile_payments: use_mobile_payments, - description: description + description: description, + gift_card_amount: gift_card_amount ).call end # @method shipping_methods - # + # # @returns shipping methods with promotions applied def shipping_methods @shipping_methods ||= ShippingMethodsForCart.new(cart: cart, shipping_methods: shipping_method_model.all).call.sort_by(&:total) diff --git a/lib/paypal_express/shipping_methods_for_cart.rb b/lib/paypal_express/shipping_methods_for_cart.rb index f5e4e76..5997348 100644 --- a/lib/paypal_express/shipping_methods_for_cart.rb +++ b/lib/paypal_express/shipping_methods_for_cart.rb @@ -26,7 +26,9 @@ def call free_shipping_method_ids.flatten! updated_shipping_methods = [] - shipping_methods.each do |shipping_method| + filtered_shipping_methods = shipping_methods.reject { |sm| sm.meta_attribute(:disabled) == 'true' } + + filtered_shipping_methods.each do |shipping_method| shipping_method_free = free_shipping_method_ids.include?(shipping_method.id) updated_shipping_methods << CartShippingMethod.new(shipping_method, shipping_method_free) end diff --git a/spec/factories/addresses.rb b/spec/factories/addresses.rb index dfd8114..8713d1b 100644 --- a/spec/factories/addresses.rb +++ b/spec/factories/addresses.rb @@ -11,8 +11,8 @@ state { Faker::Address.state } postcode { Faker::Address.postcode } country { Faker::Address.country } - preferred_billing false - preferred_shipping false + preferred_billing { false } + preferred_shipping { false } end factory :addresses_from_fixture, class: JsonStruct do @@ -27,4 +27,4 @@ send(key, value) end end -end \ No newline at end of file +end diff --git a/spec/factories/asset_files.rb b/spec/factories/asset_files.rb index 8cdff27..029d4b9 100644 --- a/spec/factories/asset_files.rb +++ b/spec/factories/asset_files.rb @@ -4,10 +4,10 @@ sequence(:name) { |n| "asset file name-#{n}" } asset_folder_id { Faker::Number.number(2) } sequence(:file_content_filename) { |n| "asset_file_name_#{n}.png" } - file_content_size 106 - file_content_content_type "image/png" + file_content_size { 106 } + file_content_content_type { "image/png" } image_width { Faker::Number.number(4) } image_height { Faker::Number.number(4) } reference { "#{Faker::Code.isbn}-#{Time.now.nsec}" } end -end \ No newline at end of file +end diff --git a/spec/factories/bundle.rb b/spec/factories/bundle.rb index bd8d7b1..5656680 100644 --- a/spec/factories/bundle.rb +++ b/spec/factories/bundle.rb @@ -8,6 +8,6 @@ end factory :bundle_list, parent: :json_api_resource_list do - type "bundle" + type { "bundle" } end end diff --git a/spec/factories/categories.rb b/spec/factories/categories.rb index 69555dd..8b74a07 100644 --- a/spec/factories/categories.rb +++ b/spec/factories/categories.rb @@ -3,7 +3,7 @@ factory :category, class: klass do title { Faker::Lorem.sentence } reference { rand(1000000000).to_s } - category_tree_id "reference:web" + category_tree_id { "reference:web" } end factory :categories_from_fixture, class: JsonStruct do obj = JsonStruct.new(JSON.parse(File.read("spec/fixtures/categories/multiple.json"))) @@ -17,4 +17,4 @@ send(key, value) end end -end \ No newline at end of file +end diff --git a/spec/factories/variants.rb b/spec/factories/variants.rb index 04fa9b3..92970be 100644 --- a/spec/factories/variants.rb +++ b/spec/factories/variants.rb @@ -5,6 +5,6 @@ description { Faker::Lorem.sentence } sku { Faker::Code.ean } reference { Faker::Lorem.words(3).join("-") } - stock_level 100 + stock_level { 100 } end end diff --git a/spec/factories/webhook.rb b/spec/factories/webhook.rb index aefa67f..be0e385 100644 --- a/spec/factories/webhook.rb +++ b/spec/factories/webhook.rb @@ -3,7 +3,7 @@ factory :webhook, class: klass do title { Faker::Lorem.words(3).join(" ") } event { "order_created" } - request_url "https://example.com/bla" - request_headers ({ "X-Token" => "test" }) + request_url { "https://example.com/bla" } + request_headers {{ "X-Token" => "test" }} end end diff --git a/spec/integration/oms/customer_order.rb b/spec/integration/oms/customer_order.rb new file mode 100644 index 0000000..84cbd7e --- /dev/null +++ b/spec/integration/oms/customer_order.rb @@ -0,0 +1,14 @@ +require "spec_helper" +require "flex_commerce_api" +require "uri" + + +RSpec.describe "OMS Order History" do + include_context "global context" + + let(:subject_class) { ::FlexCommerce::CustomerOrder } + + context "Fetching Order history via OMS" do + subject_class.fetch_orders(customer_reference: "12345") + end +end \ No newline at end of file diff --git a/spec/lib/paypal_express/auth_spec.rb b/spec/lib/paypal_express/auth_spec.rb index 500361e..f25943b 100644 --- a/spec/lib/paypal_express/auth_spec.rb +++ b/spec/lib/paypal_express/auth_spec.rb @@ -4,11 +4,11 @@ include ActiveSupport::NumberHelper include_context "context store" include_context "housekeeping" - + let(:token) { "fake-token" } let(:payer_id) { "fake-payer-id" } let(:cart) { build_stubbed(:cart, total: 100) } - let(:transaction) { + let(:transaction) { to_clean.transaction = FlexCommerce::PaymentTransaction.create( cart_id: cart.id, gateway_response: { @@ -28,7 +28,7 @@ cart.billing_address.freeze cart.freeze end - + subject { described_class.new(cart: cart, token: token, payer_id: payer_id, payment_transaction: transaction) } shared_context "mocked active merchant" do |expect_login: true, test_mode: true| @@ -85,7 +85,7 @@ context "happy path in production" do include_context "mocked active merchant", test_mode: false - + before(:each) do expect(active_merchant_gateway).to receive(:order).with(convert_amount(cart.total), token: token, payer_id: payer_id, currency: "GBP").and_return order_response expect(active_merchant_gateway).to receive(:authorize_transaction).with(transaction_id, convert_amount(cart.total), transaction_entity: "Order", payer_id: payer_id, currency: "GBP").and_return authorize_order_response @@ -99,7 +99,7 @@ context "with error scenarios" do include_context "mocked active merchant" - + it "should mark the transactions gateway_response as invalid when failure is recoverable in order stage" do order_response = instance_double "ActiveMerchant::Billing::PaypalExpressGateway", "order_response", params: {"error_codes" => "10410", "message" => "Invalid token", "ack" => "Failure", "Ack" => "Failure"}, success?: false expect(active_merchant_gateway).to receive(:order).with(convert_amount(cart.total), token: token, payer_id: payer_id, currency: "GBP").and_return order_response diff --git a/spec/lib/paypal_express/generate_summary_spec.rb b/spec/lib/paypal_express/generate_summary_spec.rb index 6f90985..3f1a21a 100644 --- a/spec/lib/paypal_express/generate_summary_spec.rb +++ b/spec/lib/paypal_express/generate_summary_spec.rb @@ -5,10 +5,11 @@ def convert_amount(amt) (amt * 100).to_i end context "without tax" do - subject { described_class.new(cart: cart) } shared_examples_for "a summary from a cart with tax ignored" do it "should have the correct subtotal" do - expect(subject.call).to include subtotal: convert_amount(line_items.sum(&:total)) + # gift card amount is deducted from subtotal if gift card used + subtotal = line_items.sum(&:total) - gift_card_amount + expect(subject.call).to include subtotal: convert_amount(subtotal) end it "should have zero tax" do expect(subject.call).to include tax: 0 @@ -20,6 +21,7 @@ def convert_amount(amt) expect(subject.call).to include shipping: convert_amount(shipping_total) end end + shared_examples_for "paypal items" do it "should have the correct items - amount and quantity" do expect(paypal_items).to match_array(line_items.map { |li| hash_including(amount: convert_amount(li.unit_price), quantity: li.unit_quantity) }) @@ -34,17 +36,34 @@ def convert_amount(amt) expect(paypal_items).to match_array(line_items.map { |li| hash_including(number: li.item.sku) }) end end + + shared_examples_for "non discounted line items" do + let(:gift_card_amount) { BigDecimal(0) } + subject { described_class.new(cart: cart, gift_card_amount: gift_card_amount) } + let(:paypal_items) { subject.call[:items] } + include_examples "paypal items" + end + shared_examples_for "discounted line items" do + let(:gift_card_amount) { BigDecimal(0) } + subject { described_class.new(cart: cart, gift_card_amount: gift_card_amount) } let(:paypal_items) { subject.call[:items][0...-1] } include_examples "paypal items" it "should have the last item as special discount item" do expect(subject.call).to include(items: array_including(hash_including(amount: convert_amount(BigDecimal(0) - cart.total_discount)))) end end - shared_examples_for "non discounted line items" do - let(:paypal_items) { subject.call[:items] } + + shared_examples_for "line items partially paid with gift cards" do + let(:gift_card_amount) { BigDecimal(10) } + subject { described_class.new(cart: cart, gift_card_amount: gift_card_amount) } + let(:paypal_items) { subject.call[:items][0...-1] } include_examples "paypal items" + it "should have the last item as gift card item" do + expect(subject.call).to include(items: array_including(hash_including(amount: convert_amount(BigDecimal(0) - gift_card_amount)))) + end end + context "with no shipping" do let(:shipping_total) { BigDecimal(0) } context "with no discounts" do @@ -56,6 +75,17 @@ def convert_amount(amt) include_examples "a summary from a cart with tax ignored" include_examples "non discounted line items" end + + context "with gift card" do + let(:cart) { double(:cart, free_shipping: false, line_items: line_items, shipping_total: shipping_total, total: line_items.sum(&:total) + shipping_total, total_discount: line_item_discount * line_items.length) } + let(:line_item_discount) { BigDecimal(0) } + let(:item) { 5.times.map { |n| double(:variant, sku: "sku_#{n}") } } + let(:line_items) { 5.times.map { |n| double(:line_item, unit_price: BigDecimal(1.67, 12), item: item[n], unit_quantity: 3, total: BigDecimal(5.01, 12), title: "Line item #{n}", tax: BigDecimal(0)) } } + + include_examples "a summary from a cart with tax ignored" + include_examples "line items partially paid with gift cards" + end + context "with line item discounts" do let(:cart) { double(:cart, free_shipping: false, line_items: line_items, shipping_total: shipping_total, total: line_items.sum(&:total) + shipping_total, total_discount: line_item_discount * line_items.length) } let(:line_item_discount) { BigDecimal(0.79, 12) } @@ -65,6 +95,7 @@ def convert_amount(amt) include_examples "discounted line items" end end + context "with shipping" do let(:shipping_total) { BigDecimal(3.99, 12) } context "with no discounts" do @@ -75,6 +106,16 @@ def convert_amount(amt) include_examples "a summary from a cart with tax ignored" include_examples "non discounted line items" end + + context "with gift card" do + let(:cart) { double(:cart, free_shipping: false, line_items: line_items, shipping_total: shipping_total, total: line_items.sum(&:total) + shipping_total, total_discount: line_item_discount * line_items.length) } + let(:line_item_discount) { BigDecimal(0) } + let(:item) { 5.times.map { |n| double(:variant, sku: "sku_#{n}") } } + let(:line_items) { 5.times.map { |n| double(:line_ttem, unit_price: BigDecimal(1.67, 12), item: item[n], unit_quantity: 3, total: BigDecimal(5.01, 12), title: "Line item #{n}", tax: BigDecimal(0)) } } + include_examples "a summary from a cart with tax ignored" + include_examples "line items partially paid with gift cards" + end + context "with line item discounts" do let(:cart) { double(:cart, free_shipping: false, line_items: line_items, shipping_total: shipping_total, total: line_items.sum(&:total) + shipping_total, total_discount: line_item_discount * line_items.length) } let(:line_item_discount) { BigDecimal(0.79, 12) }