USPS doesn't return First-Class Letter

Project: 
Ubercart
Category: 
bug report
Priority: 
normal
Status: 
active

Lyle,

Found out that the way the USPS module is setup currently (to use the "ALL" service method, which is the superenumerator for all other types - including PRIORITY and FIRST CLASS) - if we have an item that weighs very little, as in 3 ounces each, it does not return the First Class Letter rate. Instead, it returns First Class Parcel (along with Priority and Express).

The main thing is that our 3oz-products are only $1.00 each, and First-Class Parcel ends up being almost $6 for domestic shipping (when it should be less than $2.00 for Letter rate).

What I think is happening is that, as the module is looping through the services, since the F.C. Letter rate comes first, it's getting overwritten once the module hits the F.C. Parcel. Am I way off target here? I'm going to look into this, it's fairly important that we're not charging 4x the product cost just to ship something in an envelope.

Re: USPS doesn't return First-Class Letter

Hmm, me too. Looking at the request sent to USPS, the combination of attributes must be wrong, because it's not quoting First Class Mail for anything. I checked the documentation, and a <FirstClassMailType> tag is required when requesting a First Class quote, but it's not added by Ubercart.

If you try this sample USPS request URL:

http://production.shippingapis.com/ShippingAPI.dll?API=RateV3&XML=<RateV3Request%20USERID="xxxxxxx"><Package%20ID="0"><Service>ALL</Service><ZipOrigination>98144</ZipOrigination><ZipDestination>10010</ZipDestination><Pounds>0</Pounds><Ounces>3</Ounces><Size>REGULAR</Size><Machinable>True</Machinable></Package></RateV3Request>

(don't forget to put your own USERID in where I have left the xxxxxx), you will see NO First Class rates returned!

But if you stick in a <FirstClassMailType>LETTER</FirstClassMailType> tag after the <Service>ALL</Service> tag, then it returns three types of First Class postage:

  1. First-Class Mail $0.75
  2. First-Class Mail Flat $1.14
  3. First-Class Mail Parcel $1.47

So, it looks like the XML request is not being constructed properly in the case of First Class Mail. Inserting the above tag returns the quotes, but there's more work to do in uc_usps.module to parse the results and present the options to the user.

Plus, going through this exercise, I discovered the definition of "Machinable" is wrong in the code. I haven't been able to find a good definition on-line, but for instance I know for a fact that normal letters are not machinable if they are >1/4" thick (then they won't fit through the machine - hence the name!) OR if they have the wrong aspect ratio - a square envelope for example is non-machinable. (The USPS has templates on their scales and sometimes on their countertops which can be used to tell if a letter has a non-machinable aspect ratio). But most normal letters ARE machinable. The code says if they're under 6 ounces they're NOT machinable - that's just wrong.

Re: Re: USPS doesn't return First-Class Letter

Yeah I didn't know about the machinable issue, that's good to know about, though.

And with regard to the FirstClass XML data, I just edited my usps module to include the FirstClassMailType node, and changed the Service option from ALL to FIRST CLASS, and that's how I got the (one) First-Class Envelope option for 2.70 instead of 6 bucks.

Re: Re: USPS doesn't return First-Class Letter

Those machinable rules are for parcels, not envelopes. I don't know a lot about how USPS does things, so I was coding from their documentation, which wasn't all that informative.

There may be stuff we can do with a new shipping type for envelopes that can help things.

Re: Re: Re: USPS doesn't return First-Class Letter

Lyle, let me know if you're able to get to this. We have some cheap products that people are still buying, even though the shipping is three times as much as the product cost. Then they email us and tell us they got "ripped off." (If you don't want to pay the shipping, don't buy the sticker - not a great solution, I suppose...)

So if you can't get to this I'll take a gander this weekend. I'll let you know what I come up with.

Re: Re: Re: Re: USPS doesn't return First-Class Letter

Following up 20 days later ... Lyle, let me know if you'd like me to dive into this. I have some time this week.

Re: Re: Re: Re: Re: USPS doesn't return First-Class Letter

Sorry for not getting back to you. I say, "Go for it". If I haven't gotten to it for this long, there's not much chance that I will soon.

Re: Re: Re: Re: Re: Re: USPS doesn't return First-Class Letter

I'm working on this but can't quite figure out how to find out in the product or package objects, where the shipping method is. Is it even being passed into the uc_usps_quote function, along with the rest of the $packages object?

I'll do some print_r's and try to dig deeper. Right now all I need to do is check this value, because I've created an Envelope shipping method / type, but I don't know how to use that to trigger the FIRST CLASS Service Type in the XML. Anyone have pointers?

Re: Re: Re: Re: Re: Re: Re: USPS doesn't return First-Class Lett

