From f435f1a52be10cd34ad801749fcab6c4a667f302 Mon Sep 17 00:00:00 2001 From: aenand Date: Mon, 6 May 2024 14:43:39 -0400 Subject: [PATCH 1/6] Cybersource Rest: Support L2/L3 data COMP-134 Adds support for L2 and L3 data to the Cybersource Rest gateway Test Summary Local: 5882 tests, 79430 assertions, 0 failures, 23 errors, 0 pendings, 0 omissions, 0 notifications 99.609% passed Unit: 36 tests, 189 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed Remote: --- .../billing/gateways/cyber_source_rest.rb | 22 ++++++++- .../gateways/remote_cyber_source_rest_test.rb | 45 +++++++++++++++++ test/unit/gateways/cyber_source_rest_test.rb | 49 +++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/lib/active_merchant/billing/gateways/cyber_source_rest.rb b/lib/active_merchant/billing/gateways/cyber_source_rest.rb index 0a5e65711c8..fd0e30c5232 100644 --- a/lib/active_merchant/billing/gateways/cyber_source_rest.rb +++ b/lib/active_merchant/billing/gateways/cyber_source_rest.rb @@ -106,6 +106,23 @@ def scrub(transcript) private + def add_level_2_data(post, options) + return unless options[:purchase_order_number] + + post[:orderInformation][:invoiceDetails] ||= {} + post[:orderInformation][:invoiceDetails][:purchaseOrderNumber] = options[:purchase_order_number] + end + + def add_level_3_data(post, options) + return unless options[:line_items] + + post[:orderInformation][:lineItems] = options[:line_items] + post[:processingInformation][:purchaseLevel] = '3' + post[:orderInformation][:shipping_details] = { shipFromPostalCode: options[:ships_from_postal_code] } + post[:orderInformation][:amountDetails] ||= {} + post[:orderInformation][:amountDetails][:discountAmount] = options[:discount_amount] + end + def add_three_ds(post, payment_method, options) return unless three_d_secure = options[:three_d_secure] @@ -149,6 +166,8 @@ def build_auth_request(amount, payment, options) add_partner_solution_id(post) add_stored_credentials(post, payment, options) add_three_ds(post, payment, options) + add_level_2_data(post, options) + add_level_3_data(post, options) end.compact end @@ -477,7 +496,8 @@ def add_sec_code(post, options) def add_invoice_number(post, options) return unless options[:invoice_number].present? - post[:orderInformation][:invoiceDetails] = { invoiceNumber: options[:invoice_number] } + post[:orderInformation][:invoiceDetails] ||= {} + post[:orderInformation][:invoiceDetails][:invoiceNumber] = options[:invoice_number] end def add_partner_solution_id(post) diff --git a/test/remote/gateways/remote_cyber_source_rest_test.rb b/test/remote/gateways/remote_cyber_source_rest_test.rb index a08307d376a..ce6107356cc 100644 --- a/test/remote/gateways/remote_cyber_source_rest_test.rb +++ b/test/remote/gateways/remote_cyber_source_rest_test.rb @@ -585,4 +585,49 @@ def test_successful_authorize_with_3ds2_mastercard auth = @gateway.authorize(@amount, @master_card, @options) assert_success auth end + + def test_successful_purchase_with_level_2_data + response = @gateway.purchase(@amount, @visa_card, @options.merge({ purchase_order_number: '13829012412' })) + assert_success response + assert response.test? + assert_equal 'AUTHORIZED', response.message + assert_nil response.params['_links']['capture'] + end + + def test_successful_purchase_with_level_2_and_3_data + options = { + purchase_order_number: '6789', + discount_amount: '150', + ships_from_postal_code: '90210', + line_items: [ + { + productName: 'Product Name', + kind: 'debit', + quantity: 10, + unitPrice: '9.5000', + totalAmount: '95.00', + taxAmount: '5.00', + discountAmount: '0.00', + productCode: '54321', + commodityCode: '98765' + }, + { + productName: 'Other Product Name', + kind: 'debit', + quantity: 1, + unitPrice: '2.5000', + totalAmount: '90.00', + taxAmount: '2.00', + discountAmount: '1.00', + productCode: '54322', + commodityCode: '98766' + } + ] + } + assert response = @gateway.purchase(@amount, @visa_card, @options.merge(options)) + assert_success response + assert response.test? + assert_equal 'AUTHORIZED', response.message + assert_nil response.params['_links']['capture'] + end end diff --git a/test/unit/gateways/cyber_source_rest_test.rb b/test/unit/gateways/cyber_source_rest_test.rb index 8105b78c8ec..6548b7b8722 100644 --- a/test/unit/gateways/cyber_source_rest_test.rb +++ b/test/unit/gateways/cyber_source_rest_test.rb @@ -491,6 +491,55 @@ def test_adds_application_id_as_partner_solution_id CyberSourceRestGateway.application_id = nil end + def test_purchase_with_level_2_data + stub_comms do + @gateway.authorize(100, @credit_card, @options.merge({ purchase_order_number: '13829012412' })) + end.check_request do |_endpoint, data, _headers| + request = JSON.parse(data) + assert_equal '13829012412', request['orderInformation']['invoiceDetails']['purchaseOrderNumber'] + end.respond_with(successful_purchase_response) + end + + def test_purchase_with_level_3_data + options = { + purchase_order_number: '6789', + discount_amount: '150', + ships_from_postal_code: '90210', + line_items: [ + { + productName: 'Product Name', + kind: 'debit', + quantity: 10, + unitPrice: '9.5000', + totalAmount: '95.00', + taxAmount: '5.00', + discountAmount: '0.00', + productCode: '54321', + commodityCode: '98765' + }, + { + productName: 'Other Product Name', + kind: 'debit', + quantity: 1, + unitPrice: '2.5000', + totalAmount: '90.00', + taxAmount: '2.00', + discountAmount: '1.00', + productCode: '54322', + commodityCode: '98766' + } + ] + } + stub_comms do + @gateway.authorize(100, @credit_card, @options.merge(options)) + end.check_request do |_endpoint, data, _headers| + request = JSON.parse(data) + assert_equal '3', request['processingInformation']['purchaseLevel'] + assert_equal '150', request['orderInformation']['amountDetails']['discountAmount'] + assert_equal '90210', request['orderInformation']['shipping_details']['shipFromPostalCode'] + end.respond_with(successful_purchase_response) + end + private def parse_signature(signature) From 50f736454432282bc22978df7722b5ae61bb747e Mon Sep 17 00:00:00 2001 From: aenand Date: Tue, 7 May 2024 13:16:06 -0400 Subject: [PATCH 2/6] Worldpay: Refactor L2/L3 data COMP-134 Refactor L2/L3 data for Worldpay to be more in line with how active merchant gateways expect this data. It also lowers the burden for what merchants must provide to use L2/L3 data Test Summary Local: 5883 tests, 79441 assertions, 0 failures, 23 errors, 0 pendings, 0 omissions, 0 notifications 99.609% passed Unit: 117 tests, 668 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed Remote: 103 tests, 444 assertions, 2 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 98.0583% passed --- .../billing/gateways/worldpay.rb | 71 ++++++------ test/remote/gateways/remote_worldpay_test.rb | 80 ++++--------- test/unit/gateways/worldpay_test.rb | 107 ++++++++---------- 3 files changed, 105 insertions(+), 153 deletions(-) diff --git a/lib/active_merchant/billing/gateways/worldpay.rb b/lib/active_merchant/billing/gateways/worldpay.rb index 8405d805250..e6aaaf3206d 100644 --- a/lib/active_merchant/billing/gateways/worldpay.rb +++ b/lib/active_merchant/billing/gateways/worldpay.rb @@ -260,9 +260,8 @@ def add_level_two_and_three_data(xml, amount, data) xml.invoiceReferenceNumber data[:invoice_reference_number] if data.include?(:invoice_reference_number) xml.customerReference data[:customer_reference] if data.include?(:customer_reference) xml.cardAcceptorTaxId data[:card_acceptor_tax_id] if data.include?(:card_acceptor_tax_id) - { - sales_tax: 'salesTax', + tax_amount: 'salesTax', discount_amount: 'discountAmount', shipping_amount: 'shippingAmount', duty_amount: 'dutyAmount' @@ -270,53 +269,51 @@ def add_level_two_and_three_data(xml, amount, data) next unless data.include?(key) xml.tag! tag do - data_amount = data[key].symbolize_keys - add_amount(xml, data_amount[:amount].to_i, data_amount) + add_amount(xml, data[key].to_i, data) end end - xml.discountName data[:discount_name] if data.include?(:discount_name) - xml.discountCode data[:discount_code] if data.include?(:discount_code) + # xml.discountName data[:discount_name] if data.include?(:discount_name) + # xml.discountCode data[:discount_code] if data.include?(:discount_code) - add_date_element(xml, 'shippingDate', data[:shipping_date]) if data.include?(:shipping_date) + # add_date_element(xml, 'shippingDate', data[:shipping_date]) if data.include?(:shipping_date) - if data.include?(:shipping_courier) - xml.shippingCourier( - data[:shipping_courier][:priority], - data[:shipping_courier][:tracking_number], - data[:shipping_courier][:name] - ) - end + # if data.include?(:shipping_courier) + # xml.shippingCourier( + # data[:shipping_courier][:priority], + # data[:shipping_courier][:tracking_number], + # data[:shipping_courier][:name] + # ) + # end add_optional_data_level_two_and_three(xml, data) - if data.include?(:item) && data[:item].kind_of?(Array) - data[:item].each { |item| add_items_into_level_three_data(xml, item.symbolize_keys) } - elsif data.include?(:item) - add_items_into_level_three_data(xml, data[:item].symbolize_keys) - end + data[:item].each { |item| add_items_into_level_three_data(xml, item.symbolize_keys, data) } if data.include?(:item) end - def add_items_into_level_three_data(xml, item) + def add_items_into_level_three_data(xml, item, data) xml.item do xml.description item[:description] if item[:description] xml.productCode item[:product_code] if item[:product_code] xml.commodityCode item[:commodity_code] if item[:commodity_code] xml.quantity item[:quantity] if item[:quantity] - - { - unit_cost: 'unitCost', - item_total: 'itemTotal', - item_total_with_tax: 'itemTotalWithTax', - item_discount_amount: 'itemDiscountAmount', - tax_amount: 'taxAmount' - }.each do |key, tag| - next unless item.include?(key) - - xml.tag! tag do - data_amount = item[key].symbolize_keys - add_amount(xml, data_amount[:amount].to_i, data_amount) - end + xml.unitCost do + add_amount(xml, item[:unit_cost], data) + end + xml.unitOfMeasure item[:unit_of_measure] || 'each' + xml.itemTotal do + sub_total_amount = item[:quantity].to_i * (item[:unit_cost].to_i - item[:discount_amount].to_i) + add_amount(xml, sub_total_amount, data) + end + xml.itemTotalWithTax do + total_amount = item[:quantity].to_i * (item[:unit_cost].to_i - item[:discount_amount].to_i + item[:tax_amount].to_i) + add_amount(xml, total_amount, data) + end + xml.itemDiscountAmount do + add_amount(xml, item[:discount_amount], data) + end + xml.taxAmount do + add_amount(xml, item[:tax_amount], data) end end end @@ -326,7 +323,7 @@ def add_optional_data_level_two_and_three(xml, data) xml.destinationPostalCode data[:destination_postal_code] if data.include?(:destination_postal_code) xml.destinationCountryCode data[:destination_country_code] if data.include?(:destination_country_code) add_date_element(xml, 'orderDate', data[:order_date].symbolize_keys) if data.include?(:order_date) - xml.taxExempt data[:tax_exempt] if data.include?(:tax_exempt) + xml.taxExempt data[:tax_amount].to_i > 0 ? 'false' : 'true' end def order_tag_attributes(options) @@ -562,10 +559,10 @@ def add_date_element(xml, name, date) end def add_amount(xml, money, options) - currency = options[:currency] || currency(money) + currency = options[:currency] || currency(money.to_i) amount_hash = { - :value => localized_amount(money, currency), + :value => localized_amount(money.to_i, currency), 'currencyCode' => currency, 'exponent' => currency_exponent(currency) } diff --git a/test/remote/gateways/remote_worldpay_test.rb b/test/remote/gateways/remote_worldpay_test.rb index adc9f4551d4..b0213fbc139 100644 --- a/test/remote/gateways/remote_worldpay_test.rb +++ b/test/remote/gateways/remote_worldpay_test.rb @@ -59,11 +59,8 @@ def setup invoice_reference_number: 'INV12233565', customer_reference: 'CUST00000101', card_acceptor_tax_id: 'VAT1999292', - sales_tax: { - amount: '20', - exponent: '2', - currency: 'USD' - } + tax_amount: '20', + ship_from_postal_code: '43245' } } @@ -71,58 +68,30 @@ def setup level_3_data: { customer_reference: 'CUST00000102', card_acceptor_tax_id: 'VAT1999285', - sales_tax: { - amount: '20', - exponent: '2', - currency: 'USD' - }, - discount_amount: { - amount: '1', - exponent: '2', - currency: 'USD' - }, - shipping_amount: { - amount: '50', - exponent: '2', - currency: 'USD' - }, - duty_amount: { - amount: '20', - exponent: '2', - currency: 'USD' - }, - item: { + tax_amount: '20', + discount_amount: '1', + shipping_amount: '50', + duty_amount: '20', + item: [{ description: 'Laptop 14', product_code: 'LP00125', commodity_code: 'COM00125', quantity: '2', - unit_cost: { - amount: '1500', - exponent: '2', - currency: 'USD' - }, + unit_cost: '1500', unit_of_measure: 'each', - item_total: { - amount: '3000', - exponent: '2', - currency: 'USD' - }, - item_total_with_tax: { - amount: '3500', - exponent: '2', - currency: 'USD' - }, - item_discount_amount: { - amount: '200', - exponent: '2', - currency: 'USD' - }, - tax_amount: { - amount: '500', - exponent: '2', - currency: 'USD' - } - } + item_discount_amount: '200', + tax_amount: '500' + }, + { + description: 'Laptop 15', + product_code: 'LP00125', + commodity_code: 'COM00125', + quantity: '2', + unit_cost: '1500', + unit_of_measure: 'each', + item_discount_amount: '200', + tax_amount: '500' + }] } } @@ -705,7 +674,7 @@ def test_successful_purchase_with_level_two_fields end def test_successful_purchase_with_level_two_fields_and_sales_tax_zero - @level_two_data[:level_2_data][:sales_tax][:amount] = 0 + @level_two_data[:level_2_data][:tax_amount] = 0 assert response = @gateway.purchase(@amount, @credit_card, @options.merge(@level_two_data)) assert_success response assert_equal true, response.params['ok'] @@ -720,12 +689,13 @@ def test_successful_purchase_with_level_three_fields end def test_unsuccessful_purchase_level_three_data_without_item_mastercard - @level_three_data[:level_3_data][:item] = {} + @level_three_data[:level_3_data][:item] = [{ + }] @credit_card.brand = 'master' assert response = @gateway.purchase(@amount, @credit_card, @options.merge(@level_three_data)) assert_failure response assert_equal response.error_code, '2' - assert_equal response.params['error'].gsub(/\"+/, ''), 'The content of element type item is incomplete, it must match (description,productCode?,commodityCode?,quantity?,unitCost?,unitOfMeasure?,itemTotal?,itemTotalWithTax?,itemDiscountAmount?,taxAmount?,categories?,pageURL?,imageURL?).' + assert_equal response.params['error'].gsub(/\"+/, ''), 'The content of element type item must match (description,productCode?,commodityCode?,quantity?,unitCost?,unitOfMeasure?,itemTotal?,itemTotalWithTax?,itemDiscountAmount?,taxAmount?,categories?,pageURL?,imageURL?).' end def test_successful_purchase_with_level_two_and_three_fields diff --git a/test/unit/gateways/worldpay_test.rb b/test/unit/gateways/worldpay_test.rb index e35ef845cfd..b7406d041e8 100644 --- a/test/unit/gateways/worldpay_test.rb +++ b/test/unit/gateways/worldpay_test.rb @@ -89,11 +89,7 @@ def setup invoice_reference_number: 'INV12233565', customer_reference: 'CUST00000101', card_acceptor_tax_id: 'VAT1999292', - sales_tax: { - amount: '20', - exponent: '2', - currency: 'USD' - }, + tax_amount: '20', ship_from_postal_code: '43245', destination_postal_code: '54545', destination_country_code: 'CO', @@ -101,8 +97,7 @@ def setup day_of_month: Date.today.day, month: Date.today.month, year: Date.today.year - }, - tax_exempt: 'false' + } } } @@ -110,58 +105,30 @@ def setup level_3_data: { customer_reference: 'CUST00000102', card_acceptor_tax_id: 'VAT1999285', - sales_tax: { - amount: '20', - exponent: '2', - currency: 'USD' - }, - discount_amount: { - amount: '1', - exponent: '2', - currency: 'USD' - }, - shipping_amount: { - amount: '50', - exponent: '2', - currency: 'USD' - }, - duty_amount: { - amount: '20', - exponent: '2', - currency: 'USD' - }, - item: { + tax_amount: '20', + discount_amount: '1', + shipping_amount: '50', + duty_amount: '20', + item: [{ description: 'Laptop 14', product_code: 'LP00125', commodity_code: 'COM00125', quantity: '2', - unit_cost: { - amount: '1500', - exponent: '2', - currency: 'USD' - }, + unit_cost: '1500', unit_of_measure: 'each', - item_total: { - amount: '3000', - exponent: '2', - currency: 'USD' - }, - item_total_with_tax: { - amount: '3500', - exponent: '2', - currency: 'USD' - }, - item_discount_amount: { - amount: '200', - exponent: '2', - currency: 'USD' - }, - tax_amount: { - amount: '500', - exponent: '2', - currency: 'USD' - } - } + item_discount_amount: '200', + tax_amount: '500' + }, + { + description: 'Laptop 15', + product_code: 'LP00120', + commodity_code: 'COM00125', + quantity: '2', + unit_cost: '1000', + unit_of_measure: 'each', + item_discount_amount: '200', + tax_amount: '500' + }] } } end @@ -442,12 +409,30 @@ def test_transaction_with_level_two_data assert_match %r(INV12233565), data assert_match %r(CUST00000101), data assert_match %r(VAT1999292), data - assert_match %r(), data.gsub(/\s+/, '') + assert_match %r(), data.gsub(/\s+/, '') assert_match %r(43245), data assert_match %r(54545), data assert_match %r(CO), data assert_match %r(false), data - assert_match %r(), data.gsub(/\s+/, '') + assert_match %r(), data.gsub(/\s+/, '') + end.respond_with(successful_authorize_response) + assert_success response + end + + def test_transaction_with_level_two_data_without_tax + @level_two_data[:level_2_data][:tax_amount] = 0 + options = @options.merge(@level_two_data) + response = stub_comms do + @gateway.authorize(@amount, @credit_card, options) + end.check_request do |_endpoint, data, _headers| + assert_match %r(INV12233565), data + assert_match %r(CUST00000101), data + assert_match %r(VAT1999292), data + assert_match %r(), data.gsub(/\s+/, '') + assert_match %r(43245), data + assert_match %r(54545), data + assert_match %r(CO), data + assert_match %r(true), data assert_match %r(), data.gsub(/\s+/, '') end.respond_with(successful_authorize_response) assert_success response @@ -460,11 +445,11 @@ def test_transaction_with_level_three_data end.check_request do |_endpoint, data, _headers| assert_match %r(CUST00000102), data assert_match %r(VAT1999285), data - assert_match %r(), data.gsub(/\s+/, '') - assert_match %r(), data.gsub(/\s+/, '') - assert_match %r(), data.gsub(/\s+/, '') - assert_match %r(), data.gsub(/\s+/, '') - assert_match %r(Laptop14LP00125COM001252), data.gsub(/\s+/, '') + assert_match %r(), data.gsub(/\s+/, '') + assert_match %r(), data.gsub(/\s+/, '') + assert_match %r(), data.gsub(/\s+/, '') + assert_match %r(), data.gsub(/\s+/, '') + assert_match %r(Laptop14LP00125COM001252eachLaptop15LP00120COM001252each), data.gsub(/\s+/, '') end.respond_with(successful_authorize_response) assert_success response end From a3ba75cc65dc0496cf6789a764eaf8a16afbe2dd Mon Sep 17 00:00:00 2001 From: aenand Date: Thu, 9 May 2024 16:48:27 -0400 Subject: [PATCH 3/6] change total amount to not be summed --- .../billing/gateways/worldpay.rb | 3 +-- test/remote/gateways/remote_worldpay_test.rb | 18 ++++++++++-------- test/unit/gateways/worldpay_test.rb | 6 ++++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/active_merchant/billing/gateways/worldpay.rb b/lib/active_merchant/billing/gateways/worldpay.rb index e6aaaf3206d..bc3fb252877 100644 --- a/lib/active_merchant/billing/gateways/worldpay.rb +++ b/lib/active_merchant/billing/gateways/worldpay.rb @@ -306,8 +306,7 @@ def add_items_into_level_three_data(xml, item, data) add_amount(xml, sub_total_amount, data) end xml.itemTotalWithTax do - total_amount = item[:quantity].to_i * (item[:unit_cost].to_i - item[:discount_amount].to_i + item[:tax_amount].to_i) - add_amount(xml, total_amount, data) + add_amount(xml, item[:total_amount], data) end xml.itemDiscountAmount do add_amount(xml, item[:discount_amount], data) diff --git a/test/remote/gateways/remote_worldpay_test.rb b/test/remote/gateways/remote_worldpay_test.rb index b0213fbc139..63e29d6a127 100644 --- a/test/remote/gateways/remote_worldpay_test.rb +++ b/test/remote/gateways/remote_worldpay_test.rb @@ -80,17 +80,19 @@ def setup unit_cost: '1500', unit_of_measure: 'each', item_discount_amount: '200', - tax_amount: '500' + tax_amount: '500', + total_amount: '3300' }, { description: 'Laptop 15', - product_code: 'LP00125', - commodity_code: 'COM00125', - quantity: '2', - unit_cost: '1500', - unit_of_measure: 'each', - item_discount_amount: '200', - tax_amount: '500' + product_code: 'LP00125', + commodity_code: 'COM00125', + quantity: '2', + unit_cost: '1500', + unit_of_measure: 'each', + item_discount_amount: '200', + tax_amount: '500', + total_amount: '3300' }] } } diff --git a/test/unit/gateways/worldpay_test.rb b/test/unit/gateways/worldpay_test.rb index b7406d041e8..37d4b381f4f 100644 --- a/test/unit/gateways/worldpay_test.rb +++ b/test/unit/gateways/worldpay_test.rb @@ -117,7 +117,8 @@ def setup unit_cost: '1500', unit_of_measure: 'each', item_discount_amount: '200', - tax_amount: '500' + tax_amount: '500', + total_amount: '4000' }, { description: 'Laptop 15', @@ -127,7 +128,8 @@ def setup unit_cost: '1000', unit_of_measure: 'each', item_discount_amount: '200', - tax_amount: '500' + tax_amount: '500', + total_amount: '3000' }] } } From 3368ea62aaa83daef90ec9e7c7ff8b2275ce337d Mon Sep 17 00:00:00 2001 From: aenand Date: Mon, 13 May 2024 14:41:10 -0400 Subject: [PATCH 4/6] remove commented out code --- lib/active_merchant/billing/gateways/worldpay.rb | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/lib/active_merchant/billing/gateways/worldpay.rb b/lib/active_merchant/billing/gateways/worldpay.rb index bc3fb252877..f2c022440b7 100644 --- a/lib/active_merchant/billing/gateways/worldpay.rb +++ b/lib/active_merchant/billing/gateways/worldpay.rb @@ -273,19 +273,6 @@ def add_level_two_and_three_data(xml, amount, data) end end - # xml.discountName data[:discount_name] if data.include?(:discount_name) - # xml.discountCode data[:discount_code] if data.include?(:discount_code) - - # add_date_element(xml, 'shippingDate', data[:shipping_date]) if data.include?(:shipping_date) - - # if data.include?(:shipping_courier) - # xml.shippingCourier( - # data[:shipping_courier][:priority], - # data[:shipping_courier][:tracking_number], - # data[:shipping_courier][:name] - # ) - # end - add_optional_data_level_two_and_three(xml, data) data[:item].each { |item| add_items_into_level_three_data(xml, item.symbolize_keys, data) } if data.include?(:item) From c6fd4609cbb0ef55e9bb0d03d3cde17ba99d734d Mon Sep 17 00:00:00 2001 From: aenand Date: Mon, 13 May 2024 15:25:24 -0400 Subject: [PATCH 5/6] rename to line_items --- .../billing/gateways/worldpay.rb | 4 +-- test/remote/gateways/remote_worldpay_test.rb | 30 +++++++++---------- test/unit/gateways/worldpay_test.rb | 26 ++++++++-------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/lib/active_merchant/billing/gateways/worldpay.rb b/lib/active_merchant/billing/gateways/worldpay.rb index f2c022440b7..5793c9f7891 100644 --- a/lib/active_merchant/billing/gateways/worldpay.rb +++ b/lib/active_merchant/billing/gateways/worldpay.rb @@ -275,10 +275,10 @@ def add_level_two_and_three_data(xml, amount, data) add_optional_data_level_two_and_three(xml, data) - data[:item].each { |item| add_items_into_level_three_data(xml, item.symbolize_keys, data) } if data.include?(:item) + data[:line_items].each { |item| add_line_items_into_level_three_data(xml, item.symbolize_keys, data) } if data.include?(:line_items) end - def add_items_into_level_three_data(xml, item, data) + def add_line_items_into_level_three_data(xml, item, data) xml.item do xml.description item[:description] if item[:description] xml.productCode item[:product_code] if item[:product_code] diff --git a/test/remote/gateways/remote_worldpay_test.rb b/test/remote/gateways/remote_worldpay_test.rb index 63e29d6a127..07540d478e7 100644 --- a/test/remote/gateways/remote_worldpay_test.rb +++ b/test/remote/gateways/remote_worldpay_test.rb @@ -72,28 +72,28 @@ def setup discount_amount: '1', shipping_amount: '50', duty_amount: '20', - item: [{ + line_items: [{ description: 'Laptop 14', product_code: 'LP00125', commodity_code: 'COM00125', quantity: '2', unit_cost: '1500', unit_of_measure: 'each', - item_discount_amount: '200', + discount_amount: '200', tax_amount: '500', total_amount: '3300' }, - { - description: 'Laptop 15', - product_code: 'LP00125', - commodity_code: 'COM00125', - quantity: '2', - unit_cost: '1500', - unit_of_measure: 'each', - item_discount_amount: '200', - tax_amount: '500', - total_amount: '3300' - }] + { + description: 'Laptop 15', + product_code: 'LP00125', + commodity_code: 'COM00125', + quantity: '2', + unit_cost: '1500', + unit_of_measure: 'each', + discount_amount: '200', + tax_amount: '500', + total_amount: '3300' + }] } } @@ -691,13 +691,13 @@ def test_successful_purchase_with_level_three_fields end def test_unsuccessful_purchase_level_three_data_without_item_mastercard - @level_three_data[:level_3_data][:item] = [{ + @level_three_data[:level_3_data][:line_items] = [{ }] @credit_card.brand = 'master' assert response = @gateway.purchase(@amount, @credit_card, @options.merge(@level_three_data)) assert_failure response assert_equal response.error_code, '2' - assert_equal response.params['error'].gsub(/\"+/, ''), 'The content of element type item must match (description,productCode?,commodityCode?,quantity?,unitCost?,unitOfMeasure?,itemTotal?,itemTotalWithTax?,itemDiscountAmount?,taxAmount?,categories?,pageURL?,imageURL?).' + assert_equal response.params['error'].gsub(/\"+/, ''), 'The content of element type item must match (description,productCode?,commodityCode?,quantity?,unitCost?,unitOfMeasure?,itemTotal?,itemTotalWithTax?,itemDiscountAmount?,itemTaxRate?,lineDiscountIndicator?,itemLocalTaxRate?,itemLocalTaxAmount?,taxAmount?,categories?,pageURL?,imageURL?).' end def test_successful_purchase_with_level_two_and_three_fields diff --git a/test/unit/gateways/worldpay_test.rb b/test/unit/gateways/worldpay_test.rb index 37d4b381f4f..8e7e7d325d6 100644 --- a/test/unit/gateways/worldpay_test.rb +++ b/test/unit/gateways/worldpay_test.rb @@ -109,7 +109,7 @@ def setup discount_amount: '1', shipping_amount: '50', duty_amount: '20', - item: [{ + line_items: [{ description: 'Laptop 14', product_code: 'LP00125', commodity_code: 'COM00125', @@ -117,20 +117,22 @@ def setup unit_cost: '1500', unit_of_measure: 'each', item_discount_amount: '200', + discount_amount: '0', tax_amount: '500', total_amount: '4000' }, - { - description: 'Laptop 15', - product_code: 'LP00120', - commodity_code: 'COM00125', - quantity: '2', - unit_cost: '1000', - unit_of_measure: 'each', - item_discount_amount: '200', - tax_amount: '500', - total_amount: '3000' - }] + { + description: 'Laptop 15', + product_code: 'LP00120', + commodity_code: 'COM00125', + quantity: '2', + unit_cost: '1000', + unit_of_measure: 'each', + item_discount_amount: '200', + tax_amount: '500', + discount_amount: '0', + total_amount: '3000' + }] } } end From 2c42cbabcd29456c47d2ebcffa6ddb69e868000a Mon Sep 17 00:00:00 2001 From: aenand Date: Wed, 29 May 2024 14:57:24 -0400 Subject: [PATCH 6/6] changelog --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 32c4e68ea39..aab6e7ce323 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -174,6 +174,8 @@ * Worldpay: Add support for deafult ECI value [aenand] #5126 * DLocal: Update stored credentials [sinourain] #5112 * NMI: Add NTID override [yunnydang] #5134 +* Cybersource Rest: Support L2/L3 data [aenand] #5117 +* Worldpay: Support L2/L3 data [aenand] #5117 == Version 1.135.0 (August 24, 2023) * PaymentExpress: Correct endpoints [steveh] #4827