Blog

RSS
Payment Director - Pay In Store available only for In-Store Pickup- Wednesday, July 23, 2014

Prior to nopCommerce 3.40,  "In-Store Pickup" was Shipping Method and the customer had to select or enter a shipping address just to be able to get to the Shipping Methods page (or tab in One-Page Checkout).   "In-Store Pickup" has now moved to the Shipping Address page.  You can enable this by checking the '"Pick Up in Store" enabled:' option on the Configuration > Settings > Shipping Settings page.

If you have several payment options including "Pay In Store", you may want to only show "Pay In Store" if the customer selected "In Store Pickup".  Payment Director can handle this:

Order

Type

Name

Expression

Fee Expression

20

Option

Payments.PayInStore

ShippingOptionName = "In-Store Pickup"

 

Be sure to activate all the Payment Methods you want to offer, and then you only need to enter the one conditional Option above.   Any Options not indicated in the Payment Director configuration page will always show unconditionaly.

If you have multiple languages, you can access the Locale Resource String for the In-Store Pickup Shipping Method Name.  (This is also the shipping name you see on the Order).  Use Payment Director's GetLocaleString method:

Order

Type

Name

Expression

Fee Expression

10

String

In-Store Pickup

GetLocaleString("Checkout.PickUpInStore.MethodName")

 

20

Option

Payments.PayInStore

ShippingOptionName = [In-Store Pickup]

 

Additionally, if you want to show a payment method, but have it disabled so that the customer can't select it, Payment Director includes replacements for the Checkout Views that allow you to do that.  They also will let you show replacement text for the Friendly Name.  For example, if you want to still show the "Pay In Store" option, but don't want to the customer to be able to select it, and also for the description, show "(Pay In Store available only for In-Store Pickup)" rather than just "Pay In Store", you can set up a localized resource string for the text, and set up a Condition in the Friendly Name Expression:










  

Order

Type

Name

Expression

Friendly Name Expression

10

String

In-Store Pickup

GetLocaleString("Checkout.PickUpInStore.MethodName")

 

20

String

In-Store Pickup Hint

GetLocaleString("Checkout.InStorePickupHint")

 

30

Boolean

In-Store Pickup Selected

ShippingOptionName = [In-Store Pickup]

 

20

Option

Payments.PayInStore

[In-Store Pickup Selected] ? Show : Disabled

[In-Store Pickup Selected] ? "" : [In-Store Pickup Hint]

You can download the above configuration that you can then import into Payment Director.  You will find the replacement Views in the \Views subfolder in the download .zip file.  (Read the Readme.txt file in the .zip file.)

Tags :  PD-Restrict
Comments (1)
Shipping Director for nopCommerce 3.40 Released- Saturday, July 19, 2014

The SD version is 1.19

Release Notes

Updates for 3.40
Warnings about ShippingDirectorIsActive and OtherShippingRateMethodsAreActive
   Warning: Core 'Free shipping over X' is enabled
   Warning: Actual store shipping will be 0 because ...
       the cart has no items that require shipping
       all products are marked for 'Free shipping'
       the Customer role has free shipping"

Hide test button if SD is not active

Customer extension - HasAttribute  (This accesses the customer shopping attributes, not the customer custom attributes).  E.g.:
    Customer.HasAttribute("DiscountCouponCode","freeshipping")    //compare with InvariantCultureIgnoreCase

Update 2017-12 - Although the  HasAttribute  extension still works, it won't be able to check the DiscountCouponCode as in the above example.  nopCommerce now supports multiple coupon codes applied to the cart.  So, they now store XML in the DiscountCouponCode attribute.   Also, the attribute can be the null string, and you cannot call methods (like ToLower() ) on null strings.  This is how you can create a variable:

   (Customer.GetAttribute("DiscountCouponCode") + ".").ToLower()

Or just test the condition directly:

   (Customer.GetAttribute("DiscountCouponCode") + ".").ToLower().Contains("""couponcode""")

Note the extra quotes "" on both sides of string.  The XML attribute is quoted.  In the future, we'll create a collection property to make this easier.

---end of update---

Tags :  ReleaseSD
Comments (1)
Payment Director - Various Expressions- Friday, July 18, 2014

