a.m. wrote:BTW, have you implemented ITracker for some of the existing shipping rate computation providers (UPS or Fedex, for example)?
I have for UPS and Schenker.
UPS
public class UpsTracker : ITracker
{
public bool IsMatch(string trackingNumber)
{
//Not sure if this is true for every shipment, but it is true for all of our shipments
return trackingNumber.ToUpperInvariant().StartsWith("1Z");
}
public string GetUrl(string trackingNumber, Core.Domain.Localization.Language language)
{
string url = "http://wwwapps.ups.com/WebTracking/track?HTMLVersion=5.0&loc={0}&Requester=UPSHome&WBPM_lid=homepage%2Fct1.html_pnl_trk&trackNums={1}&track.x=S%C3%B6k";
string loc = language.LanguageCulture.Replace('-', '_');
url = string.Format(url, loc, trackingNumber);
return url;
}
public IList<ShipmentStatusEvent> GetShipmentEvents(string trackingNumber)
{
TrackService track = new TrackService();
TrackRequest tr = new TrackRequest();
UPSSecurity upss = new UPSSecurity();
UPSSecurityServiceAccessToken upssSvcAccessToken = new UPSSecurityServiceAccessToken();
upssSvcAccessToken.AccessLicenseNumber = "ACCESSCODE";
upss.ServiceAccessToken = upssSvcAccessToken;
UPSSecurityUsernameToken upssUsrNameToken = new UPSSecurityUsernameToken();
upssUsrNameToken.Username = "USERNAME";
upssUsrNameToken.Password = "PASSWORD";
upss.UsernameToken = upssUsrNameToken;
track.UPSSecurityValue = upss;
RequestType request = new RequestType();
String[] requestOption = { "15" };
request.RequestOption = requestOption;
tr.Request = request;
tr.InquiryNumber = trackingNumber;
System.Net.ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };
TrackResponse trackResponse = track.ProcessTrack(tr);
return trackResponse.Shipment.SelectMany(c => c.Package[0].Activity.Select(x => ToStatusEvent(x))).ToList();
}
private ShipmentStatusEvent ToStatusEvent(ActivityType activity)
{
var ev = new ShipmentStatusEvent();
switch (activity.Status.Type)
{
case "I":
if (activity.Status.Code == "DP")
{
ev.EventType = ShipmentEventType.Departed;
}
else if (activity.Status.Code == "EP")
{
ev.EventType = ShipmentEventType.ExportScanned;
}
else if (activity.Status.Code == "OR")
{
ev.EventType = ShipmentEventType.OriginScanned;
}
else
{
ev.EventType = ShipmentEventType.Arrived;
}
break;
case "X":
ev.EventType = ShipmentEventType.NotDelivered;
break;
case "M":
ev.EventType = ShipmentEventType.Booked;
break;
case "D":
ev.EventType = ShipmentEventType.Delivered;
break;
}
string dateString = string.Concat(activity.Date, " ", activity.Time);
ev.Date = DateTime.ParseExact(dateString, "yyyyMMdd HHmmss", CultureInfo.InvariantCulture);
ev.CountryCode = activity.ActivityLocation.Address.CountryCode;
ev.Location = activity.ActivityLocation.Address.City;
return ev;
}
}
Schenker
public class SchenkerTracker : ITracker
{
public bool IsMatch(string trackingNumber)
{
//Return true if it starts with your serie
}
public string GetUrl(string trackingNumber, Core.Domain.Localization.Language language)
{
string url = "http://was.schenker.nu/ctts-a/com.dcs.servicebroker.http.HttpXSLTServlet?request.service=CTTSTYPEA&request.method=search&clientid=&language={0}&country=SE&reference_type=*DWB&reference_number={1}";
string lang = language.UniqueSeoCode;
url = string.Format(url, lang, trackingNumber);
return url;
}
private string GetXml(string referenceType, string reference)
{
//DOn't forget to put the password and username in the url below (might be good to put this as a setting)
string url = "http://was.schenker.nu/ctts-a/com.dcs.servicebroker.http.HttpXSLTServlet?request.service=CTTSTYPEA_PLUGIN&request.method=search&request.format=xmledifact&reference_type=*{0}&reference_number={1}&request.user.id=USERID&request.user.password=USERPASSWORD";
url = string.Format(url, referenceType, reference);
using (WebClient client = new WebClient())
{
client.Encoding = Encoding.UTF8;
return client.DownloadString(url);
}
}
public IList<ShipmentStatusEvent> GetShipmentEvents(string trackingNumber)
{
List<ShipmentStatusEvent> events = new List<ShipmentStatusEvent>();
string xml = GetXml("DWB", trackingNumber);
StringReader reader = new StringReader(xml);
XPathDocument doc = new XPathDocument(reader);
XPathNavigator nav = doc.CreateNavigator();
var countryelement = nav.SelectSingleNode("//country_of_destination");
string destCountry = countryelement == null ? string.Empty : countryelement.Value;
foreach (XPathNavigator node in nav.Select("//status_event"))
{
ShipmentStatusEvent ev = new ShipmentStatusEvent();
string eventType = node.SelectSingleNode(".//status_event_type").Value;
string eventCode = node.SelectSingleNode(".//status_event_code").Value;
switch (eventCode)
{
case "*800":
if (eventType == "*001")
{
ev.EventType = ShipmentEventType.Booked;
}
else
{
ev.EventType = ShipmentEventType.Departed;
}
break;
case "MAN":
ev.EventType = ShipmentEventType.Departed;
break;
case "COL":
ev.EventType = ShipmentEventType.Collected;
break;
case "ENM":
case "*950":
ev.EventType = ShipmentEventType.Arrived;
break;
case "DOT":
ev.EventType = ShipmentEventType.OutForDelivery;
break;
case "DLV":
ev.EventType = ShipmentEventType.Delivered;
break;
case "NDL":
ev.EventType = ShipmentEventType.NotDelivered;
break;
case "PUP":
ev.EventType = ShipmentEventType.PickedUpByCustomer;
break;
case "DET":
case "TIN":
continue;
}
string dateElement = node.SelectSingleNode(".//status_event_date").Value;
string timeElement = node.SelectSingleNode(".//status_event_time").Value;
string date = string.Concat(dateElement, " ", timeElement);
ev.Date = DateTime.ParseExact(date, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
ev.CountryCode = node.SelectSingleNode(".//status_event_country_code").Value;
ev.Location = node.SelectSingleNode(".//status_event_place_name").Value;
events.Add(ev);
}
if (destCountry.Trim() == "Norway" && !trackingNumber.StartsWith("26460"))
events.AddRange(GetShipmentEvents(string.Concat("26460", trackingNumber)));
return events;
}
}
ShipmentStatusEvent
public class ShipmentStatusEvent
{
public ShipmentEventType EventType { get; set; }
public string Location { get; set; }
public string CountryCode { get; set; }
public DateTime Date { get; set; }
}
ShipmentEventType
public enum ShipmentEventType
{
Booked = 0,
Collected = 1,
Departed = 2,
Arrived = 3,
OutForDelivery = 4,
NotDelivered = 5,
Delivered = 6,
OriginScanned = 7,
ExportScanned = 8,
PickedUpByCustomer = 9
}