Skip to content

Commit

Permalink
#382 Feed plugins: More options and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
mgesing committed Jul 18, 2014
1 parent 7b235c0 commit 95a1913
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 88 deletions.
2 changes: 1 addition & 1 deletion changelog.md
Expand Up @@ -33,7 +33,7 @@
* (Developer) Moved _PublicControllerBase_ to SmartStore.Web.Framework
* (Developer) Moved 'AdminControllerBase' to SmartStore.Web.Framework
* #384 Web API: Inserting sluged recources like products require an URL record
* Promotion feed plugins: Asynchronous feed creation
* #382 Promotion feed plugins: Asynchronous feed creation, more options and improvements

###Bugfixes###
* Twitter Auth: fixed _SecurityTransparent_ error
Expand Down
16 changes: 16 additions & 0 deletions src/Libraries/SmartStore.Core/Data/IDbContext.cs
Expand Up @@ -85,5 +85,21 @@ IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params ob
/// </summary>
/// <returns>The count of detached entities</returns>
int DetachAll();

/// <summary>
/// Change the state of an entity object
/// </summary>
/// <typeparam name="TEntity">Type of entity</typeparam>
/// <param name="entity">The entity instance</param>
/// <param name="newState">The new state</param>
void ChangeState<TEntity>(TEntity entity, System.Data.Entity.EntityState newState);

/// <summary>
/// Changes the object state to unchanged
/// </summary>
/// <typeparam name="TEntity">Type of entity</typeparam>
/// <param name="entity">The entity instance</param>
/// <returns>true on success, false on failure</returns>
bool SetToUnchanged<TEntity>(TEntity entity);
}
}
12 changes: 12 additions & 0 deletions src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs
Expand Up @@ -6,6 +6,7 @@
using System.ComponentModel;
using System.Web.Routing;
using SmartStore.Core;
using System.Globalization;

namespace SmartStore
{
Expand Down Expand Up @@ -138,5 +139,16 @@ public static void Grow(this StringBuilder sb, string grow, string delimiter)
sb.AppendFormat("{0}{1}", delimiter, grow);
}
}

/// <summary>
/// Rounds and formats a decimal culture invariant
/// </summary>
/// <param name="value">The decimal</param>
/// <param name="decimals">Rounding decimal number</param>
/// <returns>Formated value</returns>
public static string FormatInvariant(this decimal value, int decimals = 2)
{
return Math.Round(value, decimals).ToString("0.00", CultureInfo.InvariantCulture);
}
}
}
16 changes: 13 additions & 3 deletions src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs
Expand Up @@ -712,8 +712,6 @@ public static string RemoveEncloser(this string value, string start, string end,
return value;
}

// codehint: sm-add (begin)

/// <summary>Debug.WriteLine</summary>
/// <remarks>codehint: sm-add</remarks>
[DebuggerStepThrough]
Expand Down Expand Up @@ -999,7 +997,19 @@ public static string RemoveInvalidXmlChars(this string s)
return Regex.Replace(s, @"[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD]", "", RegexOptions.Compiled);
}

// codehint: sm-add (end)
[DebuggerStepThrough]
public static string ReplaceCsvChars(this string s)
{
if (s.HasValue())
{
s = s.Replace(';', ',');
s = s.Replace('\r', ' ');
s = s.Replace('\n', ' ');
return s.Replace("'", "");
}
return "";
}

#endregion

#region Helper
Expand Down
19 changes: 19 additions & 0 deletions src/Libraries/SmartStore.Data/ObjectContextBase.cs
Expand Up @@ -519,6 +519,25 @@ public int DetachAll()
return attachedEntities.Count;
}

