Blog posts of '2012' 'September'

RSS
Exclude Shipping Methods by Product (Variant) Attribute- Saturday, September 29, 2012

Previously in this blog Exclude Shipping Methods by Specification Attribute we discussed checking a Product Specification Attribute.  The scenario was that if a product required assembly, that it could not be picked up in the store.

In this blog, we'll look at how to examine a Product Attribute.  (Product Attributes are actually Product Variant Attributes).    For example, let's say our "Assembled" attribute is something the customer chooses at the time of adding an item to a cart; they can choose a value of "Yes", or "No".   NopCommerce stores customer attribute choices in the shopping cart item's AttributeXml field.  However, we don't have to parse the XML - this field is a string, and we can just look for the correct <Value> tag in the string using the Contains() function.  Here's what a typical AttributeXml looks like for a product variant having only a single attribute  (I've added spacing and linefeeds for readability):

<Attributes>
     <ProductVariantAttribute ID="1">
         <ProductVariantAttributeValue><Value>1</Value></ProductVariantAttributeValue>
     </ProductVariantAttribute>
</Attributes>

It's that <ProductVariantAttributeValue><Value>1</Value> we are looking for - that number "1" in the value tag is the unique Id of the attribute value in the database table (just <Value>1</Value> would be enough, but I'll also include the parent tag to make it clear)

We'll use the same scenatio we did last time - Always offer Fedex, and only offer In-Store pickup if item does NOT require assembly (the leading "!" is the NOT operator).  Here we go...

Order

Type

Name

Expression

Rate Expression

100

String

Assembled Yes Tag

"<ProductVariantAttributeValue><Value>1</Value>"

 

200

Option

In-Store Pickup

!Items.Any(

AttributesXml.Contains([Assembled Yes Tag]))

0

300

Option

FedEx

true

Shipping.Fedex

Yep, that's it!  You will, however, have to find the correct Value Id.  To do that, either check in the database - e.g:

-- Products (Variants) and their Attribute/Values
SELECT p.Name as ProductName, pv.Name as VariantName, 
       pa.Id as AttributeId, pa.Name as AttributeName,
       pvav.Id as ValueId, pvav.Name as ValueName
  FROM Product p
  join ProductVariant pv
    on pv.ProductId = p.Id
  join ProductVariant_ProductAttribute_Mapping m
    on m.ProductVariantId = pv.Id
  join ProductAttribute pa
    on pa.Id = m.ProductAttributeId
  join ProductVariantAttributeValue pvav
    on pvav.ProductVariantAttributeId = m.Id  
where pvav.Name = 'Small'    
order by p.Name, pv.Name, pa.Name, pvav.name

or, you can use Shipping Director to just dump out the AttributeXml to examine.  Set up this record:

Add new 'Shipping Director' record

Order

0

Active

checked

Type

ErrorExit

Name

AttributesXml

Expression

true

Description Expression

Items.First().AttributesXml

Then, put an item with desired selection in the cart and Estimate Shipping.

Tags :  AttributesExcludeOption
Comments (1)
Exclude Shipping Methods by Specification Attribute- Thursday, September 27, 2012

[Update 9/2014  - note that as of nopCommerce 3.0, there is no longer a ProductVariant, so just delete "ProductVariant." from any expression below]

You can have shipping calculations based on the product specification attributes of items in the cart.
As an example, let's exclude a shipping method if the "Assembled" specification attribute option is applied to any item in the cart:
We have configured a Specification Attribute "Assembly" having only a single option "Assembled", and we want to hide shipping option "In-Store Pickup" if any items in the cart have the "Assembled" specification attribute option.