Here's a bunch of expressions you can try.  Be sure that you activate any Payment Method that you want to use.  

  1. Boolean $Debug true  - this will log trace messages in the System > Log.  Be sure to remove it (or make inactive) in production.
  2. Check Or Money Order - shows custom localized text
  3. Cash On Delivery - only visible if postal code starts with 888
  4. Manual Credit Card - only visible when an admin is impersonating.  Note the " use POS " hint added to the friendly name
  5. Manual and Authorize.ney - calculate the fee based on selected card
  6. Purchase Order - only visible for specific role
  7. Pay In Store - visible always, but can only be selected if shipping method selected in In-Store Pickup
  8. PayPal - only visible for store # 1 when selected shipping is FedEx

In order to utilize the features to have disabled payment methods, and to change the name of payment methods that the customer sees, replace your checkout views (.cshtml files) with the ones provided in the \Views\Checkout sub folder from the evaluation zip file you downloaded.

Type

Name

Expression

FeeExpression

FriendlyNameExpression

Boolean

$Debug

true

 

 

String

CheckOrMoneyLocalized

GetLocaleString("your.custom.text")

 

 

Option

Payments.CheckMoneyOrder

true

 

[CheckOrMoneyLocalized] + " (test)"

Option

Payments.CashOnDelivery

Customer.ShippingAddress.ZipPostalCode.StartsWith("888")
UPDATE: you can use just  Zip.StartsWith("888")

 

 

Option

Payments.Manual

OriginalCustomerIfImpersonated != null

CreditCardType = null ? 0.00 : CreditCardType = "Visa" ? OrderTotalWithoutPaymentFee * 0.02 : 1.00

FriendlyName + " (use POS)"

Option

Payments.AuthorizeNet

OriginalCustomerIfImpersonated = null

CreditCardType = null ? 0.00 : CreditCardType = "Visa" ? OrderTotalWithoutPaymentFee * 0.02 : 1.00

FriendlyName + " (fee varies)"

Option

Payments.PurchaseOrder

Customer.IsInCustomerRole("Dealer Pricing")

 

 

Option

Payments.PayInStore

ShippingOptionName = "In-Store Pickup" ? Show : Disabled

 

ShippingOptionName = "In-Store Pickup" ? "" : FriendlyName + "(Available only for In-Store Pickup)"

Option

Payments.PayPalStandard

CurrentStoreId = 1 and ShippingOptionName.StartsWith("FedEx")

 

 

You can download the configuration import file by clicking on this link PaymentDirector (Various Expressions).txt

Also, if you're using the Test button in the PD configure page, if any expression uses OrderTotalWithoutPaymentFee, then be sure you've used the public store to put an item in the cart, and if using ShippingOptionName, go through the checkout process just past selecting a shipping method.  (PD will warn you otherwise)

Comments (1)
Evaluate customer's prior orders- Friday, June 20, 2014

The GetOrders() customer extension method has been around since Shipping Director 1.13 (for nopCommerce 3.10), but we've never blogged about it.  Here's a couple of possible scenarios  (you may need to put the expression in different configuration fields depending on your needs).

Example: Prior orders containing 2 or more products from a particular vendor:

  Customer.GetOrders().Count(OrderItems.Any(Product.VendorId = 1)) > 2

Example: 10% discount (by using Surcharge Expression) if any (paid) orders in the last 45 days

    Integer PaymentStatus_Paid 30
    Customer.GetOrders().Any(CreatedOnUtc > DateTime.UtcNow.AddDays(-45) and PaymentStatusId = [PaymentStatus_Paid]) ? -[$Rate]*0.10 : 0

Example: Free Shipping for Add On Order (i.e. there's a prior order that's not yet shipped)

    Integer ShippingStatus_NotYetShipped  20
    OptionExit   Free Shipping for Add On Order    Customer.GetOrders().Any(ShippingStatusId = [ShippingStatus_NotYetShipped])     0

Tags :  Expressions
Comments (1)
Example - Free ground shipping for Coupon Code, but want the customer to still have the option to pick the quicker options from Fedex at the regular price.- Monday, June 16, 2014

Update 2023 - see Check if the customer used a coupon code, to use Customer.HasDiscountCouponCode()

You can get the customer entered Coupon Code using:  Customer.GetAttribute("DiscountCouponCode").   In an Option record's surcharge expression, use the built-in [$Name] variable to get the carrier's shipping method name and the built in [$Rate] variable to get the method's rate.  In Surcharge Expression negate the rate if the shipping option name contains the word “Ground”.

