In questa guida saranno evidenziati in rosso tutti i file del core di Nop che verranno toccati.
Operazioni sul DB
Creare un dump del database di produzione (Nop 4.3)
Ripristinarlo
Per ripristinare l'utente wmuser è necessario disassociarlo dal catalogo fulltext
Da SQL Management Aprire Storage -> Fulltext Catalogs -> nopCommerceFullTextCatalog, nella tab General impostare come Owner => dbo
Eliminare l'utente wmuser
Ri-mappare l'utente wmuser sul database nuovo
Aprire di nuovo Storage -> Fulltext Catalogs -> nopCommerceFullTextCatalog, nella tab General inserire come Owner => wmuser
Aprire di nuovo Storage -> Fulltext Catalogs -> nopCommerceFullTextCatalog, nella tab Tables/Views, pannello Eligible columns impostare italian per tutti i campi
Configurazione della Solution
Aggiornare i file Presentation\Nop.Web\App_Data\dataSettings.json e Presentation\Nop.Web\App_Data\appsettings.json
Copiare i plugin di terze parti nella cartella Plugins\Nop.Plugin.Compiled
Aggiungere il seguente codice nei build events => post build event progetto Nop.Web
Addare alla Solution (cartella Libraries) i progetti GenericUtilites, WM4Search, WM_Core e USO
Runnando la Solution dovrebbe partire con tutti i plugin disabilitati. Una volta entrati in admin è possibile vederli dall'elenco e installarli.
Non ci saranno tutti i plugin, in tal caso cliccare su ricaricare la lista di plugin, la soluzione si chiuderà da sola, ma al successivo login la lista dovrebbe essere aggiornata.
Aggiornare tutti i pacchetti nuGet della Solution che abbiano un update minor (dalla seconda cifra in poi)
Creazione di IWMCoreModelFactory per le chiamate alla WMCore.
INTERFACCIA: creare Presentation\Nop.Web\Factories\IWMCoreModelFactory.cs così
BINDING: comunicare la sua esistenza al framework modificando Presentation\Nop.Web\Startup.cs aggiungendo una riga a ConfigureServices() così
publicvoidConfigureServices(IServiceCollectionservices){// aggiunta di IWMCoreModelFactoryservices.AddSingleton<IWMCoreModelFactory,WMCoreModelFactory>();services.ConfigureApplicationServices(_configuration,_webHostEnvironment);}
Inserimento di UsoUtilitiesController uguale a quello precedente con la differenza che le chiamate a services sono diventate tutte ASYNC e perciò il trucco è aggiungere al fondo .Result per le variabili o .Wait() per i metodi come ad esempio
Cambiare le regole di rewrite, i prodotti sotto /catalogo-prodotti , le categorie sotto /catalogo e i cataloghi sotto /brand
Modificare in Nop.Web\Infrastructure\GenericUrlRouteProvider.cs
usingMicrosoft.AspNetCore.Builder;usingMicrosoft.AspNetCore.Routing;usingNop.Data;usingNop.Web.Framework.Mvc.Routing;namespaceNop.Web.Infrastructure{/// <summary>/// Represents provider that provided generic routes/// </summary>publicpartialclassGenericUrlRouteProvider:BaseRouteProvider,IRouteProvider{#region Methods/// <summary>/// Register routes/// </summary>/// <param name="endpointRouteBuilder">Route builder</param>publicvoidRegisterRoutes(IEndpointRouteBuilderendpointRouteBuilder){varlang=GetLanguageRoutePattern();#region WEBMOBILIstringconstProducts="catalogo-prodotti";stringconstCategories="catalogo";stringconstManufacturers="brand";#endregion//default routes//these routes are not generic, they are just default to map requests that don't match other patterns, //but we define them here since this route provider is with the lowest priority, to allow to add additional routes before themif(!string.IsNullOrEmpty(lang)){endpointRouteBuilder.MapControllerRoute(name:"DefaultWithLanguageCode",pattern:$"{lang}/{{controller=Home}}/{{action=Index}}/{{id?}}");}endpointRouteBuilder.MapControllerRoute(name:"Default",pattern:"{controller=Home}/{action=Index}/{id?}");if(!DataSettingsManager.IsDatabaseInstalled())return;//generic routesvargenericPattern=$"{lang}/{{SeName}}";#region WEBMOBILIendpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(constProducts+"/{SeName}");endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(constCategories+"/{SeName}");endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(constManufacturers+"/{SeName}");#endregionendpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(genericPattern);endpointRouteBuilder.MapControllerRoute(name:"GenericUrl",pattern:"{genericSeName}",defaults:new{controller="Common",action="GenericUrl"});endpointRouteBuilder.MapControllerRoute(name:"GenericUrlWithParameter",pattern:"{genericSeName}/{genericParameter}",defaults:new{controller="Common",action="GenericUrl"});endpointRouteBuilder.MapControllerRoute(name:"Product",pattern:$"{lang}/{constProducts}/{{SeName}}",defaults:new{controller="Product",action="ProductDetails"});endpointRouteBuilder.MapControllerRoute(name:"Category",pattern:$"{lang}/{constCategories}/{{SeName}}",defaults:new{controller="Catalog",action="Category"});endpointRouteBuilder.MapControllerRoute(name:"Manufacturer",pattern:$"{lang}/{constManufacturers}/{{SeName}}",defaults:new{controller="Catalog",action="Manufacturer"});endpointRouteBuilder.MapControllerRoute(name:"Vendor",pattern:genericPattern,defaults:new{controller="Catalog",action="Vendor"});endpointRouteBuilder.MapControllerRoute(name:"NewsItem",pattern:genericPattern,defaults:new{controller="News",action="NewsItem"});endpointRouteBuilder.MapControllerRoute(name:"BlogPost",pattern:genericPattern,defaults:new{controller="Blog",action="BlogPost"});endpointRouteBuilder.MapControllerRoute(name:"Topic",pattern:genericPattern,defaults:new{controller="Topic",action="TopicDetails"});endpointRouteBuilder.MapControllerRoute(name:"ProductsByTag",pattern:genericPattern,defaults:new{controller="Catalog",action="ProductsByTag"});}#endregion#region Properties/// <summary>/// Gets a priority of route provider/// </summary>/// <remarks>/// it should be the last route. we do not set it to -int.MaxValue so it could be overridden (if required)/// </remarks>publicintPriority=>-1000000;#endregion}}
Prodotto
Aggiunta metodi frmt() di utilità nelle viste per restituire decimali in Nop.Web\Extensions\HtmlExtensions.cs:
/// Restituisce (come stringa) il numero decimale specificato inserendo il punto/// ogni tre cifre. I numeri decimali sono limitati a 2/// </summary>/// <param name="val">Un decimal</param>/// <returns>Il numero nella forma mmm.kkk.uuu,dd</returns>publicstaticstringfrmt(thisdecimalval){varci=newCultureInfo("it-IT");ci.NumberFormat.NumberDecimalDigits=2;returnval.ToString("N",ci);}/// Restituisce (come stringa) il numero intero specificato inserendo il punto/// ogni tre cifre./// </summary>/// <param name="val">Un decimal</param>/// <returns>Il numero nella forma mmm.kkk.uuu,dd</returns>publicstaticstringfrmt(thisintval){varci=newCultureInfo("it-IT");ci.NumberFormat.NumberDecimalDigits=2;returnval.ToString("N",ci);}
Nel modello del prodotto in Nop.Web\Models\Catalog\ProductDetailsModel.cs aggiungere:
#region WEBMOBILI/// <summary>/// Nella nostra struttura c'è sempre un solo manufacturer per prodotto. Questa property lo restituisce./// In caso di manufacturer non settato (errore di dati) restituisce un manu vuoto per evitare una NullPointerException/// </summary>publicManufacturerBriefInfoModelManufacturer{get{if(ProductManufacturers.Count>0){returnProductManufacturers[0];}returnnewManufacturerBriefInfoModel{Name="",SeName="",IsActive=false};}}publicstringShopCity{get;set;}publicdecimalAdditionalShippingCharge{get;set;}#endregion
ProductController: al momento dichiarata l'istanza dell'interfaccia IWMCoreModelFactory, ma non utilizzata, i campi necessari sono stati aggiunti direttamente nel modello del prodotto, aggiungiamo quindi solo questa istruzione nel metodo ProductDetails(int productId, int updatecartitemid = 0):
#region WEBMOBILImodel.AdditionalShippingCharge=product.AdditionalShippingCharge;// spese di spedizione da stampare in frontend#endregion
Nella vista del prodotto, copiare la vista del tema base Nop.Web\Views\Product\_DeliveryInfo.cs in Nop.Web\Themes\Brooklyn\Views\Product\_DeliveryInfo.cs e modificarla così:
Per cambiare l'immagine in alto a sinistra bisogna sovrascriverla qui P:\DesignbestCommerce3\Presentation\Nop.Web\wwwroot\css\admin\images per 2 versioni del menu(compatto e non) logo.png 250x57 e logo-mini.png
Home - Vendor
Nascondere il pulsante Visualizza nei best seller(un Vendor non deve entrare nella pagina di modifica del prodotto lato NOP), bisogna commentare l'ultima ColumnProperty in queste 2 viste:
Nop.Web\Areas\Admin\Views\Home\_BestsellersBriefReportByAmount.cshtml e
Nop.Web\Areas\Admin\Views\Home\_BestsellersBriefReportByQuantity.cshtml
Vendite - Ordini del Cliente
Nascondere il filtro Magazzino (aggiungere la classe d-none), altrimenti un vendor potrebbe vedere le vendite degli altri vendor, vista da modificare Nop.Web\Areas\Admin\Views\Order\List.cshtml.
Nel box dove sono elencati i prodotti, il link del prodotti rimanderà alla scheda del prodotto nel frontend, mentre solo se siamo Admin entreremo nell'edit del prodotto di NOP modificare in Nop.Web\Areas\Admin\Views\Order\_OrderDetails.Products.cshtml
Dobbiamo recuperare il VendorID del dropship di Webmobili:
<em>@if(!Model.IsLoggedInAsVendor){<aasp-controller="Product"asp-action="Edit"asp-route-id="@item.ProductId">@item.ProductName</a>}else{<ahref="@Url.RouteUrl("Product", new { SeName = item.ProductSeoName })"target="_blank">@item.ProductName</a>}</em>
Se il vendorID è quello di Webmobili-dropship mostro il pulsante CLONA e ASSEGNA a RIVENDITORE. Attenzione il metodo è cambiato da code>prodService.GetProductById(item.ProductId).VendorId a GetProductByIdAsync:
Il pulsante CLONA e ASSEGNA a RIVENDITORE' apre un modale in cui selezionare il rivenditore, innanzitutto dobbiamo creare la vista/componente del modale ProductToVendorModal. Creiamo il componente in Nop.Web\Areas\Admin\Components\ProductToVendorModal.cs così:
Torniamo nella pagina contenitore di dettaglio dell'ordine in Nop.Web\Areas\Admin\Views\Order\Edit.cshtml e inseriamo al fondo la chiamata al nostro component modale appena creato con questa riga di codice:
Durante il test di acquisto di prodotto DesignbestShop, in fase di selezione della spedizione
non ci sono opzioni e rimane lì e non avanza, probabilmente per assenza plugin spedizione.