Figured it out. (A quick side note, using "TRUE" in my print_r statement- for "return" mode - solved my issue of being unable to look at the object, ie:

<?php
drupal_set_message
('<pre>'.print_r($product, TRUE).'</pre>');
?>

Anyways. Looks like shipping_type is not passed to the $packages object so I added this line to _uc_usps_package_products($products):

<?php
$package
->shipping_type = $product->shipping_type;
?>

Had to add the 'envelope' type to uc_usps_shipping_type():

<?php
function uc_usps_shipping_type(){
 
$weight = variable_get('uc_quote_type_weight', array('small_package' => 0, 'envelope' =>0));
 
 
$types = array(
     
'envelope' => array(
   
'id' => 'envelope',
   
'title' => t('Envelope'),
   
'weight' => $weight['envelope'],
  ),
     
'small_package' => array(
   
'id' => 'small_package',
   
'title' => t('Small package'),
   
'weight' => $weight['small_package'],
  )
 
  );
 
  return
$types;
}
?>

Added this to uc_usps_rate_request:

<?php
if ($package->shipping_type == 'envelope') {
       
$service_type = 'FIRST CLASS';
    } else {
       
$service_type = 'ALL';
    }
?>

.. and later on, within the $request string:
<?php
   
'<Service>' . $service_type . '</Service>' .   
   
'<FirstClassMailType>LETTER</FirstClassMailType>' .
?>

.

And finally my one caveat: I had to edit uc_usps_shipping_method() around line 177, to make the normal usps $methods array use the 'envelope' type as so:

<?php
function uc_usps_shipping_method(){
 
$enabled = variable_get('uc_quote_enabled', array('usps' => true, 'usps_intl' => true));
 
$weight = variable_get('uc_quote_method_weight', array('usps' => 0, 'usps_intl' => 1));


 
$methods = array(
   
'usps' => array(
     
'id' => 'usps',
     
'title' => t('U.S. Postal Service'),
     
'quote' => array(
       
'type' => 'envelope',
       
'callback' => 'uc_usps_quote',
       
'accessorials' => _uc_usps_services()
        ),
     
'enabled' => $enabled['usps'],
     
'weight' => $weight['usps'],
    ),   
   
'usps_intl' => array(
     
'id' => 'usps_intl',
     
'title' => t('U.S. Postal Service (Intl.)'),
     
'quote' => array(
       
'type' => 'small_package',
       
'callback' => 'uc_usps_intl_quote',
       
'accessorials' => _uc_usps_intl_services(),
      ),
     
'enabled' => $enabled['usps_intl'],
     
'weight' => $weight['usps_intl'],
    ),
  );
 
  return
$methods;
}
?>

Here's my problem so far. Leaving it as is seems to work, even if you go on to add items to your cart that won't fit in an envelope. But, when you change the first method back to 'small_package' it breaks the quotes altogether.

So this is what I've got so far. I'm going to test and if it seems to work I'm going to use it, until Lyle can take a better look.

If anyone has improvements on this feel free to post it here. I've included my entire .module zipped up for reference.

AttachmentSize
uc_usps.zip5.8 KB

Re: Re: Re: Re: Re: Re: Re: Re: USPS doesn't return First-Class

Handling orders that have mixed shipping types has always been a difficult thing to handle. I think what we can do here is add another USPS shipping method, one for parcels and one for envelopes. If we also set the envelope type to have a greater weight than "small_package", then the quote module will assume that everything will go in a box and use all of the small package methods.

Since you've already changed uc_usps_quote(), I don't think there's anything extra that needs to be done. Just make the new shipping method identical to the one there already and change the array key, id, and type.

More things to think about: do we do the same thing for international orders? Do I need to devise a way for shipping methods to have more than one shipping type?

Re: Re: Re: Re: Re: Re: Re: Re: Re: USPS doesn't return First-Cl

Cool, I know my solution was hackish at best, just a matter of getting something that worked. In general with our orders, you can either fit it all in a small or large envelope, or it goes into a parcel (for a T-shirt, etc.). So having only the fist class envelope choice come up, which happens now, for orders containing only stickers etc. works (while probably not optimal).

For International it's not the Service node that changes; instead it's the MailType node in the XML request. Since their structure is so different there is no Service or FirstClassMailType labels, just the MailType should be "Envelope" instead of "Package".

With regard to "shipping methods to have more than one shipping type," I can't say - we generally send everything as one shipment, and if it requires more than one, we'll eat the cost. Unless that's not what you mean ... (sorry for being obtuse, it's early) Smiling

Re: Re: Re: Re: Re: Re: Re: Re: Re: Re: USPS doesn't return Firs

New update, this seems to be breaking my quotes. Continued testing has revealed an issue that will basically make me hold off on this.

Feel free to not use any of the work I did, although I think passing the shipping_type to the $package object is a good idea.