čtvrtek 11. září 2025

NopCommerce Vlastní plugin

 Vytvoření pluginu

Založení nového projektu s pluginem




Projekty pluginů jsou uloženy ve složce Plugins.
Zbuildovaný plugin se ale PostBuild stepem přenáší do pložky Plugins v projektu Nop.Web

Nastavení projektu

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <Copyright>Copyright © Tyrion SW, s.r.o.</Copyright>
    <Company>Tyrion SW, s.r.o.</Company>
    <Authors>Tyrion SW, s.r.o.</Authors>
    <PackageLicenseUrl></PackageLicenseUrl>
    <OutputPath>..\..\Presentation\Nop.Web\Plugins\Payments.ComGate</OutputPath>
    <OutDir>$(OutputPath)</OutDir>
    <CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
  </PropertyGroup>
...

...
<ItemGroup>
    <ProjectReference Include="..\..\Presentation\Nop.Web.Framework\Nop.Web.Framework.csproj" />
    <ClearPluginAssemblies Include="$(MSBuildProjectDirectory)\..\..\Build\ClearPluginAssemblies.proj" />
  </ItemGroup>


  <!-- This target execute after "Build" target -->
  <Target Name="NopTarget" AfterTargets="Build">
    <!-- Delete unnecessary libraries from plugins path -->
    <MSBuild Projects="@(ClearPluginAssemblies)" Properties="PluginPath=$(MSBuildProjectDirectory)\$(OutDir)" Targets="NopClear" />
  </Target>

Reference na Framework

Aby byla v projektu dostupná funkcionaliza NopCommerce je potřeba přidat rteferenci na projekt Nop.Web.Framework. V něm se například nachází třída BasePlugin ze které budeme náš nový plugin dědit.

plugin.json


logo.png

Logo se potom zobrazuje v seznamu pluginů v administraci NopCommerce a u platebních metod jako logo platební metody

Nastavení vlastností souborů

Jak plugin.json tak i logo.png musí mít nastaveny vlastnosti 



Třída pluginu



Administrace / Configuration / Local plugins


Controller


public ActionResult Index2()
        {
            return new ContentResult() { Content="Ahoj" };
        }

public ActionResult Index()
        {
            return View("~/Plugins/Payments.Test/Views/Index.cshtml");
        }

Konfigurace


return $"{_webHelper.GetStoreLocation()}Admin/PaymentComGate/Configure";

Routing

https://docs.nopcommerce.com/en/developer/tutorials/guide-to-creating-a-page-containing-a-reporting-table-of-datatables.html
public partial class RouteProvider : IRouteProvider
    {
        /// <summary>
        /// Register routes
        /// </summary>
        /// <param name="endpointRouteBuilder">Route builder</param>
        public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
        {
            
            endpointRouteBuilder.MapControllerRoute("Plugin.Payments.Test.Index", "Plugins/Test/Index",
                 new { controller = "Test", action = "Index" });

            endpointRouteBuilder.MapControllerRoute("Plugin.Payments.Test.Generator", "Admin/Test/Generator",
                 new { controller = "Test", action = "Generator" });


        }

        /// <summary>
        /// Gets a priority of route provider
        /// </summary>
        public int Priority => -1;
    }

Menu položka

Views





Zdroj:

Make.com - zpracování vícestránkové odpovědi

 Make.com - zpracování vícestránkové odpovědi

Pokud HTTP response vrací vícestránkovou odpověď, je potřeba ji zpracovat v cyklu a projít všechny stránky.
To není úplně jednoduché realizovat na platformě Make, pokud odpověď neobsahuje počet stránek, ale pouze odkaz na další stránku. např. takto: 

Mně se zatím jako jediný osvědčil tento scénář:

  • Vytvořit proměnné done a ContinuationToken.

  • Ty následně načíst a použít ve volání HTTP requestu.

  • Po HTTP requestu znovu nastavit proměnné v závislosti na odpovědi.

  • Poté zpracovat data z odpovědi iterátorem.

  • Před HTTP requestem je nastavený filtr na done != true a na true se proměnná done nastaví, pokud se v odpovědi vrátí ContinuationToken = null.





pondělí 21. července 2025

Make.com konverze času na desetinné číslo

Hodnotu ve formátu 12:30:30 převede na desetinné číslo 12.508333333333333 v hodinách

V proměnné 2.YourTimeVariable mám uložený čas 12:30:30

Funkce v prostředí Make.com