Update 2017 - see below if using version 3.90 or later, and don't add this DiscountCouponCode variable!

Update 2017-12 - nopCommerce now supports multiple coupon codes applied to the cart.  So, they now store XML in the attribute. But, also, the attribute can be the null string, and you cannot call methods (like ToLower() ) on null strings.  This is how you can create the variable:

 (Customer.GetAttribute("DiscountCouponCode") + ".").ToLower()

Or just test the condition directly:

   (Customer.GetAttribute("DiscountCouponCode") + ".").ToLower().Contains("""couponcode""")

Note the extra quotes "" on both sides of string.  The XML attribute is quoted.  In the future, we'll create a collection property to make this easier.

Update 2018-07 - Smart tip - If using a unpublished category, you can create a new product template that shows the free shipping tag

---end of update---

Add new 'Shipping Director' record - a variable to get the customer entered coupon code.  Use ' + "." ' at the end because when the customer does not enter a code, then [DiscountCouponCode] will be null, so we need to check that before applying ToLower() below, or easier is just to append the ".". *

Type

String

Name

DiscountCouponCode

Expression

Customer.GetAttribute("DiscountCouponCode") + "."

Add new 'Shipping Director' record - a variable to calculate when free ground.  For example, if the Coupon Code is "freeground." (with "." at the end):

Type

Boolean

Name

FreeGround

Expression

[DiscountCouponCode].ToLower() = "freeground."



Add new 'Shipping Director' record - an Option record to get the rate.  Use a negative surcharge.

Type

Option

Name

FedEx Free ground shipping with Coupon

Expression

true

Rate Expression

Shipping.FedEx

Surcharge Expression

[FreeGround] and [$Name].Contains("Ground") ? -[$Rate] : 0

Name Expression

[FreeGround] and [$Name].Contains("Ground") ? "Free Ground Shipping" : [$Name]

Description Expression

 



If you have many different coupon codes, then give them something common so that you can easily detect them.   For example, if you have codes "ground1", "ground2", etc., then the variable's expression could be [DiscountCouponCode].ToLower().StartsWith("ground").  Or, you could use ... .Contains("ground").   

(*We could have used ' + "" ' (empty string) above rather than ".", but all strings contain and start with the empty string)