public void ChangeState<TEntity>(TEntity entity, System.Data.Entity.EntityState newState)
{
((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.ChangeObjectState(entity, newState);
}

public bool SetToUnchanged<TEntity>(TEntity entity)
{
try
{
ChangeState<TEntity>(entity, System.Data.Entity.EntityState.Unchanged);
return true;
}
catch (Exception exc)
{
exc.Dump();
return false;
}
}

private string FormatValidationExceptionMessage(IEnumerable<DbEntityValidationResult> results)
{
var sb = new StringBuilder();
Expand Down
2 changes: 1 addition & 1 deletion src/Plugins/Feed.Froogle/Description.txt
@@ -1,6 +1,6 @@
FriendlyName: Google Merchant Center (GMC)
SystemName: PromotionFeed.Froogle
Version: 2.2
Version: 2.21
MinAppVersion: 2.0.0
Author: SmartStore AG
DisplayOrder: 1
Expand Down
10 changes: 5 additions & 5 deletions src/Plugins/Feed.Froogle/FroogleFeedPlugin.cs
Expand Up @@ -23,10 +23,10 @@ public class FroogleFeedPlugin : BasePlugin, IMiscPlugin
GoogleProductObjectContext objectContext,
ILocalizationService localizationService)
{
this._googleService = googleService;
this._settingService = settingService;
this._objectContext = objectContext;
this._localizationService = localizationService;
_googleService = googleService;
_settingService = settingService;
_objectContext = objectContext;
_localizationService = localizationService;
}

/// <summary>
Expand Down Expand Up @@ -69,7 +69,7 @@ public override void Uninstall()

_settingService.DeleteSetting<FroogleSettings>();

_localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey);
_localizationService.DeletePluginStringResources(this.PluginDescriptor);

var migrator = new DbMigrator(new Configuration());
migrator.Update(DbMigrator.InitialDatabase);
Expand Down
12 changes: 12 additions & 0 deletions src/Plugins/Feed.Froogle/Localization/resources.de-de.xml
Expand Up @@ -266,4 +266,16 @@
<LocaleResource Name="ExportBasePrice.Hint">
<Value>Aktivieren Sie diese Option, wenn Sie denGrundpreis des Produkt exportieren möchten.</Value>
</LocaleResource>
<LocaleResource Name="ConvertNetToGrossPrices">
<Value>Netto- in Bruttopreise umrechnen</Value>
</LocaleResource>
<LocaleResource Name="ConvertNetToGrossPrices.Hint">
<Value>Legt fest, dass Netto- in Bruttopreise umgerechnet werden sollen.</Value>
</LocaleResource>
<LocaleResource Name="LanguageId">
<Value>Sprache</Value>
</LocaleResource>
<LocaleResource Name="LanguageId.Hint">
<Value>Legt die Sprache fest, in der sprachabhängige Werte (z.B. der Produktname) exportiert werden sollen.</Value>
</LocaleResource>
</Language>
12 changes: 12 additions & 0 deletions src/Plugins/Feed.Froogle/Localization/resources.en-us.xml
Expand Up @@ -266,4 +266,16 @@
<LocaleResource Name="ExportBasePrice.Hint">
<Value>Activate this option if you want to export the base price of the product.</Value>
</LocaleResource>
<LocaleResource Name="ConvertNetToGrossPrices">
<Value>Convert net into gross prices</Value>
</LocaleResource>
<LocaleResource Name="ConvertNetToGrossPrices.Hint">
<Value>Determines to convert net into gross prices.</Value>
</LocaleResource>
<LocaleResource Name="LanguageId">
<Value>Language</Value>
</LocaleResource>
<LocaleResource Name="LanguageId.Hint">
<Value>Determines which language to use to export language dependent values (for instance the product name).</Value>
</LocaleResource>
</Language>
10 changes: 10 additions & 0 deletions src/Plugins/Feed.Froogle/Models/FeedFroogleModel.cs
Expand Up @@ -106,6 +106,12 @@ public string AvailableGoogleCategoriesAsJson
[SmartResourceDisplayName("Plugins.Feed.Froogle.ExportBasePrice")]
public bool ExportBasePrice { get; set; }

[SmartResourceDisplayName("Plugins.Feed.Froogle.ConvertNetToGrossPrices")]
public bool ConvertNetToGrossPrices { get; set; }

[SmartResourceDisplayName("Plugins.Feed.Froogle.LanguageId")]
public int LanguageId { get; set; }

public void Copy(FroogleSettings settings, bool fromSettings)
{
if (fromSettings)
Expand Down Expand Up @@ -137,6 +143,8 @@ public void Copy(FroogleSettings settings, bool fromSettings)
ExpirationDays = settings.ExpirationDays;
ExportShipping = settings.ExportShipping;
ExportBasePrice = settings.ExportBasePrice;
ConvertNetToGrossPrices = settings.ConvertNetToGrossPrices;
LanguageId = settings.LanguageId;
}
else
{
Expand Down Expand Up @@ -167,6 +175,8 @@ public void Copy(FroogleSettings settings, bool fromSettings)
settings.ExpirationDays = ExpirationDays;
settings.ExportShipping = ExportShipping;
settings.ExportBasePrice = ExportBasePrice;
settings.ConvertNetToGrossPrices = ConvertNetToGrossPrices;
settings.LanguageId = LanguageId;
}
}
}
Expand Down
73 changes: 32 additions & 41 deletions src/Plugins/Feed.Froogle/Services/GoogleFeedService.cs
@@ -1,31 +1,26 @@
using Autofac;
using Telerik.Web.Mvc;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Web;
using System.Web.Mvc;
using System.Collections.Generic;
using System.Globalization;
using SmartStore.Web.Framework.Plugins;
using SmartStore.Plugin.Feed.Froogle.Domain;
using SmartStore.Plugin.Feed.Froogle.Models;
using SmartStore.Core.Data;
using SmartStore.Core.Domain.Catalog;
using SmartStore.Core.Domain.Directory;
using SmartStore.Services.Catalog;
using SmartStore.Plugin.Feed.Froogle.Domain;
using SmartStore.Plugin.Feed.Froogle.Models;
using SmartStore.Web.Framework.Plugins;
using Telerik.Web.Mvc;
using SmartStore.Core.Domain.Tasks;
using SmartStore.Services.Stores;
using SmartStore.Core.Domain.Stores;
using System.Web.Mvc;
using System.Collections.Generic;
using SmartStore.Web.Framework;
using SmartStore.Services.Directory;
using SmartStore.Core;
using SmartStore.Core.Logging;
using Autofac;
using System.Threading;
using SmartStore.Core.Async;
using System.Web;
using SmartStore.Services.Catalog;
using SmartStore.Services.Directory;
using SmartStore.Services.Tasks;
using SmartStore.Services.Localization;