{{(parseNumber(get(split(2.YourTimeVariable; ":"); 1); )) + (parseNumber(get(split(2.YourTimeVariable; ":"); 2); ) / 60) + (parseDate(get(split(2.YourTimeVariable; ":"); 3); ) / 3600)}}


Vyzkoušej Make.com



Poznámka:

pro vkládání funkcí v editoru výrazu je potřeba je vyhledávat v nabídce, která se zobrazí po vložení znaku lomítka '/' 

Zápis je poněkud krkolomný a je potřeba si na něj zvyknout.

Matematické operace je potřeba zadávat také přes znak lomeno


Druhá varianta



{{parseNumber(substring(1.cas; 0; 2); ) + (parseNumber(substring(1.cas; 3; 5); ) /60 ) + (parseNumber(substring(1.cas; 6; 8); ) /3600) }}



 

středa 23. listopadu 2022

pondělí 1. srpna 2022

NopCommerce Payment Plugin


Components

One or more errors occurred. (A view component named 'PaymentComGate' could not be found. A view component must be a public non-abstract class, not contain any generic parameters, and either be decorated with 'ViewComponentAttribute' or have a class name ending with the 'ViewComponent' suffix. A view component must not be decorated with 'NonViewComponentAttribute'.)

Nebo

One or more errors occurred. (A view component named 'PaymentBesteron' could not be found. A view component must be a public non-abstract class, not contain any generic parameters, and either be decorated with 'ViewComponentAttribute' or have a class name ending with the 'ViewComponent' suffix. A view component must not be decorated with 'NonViewComponentAttribute'.)


Řešení

 namespace Nop.Plugin.Payments.{NázevSlužby}.Components
{

          [ViewComponent(Name = "Payment{NázevSlužby}")]

 public class Payment{NázevSlužby}ViewComponent : NopViewComponent
    {
        public IViewComponentResult Invoke()
        {
            return View("~/Plugins/Payments.{NázevSlužby}/Views/PaymentInfo.cshtml");
        }
    }

            } 

Souvisí s metodou GetPublicViewComponentName ve třídě {NázevSlužby}PaymentProceser

/// <summary>
/// Gets a name of a view component for displaying plugin in public store ("payment info" checkout step)
/// </summary>
/// <returns>View component name</returns>
public string GetPublicViewComponentName()
{
return "Payment{NázevSlužby}";
}

 

Services

Služby které jsou využívány v konstruktorech je potřeba nejprve zaregistrovat tak aby je IOC mohl nalézt. Registrují se ve třídě NopStartup ve složce Infrastructure
Pokud je použijete bez registrace tak Vám pravděpodobně nepůjde plugin ani nainstalovat a instalace skončí chybou ve smyslu že se nepodařilo nalézt vyhovující konstruktor.

Views

Configure.cshtml

Zobrazuje formulář v administraci kterým se nastavují údaje pro komunikaci s platební bránou. Například ID obchodníka

PaymentInfo.cshtml

Zobrazuje informace o tom že po dokončení objednávky budete přesměrování na platební bránu, nebo může obsahuvat formulář pro zadání doplňujících informací pro dokončení platby.

Zdroj:

čtvrtek 13. ledna 2022

Visual Studio nerozpozná nově přidanou třídu

 Po přidání nové třídy do projektu se VS chovalo jako kdyby nová třída vůbec přidaná nebyla.

Řešení:

Aktualizovat verzi knihovny "Microsoft.Net.Compilers" z verze 1.0.0 na alespoň 3.0.0

Zdroj:

https://developercommunity.visualstudio.com/t/cannot-navigate-to-the-symbol-under-the-caret-3/505489

čtvrtek 18. února 2021

Test ukazující funkci Distinct a SequenceEqual

[TestMethod]

public void Distinct_SequenceEqual()
{
// ARRANGE
var list1 = new List<string>() { "Karel", "Jan", "Jindra", "Jan"};
var list2 = new List<string>() { "Karel", "Jan", "Jindra" };

// ACT
var result = !list1.Distinct()
.SequenceEqual(list2);

// ASSERT
Assert.IsFalse(result);
}

úterý 29. prosince 2020

Home Assistant Vs Somfy a TaHoma

 Propojeni Google Home a Somfy samo o sobe neni v cechach zrovna jednoduche. Nejprve musite zmenit nastaveni jazyka a regionu na svem mobilnim telefonu na anglictinu. Protoze v cechach toto propojeni neni podporovano.

