Class: FriendlyShipping::Services::Ups::SerializeShipmentConfirmRequest

Inherits:
Object
  • Object
show all
Defined in:
lib/friendly_shipping/services/ups/serialize_shipment_confirm_request.rb

Class Method Summary collapse

Class Method Details

.call(shipment:, options:) ⇒ Object

Item options (only necessary for international shipping)



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/friendly_shipping/services/ups/serialize_shipment_confirm_request.rb', line 19

def call(
  shipment:,
  options:
)
  xml_builder = Nokogiri::XML::Builder.new do |xml|
    xml.ShipmentConfirmRequest do
      xml.Request do
        xml.RequestAction('ShipConfirm')
        # Required element controls level of address validation.
        xml.RequestOption(options.validate_address ? 'validate' : 'nonvalidate')
        xml.SubVersion('1707')
        # Optional element to identify transactions between client and server.
        if options.customer_context
          xml.TransactionReference do
            xml.CustomerContext(options.customer_context)
          end
        end
      end

      xml.Shipment do
        xml.Service do
          xml.Code(options.shipping_method.service_code)
        end

        xml.ShipTo do
          SerializeShipmentAddressSnippet.call(xml: xml, location: shipment.destination)
        end

        # Required element. The company whose account is responsible for the label(s).
        xml.Shipper do
          SerializeShipmentAddressSnippet.call(xml: xml, location: options.shipper || shipment.origin)

          xml.ShipperNumber(options.shipper_number)
        end

        if options.shipper || options.return_service_code
          origin = options.return_service_code ? shipment.destination : shipment.origin
          xml.ShipFrom do
            SerializeShipmentAddressSnippet.call(xml: xml, location: origin)
          end
        end

        if options.negotiated_rates
          xml.RateInformation do
            xml.NegotiatedRatesIndicator
          end
        end

        # shipment.options.fetch(:reference_numbers, {}).each do |reference_code, reference_value|
        #   xml.ReferenceNumber do
        #     xml.Code(reference_code)
        #     xml.Value(reference_value)
        #   end
        # end

        if options.billing_options.prepay
          xml.PaymentInformation do
            xml.Prepaid do
              build_billing_info_node(xml, options)
            end
          end
        else
          xml.ItemizedPaymentInformation do
            xml.ShipmentCharge do
              # Type '01' means 'Transportation'
              # This node specifies who will be billed for transportation.
              xml.Type('01')
              build_billing_info_node(xml, options)
            end
            if international?(shipment) && options.terms_of_shipment_code == 'DDP'
              # The shipper will cover duties and taxes
              # Otherwise UPS will charge the receiver
              xml.ShipmentCharge do
                xml.Type('02') # Type '02' means 'Duties and Taxes'
                build_billing_info_node(
                  xml,
                  options,
                  bill_to_consignee: true
                )
              end
            end
          end
        end

        if international?(shipment)
          unless options.return_service_code
            xml.SoldTo do
              sold_to_location = options.sold_to || shipment.destination
              SerializeShipmentAddressSnippet.call(xml: xml, location: sold_to_location)
            end
          end

          if shipment.origin.country.code == 'US' && ['CA', 'PR'].include?(shipment.destination.country.code)
            # Required for shipments from the US to Puerto Rico or Canada
            # We'll assume USD as the origin country is the United States here.
            xml.InvoiceLineTotal do
              total_value = shipment.packages.inject(Money.new(0, 'USD')) do |shipment_sum, package|
                shipment_sum + package.items.inject(Money.new(0, 'USD')) do |package_sum, item|
                  package_sum + (item.cost || Money.new(0, 'USD'))
                end
              end
              xml.MonetaryValue(total_value.to_f)
            end
          end

          contents_description = shipment.packages.flat_map do |package|
            package.items.map(&:description)
          end.compact.join(', ')

          unless contents_description.empty?
            xml.Description(contents_description)
          end
        end

        if options.return_service_code
          xml.ReturnService do
            xml.Code(options.return_service_code)
          end
        end

        xml.ShipmentServiceOptions do
          xml.SaturdayDelivery if options.saturday_delivery
          xml.UPScarbonneutralIndicator if options.carbon_neutral
          if options.delivery_confirmation_code
            xml.DeliveryConfirmation do
              xml.DCISType(options.delivery_confirmation_code)
            end
          end

          if international?(shipment)
            build_international_forms(xml, shipment, options)
          end
        end

        shipment.packages.each do |package|
          package_options = options.options_for_package(package)
          reference_numbers = allow_package_level_reference_numbers(shipment) ? package_options.reference_numbers : {}
          delivery_confirmation_code = package_level_delivery_confirmation?(shipment) ? package_options.delivery_confirmation_code : nil
          SerializePackageNode.call(
            xml: xml,
            package: package,
            reference_numbers: reference_numbers,
            delivery_confirmation_code: delivery_confirmation_code,
            shipper_release: package_options.shipper_release
          )
        end
      end

      xml.LabelSpecification do
        xml.LabelStockSize do
          xml.Height(options.label_size[0])
          xml.Width(options.label_size[1])
        end

        xml.LabelPrintMethod do
          xml.Code(options.label_format)
        end

        # API requires these only if returning a GIF formated label
        if options.label_format == 'GIF'
          xml.HTTPUserAgent('Mozilla/4.5')
          xml.LabelImageFormat(options.label_format) do
            xml.Code(options.label_format)
          end
        end
      end
    end
  end
  xml_builder.to_xml
end