I needed to do this too on my site (1.80) but I went further to make the solution future proof. I modified Checkout.aspx.cs so that it check if any of the items in the cart have shipping enabled. If not then it redirects to the payment method page, otherwise it will go to the shipping address page. Bolded lines are what changed. I did some other stuff like making the progress control only show the steps absolutely necessary given the contents of the shopping cart but those are too involved to post.
protected void Page_Load(object sender, EventArgs e)
{
CommonHelper.SetResponseNoCache(Response);
if (this.Cart.Count == 0)
Response.Redirect(SEOHelper.GetShoppingCartUrl());
//user validation
if (NopContext.Current.User == null && CustomerManager.AnonymousCheckoutAllowed)
{
//create anonymous record
CustomerManager.CreateAnonymousUser();
}
if ((NopContext.Current.User == null) || (NopContext.Current.User.IsGuest && !CustomerManager.AnonymousCheckoutAllowed))
{
string loginURL = SEOHelper.GetLoginPageUrl(true);
Response.Redirect(loginURL);
}
//reset checkout data
CustomerManager.ResetCheckoutData(NopContext.Current.User.CustomerId, false);
bool shippingStepNeeded = false;
//validation
var scWarnings = ShoppingCartManager.GetShoppingCartWarnings(Cart, NopContext.Current.User.CheckoutAttributes, true);
if (scWarnings.Count > 0)
{
Response.Redirect(SEOHelper.GetShoppingCartUrl());
}
else
{
foreach (ShoppingCartItem sci in this.Cart)
{
if (sci.IsShipEnabled)
shippingStepNeeded = true;
var sciWarnings = ShoppingCartManager.GetShoppingCartItemWarnings(
sci.ShoppingCartType,
sci.ProductVariantId,
sci.AttributesXml,
sci.CustomerEnteredPrice,
sci.Quantity);
if (sciWarnings.Count > 0)
{
Response.Redirect(SEOHelper.GetShoppingCartUrl());
}
}
}
if (SettingManager.GetSettingValueBoolean("Checkout.UseOnePageCheckout"))
{
Response.Redirect("~/checkoutonepage.aspx");
}
else
{
if (shippingStepNeeded)
Response.Redirect("~/checkoutshippingaddress.aspx");
else
Response.Redirect("~/checkoutpaymentmethod.aspx");
}
}