Potom co obe sluzby propojite se vam sice do Google home dosynchronizuji vsechny mistnosti a zarizeni (rolety, zaluzie, ...) Ale z aplikace Google home je nemuzete nijak primo ovladat.

Ovladat rolety muzete stale jen z originalni aplikace somfy.

Ovladat je muzete pomoci hlasovych prikazu.

Hey Google open blinds

hey Google close blinds

hey Google close bedroom blinds 50%

Hey Google rotate bedroom blinds 20%


Rozhodne pri pojmenovani zarizeni v Somfy je dobry napad pojmenovat je anglicky. 

Take dobry napad je pojmenovat zarizeni tak aby jste dokazali jmeno spravne vyslovit.

Pokud si nastavite treba scenar ktery budete spoustet behem obedu a pojmenujete ho lunch.

Budete mit pravdepodobne nekdy problem ho aktivovat, protoze alespon v mem pripade Mel Google problem rozlisit jestli jsem rekl


Lunch, launch a lounge.






středa 11. listopadu 2020

Ukládání desetinných čísel ASP.NET MVC

 Validace hodnot formuláře pomocí knihovny jquery.validate.js

@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}


Vyžaduje pro čekou culture drobnou úpravu v _Layout.cshtml, která nahradí validační funkci pro desetinná čísla


<script type="text/javascript">

        $.validator.methods.number = function (value, element) {

            return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)?(?:,\d+)?$/.test(value);

       }

        $.validator.methods.range = function (value, element, param) {

            value = Number(value.toString().replace(',', '.'));

            return this.optional(element) || (value >= Number(param[0].toString().replace(',', '.')) && value <= Number(param[1].toString().replace(',', '.')));

        }


    </script>

neděle 27. září 2020

Přesmětování HTTP na HTTPS ve WebConfigu

Stačí do WebConfigu doplnit rewrite pravidlo do části  System.Webserver

<rewrite>
<rules>
<rule name="HTTP to HTTPS redirect" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="https://{HTTP_HOST}/{R:1}" />
</rule>
</rules>


 Zdroj:

https://napoveda.czechia.com/clanek/presmerovani-http-na-https/

středa 17. června 2020

Test přihlášení ASP stránky


class Program
    {
        public class SettingModel
        {
            public string Login { get; set; }
            public string Password { get; set; }
            public string Url { get; set; }
            public string Assert { get; set; }
        }

        public static SettingModel ParseCommandLineArguments(string[] args)
        {
            var result = new SettingModel();
            for( int n=0; n < args.Length; n++)
            {
                switch (args[n].ToLower()) 
                {
                    case "-l":
                        result.Login = args[++n];
                        break;

                    case "-p":
                        result.Password = args[++n];
                        break;

                    case "-u":
                        result.Url = args[++n];
                        break;

                    case "-a":
                        result.Assert = args[++n];
                        break;
                }
            }

            return result;
        }

        static void Main(string[] args)
        {
            var model = ParseCommandLineArguments(args);

            Uri baseUri = new Uri(model.Url);
            //HttpClientHandler handler = new HttpClientHandler();
            //handler.CookieContainer = new CookieContainer();
            //HttpClient client = new HttpClient(handler);
            using (HttpClient client = new HttpClient()) 
            { 
                var getRequest = client.GetAsync(baseUri);
                getRequest.Wait();
                HttpResponseMessage response = getRequest.Result;

                //CookieCollection collection = handler.CookieContainer.GetCookies(uri); // Retrieving a Cookie
                var htmlPage = response.Content.ReadAsStringAsync();
                htmlPage.Wait();

                var html = htmlPage.Result;
                var reg = Regex.Match(html, "<input name=\"__RequestVerificationToken\" type=\"hidden\" value=\"(.*)\" />");
                if (reg.Success)
                {
                    var regexGroups = reg.Groups;

                    var formVariables = new List<KeyValuePair<string, string>>();
                    formVariables.Add(new KeyValuePair<string, string>("login", model.Login));
                    formVariables.Add(new KeyValuePair<string, string>("password", model.Password));
                    formVariables.Add(new KeyValuePair<string, string>("__RequestVerificationToken", regexGroups[1].Value));
                    var loginFormData = new FormUrlEncodedContent(formVariables);

                    var postRequest = client.PostAsync(baseUri, loginFormData);
                    postRequest.Wait();
                    var postResult = postRequest.Result;

                    var dashboardHtmlPage = postResult.Content.ReadAsStringAsync();
                    htmlPage.Wait();
                    var htmlToAssert = dashboardHtmlPage.Result;

                    Assert(model.Assert, htmlToAssert);
                }
            }
        }

        private static void Assert(string assertString, string htmlToAssert)
        {
            if (htmlToAssert.Contains(assertString)) // "/KlientskaZona/ProfilSpolecnosti/ProfilSpolecnosti"))
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("Success");
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Failed");
            }
        }
    }