Here how it looks if you're using an carrier rate calculation method like Fedex.  The first Option record is an "In-Store Pickup" defined in SD and will appear with $0 only if no products in the cart have "Assembled" attribute.
(We'll use a Reference as a shortcut to get the specification attributes to make it more readable):

Order

Type

Name

Expression

Rate Expression

100

Reference

Attributes

ProductVariant.Product.ProductSpecificationAttributes

 

200

Option

In-Store Pickup

!Items.Any([@Attributes].Any( SpecificationAttributeOption.Name = "Assembled"))

0

300

Option

FedEx

true

Shipping.Fedex


Here how it looks if you're using an internal rate calculation method like ByWeight, and defined a Shipping Method "In-Store Pickup" in Admin > Configuration > Shipping > Shipping Methods:

Order

Type

Name

Expression

Rate Expression

Name Expression

100

Reference

Attributes

ProductVariant.Product.ProductSpecificationAttributes

 

 

200

Option

Shipping By Weight

true

Shipping.ByWeight

[$Name] = "In-Store Pickup" and Items.Any([@Attributes].Any( SpecificationAttributeOption.Name = "Assembled")) ? "" : [$Name]

When Shipping Director processes the Option record, the Name Expression is computed for each shipping method option returned by the Shipping.Weight plugin (e.g. "In-Store Pickup", "Ground", "Air", etc.).

When a plugin returns multiple shipping options, calculating a specific Name Expression to blank will suppress that option. (the ternary opertator " ? : " acts like an if-then-else)

For the SpecificationAttributeOption in the above example, if you want to use the Id rather than the Name (e.g. your Name is localized, or it it might be changing in future), then be sure to check the SQL database table [SpecificationAttributeOption] to get the correct Id:
   ... .Any(SpecificationAttributeOption.Id = 1) ...

If you've localized your shipping methods names (i.e. created a language resource with Resource Name = "In-Store Pickup"), then be sure to use SD's GetLocaleString() function (must be assigned to a string variable) to get the localized name for use in the expression above:

Order

Type

Name

Expression

10

String

In-Store Pickup Text

GetLocaleString("In-Store Pickup")

Then in the Option record, reference the variable : ... $Name = [In-Store Pickup Text] and Items.Any(...



(P.S.  If you ever need to check the Attribute rather than an AttributeOption, then use SpecificationAttributeOption.SpecificationAttribute.Name .  For example, above we said we have a Specification Attribute "Assembly" having only a single option "Assembled".  But it could also have had two options: "Assembled" and "Not Assembled".  If we didn't care which option, but just that it had the "Assembly" Attribute, then we'd use SpecificationAttributeOption.SpecificationAttribute.Name = "Assembly".)

Tags :  AttributesExcludeOption
Comments (3)
Looking up Freight Rates- Thursday, September 20, 2012

Most common carriers don't handle packages that weigh more than 150lbs.  Or, if they do, they have special freight rates.  Usually, you get the best rate by negotiating with an LTL trucking service.  Unfortunately, most don't have an API that can be called from an eCommerce system, and if they do, nopCommerce does not have any out-of-the-box.   (Also, Freight Rates can be a little tricky, because they sometimes require a Freight Class, but we won't go into that here)

In a previous blog, I showed how Shipping Director can deal with Freight scenarios by using your own rate lookup tables .  Here's another way that has a carrier's freight rates entered using the Shipping.ByWeight plugin, and then use Shipping Director to handle using Fedex plugin if weight is <= 150 lbs, or use ByWeight plugin to get freight rate if weight is > 150 lbs

Type

Name

Expression

Rate Expression

Surcharge Expression

Decimal

Freight Fuel Surcharge %

30.7

 

 

OptionExit

FedEx

[$TotalWeight] <= 150

Shipping.Fedex

 

String

State

ShippingAddress.StateProvince.Abbreviation

 

 

ErrorExit

No Freight State

"AK,HI,ID,MT,NM,ND,SD,TX,WY".Contains([State])

 

 

Option

Freight

true

Shipping.ByWeight

[$Rate] * ([Freight Fuel Surcharge %] / 100.0)



The freight rates don't change that often, but Fuel Surcharge % does, so it can be easily adjusted.
Also, you can prevent customers from shipping freight to the states that your carrier does not handle - Use the Decription Expression to show them a friendly message.


Tags :  Freight
Comments (2)
Shipping Director - Variable and Expression Data Types- Monday, September 3, 2012

Be sure your expression is of the correct type whether assigned to a variable, or used in one of the Expression fields of a record.  Here are the types for the various Expression Fields:

Record/ExpressionName

Data Type

Description

Option and OptionExit

 

 

Expression

Boolean

When evaluates to true, the Option is presented to customer

Rate Expression

Decimal

The calculated Rate + Surcharge appears to customer as the rate

Surcharge Expression

Decimal

 

Name Expression

String

If present, will override the record Name displayed to customer

Description Expression

String

If present, the description appears under the Name/Rate line

 

Error and ErrorExit

 

 

Expression

Boolean

When evaluates to true, the Error message is presented to customer

Description Expression

String

Required.  The description appears under the Name/Rate line

 

Packing

 

See the Packing blogs

Expression

Boolean

When evaluates to true, the packing is performed

Packing Method

literal

E.g. Packing.FirstFitSingleBox  .

Requires Own Package Expression

Boolean

Evaluated for each item

Sender Expression

Boolean

Evaluated for each item

Exclude Item Expression

Boolean

Evaluated for each item

 

Reference

 

See the Reference Type blog

Expression

literal

A reference is a type of variable that is really just a shortcut.

 

 

Notes

 

Booleans

You can use literals 'true' and 'false'.   (lowercase, no quotes)

Strings

Be sure to put literals in double quotes.
To put a double quote in your literal, use two double quotes.
If using String.Format(), beware of localization.

Decimals, Doubles, Singles

Literals must include a decimal point "." regardless of localization
If using e.g. Decimal.Parse(), beware of localization.

DateTimes

Construct literals using DateTime() - e.g. DateTime(2010,8,9).  If using DateTime.Parse(dateString), beware of localization parsing.

Rate and Surcharge Expression

Numeric only.  Do not include any leading currency symbol.

Comments (0)
Shipping Director - Built-in Variables- Monday, September 3, 2012

Here's a list of all built-in variables.  Note that they all start with a "$".  As with user defined variables, the must be enclosed in brackets when used - e.g. [$TotalWeight].

     

Shopping Cart Properties - Set by system at start of rate calculation
$TotalWeight Decimal   uses ShippingService.GetShoppingCartTotalWeight()

$SubTotalWithoutDiscounts Decimal    (uses orderTotalCalcService.GetShoppingCartSubTotal() )

$SubTotalWithDiscounts Decimal

$SubTotalWithoutDiscountsInclTax Decimal

$SubTotalWithDiscountsInclTax Decimal

$ProductTotalWithoutDiscounts Decimal    (uses PriceCalculationService.GetSubTotal() )
$ProductTotalWithDiscounts Decimal

$IsFreeShipping Decimal   uses OrderTotalCalcService.IsFreeShipping()

Shipping Director Record - Set by system for each row (used in debugging and error messages)
$Id Integer   SD record's Id field
$Order Integer   SD record's Order Field
$Name String   SD records's Name field
$Expression String   Set before each expression evaluated (Expression, RateExpression, SurchargeExpression, etc.)

Option Processing - Set by system when the record type is Option, OptionExit, OptionReplace (OptionReplace available only in SD ver 1.05 and above)
$Name String 
$Description String
$Rate Decimal (e.g. surcharge expression can use $Rate)
The Option record's Expressions can reference $Name & $Description & $Rate variables.  Thus, you can adjust the data returned by external shipping rate methods.  (Reminder – an external shipping rate method is called in the Option’s Rate Expression – e.g. Shipping.Fedex).
External shipping rate methods can return multiple options/rates.  If the $Name of an external shipping rate option is set to "", then that option is removed.
Example: To show an option name of just "Ground" and "Priority" rather than "FedEx Ground" and "FedEx Priority", use [
$Name].Replace("FedEx ", "") in the NameExpression to remove the word "FedEx " from the option name.

 

Shipping Option Request properties (These are passed to other shipping rate calculation methods to override the other methods' configuration page.  Not supported by all shipping rate methods.)
$ZipPostalCodeFrom String
$StateProvinceFrom String
$CountryFromTwoLetterIsoCode String

Set by system after other shipping rate calculation method is called
$ShippingOptionsCount Integer

SD sets this after using an external shipping plugin (or SQL) with the total # of shipping rate options it returned.  It's not typically used, but if you are doing something where you think no options will match, then you should check it and say something like "call for rate".


Packaging
$Sender string ""   Set by system when a package is rated manually (not external shipper rate).  Can then be used in Option's Rate, Surchage, Name, Description expressions
$PackageCount Integer 0   Set by system after packaging.  Although defaults to 0, if no Packaging is done, the system actually creates 1 package with all shopping cart items just before rate calculation.

Packaging using PackingFirstFitSingleBox
$PackageBoxWeight Decimal
$PackageBoxMaxWeight Decimal
$PackageBoxHeight Decimal
$PackageBoxLength Decimal
$PackageBoxWidth Decimal
$PackageItemAddWeight Decimal
$PackageItemAddDimension Decimal
$PackageShrinkPercent Integer 0 - Used by PackingFirstFitSingleBox - If $PackageShrinkPercent > 0, and the volume actually packed is less than this % of the given box volume, then this will shrink the final box to its actual packed content volume, rather than the given box volume.  ("
less than this %" => The idea is if the box is "almost full", then use the box dimensions)

Packaging's SenderExpression can evaluate to a string that can contain Ship From Location information.  The string is of the form:
"State=...; ZipCode=...; Country=...;"
This allows different Ship From address for each Sender (see Shipping Option Request properties above):


$PackageBox variable (shorthand for setting many package attributes in one line)
 e.g. $PackageBox   "MaxWeight:40,Height:15,Width:15,Length:15"
 Here's how each shorthand attribute corresponds to the built in variable:
    MaxWeight    => $PackageBoxMaxWeight
    Height       => $PackageBoxHeight
    Width        => $PackageBoxWidth
    Length       => $PackageBoxLength
    Weight       => $PackageBoxWeight
    AddWeight    => $PackageItemAddWeight
    AddDimension => $PackageItemAddDimension
    ShrinkPercent=> $PackageShrinkPercent


Rate Request Type - When Packaging, can be set by user to indicate the way that rate requests are made to other rate calculation methods when Packaging
$ShippingRateRequest String
    "OneRequestForAllPackages"
    "OneRequestPerPackage"
    "OneRequestPerSender"

E.g. "OneRequestPerPackage" => Get FedEx rates separately for each package

if $ShippingRateRequest is not set by user, then the system will default depending on if the Packing SenderExpression used:
    if no SenderExpression then "OneRequestForAllPackages" else  "OneRequestPerSender"


Debugging

$Debug boolean false   When true, detailed messages are written to the system log.

(Note:   Because log messages are not HTML formatted, they can be hard to read in the browser.  So, when viewing a System Log record, click View to see the log detail page.  Then, right click the page and "View Source".  Scroll down (a bit more than half way) until you see the plain text messages.)



Flow Control  (SD ver 1.05 and up)
$Goto Integer 0 Set to a Order/Line number. Can be conditional and dynamic. Set to 0 to skip.  E.g. Use ternary if/then/else operator $Goto condition ? 100 : 0 ==> "If condition then Goto 100 (else goto next line)"

Special Functions
Special functions must be assigned to a String variable and must be the first word in the variable’s Expression field.  The expression cannot be complex: E.g. it can be like GetLocaleString("...") or GetLocaleString([someotherstringvar]), but cannot include any operators.


GetLocaleString(<string>)   get a language specific message.
GetSetting(<string>)        get a setting

Tags :  VariablesGettingStarted
Comments (1)