cargowise-ts 1.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +64 -0
- data/COPYING +340 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +107 -0
- data/TODO +2 -0
- data/lib/cargowise/abstract_result.rb +89 -0
- data/lib/cargowise/client.rb +113 -0
- data/lib/cargowise/consol.rb +29 -0
- data/lib/cargowise/document.rb +23 -0
- data/lib/cargowise/invoice.rb +30 -0
- data/lib/cargowise/order.rb +64 -0
- data/lib/cargowise/order_search.rb +67 -0
- data/lib/cargowise/order_wsdl.xml +2047 -0
- data/lib/cargowise/packing.rb +25 -0
- data/lib/cargowise/shipment.rb +158 -0
- data/lib/cargowise/shipment_search.rb +100 -0
- data/lib/cargowise/shipment_wsdl.xml +1446 -0
- data/lib/cargowise.rb +20 -0
- metadata +148 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'cargowise/abstract_result'
|
4
|
+
|
5
|
+
module Cargowise
|
6
|
+
|
7
|
+
# Extra packing detail associated with a Shipment. Not built
|
8
|
+
# directly, but available via the packings attribute
|
9
|
+
# of the Shipment model.
|
10
|
+
#
|
11
|
+
class Packing < AbstractResult
|
12
|
+
|
13
|
+
attr_reader :pack_type, :line_price, :weight, :volume, :description
|
14
|
+
|
15
|
+
def initialize(node)
|
16
|
+
@node = node
|
17
|
+
|
18
|
+
@pack_type = text_value("./PackType")
|
19
|
+
@line_price = decimal_value("./LinePrice")
|
20
|
+
@weight = kg_value("./Weight")
|
21
|
+
@volume = cubic_value("./Volume")
|
22
|
+
@description = text_value("./Description")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'cargowise/abstract_result'
|
4
|
+
require 'cargowise/packing'
|
5
|
+
require 'cargowise/consol'
|
6
|
+
require 'cargowise/document'
|
7
|
+
require 'cargowise/invoice'
|
8
|
+
|
9
|
+
module Cargowise
|
10
|
+
|
11
|
+
# A shipment that is currently on its way to you. Could take on a
|
12
|
+
# variety of forms - carton, palet, truck? Could be travelling via
|
13
|
+
# air, sea, road, rail, donkey?
|
14
|
+
#
|
15
|
+
# Typcially you will lookup the status of a shipment you're aware of
|
16
|
+
# using the shipment number:
|
17
|
+
#
|
18
|
+
# Shipment.find_by_shipment_number(...)
|
19
|
+
#
|
20
|
+
# If you want all recent shipments (delivered and undelivered) to
|
21
|
+
# ensure you know what's coming:
|
22
|
+
#
|
23
|
+
# Shipment.find_with_recent_activity(...)
|
24
|
+
#
|
25
|
+
# All shipment objects are read-only, see the object attributes to see
|
26
|
+
# what information is available.
|
27
|
+
#
|
28
|
+
class Shipment < AbstractResult
|
29
|
+
|
30
|
+
attr_reader :number, :housebill, :goods_description, :service_level
|
31
|
+
attr_reader :client_reference
|
32
|
+
attr_reader :origin, :destination, :etd, :eta, :delivered_date
|
33
|
+
attr_reader :kg, :cubic_meters
|
34
|
+
|
35
|
+
attr_reader :shipper_name
|
36
|
+
|
37
|
+
attr_reader :consignee_name
|
38
|
+
|
39
|
+
attr_reader :consols, :packings, :documents, :invoices
|
40
|
+
|
41
|
+
def initialize(node)
|
42
|
+
@node = node
|
43
|
+
|
44
|
+
@number = text_value("./Number")
|
45
|
+
@housebill = text_value("./HouseBill")
|
46
|
+
@goods_description = text_value("./GoodsDescription")
|
47
|
+
@service_level = text_value("./ServiceLevel")
|
48
|
+
@client_reference = text_value("./ClientReference")
|
49
|
+
@origin = text_value("./Origin")
|
50
|
+
@destination = text_value("./Destination")
|
51
|
+
@etd = time_value("./ETD")
|
52
|
+
@eta = time_value("./ETA")
|
53
|
+
@delivered_date = time_value("./DeliveredDate")
|
54
|
+
@kg = kg_value("./Weight")
|
55
|
+
@cubic_meters = cubic_value("./Size")
|
56
|
+
|
57
|
+
@shipper_name = text_value("./Shipper/OrganisationDetails/Name")
|
58
|
+
|
59
|
+
@consignee_name = text_value("./Consignee/OrganisationDetails/Name")
|
60
|
+
|
61
|
+
@consols = node_array("./Consols/Consol").map { |node|
|
62
|
+
Consol.new(node)
|
63
|
+
}
|
64
|
+
|
65
|
+
@packings = node_array("./Packings/Packing").map { |node|
|
66
|
+
Packing.new(node)
|
67
|
+
}
|
68
|
+
|
69
|
+
@documents = node_array("./DocumentLinks/DocumentLink").map { |node|
|
70
|
+
Document.new(node)
|
71
|
+
}.sort_by { |doc|
|
72
|
+
doc.date
|
73
|
+
}
|
74
|
+
|
75
|
+
@invoices = node_array("./RelatedInvoiceLinks/InvoiceLink").map { |node|
|
76
|
+
Invoice.new(node)
|
77
|
+
}.sort_by { |inv|
|
78
|
+
inv.due_date
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
# returns the raw XML string this shipment is based on
|
83
|
+
#
|
84
|
+
def to_xml
|
85
|
+
@node.to_xml
|
86
|
+
end
|
87
|
+
|
88
|
+
# returns a space separated string with all transport modes being used
|
89
|
+
# to move this shipment
|
90
|
+
#
|
91
|
+
def transport_mode
|
92
|
+
@consols.map { |con| con.transport_mode }.uniq.sort.join(" ")
|
93
|
+
end
|
94
|
+
|
95
|
+
# lookup full Cargowise::Order objects for each order on this shipment.
|
96
|
+
#
|
97
|
+
# client is a Cargowise::Client instance to look for the related shipments on
|
98
|
+
#
|
99
|
+
def orders(client)
|
100
|
+
@orders ||= client.orders.by_shipment_number(self.number)
|
101
|
+
end
|
102
|
+
|
103
|
+
# lookup related Cargowise::Shipment objects. These are usually "child" shipments
|
104
|
+
# grouped under a parent. Think a consolidated pallet (the parent) with cartons from
|
105
|
+
# multiple suppliers (the children).
|
106
|
+
#
|
107
|
+
# client is a Cargowise::Client instance to look for the related shipments on
|
108
|
+
#
|
109
|
+
def related_shipments(client)
|
110
|
+
@related ||= @consols.map { |consol|
|
111
|
+
consol.master_bill
|
112
|
+
}.compact.map { |master_bill|
|
113
|
+
client.shipments.by_masterbill_number(master_bill)
|
114
|
+
}.flatten.select { |shipment|
|
115
|
+
shipment.number != self.number
|
116
|
+
}.compact
|
117
|
+
end
|
118
|
+
|
119
|
+
# if this shipment has an order ref associated with it, find it.
|
120
|
+
#
|
121
|
+
# This data isn't available via the API, so we need to screen scrape the
|
122
|
+
# website to get it.
|
123
|
+
#
|
124
|
+
# client is a Cargowise::Client instance to look for the related shipments on
|
125
|
+
#
|
126
|
+
def order_ref(client)
|
127
|
+
if client.base_uri
|
128
|
+
@order_ref ||= html_page(client).search(".//span[@id='Ztextlabel1']/text()").to_s.strip || ""
|
129
|
+
else
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
# retrieve a Mechanize::Page object that containts info on this shipment
|
137
|
+
#
|
138
|
+
def html_page(client)
|
139
|
+
return nil unless client.base_uri
|
140
|
+
|
141
|
+
@html_page ||= begin
|
142
|
+
login_uri = client.base_uri + "/Login/Login.aspx"
|
143
|
+
agent = Mechanize.new
|
144
|
+
agent.agent.http.ssl_version = :TLSv1
|
145
|
+
if File.file?(Cargowise::CA_CERT_FILE)
|
146
|
+
agent.agent.http.ca_file = CA_CERT_FILE
|
147
|
+
end
|
148
|
+
page = agent.get(login_uri)
|
149
|
+
form = page.forms.first
|
150
|
+
input_name = form.fields.detect { |field| field.name.to_s.downcase.include?("number")}.andand.name
|
151
|
+
form.__send__("#{input_name}=", self.number) if input_name
|
152
|
+
form.add_field!("ViewShipmentBtn","View Shipment")
|
153
|
+
agent.submit(form)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'cargowise/shipment'
|
4
|
+
|
5
|
+
module Cargowise
|
6
|
+
|
7
|
+
class ShipmentSearch
|
8
|
+
|
9
|
+
def initialize(savon_client)
|
10
|
+
@savon_client = savon_client
|
11
|
+
end
|
12
|
+
|
13
|
+
# find all shipments with a MasterBillNumber that matches ref
|
14
|
+
#
|
15
|
+
def by_masterbill_number(ref)
|
16
|
+
by_number("MasterBillNumber", ref)
|
17
|
+
end
|
18
|
+
|
19
|
+
# find all shipments with a ShipmentNumber that matches ref
|
20
|
+
#
|
21
|
+
def by_shipment_number(ref)
|
22
|
+
by_number("ShipmentNumber", ref)
|
23
|
+
end
|
24
|
+
|
25
|
+
# find all shipments that haven't been delivered yet.
|
26
|
+
#
|
27
|
+
# This times out on some systems, possibly because the logistics company
|
28
|
+
# isn't correctly marking shipments as delivered, so the result is too
|
29
|
+
# large to transfer in a timely manner.
|
30
|
+
#
|
31
|
+
def undelivered
|
32
|
+
filter_hash = {
|
33
|
+
"tns:Filter" => { "tns:Status" => "Undelivered" }
|
34
|
+
}
|
35
|
+
get_shipments_list(filter_hash)
|
36
|
+
end
|
37
|
+
|
38
|
+
# find all shipments that had some activity in the past fourteen days. This could
|
39
|
+
# include leaving port, being delivered or passing a milestone.
|
40
|
+
#
|
41
|
+
def with_recent_activity
|
42
|
+
filter_hash = {
|
43
|
+
"tns:Filter" => {
|
44
|
+
"tns:Date" => {
|
45
|
+
"tns:DateSearchField" => "ALL",
|
46
|
+
"tns:FromDate" => (Date.today - 14).strftime("%Y-%m-%d"),
|
47
|
+
"tns:ToDate" => (Date.today + 14).strftime("%Y-%m-%d")
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
get_shipments_list(filter_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
# find all shipments that had were shipped in the past 14 days or will ship in
|
55
|
+
# the next 14 days
|
56
|
+
#
|
57
|
+
def recently_shipped
|
58
|
+
filter_hash = {
|
59
|
+
"tns:Filter" => {
|
60
|
+
"tns:Date" => {
|
61
|
+
"tns:DateSearchField" => "ETD",
|
62
|
+
"tns:FromDate" => (Date.today - 14).strftime("%Y-%m-%d"),
|
63
|
+
"tns:ToDate" => (Date.today + 14).strftime("%Y-%m-%d")
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
get_shipments_list(filter_hash)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def by_number(field, ref)
|
73
|
+
filter_hash = {
|
74
|
+
"tns:Filter" => {
|
75
|
+
"tns:Number" => {
|
76
|
+
"tns:NumberSearchField" => field,
|
77
|
+
"tns:NumberValue" => ref
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
get_shipments_list(filter_hash)
|
82
|
+
end
|
83
|
+
|
84
|
+
# return an array of shipments. Each shipment should correspond to
|
85
|
+
# a consolidated shipment from the freight company.
|
86
|
+
#
|
87
|
+
# filter_hash should be a hash that will be serialised into an
|
88
|
+
# XML fragment specifying the search criteria. See the WSDL documentation
|
89
|
+
# for samples
|
90
|
+
#
|
91
|
+
def get_shipments_list(filter_hash)
|
92
|
+
response = @savon_client.call(:get_shipments_list, message: filter_hash)
|
93
|
+
response.xpath("//tns:GetShipmentsListResult/tns:WebShipment", {"tns" => Cargowise::DEFAULT_NS}).map do |node|
|
94
|
+
Cargowise::Shipment.new(node)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|