úterý 19. listopadu 2019

Integrace platební brány ComGate

Co je důležité implementovat
Je potřeba implementovat vytvoření platby na pozadí. Které Vám vrátí adresu kam přesměrovat klienta.
Dále pak implementovat tři návratové stránky kam je přesměrován klient v případě že: 
  • je platba uhrazena. 
  • byla platba zrušena. 
  • platba byla provedena ale čeká se na její ověření.

A jako poslední implementovat handler, který provolá brána v okamžiku kdy se změní stav platby.
V tomto handleru je dobrý nápad porovnat jestli se s vámi baví někdo kdo zná vaše  merchant=12345678 a secret=ZXhhbXBsZS5jb206QUJDeHl6 tedy server ComGate a jestli požadavek přichází z IP která patří Comgate bráně tedy IP adresa 89.185.236.55
Dále pak porovnat jestli už nebyla platba uhrazena dříve aby jste zboží neposlali třeba několikrát.


Chyby
comgate 1400: Unauthorized access!
Pokud se Vám vrací tato chyba, zkontrolujte:
Jestli máte správně vyplněny parametry merchant a secret
Jestli v požadavku na generování platby na pozadí zasíláte parametr PrepareOnly = true,

pátek 18. října 2019

Povolení migrací EF vyhazuje chybu "Cannot bind argument to parameter 'Path'"


PM> Enable-Migrations
Enable-Migrations : Cannot bind argument to parameter 'Path' because it is null.
At line:1 char:1
+ Enable-Migrations
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Enable-Migrations], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Enable-Migrations


Řešení
I get it fixed by setting the project containing DbContext as the Startup Project


Zdroj:
https://github.com/aspnet/EntityFramework6/issues/492

pondělí 7. října 2019

Fotogalerie v klávesnici EZS Paradox TM70

8 – ZOBRAZOVÁNÍ FOTOGRAFIÍ
Klávesnici je možné využít jako jednoduchý fotorámeček. Po čase klidu je možné nastavit
zobrazování fotografií umístěných na SD kartě.
Pro zobrazování obrázků musí být vložena paměťová SD karta. Karta musí mít velikost
minimálně 4GB. Karta musí být naformátována v režimu FAT32. Soubory s
obrázky musí být na kartě uloženy v adresáři photo. Na kartu je možné uložit maximálně
512 fotografií.
Fotografie musí být ve formátu BMP a mít rozlišení 800 x 480 v 32 bitové barevné hloubce.

Pokud vyndáte SD kartu nahrajete fotky a zase ji vrátíte zpátky tak se fotky nezobrazí, je potřeba klávesnici odpojit od napájení a nechat ji restartovat. Na jiný způsob jsem nepřišel.

pondělí 23. září 2019

sobota 20. července 2019

Chybová hláška při vytváření migrace Entity Framewok Code First

One or more validation errors were detected during model generation:
Esu.WebPortal.Dal.Foo: : EntityType 'Foo' has no key defined. Define the key for this EntityType.
Foos: EntityType: EntitySet 'Foos' is based on type 'Foo' that has no keys defined.

Pokud přidáte do entity property, která není skalárního typu jako např. string nebo int. Vytvoří se vrámci této entity všechny property daného typu s prefixem podle názvu property tohoto typu.

Pokud ale daný typ obsahuje také property neskalárního typu. Entity Framework se s tímto nevyrovná a chce po Vás aby jste doplnil Primární klíč.

Řešením je smířit se s tím že takové zanoření není možné a property s nejnižší úrovně posunout o úroveň víš.

středa 6. března 2019

SVN a Visual Studio

Pro Visual Studio 2017 existuje extension pro SVN

Je potřeba instalovat TortoiseSVN a VisualSVN Extension


pondělí 18. února 2019

MS SQL a FOR cyklus

MS SQL nemá konstrukci pro cyklus FOR. Namísto ní se podmínka rozepíše do cyklu WHILE. Například nějak takto:
declare @n int = 2
WHILE (@n > 0)
BEGIN
   print @n;
   set @n = @n-1;
END  

Zdroj:
https://docs.microsoft.com/en-us/sql/t-sql/language-elements/while-transact-sql?view=sql-server-2017