(update 7/26/2014:

For 2.65, replace    

   Customer.GetAttribute("DiscountCouponCode")

with just

      Customer.DiscountCouponCode 

(update - 3.90 allows "Multiple discount codes", so the above will The syntax error is due to the embedded quotes in the XML in the string variable.  So, don't use a variable.  use this:

Customer.GetAttribute("DiscountCouponCode").Contains("""freeship""")

 

The quoted quotes  ' "" ' replaces using the "." before to make sure the match is not a substring.  The XML has those embedded quotes to match exactly - i.e.  <CouponCode Code="freeground" /> ). 

Add new 'Shipping Director' record - a variable to calculate when free ground.  For example, if the Coupon Code is "freeground.":

Type

Boolean

Name

FreeGround

Expression

Customer.GetAttribute("DiscountCouponCode").Contains("""freeship""")

Tags :  FreeShipping
Comments (5)
Add a handling charge for a Category- Wednesday, April 2, 2014

If you want to charge a fee when the cart contains any items from a given Category...

Order

Type

Name

Expression

Rate Expression

Surcharge Expression

100

Decimal

SurchargeForX

Items.Any(Product.HasCategory("CategoryX")) ? 20 : 0

 

 

110

Option

Shipping

true

Shipping.Fedex

[SurchargeForX]

The variable for surcharge is calculated using the ternary if-then-else operator “ ? : “.  The Option record’s rate expression can be a fixed amount, or can refer to any shipping rate calculation plugin.

Additionally, you can show the customer a description explaining that a fee has been added (it appears to customerunder the shipping option name).  Just include a Description Expression on the Optionline:

[SurchargeForX] = 0 ? "" : "A $" + [SurchargeForX].ToString() + " has been added because your cart contains a product formCategory X"

If you only want to charge the fee if the total amount of merchandise from that particular Category is under $250, then we need to calculate the total $ amount of the items for that Category, then the expression for SurchargeForX would need to check if that total is less than $250:

Make these changes to the above:  add line 10 for the total $ calculation and change line 100 to use the total:

Order

Type

Name

Expression

Rate Expression

Surcharge Expression

10

Decimal

TotalForX

Items.Where(Product.HasCategory("CategoryX")) .Sum(GetSubTotalWithDiscounts())

 

 

100

Decimal

SurchargeForX

[TotalForX] < 250 ? 20 : 0

 

 

(There is also GetSubTotalWithoutDiscounts() if you do not want to include any discounts in the total calculation.

Tags :  Surcharge
Comments (0)
Expressions can use Extension Methods- Tuesday, January 7, 2014

When writing expressions, it is typically necessary to access the objects within the "context" of the calculation (for both Shipping Rates and Payment Methods).  The context includes the Customer and the Shopping Cart (Items) among other objects.  For example, if you need to know how many items are in the cart, the expression might look like:  Items.Count().   Items is a collection, and "Count()" is a a built in method (Linq) that counts the number of items in a collection.  NopCommerce objects have properties - e.g. a (shopping cart) Item has a Product property and a Quantity property.  So, Items.Count() is not really an accurate count of the # of products in the cart.  To do that, you need to sum the Quantity: Items.Sum(Quantity).   Without going into details about writing Linq expressions, suffice it to say that to use them in SD & PD it's necessary to access properties of nopCommerce objects, and we sometimes need helper methods that are more specific to nopCommerce objects (see this blog about Shopping Cart Object and Query Operators , but note it's based on the older nopCommerce versions that had product variants).  So, here's a list of helper methods (and also includes String helper methods). To use them, follow the nopCommerce object with a "." followed by the method name - e.g. Customer.IsInRole("Member").  In the future, I'll come back and fill in the Description column with more info/examples.


Class / Extension

Return

Description

String

 

 

SubstringAfter(value [,includeDelimiter = false])

String

 

SubstringBefore(value [,includeDelimiter = false])

String

 

SubstringBetween(value [,includeDelimiter = false])

String

 

SubstringRemove(value
    [,stringComparison = StringComparison.InvariantCulture])

String

 

SubstringRemoveIgnoreCase(value)

String

 

ToTitleCase()

String

 

ToOnlyAlphaAndDigits()

String

 

Split(string [,separator])

String

 

IsNumeric()

Boolean

 

IsInteger()

Boolean

 

SelectSingleNode(xpath)

XmlNode

 

Customer

 

 

IsInRole(roleSystemName)

(or  IsInCustomerRole(roleSystemName)  )

Boolean

E.g. Customer.IsInRole("Free Shipping") 

Be sure to assign the Role's "System name" field.

If you need to do a wildcard match, use e.g.  Customer.CustomerRoles.Any(SystemName.Contains("Discount"))

(UPDATE: The  CustomerRoles collection  no longer works as of SD for 4.30 -

GetAttribute(attributeName)

String

 

GetAttributeValues(attributeName [valueSeparator])

String

attribute value, or if list/checkboxes, then separated list of selected values for attribute (nopC 3.30+)

HasAttributeValue(attributeName)

HasAttributeValue(attributeName, valueName)

HasAttributeValue(attributeName, valueId)

Boolean

True if has attribute [and value]

HasDiscountCouponCode("couponcode")

Boolean

True if customer used coupon code. (Case is ignored,)

AppliedDiscountCouponCodes()

string[]

You can use .Contains(), .Any(), etc. to test the array

Example: Customer.AppliedDiscountCouponCodes().Any()

GetOrders()

Orders collection

 

GetRewardPointsBalancePoints()

Integer

 

GetRewardPointsBalanceAmount()

Decimal

 

Product

 

 

HasCategory(categoryName)

Boolean

 Example: Product.HasCategory("Free Shipping")

HasCategory(categoryId)

Boolean

 Example: Product.HasCategory(5)

HasCategoryMatch(categoryNameRegex)

Boolean

 Example: Product.HasCategoryMatch("Brushes") 

   (has a category that has the word "Brushes" in its name)

HasParentCategory(categoryName)

Boolean

 

HasParentCategory(categoryId)

Boolean

 

HasParentCategoryMatch(categoryNameRegex)

Boolean

 

HasManufacturer(manufacturerName)

Boolean

 

HasManufacturer(manufacturerId)

Boolean

 

ShoppingCartItem

 

 

GetWeight()

Decimal

Shopping Cart Item Weight (Includes attribute weight if any.) (The weight is for single item; multiply by Quantity if required)

GetAttributeValues(attributeName [, valueSeparator = ", "])

String

returns string of separated values for given attributeName

HasAttributeValue(attributeName [, valueName])

Boolean

if no valueName param passed, then any for given attributeName

HasAttributeValue(valueId)

Boolean

 

GetVendor()

Vendor

 

GetVendorAddresses()

Address collection

 

GetShippingOriginAddress()

Address

If the product has a warehouse assigned, then this returns that warehouse's address, otherwise it returns the shipping origin address in Shipping Settings.

example: surcharge if any cart items are being shipped from Zip Code 12345

 Decimal  Surcharge    Items.Any(GetShippingOriginAddress().ZipPostalCode = "12345") ? 2 : 0

GetWarehouse()

Warehouse

 

GetSubTotalWithDiscounts()

Decimal

 

GetSubTotalWithoutDiscounts()

Decimal

 

HasSku(sku)

Boolean

 Will also test against product attribute combinations SKU

Address

 

 

ToSenderString([defaultIfNone])

String

*

GetState()

StateProvince

In Shipping Director you can just use State to get the two character state abbreviation.
In Payment Director you can use ShippingAddress.GetState().Abbreviation

GetCountry()

Country

In Shipping Director you can just use Country to get the two character country code.
In Payment Director you can use ShippingAddress.GetCountry().TwoLetterIsoCode

ZipPostalCode

string

In Shipping Director you can just use Zip to get the postal zip code.
In Payment Director you can use ShippingAddress.ZipPostalCode

GetAttributeValues()

string

Since attributes can be defined as checkboxes that can multi-select
this function can return a comma separated value
If your field is a Text Box expecting a numeric value, you can parse it
Example: Decimal.Parse(ShippingAddress.GetAttributeValues("MinShippingAmount"))

Warehouse

 

 

ToSenderString([defaultIfNone])

String

**

GetAddress()

String

Check that a product has a warehouse before using this.  It's safer to use an Item's GetShippingOrigiAddress() (see above)

(Root)

 

 

GetLocaleStringResourceByName(resourceName)

String

 

*SenderStringFormat - Address

{Company}:Address={Address1};City={City};StateProvince={StateProvince};ZipCode={ZipPostalCode};Country={Country.TwoLetterIsoCode};

*SenderStringFormat - Warehouse

{Warehouse.Name}:Address={Address1};City={City};StateProvince={StateProvince};ZipCode={ZipPostalCode};Country={Country.TwoLetterIsoCode};

Tags :  VariablesGettingStarted
Comments (0)
More per-store information- Thursday, December 19, 2013
Shipping Director and Payment Director have built-in variables that you can use to configure your scenario on a per store basis:
  • $CurrentStoreId
  • $CurrentStoreName

(UPDATE:  You no longer need to use [$CurrentStoreId] or [$CurrentStoreName].  You can just use 

  • CurrentStoreId
  • CurrentStoreName

 e.g.  CurrentStoreId = 1

)

The 2nd half of this example describes that:


When using Shipping Director, it must be the only Active shipping method.  You can still use/call other carriers (e.g. USPS, FedEx, etc.) from Shipping Director, and you can configure them in their configuration page, but they must not be Active.  Thus, if you use Shipping Director in a multi-store environment, then you must have a License for each URL.

Similarly for Payment Director; if you want conditional payment methods for one store, and allow all the payment methods for another store, you still need to purchase multiple licenses.

When you purchase each license, you will enter a specific url, and then download the License.txt file.  Each file will be called "License.txt", and you must rename them uniquely but starting with the text "License", and having ".txt" extension (e.g. License_store1.txt, License_store2.txt, etc.).  Put them all in the plugin folder.

Tags :  Multi-Store
Comments (0)
Exclude Letter and Postcards from USPS First Class- Friday, November 29, 2013

In a prior post, I presented an example where it was desired to Exclude Shipping Options from Carrier Plugins

Here’s a similar recent scenario I helped a client configure.  The client uses USPS and wanted to offer First Class Parcel, but not First Class Letter or First Class Postcards.   Out of the box, the USPS shipping plugin only has a checkbox for “First Class”.  USPS will return all applicable first class methods/rates that match the input dimensions (weight, height, etc.).  If you’re not using dimensions, or you have really small/light items (like physical gift cards), you could see the Letter & Postcards methods.  For example, if in the USPS plugin configuration page you check off First Class, Priority Mail Express, and Priority Mail, then you could get back all these options (if your cart is “light”):

USPS Priority Mail Express 1-Day™ ($25.25) 
USPS Priority Mail 2-Day™ ($6.00) 
USPS First-Class Mail® Parcel ($2.07) 
USPS First-Class Mail® Letter ($0.66) 
USPS First-Class Mail® Postcards ($0.33)

So, if you’re not using dimensions, or you have really small/light items and you don’t want to offer Letter & Postcards methods, then they can be excluded by Shipping Director using the [$Name] variable in the Option record’s Name Expression.

The client also wanted to exclude First Class Parcel if the cart contained certain items.   As per previous blogs, the recommendation is to create an unpublished Category for those products.  (Products can be in more than one category.)

And, to make this more interesting, let’s say that there are two stores.  The first store offers in-store pick up and the methods as described above.  The second store will only offer the “Priority Mail” methods.

First, on lines 10 & 20, it has the requisite checks for Address (because Estimate Shipping does not), and also includes on line 30 a check to reject PO Boxes.  On line 100 is the check if there are any items in the cart that should cause the Parcel method to be suppressed.  Line 110 is the in-store option, but the Expression is set to only allow it for store 1 ([$CurrentStoreId]=1).  Line 130 is the USPS option for store 1 (includes the Name filtering using the ternary if-then-else operator “ ? : “ ).  Finally, on line 150, is the USPS option for store 2 also using “ ? : “.  When an external shipping plugin (e.g. “Shipping.USPS”) is in the Rate Expression field, the Name Expression checks each method from the carrier, and if the expression evaluates to blank (“”) the method is suppressed.

Order

Type

Name

Expression

Rate Expression

Name Expression

Description Expression

10

ErrorExit

No State Entered

ShippingAddress.StateProvince = null

 

 

"Please enter Country, State, and Zip"

20

ErrorExit

No Zip Entered

ShippingAddress.ZipPostalCode = null

 

 

"Please enter Country, State, and Zip"

30

ErrorExit

No PO Boxes

ShippingAddress.Address1 != null and Regex.IsMatch(ShippingAddress.Address1, "(?i)\b(?:Post\ (?:Office\ )?|P[.\ ]?O\.?\ )?Box\b")

 

 

"Sorry, we can't ship to PO Boxes."

100

Boolean

SuppressParcel

Items.Any(Product.HasCategory("Suppress Parcel"))

 

 

 

110

Option

In-Store Pickup

[$CurrentStoreId]=1

0

 

"Customer will pick-up at our store in YourTown, NY"

130

Option

US Mail Store 1

[$CurrentStoreId]=1

Shipping.USPS

[$Name].Contains("Letter") or [$Name].Contains("Postcards") or ([$Name].Contains("Parcel") and [SuppressParcel]) ? "" : [$Name]

 

150

Option

US Mail Store 2

[$CurrentStoreId]=2

Shipping.USPS

 [$Name].Contains("Priority Mail") ? [$Name] : ""

 

You can download the configuration import file by clicking on this link ShippingDirector (Exclude Letter and Postcards from USPS First Class).txt


Tags :  ExcludeOptionMulti-Store
Comments (0)
Html in Shipping Method error messages- Sunday, November 17, 2013

Shipping Director provides ability for the calculation of an Error Description using the Error (or ErrorExit) record type.  But, out of the box, nopC will not show the HTML correctly.  One needs to just modify the view file - e.g.

\Views\ShoppingCart\EstimateShipping.cshtml
change from 
    @foreach (var error in Model.Warnings)
    {
        <li>@error</li>
    }

to
    @foreach (var error in Model.Warnings)
    {
        <li>@Html.Raw(error)</li>
    }


similarly in

\Views\Checkout\ShippingMethod.cshtml
\Views\Checkout\ShippingMethod.Mobile.cshtml
\Views\Checkout\OpcShippingMethods.cshtml

Tags :  HTML
Comments (0)
Previous 1 2 3 4 5 Next ... Last