namespace SmartStore.Plugin.Feed.Froogle.Services
{
Expand All @@ -37,36 +32,27 @@ public partial class GoogleFeedService : IGoogleFeedService
private readonly IRepository<GoogleProductRecord> _gpRepository;
private readonly IProductService _productService;
private readonly IManufacturerService _manufacturerService;
private readonly IStoreService _storeService;
private readonly ICategoryService _categoryService;
private readonly IMeasureService _measureService;
private readonly MeasureSettings _measureSettings;
private readonly IPriceCalculationService _priceCalculationService;
private readonly IWorkContext _workContext;
private readonly IDbContext _dbContext;

public GoogleFeedService(
IRepository<GoogleProductRecord> gpRepository,
IProductService productService,
IManufacturerService manufacturerService,
IStoreService storeService,
ICategoryService categoryService,
FroogleSettings settings,
IMeasureService measureService,
MeasureSettings measureSettings,
IPriceCalculationService priceCalculationService,
IWorkContext workContext,
IDbContext dbContext,
IComponentContext ctx)
{
_gpRepository = gpRepository;
_productService = productService;
_manufacturerService = manufacturerService;
_storeService = storeService;
_categoryService = categoryService;
Settings = settings;
_measureService = measureService;
_measureSettings = measureSettings;
_priceCalculationService = priceCalculationService;
_workContext = workContext;
_dbContext = dbContext;

_helper = new FeedPluginHelper(ctx, "PromotionFeed.Froogle", "SmartStore.Plugin.Feed.Froogle", () =>
{
Expand Down Expand Up @@ -306,20 +292,25 @@ private string WriteItem(XmlWriter writer, Store store, Product product, Currenc
if (category.IsNullOrEmpty())
return Helper.GetResource("MissingDefaultCategory");

var brand = (manu != null && manu.Manufacturer.Name.HasValue() ? manu.Manufacturer.Name : Settings.Brand);
string manuName = (manu != null ? manu.Manufacturer.GetLocalized(x => x.Name, Settings.LanguageId, true, false) : null);
string productName = product.GetLocalized(x => x.Name, Settings.LanguageId, true, false);
string shortDescription = product.GetLocalized(x => x.ShortDescription, Settings.LanguageId, true, false);
string fullDescription = product.GetLocalized(x => x.FullDescription, Settings.LanguageId, true, false);

var brand = (manuName ?? Settings.Brand);
var mpn = Helper.GetManufacturerPartNumber(product);

bool identifierExists = product.Gtin.HasValue() || brand.HasValue() || mpn.HasValue();

writer.WriteElementString("g", "id", _googleNamespace, product.Id.ToString());

writer.WriteStartElement("title");
writer.WriteCData(product.Name.Truncate(70));
writer.WriteCData(productName.Truncate(70));
writer.WriteEndElement();

var description = Helper.BuildProductDescription(product, manu, d =>
var description = Helper.BuildProductDescription(productName, shortDescription, fullDescription, manuName, d =>
{
if (product.FullDescription.IsNullOrEmpty() && product.ShortDescription.IsNullOrEmpty())
if (fullDescription.IsNullOrEmpty() && shortDescription.IsNullOrEmpty())
{
var rnd = new Random();
Expand Down Expand Up @@ -362,24 +353,24 @@ private string WriteItem(XmlWriter writer, Store store, Product product, Currenc
writer.WriteElementString("g", "condition", _googleNamespace, Condition());
writer.WriteElementString("g", "availability", _googleNamespace, Availability(product));

decimal priceBase = _priceCalculationService.GetFinalPrice(product, null, _workContext.CurrentCustomer, decimal.Zero, true, 1);
decimal price = Helper.ConvertFromStoreCurrency(priceBase, currency);
decimal price = Helper.GetProductPrice(product, currency);
string specialPriceDate;

if (SpecialPrice(product, out specialPriceDate))
{
writer.WriteElementString("g", "sale_price", _googleNamespace, Helper.DecimalUsFormat(price) + " " + currency.CurrencyCode);
writer.WriteElementString("g", "sale_price", _googleNamespace, price.FormatInvariant() + " " + currency.CurrencyCode);
writer.WriteElementString("g", "sale_price_effective_date", _googleNamespace, specialPriceDate);

// get regular price
// get regular price ignoring any special price
decimal specialPrice = product.SpecialPrice.Value;
product.SpecialPrice = null;
priceBase = _priceCalculationService.GetFinalPrice(product, null, _workContext.CurrentCustomer, decimal.Zero, true, 1);
price = Helper.GetProductPrice(product, currency);
product.SpecialPrice = specialPrice;
price = Helper.ConvertFromStoreCurrency(priceBase, currency);

_dbContext.SetToUnchanged<Product>(product);
}

writer.WriteElementString("g", "price", _googleNamespace, Helper.DecimalUsFormat(price) + " " + currency.CurrencyCode);
writer.WriteElementString("g", "price", _googleNamespace, price.FormatInvariant() + " " + currency.CurrencyCode);

writer.WriteCData("gtin", product.Gtin, "g", _googleNamespace);
writer.WriteCData("brand", brand, "g", _googleNamespace);
Expand All @@ -403,7 +394,7 @@ private string WriteItem(XmlWriter writer, Store store, Product product, Currenc

if (Settings.ExportShipping)
{
string weightInfo, weight = Helper.DecimalUsFormat(product.Weight);
string weightInfo, weight = product.Weight.FormatInvariant();

if (measureWeightSystemKey.IsCaseInsensitiveEqual("gram"))
weightInfo = weight + " g";
Expand All @@ -423,7 +414,7 @@ private string WriteItem(XmlWriter writer, Store store, Product product, Currenc

if (BasePriceSupported(product.BasePriceBaseAmount ?? 0, measureUnit))
{
string basePriceMeasure = "{0} {1}".FormatWith(Helper.DecimalUsFormat(product.BasePriceAmount ?? decimal.Zero), measureUnit);
string basePriceMeasure = "{0} {1}".FormatWith((product.BasePriceAmount ?? decimal.Zero).FormatInvariant(), measureUnit);
string basePriceBaseMeasure = "{0} {1}".FormatWith(product.BasePriceBaseAmount, measureUnit);

writer.WriteElementString("g", "unit_pricing_measure", _googleNamespace, basePriceMeasure);
Expand Down

0 comments on commit 95a1913

Please sign in to comment.