Szablony dla zaawansowanych

Silnik szablonów graficznych

Liquid to nowy silnik szablonów graficznych, dostępny w Comarch e-Sklep, który pozwala swobodnie modyfikować interfejs sklepu internetowego. Wykorzystuje kombinacje instrukcji, obiektów, filtrów i akcji aby dynamicznie budować strukturę strony. Dzięki silnikowi Liquid można w dowolny sposób budować listę towarów, szczegóły produktu, proces zamówienia oraz wiele innych elementów dostępnych w Comarch e-Sklep. Poniżej przedstawione zostało kilka przykładów wykorzystania silnika Liquid. Wypisanie nazw produktów promocyjnych {% for product in newproducts.Products -%} {{ product.Name }} {% endfor -%}   Wyświetlenie obrazków zawartych w banerze {% for slide in config.Banners['slider'].Images -%} <img title="{{slide.Title}}" src="{{slide.Url}}" alt="{{slide.Alt}}" /> {% endfor -%}   Prosty formularz logowania <form method="POST" id="loginForm"> <input name="email" type="email" placeholder="Podaj email" required/> <input name="password" type="password" placeholder="Podaj hasło" required/> <input name="__csrf" type="hidden" value="{{ page.CSRF }}"/> <input name="__action" type="hidden" value="Customer/Login"/> <button type="submit">Zaloguj</button> </form>   Prosty formularz logowania z obsługą po stronie JavaScript <form method="POST" id="loginForm"> <input name="email" type="email" placeholder="Podaj email" required/> <input name="password" type="password" placeholder="Podaj hasło" required/> <input name="__csrf" type="hidden" value="{{ page.CSRF }}" required/> <button id="loginAction" type="submit">Zaloguj</button> </form> <script> $('#loginAction').on('click', function(){ var data = $('#loginForm').serializeArray(); data.push({name: "__action", value: "Customer/Login"}); $.post(location.href, data).then(function(response) { if(response.action.Result) { console.log('udało się zalogować') } else { console.log('nie udało się zalogować'); } }); }); </script>  
Wskazówka
W powyższym przykładzie wykorzystana została popularna biblioteka jQuery. Nie jest ona jednak konieczna by korzystać z silnika Liquid.

Składnia języka liquid

Składnia języka Liquid

Rodzaje znaczników

Składnia silnika Liquid zawiera dwa typy znaczników. Znacznik wypisujący dane oraz znacznik sterujący. Znacznik wypisujący dane stosowany jest do wypisywania wartości zmiennych lub wyrażeń, również z zastosowaniem filtrów. {{customer.Email}} {{customer.Email | Upcase}} Filtry mogą przyjmować parametry, które podawane są wewnątrz znaczników wypisujących. {{3 | Plus: 3}} {{3 | Plus: 3 | Minus: 2}} Drugi typ znacznika jest stosowany dla operacji sterujących, m.in. instrukcji warunkowych, pętli itp. {% if customer.Authenticated -%} Gratuluję! Masz tutaj dostęp {% endif -%} {% unless customer.Company %} Nie jesteś firmą {% endunless %}
Uwaga
UWAGA W powyższym przypadku można zauważyć zamknięcie znacznika na dwa różne sposoby: z myślnikiem lub bez. Zalecane jest zamknięcie znacznika z użyciem myślnika, ponieważ instrukcja nie doda wtedy znaku nowej linii do kodu HTML. Jest to szczególnie ważne przy pętlach zawierających dużą ilość iteracji.

Operatory

= przypisanie
== równy
> większy
>= większy lub równy
< mniejszy
<= mniejszy lub równy
and koniunkcja
or alternatywa
!= różny
<> różny
contains zawiera ciąg
Wskazówka
Liquid nie posiada operatora negacji. Zamiast tego można skorzystać z instrukcji unless lub wyrażenia == false
Wskazówka
Liquid nie posiada operatorów arytmetycznych. Zamiast tego oferuje filtry: Plus, Minus, Times, DividedBy oraz Modulo.

Elementy silnika Liquid

Instrukcje sterujące

Instrukcje sterujące dodają do kodu HTML oraz CSS logikę charakterystyczną dla języków programowania. Wzbogacają statyczny kod strony o zmienne, instrukcje warunkowe, pętle oraz wstawki zewnętrznego fragmentu kodu.

Obiekty

Obiekty zawierają wszystkie dane sklepu internetowego. Można w nich znaleźć informacje dotyczące produktów, kategorii, konfiguracji sklepu oraz szablonu, a także dane klienta sklepu.
Wskazówka
Więcej na temat obiektów przeczytasz w artykule Dostępne obiekty.

Filtry

Filtry służą do formatowania danych oraz operacji arytmetycznych. Są używane w połączeniu z obiektami, aby zmienić sposób wyświetlania otrzymanych danych. {{config.Now}} {{config.Now | Date: "yyyy-MM-dd"}} {{config.Now | Date: "HH:mm"}} 2016-12-20 13:15:30 2016-12-20 13:15
Wskazówka
Więcej na temat filtrów można przeczytać w artykule Dostępne filtry

Akcje

Interfejs komunikuje się ze sklepem za pomocą akcji. Akcje aktualizują informacje w bazie danych oraz dane sesyjne. Można je zaimplementować za pomocą formularzy lub z użyciem zapytań AJAX. Proste logowanie utworzone za pomocą formularza <form id="loginForm" method="POST"> <input name="email" required="" type="email" placeholder="Podaj email" /> <input name="password" required="" type="password" placeholder="Podaj hasło" /> <input name="__csrf" type="hidden" value="{{ page.CSRF }}" /> <input name="__action" type="hidden" value="Customer/Login" /> <button type="submit">Zaloguj</button> </form> Proste logowanie napisane z użyciem zapytania AJAX <form id="loginForm" method="POST"> <input name="email" type="email" placeholder="Podaj email" required/> <input name="password" type="password" placeholder="Podaj hasło" required/> <input name="__csrf" type="hidden" value="{{ page.CSRF }}"/> <button id="loginAction" type="submit">Zaloguj</button> </form> <script> $('#loginAction').on('click', function(){ var data = $('#loginForm').serializeArray(); data.push({name: "__action", value: "Customer/Login"}); $.post(location.href, data).then(function(response){ if(response.action.Result) { console.log('udało się zalogować') } else { console.log('nie udało się zalogować'); } }); }); </script> Oprócz pól wymaganych przez akcję, każde zapytanie na serwer może zawierać parametry:
  • __collection – nazwa obiektu, który ma zostać zwrócony z serwera
  • __template – ścieżka pliku html, którego kod chcemy pobrać
  • __include – wartość zmiennej, jeżeli chcemy wstrzyknąć zmienną w pobrany kod html. Dozwolony jedynie typ prosty
Żaden z parametrów nie jest obowiązkowy, o ile nie wymaga go wykonywana akcja. Nic nie stoi na przeszkodzie, żeby pobrać sam obiekt, lub zwrócić tylko kod html. W odpowiedzi otrzymamy obiekt o parametrach:
  • action – informacje o rezultacie akcji lub null, jeżeli żadna akcja nie była wykonywana
  • collection – zwracany obiekt lub null, jeżeli żaden obiekt nie został zwrócony
  • template – kod html lub null, jeżeli żaden plik nie był pobierany
Parametr action może zawierać m.in. informacje o powodzeniu akcji, ewentualnym przekierowaniu oraz o rezultacie walidacji po stronie serwera. Dla przykładu, można następująco zmodyfikować skrypt odpowiedzialny za obsługę logowania: <script> $('#loginAction').on('click', function(){ var data = $('#loginForm').serializeArray(); data.push({name: "__action", value: "Customer/Login"}); $.post(location.href, data).then(function(response){ var actionResponse = response.action; console.log('Nazwa wykonanej akcji', actionResponse.Action); console.log('Czy wykonało się poprawnie?', actionResponse.Result); console.log('Rezultat walidacji serwerowej', JSON.stringify(actionResponse.Validation)); }); }); </script> Rezultat operacji w przypadku niepoprawnych danych wyglądać będzie następująco: Nazwa wykonanej akcji Customer/Login Czy wykonało się poprawnie? false Rezultat walidacji serwerowej [{ "Field":"email", "Error":"E-mail: Format jest nieprawidłowy" }] Natomiast zapytanie z poprawnymi danymi zrwóci: Nazwa wykonanej akcji Customer/Login Czy wykonało się poprawnie? true Rezultat walidacji serwerowej null Za pomocą jednego zapytania można pobrać wiele obiektów, oddzielając je znakami |. Nie zaleca się stosowania spacji między znakami, ponieważ znajdą się one w nazwie obiektów, co może generować niespodziewane błędy. $.get(location.href, {__collection:'page.Language|customer.Currency'}).then(function(response){ var objs = response.collection; console.log('Język', objs['page.Language']); console.log('Waluta', objs['customer.Currency']); }); Język pl Waluta PLN
Wskazówka
Więcej o akcjach możesz przeczytać w artykule Dostępne akcje.

Pliki szablonu

Pliki szablonu

Pliki szablonu dostępne są w panelu administracyjnym lub poprzez narzędzie Comarch e-Sklep Liquid Sync. W panelu sklepu należy przejść do sekcji Wygląd sklepu/Ustawienia w menu więcej należy wybrać opcję Edytuj ustawienia zaawansowane w tej sekcji ponownie wybieramy menu więcej i wybieramy opcję Edytuj HTML. W szablonie wykorzystywane są pliki:
  • z arkuszami stylów
  • graficzne
  • skryptów
  • pozostałe pliki
Pliki szablonu grupowane są katalogach systemowych oraz katalogach użytkownika. Dopuszczalne rozszerzenia plików:
  • z arkuszami stylów: .css
  • graficzne: .gif, .jpg, .jpeg, .png, .ico
  • skryptów: .js
  • pozostałe pliki: .htm, .html, .liquid
  Dopuszczalne znaki w nazwach plików:
  • liczby: 0-9
  • małe litery: a-z (bez znaków diaktrycznych)
  • znaki specjalne: łącznik, znak podkreślenia, kropka
  W trakcie wgrywania pliku z dysku duże litery znajdujące się w nazwach plików (i katalogów) zostaną automatycznie zamienione na małe litery. Znaki specjalne inne niż wskazane zostaną zamienione na znak podkreślenia.

Pliki w szablonie muszą być poprawnie kodowane. Kodowanie UTF-8 bez BOM. Pliki nie mogą zawierać znaków kontrolnych.

Nazwy plików i katalogów zaczynających się od „__” (dwa znaki podkreślenia) są zastrzeżone dla Comarch. Katalogi i pliki z taką nazwą pełnią specjalne funkcje w szablonie lub narzędziach do zarządzania szablonem.

Struktura katalogów

Katalogi „systemowe” Struktura katalogów „systemowych” w szablonie Pliki szablonu: 1 - Struktura katalogów systemowych W katalogu css należy dodać pliki z arkuszami stylów wykorzystywanych w szablonie. W katalogu css/img należy dodać pliki graficzne wykorzystywane w szablonie. W katalogu js należy dodać pliki skryptów wykorzystywane w szablonie. W katalogu ROOT należy dodać pozostałe pliki wykorzystywane w szablonie (strony, wstawki). Pliki szablonu: 2 - Katalog root

Pliki szablonu z arkuszami stylów, graficzne i skryptów muszą znajdować się we wskazanych powyżej katalogach. W przeciwnym wypadku nie będą poprawnie interpretowane przez przeglądarki internetowe.

Katalogi użytkownika Struktura katalogów użytkownika jest dowolna. Należy przestrzegać, by liczba poziomów zagnieżdżeń była ograniczona do niezbędnego minimum. Zbytnio rozbudowana struktura katalogów może nie być wspierana w narzędziu do synchronizacji szablonów. Dopuszczalne znaki w nazwach katalogów:
  • liczby: 0-9
  • małe litery: a-z (bez znaków diaktrycznych)
  • znaki specjalne: łącznik, znak podkreślenia
 

Pliki użytkownika w sklepie

W szablonie można korzystać z plików użytkownika (Katalog usr/*). Należy jednak mieć na uwadze, że pliki użytkownika:
  • nie będą importowane z pliku z szablonem stron
  • nie będą eksportowane do pliku z szablonem stron
W szablonie nie wolno korzystać z plików znajdujących się w katalogach:
  • Katalog App_Themes/
  • Katalog view/
  • Katalog scripts/
  • Katalog images/
  • Katalog t/
  • Katalog m/
  • Katalog fb/
  Katalogi te zawierają elementy wyglądu dotychczasowych szablonów (bez technologii Liquid).

Plik __settings.liquid

Plik __settings.liquid wykorzystywany jest do budowy interfejsu graficznego do zmiany ustawień szablonu.Plik ten przygotowuje autor szablonu.
Wymagania dla nakładki na ustawienia:
  • Nazwa pliku to __settings.liquid
  • Plik implementuje funkcję __SaveLiquidSettings(). Funkcja ta zwraca obiekt js, z którego zostaną zapisane ustawienia. Właściwości tego obiektu mogą zawierać tylko typy proste i tablice. Nie mogą natomiast zawierać obiektów.
__SaveLiquidSettings() Funkcja zwraca obiekt js, z którego zostaną zapisane ustawienia dla szablonu. Funkcja wywoływana jest automatycznie przy zapisie ustawień w panelu administracyjnym. Zapis ustawień w panelu odbywa się poprzez naciśnięcie przycisku ZapiszPliki szablonu: 3 - Przycisk zapisz. Funkcja ma zwracać wszystkie ustawienia, zarówno te zmienione oraz te niezmienione przez użytkownika. Przykład zawartości pliku __settings.liquid <style> .settings { height: 100px; width: 300px; border: solid 1px #000000; padding: 8px; margin: 8px; } </style> <div class="settings"> color1: <input name="color1" type="color" value="{{settings.color1}}" /> color2: <input name="color2" type="color" value="{{settings.color2}}" /> </div> <script> function __SaveLiquidSettings() { var o = {}; //zebranie wszystkich ustawień i zbudowanie z nich obiektu. //przykładowa implementacja: $(".settings input").each(function (el, el2) { o[el2.name] = el2.value; }); return o; } </script>

Liquid w wydrukach

Szablony wydruków

Comarch e-Sklep umożliwia kontrahentom drukowanie złożonych zamówień lub reklamacji. Szablony wydruków można tworzyć w panelu administracyjnym. Szczegółowy opis obszaru wydruków w panelu e-Sklep można znaleźć w artykule Wydruki, natomiast poniżej omówiony zostanie sposób tworzenia własnych szablonów wydruków za pomocą technologii HTML, CSS, oraz składni Liquid. Wydruk powinien posiadać konstrukcję typowej strony HTML, czyli zawierać wszystkie wymagane znaczniki HTML. Styl css powinien być umieszczony w pliku wydruku, bez ładowania z zewnątrz. W wydrukach można korzystać również z instrukcji sterujących, filtrów, oraz wybranych obiektów silnika Liquid.

Wydruk zamówienia

W wydruku zamówienia dostępne są dwa obiekty:
  • order
  • config
Order jest odpowiednikiem obiektu lokalnego customerprofile.Order, czyli obiektu przechowującego zamówienie w profilu klienta. Dokładny opis obiektu znajduje się w artykule Obiekty lokalne. Obiekt config jest opisany w artykule Obiekty globalne. Obiekty dostarczają do wydruku dane zamówienia, zamawiającego oraz sklepu.

Wydruk reklamacji i zwrotu

W wydruku reklamacji i zwortu są dostępne trzy obiekty: 
  • complaint
  • customer
  • config
Complaint jest odpowiednikiem obiektu lokalnego customerprofile.Complaint, który przechowuje zwrot lub reklamację w profilu klienta. Strukturę tego obiektu można zobaczyć w artykule Obiekty lokalne. Opis obiektów customer oraz config znajduje się w artykule Obiekty globalne. Obiekty zawierają dane reklamacji lub zwrotu, dane sklepu, oraz dane użytkownika składającego reklamację lub zwrot.

Przykład użycia

Poniżej przedstawiony został minimalistyczny przykład wydruku zamówienia.
<!DOCTYPE html> <html> <head> <title>Zamówienie nr {{ order.Id }} - {{ config.ShortName }} - {{ config.Url }}</title> </head> <style> html { font-size:14px; } body { font-family:Helvetica; } .print { font-size:1.5rem; color: #3F51B5; cursor:pointer; font-weight:700; } @media print { .print { display:none; } } </style> <body> <h1>Zamówienie nr {{ order.Id }}</h1> <p>{{ order.Date }}</p> <h2>Sprzedawca</h2> <p>{{ config.Shop.ShortName }}</p> <p>{{ config.Shop.Name }}</p> <h2>Nabywca:</h2> <p>{{ order.Customer.DeliveryAddress.Name }} {{ order.Customer.DeliveryAddress.Name2 }}</p> <h2>Dostawa i płatność</h2> <p> {{ order.Delivery.Name }} ({{ order.Delivery.TotalValue | ToPrice }} {{order.Currency}}), {{ order.Payment.Name }} ({{ order.Payment.TotalValue | ToPrice }} {{order.Currency}}), </p>    <h2>Produkty</h2> {% for poduct in order.Products -%} <p> {{ poduct.NameNoHtml }} | {{ poduct.Quantity }} x {{ poduct.TotalPrice|ToPrice }} {{order.Currency}} | {{ poduct.TotalValue|ToPrice }} {{order.Currency}} </p> {% endfor -%} <h2>Razem</h2> <p>{{order.OrderTotalValue | ToPrice}} {{order.Currency}}</p> <span class="print" onclick="window.print();"> Drukuj </span> </body> </html>  
Strona wydruku zamówienia będzie wyglądać w następujący sposób:Strona z wydrukiem zamówienia Podgląd wydruku w przeglądarce Chrome, który wyświetli się po klinięciu Drukuj, będzie wyglądał jak poniżej. Podgląd wydruku zamówienia

Obiekty globalne

Obiekty globalne dostępne są domyślnie na wszystkich stronach sklepu. Nie wymagają aktywacji.

Config

Obiekt udostępnia konfigurację sklepu. Nazwa zmiennej globalnej: config. Obiekt zawiera następujące właściwości:
config.Application config.Footer
config.AuthenticatedOnly config.GTM
config.B2B config.GTMHead
config.Banners.Nazwa config.Languages
config.CompanyOnly config.Lookbook
config.Complaints.Nazwa config.Messages.Nazwa
config.Contact config.Now
config.Countries.Nazwa config.Orders
config.Currencies config.Pages
config.DecimalPlacesPrice config.Products.Nazwa
config.DecimalSeparator config.Registration.Nazwa
config.DecimalThousandsSeparators config.Reviews.Nazwa
config.DefaultCountry config.Shop.Nazwa
config.DefinedPages.NazwaStrony config.Stock.Nazwa
config.ENTERPRISE config.TOS.Nazwa
config.External config.Tags.Nazwa
 

Page

Obiekt udostępnia informacje o aktualnej stronie. Nazwa zmiennej globalnej: page. Obiekt zawiera następujące właściwości:
page.BaseHref page.LinkNext
page.Breadcrumbs page.LinkPrev
page.CSRF page.MetaDescription
page.CanonicalLink page.MetaKeywords
page.Cookies page.MetaTitle
page.CurrentGroupNodes page.Objects
page.CurrentSiteNode.Nazwa page.POST
page.FbDL page.PageId
page.GET page.PageKey
page.GtmDL page.ParentSiteNode.Nazwa
page.GroupId page.ProductId
page.GroupNodes page.QueryString
page.HiddenPrices page.TemplateInclude
page.IsHttp404 page.TemplateName
page.Language page.Url
page.LanguageId page.UrlRaw
 

Usr

Obiekt udostępnia informacje o zalogowanym użytkowniku. Nazwa zmiennej globalnej: usr. Obiekt zawiera następujące właściwości:
usr.Authenticated usr.IsAdmin
usr.Email
 

Customer

Obiekt udostępnia informacje o kontrahencie w sklepie (jednorazowy lub zalogowany). Nazwa zmiennej globalnej: customer. Obiekt zawiera następujące właściwości:
customer.Address customer.Employee
customer.Attributes customer.HidePrices
customer.Authenticated customer.Invoice
customer.Cart customer.NewsletterSubscriber
customer.Carts customer.PaymentDueDays
customer.Companies customer.Points
customer.Company customer.PriceId
customer.CompanyErpId customer.ReviewAuthor
customer.CompanyId customer.SSN
customer.ComparisonToolItems customer.SubtotalPrices
customer.CreditLimit customer.Supervisor
customer.Currency customer.TIN
customer.CurrencyExt customer.UserId
customer.CustomerDetailsEditable customer.UserId32
customer.DeliveryAddress.Nazwa customer.VATEU
customer.Email customer.WishListCount
 

Currency

Obiekt udostępnia informacje o aktualnie wybranej walucie w sklepie (jest aliasem do właściwości customer.Currency). Nazwa zmiennej globalnej: currency.
Wskazówka
Obiekt ten nie posiada właściwości - zawsze zwraca on używaną walutę (string).
 

Translations

Obiekt udostępnia tłumaczenia fraz dostępne w sklepie. Nazwa zmiennej globalnej: translations.
Wskazówka
Każdy szablon zawiera standardowe tłumaczenia. Zawierają one Key(id) oraz wartość przypisaną danemu tłumaczeniu dla konkretnego języka.
 

Settings

Obiekt udostępnia ustawienia danego szablonu w sklepie. Nazwa zmiennej globalnej: settings. Użycie tego obiektu umożliwia dokonywanie pewnych zmian w sklepie bez ingerencji w kod (np. zmiana kolorów).
Wskazówka
Właściwości tego obiektu, można znaleźć w Panelu Administracyjnym w zakładce Ustawienia(JSON). Można je dodawać, edytować i usuwać bezpośrednio w tej zakładce, lub z poziomu graficznej nakładki, za którą odpowiada plik __settings.liquid.
 

 __action

Obiekt udostępnia informacje związane z wykonaną akcją. Nazwa zmiennej globalnej: __action. Dla akcji wykonywanych w AJAX nazwa obiektu: action.  

__actionGET

Obiekt udostępnia informacje związane z wykonaną akcją na podstawie parametrów przekazanych w linku. Link wysyłany jest mailem do użytkownika sklepu. Dotyczy akcji takich jak: aktywacja, deaktywacja newslettera, aktywacja konta, potwierdzenie zamówienia, itd. Nazwa zmiennej globalnej: __actionGET.  

 

Opis używanych obiektów globalnych:

 
config.Application
Obiekt (Object) zawiera informacje o używanej aplikacji. Właściwości:
  • Name (string) - nazwa oprogramowania,
  • Website (string) - adres z dodatkowymi informacjami.
 
 
config.AuthenticatedOnly
Pole (bool) - tylko zalogowani mają dostęp do sklepu.
 
 
config.B2B
Pole (bool) - sklep w wersji B2B.
 
 
config.Banners.Nazwa
Tablica obiektów (Object[]) - pojedynczy obiekt zawiera informacje o bannerze. Właściwości:
  • Images (Object[]) - pojedynczy obiekt zawiera informacje na temat użytego obrazu,   Właściwości:
    • Alt (string),
    • DateTill (string),
    • File (string),
    • Heading (string),
    • Id (int),
    • Link (string),
    • TargetBlank (bool),
    • Text (string),
    • Title (string),
    • Url (string).
  • Name (string) - nazwa banera,
  • TargetBlank (bool) - kliknięcie w baner z linkiem spowoduje otworzenie adresu w nowym oknie,
  • Type (string) - typ.
 
 
config.CompanyOnly
Pole (bool) - tylko firmy mają możliwość rejestracji.
 
 
config.Complaints.Nazwa
Obiekt (Object) zawiera informacje o ustawieniach związanych z reklamacjami. Właściwości:
  • AttachmentExtensions (string) - rozszerzenia załączonych plików,
  • AttachmentMaxSize (int) - maksymalny rozmiar pliku,
  • AttachmentEnabled (bool) - załączanie plików,
  • AttachmentMaxCount (int) - maksymalna ilość załączonych plików,
  • ComplaintsEnabled (bool) - składanie reklamacji,
  • DaysToReturn (int) - liczba dni na zwrot,
  • Defects (Object[]) - obiekt zawiera informacje na temat występującego defektu (np. wada konstrukcyjna),   Właściwości:
    • Id (int),
    • Name (string).
  • Requests (Object[]) - pojedynczy obiekt zawiera informacje na temat żądań związanych z przedmiotem (np. naprawa); analogicznie do Defects,
  • Returns (Object[]) - pojedynczy obiekt zawiera informacje na temat zwrotu; analogicznie do Defects,
  • ReturnsEnabled (bool) - zwrot towaru.
 
 
config.Contact
Obiekt (Object) zawiera informacje kontaktowe. Właściwości:
  • AttachmentExtensions (string) - rozszerzenia załączonych plików,
  • AttachmentMaxSize (int) - maksymalny rozmiar pliku,
  • AttachmentsEnabled (bool) - załączanie plików,
  • AttachmentsMaxCount (int) - maksymalna ilość załączonych plików,
  • Contacts (Object[]) - pojedynczy obiekt zawiera informacje na temat działu;.   Właściwości:
    • Id (int),
    • Name (string).
 
 
config.Countries.Nazwa
Tablica obiektów (Object[]) - pojedynczy obiekt zawiera informacje o ustawieniach danego kraju. Właściwości:
  • ISOCode (string) - kod kraju,
  • ISOCode3 (string) - kod kraju (3 znaki),
  • Name (string) - nazwa kraju,
  • RequiredFields (Object) - obiekt zawiera informacje odnośnie wymaganych pól,
  •   Właściwości:
    • City (bool),
    • Street (bool),
    • StreetNo (bool),
    • TIN (bool),
    • ZipCode (bool).
  • SSNRegex (string) - ustawienia Regex PESEL,
  • States (string[]) - spis województw,
  • TINRegex (string) - ustawienia Regex NIP,
  • ZipCodeFormat (string) - ustawienia kodu pocztowego,
  • ZipCodeRegex (string) - ustawienia Regex kodu pocztowego.
 
 
config.Currencies
Tablica obiektów (Object[]) - pojedynczy obiekt zawiera informacje o walutach. Właściwości:
  • BankAccount (Object) - obiekt zawiera informacje na temat konta bankowego,
    • AccountNumber (string) - numer konta,
    • Bank (string) - bank,
    • SWIFT (string) - numer KRS lub CEIDG, organ rejestrujący
  • Code (string) - kod waluty (np. EUR),
  • Symbol (string).
 
 
config.DecimalPlacesPrice
Pole (int) - ilość miejsc po przecinku dotyczących cen.
 
 
config.DecimalSeparator
Pole (string) - separator liczb dziesiętnych.
 
 
config.DecimalThousandsSeparators
Pole (string) - separator tysięczny (np. 5 600zł zamiast 5600zł).
 
 
config.DefaultCountry
Pole (string) - ustawiony kraj domyślny.
 
 
config.DefinedPages.NazwaStrony
Obiekt (Object) zawiera informacje o zdefiniowanych stronach. W skład stron wchodzą:
  • About (Object),
  • AdvancedSearch (Object),
  • Blog (Object),
  • BlogDetails (Object),
  • Brands (Object),
  • Complaints (Object),
  • Contact (Object),
  • ContinueShopping (Object),
  • CustomerProfile (Object),
  • Home (Object),
  • Http404 (Object),
  • Login (Object),
  • LookBook (Object),
  • Loyalty (Object),
  • Manufacturers (Object),
  • Order (Object),
  • PasswordReminder (Object),
  • Payment (Object),
  • Privacy (Object),
  • ProductComparisonTool (Object),
  • ProductDetails (Object),
  • ProductList (Object),
  • Registration (Object),
  • Shipping (Object),
  • Terms (Object),
  • UponLogging (Object),
  • WithdrawalRight (Object),
  • nonexistentgroup (Object),
  • nonexistentproduct (Object).
Każda strona posiada właściwości:
  • Name (string),
  • Heading,
  • Id (string),
  • Url (string).
 
 
config.ENTERPRISE
Pole (bool) - sklep w wersji Enterprise.
 
 
config.External
Obiekt (Object) zawiera informacje o integracjach z zewnętrznymi usługami. Właściwości:
  • Edrone (Object) - obiekt zawiera informacje komunikacyjne z systemem Edrone,   Właściwości:
    • AppId (string).
  • Facebook (Object) - obiekt zawiera informacje komunikacyjne z systemem Facebook,   Właściwości:
    • AppID (string).
  • Google (Object) - obiekt zawiera informacje komunikacyjne z systemem Google,   Właściwości:
    • ClientID (string).
  • SalesManago.
 
 
config.Footer
Obiekt (Object) zawiera informacje o stopce. Właściwości:
  • JoinUs (string[]) - pojedynczy łańcuch znakowy to link do portalu społecznościowego ustawiany w Panelu Administracyjnym,
  • Sections (Object[]) - pojedynczy obiekt zawiera informacje na temat stopki.   Właściwości:
    • Heading (string) - nagłówek,
    • Pages (Object[]) - pojedynczy obiekt zawiera informacje na temat odnośniku do stopki.
          Właściwości:
      • Heading - nagłówek,
      • Id (string) - id,
      • Name (string) - nazwa,
      • Url (string) - url.
 
 
config.GTM
Pole (string) - kod Google Tag Manager.
 
 
config.GTMHead
Pole (string) - kod Google Tag Manager umieszczany w sekcji 'head.
 
 
config.Languages
Obiekt (Object) zawiera informacje o ustawieniach wybranych języków. Właściwości:
  • Id (int) - id,
  • Language (string) - język,
  • Name (string) - nazwa.
 
 
config.Lookbook
Obiekt (Object) zawiera informacje o ustawieniach Lookbook. Właściwości:
  • Current,
  • List (Object[]).   Właściwości:
    • Images (Object[]) - pojedynczy obiekt zawiera informacje o obrazie,  
      • Alt (string),
      • DateTill (string),
      • File (string),
      • Heading (string),
      • Id (int),
      • JSON (string),
      • Link (string),
      • TargetBlank (bool),
      • Text (string),
      • Title (string),
      • Url (string).
    • Name (string),
    • TargetBlank (bool),
    • Text (string),
    • Type (string),
    • Url (string).
 
 
config.Messages.Nazwa
Tablica obiektów (Object[]) - pojedynczy obiekt zawiera informacje o wiadomości aplikacji. Może być wykorzystywany do wyświetlania treści, np. notyfikacja o wykorzystywaniu cookies. Właściwości:
  • Days (int) - liczba dni,
  • Id (string) - id,
  • Message (string) - treść,
  • Title (string) - tytuł,
  • Type (int) - typ,
  • Url (string) - adres Url.
 
 
config.Now
Pole (string) - obecny czas.
 
 
config.Orders
Obiekt (Object) zawiera informacje o atrybutach zamówienia. Właściwości:
  • AttachmentExtensions (string) - rozszerzenia załączonych plików,
  • AttachmentMaxSize (int) - maksymalny rozmiar pliku,
  • AttachmentEnabled (bool) - załączanie plików,
  • AttachmentMaxCount (int) - maksymalna ilość załączonych plików,
  • AttributesCart (Object) - obiekt zawiera informacje na temat atrybutów w zamówieniu,   Właściwości:
    • Header (Object[]) - pojedynczy obiekt zawiera informacje na temat atrybutu w nagłówku,   Właściwości:
      • Editable (bool) - edytowalność,
      • Format - rodzaj atrybutu,
      • Id - id,
      • Name (string) - nazwa,
      • Required (bool) - czy wymagany,
      • Values - wartości dla atrybutu typu lista.
    • Position (Object[]) - pojedynczy obiekt zawiera informacje na temat atrybutu na elemencie zamówienia; analogicznie do Header
  • AttributesEdit (Object) - obiekt zawiera informacje na temat atrybutów w profilu klienta na szczegółach zamówienia; analogicznie do AttributesCart
 
 
config.Pages
Obiekt (Objec) zawiera informacje o stronach użytych w sklepie. Właściwości:
  • Heading,
  • Id (string),
  • Name (string),
  • Url (string),
 
 
config.Products.Nazwa
Obiekt (Object) zawiera informacje o ustawieniach produktów. Właściwości:
  • ShowCode (bool) - wyświetlanie kodu produktu,
  • DecimalUnits (bool) - wyświetlanie wartości/liczb niecałkowitych.
 
 
config.Registration.Nazwa
Obiekt (Object) zawiera informacje o ustawieniach związanych z rejestracją. Właściwości:
  • AuthorizationRequired (bool) - wymagana autoryzacja,
  • Retail (Object) - obiekt zawiera informacje związane z rejestracją klienta prywatnego,   Właściwości:
    • AddressVisible (bool) - widoczny adres,
    • AddressRequired (bool) - wymagany adres,
    • PhoneVisible (bool) - widoczny telefon,
    • PhoneRequired (bool) - wymagany telefon.
  • Company (Object) - obiekt zawiera informacje związane z rejestracją klienta firmowego; analogicznie do Retail,
  • ConfirmationRequired (bool) - wymagane potwierdzenie,
  • Disabled (bool) - rejestracja,
  • ValidateTin (bool) - walidacja przy rejestracji.
 
 
config.Reviews.Nazwa
Obiekt (Object) zawiera informacje o ustawieniach odnośnie recenzji/opinii o towarze. Właściwości:
  • AuthenticationRequired (bool) - wymagane zalogowanie,
  • Enabled (bool) - recenzje,
  • OnlyPurchasedProducts (bool) - napisanie opinii/ocenianie tylko w przypadku kiedy produkt został wcześniej zakupiony,
  • Reviews (Object[])- pojedynczy obiekt zawiera informacje o ustawieniu systemu oceny,   Właściwości:
    • Rate (int) - ocena od 1 do 5,
    • Text (string) - opis słowny oceny.
 
 
config.Shop.Nazwa
Obiekt (Object) zawiera informacje o konfiguracji sklepu. Właściwości:
  • Address.Nazwa (Object) - obiekt zawiera informacje na temat konfiguracji danych adresowych sklepu,   Właściwości:
    • City (string),
    • Country (string),
    • Latitude (string),
    • Longitude (string),
    • State (string),
    • Street (string),
    • StreetNo (string),
    • UnitNo (string),
    • ZipCode (string).
  • Contact.Nazwa - obiekt zawiera informacje na temat kongifuracji danych kontaktowych sklepu,   Właściwości:
    • Email (string),
    • Fax (string),
    • GG (string),
    • GSM (string),
    • PhoneNo (string),
    • PhoneNo2 (string),
    • Skype (string),
  • Description (string) - opis sklepu,
  • ImageUrl (string) - nazwa użytego loga,
  • Name (string) - nazwa sklepu,
  • Registrant (string) - organ rejestrujący,
  • Regon (string) - numer Regon,
  • ShortName (string) - kod firmy,
  • TIN (string) - numer NIP,
 
 
config.Stock.Nazwa
Obiekt (Object) zawiera informacje o ustawieniach magazynowych. Właściwości:
  • Enabled (bool) - kontrola stanów magazynowych,
  • QuantityControl (bool) - kontrola ilości.
 
 
config.TOS.Nazwa
Obiekt (Object) zawiera informacje o zdefiniowanych treściach w Panelu Administracyjnym. Właściwości:
  • Consents (Object) - obiekt zawiera informacje na temat udzielonych zgód dla akcji,   Właściwości:
    • Newsletter (Object[]) - pojedynczy obiekt zawiera informacje na temat zgody (tablica dotyczy akceptacji polityki prywatności),   Właściwości:
      • Channels (Object[]),   Właściwości:
        • Id (int),
        • Key (string),
        • Name (string),
        • Type (int).
      • Contents,
      • Id (int),
      • PublishedDate (string),
      • Required (bool),
      • Statement (bool),
      • Text (string),
      • Type (string),
    • Order (Object[]) - pojedynczy obiekt zawiera informacje na temat zgody (tablica dotyczy odstąpienia od umowy); analogicznie do Newsletter,
    • Registration (Object[]) - pojedynczy obiekt zawiera informacje na temat zgody (tablica dotyczy otrzymywanie newslettera i akceptacji regulaminu); analogicznie do Newsletter,
    • Inquiries (Object[]) - pojedynczy obiekt zawiera informacje na temat zgody (tablica dotyczy zapytań ofertowych); analogicznie do Newsletter.
  • FormalContents.Nazwa (Object) - obiekt zawiera informacje wyświetlane na stronach, np. informacje o prawie do odstąpienia od umowy,   Właściwości:
    • About (Object),   Właściwości:
      • ContentHtml (string),
      • ContentPdfUrl,
      • Files,
      • Id (int),
      • Key (string),
      • Name (string),
      • PageId,
      • PublishedDate (string),
      • Type (int).
    • Complaints (Object); analogicznie do About,
    • Loyalty (Object), analogicznie do About,
    • Payment (Object), analogicznie do About,
    • Privacy (Object), analogicznie do About,
    • Shipping (Object), analogicznie do About,
    • Terms (Object), analogicznie do About,
    • WithdrawalRight (Object) analogicznie do About.
  • Pages.
 
 
config.Tags.Nazwa
Obiekt (Object) zawiera informacje o konfiguracji tagów. Właściwości:
  • Blog (Object[]) - pojedynczy obiekt zawiera informacje na temat tagu bloga,   Właściwości:
    • Text - nazwa,
    • Url - url do wszystkich postów z danym tagiem,
    • Weight - waga
  • Search (Object[]) - pojedynczy obiekt zawiera informacje na temat tagu wyszukiwania.
 
 
config.TemplateId
Pole (int) - id szablonu.
 
 
config.UniqueId
Pole (string) - unikalne id.
 
 
config.Url
Pole (string) - adres url sklepu.
 
 
config.VATEU
Obiekt (Object) zawiera informacje o konfiguracji VATEU. Właściwości:
  • ISOCode (string),
  • Name (string),
  • Value (string).
 
 
config.Version
Pole (string) - wersja sklepu.
 
 
page.BaseHref
Pole (string) - podstawowy adres strony (bez obecnej podstrony - jedynie główny odnośnik do strony głównej).
 
 
page.Breadcrumbs
Tablica obiektow (Object[]) - pojedynczy obiekt zawiera informacje o breadcrumbs danej strony. Właściwości:
  • Heading - nagłówek,
  • Id (string) - numer id,
  • Name (string) - nazwa,
  • Url (string) - adres url,
 
 
page.CSRF
Pole (string) - wygenerowany token.
 
 
page.CanonicalLink
Pole (string) - pełny adres strony, na której znajduje się użytkownik.
 
 
page.Cookies
Obiekt (Object) zawiera informacje o cookies.
 
 
page.CurrentGroupNodes
Obiekt (Object) zawiera informacje o kategorii.
 
 
page.CurrentSiteNode.Nazwa
Obiekt (Object) zawiera informacje o przeglądanej stronie. Właściwości:
  • Heading,
  • Id (string),
  • Name (string),
  • Url (string),
  • Count (int) - występuje w szczegółach towaru,
  • HasChildren (bool) - występuje w szczegółach towaru,
  • ImageId (int) - występuje w szczegółach towaru,
  • Image (Object) - obiekt zawiera informacje na temat zdjęcia; występuje w szczegółach towaru.   Właściwości:
    • ExternalUrl (string),
    • Id (int),
    • Link (string).
 
 
page.FbDL
Pole (string).
 
 
page.GET
Obiekt (Object) zawiera informacje pobrane GETem.
 
 
page.GtmDL
Pole (string) - Google Tag Manager.
 
 
page.GroupId
Pole (int) - id grupy.
 
 
page.GroupNodes
Obiekt (Object) zawiera informacje o kategoriach dostępnych w sklepie. Właściwości:
  • Count (int),
  • HasChildren (bool),
  • Heading,
  • Id (string),
  • Image (Object) - obiekt zawiera informacje na temat zdjęcia,   Właściwości:
    • ExternalUrl (string),
    • Id (int),
    • Link (string).
  • ImageId (int),
  • Name (string),
  • Nodes (Object) - analogicznie do GroupNodes, lecz bez właściwości Nodes,
  • Url (string).
 
 
page.HiddenPrices
Pole (bool) - widoczna cena.
 
 
page.IsHttp404
Pole (bool) - zawiera informacje czy strona jest stroną błędu 404.
 
 
page.Language
Pole (string) - język strony.
 
 
page.LanguageId
Pole (int) - język strony.
 
 
page.LinkNext
Pole (string) - następna strona w historii przeglądarki.
 
 
page.LinkPrev
Pole (string) - poprzednia strona w historii przeglądarki.
 
 
page.MetaDescription
Pole (string) - meta-tagi użyte w tekście źródłowym strony.
 
 
page.MetaKeywords
Pole (string) - słowa kluczowe użyte na stronie.
 
 
page.MetaTitle
Pole (string) - tytuł strony.
 
 
page.Objects
Obiekt (Object) zawiera informacje o obiektach lokalnych dostępnych na stronie.
 
page.POST
Obiekt (Object) zawiera informacje o elementach wysłanych POSTem.
 
page.PageId
Pole (int) - id przeglądanej strony.
 
 
page.PageId
Pole (string).
 
 
page.ParentSiteNode.Nazwa
Obiekt (Object) zawiera informacje o stronie nadrzędnej do tej, którą obecnie przeglądamy. Właściwości:
  • Id (string) - numer id,
  • Name (string) - nazwa,
  • Heading - tytuł,
  • Url (string) - adres url.
 
 
page.ProductId
Pole (int) - id towaru (występuje na stronie ze szczegółami towaru).
 
 
page.QueryString
Pole (string) - zawartość GET z url (np. treść wpisana do wyszukiwarki).
 
 
page.TemplateInclude
Pole (string) - wartość wpisywana w PA dla konkretnej strony.
 
 
page.TemplateName
Pole (string) - nazwa pliku html.
 
 
page.Url
Pole (string) - adres url przeglądanej strony.
 
 
page.UrlRaw
Pole (string) - adres url przeglądanej strony wraz z dodatkowymi parametrami (takimi jak np. wyszukiwana fraza).
 
 
usr.Authenticated
Pole (bool) - zalogowany użytnownik.
 
 
usr.Email
Pole (string) - adres email użytkownika.
 
 
usr.IsAdmin
Pole (bool) - użytkownik z uprawnieniami administratora.
 
 
customer.Address
Obiekt (Object) zawiera informacje o adresie klienta. Właściwości:
  • City (string),
  • Country (string),
  • Email (string),
  • Name (string),
  • Name2 (string),
  • Name3 (string),
  • PhoneNo (string),
  • State (string),
  • StreetNo (string),
  • UnitNo (string),
  • ZipCode (string),
 
 
customer.Attributes
Obiekt (Object) zawiera informacje o atrybutach.
 
 
customer.Authenticated
Pole (bool) - zalogowany użytkownik.
 
 
customer.Cart
Obiekt (Object) zawiera informacje o przedmiotach w koszyku. Właściwości:
  • CartEmpty (bool) - pusty aktywny koszyk klienta,
  • Count (int) - liczba przedmiotów w koszyku,
  • Currency (string) - waluta,
  • CurrencyExt (Object),   Właściwości:
    • Code (string),
    • Symbol (string).
  • Discount (float) - zniżka,
  • EditedOrderId (int) - id zamówienia aktualnie edytowanego (występuje kiedy koszyk ma produkty),
  • Email (string) - adres email,
  • Id (int) - id koszyka,
  • Inquiry (bool) - zapytanie ofertowe (występuje kiedy koszyk ma produkty),
  • Products (Object[]),   Właściwości:
    • AskForPrice (bool) - zapytanie odnośnie ceny,
    • AskForPriceId,
    • Code (string) - kod produktu,
    • DecimalPlacesPrice (int),
    • DecimalUnit (bool) - liczby całkowite dla jednostek,
    • DefaultGroup (int) - domyślna grupa,
    • Description (string),
    • GIdNumber (int),
    • Id (int) - id przedmiotu,
    • Image (Object) - obiekt zawiera informacje na temat zdjęcia,   Własciwości:
      • ExternalUrl (string),
      • Id (int),
      • Link (string).
    • ImageId (int) - id obrazu,
    • IsSetElement (bool) - przedmiot elementem zestawu,
    • IsSetParent (bool) - przedmiot przedmiotem głównym,
    • Link (string) - link produktu,
    • NameNoHtml (string) - nazwa produktu (bez znaczników HTML),
    • No (int) - numer przedmiotu w koszyku,
    • Price (decimal) - cena,
    • Quantity (int) - ilość,
    • SaleUnit (string) - jednostka sprzedażowa (np. para),
    • SubtotalPrice (decimal) - cena bez VAT,
    • TotalPrice (decimal) - cena całkowita,
    • Url (string) - url produktu.
  • Saved (int) - oszczędność,
  • SubtotalPrices (bool) - stawka VAT w cenie,
  • Value (decimal) - wartość,
  • ValueBeforeDiscount (decimal) - wartość przed obniżką,
 
 
customer.Carts
Tablica obiektów (Object[]) - pojedynczy obiekt zawiera informacje o elemencie w liście koszyków. Właściwości:
  • Count (int) - ilość przedmiotów w koszyku,
  • Current (bool) - aktywny,
  • EditedOrderId (int) - id edytowanego zamówienia,
  • Id (int) - id koszyka,
  • Inquiry (bool) - zapytanie ofertowe,
  • Name (string) - nazwa.
 
 
customer.Companies
Obiekt (Object) zawiera informacje o firmie. Właściwości:
  • Default (bool),
  • Id (int),
  • Name (string),
  • Name2 (string).
 
 
customer.Company
Pole (bool) - posiadacz konta firmowego.
 
 
customer.CompanyErpId
Pole (int) - id firmy klienta (w ERP).
 
 
customer.CompanyId
Pole (int) - id.
 
 
customer.ComparisonToolItems
Pole - przedmioty przechowywane w porównywarce towarów.
 
 
customer.CreditLimit
Obiekt (Object) zawiera informacje o limicie kredytowym. Właściwości:
  • Active (bool),
  • Flag (int),
  • Left (decimal),
  • OverdueActive (bool),
  • OverdueLeft (decimal),
  • OverdueUsed (decimal,
  • OverdueValue (int),
  • Status (int),
  • StatusText (string),
  • Used (decimal),
  • Value (int).
 
 
customer.Currency
Pole (string) - waluta klienta.
 
 
customer.CurrencyExt
Obiekt (Object). Właściwości:
  • Code (string),
  • Symbol (string).
 
 
customer.CustomerDetailsEditable
Pole (bool) - edytowalność danych klienta.
 
 
customer.DeliveryAddress.Nazwa
Obiekt (Object) zawiera informacje o adresie dostawy. Właściwości:
  • City (string),
  • Country (string),
  • Name (string),
  • Name2 (string),
  • Name3 (string),
  • PhoneNo (string),
  • State (string),
  • Street (string),
  • StreetNo (string),
  • UnitNo (string),
  • ZipCode (string).
 
 
customer.Email
Pole (string) - adres email klienta.
 
 
customer.Employee
Obiekt (Object) zawiera informacje o kliencie. Właściwości:
  • Email (string) - adres email,
  • LanguageId (int) - język,
  • Name (string) - nazwa,
  • Name2 (string) - dodatkowe pole nazwy,
  • Owner (bool),
  • PhoneNo (string) - numer telefonu.
 
 
customer.HidePrices
Pole (bool) - widoczność cen w sklepie.
 
 
customer.Invoice
Pole (bool) - otrzymanie faktury.
 
 
customer.NewsletterSubscriber
Pole (bool) - subskrybcja newslettera.
 
 
customer.PaymentDueDays
Pole (int) - termin płatności w dniach.
 
 
customer.Points
Pole (int) - punkty lojalnościowe klienta.
 
 
customer.PriceId
Pole (int) - id cennika (tylko w wersji Enterprise).
 
 
customer.ReviewAuthor
Pole (string) - nick wybrany przez klienta.
 
 
customer.SSN
Pole (string) - numer PESEL klienta.
 
 
customer.SubtotalPrices
Pole (bool) - cena z VAT.
 
 
customer.Supervisor
Obiekt (Object). Właściwości:
  • Email (string),
  • FirstName (string),
  • ImageUrl (string),
  • LastName (string),
  • PhoneNo (string).
 
 
customer.TIN
Pole (string) - numer NIP klienta.
 
 
customer.UserId
Pole (string) - id klienta.
 
 
customer.UserId32
Pole (string) - id klienta (z 64 znakami).
 
 
customer.VATEU
Pole (string) - numer VATEU.
 
 
customer.WishListCount
Pole (int) - liczba przedmiotów na liście życzeń/przechowalni użytkownika.
 

Panel Administracyjny - obiekty dostępne w wiadomościach E-mail

Niniejszy artykuł przedstawia wykaz obiektów, które użytkownik ma do dyspozycji w wiadomościach e-mail. Obiekty te pozwalają na wysyłanie w wiadomościach e-mail do Klientów sprecyzowanych informacji dotyczących m.in. ich zamówienia. W artykule tym znajdzie się szczegółowy opis każdego obiektu oraz jego właściwości, a także informacja, które obiekty są obsługiwane w konkretnych typach maili.
Wskazówka
Lista wiadomości e-mail wraz z obsługiwanymi obiektami znajduje się na końcu artykułu.
Wskazówka
Niniejszy artykuł tworzony był w oparciu o sklep w wersji 2021. Starsze wersje sklepu mogą nie obsługiwać niektórych typów wiadomości lub niektórych obiektów!

config

Obiekt config jest podstawowym obiektem w wiadomościach e-mail. Zawiera informacje o ustawieniach sklepu, jego danych kontaktowych, ustawieniach itp. Dostępne właściwości:
  1. TOS - informacje o zgodach, regulaminach, zawiera:
    • FormalContents - treści formalne, zawiera:
        • Terms - regulamin sklepu, zawiera:
          • Id - numer id,
          • Type - typ,
          • Key - klucz,
          • Name - nazwa,
          • ContentHtml - treść w HTML,
          • ContentPdfUrl - adres URL do załączników w formacie PDF,
          • PublishedDate - data publikacji,
          • PageId - numer id podstrony,
          • Files - załączniki, zawiera:
            • Name - nazwa,
            • Url - adres URL załącznika,
      Wskazówka
      Pozostałe właściwości pola TOS zawierają te same pola, co powyższe pole config.TOS.FormalContents.
        • Privacy - polityka prywatności,
        • WithdrawalRight - prawo do odstąpienia od umowy,
        • About - informacje o sklepie,
        • Shipping - wysyłka,
        • Payment - płatność,
        • Complaints - reklamacje i zwroty,
        • Loyalty - program lojalnościowy,
      Wskazówka
      Oprócz powyższych, znajdują się tutaj także informacje dodane w Panelu Administracyjnym w polu Ustawienia -> Treści -> Regulamin i inne -> Użytkownika. Zawierają te same pola co powyższe.
  2. DecimalSeparator - separator liczb dziesiętnych,
  3. DecimalPlacesPrice - ilość cyfr po przecinku,
  4. DecimalThousandsSeparator - separator "tysięcy" - w jaki sposób oddzielane są kolejne 3 cyfry przed przecinkiem,
  5. B2B - czy sklep jest w wersji B2B,
  6. ENTERPRISE - czy sklep jest w wersji Enterprise,
  7. UniqueId - unikalny numer id,
  8. Url - adres URL sklepu,
  9. Version - aktualna wersja sklepu,
  10. CompanyOnly - jeśli true to zamówienie można złożyć tylko jako firma,
  11. AuthenticatedOnly - czy sklep dostępny jest tylko dla zalogowanych użytkowników,
  12. DefaultCountry - kraj domyślny,
  13. Countries - lista krajów, zawiera:
    • ISOCode - kod ISO,
    • ISOCode3 - kod ISO,
    • Name - nazwa kraju,
    • ZipCodeRegex - wzorzec do kodów pocztowych danego kraju,
    • ZipCodeFormat - format kodu pocztowego danego kraju,
    • SSNRegex - wzorzec do numeru PESEL,
    • TINRegex - wzorzec do NIPu,
    • States - zawiera listę województw,
    • RequiredFields - zawiera pola wymagane wraz z wartościami true (wymagane) lub false (nie jest wymagane):
      • City - miasto,
      • Street - ulica,
      • StreetNo - numer domu,
      • TIN - numer NIP,
      • ZipCode - kod pocztowy,
  14. Languages - tablica z językami. Każde pole tablicy zawiera:
    • Language - kod języka,
    • Name - nazwa języka,
    • Id - id języka,
  15. Products - zawiera ustawienia produktów wraz z wartościami true (włączone) lub false (wyłączone):
    • ShowCode - pokazywanie kodów,
    • DecimalUnits - jednostki dziesiętne,
  16. Reviews - opinie, zawiera:
    • Enabled - czy włączone,
    • AuthenticationRequired - czy do utworzenia opinii wymagane jest bycie zalogowanym,
    • OnlyPurchasedProducts - czy opinie można wystawić tylko zakupionym produktom,
    • Reviews - skala ocen - każdy element tablicy zawiera następujące pola:
      • Rate - ocena (cyfra),
      • Text - ocena (tekst),
  17. Registration - informacje dotyczące rejestracji, zawiera:
    • Retail - zawiera:
      • AddressVisible - czy adres jest widoczny,
      • AddressRequired - czy adres jest wymagany,
      • PhoneVisible - czy numer telefonu jest widoczny,
      • PhoneRequired - czy numer telefonu jest wymagany,
    • Company - konto firmowe, zawiera:
      • AddressVisible - czy adres jest widoczny,
      • AddressRequired - czy adres jest wymagany,
      • PhoneVisible - czy numer telefonu jest widoczny,
      • PhoneRequired - czy numer telefonu jest wymagany,
    • AuthorizationRequired - czy autoryzacja jest wymagana,
    • ConfirmationRequired - czy potwierdzenie jest wymagane,
    • Disabled - czy konto jest nieaktywne,
    • ValidateTin - czy numer NIP jest zatwierdzony,
  18. VATEU - tablica prefixów, każdy element zawiera:
    • Name - nazwa (np. "PL - Polska"),
    • Value - wartość (np. "PL)",
    • ISOCode - kod ISO (np. "PL"),
  19. DefinedPages - zawiera listę zdefiniowanych stron:
    • Home - strona główna,
    • Terms - regulamin,
    • Privacy - polityka prywatności,
    • Registration - rejestracja,
    • Contact - kontakt,
    • ProductList - lista produktów
    • ProductDetails - szczegóły produktu,
    • ProductComparisonTool - porównywarka towarów,
    • Order - zamówienie,
    • ContinueShopping - kontynuuj zakupy,
    • AdvancedSearch - wyszukiwanie zaawansowane,
    • CustomerProfile - profil klienta,
    • nonexistentgroup - nieistniejąca grupa towarów,
    • nonexistentproduct - nieistniejący produkt,
    • Login - logowanie,
    • Shipping - wysyłka,
    • PasswordReminder - przypomnienie hasła,
    • UponLogging - strona otwierana po zalogowaniu się,
    • Http404 - strona nieistniejąca (błąd 404),
    • Payment - płatności,
    • About - o firmie,
    • WithdrawalRight - prawo do odstąpienia umowy,
    • Blog - blog,
    • BlogDetails - wpis na blogu,
    • Complaints - reklamacje,
    • Loyalty - program lojalnościowy,
    • Manufacturers - producenci,
    • Brands - marki,
    Każda ze zdefiniowanych stron zawiera następujące właściwości:
    • Id - numer id,
    • Name - nazwa
    • Heading - nagłówek,
    • Url - adres URL podstrony,
  20. Pages - zawiera listę stron, każda ze stron zawiera następujące pola:
    • Id - numer id,
    • Name - nazwa,
    • Heading - nagłówek,
    • Url - adres URL podstrony,
  21. Footer - stopka, zawiera:
    • JoinUs - "Dołącz do nas" (media społecznościowe) - obrazek i link,
    • Sections - sekcje, zawiera listę sekcji. Każda sekcja zawiera:
      • Heading - nagłówek,
      • Pages - lista stron, każda strona zawiera:
        • Id - numer id,
        • Name - nazwa,
        • Heading - nagłówek,
        • Url - adres URL,
  22. Currencies - waluty. Lista, której każdy element zawiera:
    • BankAccount - konto bankowe, zawiera:
      • AccountNumber - numer konta,
      • Bank - nazwa banku,
      • SWIFT - kod SWIFT,
    • Code - kod waluty,
  23. Stock - stany magazynowe, zawiera:
    • Enabled - czy włączona obsługa stanów magazynowych,
    • QuantityControl - czy włączona kontrola stanów magazynowych,
  24. Tags - tagi, zawiera listę tagów dla wyszukiwarki i bloga,
  25. Messages - wiadomości (komunikaty). Lista, której każdy element zawiera:
    • Title - tytuł,
    • Message - treść komunikatu,
    • Url - adres URL do podstrony,
    • Days - ilość dni, po których komunikat pokazuje się ponownie,
    • Id - numer id,
    • Type - typ, numer określa, czy komunikat pokazuje się w nagłówku, stopce, czy pop-upie,
  26. GTM - Google Tag Manager,
  27. GTMHead,
  28. Complaints - reklamacje, zawiera:
    • Returns - zwroty, każdy element listy zawiera:
      • Id - numer id,
      • Name - nazwa,
    • Defects - defekty, każdy element listy zawiera:
      • Id - numer id,
      • Name - nazwa,
    • Requests - rozwiązania, każdy element listy zawiera:
      • Id - numer id,
      • Name - nazwa,
    • DaysToReturn - ilość dni na zwrot zakupów,
    • ReturnsEnabled - czy zwroty są możliwe,
    • ComplaintsEnabled - czy reklamacje są możliwe,
    • AttachmentsEnabled - czy można dodać załączniki do reklamacji,
    • AttachmentsMaxCount - maksymalna liczba załączników,
    • AttachmentExtensions - lista zawierająca dozwolone formaty plików - załączników,
    • AttachmentMaxSize - maksymalny rozmiar załącznika,
  29. External - logowanie z zewnątrz, zawiera:
    • Facebook,
    • Google,
    • Edrone, zawiera pole AppId,
    • SalesMango,
  30. Contact - zawiera pole Contacts
  31. Now - aktualna data,
  32. Shop - informacje o sklepie, zawiera:
    • Contact - dane kontaktowe, zawiera:
      • PhoneNo - numer telefonu,
      • PhoneNo2 - drugi numer telefonu,
      • GSM - numer telefonu komórkowego,
      • Fax - fax,
      • Skype - nazwa na Skype,
      • GG - nazwa na Gadu-Gadu,
      • Email - adres e-mail,
    • Address - dane adresowe, zawiera:
      • Street - ulica,
      • StreetNo - numer domu,
      • UnitNo - numer lokalu,
      • ZipCode - kod pocztowy,
      • City - miasto,
      • State - województwo,
      • Country - kraj,
      • Latitude - szerokość geograficzna,
      • Longitude - długość geograficzna,
    • Name - nazwa sklepu,
    • ShortName - skrócona nazwa sklepu,
    • TIN - numer NIP,
    • Regon - numer identyfikacyjny REGON,
    • Registrant - informacja o działalności gospodarczej,
    • Description - informacje dodatkowe,
    • ImageUrl - adres URL do obrazka z logo sklepu,
    • Application - informacje o aplikacji, zawiera:
      • Name - nazwa aplikacji,
      • Website - stronę aplikacji,
  33. Orders - ustawienia dotyczące zamówień, zawiera:
    • AttributesCart - zawiera:
      • Header,
      • Position,
    • AttributesEdit - zawiera:
      • Header,
      • Position,
    • AttachmentsEnabled - czy załączniki są dozwolone,
    • AttachmentsMaxCount - maksymalna liczba załączników,
    • AttachmentExtensions - lista dozwolonych rozszerzeń plików,
    • AttachmentMaxSize - maksymalny rozmiar załącznika,
Obiekt używany w następujących mailach:
  1. Szablon,
  2. Złożenie zamówienia,
  3. Zamówienie potwierdzone przez Klienta,
  4. Zmiana statusu zamówienia,
  5. Zamówienie zrealizowane,
  6. Zamówienie anulowane,
  7. Zamówienie zapłacone płatność online lub ratalna,
  8. Dodanie listu przewozowego,
  9. Dodanie faktury,
  10. Informacja o zamówieniu do punktu odbioru osobistego,
  11. Potwierdzenie złożenia reklamacji,
  12. Zmiana statusu reklamacji,
  13. Zamówienie z ERP,
  14. Rozpoczęcie edycji,
  15. Zatwierdzenie zamówienia,
  16. Przypomnienie o zakupach,
  17. Przypomnienie o dokończeniu płatności online,
  18. Przypomnienie o wystawieniu opinii za zakupiony towar,
  19. Podział zamówienia,
  20. Zamówienie wysłane,
  21. Pierwsze przypomnienie o dokończeniu zamówienia,
  22. Drugie przypomnienie o dokończeniu zamówienia,
  23. Zapytanie o koszt dostawy zamówienie bez kosztów dostawy,
  24. Ustalenie kosztów dostawy,
  25. Złożenie zapytania cenowego,
  26. Powiadomienie o ofercie,
  27. Powiadomienie o dostępności towaru,
  28. Kupon rabatowy,
  29. Rabat dla stałego Klienta,
  30. Kupon rabatowy na darmową dostawę,
  31. Założenie konta przez Klienta,
  32. Założenie konta przez sklep,
  33. Konto potwierdzone,
  34. Stan konta aktywne, zablokowane,
  35. Zmiana adresu e-mail,
  36. Program lojalnościowy,
  37. Przypomnienie hasła,
  38. Reset hasła przez sklep,
  39. Zapis do newslettera,
  40. Zapis do newslettera przez sklep,
  41. Wypisanie z newslettera przez sklep,
  42. Zapytanie ze strony kontakt,
  43. Zapytanie o towar,
  44. Powiadom znajomego o towarze,

order

Obiekt order zawiera wszystkie informacje na temat zamówienia. Dostępne właściwości:
  1. Document - typ dokumentu dodanego do zamówienia (paragon lub faktura),
  2. DocumentText - nazwa dokumentu dodanego do zamówienia,
  3. OrderTotalValueInWords - wartość zamówienia wypisana jako tekst,
  4. ProductsTotalValueBeforeDiscount - wartość zamówienia bez zniżek,
  5. WeightUnit - jednostka masy,
  6. PreOrder - czy przedsprzedaż,
  7. ConfirmationTime - czas na zatwierdzenie zamówienia,
  8. ConfirmationDueDate - termin potwierdzenia zamówienia,
  9. ConfirmationUrl - link do potwierdzenia zamówienia,
  10. ThirdPartyConsent - zgoda na przekazywanie danych osobom trzecim,
  11. Attachments - załączniki,
  12. CanCancel - czy zamówienie może zostać anulowane,
  13. CanAccept - czy zamówienie może zostać zaakceptowane,
  14. CanRestorePayment - czy płatność może zostać kontynuowana,
  15. CanCopy - czy zamówienie może zostać skopiowane,
  16. CanEdit - czy zamówienie może zostać edytowane,
  17. EditingAllowed - czy edycja zamówienia jest dozwolona,
  18. IsEdited - czy zamówienie było edytowane,
  19. RecalculationRequired - czy zamówienie można przeliczyć,
  20. ReportUrl - link do "raportu" z zamówienia,
  21. RelatedOffers - oferty powiązane z zamówieniem,
  22. SubtotalPrices - czy są ceny netto,
  23. ProductsSubtotalValue - wartość netto zamówienia,
  24. ProductsTotalValue - wartość brutto zamówienia
  25. Attributes - atrybuty,
  26. RelatedOrders - powiązane zamówienia,
  27. Id - numer id zamówienia,
  28. Hash - unikalny numer oznaczający zamówienie,
  29. Date - data złożenia zamówienia,
  30. ERPOrderNumber - numer zamówienia z systemu ERP,
  31. Status - status zamówienia (jako liczba),
  32. StatusText - status zamówienia (jako tekst),
  33. Currency - waluta,
  34. LanguageId - numer id języka,
  35. NotDeterminedDeliveryCost - czy nieustalony koszt dostawy,
  36. Note - wiadomość dla sprzedawcy,
  37. Discount - zniżka,
  38. ProductsValue - wartość produktów,
  39. ProductsValueBeforeDiscount - wartość produktów przed rabatem,
  40. ProductsVatValue - wartość VAT w zamówieniu,
  41. OrderTotalValue - wartość zamówienia brutto,
  42. Weight - waga,
  43. Customer - informacje o kupującym, zawiera:
    • VATEU - prefix,
    • RegisteredUser - czy użytkownik był zalogowany składając zamówienie,
    • Email - adres e-mail,
    • SSN - numer ubezpieczenia społecznego,
    • TIN - numer NIP,
    • Invoice - czy użytkownik poprosił o otrzymanie faktury,
    • Company - czy konto firmowe,
    • DeliveryAddress - adres dostawy, zawiera:
      • Name - dane kupującego,
      • Name2 - dane kupującego,
      • Name3 - dane kupującego,
      • Street - ulica,
      • StreetNo - numer domu,
      • UnitNo - numer lokalu,
      • ZipCode - kod pocztowy,
      • City - miasto,
      • State - województwo,
      • Country - kraj,
      • PhoneNo - numer telefonu,
    • InvoiceAddress - adres na fakturze, zawiera:
      • Email - adres e-mail,
      • Name - dane kupującego,
      • Name2 - dane kupującego,
      • Name3 - dane kupującego,
      • Street - ulica,
      • StreetNo - numer domu,
      • UnitNo - numer lokalu,
      • ZipCode - kod pocztowy,
      • City - miasto,
      • State - województwo,
      • Country - kraj,
      • PhoneNo - numer telefonu,
    • Buyer - trzecie dane klienta,
    • Employee - zwraca informacje na temat pracownika, zawiera:
      • Email - adres e-mail,
      • Name - dane pracownika,
      • Name2 - drugie dane pracownika,
      • PhoneNo - numer telefonu,
      • LanguageId - numer id języka,
  44. Payment - płatność, zawiera:
    • SubtotalValue - wartość netto,
    • MethodId - numer id metody płatności,
    • MethodIdText - metoda płatności (tekst),
    • MethodType - metoda płatności (typ),
    • Status - status płatności (numer),
    • StatusText - status płatności (tekst),
    • Name - nazwa metody płatnosci,
    • Description - dodatkowy opis metody płatności,
    • DueDateText - termin płatności (tekst),
    • TotalValue - wartość brutto,
    • OnlineNumber - Id transakcji z platności online,
  45. Delivery - dostawa, zawiera:
    • SubtotalValue - wartość netto,
    • MethodId - numer id sposobu dostawy,
    • Name - nazwa sposobu dostawy,
    • Description - dodatkowy opis sposobu płatności,
    • DateText - termin dostawy (słownie),
    • Status - status dostawy,
    • StatusText - status dostawy (tekst),
    • Waybill - list przewozowy,
    • Waybills - listy przewozowe, zawiera:
      • Name - kurier,
      • Number - numer listu przewozowego,
      • Url - link do śledzenia paczki,
    • TotalValue - wartość brutto,
    • CollectionPointAddress - dane punktu odbioru,
    • CollectionPointId - identyfikator punktu odbioru,
    • CollectionPointTypeId - identyfikator typu punktu odbioru,
    • CollectionPoint - punkt odbioru,
    • PackageCount - ilość paczek,
  46. Products - informacje o produktach w zamówieniu. Każdy element zawiera:
    • StatusText - status dostępności,
    • UnitPriceRatio - przelicznik ceny za jednostkę miary,
    • UnitPriceUnit - możliwa jednostka przeliczniowa (np. litry na mililitry, gramy na kilogramy itd.),
    • CanReturn - czy produkt może być zwrócony,
    • CanComplain - czy produkt może być zareklamowany,
    • IsModified - czy modyfikowany,
    • IsDeleted - czy skasowany,
    • IsEdited - czy edytowany,
    • SubtotalPrice - cena netto,
    • TotalPrice - cena brutto,
    • SubtotalValue - wartość netto,
    • TotalValue - wartość brutto,
    • Attributes - lista atrybutów,
    • No - numer,
    • Code - kod towaru,
    • Description - wartość atrybutu typu lista,
    • Quantity - ilość,
    • Unit - jednostka,
    • VAT - wartość VAT,
    • Price - cena,
    • Value - wartość,
    • WasteMgmtCost - koszt gospodarowania odpadami,
    • ReturnedQuantity - ilość zwróconego towaru,
    • IsSetParent - czy przedmiot jest główną częścią np. zestawu,
    • IsSetElement - czy nalezy do zestawu,
    • SetName - nazwa zestawu,
    • UPC - kod EAN towaru,
    • Image - zdjęcie, zawiera:
      • Id - numer id zdjęcia,
      • Link - link do towaru,
      • ExternalUrl - zewnętrzny URL,
    • ImageId - numer id zdjęcia,
    • Id - numer id towaru,
    • DefaultGroup - grupa domyślna,
    • NameNoHtml - nazwa bez znaczników HTML,
    • Link - link do strony produktu,
    • Url - link do towaru,
  47. ItemsPerPage - ilość towarów na stronie,
  48. PageCount - ilość stron,
  49. PageNo - numer strony,
  50. TotalItems - ilość produktów,
  51. Documents - lista dokumentów,
  52. DeliveryDate - zawiera liczbę (zazwyczaj dni) w ciągu których towar zostanie dostarczony,
  53. SelectedDeliveryDate - wybrana przez Klienta data dostawy,
  54. ExpectedDate - dzień dostarczenia towaru,
  55. ProcessedDate - data wysłania,
  56. ExpirationDate - dzień do którego towary zostaną dostarczone,
  57. Points - liczba punktów lojalnościowych, które klient otrzyma za zakup towarów,
  58. PointsPaid - punkty lojalnościowe wydane w tym zamówieniu,
  59. SplitPayment - podział płatności,
  60. Source - źródło,
  61. Url - adres URL do zamówienia w profilu Klienta,
Obiekt używany w następujących mailach:
  1. Złożenie zamówienia,
  2. Zamówienie potwierdzone przez Klienta,
  3. Zmiana statusu zamówienia,
  4. Zamówienie zrealizowane,
  5. Zamówienie anulowane,
  6. Zamówienie zapłacone płatność online lub ratalna,
  7. Dodanie listu przewozowego,
  8. Dodanie faktury,
  9. Informacja o zamówieniu do punktu odbioru osobistego,
  10. Zamówienie z ERP,
  11. Rozpoczęcie edycji,
  12. Zatwierdzenie zamówienia,
  13. Przypomnienie o dokończeniu płatności online,
  14. Przypomnienie o wystawieniu opinii za zakupiony towar,
  15. Podział zamówienia,
  16. Zamówienie wysłane,
  17. Zapytanie o koszt dostawy zamówienie bez kosztów dostawy,
  18. Ustalenie kosztów dostawy,

customer

Obiekt customer zawiera informacje na temat Klienta.
Wskazówka
Niektóre pola w obiekcie customer dostępne są tylko dla poszczególnych maili. Przykładowo, pole OldEmail będzie dostępne w wiadomości związanej ze zmianą adresu e-mail, ale w wiadomości ze statusem rejestracji już nie.
Dostępne właściwości:
  1. ConfirmationUrl - adres url do potwierdzenia konta,
  2. Discount - znizki,
  3. PasswordReminderUrl - adres url do przypomnienia hasła,
  4. Status - status Klienta (numer),
  5. StatusText - status Klienta (tekst),
  6. Email - adres e-mail,
  7. Name - dane Klienta,
  8. Name2 - dane Klienta,
  9. PhoneNo - numer telefonu,
  10. OldEmail - poprzedni adres e-mail,
Obiekt używany w następujących mailach:
  1. Potwierdzenie złożenia reklamacji,
  2. Zmiana statusu reklamacji,
  3. Przypomnienie o zakupach,
  4. Powiadomienie o dostępności towaru,
  5. Kupon rabatowy,
  6. Rabat dla stałego Klienta,
  7. Kupon rabatowy na darmową dostawę,
  8. Założenie konta przez Klienta,
  9. Założenie konta przez sklep,
  10. Konto potwierdzone,
  11. Stan konta aktywne, zablokowane,
  12. Zmiana adresu e-mail,
  13. Program lojalnościowy,
  14. Przypomnienie hasła,
  15. Reset hasła przez sklep,
  16. Zapytanie ze strony kontakt,
  17. Zapytanie o towar,
  18. Powiadom znajomego o towarze,

complaint

Obiekt complaint wykorzystywany jest w mailach związanych ze zwrotami i reklamacjami. Dostępne właściwosci:
  1. OrderDate - data zlożenia zamówienia,
  2. OrderDeliveryDate - data dostarczenia zamówienia,
  3. Code - kod reklamowanego towaru,
  4. Defect - powód reklamacji,
  5. DefectDescription - opis powodu reklamacji,
  6. Response - odpowiedź,
  7. DefectDate - data wystąpienia usterki,
  8. Request - sposób rozwiązania problemu,
  9. AccountNumber - numer konta,
  10. ReportUrl - link do reklamacji,
  11. ModifiedDate - data ostatniej modyfikacji,
  12. Attachments - załączniki,
  13. ComplaintId - numer id reklamacji,
  14. CreatedDate - data utworzenia reklamacji,
  15. Status - status reklamacji (liczba),
  16. StatusText - status reklamacji (tekst),
  17. Type- typ reklamacji (liczba),
  18. TypeText - typ reklamacji (tekst),
  19. OrderId - numer id zamówienia,
  20. Quantity - ilość towaru,
  21. Unit - jednostka,
  22. Description - opis,
  23. Price - cena,
  24. Value - wartość,
  25. SubtotalPrices - czy są ceny netto,
  26. SubtotalPrice - cena netto,
  27. TotalPrice - cena brutto,
  28. SubtotalValue - wartość netto,
  29. TotalValue - wartość brutto,
  30. Currency - waluta,
  31. ImageId - numer id zdjęcia towaru,
  32. Image - zdjęcie, zawiera:
    • Id - id zdjęcia,
    • Link - link do zdjęcia,
    • ExternalUrl - zewnętrzny link,
  33. Id - numer id towaru,
  34. DefaultGroup - numer domyślnej grupy,
  35. NameNoHtml - nazwa towaru bez znaczników HTML,
  36. Link - link do strony produktu,
  37. Url - link do towaru,
Obiekt używany w następujących mailach:
  1. Potwierdzenie złożenia reklamacji,
  2. Zmiana statusu reklamacji,

product

Obiekt product wykorzystywany jest w mailach z przypomnieniem o zakupach oraz zapytaniem o towar. Dostępne właściwości:
  1. Code - kod towaru,
  2. UPC - kod EAN towaru,
  3. Id - numer id towaru,
  4. DefaultGroup - grupa domyślna,
  5. NameNoHtml - nazwa towaru bez znaczników HTML,
  6. Link - link do strony produktu,
  7. Url - link do produktu,
Obiekt używany w następujących mailach:
  1. Przypomnienie o zakupach,
  2. Powiadomienie o dostępności towaru,
  3. Zapytanie o towar,
  4. Powiadom znajomego o towarze,

cart

Obiekt cart posiada właściwości do porzuconych koszyków. Dostepne właściwości:
  1. Url - link do porzuconego koszyka,
  2. Id - numer id porzuconegeo koszyka,
  3. Email - adres e-mail użytkownika, do którego należy porzucony koszyk,
  4. Name - dane Klienta,
  5. Name2 - drugie dane Klienta,
  6. PhoneNo - numer telefonu Klienta,
  7. Currency - waluta,
  8. Date - data utworzenia koszyka,
  9. Value - wartość koszyka,
  10. Authenticated - czy użytkownik był zalogowany,
  11. Products - lista produktów w koszyku, każdy element zawiera:
    • Code - kod produktu,
    • Quantity - ilość,
    • SaleUnit - jednostka miary,
    • Price - cena,
    • Value - wartość,
    • ImageId - numer id zdjęcia produktu,
    • Image - informacje o zdjęciu, zawiera:
      • Id - numer id zdjęcia,
      • Link - link do zdjęcia,
      • ExternalUrl - link zewnętrzny,
    • Id - numer Id produktu,
    • DefaultGroup - grupa domyślna,
    • NameNoHtml - nazwa produktu bez znaczników HTML,
    • Link - link do strony towaru,
    • Url - link do produktu,
Obiekt używany w następujących mailach:
  1. Pierwsze przypomnienie o dokończeniu zamówienia,
  2. Drugie przypomnienie o dokończeniu zamówienia,

inquiry

Obiekt inquiry wykorzystywany jest w przypadku zapytań ofertowych. Dostępne właściwości:
  1. ConfirmationUrl - link potwierdzający,
  2. Name - nazwa Klienta,
  3. Email - adres e-mail Klienta,
  4. PhoneNo - numer telefonu,
  5. Hash -unikalny numer oznaczający ofertę,
  6. Inquiry - czy zapytanie ofertowe,
  7. ExpirationDate - data ważności oferty,
  8. ProcessedDate - data realizacji zamówienia,
  9. OneTimeOffer zezwolenie na wiele zamowień z oferty, lub nie,
  10. Message - wiadomość do zapytania,
  11. Answer - odpowiedź,
  12. Products - produkty w zapytaniu, każdy element zawiera:
    • Code - kod produktu,
    • UPC - kod EAN produktu,
    • Quantity - ilość,
    • SaleUnit - jednostka (wybrana),
    • BasicUnit - jednostka podstawowa,
    • BasicUnitRatio - przelicznik jednostki,
    • UnitPriceRatio - przelicznik ceny za jednostkę miary,
    • UnitPriceUnit - możliwa jednostka przeliczeniowa (np. litry na mililitry, gramy na kilogramy itd.),
    • VAT - podatek VAT,
    • SubtotalValue - wartość netto,
    • TotalValue - wartość brutto,
    • TotalPrice - cena brutto,
    • SubtotalPrice - cena netto,
    • Attributes - atrybuty, każdy element zawiera:
      • Id - numer id,
      • Name - nazwa atrybutu,
      • ValueId - numer id wartości,
      • Value - wartość atrybutu,
    • Description - opis,
    • ExternalUrl - link zewnętrzny,
    • Id - numer id,
    • DefaultGroup - domyślna grupa,
    • NameNoHtml - nazwa towaru bez znaczników HTML,
    • Link - link do strony produktu,
    • Url - link do towaru,
  13. ItemsPerPage - maksymalna ilość przedmiotów na stronę,
  14. PageCount - ilość stron,
  15. PageNo - numer aktualnej strony,
  16. TotalItems - ilość przedmiotów,
  17. SubtotalValue - wartość oferty netto,
  18. TotalValue - wartość oferty netto,
  19. VatValue - wartość podatku VAT,
  20. Currency - waluta,
  21. Attachments - załączniki,
  22. RelatedOrders - powiązane zamówienia,
  23. RelatedOffers - powiązane oferty/zapytania ofertowe,
  24. DeliveryTotalValue - koszt dostawy,
  25. SelectedCountry - wybrany kraj,
  26. SelectedDelivery - wybrany sposób dostawy,
  27. SelectedPayment - wybrany sposób płatności,
  28. Id - numer id oferty,
  29. Date - data złożenia oferty,
  30. Status - status oferty (liczba),
  31. StatusText - status oferty (tekst),
Obiekt używany w następujących mailach:
  1. Złożenie zapytania cenowego,
  2. Powiadomienie o ofercie,

coupon

Obiekt coupon dotyczy kuponów rabatowych. Dostępne właściwości:
  1. Code - kod rabatowy,
  2. ProductsMinimumTotalValue - minimalna wartość zamówienia brutto,
  3. DateFrom - początkowa data obowiązywania kuponu rabatowego,
  4. DateTill - końcowa data obowiązywania kuponu rabatowego,
  5. Type - typ kuponu rabatowego (liczba),
  6. Discount - wartość rabatu,
  7. Currency - waluta,
  8. Groups - grupy towarów,
  9. Countries - kraje,
Obiekt używany w następujących mailach:
  1. Kupon rabatowy,
  2. Kupon rabatowy na darmową dostawę,

discount

Obiekt discount związany jest z rabatami. Dostępny jest w mailu "Rabat dla stałego klienta". Dostępne właściwości:
  1. Discount - wartość rabatu (w procentach),
  2. DateFrom - poczatkowa data obowiązywania rabatu,
  3. DateTill - końcowa data obowiązywania rabatu,
Obiekt używany w następujących mailach:
  1. Rabat dla stałego klienta,

loyalty

Loyalty to obiekt wykorzystywany w mailu dotyczącym programu lojalnościowego. Dostępne właściwości:
  1. Points - ilość punktów,
  2. Message - wiadomość,
Obiekt używany w następujących mailach:
  1. Program lojalnościowy,

subject

Subject jest obiektem nie posiadającym żadnych właściwości. Wykorzystywany jest jako temat wiadomości. Obiekt używany w następujących mailach:
  1. Zapytanie ze strony kontakt,

message

Obiekt message wykorzystywany jest w mailu "Zapytanie o Towar", "Zapytanie ze strony kontakt" oraz "Powiadom znajomego o towarze". Obiekt ten jest treścią wiadomości wysyłaną przez Klienta. Nie posiada żadnych właściwości. Użycie obiektu to po prostu {{ message }}. Obiekt używany w następujących mailach:
  1. Zapytanie ze strony kontakt,
  2. Zapytanie o towar,
  3. Powiadom znajomego o towarze,

userFields

Obiekt posiada tylko jedną właściwość o nazwie macro_field. Obiekt używany w następujących mailach:
  1. Zapytanie ze strony kontakt,

friend

Obiekt friend stanowi informacje na temat "znajomego", któremu wysyłamy informację o towarze w mailu "Powiadom znajomego o towarze". Posiada następujące właściwości:
  1. Email - adres e-mail znajomego,
  2. Name - dane znajomego,
  3. Name2 - drugie dane znajomego,
  4. PhoneNo - numer telefonu znajomego,
Obiekt używany w następujących mailach:
  1. Powiadom znajomego o towarze,

subscriber

Subscriber to obiekt wykorzystywany w wiadomościach e-mail związanych z newsletterem. Dostępne właściwości:
  1. Email - adres e-mail,
  2. ConfirmationUrl - link potwierdzający subskrypcję,
Obiekt używany w następujących mailach:
  1. Zapis do newslettera,
  2. Zapis do newslettera przez sklep,
  3. Wypisanie z newslettera przez sklep,

Spis maili oraz obiektów w nich używanych

Spis dotyczy wersji sklepu 2021
L.P. Nazwa maila Używane obiekty
Zamówienia
1 Szablon (używany w każdym mailu) config
2 Złożenie zamówienia config, order
3 Zamówienie potwierdzone przez Klienta config, order
4 Zmiana statusu zamówienia config, order
5 Zamówienie zrealizowane config, order
6 Zamówienie anulowane config, order
7 Zamówienie zapłacone płatność online lub ratalna config, order
8 Dodanie Listu przewozowego config, order
9 Dodanie faktury config, order
10 Informacja o zamówieniu do punktu odbioru osobistego config, order
11 Potwierdzenie złożenia reklamacji config, customer, complaint
12 Zmiana statusu reklamacji config, customer, complaint
13 Zamówienie z ERP config, order
14 Rozpoczęcie edycji config, order
15 Zatwierdzenie zamówienia config, order
16 Przypomnienie o zakupach config, customer, product
17 Przypomnienie o dokończeniu płatności online config, order
18 Przypomnienie o wystawieniu opinii za zakupiony towar config, order
19 Podział zamówienia config, order
20 Zamówienie wysłane config, order
21 Pierwsze przypomnienie o dokończeniu zamówienia config, cart
22 Drugie przypomnienie o dokończeniu zamówienia config, cart
Zapytanie o koszt dostawy, Zapytanie o cenę towaru
1 Zapytanie o koszt dostawy zamówienie bez kosztów dostawy config, order
2 Ustalenie kosztów dostawy config, order
3 Złożenie zapytania cenowego config, inquiry
4 Powiadomienie o ofercie config, inquiry
5 Powiadomienie o dostępności towaru config, customer, product
Rabaty
1 Kupon rabatowy config, customer, coupon
2 Rabat dla stałego klienta config, customer, discount
3 Kupon rabatowy na darmową dostawę config, customer, coupon
Klienci
1 Założenie konta przez klienta config, customer
2 Założenie konta przez sklep config, customer
3 Konto potwierdzone config, customer
4 Stan konta aktywne, zablokowane config, customer
5 Zmiana adresu e-mail config, customer
6 Program lojalnościowy config, customer, loyalty
7 Przypomnienie hasła config, customer
8 Reset hasła przez sklep config, customer
Subskrybenci (newsletter)
1 Zapis do newslettera config, subscriber
2 Zapis do newslettera przez sklep config, subscriber
3 Wypisanie z newslettera przez sklep config, subscriber
Kontakt
1 Zapytanie ze strony kontakt config, customer, subject, message, userFields
2 Zapytanie o towar config, customer, message, product
3 Powiadom znajomego o towarze config, customer, message, product, friend

Konfigurator towaru

Wstęp

Konfigurator produktów powstał z myślą o firmach produkcyjnych, które w e-Sklepie internetowym chcą sprzedawać produkty na indywidualne zamówienie, uzależnione od ustalonych kryteriów. W celu odpowiedzi na potrzeby użytkowników e-Sklepu związane z obsługą tego rodzaju zamówień  w Comarch e-Sklep został przygotowany mechanizm, za pomocą którego można we własnym zakresie zaimplementować funkcję umożliwiającą, na podstawie parametrów podanych przez obsługę sklepu, dodanie do koszyka spersonalizowanego towaru (towarów) z ceną wyliczoną poza sklepem ("na zewnątrz"). W ten sposób Klienci e-Sklepu w wersji B2B będą mogli w łatwy sposób składać indywidualne zamówienia poprzez przejrzystą prezentację oferty z wieloma kryteriami wyboru, które mogą być dowolnie łączone. Niewątpliwą korzyścią z tego rozwiązania jest również optymalizacja procesu sprzedaży. Klient samodzielnie personalizuje towar według ustalonych parametrów i nie wymaga obsługi sprzedawcy. Dzięki temu do e-Sklepu trafia gotowe do realizacji zamówienie.
Wskazówka
Implementacja konfiguratora towarów przeznaczona jest dla użytkowników zaawansowanych i przy jej konfiguracji niezbędna jest wiedza programistyczna.
Uwaga
W tym artykule trzeba będzie wprowadzać zmiany w plikach js. Z tego artykułu dowiesz się jak je minifikować.
Podstawowe różnice między konfiguratorem produktu a towarem zgrupowanym (tzw. fantomem) zostały przedstawione w tym artykule.

Kto może używać tej opcji

Aby korzystać z mechanizmu dodawania towaru do koszyka z ceną wyliczoną poza e-Sklepem niezbędne jest:
  • posiadanie Comarch e-Sklep B2B w wersji co najmniej 2020.3;
  • zainstalowanie dodatku Comarch e-Sklep Sync w wersji co najmniej 2020.3 i włączenie go w panelu e-Sklepu;
  • włączenie w panelu administracyjnym w menu Ustawienia/ Ustawienia sklepu/ Ogólne/ Comarch e-Sklep Sync opcji Konfigurator towarów;
  • oznaczenie w paneli administracyjnym na towarze, że jest to towar konfigurowalny,
  • zaimplementowanie* w usłudze Comarch e-Sklep Sync mechanizmu z obsługą kryteriów wyboru towaru (dodanie nowego workera). *opcja niedostępna w Comarch ERP Optima Chmura Standard;
  • zmodyfikowanie standardowego szablonu Szafir (lub własnego szablonu wyglądu e-Sklepu), tak, by w przypadku towaru konfigurowalnego, wyświetlać opcje wyboru i odpowiednią cenę.
W efekcie wprowadzonych zmian Klient będzie miał możliwość dodania do koszyka pozycji z ceną wyliczoną poza e-Sklepem na podstawie określonych przez obsługę sklepu kryteriów. W zależności od sposobu implementacji, mechanizm konfiguratora produktu pozwala na:
  • dodanie do koszyka jednej pozycji towarowej, gdzie w jej szczegółach będą wszystkie informacje o wybranych przez Klienta parametrach. Przykład użycia został przedstawiony poniżej;
  • dodanie do koszyka kilku pozycji towarowych, które łącznie spełniają parametry zamówienia złożonego przez Klienta.

Przykład użycia

Poniżej przedstawiono przykład wykorzystania opcji konfiguratora towarów w integracji e-Sklepu z Comarch ERP Optima (w przypadku korzystania z Comarch ERP Optima Chmura Standard brak możliwości implementacji własnych workerów Comarch e-Sklep Sync). Jest to najprostszy przypadek, kiedy do jednego towaru przypisujemy różne konfigurowalne elementy (w tym przykładzie w postaci atrybutów). Po stworzeniu w e-Sklepie indywidualnego projektu produktu, Klient w koszyku będzie miał widoczną jedną pozycję z ceną wyliczoną poza e-Sklepem (w naszym przykładzie jest ona pobrana bezpośrednio z pliku XML, który jest dodany do karty towaru w systemie ERP). Pobierz plik ze zmianami (dotyczą wersji 2020.4) niezbędnymi do implementacji poniższego przykładu.
  1. W systemie Comarch ERP Optima przygotuj kartotekę towaru, który po przesłaniu do e-Sklepu będzie mógł być indywidualnie skonfigurowany przez Klienta podczas zakupu.
  2. W panelu administracyjnym e-Sklepu w wersji B2B na szczegółach tego towaru zaznacz, że towar jest konfigurowalny, a następnie zmiany w ustawieniach towaru opublikuj (przycisk w górnym prawym rogu).
  3. Do danego towaru w systemie ERP przypisz elementy konfigurowalne w postaci atrybutów o typie lista. Na liście dla każdego atrybutu dodaj wartości czyli warianty elementów, które klient może wybrać podczas zakupu. Do towaru konfigurowalnego można dodać dowolną ilość atrybutów z dowolną ilością wariantów. Ważne, żeby na towarze nie wskazywać konkretnych wartości (kolumna Wartość musi pozostać pusta), a wszystkie atrybuty były udostępnione do Comarch e-Sklep:
4. Przygotuj plik XML o odpowiedniej strukturze (do pobrania powyżej) , w którym wskażesz ceny netto, VAT oraz ceny brutto poszczególnych wariantów w konfigurowalnych elementach towaru: 5. Przygotowany plik dodaj do karty towaru w systemie ERP na zakładce Atrybuty w sekcji Załączniki. Dane o cenach zostaną pobrane z pliku XML przez usługę Comarch e-Sklep Sync, dlatego nie należy pliku XML udostępniać do e-Sklepu: 6. Do karty towaru konfigurowalnego w systemie ERP dodaj zdjęcie i udostępnij je do e-Sklepu (patrz: zrzut powyżej). Będzie ono wyświetlone na szczegółach produktu konfigurowalnego jako główne zdjęcie dla domyślnych wariantów towaru. 7. Zmodyfikuj* usługę Comarch e-Sklep Sync. W tym celu w pliku configWorkers.json dodaj nowy worker według instrukcji, który będzie wyliczał ostateczną cenę indywidualnego produktu w oparciu o ceny poszczególnych jego elementów. Przykład workera wraz z modyfikacjami usługi Comarch e-Sklep Sync dostępny do pobrania powyżej.(*opcja niedostępna w Comarch ERP Optima Chmura Standard) 8. Wprowadź zmiany w szablonie Szafir według instrukcji udostępnionej powyżej. Po przeprowadzeniu modyfikacji zapisz je, a następnie opublikuj. 9. Wykonaj synchronizację danych z systemu ERP. Wówczas do e-Sklepu zostaną przesłane dane o konfigurowalnych elementach towaru. Usługa Comarch e-Sklep Sync pobierze z pliku XML informację o cenach poszczególnych składowych produktu. 10. Powyższa instrukcja pozwala na przygotowanie na szczegółach produktu w szablonie Szafir w sklepie w wersji B2B następującego towaru konfigurowalnego. Podczas zakupu, Klient może samodzielnie dopasować warianty elementów, które są udostępnione przez sprzedawcę do samodzielnej konfiguracji: Po wybraniu dostępnych opcji, należy kliknąć w Zapisz - wówczas usługa Comarch e-Sklep Sync pobierze z pliku XML (przypisanego do towaru w pkt. 4) informację o cenach poszczególnych składowych produktu i na tej podstawie zostanie wyliczona cena indywidualnego projektu Klienta. Obok ceny pojawi się opcja dodania towaru do koszyka. W koszyku będzie widoczna jedna pozycja wraz z informacją o wybranych elementach oraz całkowita cena produktu: 11. Sprzedawca w panelu administracyjnym na szczegółach zamówienia będzie miał widoczną również jedną pozycję towarową wraz z elementami wybranymi przez Klienta. Po synchronizacji do Comarch ERP Optima, na Rezerwacji Odbiorcy na szczegółach pozycji (po użyciu przycisku lupki) będzie dostępna informacja o szczegółach projektu Klienta: Przenosi się ona również na dokumenty powiązane (Wydania zewnętrzne, Faktury Sprzedaży), co ułatwia szybką realizację indywidualnego zamówienia pochodzącego z e-Sklepu.
Wskazówka
Podczas minifikacji plików js może dojść do sytuacji, gdzie otrzymamy błąd informujący o zbyt dużym rozmiarze pliku. W takiej sytuacji proponujemy dodać plik init-ui3.js. Do tego pliku należy przekleić cały kod, który został dodany do init-ui2.js. Następnie na końcu pliku _layout.html proszę znaleźć następującą linijkę: <script src="js/init-ui2.js?v={{ lqTS }}"></script> Bezpośrednio pod tą linijką proszę wkleić następujący kod:<script src="js/init-ui3.js?v={{ lqTS }}"></script>  

Więcej informacji

Przykład konfiguratora produktu - zobacz >> Kod źródłowy przykładu - pobierz >> Więcej informacji na temat konfiguracji usługi Sync można znaleźć w artykule Comarch e-Sklep Sync.

Jakie są możliwości zarządzania szablonami w e-Sklepie?

Szablony w sklepie

W tym artykule dowiesz się o zaawansowanych możliwościach zarządzania sza

Jak wybrać szablon w panelu?

W obszarze Panel administracyjny/ Gotowe szablony Comarch możliwe jest wybranie szablonu z dostępnych szablonów domyślnych. Jeżeli jesteśmy ciekawi jak dany szablon prezentuje się to po kliknięciu w link Zobacz demo zostaniemy przekierowani na stronę z wersją demonstracyjną danego szablonu. Edycja nazwy szablonu jest możliwa po wejściu do zakładki Szablon w Zaawansowanych ustawieniach: Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Szablon Włączenie opcji Podgląd zmian wyglądu sklepu w czasie rzeczywistym (dla administratora) pozwala na bieżąco sprawdzać przez administratora zmiany wprowadzone w szablonach(wystarczy odświeżyć stronę).
Wskazówka
Pamiętaj, że zmiany wprowadzane w szablonach widoczne są w sklepie po ich opublikowaniu.

Co to są testy A/B w panelu e-Sklepu?

Administrator ma możliwość przeprowadzenia testów A/B. Aby móc je aktywować należy się udać do: Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane następnie wybieramy zakładkę Testy A/B. Po zaznaczeniu funkcji Testy A/B należy aktywować przynajmniej dwa spośród wgranych szablonów.

Jak można dodać ustawienia dla szablonu w panelu?

Dodawanie ustawień dla szablonu dostępne jest w panelu administracyjnym sklepu w obszarze Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Ustawienia (JSON).

Ustawienia dla szablonu dostępne są w formacie JSON.

Zdefiniowane ustawienia dla obiektu dostępne są w szablonie poprzez obiekt globalny settings.

Obiekt globalny settings dostępny jest także w plikach arkuszy stylów (css).

Gdzie można dodać bannery do szablonów?

Dodawanie bannerów do szablonów Liquid odbywa się w obszarze Wygląd sklepu/ Ustawienia/ Bannery. Stworzone bannery przypisywane są do konkretnego szablonu. Więcej informacji o bannerach można znaleźć tutaj.

Dodawanie szablonu

Gdzie jest dostępna lista plików szablonu?

Lista plików szablonu dostępna jest w panelu administracyjnym sklepu w obszarze Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Edytuj HTML.  

Jak można dodać plik szablonu?

Plik szablonu można dodać w panelu administracyjnym w menu Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Edytuj HTML za pomocą przycisku Dodaj: Przed dodaniem pliku szablonu należy wybrać, dla którego szablonu oraz jakiego rodzaju interfejsu dodajemy szablon. Dostępne rodzaje to:
  • szablon wykorzystywany w sklepie,
  • szablon wykorzystywany w wersji mobilnej sklepu,
  • szablon wykorzystywany w sklepie na Facebook.

Edycja plików szablonu

Pliki szablonu mogą być edytowane bezpośrednio z listy plików szablonu. Wystarczy kliknąć na plik, który nas interesuje, aby pojawiło się okno z możliwością edycji.

Zapis zmian możliwy jest także poprzez skrót klawiaturowy Ctrl + S

Wskazówka
Od wersji 2020 w szablonie Topaz została dodana informacja na temat godziny wygenerowania szablonu w kreatorze. Z listy plików należy wybrać _layout.html. Informacje na temat modyfikacji, w tym godzina ostatniej modyfikacji, znajdują się nad oknem edycji pliku. Jeżeli plik nie był modyfikowany, wówczas godzina odpowiada godzinie wygenerowania szablonu w kreatorze.
Wskazówka
Od wersji 2022 w standardowych szablonach Comarch wprowadziliśmy optymalizacje widoków poszczególnych stron w oparciu o przeprowadzony audyt Grupy iCEA. Dodatkowo wprowadziliśmy usprawnienia do prowadzenia efektywnych działań pozycjonujących za pomocą panelu Comarch e-Sklep, dzięki czemu jest to obecnie stosunkowo wygodne narzędzie do zarządzania zawartością sklepu internetowego, a także do skutecznego pozycjonowania.

Dodawanie obiektów

Obiekty zwracają dane dostępne w sklepie, przykładowo:
  • informacje o towarach,
  • informacja o zalogowanym kontrahencie,
  • informacje o zamówieniach,
  • koszyk
Obiekt należy wykorzystać w szablonach w celu wyświetlenia tych informacji w sklepie.

Więcej informacji o obiektach i ich podziałach można znaleźć w artykule Obiekty w sklepie.

 

Lista obiektów lokalnych

Lista obiektów lokalnych dostępna jest w Panelu administracyjnym sklepu w obszarze Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Obiekty. Kolumny na liście:
  • Nazwa – nazwa danego obiektu
  • Typ -Typ obiektu

Dodawanie obiektów

Obiekt należy dodać używając przycisku Dodaj. Na formularzu dodawania należy wybrać typ obiektu oraz wprowadzić jego nazwę, następnie nacisnąć przycisk Dodaj. Zostanie dodany obiekt z domyślna konfiguracją.

Nazwa obiektu wykorzystywana jest w szablonie do odwołania się do tego obiektu. Zmiana nazwy jest niedostępna.

 

Konfiguracja obiektu

Konfiguracja obiektu możliwa jest po kliknięciu w link JSON.   Zostaniemy przekierowani na stronę gdzie będziemy mogli:
  • Ustawić opcje konfiguracyjne obiektu
  • Wybrać strony, na których obiekt ma być aktywny
Zmiany możemy zapisać przyciskiem Zapisz znajdującym się w prawym górnym rogu. Obiekty należy aktywować tylko na stronach, na których będą one wykorzystywane. Każdy aktywowany obiekt wpływa na szybkość ładowania i wyświetlania stron w sklepie.  

Tłumaczenia w szablonie

Zmiany fraz i ich tłumaczenie odbywa się w obszarze Wygląd sklepu/ Ustawienia/ Tłumaczenia. Aby dodać nowe tłumaczenie należy nacisnąć przycisk Dodaj. Istnieje możliwość dodawania tłumaczeń dla różnych języków. Możemy również importować listę tłumaczeń z pliku XML. Służy do tego przycisk Import z pliku XML znajdujący się w rozwijanym menu w prawnym górnym rogu.

Powiązanie stron z szablonem i obiektami

Powiązanie stron z plikami szablonu oraz aktywnymi na tych stronach obiektami dostępne jest w Panelu administracyjnym sklepu w obszarze Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Strony. Przed powiązaniem stron należy wybrać, dla którego oraz jakiego rodzaju interfejsu wykonujemy powiązanie. Dla każdej strony należy ustawić:
  • Plik szablonu, który będzie wykorzystany na stronie.
  • Obiekty, które mają być dostępne dla strony.
Ustawienie pliku szablonu. W polu Szablon należy wprowadzić nazwę pliku i zapisać zmiany przyciskiem Zapisz. Wybór obiektów dla wskazanej strony możliwy jest po naciśnięciu przycisku Obiekty. Należy wybrać obiekty, które mają być dostępne na danej stronie i zapisać zmiany przyciskiem Zapisz. Ponadto dla każdej strony można ustawić wstawkę szablonu, która będzie dołączona do pliku szablonu poprzez obiekt page(property TemplateInclude). W polu Include należy wprowadzić nazwę pliku i zapisać zmiany przyciskiem Zapisz.

Obiekty należy aktywować tylko na stronach, na których będą one wykorzystywane. Każdy aktywowany obiekt wpływa na szybkość ładowania i wyświetlania stron w sklepie.

 

Import / Eksport szablonu

Import, eksport oraz przywracanie domyślnego szablonu odbywa się w obszarze Wygląd sklepu / Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Import/Eksport z pliku XML.  

Import z szablonu

W celu zaimportowania gotowego szablonu, należy za pomocą przycisku Wybierz plik XML wybrać plik z szablonem z dysku. Jeżeli importowany szablon posiada hasło, to należy je podać podczas importu. Jeżeli opcja Podmień istniejące bannery zostanie niezaznaczona, to podczas importu istniejące bannery nie zostaną nadpisane. Od wersji 2019.2 wprowadzono możliwość importu i eksportu bannerów bez sprawdzania limitu danych. Dzięki temu można przenosić dużą ilość bannerów bez obciążania szablonu. Opcja Importuj bannery zastępuje dotychczasowe bannery w e-Sklepie. Zmiany należy zatwierdzić opcją ‚Publikuj’ dostępną w menu rozwijanym Więcej . Zaimportowane bannery widoczne są w Wygląd sklepu/ Ustawienia/ Bannery.  

Eksport szablonu/ banneru

Eksport do pliku odbywa się w zakładce Eksport do pliku XML. Eksportowany szablon można podpisać danymi autora, takimi jak jego nazwa, adres e-mail, telefon oraz adres www. W wersji 2019.2 została wprowadzona możliwość eksportu oraz importu szablonu bez bannerów. Dodatkowo można do e-Sklepu zaimportować oddzielnie bannery (bez sprawdzania limitu danych). Dzięki temu można przenosić szablony, do których dodano dużą ilość bannerów.
Uwaga
Maksymalny rozmiar importowanego oraz eksportowanego szablonu nie może przekraczać 8MB.

Zabezpieczenie szablonu hasłem

Istnieje możliwość zabezpieczenia tworzonego szablonu przed niepowołanym dostępem. Blokady można zdefiniować w obszarze Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Szablon. Na samym dole strony dostępna jest opcja Zmień hasło.

Dedykowany szablon dla wersji mobilnej

Darmowe szablony Comarch tworzone są w technologi RWD, co sprawia, że są one wyświetlane poprawnie zarówno na urządzeniach typu desktop, jak i na urządzeniach mobilnych. W takim przypadku aktywacja dodatkowej wersji mobilnej, bez modyfikacji plików szablonu, może powodować błędy w wyświetlaniu sklepu na urządzeniu mobilnym. W panelu administracyjnym Ustawienia/ Ustawienia sklepu/ Ogólne widoczny jest parametr "Dedykowany szablon dla wersji mobilnej", który znajduje zastosowanie dla specjalnie przygotowanych dedykowanych szablonów posiadających osobną wersję mobilną. Dodatkowo zablokowano możliwość aktywacji tej funkcji, jeżeli w e-Sklepie nie ma wymaganego szablonu. Podczas aktualizacji e-Sklepu, w przypadku, gdy w sklepie nie utworzono specjalnego szablonu dla wersji mobilnej, następuje deaktywacja wersji mobilnej.

Obiekty w sklepie

W Comarch e-Sklep oddaliśmy do Państwa dyspozycji obiekty. Wyróżniamy dwa rodzaje obiektów, są to obiekty globalne oraz obiekty lokalne.
Wskazówka
Aktywacja obiektów w Comarch e-Sklep odbywa się w Panelu Administracyjnym, w sekcji Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane/ Obiekty.
comarch-e-sklep-panel-administracyjny
Uwaga
Obiekty globalne nie wymagają aktywacji, są importowane wraz z szablonem. Obiekty tego typu są dostępne na każdej stronie sklepu.
Do obiektów globalnych zaliczamy:
  1. config,
  2. page,
  3. customer,
  4. currency,
  5. usr,
  6. __action,
  7. __actionGET,
  8. settings,
  9. translations
Wskazówka
Więcej na temat obiektów globalnych mogą Państwo przeczytać w artykule o obiektach globalnych
Uwaga
Obiekty lokalne domyślnie nie są dostępne w sklepie. Obiekt należy dodać, oraz aktywować na wybranych stronach. Obiekty lokalne są importowane wraz z szablonem. Odwołania do obiektów przez Zmienne Lokalne. Nazwa zmiennej nadawana w momencie aktywacji obiektu. Obiekt udostępnia informacje o aktualnej stronie.
Przykładowe obiekty lokalne dostępne w Comarch e-Sklep to:
  1. productnew,
  2. manufacturersbrands,
  3. productrecommended,
  4. productlist,
  5. cart,
  6. productdetails,
  7. blog,
  8. customerprofile,
  9. productcomparisontool,
  10. productuserreviews,
  11. productlastviewed
Wskazówka
Jest to przykładowa lista obiektów.Więcej na temat obiektów lokalnychmogą Państwo przeczytać w Obiekty lokalne

Akcje

W Comarch e-Sklep udostępniliśmy do Państwa dyspozycji Akcje -  są to działania na stronie związane z interakcją użytkownika (kupującego jak i zarządzającego sklepem), takie jak np. dokonywanie zakupów, dodawanie produktów do koszyka czy zmiana waluty.

Lista dostępnych akcji znajduje się w Panelu Administracyjnym sklepu w następującej ścieżce: Panel administracyjny/Wygląd sklepu/Dokumentacja.

Związane z Klientem

Akcje te możemy określić jako powiązane z Klientem i jego działaniami na stronie. W skład tych akcji wchodzą:
CompanyChange EmployeeUnlock
CompanyDefaultUpdate EmployeeUpdate
ConsentAccept LanguageChange
ConsentsLoginAccept LanguageDefaultUpdate
ConsentWithdraw Login
CurrencyChange Logout
DeliveryAddressAdd OldPasswordChange
DeliveryAddressDelete PasswordChange
DeliveryAddressUpdate PasswordRecover
EmailChange Register
EmployeeAdd ReviewAuthorUpdate
EmployeeDelete Update
EmployeeLock
 

Dotyczące zamówienia

Akcje w tej grupie dotyczą składanych zamówień. W skład tych akcji wchodzą:
Accept DeliveryCountryChange
Add DeliveryDateChange
Cancel EmailSet
AttachmentAdd FastDeliveryCheck
AttachmentDelete InvoiceAddressUpdate
AttributesSet InvoiceChange
ComplaintAdd NoteAdd
BuyerChange PaymentMake
BuyerUpdate PointsUse
ComplaintCancel RestorePayment
Copy ReturnAdd
CouponAdd StatusGet
CouponDelete TinUpdate
DeliveryAddressUpdate StepNext
DeliveryChange StepPrev
DeliveryCollectionPointChange
 

Newsletter

Akcja odpowiada za działanie związane z newsletterem. W skład tych akcji wchodzą:
Subscribe Unsubscribe
 

Akcje GET

Akcje te umożliwiają pobieranie danych z serwera celem utworzenia np. breadcrumbs. W skład tych akcji wchodzą:
CollectionPointCities SearchAdvanced
CollectionPoints SearchAutocomplete
Groups SearchFilters
Search ProductId
 

Produkty

Akcje te odpowiadają za działania związane z produktami, takimi jak możliwość dodania opinii na temat produktu. W skład tych akcji wchodzą:
AskForPrice ReviewAdd
CollectionPointsStockLevelsGet StockLevelsGet
ComparisonToolAdd WishListAdd
ComparisonToolDelete WishListCheck
DeliveryCostGet WishListDelete
FastDeliveryCheck WishListUpdate
NotifyAboutProductAvailability
 

Koszyk

Akcje te odpowiadają za działania związane z koszykiem, np. dodaniem produktu do koszyka. W skład tych akcji wchodzą:
Add NameSet
AttributesSet PositionDelete
Change QuantityChange
Create Recalculate
Delete SetAdd
ExternalAdd SetExtAdd
ImportCSV
 

Kontakt

Akcje te odpowiadają za kontakt, np. w celu zapytania o dany produkt. W skład tych akcji wchodzą:
AskAboutProduct TellFriendAboutProduct
Send
 

Edycja zamówienia

Akcje te związane są z edycją zamówienia. W skład tych akcji wchodzą:
Accept PositionAttributesSet
AttributesSet PositionDelete
Cancel PositionQuantityChange
CartCreate PositionUndo
CartMerge Recalculate
Edit Undo
 

External

Akcje te odpowiedzialne są za możliwość logowania się poprzez Facebook lub Google. W skład tych akcji wchodzą:
FbAccountLink GoogleAccountLink
FbAccountUnlink GoogleAccountUnlink
FbLogin GoogleLogin
 

Sync

Akcje te odpowiadają za działania związane z pobieraniem danych z baz systemów. Więcej informacji można znaleźć klikając w odnośnik - Comarch e-Sklep Sync. W skład tych akcji wchodzą:
Exec
 

Zapytania ofertowe

Akcje te odpowiadają za działania związane ze składaniem zapytań ofertowych. W skład tych akcji wchodzą:
Add Set
CartMerge
 

Sesja użytkownika

Akcje te odpowiadają za działania związane z utrzymywaniem sesji użytkownika. W skład tych akcji wchodzą:
Ping
 

 

Opis używanych akcji:

 
CompanyChange
Akcja odpowiada za zmianę firmy. Parametry:
  • id (int, pole obowiązkowe).
<form action="{{ page.Url }}{{ page.QueryString | H }}" method="post">
<input type="hidden" name="__action" value="Customer/CompanyChange"/>
<input type="hidden" name="id" value=""/>
</form>
 
 
CompanyDefaultUpdate
Akcja odpowiada za wczytanie domyślnych ustawień firmy. Parametry:
  • id (int, pole obowiązkowe).
<form action="{{ page.Url }}{{ page.QueryString | H }}" method="post">
<input type="hidden" name="__action" value="Customer/CompanyDefaultUpdate"/>
<input type="hidden" name="id" value=""/>
</form>
 
 
ConsentAccept
Akcja odpowiadająca za akceptację zgody, na przykład podczas składania zamówienia. Parametry:
  • tos (int lub null),
  • channelKey (string).
{% for tos in customer-profile.Consents -%}
   {% if tos.Checked == false -%}
     <div class="form-lq tos-ui">
     <div class="tos-name-ui">{{ tos.Text }}</div>
       {% assign channelsSize = tos.Channels | Size -%}
        {% if channelsSize > 0 -%}
         {% for channel in tos.Channels -%}
          <div class="channel-ui">
          <button class="agreements-in-profile-lq" data-action="Customer/ConsentAccept" data-key="{{ channel.Key }}">{{translations.Accept}}</button>
          <span class="channel-name-ui">{{channel.Name}}</span>
          </div>
         {% endfor -%}
         {% else -%}
          <div class="date-container-ui">
          <button class="agreements-in-profile-lq tos-lq" data-action="Customer/ConsentAccept" data-key="{{ tos.Id }}">{{translations.AcceptAgreement}}</button>
          </div>
         {% endif -%}
      </div>
    {% endif -%}
{% endfor -%}
 
 
ConsentsLoginAccept
Akcja odpowiadająca za akceptację zgody obowiązkowej podczas logowania. Parametry:
  • tos (int[]) - może zostac przekazane wielokrotnie w ramach jednej akcji (int),
  • channelKey (string[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (string).
<form method="POST">
<input type="hidden" name="__action" value="Customer/ConsentsLoginAccept"/>
{% for tos in __consents -%}
   {% if tos.Required and tos.Statement == false -%}
     {% assign requiredExists = true -%}
     {% break -%}
   {% endif -%}
{% endfor -%}
</form>
 
 
ConsentWithdraw
Akcja odpowiada za wycofanie zgody. Parametry:
  • tos (int lub null),
  • channelKey (string).
{% for tos in customer-profile.Consents -%}
   {% if tos.Checked -%}
     <div class="form-lq tos-ui">
     <div class="tos-name-ui">{{ tos.Text }}</div>
       {% assign channelsSize = tos.Channels | Size -%}
        {% if channelsSize > 0 -%}
         {% for channel in tos.Channels -%}
          <div class="channel-ui">
          {% if channel.Checked -%}
              <button class="agreements-in-profile-js btn-pure-ui f-left-ui" data-action="Customer/ConsentWithdraw" data-key="{{ channel.Key }}">{{translations.Withdraw}}</button>
              <span class="channel-name-with-date-ui">{{channel.Name}}</span>
              <span class="date-label-ui">{{translations.AcceptanceDate}}: </span>
              <span class="date-ui"> <strong>{{channel.Date | Date:dateFormat}}</strong></span>
	      {% assign checkedChannelsSize = checkedChannelsSize | Plus:1 -%}
	  {% endif -%}
          </div>
         {% endfor -%}
         {% else -%}
          <div class="date-container-ui">
		<button class="agreements-in-profile-js tos-js btn-pure-ui" data-action="Customer/ConsentWithDraw" data-key="{{ tos.Id }}">{{translations.WithdrawAgreement}}</button>
		<span class="date-label-ui">{{translations.AgreementAccepted}}: </span>
                <span class="date-ui"> <strong>{{tos.Date | Date:dateFormat}}</strong></span>
		{% if tos.Required -%}
		     <div class="withdraw-required-info-ui error-ui">{{translations.WithdrawRequiredInfo}}!</div>
		{% endif -%}
	  </div>
         {% endif -%}
      </div>
    {% endif -%}
{% endfor -%}
 
 
CurrencyChange
Akcja odpowiada za zmianę waluty. Parametry:
  • currency (string, pole obowiązkowe).
<form method="post">
<select name="currency" required>
{% for currency in config.Currencies -%}
<option value="{{ currency.Code }}">{{ currency.Code }}</option>
{% endfor -%}
</select>
<button type="submit">Zmień</button>
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" required />
<input type="hidden" name="__action" value="Customer/CurrencyChange" required />
</form>
 

 
DeliveryAddressAdd
Akcja odpowiada za dodanie adresu do dostawy. Parametry:
  • addresId (int lub null),
  • default (bool),
  • name (string, pole obowiązkowe) - maksymalna długość to 64 znaki,
  • name2 (string) - maksymalna długość to 64 znaki,
  • name3 (string) - maksymalna długość to 250 znaków,
  • countryCode (string, pole obowiązkowe) - maksymalna długość to 2 znaki,
  • zipCode (string)- maksymalna długość to 20 znaków,
  • city (string) - maksymalna długość to 50 znaków,
  • street (string) - maksymalna długość to 150 znaków,
  • streetNo (string) - maksymalna długość to 20 znaków,
  • unitNo (string) - maksymalna długość to 20 znaków,
  • state (string) - maksymalna długość to 50 znaków,
  • phoneNo (string) - maksymalna długość to 50 znaków.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/DeliveryAddressAdd" />
<input type="hidden" name="__template" value="customer/profile-data.html" />
{% include 'customer/profile-data-address.html' %}
<button>Zatwierdź</button>
</form>
 

 
DeliveryAddressDelete
Umożliwia usunięcie adresu dostawy. Parametry:
  • addressId (int, pole obowiązkowe).
{% assign address = customer.DeliveryAddresses[0] -%}
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/DeliveryAddressDelete" />
<input type="hidden" name="addressId" value="{{ address.Id }}" />
</form>
 

 
DeliveryAddressUpdate
Akcja umożliwia edycję adresu. Parametry:
  • addresId (int lub null),
  • default (bool),
  • name (string, pole obowiązkowe) - maksymalna długość to 64 znaki,
  • name2 (string) - maksymalna długość to 64 znaki,
  • name3 (string) - maksymalna długość to 250 znaków,
  • countryCode (string, pole obowiązkowe) - maksymalna długość to 2 znaki,
  • zipCode (string) - maksymalna długość to 20 znaków,
  • city (string) - maksymalna długość to 50 znaków,
  • street (string) - maksymalna długość to 150 znaków,
  • streetNo (string) - maksymalna długość to 20 znaków,
  • unitNo (string) - maksymalna długość to 20 znaków,
  • state (string) - maksymalna długość to 50 znaków,
  • phoneNo (string) - maksymalna długość to 50 znaków.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/DeliveryAddressUpdate" />
<input type="hidden" name="__template" value="customer/profile-data.html" />
<input type="hidden" name="addressId" value="{{ address.Id }}" />
{% if address.Default %}
<input type="hidden" name="default" value="1" />
{% endif %}
<div>
{% if address.Street == "" %}
{% include 'customer/profile-data-address.html' with -1 %}
{% else %}
{% include 'customer/profile-data-address-pr.html' with address.Id %}
{% endif %}
</div>
<button>Zatwierdź</button>
{% if address.Default == false %}
<button data-id="{{ address.Id }}">{{ translations.Cst_RemoveDeliveryAddress}}</button>
{% endif %}
{% if address.Default == false %}
<button>Zatwierdź</button>
{% endif %}
</form>
 

 
EmailChange
Akcja odpowiadająca zmianie adresu e-mail. Parametry:
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • emailRepeat (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • password (string, pole obowiązkowe),
  • doNotChangeCompanyEmail (bool) - występuje tylko w wersji enterprise.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/EmailChange" />
<input type="hidden" name="__template" value="customer/profile-account.html" />
<input type="email" name="email" placeholder="* {{ translations.Prf_NewEmail }}" required />
<input type="email" name="emailRepeat" placeholder="* {{ translations.Prf_RepeatEmail }}" required />
<input type="password" name="password" placeholder="* {{ translations.Com_Password }}"
required />
<button>Zmień</button>
</form>
 

 
EmployeeAdd
Akcja odpowiada za dodanie pracownika. Parametry:
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="Customer/EmployeeAdd" />
<input type="email" name="email" placeholder="" required />
<button>Zatwierdź</button>
</form>
 

 
EmployeeDelete
Akcja odpowiada za usunięcie pracownika. Parametry:
  • id (int, pole obowiązkowe).
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="Customer/EmployeeDelete" />
<input type="number" name="id" placeholder="" required />
<button>Zatwierdź</button>
</form>
 
 
EmployeeLock
Akcja odpowiada za zablokowanie pracownika. Parametry:
  • id (int, pole obowiązkowe).
<form method="POST"> <input type="hidden" name="__csrf" value="{{ page.CSRF }}"/> 
<input type="hidden" name="__action" value="Customer/EmployeeLock" /> 
<input type="number" name="id" placeholder="" required /> 
<button>Zatwierdź</button> 
</form>
 
 
EmployeeUnlock>
Akcja odpowiada za odblokowanie pracownika. Parametry:
  • id (int, pole obowiązkowe).
<form method="POST"> <input type="hidden" name="__csrf" value="{{ page.CSRF }}"/> 
<input type="hidden" name="__action" value="Customer/EmployeeUnock" /> 
<input type="number" name="id" placeholder="" required /> 
<button>Zatwierdź</button> 
</form>
 
 
EmployeeUpdate
Akcja ta odpowiada za aktualizację danych pracowników w profilu. Parametry:
  • name (string) - maksymalna długość to 50 znaków,
  • name2 (string) - maksymalna długość to 50 znaków,
  • phoneNo (string) - maksymalna długość to 50 znaków,
  • languageId (short lub null).
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="Customer/EmployeeUpdate" />
<input type="text" name="name" placeholder=" "/>
<input type="text" name="name2" placeholder=" " />
<input type="tel" name="phoneNo" placeholder=" " />
<button>Zatwierdź</button>
</form>
 

 
LanguageChange
Odpowiada za wybór i zmianę języka w sklepie. Parametry:
  • languageId (short, pole obowiązkowe).
{% assign lngCount = config.Languages | Size -%}
{% if lngCount > 1 -%}
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/LanguageChange" />
<select name="languageId">
{% for lng in config.Languages -%}
<option value="{{ lng.Id }}" {% if page.LanguageId == lng.Id -%} selected {% endif -%}>{{ lng.Name }}</option>
{% endfor -%}
</select>
{% endif -%}
</form>
 

 
LanguageDefaultUpdate
Odpowiada za ustawienie domyślnego języka. Parametry:
  • languageId (short, pole obowiązkowe).
{% assign lngCount = config.Languages | Size -%}
{% if lngCount > 1 -%}
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/LanguageDefaultUpdate" />
<select name="languageId">
{% for lng in config.Languages -%}
<option value="{{ lng.Id }}" {% if page.LanguageId == lng.Id -%} selected {% endif -%}>{{ lng.Name }}</option>
{% endfor -%}
</select>
{% endif -%}
</form>
 

 
Login
Akcja odpowiadająca za logowanie. Parametry:
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • password (string, pole obowiązkowe),
  • remember (bool).
<form method="POST">
<input type="hidden" name="__action" value="Customer/Login" />
<input type="email" name="email" value="{{ customer.Email }}"
{% if customer.Email == blank %} placeholder="* {{ translations.Com_EmailAddress }} "
{% endif %}
required autofocus />
<input type="password" name="password" placeholder="* {{ translations.Com_Password }}"
required />
<a href="{{ config.DefinedPages.PasswordReminder.Url }}" class="remind">{{ translations.Lgn_DontRememberPassword }}</a>
<button>Login</button>
</form>
 

 
Logout
Akcja ta odpowiada za wylogowanie zalogowanego użytkownika (Klienta).
<form action="{{ page.Url }}{{ page.QueryString | H}}" method="post">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/Logout" />
<button>Wyloguj</button>
</form>
 

 
OldPasswordChange
Akcja odpowiadająca za zmianę hasła. Parametry:
  • oldPassword (string, pole obowiązkowe),
  • password (string, pole obowiązkowe),
  • passwordRepeat (string, pole obowiązkowe).
<form method="POST">
<input type="hidden" name="__action" value="Customer/OldPasswordChange" />
<input type="hidden" name="__template" value="customer/profile-account.html" />
<input type="password" name="oldPassword" placeholder="" required />
<input type="password" name="password" placeholder=" " required />
<input type="password" name="passwordRepeat" placeholder=" " required />
<button>Zatwierdź</button>
</form>
 

 
PasswordChange
Akcja odpowiadająca za zmianę hasła (np. przy pomocy formularza ,,zapomniałem hasła"). Parametry:
  • password (string, pole obowiązkowe),
  • passwordRepeat (string, pole obowiązkowe),
  • hash (string, pole obowiązkowe).
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/PasswordChange" />
<input type="hidden" name="hash" value="{{ page.GET['hash'] }}" >
<input type="password" name="password" value="" required/>
<input type="password" name="passwordRepeat" value="" required/>
<button>Zatwierdź</button>
</form>
 

 
PasswordRecover
Akcja której zadaniem jest odzyskanie hasła. Parametry:
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/PasswordRecover" />
<input type="email" name="email" value="{{ customer.Email }}" required/>
<button>Zatwierdź</button>
</form>
 

 
Register
Akcja ta odpowiada za rejestrację użytkownika. Parametry:
  • company (bool),
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • password (string, pole obowiązkowe),
  • passwordRepeat (string),
  • phoneNo (string) - maksymalna długość to 50 znaków,
  • name (string) - maksymalna długość to 64 znaki,
  • name2 (string) - maksymalna długość to 64 znaki,
  • name3 (string) - maksymalna długość to 250 znaków,
  • countryCode (string) - maksymalna długość to 2 znaki,
  • zipCode  (string) - maksymalna długość to 20 znaków,
  • city (string) - maksymalna długość to 50 znaków,
  • street (string) - maksymalna długość to 150 znaków,
  • streetNo (string) - maksymalna długość to 20 znaków,
  • unitNo (string) - maksymalna długość to 20 znaków,
  • state (string) - maksymalna długość to 50 znaków,
  • tin (string) - maksymalna długość to 20 znaków,
  • ssn (string) - maksymalna długość to 20 znaków,
  • tos (int[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (int),
  • channelKey (string[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (string),
  • vateu (string) - występuje tylko w wersji Enterprise, maksymalna długość to 2 znaki.
Uwaga
W przypadku użytkowników nie będących firmami pola obowiązkowe to jedynie mail oraz password, przykładowy kod dla takiego rozwiązania zawierałby jedynie te dwa pola.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/Register" />
<input type="hidden" name="company" value="{% if registerCompany %}1{% endif %}" />
{% if registerCompany == 0 %}
    <input type="email" name="email" value="{{ customer.Email }}" {% if customer.Email == blank %} placeholder=" " {% endif %} required autofocus />
    <input type="password" name="password" placeholder="* {{ translations.Com_Password }}" required />
    {% if registerCompany %}
        {% if config.ENTERPRISE %}
        <select name="vateu" class="small">
        {% for v in config.VATEU %}
            <option value="{{ v.Value }}">{{ v.Name }}</option>
        {% endfor %}
        </select>
    {% endif %}
    <input type="text" name="tin" class="small nm" placeholder=" " />
{% endif %}
{% if registerConf.AddressVisible %}
    <input type="text" name="name" placeholder=" " {% if customerAddressRequired %} required {% endif %} />
    <input type="text" name="name2" />
    <select name="countryCode" placeholder=" " {% if customerAddressRequired %} required {% endif %} >
    {% for c in config.Countries %}
        <option {% if config.DefaultCountry == c.ISOCode %} selected {% endif %} value="{{ c.ISOCode }}">{{ c.Name }}</option>
    {% endfor %}
    </select>
    <input type="text" name="street" placeholder=" " {% if customerAddressRequired %} required {% endif %} />
    <input type="text" name="streetNo" placeholder=" " {% if customerAddressRequired %} required {% endif %} />
    <input type="text" name="unitNo" placeholder=" " />
    <input type="text" name="zipCode" placeholder=" " {% if customerAddressRequired %} required {% endif %} />
    <input type="text" name="city" placeholder=" " {% if customerAddressRequired %} required {% endif %} />
    {% comment %}
    <input type="text" name="state" placeholder=" " {% if customerAddressRequired %} required {% endif %} />
    {% endcomment %}
{% endif %}
{% if registerConf.PhoneVisible %}
    <input type="tel" name="phoneNo" placeholder=" " {% if registerConf.PhoneRequired %} required {% endif %} />
{% endif %}
<div class="switch">
    {% for tos in config.TOS.Consents.Registration -%}
        {% if tos.Statement %}
            <label>{{tos.Text}}</label>
        {% else %}
            <input name="tos" id="tos{{ tos.Id }}" type="checkbox" value="{{ tos.Id }}" {% if tos.Required %} required {% endif %} />
            <label for="tos{{ tos.Id }}">{% if tos.Required %}*{% endif %} {{tos.Text}}</label>
        {% endif %}
    {% endfor -%}
</div>
<a href="{{ config.DefinedPages.Login.Url }}">{{ translations.Lgn_LoginB }}</a>
</form>
 

 
ReviewAuthorUpdate
Odpowiada za dodanie nicku dla użytkownika który dodaje opinie o produkcie. Parametry:
  • author (string, pole obowiązkowe) - maksymalna długość to 50 znaków.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/ReviewAuthorUpdate" />
<input type="hidden" name="__template" value="customer/profile-account.html" />
<input type="text" name="author" value="{{ customer.ReviewAuthor }}"
placeholder=" " required />
<button>Zatwierdź</button>
</form>
 

 
Update
Akcja odpowiadająca za zmianę danych konta. Parametry:
  • email (string, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • company (bool),
  • name (string, pole obowiązkowe) - maksymalna długość to 64 znaki,
  • name2 (string) - maksymalna długość to 64 znaki,
  • name3 (string) - maksymalna długość to 250 znaków,
  • countryCode (string, pole obowiązkowe) - maksymalna długość to 2 znaki,
  • zipCode (string) - maksymalna długość to 20 znaków,
  • city (string) - maksymalna długość to 50 znaków,
  • street (string) - maksymalna długość to 150 znaków,
  • streetNo (string) - maksymalna długość to 20 znaków,
  • unitNo (string) - maksymalna długość to 20 znaków,
  • state (string) - maksymalna długość to 50 znaków,
  • phoneNo (string) - maksymalna długość to 50 znaków,
  • tin (string) - maksymalna długość to 20 znaków,
  • ssn (string) - maksymalna długość to 20 znaków,
  • invoice (bool),
  • vateu (string) - występuje tylko w wersji Enterprise, maksymalna długość to 2 znaki,
  • subtotalPrices (bool) - występuje tylko w wersji enterprise.
<form action="{{ page.Url }}{{ page.QueryString | H}}" method="post" novalidate>
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Customer/Update" />
<input type="hidden" name="__template" value="customer/profile-data.html" />
<input type="hidden" name="company" value="{% if customer.Company %}1{% endif %}" />
<input type="hidden" name="invoice" value="{% if customer.Invoice %}1{% endif %}" />
<div>
{% if customer.Address.Street <> "" %}
{% include 'customer/profile-data-address-pr.html' with -1 %}
{% if customer.Company %}
{% include 'customer/profile-data-compaddr-pr.html'%}
{% endif %}
{% else %}
{% include 'customer/profile-data-address.html' with -1 %}
{% if customer.Company %}
{% include 'customer/profile-data-compaddr.html'%}
{% endif %}
{% endif %}
</div>
<button>Zatwierdź</button>
{% if customer.Address.Street <> "" %}<button>Zatwierdź</button>{% endif %}<div>
{{ translations.Prf_AccountFor }}: {% if customer.Company == false %}{{ translations.Prf_RetailCustomer }}{%else%}{{ translations.Prf_Company }}{%endif%}
</div>
</form>
 

 
Accept
Umożliwia akceptację zamówienia w sytuacji, gdy mamy do czynienia z np. negocjowalnym kosztem transportu. Parametry:
  • id (int, pole obowiązkowe),
  • hash (string).
<div class="form-js no-message-lq">
    <input type="hidden" name="__action" value="Order/Accept" />
    <input type="hidden" name="id" value="{{ order.Id }}" />
    <input type="hidden" name="hash" value="{{ order.Hash }}" />
    <button class="post-lq parent-container-reload-js">
        {{ translations.OrderAccept }}
    </button>
</div>
 
 
Add
Odpowiada za dodanie zamówienia. Parametry:
  • tos (int[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (int),
  • channelKey (string[]) - może zotać przekazane wielokrotnie w ramach jednej akcji (string).
<div class="form-js adding-order-form-js tos-form-ui {% if settings.cartVersion == 'comfortable' -%} comfortable-tos-ui {% endif -%}">
    <input  aria-label="action-order-add" type="hidden" name="__action" value="Order/Add" />
    {% for tos in config.TOS.Consents.Order -%}
        {% assign channelsSize = tos.Channels | Size -%}
        {% if channelsSize > 0 -%}
            {% assign onlyEmail = false -%}
            {% if channelsSize == 1 and tos.Channels[0].Type == 1 -%}
                {% assign onlyEmail = true -%}
            {% endif -%}
            {% if onlyEmail == false -%}
                <span class="error-ui validation-info-js validation-channel-js hidden-js">{{ translations.ChooseOption }}</span>
            {% endif -%}
        {% endif -%}
        <div class="tos-container-js {% if tos.Statement -%} statement-ui statement-lq {% endif -%}" >
            {% if tos.Statement -%}
                {% unless channelsSize == 1 -%}
                    {% if tos.Required-%}<span class="required-ui">* </span>{% endif -%} {{tos.Text | Remove: '.' }} {{translations.Consents_InTheFormOf}}:
                {% endunless -%}
            {% else -%}
            <label class="checkbox-ui tos-js">
            {% if channelsSize == 1 -%}
                <input aria-label="tos" type="checkbox" name="tos" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} />
            {% elsif channelsSize > 0 -%}
                <input aria-label="tos" type="checkbox" name="tos" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} />
                <span>{% if tos.Required-%}<span class="required-ui">* </span>{% endif -%} {{tos.Text | Remove: '.' }} {{translations.Consents_InTheFormOf}}:</span>
                {% if tos.Required -%}
                    <span class="error-ui validation-info-js validation-required-js hidden-js">{{ translations.RequiredField }}</span>
                {% endif -%}
            {% else -%}
                <input  aria-label="tos" type="checkbox" name="tos" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} />
                <span class="label-ui">{% if tos.Required -%}<span class="required-ui">*</span> {% endif -%}{{ tos.Text }}</span>
                {% if tos.Required -%}
                    <span class="error-ui validation-info-js validation-required-js hidden-js">{{ translations.RequiredField }}</span>
                {% endif -%}
            {% endif -%}
            </label>
            {% endif -%}
            {% if channelsSize > 0 -%}
                {% if onlyEmail == false -%}
                    <span class="error-ui validation-info-js validation-channel-js hidden-js">{{ translations.ChooseOption }}</span>
                {% endif -%}
            {% endif -%}
            {% for channel in tos.Channels -%}
                <label class="checkbox-ui channel-ui {% if channelsSize > 0 -%} channel-js {% endif -%}">
                {% if tos.Statement -%}
                    {% if channelsSize == 1 -%}
                        <input aria-label="channelKey" type="hidden" name="channelKey" value="{{ channel.Key }}" checked />
                        <input aria-label="channelKey" type="checkbox" checked disabled />
                        <span class="statementLabel-ui">{% if tos.Required-%}<span class="required-ui">* </span>{% endif -%} {{tos.Text | Remove: '.' }} {{translations.Consents_InTheFormOf}} {% unless channel.Name == "SMS" -%} {{ channel.Name | Downcase }}. {% else -%} {{ channel.Name }}. {% endunless -%}</span>
                    {% elsif channelsSize > 0 -%}
                        <input aria-label="channelKey" type="checkbox" name="channelKey" value="{{ channel.Key }}" checked />
                        <span class="statementLabel-ui" >{{ channel.Name }}</span>
                    {% endif -%}
                {% else -%}
                    {% if channelsSize == 1 -%}
                        <input  aria-label="channelKey" type="checkbox" name="channelKey" value="{{ channel.Key }}" />
                        <span class="label-ui" style="margin-left: 0 !important;">{% if tos.Required-%}<span class="required-ui">* </span>{% endif -%} {{tos.Text | Remove: '.' }} {{translations.Consents_InTheFormOf}} {% unless channel.Name == "SMS" -%} {{ channel.Name | Downcase }}. {% else -%} {{ channel.Name }}. {% endunless -%}</span>
                    {% elsif channelsSize > 0 -%}
                        <input  aria-label="channelKey" type="checkbox" name="channelKey" value="{{ channel.Key }}" />
                        <span class="label-ui">{{ channel.Name }}</span>
                    {% endif -%}
                {% endif -%}
                </label>
            {% endfor -%}
        </div>
    {% endfor -%}
    <small class="mb10-ui block-ui"><span class="required-ui">*</span> {{ translations.RequiredFields }}</small>
    <div class="order-validation-lq hidden-js message-bar-ui warning-bar-ui">{{translations.ConfirmAll}}</div>
        {% if customer.CreditLimit and creditStatus == 2 -%}
            <div class="order-validation-lq credit-limit-error-ui message-bar-ui error-bar-ui">{{ translations.CreditLimitStatus_2 }}</div>
        {% elsif customer.CreditLimit and creditStatus == 1 -%}
            <div class="order-validation-lq credit-limit-error-ui message-bar-ui warning-bar-ui">{{ translations.CreditLimitStatus_1 }}</div>
        {% endif -%}
        {% if usr.Authenticated or notAuthWithData -%}
            <div class="summary-with-btn-js summary-with-btn-ui" {% if settings.cartVersion == "comfortable" -%} style="display: none;" {% endif -%}>
            <div class="clear-after-ui box-ui">
                <div class="f-left-ui half-ui total-amount-label-ui"><strong>{{ translations.AmountDue }}</strong></div>
                <div class="f-right-ui half-ui total-amount-ui">{{ order.OrderTotalValue | ToPrice }} {{ order.CurrencyExt }}</div>
            </div>
            <button aria-label="order-recalculate" class="order-button-ui parent-container-reload-js {% if creditStatus != 2 -%} add-order-lq {% endif -%}" {% if creditStatus == 2 -%}disabled{% endif -%}>
                {{translations.PayAndOrder}}
            </button>
    </div>
{% endif -%}
</div>
 

 
Cancel
Akcja ta odpowiada za anulowanie zamówienia. Parametry:
  • id (int, pole obowiązkowe),
  • hash (string).
<div class="form-js form-into-data-lq" data-success="{{ translations.OrderCanceled }}">
    <input type="hidden" name="__action" value="Order/Cancel" />
    <input type="hidden" name="id" value="{{ order.Id }}" />
    <input type="hidden" name="hash" value="{{ order.Hash }}" />
    <button class="btn-gray-ui parent-container-reload-js cancel-order-lq">
        {{ translations.OrderCancel }}
    </button>
</div>
 

 
AttachmentAdd
Akcja odpowiada za dodawanie załącznika do zamówienia. Parametry:
  • file - pole do wczytywania plików.
function processFilesList(fileInput, fileList) {
    var file = fileList.pop();
    if (file) {
        var fd = new FormData();
        fd.append('__csrf',__CSRF);
        fd.append('__action','Order/AttachmentAdd');
        fd.append('__template','order/attachements.html');
        fd.append('file', file);
        $.ajax({data: fd, processData: false, contentType: false, type: 'POST',
            success: function(data){
                fileInput.val('');
                if(data.action.Result){
                    $('.attachements-lq').html(data.template);
                } else {
                    if(window.AttachementsNotAdded == undefined){
                        window.AttachementsNotAdded = [];
                    }
                    var attachement = '<div style="padding: 20px;"><strong>'+file.name+'</strong>: '+data.action.Message+'</div>';
                    window.AttachementsNotAdded.push(attachement);
                }
                processFilesList(fileInput, fileList);
            }
        });
 

 
AttachmentDelete
Akcja odpowiada za usuwanie załącznika do zamówienia. Parametry:
  • id (guid, pole obowiązkowe).
function removeAttachementInOrder(e) {
    $.post('', {__csrf: __CSRF, __action: 'Order/AttachmentDelete', id: $(e.currentTarget).data('id')}, function(result) {
        $(e.currentTarget).parents('.file-container-lq').remove();
    });
};
 

 
AttributesSet
Akcja odpowiada za ustawienie atrybutów zamówienia. Parametry:
  • attribute (string[]) - może zotać przekazane wielokrotnie w ramach jednej akcji (string), maksymalna długość to 1000 znaków.
{% assign headerSize = config.Orders.AttributesCart.Header | Size -%}
    {% if headerSize > 0 and settings.cartVersion != "comfortable" -%}
        <div class="form-js header-attributes-set-form-js">
            <input  aria-label="action-order-attributesset" type="hidden" name="__action" value="Order/AttributesSet" />
            <div class="box-ui mt20-ui clear-after-ui address-ui">
                {% for headerAttr in config.Orders.AttributesCart.Header -%}
                    <div class="header-attribute-cart-ui">
                        <label>
                            {{ headerAttr.Name }}
                            {% if headerAttr.Required -%}
                                <span class="required-ui">*</span>
                            {% endif -%}
                        </label>
                        {% case headerAttr.Format -%}
                            {% when 1 -%}
                                <input  aria-label="attribute" type="text" name="attribute" value="" maxlength="50" {% if headerAttr.Required -%} required {% endif -%} {% if positionAttr.Editable -%} data-editable="true" {% endif -%} />
                            {% when 2 -%}
                                <input  aria-label="attribute" type="number" name="attribute" value="" maxlength="50" {% if headerAttr.Required -%} required {% endif -%} {% if positionAttr.Editable -%} data-editable="true" {% endif -%} />
                            {% when 3 -%}
                                <span class="select-background-ui">
                                    <select aria-label="attribute" name="attribute" {% if positionAttr.Editable -%} data-editable="true" {% endif -%}>
                                        {% for val in headerAttr.Values %}
                                            <option {% if val.ValueId == headerAttr.Values[0].ValueId -%} selected="selected" {% endif -%} value="{{ val.ValueId }}">{{ val.Value }}</option>
                                        {% endfor -%}
                                    </select>
                                </span>
                                <i class="ti-angle-down select-arrow-ui"></i>
                            {% when 4 -%}
                                <input aria-label="attribute" type="date" name="attribute" value="" placeholder="rrrr-mm-dd" {% if headerAttr.Required -%} required {% endif -%} {% if positionAttr.Editable -%} data-editable="true" {% endif -%} />
                        {% endcase -%}
                        <div class="error-ui validation-info-js validation-required-js hidden-js">
                            {{ translations.FillAttributeValue }}
                        </div>
                    </div>
                {% endfor -%}
            </div>
        </div>
    {% endif -%}
 

 
ComplaintAdd
Akcja odpowiada za dodanie reklamacji. Parametry:
  • orderId (int, pole obowiązkowe),
  • no (int, pole obowiązkowe),
  • quantity (decimal) - może przyjąć wartość od 0.01 do 99999,
  • message (string) - maksymalna długość to 1000 znaków,
  • accountNumber (string) - maksymalna długość to 50 znaków,
  • defectId (int lub null),
  • requestId (int lub null),
  • defectDate (string, pole obowiązkowe, wyrażenie regularne),
  • files - pole do wczytywania plików.
<form method="POST">
    <input type="text" name="quantity" min="1" placeholder="{{translations.Com_Quantity}}" />
    {% if config.Complaints.Defects <> null -%}
        {% assign defectsSize = config.Complaints.Defects | Size -%}
        <select name="defectId">
        {% if defectsSize > 1 -%}
            <option value="">{% if defectsSize > 1 -%}* {% endif -%} {{translations.Prf_Defect}}</option>
        {% endif -%}
        {% for def in config.Complaints.Defects -%}
            <option value="{{def.Id}}">{{def.Name}}</option>
        {% endfor -%}
        </select>
    {% endif -%}
    <input type="date" name="defectDate" placeholder="RRRR-MM-DD" data-placeholder="year-month-day" value="{{config.Now | Date: "yyyy-MM-dd"}}" max="{{config.Now | Date: "yyyy-MM-dd"}}" min="{{order.Date | Date: "yyyy-MM-dd"}}"/>
    <textarea name="message" placeholder="{{translations.Com_AditionalInfo}}"></textarea>
    {% if config.Complaints.Requests <> null -%}{% assign requestsSize = config.Complaints.Requests | Size -%}
        <select name="requestId">
       {% if requestsSize > 1 -%}
           <option value="">{% if requestsSize > 1 -%}* {% endif %} {{translations.Prf_ComplainRequest}}</option>
       {% endif %}
       {% for req in config.Complaints.Requests -%}
           <option value="{{req.Id}}">{{req.Name}}</option>
       {% endfor -%}
       </select>
    {% endif -%}
    <input type="text" name="accountNumber" placeholder="{{translations.Crt_BankAccountNumber}}" />send
    <button>{{translations.Prf_SubmitAComplaint}}</button>
    <input type="hidden" name="no" value="{{ product.No }}"/>
    <input type="hidden" name="orderId" value="{{ order.Id }}"/>
    <input type="hidden" name="__action" value="Order/ComplaintAdd" />
    <input type="hidden" name="__CSRF" value="{{page.CSRF}}"/>
</form>
 
 
BuyerChange
Akcja odpowiedzialna za zmianę nabywcy. Parametry:
  • buyer (bool).
{% if order.Customer.Buyer == null -%}
    <script>
        $.post('', {__action: 'Order/BuyerChange', buyer: true, __csrf: __CSRF});
    </script>
{% endif -%}
 

 
BuyerUpdate
Akcja odpowiedzialna za aktualizację danych nabywcy. Parametry:
  • name (string, pole obowiązkowe) - maksymalna długość to 64 znaki,
  • name2 (string) - maksymalna długość to 64 znaki,
  • name3 (string) - maksymalna długość to 250 znaków,
  • countryCode (string, pole obowiązkowe) - maksymalna długość to 2 znaki,
  • zipCode (string) - maksymalna długość to 20 znaków,
  • city (string) - maksymalna długość to 50 znaków,
  • street (string) - maksymalna długość to 150 znaków,
  • streetNo (string) - maksymalna długość to 20 znaków,
  • unitNo (string) - maksymalna długość to 20 znaków,
  • state (string) - maksymalna długość to 50 znaków,
  • phoneNo (string) - maksymalna długość to 50 znaków,
  • vateu (string) - maksymalna długość to 2 znaki,
  • tin (string),
  • ssn (string) - maksymalna długość to 20 znaków,
  • invoice (bool),
  • company (bool).
<form method="POST">  
   <input type="text" name="name" value="{% if customerDeliveryAddress.Name != "" -%}{{ customerDeliveryAddress.Name | H }}{% else -%}{{ customerAddress.Name | H }}{% endif -%}" required/> 
   <input type="text" name="street" value="{% if customerDeliveryAddress.Street != "" -%}{{ customerDeliveryAddress.Street | H }}{% else -%}{{ customerAddress.Street | H }}{% endif -%}" required/> 
   <input type="text" name="streetNo" value="{% if customerDeliveryAddress.StreetNo != "" -%}{{ customerDeliveryAddress.StreetNo }}{% else -%}{{ customerAddress.StreetNo }}{% endif -%}" required/> 
   <input type="text" name="countryCode" value="{% if customerDeliveryAddress.CountryCode != "" -%}{{ customerDeliveryAddress.CountryCode }}{% else -%}{{ customerAddress.CountryCode }}{% endif -%}" required/>
   <input type="text" name="unitNo" value="{% if customerDeliveryAddress.UnitNo != "" -%}{{ customerDeliveryAddress.UnitNo }}{% else -%}{{ customerAddress.UnitNo }}{% endif -%}"/> 
   <input type="text" name="zipCode" value="{% if customerDeliveryAddress.ZipCode != "" -%}{{ customerDeliveryAddress.ZipCode }}{% else -%}{{ customerAddress.ZipCode }}{% endif -%}" required/> 
   <input type="text" name="city" value="{% if customerDeliveryAddress.City != "" -%}{{ customerDeliveryAddress.City | H }}{% else -%}{{ customerAddress.City | H }}{% endif -%}" required/> 
   <input type="hidden" name="__csrf" value="{{ page.CSRF }}" /> 
   <input type="hidden" name="__action" value="Order/BuyerUpdate" /> 
</form>
 

 
ComplaintCancel
Akcja ta odpowiada za anulowanie reklamacji. Parametry:
  • complaintId (int, pole obowiązkowe).
<div class="form-js form-into-data-lq">
	<input type="hidden" name="__action" value="Order/ComplaintCancel" />
	<input type="hidden" name="complaintId" value="{{ complaint.ComplaintId }}" />
	<button class="btn-gray-ui parent-container-reload-js cancel-complaint-lq">
   		{{ cancel }}
	</button>
</div>
 

 
Copy
Akcja odpowiadająca za kopiowanie zamówienia. Parametry:
  • orderId (int, pole obowiązkowe),
  • hash (string).
async function copyToCart(trigger, changeToInquiry){
    document.getElementsByClassName('during-ajax-modal-js')[0].classList.remove('hidden-js');
    if(trigger.classList == undefined){
        var trigger = this;
    }
    const id = trigger.dataset.id;
    const hash = trigger.dataset.hash;
    const data = {
        orderId: id,
        hash: hash,
        __action: 'Order/Copy'
    };
    const result = await js.post(data);
 

 
CouponAdd
Akcja pozwalająca na dodanie kuponu. Parametry:
  • code (string, pole obowiązkowe) - maksymalna długość to 40 znaków,
  • email (string, wyrażenie regularne) - maksymalna długość to 192 znaki.
<div class="form-js form-into-data-lq block-ui clear-after-ui {% if settings.cartVersion == 'comfortable' -%} comfortable-coupon-container-ui {% endif -%}">
    <input aria-label="action-order-couponadd" type="hidden" name="__action" value="Order/CouponAdd" />
    <div class="inputs-wrapper-ui clear-after-ui f-left-ui">
        <input aria-label="email" type="hidden" name="email" value="{{ customer.Email }}" />
        <div class="f-left-ui input-wrapper-ui full-ui">
            <span class="f-left-ui">{{ translations.DiscountCode }}</span>
            <input aria-label="code" type="text" class="f-left-ui no-email-ui" name="code" maxlength="50"/>
            <div class="error-ui validation-info-js validation-required-js hidden-js">{{ translations.FillDiscountCode }}</div>
        </div>
    </div>
    <button aria-label="add-coupon" class="add-coupon-lq enter-key-trigger-lq parent-container-reload-js add-coupon-ui f-right-ui">{{ translations.Calculate }}</button>
</div>
 

 
CouponDelete
Akcja umożliwiająca usunięcie kuponu.
<div class="form" id="coupon-delete">
    <button aria-label="deleteCouponButton" type="submit" class="coupon-delete-post"><span class="glyphicon glyphicon-remove"></span> {{translations.Crt_CouponDelete}}</button>
    <p>{{cart.Coupon}}</p>
    <input aria-label="action" type="hidden" name="__action" value="Order/CouponDelete"/>
</div>
 

 
DeliveryAddressUpdate
Akcja odpowiada za uaktualnienie adresu dostawy. Parametry:
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • name (string, pole obowiązkowe) - maksymalna długość to 64 znaki,
  • name2 (string) - maksymalna długość to 64 znaki,
  • name3 (string) - maksymalna długość to 250 znaków,
  • zipCode (string) - maksymalna długość to 20 znaków,
  • city (string) - maksymalna długość to 50 znaków,
  • street (string) - maksymalna długość to 150 znaków,
  • streetNo (string) - maksymalna długość to 20 znaków,
  • unitNo (string) - maksymalna długość to 20 znaków,
  • state (string) - maksymalna długość to 50 znaków,
  • phoneNo (string) - maksymalna długość to 50 znaków.
<form method="POST">
    <input type="email" name="email" value="{% if cart.Customer.Email != "" -%}{{ cart.Customer.Email }}{% else -%}{{ customer.Email }}{% endif -%}" required/>
    <input type="text" name="name" value="{% if customerDeliveryAddress.Name != "" -%}{{ customerDeliveryAddress.Name | H }}{% else -%}{{ customerAddress.Name | H }}{% endif -%}" required/>
    <input type="text" name="name2" value="{% if customerDeliveryAddress.Name != "" -%}{{ customerDeliveryAddress.Name2 | H }}{% else -%}{{ customerAddress.Name2 | H }}{% endif -%}"/>
    <input type="text" name="name3" value="{% if customerDeliveryAddress.Name != "" -%}{{ customerDeliveryAddress.Name3 | H }}{% else -%}{{ customerAddress.Name3 | H }}{% endif -%}"/>
    <input type="text" name="street" value="{% if customerDeliveryAddress.Street != "" -%}{{ customerDeliveryAddress.Street | H }}{% else -%}{{ customerAddress.Street | H }}{% endif -%}" required/>
    <input type="text" name="streetNo" value="{% if customerDeliveryAddress.StreetNo != "" -%}{{ customerDeliveryAddress.StreetNo }}{% else -%}{{ customerAddress.StreetNo }}{% endif -%}" required/>
    <input type="text" name="unitNo" value="{% if customerDeliveryAddress.UnitNo != "" -%}{{ customerDeliveryAddress.UnitNo }}{% else -%}{{ customerAddress.UnitNo }}{% endif -%}"/>
    <input type="text" name="zipCode" value="{% if customerDeliveryAddress.ZipCode != "" -%}{{ customerDeliveryAddress.ZipCode }}{% else -%}{{ customerAddress.ZipCode }}{% endif -%}" required/>
    <input type="text" name="city" value="{% if customerDeliveryAddress.City != "" -%}{{ customerDeliveryAddress.City | H }}{% else -%}{{ customerAddress.City | H }}{% endif -%}" required/>
    <input type="text" name="countryCode" value="{{ config.Countries[customerDeliveryAddress.Country].Name }}" readonly/>
    <input type="tel" name="phoneNo" value="{% if customerDeliveryAddress.PhoneNo != "" -%}{{ customerDeliveryAddress.PhoneNo }}{% else -%}{{ customerAddress.PhoneNo }}{% endif -%}" {% if cart.SelectedDelivery.PhoneRequired -%} required {% endif -%}/>
    <input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
    <input type="hidden" name="__action" value="Order/DeliveryAddressUpdate" />
</form>
 

 
DeliveryChange
Akcja odpowiedzialna za zmianę metody dostawy towaru. Parametry:
  • id (int, pole obowiązkowe),
  • channel (string).
<div class="form-js no-message-lq delivery-form-js">
    <input aria-label="action-order-deliverychange" type="hidden" name="__action" value="Order/DeliveryChange" />
    <input aria-label="id" type="hidden" name="id" data-type="{{ order.SelectedDelivery.CollectionPointTypeId }}" value="{{order.SelectedDeliveryPaymentId}}" />
</div>
 

 
DeliveryCollectionPointChange
Pozwala na wybranie miejsca odbioru paczki (np. przy korzystaniu z paczkomatów). Parametry:
  • id (int, pole obowiązkowe),
  • data (string).
function chooseCollectionPointOnList(e) {
    var id = $(e.currentTarget).data('id');
    $.post(null, {__csrf: __CSRF, __action: 'order/DeliveryCollectionPointChange', id: id});
    window.choosenCollectionPointId = true;
    window.pointChoosen = true;
    $('.choose-collection-point-lq').removeClass('grey-ui');
    $(e.currentTarget).addClass('grey-ui');
    app.replaceTemplate(e);
}
 

 
DeliveryCountryChange
Akcja odpowiedzialna za zmianę kraju dostawy. Parametry:
  • countryCode (string).
<div class="{% if settings.cartVersion != 'comfortable' -%} f-left-ui golden-big-ui {% else -%} comfortable-country-ui {% endif -%} country-ui">
    <div class="form-js no-message-lq half-ui-with-space-ui choose-country-in-cart-ui">
    {% if settings.cartVersion == "comfortable" -%}
        <label class="label-ui">{{ translations.DelivCountry }}</label>
        <div>
    {% else -%}
        <span>{{ translations.DelivCountryInfo }}:</span>
        <span>
    {% endif -%}
    {% assign countriesSize = config.Countries | Size -%}
    {% if countriesSize > 1 -%}
        <span class="select-background-ui">
        <select  aria-label="change-delivery-country" class="change-delivery-country-lq parent-container-reload-js" name="countryCode">
            {% if order.Customer.DeliveryAddress.Country != '' -%}
                {% assign countryCode = order.Customer.DeliveryAddress.Country -%}
            {% elseif customer.Address.Country != '' -%}
                {% assign countryCode = customer.Address.Country -%}
            {% else -%}
                {% assign countryCode = config.DefaultCountry -%}
            {% endif -%}

            {% for country in config.Countries -%}
                <option class="parent-container-reload-js" {% if country.ISOCode == countryCode -%} selected="selected" {% endif -%} value="{{ country.ISOCode }}">
                    {{ config.Countries[country.ISOCode].Name }}
                </option>
            {% endfor -%}
        </select>
        </span>
        <i class="ti-angle-down select-arrow-ui"></i>
    {% else -%}
        {{ config.Countries[0].Name }}
        <input type="hidden" name="countryCode" value="{{config.Countries[0].ISOCode}}">
    {% endif -%}
    {% if settings.cartVersion == "comfortable" -%}
        </div>
    {% else -%}
        </span>
    {% endif -%}
    <input  aria-label="action-order-deliverycountrychange" type="hidden" name="__action" value="Order/DeliveryCountryChange" />
    </div>
</div>
 

 
DeliveryDateChange
Akcja odpowiada za zmianę terminu dostawy. Parametry:
  • date (string, wyrażenie regularne).
<label class="mt20-ui labeui">{{ translations.ScheduledDeliveryDate }}</label>
<div class="form-lq delivery-date-change-form-lq">
  <input type="hidden" name="__action" value="Order/DeliveryDateChange" />
  <input type="{{type}}" name="date" min="{{minDate}}" max="{{maxDate}}" value="{{dateValue}}" />
 </div>
{% elseif order.SelectedDelivery.DateText != "" -%}
<label class="mt20ui labelui">{{ translations.ScheduledDeliveryDate }}</label>
    {{ order.SelectedDelivery.DateText }}
{% endif -%}
 

 
EmailSet
Akcja odpowiada za ustawienie adresu email. Parametry:
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki.
<form method="POST">
    <input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
    <input type="hidden" name="__action" value="Order/EmailSet" />
    <input id="email" type="text" name="email" />
    <button>Zatwierdź</button>
</form>
 
 
FastDeliveryCheck
Akcja ta odpowiada za sprawdzenie możliwości szybszej dostawy kurierskiej. Parametry:
  • zipCode (string) - maksymalna długość to 50 znaków.
<div class="info-ui">
    <div class="mb30-ui">{{ translations.DeligooTextInCart }}</div>
    <div class="mb30-ui form-js form-js check-deligoo-availability-form-js">
        <label>{{ translations.ZipCode }} <span class="required-ui">*</span></label>
        <input aria-label="zipCode" type="text" name="zipCode" value="{{ order.Customer.DeliveryAddress.ZipCode }}" required maxlength="20" {% if order.Customer.DeliveryAddress.ZipCode != '' -%} readonly {% endif -%}/>
        <input aria-label="countryCode" type="hidden" name="countryCode" value="" data-zip-regex="^\d{2}-\d{3}$"/>
        <input aria-label="action" type="hidden" name="__action" value="Order/FastDeliveryCheck"/>
        <button class="check-deligoo-availability-ui check-deligoo-availability-js {% if deligooSelected and order.Customer.DeliveryAddress.ZipCode != '' -%} check-deligoo-when-enter-cart-js {% endif -%} {% if order.Customer.DeliveryAddress.ZipCode != '' -%} hidden-js {% endif -%}">{{ translations.Check }}</button>
        <i class="va-mid-ui ti-check deligoo-success-icon-ui deligoo-success-icon-js hidden-js"></i>
        <i class="va-mid-ui ti-close deligoo-error-icon-ui deligoo-error-icon-js hidden-js"></i>
        <div class="validation-info-js validation-required-js hidden-js register-login-validation-error-text-ui small-input-error-ui small-input-error-ui">
            {{ translations.FillZipCode }}
        </div>
        <div class="validation-info-js validation-zip-code-lq hidden-js register-login-validation-error-text-ui small-input-error-ui">
            {{ translations.FillProperZipCode }} XX-XXX
        </div>
    </div>
    <div class="deligoo-success-js hidden-js">{{ translations.DeligooSuccessInCart }}</div>
    <div class="deligoo-error-js hidden-js">{{ translations.DeligooErrorInCart }}</div>
</div>
 

 
InvoiceAddressUpdate
Akcja ta odpowiada za zmianę danych faktury. Parametry:
  • name (string, pole obowiązkowe) - maksymalna długość to 64 znaki,
  • name2 (string) - maksymalna długość to 64 znaki,
  • name3 (string) - maksymalna długość to 250 znaków,
  • countryCode (string, pole obowiązkowe) - maksymalna długość to 2 znaki,
  • zipCode (string) - maksymalna długość to 20 znaków,
  • city (string) - maksymalna długość to 50 znaków,
  • street (string) - maksymalna długość to 150 znaków,
  • streetNo (string) - maksymalna długość to 20 znaków,
  • unitNo (string) - maksymalna długość to 20 znaków,
  • state (string) - maksymalna długość to 50 znaków,
  • phoneNo (string) - maksymalna długość to 50 znaków,
  • tin (string),
  • ssn (string) - maksymalna długość to 20 znaków,
  • invoice (bool),
  • company (bool),
  • vateu (string) - występuje tylko w wersji Enterprise, maksymalna długość to 2 znaki.
<form id="invoice-address-data">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Order/InvoiceAddressUpdate" />
<input type="hidden" name="company-or-not" value="{% if customer.Company -%}company{% endif -%}" />
<input type="checkbox" name="invoice" {% if cart.Customer.Invoice == true -%}checked{% endif -%}/>
<input id="company" type="checkbox" name="company" {% if cart.Customer.Company -%} checked {% endif -%} />
<input type="hidden" name="company-change" />
<input type="text" name="tin" value="{{ cart.Customer.TIN }}" {% if cart.Customer.Company == false -%} class="hidden" required {% endif -%}/>
<input type="text" name="name" value="{{ cart.Customer.InvoiceAddress.Name | H }}" required/>
<input type="text" name="street" value="{{ cart.Customer.InvoiceAddress.Street | H }}" required/>
<input type="text" name="streetNo" value="{{ cart.Customer.InvoiceAddress.StreetNo }}" required/>
<input type="text" name="unitNo" value="{{ cart.Customer.InvoiceAddress.UnitNo }}"/>
<input type="text" name="zipCode" value="{{ cart.Customer.InvoiceAddress.ZipCode }}" required/>
<input type="text" name="city" value="{{ cart.Customer.InvoiceAddress.City | H }}" required/>
<input type="hidden" name="countryCode" value="{{ country.ISOCode }}" required/>
<select id="select-country">
{% for country in config.Countries -%}
{% if country.ISOCode == customerDeliveryAddress.Country -%}
<option selected="selected" name="countryCode" value="{{ country.ISOCode }}">{{ config.Countries[country.ISOCode].Name }}</option>
{% else -%}
<option name="countryCode" value="{{ country.ISOCode }}">{{ config.Countries[country.ISOCode].Name }}
</option>
{% endif -%}
{% endfor -%}
</select>
<button>Zatwierdź</button>
</form>
 

 
InvoiceChange
Akcja odpowiada za wybranie opcji wystawienia faktury. Parametry:
  • invoice (bool).
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Order/InvoiceChange" />
<input type="checkbox" name="invoice"/>
</form>
 

 
NoteAdd
Akcja odpowiada za dodanie wiadomości do zamówienia. Parametry:
  • note (string) - maksymalna długość to 500 znaków.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Order/NoteAdd" />
<textarea name="note"></textarea>
</form>
 

 
PaymentMake
Akcja odpowiada za dokonywanie płatności. Parametry:
  • id (int, pole obowiązkowe),
  • hash (string, pole obowiązkowe).
<form method="POST">
    <input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
    <input type="hidden" name="__action" value="Order/PaymentMake" />
    <input type="hidden" name="id" value="{{ order.Id }}" />
    <input type="hidden" name="hash" value="{{ customer-profile.Order.Hash }}" />
</form>
 

 
PointsUse
Akcja odpowiada za płacenie punktami.
<div class="flex-ui vertically-centered-ui">
   <p class="f-left-ui">{{translations.WantToUsePoints}}</p>
 <div class="form-lq no-message-lq block-ui">
<input type="hidden" name="__action" value="Order/PointsUse" />
<button class="post-lq parent-container-reload-lq f-right-ui wider-button-ui"><i class="ti-cup"></i> {{ translations.PayViaLoyaltyPoints }}</button>
 </div>
 </div>
 

 
RestorePayment
Akcja odpowiada za możliwość opłacenia zamówienia gdy wcześniej się to nie udało (np. w wyniku awarii internetu). Parametry:
  • id (int, pole obowiązkowe),
  • hash (string).
<div class="form-lq form-into-data-lq">
    <input type="hidden" name="__action" value="Order/RestorePayment" />
    <input type="hidden" name="id" value="{{ order.Id }}" />
    <input type="hidden" name="hash" value="{{ order.Hash }}" />
    <button class="post-lq parent-container-reload-lq" data-url="{{ page.Url }}?{{ orderString | H }}={{ order.Id }}{% if tab -%}&tab={{tab}}{% endif -%}">
        {{ translations.Pay }}
    </button>
</div>
 

 
ReturnAdd
Akcja odpowiedzialna za zwrot. Parametry:
  • orderID (int, pole obowiązkowe),
  • no (int, pole obowiązkowe),
  • quantity (decimal) - może przyjąć wartość od 0.01 do 99999,
  • message (string) - maksymalna długość to 1000 znaków,
  • accountNumber (string) - maksymalna długość to 50 znaków,
  • returnId (int lub null),
  • files - pole do wczytywania plików.
<form method="POST">
<input type="text" name="quantity" min="1" placeholder="{{translations.Com_Quantity}}"/> <span class="unit"></span>
{% assign returnTyppes = config.Complaints.Returns | Size -%}
{% if returnTyppes > 1 -%}
<select name="returnId" placeholder="{{ translations.Prf_ChooseReturn }}">
<option value="">* {{ translations.Prf_ChooseReturn }}</option>
{% for ret in config.Complaints.Returns -%}
<option value="{{ret.Id}}">{{ret.Name}}</option>
{% endfor -%}
</select>
<span class="cs-validation" data-field="returnId" data-validator="required">{{translations.Com_RequiredField}}</span>
{% endif -%}
<textarea name="message" placeholder="{{translations.Com_AditionalInfo}}"></textarea>
<span data-field="message" data-validator="maxLength" data-value="1000">{{translations.Com_MaxLenghtExceeded}}: 1000</span>
<input type="text" name="accountNumber" placeholder="{{translations.Crt_BankAccountNumber}}" />
<span data-field="accountNumber" data-validator="maxLength" data-value="50">{{translations.Com_MaxLenghtExceeded}}: 50</span>
<button>Zatwierdź</button>
<input type="hidden" name="no" value=""/>
<input type="hidden" name="orderId" value=""/>
<input type="hidden" name="__action" value="Order/ReturnAdd" />
<input type="hidden" name="__CSRF" value="{{page.CSRF}}"/>
</form>
 

 
StatusGet
Akcja odpowiedzialna za pobranie statusu zamówienia. Parametry:
  • id (int, pole obowiązkowe),
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki.
<form>
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Order/StatusGet" />
<input type="hidden" name="id" value="{{ customer-profile.Order.Id }}" />
<input type="email" name="email" placeholder="" required />
<button>Zatwierdź</button>
</form>
 
 
TinUpdate
Akcja odpowiedzialna za aktualizację numeru TIN. Parametry:
  • vateu (string) - maksymalna długość to 2 znaki,
  • tin (string),
  • ssn (string) - maksymalna długość to 20 znaków.
<form> 
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Order/TinUpdate" /> 
<input type="email" name="tin" value="{{ config.Shop.TIN }}"/>
<button>Zatwierdź</button> 
</form>
 

 
StepNext
Akcja odpowiedzialna za kolejny krok w przypadku składania zamówienia.
<div class="no-message-lq">
	<input type="hidden" name="__action" value="Order/StepNext" />
    <button class="post-lq parent-container-reload-lq">
        <i class="fa fa-angle-right"></i>
    </button>
</div>
 

 
StepPrev
Akcja odpowiedzialna za powrót do poprzedniego kroku podczas składania zamówienia.
<div class="no-message-lq">
	<input type="hidden" name="__action" value="Order/StepPrev" />
    <button class="post-lq parent-container-reload-lq">
        <i class="fa fa-angle-left"></i>
    </button>
</div>
 

 
Subscribe
Kod odpowiadający za subskrypcję do newslettera. Parametry:
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • tos (int[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (int),
  • channelKey (string[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (string).
<form id="NewsletterSubscribeForm" action="{{ page.Url }}{{ page.QueryString | H}}" method="post" novalidate>
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Newsletter/Subscribe" />
<input type="email" name="email" value="{{ customer.Email }}"
{% if customer.Email == blank -%} placeholder="* {{ translations.Com_EmailAddress }}" {% endif -%} required />
<button title="{{ translations.Nls_NewsletterSubscribeTooltip }}">+</button>
<div class="switch ">
{% for tos in config.TOS.Consents.Newsletter -%}
{% if tos.Statement -%}
<label>{{tos.Text}}</label>
{% else -%}
<input name="tos" id="tos{{ tos.Id }}" type="checkbox" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} />
<label for="tos{{ tos.Id }}">{% if tos.Required -%}*{% endif -%} {{tos.Text}}</label>
{% endif -%}
{% endfor -%}
</div>
<span class="legend">* {{ translations.Reg_RequiredFieldsExp }} </span>
</form>

{% for channel in tos.Channels -%}
<label class="checkbox-ui channel-ui {% if onlyEmail == false -%} channel-lq {% endif -%} {% if tos.Statement == false -%} disabled-channel-lq {% endif -%}">
{% if onlyEmail == false -%}
<input type="checkbox" name="channelKey" value="{{ channel.Key }}" {% if tos.Statement == false -%} disabled {% endif -%} />
{% else -%}
<input type="hidden" name="channelKey" value="{{ channel.Key }}" checked />
<input type="checkbox" checked disabled />
{% endif -%}
<span class="label-ui">{{ channel.Name }}</span></label>
{% endfor -%}
 

 
Unsubscribe
Kod odpowiedzialny za wypisanie się z subskrypcji mailowej.
<form id="NewsletterUnsubscribeForm" action="{{ page.Url }}{{ page.QueryString | H}}" method="post">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Newsletter/Unsubscribe" />
<input type="hidden" name="__template" value="customer/profile-account.html" />
<p>{{ customer.Email }}</p>
<button>Anuluj subskrypcję</button>
</form>
 

CollectionPointCities
Akcja odpowiada za pobranie miast, w których znajdują się punkty odbioru. Parametry:
  • country (string) - maksymalna długość to 2 znaki,
  • typeId (short),
  • all (bool),
  • stockLevels (bool).
     $.get('', {__csrf:__CSRF, __action:'Get/CollectionPointCities', stockLevels: true}, function(res){
            window.CitiesWithPOO = res.action.Object;
            $('.show-shops-infos-lq').html('');
            var size = window.CitiesWithPOO.length;
            for(i=0; i<size; i++){
                $('.show-shops-infos-lq').append(''+window.CitiesWithPOO[i]+'');
            }
        });
 

 
CollectionPoints
Akcja odpowiada za pobranie punktów odbioru towarów. Parametry:
  • country (string) - maksymalna długość to 2 znaki,
  • city (string) - maksymalna długość to 50 znaków,
  • typeId (short),
  • all (bool),
  • stockLevels (bool).
<div class="box-ui clear-after-ui"/>
{% if order.SelectedDelivery.CollectionPoint -%}
    <div class="f-left-ui cart-option-ui address-ui half-ui-with-space-ui collection-point-info-lq"/>
        <p/>
            {% if order.SelectedDelivery.CollectionPointTypeId == 2 -%}
                {{ translations.ChoosenInpostMachine }}
            {% else -%}
                {{ translations.ChoosenCollectionPoint }}
            {% endif -%}
        <p/>
        <div class="right-corner-ui">
            <button class="btn-pure-ui other-address-ui show-map-in-order-lq">
                  <i class="va-mid-ui ti-pencil"></i>
                  <span class="va-mid-ui line-height-1-ui"/<{{translations.Change}}</span>
             </button>
         </div >
         <div class="box-ui clear-after-ui">
  {% assign cp = order.SelectedDelivery.CollectionPoint -%}
            {% assign name = cp.Address | Split:',' | Last | Split:'(' | First -%}
            {% if name == '' or name == ' ' or name == '  ' -%}
                {% assign name = cp.Address | Split:'(' | Last | Remove:')' -%}
                {% capture name -%}{{name}}{% endcapture -%}
            {% endif -%}
<p><strong>{{name}}</strong></p>
<p>{{cp.Street}} {{cp.StreetNo}}{% if cp.UnitNo != null and cp.UnitNo != '' -%}/{{cp.UnitNo}}{% endif -%}</p>
<p>{{cp.ZipCode}} {{cp.City}}</p>
<p>{{cp.Country}}</p>


 

 
Groups
Pobiera grupy podrzędne dla wskazanej grupy. Akcja ta umożliwia zbudowanie dynamicznego menu czy breadcrumbs. Parametry:
  • groupId (int),
  • languageId (short),
  • levels (int).
<script type="text/javascript">
 (function () {
$(function () {
 $('nav.breadcrumbs>ol>li').hover( 
 function () { 
 var t = $(this), gId = ('' + t.data('id')).split(',')[1]; 
 if (gId && t.find('ol').length == 0) { 
 $.get(null, { __action: 'Get/Groups', groupId: gId, languageId: __lngId }, function (d) { 
 var obj = d.action.Object; 
 if (obj.length) { 
 var ol = $('<ol></ol>'); 
 t.append(ol); 
 $.each(obj, function (i, el) { 
 var a = $('<a></a>').attr('href', el.Url).text(el.Title); 
 ol.append(a); 
 a.wrap('<li></li>') 
});
}
});
}
 else t.find('ol').show(); 
},
 function () { 
 $(this).find('ol').hide(); 
}
);
});
 })(jQuery); 
</script>
 

 
Search
Akcja odpowiada za wyszukiwarkę. Parametry:
  • search (string, pole obowiązkowe) - maksymalna długość to 100 znaków.
<div class="form-js input-field-search-ui {{ noSearchOnMobile }} quick-search-form-js {% if settings.autofill == 'yes' %} autocomplete-form-js {% endif -%}">
    <input type="hidden" name="__action" aria-label="get/search-action" value="Get/Search" />
    <input placeholder="{{ translations.SearchArticleDots }}" aria-label="search" type="search" class="search-ui" value="" name="search" maxlength="100" {% if settings.autofill == 'yes' %} autocomplete="off" data-max-autocomplete-products="{{settings.autofillQuantity}}" {% endif -%} />
    <button class="ti-search search-btn-ui quick-search-js enter-key-trigger-lq" title="{{ translations.Search }}"></button>
</div>
 

 
SearchAdvanced
Akcja odpowiada za zaawansowaną wyszukiwarkę. Parametry:
  • search (string) - maksymalna długość to 100 znaków,
  • searchAll (string) - maksymalna długość to 100 znaków,
  • searchAny (string) - maksymalna długość to 100 znaków,
  • searchWild (string) - maksymalna długość to 100 znaków,
  • fields (int) - przyjmuje jedną z podanych niżej wartości:
      • 2 – szukaj w opisie,
      • 4 – szukaj w atrybutach,
      • 8 – szukaj w kodzie produktu,
      • 128 – szukaj w symbolu,
      • 256 – szukaj w EAN,
      • 512 – szukaj w kodzie u producenta.
  • flags (int) - przyjmuje jedną z podanych niżej wartości:
      • 1 – ma zdjęcie,
      • 2 – nowość,
      • 4 – promocja,
      • 8 – produkt z gazetki,
      • 16 – produkt polecany,
      • 32 – wyprzedaż,
      • 64 – super jakość,
      • 128 – super cena,
      • 256 – najlepiej oceniany,
      • 512 – rekomendacja sprzedawcy.
      • 1024 – towar za punkty.
  • priceFrom (long lub null),
  • priceTo (long lub null),
  • groupId (int lub null),
  • manufactureId (int lub null),
  • brandId (int lub null).
Wskazówka
Flagi można sumować — wartość wpisana do metody to suma wartości poszczególnych flag. Jeżeli suma będzie równa np. 14, wyszukanie nastąpi po flagach:
  • nowość,
  • promocja,
  • produkt z gazetki.
<div class='element-attached-lq search-inputs-ui'>
    <input aria-label="action-searchAdvanced" type='hidden' name='__action' value='Get/SearchAdvanced' />
	<input aria-label="search" type='search' name='search' class='attach-on-mobile-lq advanced-search-input-ui advanced-search-input-lq' placeholder="{{translations.SearchPhrase}}" maxlength="100" />
	<select aria-label="groupId" name="groupId" class='groupId'>
		<option value="" >{{translations.AllCategories}}</option>
        {% for category in page.GroupNodes -%}
            {% assign t = category.Id | Split:',' %}
			<option value="{{ t[1] }}">{{category.Name}}</option>
		{% endfor -%}
	</select>
	<i class="ti-angle-down select-arrow-ui"></i>	   
	<button aria-label="advanced-search-button" class="attach-on-mobile-lq post-lq advanced-search-button-ui">
		<span>{{ translations.Search }}</span>
		<i class="ti-search"></i>
	</button>
</div>
<div class="categories-adv-search-mobile-ui">{{ translations.SearchIn }}</div>
<div class='price-and-phrase-container'>
	<label class="checkbox-ui control-ui control-radio-ui">
        <input aria-label="tos-search" name="tos" type="radio" class='search-radio-ui search-radio-lq' value='search' checked>
            {{translations.WithSequence}}
        <span class="control-indicator-ui"></span>
    </label>
    <label class="checkbox-ui control-ui control-radio-ui">
        <input aria-label="tos-searchall" name="tos" type="radio" class='search-radio-ui search-radio-lq' value="searchAll">
            {{ translations.WithAllWords }}
		<span class="control-indicator-ui"></span>
    </label>
	<label class="checkbox-ui control-ui control-radio-ui" >
        <input aria-label="tos-searchany" name="tos" type="radio" class='search-radio-ui search-radio-lq' value="searchAny">
            {{ translations.WithAnyWord }}
		<span class="control-indicator-ui"></span>
    </label>
	<label class="checkbox-ui control-ui control-radio-ui">
        <input aria-label="tos-searchwild" name="tos" type="radio" class='search-radio-ui search-radio-lq' value="searchWild" >
            {{ translations.WithPartOfWord }}
     	<span class="control-indicator-ui"></span>
    </label>
</div>
 

 
SearchAutocomplete
Akcja odpowiada za wyświetlanie podpowiedzi 5 towarów w trakcie wyszukiwania. Parametry:
  • search (string, pole obowiązkowe) - maksymalna długość to 100 znaków.
function autocomplete(e) {
    let phrase = e.target.value.replace(/[*]*/gi, '');
    const maxAutocompleteProducts = e.target.dataset.maxAutocompleteProducts;
    if (phrase != '' && phrase.length > 1) {
        $.get(location.pathname, { __action: 'Get/SearchAutocomplete', search: phrase }).then(function (res) {
            if($(window).width() > 1279){
                var right = 'right: 50px';
            } else if($(window).width() > 680){
                var right = '';
            } else {
                var right = 'right: 61px';
            }
            var loader = '';
            $('.quick-search-form-js.autocomplete-form-js').append(loader);
            var url = res.action.Redirect302;
            $.get(url, {__collection:'products.Products|page.BaseHref|currencyExt.Symbol|config.Products.ShowCode'}, function(res) {
                $('.autocomplete-js').remove();
                var list = res.collection['products.Products'];
                var showCode = res.collection['config.Products.ShowCode'];
                if (list.length > 0){
                    if (list.length > maxAutocompleteProducts) {
                        var size = maxAutocompleteProducts;
                    } else {
                        var size = list.length;
                    }
                    var baseHref = res.collection['page.BaseHref'];
                    var currency = res.collection['currencyExt.Symbol'];
 

 
SearchFilters
Akcja odpowiada za zastosowanie filtrów wyszukiwania. Parametry:
  • __skipParameter (string[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (string).
<input type="hidden" name="__action" value="Get/SearchFilters">

<button class="selected-filter-item-ui selected-filter-item-js" data-field="all">
    <i class="ti-close filter-delete-ui"></i>
    <span>{{translations.ResetFilters}}</span>
</button>

{% unless customer.HidePrices -%}
    {% if products.FilteringOptions.PriceFrom != null and products.FilteringOptions.PriceFrom > 0 -%}
        <button class="selected-filter-item-ui selected-filter-item-js" data-field="$minPrice">
            <i class="ti-close filter-delete-ui"></i>
            <span>{{translations.PriceFrom}} <strong>{{products.FilteringOptions.PriceFrom}}</strong> {{customer.CurrencyExt}}</span>
        </button>
        <input aria-label="minPrice" name="$minPrice" type="hidden" value="{{products.FilteringOptions.PriceFrom}}" maxlength="12">
    {% endif -%}

    {% if products.FilteringOptions.PriceTo != null -%}
        <button class="selected-filter-item-ui selected-filter-item-js" data-field="$maxPrice">
            <i class="ti-close filter-delete-ui"></i>
            <span>{{translations.PriceTo}} <strong>{{products.FilteringOptions.PriceTo}}</strong> {{customer.CurrencyExt}}</span>
        </button>
        <input aria-label="maxPrice" name="$maxPrice" type="hidden" value="{{products.FilteringOptions.PriceTo}}" maxlength="12">
    {% endif -%}
{% endunless -%}
 

 
ProductId
Akcja ta pozwala na zwrócenie wartości ID towaru znajdującego się w bazie e-Sklepu na podstawie ID towaru w bazie systemu ERP (GIDNumber). Może być przydatna podczas pisania własnych dodatków dla Comarch e-Sklep Sync. Parametry:
  • gidNumbers (int[], pole obowiązkowe).
<script type="text/javascript">
function getProductID(...gidNumbers) {
	jQuery.get(null, jQuery.param(
		{__action:'Get/ProductId', gidNumbers: gidNumbers}, true), 
		res => res.action.Object
	);
},
</script>
Uwaga
Akcja dostępna jest w sklepach B2B od wersji 2021.2.

 
AskForPrice
Akcja odpowiada za złożenie zapytania o cenę produktu. Parametry:
  • productId (int, pole obowiązkowe),
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • phoneNo (string) - maksymalna długość to 20 znaków,
  • quantity (decimal, pole obowiązkowe) - może przyjąć wartość od 0.01 do 99999,
  • unitId (int lub null),
  • message (string) - maksymalna długość to 500 znaków.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Product/AskForPrice" />
<input type="hidden" name="productId" value="{{ product.Id }}" />
<input type="email" name="email" value="{{ customer.Email }}" required />
<input type="tel" name="phoneNo" value="{{ customer.Address.PhoneNo }}"/>
<input type="button" value="-" />
<input type="text" name="quantity" value="1" min="1" max="99999"/>
<input type="button" value="+" field='quantity'/>
{% if product.Units[1] -%}
{% for unit in product.Units -%}
<input type="button" value="{{ unit.Name }}"/>
<input type="hidden" value="{{ unit.Id }}" data-ratio="{{ unit.Ratio }}"/>
{% endfor -%}
{% endif -%}
{% for unit in product.Units -%}
{% if unit.Default == true or unit.Id == null -%}
<input name="unitId" type="hidden" value="{{ unit.Id }}"/>
{% endif -%}
{% endfor -%}
<textarea type="text" name="message" required></textarea>
<button>Zatwierdź</button>
</form>
 

 
CollectionPointsStockLevelsGet
Akcja odpowiada za pobieranie stanów magazynowych w salonach danego towaru. Parametry:
  • products (string, pole obowiązkowe),
  • country (string) - maksymalna długość to 2 znaki,
  • city (string) - maksymalna długość to 50 znaków,
  • pointTypeId (short),
  • pointId (int lub null).
function showShopsInfos(e) {
    var city = $(e.currentTarget).val();
    if(city != ''){
        var productType = $('[name=productType]').val();
        if (productType == 'batch'){
            var productId = $('[data-product-id]').data('product-id');
            var supplyId = $('[data-supply-id].active-lq').data('supply-id');
        } else if (productType == 'clip'){
            var productId = $('[data-supply-id].active-lq').data('supply-id');
        } else {
            var productId = $('[data-product-id]').data('product-id');
        }
        var downloaded = false;
        var index = '';
        if(window.productsWithPOO){
            var size = window.productsWithPOO.length;
            for(i=0; i<size; i++){
                index = i;
                if(window.productsWithPOO[i].name == city+'-'+productId+'-'+supplyId){
                    downloaded = true;
                    index = i;
                    break;
                }
            }
            if(!downloaded){
                window.productsWithPOO.push({name: city+'-'+productId+'-'+supplyId});
                index = index + 1;
            }
        } else {
            window.productsWithPOO = [];
            window.productsWithPOO.push({name: city+'-'+productId+'-'+supplyId});
            index = 0;
        }
        if(!downloaded){
            $('.during-ajax-modal-lq').removeClass('hidden-lq');
            $.post(null, {__csrf:__CSRF, __action:'Product/CollectionPointsStockLevelsGet',city:city ,products:JSON.stringify([{ProductId:productId, SupplyId:supplyId}])},function(res){
                if(window.productsWithPOO[index].name == city+'-'+productId+'-'+supplyId){
                    window.productsWithPOO[index].shops = res.action.Object;
                    appendShopsInfos(window.productsWithPOO[index].shops);
                    $('.during-ajax-modal-lq').addClass('hidden-lq');
                }
            });
        } else {
            appendShopsInfos(window.productsWithPOO[index].shops);
        }
    }
};

 
Wskazówka
Jeżeli chcesz pokazać w e-Sklepie ilości towaru w podziale na magazyny (e-Sklepu i hurtowni), to można je pobrać akcją 'Product/StockLevelsGet'.
 

 
ComparisonToolAdd
Akcja odpowiadająca za dodanie produktu do porównania z innym produktem. Parametry:
  • productId (int, pole obowiązkowe).
<form action="{{ page.Url }}{{ page.QueryString | H }}" method="post">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="Product/ComparisonToolAdd" />
<input type="hidden" name="productId" value="{{ productD.Id }}"/>
<input type="hidden" name="url" value="{{ page.BaseHref }}{{ config.DefinedPages.ProductComparisonTool.Url }}"/>
</form>
 

 
ComparisonToolDelete
Akcja odpowiada za usunięcie przedmiotu z porównania. Parametry:
  • productId (int, pole obowiązkowe).
{% for product in comparer.Products -%}
<form action="{{ page.Url }}{{ page.QueryString | H }}" method="post">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="Product/ComparisonToolDelete" />
<input type="hidden" name="productId" value="{{ product.Id }}"/>
<button>Zatwierdź</button>
</form>
{% endfor -%}
 

 
DeliveryCostGet
Akcja odpowiada za pobranie najniższej ceny dostawy dla danego towaru. Parametry:
  • id (int, pole obowiązkowe),
  • unitId (int lub null, pole obowiązkowe).
<p class="delivery hidden">{{translations.Com_DeliveryFrom}}: {{currency}}</p>
<script>
    Number.prototype.format = function(n, x, s, c) {
       var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
       num = this.toFixed(Math.max(0, ~~n));
       return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
    };
    Number.prototype.toPrice = function () {
       var decimalPlaces = __decimalPlacesPrice || 2;
       return this.format(decimalPlaces, 3, __decThoSep, __decSep);
    }
    $.get('', {__action:'Product/DeliveryCostGet', id: '{{_pd.Id}}' },function(res){
       if(res.action.Object.Cost > 0){
           $('.delivery').removeClass('hidden');
           $('.delivery-cost').text(res.action.Object.Cost.toPrice());
       }
    });
</script>
 
 
FastDeliveryCheck
Akcja odpowiadająca za sprawdzenie dostępności usługi szybkiej dostawy w podanej lokalizacji. Parametry:
  • products (string, pole obowiązkowe),
  • country (string) - maksymalna długość to 2 znaki,
  • zipCode (string) - maksymalna długość to 50 znaków.
<form action="{{ page.Url }}{{ page.QueryString | H }}" method="post">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input aria-label="action" type="hidden" name="__action" value="Product/FastDeliveryCheck" />
<input aria-label="zipCode" type="text" name="zipCode" value="{{ customer.Address.ZipCode }}" maxlength="50"/>
<input aria-label="country" type="hidden" name="country" value="" />
<input aria-label="products" type="hidden" name="products" value='[{"ProductId":{{ product.Id }}}]' />
<button>Zatwierdź</button>
</form>
 
 
NotifyAboutProductAvailability
Akcja odpowiadająca za złożenie zapytania odnośnie poinformowania użytkownika o ponownej dostępności towaru. Parametry:
  • productId (int, pole obowiązkowe),
  • name (string, pole obowiązkowe) - maksymalna długość to 50 znaków,
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • phoneNo (string) - maksymalna długość to 20 znaków.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Product/NotifyAboutProductAvailability" />
<input type="hidden" name="productId" value="{{ product.Id }}" />
<input type="email" name="email" value="{{ customer.Email }}" required />
<input type="text" name="name" value="{{ customer.Address.Name }}" required />
<input type="tel" name="phoneNo" value="{{ customer.Address.PhoneNo }}"/>
<button>Zatwierdź</button>
</form>
 

 
ReviewAdd
Akcja odpowiadająca za dodanie opinii na temat produktu. Parametry:
  • rating (short, pole obowiązkowe) - może przyjąć wartość od 1 do 5,
  • comment (string, pole obowiązkowe) - maksymalna długość to 4000 znaków,
  • author (string, pole obowiązkowe) - maksymalna długość to 50 znaków,
  • productId (int, pole obowiązkowe),
  • orderHash (string).
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="Product/ReviewAdd" />
<input type="text" name="author" {% if customer.Authenticated == true -%}{% if customer.ReviewAuthor != "" -%} value="{{ customer.ReviewAuthor | H }}" {% else -%} value="{{ customer.Address.Name | H }}" {% endif -%}{% endif -%} required />
<textarea type="text" name="comment" required></textarea>
<input type="hidden" name="rating" value="5"/>
<input type="hidden" name="productId" value="{{ product.Id }}"/>
<input type="hidden" name="orderHash" value=""/>
<button>Zatwierdź</button>
</form>
 
 
StockLevelsGet
Akcja odpowiada za pobieranie stanów magazynowych z podziałem na magazyny (e-Sklepu i hurtowni). Parametry:
  • id (int lub int[], pole obowiązkowe).
const productsId = [13, 27, 31]; 
$.get(null, {__action:'Product/StockLevelsGet', id: productsId}, function(res) { 
      if(res.action.Object) { 
          console.log(res.action.Object); 
      } 
});
Dla powyższej akcji zostanie zwrócony ten sam obiekt Stock (jak np. na szczegółach towaru), ale z dwoma dodatkowymi właściwościami: > WarehouseId, > WarehouseName. Właściwości mogą być puste (null) - jeśli jest to stan z ERP, a nie z hurtowni.  

 
WishListAdd
Akcja odpowiedzialna za dodanie produktu do listy życzeń. Parametry:
  • productId (int, pole obowiązkowe),
  • quantity (decimal) - może przyjąć wartość od 1 do 99999,
  • note (string) - maksymalna długość to 500 znaków.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="product/WishListAdd" />
<input type="hidden" name="productId" value="{{ product.Id }}" required />
<input type="text" name="quantity" value="1"/>
<input type="button" value="+" field="quantity"/>
<textarea name="note"></textarea>
<button>Zatwierdź</button>
</form>
 
 
WishListCheck
Akcja odpowiedzialna za sprawdzenie czy produkt należy do listy życzeń. Parametry:
  • products (int[]).
$.get(null, { __action: 'Product/WishListCheck', products: JSON.stringify([parseInt(productId)]) }, function (result) {
                if (result.action.Object != '') {
                    //Product in wishlist
                    if (!($('.productDetails-buttons--wishList').hasClass('wishListPopup-js'))) {
                        $('input[aria-label="wishListAdd"]').val('Product/WishListDelete');
                        $('.productDetails-buttons--wishList__removeProduct').removeClass('hidden');
                        $('.productDetails-buttons--wishList__addProduct').addClass('hidden');
                        $('.productDetails-buttons--wishList__svgIcon').html('<use xlink:href="css/img/icons-sprite.svg#heart-solid"></use>');
                        $('.productDetails-buttons--wishList').removeClass('productWishListAdd-js').addClass('productWishListRemove-js');
                    }
                } else {
                    //Product not in wishlist
                    if (!($('.productDetails-buttons--wishList').hasClass('wishListPopup-js'))) {
                        $('input[aria-label="wishListAdd"]').val('Product/WishListAdd');
                        $('.productDetails-buttons--wishList__removeProduct').addClass('hidden');
                        $('.productDetails-buttons--wishList__addProduct').removeClass('hidden');
                        $('.productDetails-buttons--wishList__svgIcon').html('<use xlink:href="css/img/icons-sprite.svg#heart-light"></use>');
                        $('.productDetails-buttons--wishList').removeClass('productWishListRemove-js').addClass('productWishListAdd-js');
                    }
                }
            });
 

 
WishListDelete
Akcja odpowiadająca za usuwanie przedmiotu z listy życzeń. Parametry:
  • productId (int lub null).
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="product/WishListDelete" />
<input type="hidden" name="productId" value="{{ product.Id }}" required />
<button>Zatwierdź</button>
</form>
 

 
WishListUpdate
Akcja odpowiada za ustawienie/zmianę daty na liście życzeń. Parametry:
  • productId (int),
  • note (string) - maksymalna długość to 500 znaków,
  • notify (bool),
  • notifyDate (string, wyrażenie regularne).
function updateReminderDate(e) {
    var container = $('.after-adding-to-wishlist-popup-lq .after-adding-to-cart-popup-container-lq');
    var message = $(e.currentTarget).data('success');
    var productId = $(e.currentTarget).data('id');
    var inputVal = $(e.currentTarget).val();
    var data = {
        productId: productId,
        __csrf: __CSRF,
        __action: 'Product/WishListUpdate'
    };
    if(inputVal != ""){
        var date = inputVal + ' 06:00:00';
        data.notify = true;
        data.notifyDate = date;
    } else {
        data.notify = false;
    }
    $.post(null, data);
};
 

Add
Odpowiada za dodanie produktów do koszyka. Parametry:
  • productId (int, pole obowiązkowe),
  • quantity (decimal) - może przyjąć wartość od 0.01 do 99999,
  • unitId (int lub null),
  • attributeId (long[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (long),
  • attributeEditable (string[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (string),
  • supplyId (int lub null),
  • cartId (int lub null).
<form method="POST">
<input type="number" name="quantity" value="1" required/>
<input type="hidden" name="productId" value="{{productdetails.Product.Id}}" />
<input type="hidden" name="__CSRF" value="{{page.CSRF}}" />
<input type="hidden" name="__action" value="Cart/Add" />
<button type="submit">Dodaj do koszyka</button>
</form>
 

 
AttributesSet
Akcja odpowiada za ustawianie atrybutów na koszyku. Parametry:
  • no (int lub null),
  • attribute (string[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (string), maksymalna długość to 1000 znaków.
<form method="POST">
{% if page.PageId == config.DefinedPages.Order.Id -%}
        {% assign attributes = config.Orders.AttributesCart.Position -%}
	{% assign positionAttrSize = attributes | Size -%}
	{% assign showInCart = true -%}
	{% assign action = 'Cart/AttributesSet' -%}
{% endif %}
	<input type="hidden" name="__action" value="{{ action }}" />
	<input type="hidden" name="no" value="{{ product.No }}" />
</form>
 

 
Change
Akcja odpowiada za zmianę koszyka. Parametry:
  • id (int, pole obowiązkowe).
<form method="POST">
{% if customer.Carts[1] -%}
            <input type="hidden" name="__action" value="Cart/Change" />
            <input type="hidden" name="id" />
            <ul>
                {% for cart in customer.Carts -%}
                    <li class="choose-cart-lq" data-id="{{ cart.Id }}" data-name="{{ cart.Name | H }}">{{ translations.Cart }} {{ cart.Name }}</li>
                {% endfor -%}
            </ul>
{% endif -%}
</form>
 
 
Create
Akcja odpowiada za utworzenie nowego koszyka. Parametry:
  • inquiry (bool).
if(parameters && !validationError){
            var obj = {
                parameters: JSON.stringify(parameters),
                loadParent: loadParent,
                e: e,
                form: form
            };
            var activeInquiryId = window.app.getCookie('activeInquiryId');
            if((activeInquiryId == -1 || activeInquiryId == '') && $(e.currentTarget).hasClass('add-to-inquiry-lq')){
                $.post('', {__action: 'Cart/Create', inquiry: true, __csrf: __CSRF}, function(result) {
                    var inquiryId = result.action.Object.CartId;
                    for(var i=0; i<parameters.length; i++){
                        parameters[i].cartId = inquiryId;
                    }
                    obj.parameters = JSON.stringify(parameters);
                    js.addManyProductsToCart(obj, e);
                });
            } else {
                js.addManyProductsToCart(obj, e);
            }
        }
 

 
Delete
Akcja ta umożliwia usunięcie wszystkich produktów z koszyka.
<form method="POST">
<input type="hidden" name="__CSRF" value="{{page.CSRF}}" />
<input type="hidden" name="__action" value="Cart/Delete" />
<button type="submit">USUŃ</button>
</form>
 

 
ExternalAdd
Akcja dla konfiguratora produktów. Dodaje do koszyka zawartość zwróconą z sync. Parametry:
  • id (int, pole obowiązkowe),
  • type (int).
if(a.Result && e.hasClass('sendCart-lq')){ 
                $('.set-price-lq').html('');
                $.post(null, {__CSRF:__CSRF, __action:'cart/externalAdd', id:a.Object.Id}, result => {
                    var cartId = window.app.getCookie('lastCartId');
                    $.get('', {__collection: 'customer.Cart.Count|customer.Cart.Value|customer.Cart.EditedOrderId|customer.CurrencyExt.Symbol'}, function (result) {
                        var cartCount = result.collection['customer.Cart.Count'];
                        var cartValue = result.collection['customer.Cart.Value'].toPrice();
                        var editedOrderId = result.collection['customer.Cart.EditedOrderId'];
                        if(editedOrderId != null && activeInquiryId == -1){
                            window.app.setCookie('lastCartId', -1);
                        }
                        $('.carts-change-popup-lq .selected-cart-ui').removeClass('selected-cart-ui');
                        $('.change-cart-link-js[data-id='+cartId+']').parent().addClass('selected-cart-ui');
                        $('.cart-count-lq').text(cartCount);
                        $('.counter-bg-lq').removeClass('hidden-js');
                        $('.cart-value-lq').text(cartValue);
                        $('.cart-value-with-currency-lq').text(cartValue+' '+result.collection['customer.CurrencyExt.Symbol']);
                        $('.load-cart-lq[data-cart-id]').attr('data-cart-id', cartId);
                    });

                    app.afterAddingToCart(e, result.action.message, null, result.template);
                }); 
            }
 

 
ImportCSV
Akcja odpowiada za importowanie koszyka z pliku. Parametry:
  • file - pole do wczytywania plików,
  • separator (char lub null),
  • decimalSeparator (char lub null).
importCSV: function(e){
        $('.during-ajax-modal-lq').removeClass('hidden-lq');
        var file = $(e.currentTarget);
        file.addClass('prevent-double-change-lq');
        var fd = new FormData();
        fd.append('__csrf',__CSRF);
        fd.append('__action','Cart/ImportCSV');
        fd.append('file', e.currentTarget.files[0]);
        $.ajax({data: fd, processData: false, contentType: false, type: 'POST',
            success: function(data){
                file.val('');
                if(data.action.Multiple){
                    var results = data.action.Results;
                    var imported = true;
                    var validationArr = [];
                    for(var i=0; i<results.length; i++){
                        if(!results[i].Result){
                            imported = false;
                            var name = results[i].Object.NameNoHtml;
                            var message = results[i].Message
                            if(results[i].Description != null){
                                message += ' ' + results[i].Description;
                            }
                            validationArr.push({name:name, message:message});
                        }
                    }
                } else {
                    if(data.action.Result){
                        var imported = true;
                    } else {
                        var imported = false;
                    }
                }


 

 
NameSet
Akcja odpowiada za ustawienie nazwy wybranego koszyka. Parametry:
  • id (int, pole obowiązkowe),
  • name (string) - maksymalna długość to 30 znaków.
$('body').on('change','.carts-change-popup-lq input',function(e){
        $.post(null,{__csrf:__CSRF,__action:'Cart/NameSet',id:$(this).data('id'),name:$(this).val()},function(){location.reload();});
    });
 

 
PositionDelete
Odpowiada za usuwanie danej pozycji z koszyka. Parametry:
  • no (int, pole obowiązkowe),
  • position (bool).
<div class="form-js flr-ui no-message-lq">
    <input type="hidden" name="__action" value="Cart/PositionDelete" />
    <input type="hidden" name="no" value="{{ product.No }}" />
    {% if product.IsSetElement -%}
	<input type="hidden" name="position" value="true" />
    {% endif -%}
    <button class="remove-product-from-cart-lq parent-container-reload-js btn-pure-ui ti-trash {% if productsSize == 1 -%} last-product-lq {% endif -%}" title="{{ translations.Delete }}"></button>
    <span class="remove-product-from-cart-lq parent-container-reload-js mobile-ui {% if productsSize == 1 -%} last-product-lq {% endif -%}">{{ translations.Delete }}</span>
</div>
 

 
QuantityChange
Akcja powoduje zmianę ilości przedmiotu w koszyku. Parametry:
  • quantity (decimal, pole obowiązkowe) - może przyjąć wartość od 0.01 do 99999,
  • no (int, pole obowiązkowe).
<form method="POST">
Produkt: {{cart.Products[forloop.index0].NameNoHtml}}<br/>
Ilość: {{cart.Products[forloop.index0].Quantity}}<br/>
<button>Zwiększ ilość o 1</button>
<input type="hidden" name="quantity" value="{{cart.Products[forloop.index0].Quantity | ToInt | Plus: 1}}"/>
<input type="hidden" name="no" value="{{cart.Products[forloop.index0].No}}"/>
<input type="hidden" name="__CSRF" value="{{page.CSRF}}" />
<input type="hidden" name="__action" value="cart/QuantityChange" />
</form>
 

 
Recalculate
Odpowiada za ponowne przeliczenie koszyka.
<form method="post">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="cart/Recalculate" />
<input type="hidden" name="__template" value="order/cart.html" />
<input type="hidden" name="__collection" value="customer.Cart.Value" />
</form>
 

 
SetAdd
Akcja obsługuje dodawanie zestawu produktów. Parametry:
  • productId (int, pole obowiązkowe),
  • setId (int, pole obowiązkowe),
  • quantity (int) - może przyjąć wartość od 1 do 99,
  • attributeId (int[]) - może zotać przekazane wielokrotnie w ramach jednej akcji (int),
  • supplyId (int[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (int).
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}"/>
<input type="hidden" name="__action" value="cart/SetAdd" />
<input type="hidden" name="productId" value="{{ product.Id }}" />
<input type="text" name="productId" value="{{set.SetId }}" required/>
<input type="text" name="setId" value="1"/>
<button>Zatwierdź</button>
</form>
 

 
SetExtAdd
Akcja obsługuje dodawanie nowego zestawu produktów. Parametry:
  • setId (int, pole obowiązkowe),
  • quantity (int) - może przyjąć wartość od 1 do 99,
  • products (Object[], pole obowiązkowe) - jako argument przyjmuje tablicę obiektów zawierających dane produktów z zestawu.
if(form.hasClass('add-set-to-cart-lq')){
	var set = {setId:Number($(e.currentTarget).data('set-id')), quantity:1, products:[]};
    var setProducts = form.find('.set-product-lq');
    setProducts.each(function () {
		var setProduct = {
			setElementId: Number($(this).data('set-element-id')),
			setProductId: Number($(this).data('set-product-id'))
		};
		if($(this).find('[name=attributePolyvalent]').length > 0){
			var attributesPolyvalent = [];
			$(this).find('[name=attributePolyvalent]').each(function(){
				var attribute = {
					id: Number($(this).data('id')),
					valueId:  Number($(this).val())
				};
				attributesPolyvalent.push(attribute);
			});
			setProduct.attributesPolyvalent = attributesPolyvalent;
		}
		if($(this).find('[name=attributeEditable]').length > 0){
			var attributesEditable = [];
			$(this).find('[name=attributeEditable]').each(function(){
				var attribute = {
					id: Number($(this).data('id')),
					value:  $(this).val()
				};
				attributesEditable.push(attribute);
			});
			setProduct.attributesEditable = attributesEditable;
		}
		set.products.push(setProduct);
    });
	var data = [
		{name: "__csrf", value: __CSRF}, 
		{name: "__action", value: 'Cart/SetExtAdd'}, 
		{name: "set", value: JSON.stringify(set)}
	];
}
 

 
AskAboutProduct
Akcja pozwalająca na złożenie zapytania o produkt. Parametry:
  • productId (int, pole obowiązkowe),
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • phoneNo (string) - maksymalna długość to 20 znaków,
  • name (string, pole obowiązkowe) - maksymalna długość to 50 znaków,
  • message (string, pole obowiązkowe) - maksymalna długość to 500 znaków,
  • copy (bool).
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Contact/AskAboutProduct" />
<input type="hidden" name="productId" value="{{ product.Id }}" />
<input type="email" name="email" value="{{ customer.Email }}" required />
<input type="text" name="name" value="{{ customer.Address.Name }}" required />
<input type="tel" name="phoneNo" value="{{ customer.Address.PhoneNo }}"/>
<textarea type="text" name="message" required></textarea>
<input type="checkbox" name="copy"/>
<button>Zatwierdź</button>
</form>
 

 
Send
Akcja odpowiadająca za wysłanie zawartości formularza kontaktowego. Parametry:
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • name (string) - maksymalna długość to 50 znaków,
  • phoneNo (string) - maksymalna długość to 20 znaków,
  • subject (string, pole obowiązkowe) - maksymalna długość to 50 znaków,
  • message (string, pole obowiązkowe) - maksymalna długość to 500 znaków,
  • copy (bool),
  • contactId (int lub null),
  • files - pole do wczytywania plików. Maksymalna ilość załączników jest określona w obiekcie config.Contact.AttachmentsMaxCount,
  • macro_xx (string) - pole zdefiniowane przez użytkownika. Może występować wiele razy. Napis xx jest edytowalny, ale przedrostek musi pozostać taki sam. Przykładem poprawnej nazwy jest: macro_Pole1.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Contact/Send" />
<input type="hidden" name="copy" value="1" />
<input type="email" name="email" value="{{ customer.Email }}"
{% if customer.Email == blank -%} placeholder="* {{ translations.Com_EmailAddress }}" {% endif -%}
required />
<input type="tel" name="phoneNo" value="{{ customer.Address.PhoneNo }}"
placeholder="{{ translations.Prf_Telephone }}" />
<input type="text" name="subject" placeholder="* {{ translations.Cfm_Subject }}" required autofocus />
<textarea type="text" name="message" placeholder="* {{ translations.Pps_Message }}" required /></textarea>
<input 
	type="file" 
	name="resume" 
	id="resume"  
	required 
	accept="{{ config.Contact.AttachmentExtensions }}" 
	data-file-size="{{ config.Contact.AttachmentMaxSize }}" 
	data-size-exceeded="{{ translations.Com_FileSizeExceeded | Format: maxSize }}"
	data-invalid-file="{{ translations.Com_InvalidFile | Format: config.Contact.AttachmentExtensions }}"
	data-not-added-info="{{translations.AttachementsNotAdded}}"
>
<button>Zatwierdź</button>
</form>
Przykład modyfikacji w szablonie Bursztyn z użytymi polami macro_xx:
<div class="contact-form {% if settings.googleMapsKey != '' and config.Shop.Address.Latitude != 0 and config.Shop.Address.Longitude != 0 -%} col-md-4 {% endif%} col-sm-12 col-xs-12">
			<div class="row">
				<div class="content form-content">
					<div class="title">{{ translations.Cff_WriteEmail }}</div>
					<form class="reg-form"
					id="ContactSendForm" action="{{ page.Url }}{{ page.QueryString | H}}" method="post">
						<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
						<input type="hidden" name="__action" value="Contact/Send" />
						<input type="hidden" name="copy" value="1" />

						<input type="email" name="email" value="{{ customer.Email }}" 
						{% if customer.Email == blank -%} placeholder="* {{ translations.Com_EmailAddress }}" {% endif -%} 
						required />	
						<input type="tel" name="phoneNo"  value="{{ customer.Address.PhoneNo }}" 
						placeholder="{{ translations.Prf_Telephone }}" />
						<input type="text" name="subject" placeholder="* {{ translations.Cfm_Subject }}" required autofocus />
						<textarea type="text" name="message" placeholder="* {{ translations.Pps_Message }}" required /></textarea>

						<input type="text" name="macro_Pole1" placeholder="* Pole1" required />
						<input type="text" name="macro_Pole2" placeholder="* Pole2" required />

						<span class="legend">* {{ translations.Reg_RequiredFieldsExp }} </span>
						<button class="primary-action">{{ translations.Com_Send }}</button>
					</form>
				</div>
			</div>
		</div>
		
		{% if settings.googleMapsKey != '' and config.Shop.Address.Latitude != 0 and config.Shop.Address.Longitude != 0 -%}
			<div id="map-canvas" class="col-md-8 col-xs-12"></div>
		{% endif %}
	</div>
Aby pola użytkownika były widoczne w mailu ze strony kontakt należy należy dodać w ich treści zdefiniowane pola. Przykład dodania takich pól poniżej:
<div style="padding: 20px; margin: 20px; font-family: Arial, Helvetica, sans-serif; text-align: left; border: 1px solid #cc6600; font-size: 12pt;"><h2 style="color: #cc6600;">ZAPYTANIE ZE STRONY INTERNETOWEJ</h2><br />
<p>Nadawca: <a href="mailto:{{ customer.Email }}"><b>{{ customer.Email }}</b></a><br />Temat: <b>{{ subject }}</b></p>
<p>Treść wiadomości:<br /> {{ message }}</p> 

<pre>
  Pole 1 {{userFields.macro_Pole1}}
  Pole 2 {{userFields.macro_Pole2}}
</pre>

</div>
Tworzymy pomocniczą tablice zawierającą ścieżki do plików. Przykład:
 addAttachementInResume: function(e) {
        window.attachementsInResume = [];
        var filesArr = $(e.currentTarget).parents('.inputs-container-js').find('.addAttachementInResume-js');
        filesArr.each(function () {
            if(this.files.length > 0){
                var maxSize = $(this).data('file-size');
                if(this.files[0].size > maxSize){
                    var message = $('[data-not-added-info]').data('not-added-info') + '.
' + this.files[0].name + '
: ' + $(this).data('size-exceeded');
                    app.showTemporaryPopup(message, 'error', '', 8000);
                    $(this).val('');
                    $(this).next().hide();
                } else {
                    window.attachementsInResume.push(this.files[0]);
                    $(e.currentTarget).siblings('.fileInfo-js').html(this.files[0].name);
                }
            }
        });
    }
W celu przesłania ciała akcji najlepiej użyć FormData (JavaScript API), do której przekażemy kolejne pola. Pliki przekazujemy jako file0, file1, .. fileN. Przykład poniżej:
postResume: function(e) {
        if(app.validationBeforePost(e) != 'error'){
            var form = $(e.currentTarget).parents('.inputs-container-js');
            var dataFromHTML = form.find('input:not([disabled]), select:not([disabled]), textarea:not([disabled])').serializeArray();
            var fileList = window.attachementsInResume;
            if(fileList != undefined){
                var filesSize = fileList.length;
            }
            var fd = new FormData();
            fd.append('__csrf', __CSRF);
            for(var i=0; i<dataFromHTML.length; i++){ fd.append(dataFromHTML[i].name,dataFromHTML[i].value); } if (filesSize > 0) {
                window.AttachementsErrors = 0;
                function addAttachementError(file, message) {
                    if(window.AttachementsNotAdded == undefined){
                        window.AttachementsNotAdded = [];
                    }
                    var attachement = ' '+file.name+': '+message+' ';
                    window.AttachementsNotAdded.push(attachement);
                    window.AttachementsErrors += 1;
                };
                var input = form.find('[type=file]').eq(0);
                var extensions = input.attr('accept').split(', ');
                var fileSize = input.data('file-size');
                for (var i=0; i<filesSize; i++) {
                    var file = fileList.pop();
                    if(file.size < fileSize){
                        var extensionArr = file.name.split('.');
                        var extension = '.' + extensionArr[extensionArr.length - 1].toLowerCase();
                        var wrongExtension = true;
                        for(var j=0; j<extensions.length; j++){
                            if(extension == extensions[j]){
                               fd.append('file'+i, file);
                               var wrongExtension = false;
                            }
                        }
                        if(wrongExtension){
                           var message = input.data('invalid-file');
                           addAttachementError(file, message); 
                        }
                    } else {
                        var message = input.data('size-exceeded');
                        addAttachementError(file, message);
                    }
                }
                if(window.AttachementsNotAdded){
                    var message = $('[data-not-added-info]').data('not-added-info') + window.AttachementsNotAdded.join('');
                    app.showTemporaryPopup(message, 'error', '', 8000);
                    window.AttachementsNotAdded = undefined; window.AttachementsErrors = undefined;
                }
            }
            $.ajax({ data: fd, processData: false, contentType: false, type: 'POST', success: function (data) {
                $('.addAttachementInResume-js').val('');
                if (data.action.Result) {
                    var message = form.data('success-info');
                    app.showTemporaryPopup(message, 'success', '', 8000);
                    $('.clearFileInput-js').hide();
                    app.hidePopup(e);
                } else {
                    app.showTemporaryPopup(data.action.Description, 'error', '', 8000);
                }
            }};
            $('.fileInfo-js').html('');
        }
},
 

 
TellFriendAboutProduct
Akcja odpowiedzialna za wysłanie powiadomienia odnośnie danego produktu do innej osoby poprzez e-mail. Parametry:
  • productId (int, pole obowiązkowe),
  • email (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • name (string) - maksymalna długość to 50 znaków,
  • message (string, pole obowiązkowe) - maksymalna długość to 500 znaków,
  • copy (bool),
  • friendEmail (string, pole obowiązkowe, wyrażenie regularne) - maksymalna długość to 192 znaki,
  • friendName (string) - maksymalna długość to 50 znaków.
<form method="POST">
<input type="hidden" name="__csrf" value="{{ page.CSRF }}" />
<input type="hidden" name="__action" value="Contact/TellFriendAboutProduct" />
<input type="hidden" name="productId" value="{{ product.Id }}" />
<input type="email" name="email" value="{{ customer.Email }}" required />
<input type="text" name="name" value="{{ customer.Address.Name }}" />
<input type="email" name="friendEmail" required />
<input type="text" name="friendName" />
<textarea type="text" name="message" required></textarea>
<button>Zatwierdź</button>
</form>
 

 
Accept
Akcja odpowiedzialna za wysłanie żądania o zastosowanie wszystkich zmian. Parametry:
  • orderId (int, pole obowiązkowe).
 this.accept = function (aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/Accept',
                    __csrf: __CSRF,
                    orderId: this.orderId,
                    __template: this.orderTemplateUrl,
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;
                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    window.UIFeatures.pureReplaceTemplate(thisRef.orderTemplateContainer, null, null, res.template, thisRef.orderRequestUrl);
                    if (!res.action.Result) {
                        $('.during-ajax-modal-lq').addClass('hidden-lq');
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action, 'warning'));
                    }
                    thisRef.recalculationRequired = false;
                    window.app.setCookie('lastCartId', -1);
                });
            }
 

 
AttributesSet
Akcja odpowiedzialna za edycję atrybutów odnoszących się bezpośrednio do zamówienia. Parametry:
    • orderId (int, pole obowiązkowe),
    • attribute (string[]) - może zostać przekazane wielokrotnie w ramach jednej akcji (string), maksymalna długość to 1000 znaków.
<div class="remarks-ui">
    <div class="form-js header-attributes-set-form-js">
        <input type="hidden" name="__action" value="OrderEdit/AttributesSet" />
        <input type="hidden" name="orderId" value="{{ order.Id }}" />
        {% assign i = 0 -%}
        {% for headerAttr in config.Orders.AttributesEdit.Header -%}
            {% assign intId = headerAttr.Id | ToInt -%}
            {% unless headerAttr.Editable == false and order.Attributes[intId].Value == null -%}
                {% assign i = i | Plus: 1 -%}
                {% assign modulo = i | Modulo: 3 -%}
                {% if modulo == 1 -%}
                    <div class="order-info-row-ui">
                {% endif -%}
                <div class="order-info-item-ui">
                    <div class="name-ui">
                        {{ headerAttr.Name }}
                        {% if headerAttr.Required -%}
                            <span class="required-ui">*</span>
                        {% endif -%}
                    </div>
                    <div class="content-ui">
                        {% if headerAttr.Editable -%}
                            {% case headerAttr.Format -%}
                                {% when 1 -%}
                                    <input type="text" name="attribute" value="{{ order.Attributes[intId].Value }}" maxlength="50" {% if headerAttr.Required -%} required {% endif -%} />
                                {% when 2 -%}
                                    <input type="number" name="attribute" value="{{ order.Attributes[intId].Value }}" maxlength="50" {% if headerAttr.Required -%} required {% endif -%} />
                                {% when 3 -%}
                                    <span class="select-background-ui">
                                        <select name="attribute">
                                            {% for val in headerAttr.Values %}
                                                <option {% if val.ValueId == headerAttr.Values[0].ValueId or val.ValueId == order.Attributes[intId].ValueId -%} selected="selected" {% endif -%} value="{{ val.ValueId }}">{{ val.Value }}</option>
                                            {% endfor -%}
                                        </select>
                                    </span>
                                    <i class="ti-angle-down select-arrow-ui"></i>
                                    {% when 4 -%}
                                        <input type="date" name="attribute" value="{{ order.Attributes[intId].Value | Date:dateFormat }}" {% if headerAttr.Required -%} required {% endif -%} />
                            {% endcase -%}
                            <div class="error-ui validation-info-js validation-required-js hidden-js">
                                {{ translations.FillAttributeValue }}
                            </div>
                        {% else -%}
                            {{ order.Attributes[intId].Value }}
                        {% endif -%}
                    </div>
                </div>
                {% if modulo == 0 or i == ordAttrSize -%}
		    </div>
		{% endif -%}
	    {% endunless -%}
	{% endfor -%}
    </div>
    <div class="mt20-ui small-text-ui"><span class="required-ui">*</span> {{ translations.RequiredFields }}</div>
</div>
 

 
Cancel
Akcja odpowiedzialna za wysłanie żądania o anulowaniu wszystkich zmian. Parametry:
    • orderId (int, pole obowiązkowe).
    this.cancel = function (aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/Cancel',
                    __csrf: __CSRF,
                    orderId: this.orderId,
                    __template: this.orderTemplateUrl,
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;
                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    window.UIFeatures.pureReplaceTemplate(thisRef.orderTemplateContainer, null, null, res.template, thisRef.orderRequestUrl);
                    if (!res.action.Result) {
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action, 'warning'));
                    }
                    thisRef.recalculationRequired = false;
                    window.app.setCookie('lastCartId', -1);
                    if($('.escape-editing-lq').length > 0 ){
                        $('.escape-editing-lq').trigger('click');
                    }
                });
            }
 

 
CartCreate
Akcja odpowiedzialna za wysłanie żądania o utworzenie koszyka do edycji zamówienia.
    • orderId (int, pole obowiązkowe).
  this.cartCreate = function (aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/CartCreate',
                    __csrf: __CSRF,
                    orderId: this.orderId,
                    __template: this.orderTemplateUrl,
                    __collection: 'config.DefinedPages.Home.Url|customer-profile.OrderQueryGET'
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;
                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    // check if cartId avalible, and put in cookies
                    if (!res.action.Result) {
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action, 'warning'));
                    } else {
                        window.app.setCookie('OrderQueryGET', res.collection['customer-profile.OrderQueryGET']);
                        window.app.newUrl(res.collection['config.DefinedPages.Home.Url']);
                    }
                });
            }
 

 
CartMerge
Akcja odpowiedzialna za wysłanie żądania o połączenie koszyka z edytowanym zamówieniem. Parametry:
    • orderId (int lub null).
    this.cartMerge = function (messagesContainerSelector, aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/CartMerge',
                    __csrf: __CSRF,
                    __collection: 'config.DefinedPages.CustomerProfile.Url'
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;
                return window.UIFeatures.makePostRequest(data, null, function (res) {
                    if (res.action.Result) {
                        //temp order url - to change in future (when profile routing will be implemented)
                        var orderQueryGET = window.app.getCookie('OrderQueryGET');
                        window.app.setCookie('OrderQueryGET', '', -1);
                        if(orderQueryGET.indexOf('&tab=order-details') === -1){
                            window.app.newUrl(res.collection + '?' + orderQueryGET + '=' + thisRef.orderId + '&tab=order-details');
                        } else {
                            window.app.newUrl(res.collection + '?' + orderQueryGET + '=' + thisRef.orderId);
                        }
                    } else {
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action));
                    }
                });
            }
 

 
Edit
Akcja odpowiedzialna za wysłanie żądania o rozpoczęcie procesu edycji.
    • orderId (int, pole obowiązkowe).
       this.edit = function (aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/Edit',
                    __csrf: __CSRF,
                    orderId: this.orderId,
                    __template: this.orderTemplateUrl,
                    __collection: 'customer-profile.Order.RecalculationRequired'
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;
                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    window.UIFeatures.pureReplaceTemplate(thisRef.orderTemplateContainer, null, null, res.template, thisRef.orderRequestUrl);
                    if (!res.action.Result) {
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action, 'warning'));
                    }
                    thisRef.recalculationRequired = res.collection;
                });
            }
 

 
PositionAttributesSet
Akcja odpowiedzialna za edycję atrybutów poszczególnych towarów w zamówieniu. Parametry:
    • orderId (int, pole obowiązkowe),
    • no (int, pole obowiązkowe),
    • attribute (string[]) - może zostać przekazane wielokrotnie w ramach jednej akcji, maksymalna długość to 1000 znaków.
<div class="form-js position-attributes-set-form-js">
    <input type="hidden" name="__action" value="OrderEdit/PositionAttributesSet" />
    <input type="hidden" name="no" value="{{ product.No }}" />
    {% if showInCustomerProfile -%}
	<input type="hidden" name="orderId" value="{{ order.Id }}" />
    {% endif -%}
    {% for positionAttr in attributes -%}
	{% assign intId = positionAttr.Id | ToInt -%}
	{% if nullAttributes != '' -%}
		{% assign isNull = false -%}
		{% for nullAttribute in nullAttributes -%}
			{% if nullAttribute == positionAttr.Id -%}
			        {% assign isNull = true -%}
				{% break -%}
			{% endif -%}
		{% endfor -%}
	{% else -%}
		{% assign isNull = false -%}
	{% endif -%}
	{% if isNull == false -%}
		{% assign mod = i | Modulo:5 -%}
		{% if mod == 0 -%}
			{% assign pageNo = pageNo | Plus:1 -%}
		{% endif -%}
  		<div class="div-table-cell-ui attributes-view-cell-ui {% if order.EditingAllowed -%} order-edit-active-ui {% endif -%} attributes-view-lq hidden-js page{{pageNo}}-lq">
			{% if positionAttr.Editable -%}
				<label class="mobile-ui">{{ positionAttr.Name }} {% if positionAttr.Required -%} <span class="required-ui"> *</span>{% endif -%}</label>
	  			{% case positionAttr.Format -%}
					{% when 1 -%}
		    	  			<input type="text" name="attribute" value="{{ product.Attributes[intId].Value }}" maxlength="50" {% if positionAttr.Required -%} required {% endif -%} />
					{% when 2 -%}
						<input type="number" name="attribute" value="{{ product.Attributes[intId].Value }}" maxlength="50" {% if positionAttr.Required -%} required {% endif -%} />
					{% when 3 -%}
				    		<span class="select-background-ui">
							<select name="attribute">
								{% for val in positionAttr.Values %}
									<option {% if val.ValueId == positionAttr.Values[0].ValueId or val.ValueId == product.Attributes[intId].ValueId -%} selected="selected" {% endif -%} value="{{ val.ValueId }}">{{ val.Value }}</option>
								{% endfor -%}
							</select>
				        	</span>
				        	<i class="ti-angle-down select-arrow-ui"></i>
					{% when 4 -%}
						<input type="date" name="attribute" value="{{ product.Attributes[intId].Value | Date:'yyyy-MM-dd' }}" placeholder="rrrr-mm-dd" {% if positionAttr.Required -%} required {% endif -%} />
				{% endcase -%}
				<div class="error-ui validation-info-js validation-required-js hidden-js">
			    		{{ translations.FillAttributeValue }}
				</div>
			{% else -%}
				{{ product.Attributes[intId].Value }}
			{% endif -%}
    		</div>
    		{% assign i = i | Plus:1 -%}
    	{% endif -%}
    {% endfor -%}
    {% assign mod = i | Modulo:5 -%}
    {% if mod != 0 -%}
    	{% for obj in (mod..4) -%}
		<div class="div-table-cell-ui attributes-view-cell-ui {% if order.EditingAllowed -%} order-edit-active-ui {% endif -%} attributes-view-lq hidden-js page{{pageNo}}-lq"></div>
	{% endfor -%}
    {% endif -%}
</div>
 

 
PositionDelete
Akcja odpowiedzialna za wysłanie żądania o usunięcie pozycji. Parametry:
    • orderId (int, pole obowiązkowe),
    • no (int, pole obowiązkowe).
  this.positionDelete = function (posNo, aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/PositionDelete',
                    __csrf: __CSRF,
                    no: posNo,
                    orderId: this.orderId,
                    __template: this.orderTemplateUrl,
                    __collection: 'customer-profile.Order.RecalculationRequired'
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;
                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    window.UIFeatures.pureReplaceTemplate(thisRef.orderTemplateContainer, null, null, res.template, thisRef.orderRequestUrl);
                    if (!res.action.Result) {
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action, 'warning'));
                    }
                    thisRef.recalculationRequired = res.collection;
                });
            }
 

 
PositionQuantityChange
Akcja odpowiedzialna za wysłanie żądania o zmianę ilości danej pozycji. Parametry:
    • orderId (int, pole obowiązkowe),
    • no (int, pole obowiązkowe),
    • quantity (decimal, pole obowiązkowe) - może przyjąć wartość od 0.01 do 99999.
this.positionQuantityChange = function (posNo, quantity, messagesContainerSelector, aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/PositionQuantityChange',
                    __csrf: __CSRF,
                    no: posNo,
                    orderId: this.orderId,
                    quantity: quantity,
                    __template: this.orderTemplateUrl,
                    __collection: 'customer-profile.Order.RecalculationRequired'
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;
                if(aditionalRequestData.orderDetPageId && thisRef.orderRequestUrl.indexOf('orderDetPageId='+aditionalRequestData.orderDetPageId) === -1){
                    if(thisRef.orderRequestUrl.indexOf('orderDetPageId') !== -1){
                        thisRef.orderRequestUrl = thisRef.orderRequestUrl.substring(0, thisRef.orderRequestUrl.indexOf('&orderDetPageId')) + '&orderDetPageId=' + aditionalRequestData.orderDetPageId;
                    } else {
                        thisRef.orderRequestUrl = thisRef.orderRequestUrl + '&orderDetPageId=' + aditionalRequestData.orderDetPageId;
                    }
                }

                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    window.UIFeatures.pureReplaceTemplate(thisRef.orderTemplateContainer, null, null, res.template, thisRef.orderRequestUrl);
                    if (!res.action.Result) {
                        var container = $(messagesContainerSelector);
                        container.find('.error-msg-lq').remove();
                        var messageContainer = '<div class="quantity-error-ui error-msg-lq">'+res.action.Description+'</div>';
                        container.append(messageContainer);
                        container.find('.error-msg-lq').delay(3000).fadeOut(300, function(){
                            $(this).remove();
                        });
                    }
                    thisRef.recalculationRequired = res.collection;
                });
            }
 

 
PositionUndo
Akcja odpowiedzialna za wysłanie żądania o cofnięcie wszystkich zmian danej pozycji w zamówieniu. Parametry:
    • orderId (int, pole obowiązkowe),
    • no (int, pole obowiązkowe).
 this.undo = function (aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/Undo',
                    __csrf: __CSRF,
                    orderId: this.orderId,
                    __template: this.orderTemplateUrl,
                    __collection: 'customer-profile.Order.RecalculationRequired'
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;

                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    window.UIFeatures.pureReplaceTemplate(thisRef.orderTemplateContainer, null, null, res.template, thisRef.orderRequestUrl);
                    if (!res.action.Result) {
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action, 'warning'));
                    }
                    thisRef.recalculationRequired = res.collection;
                });
            }
 

 
Recalculate
Akcja odpowiedzialna za wysłanie żądania o przeliczenie zamówienia. Parametry:
  • orderId (int, pole obowiązkowe).
     this.recalculate = function(aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/Recalculate',
                    __csrf: __CSRF,
                    orderId: this.orderId,
                    __template: this.orderTemplateUrl,
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;
                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    window.UIFeatures.pureReplaceTemplate(thisRef.orderTemplateContainer, null, null, res.template, thisRef.orderRequestUrl);
                    if (!res.action.Result) {
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action, 'warning'));
                    }
                    thisRef.recalculationRequired = false;
                });
            }
 

 
Undo
Akcja odpowiedzialna za wysłanie żądania o cofnięcie wszystkich zmian w zamówieniu. Parametry:
    • orderId (int, pole obowiązkowe).
     this.undo = function (aditionalRequestData) {
                var data = {
                    __action: 'OrderEdit/Undo',
                    __csrf: __CSRF,
                    orderId: this.orderId,
                    __template: this.orderTemplateUrl,
                    __collection: 'customer-profile.Order.RecalculationRequired'
                };

                if (aditionalRequestData) {
                    data = $.extend(data, aditionalRequestData);
                }

                var thisRef = this;

                return window.UIFeatures.makePostRequest(data, thisRef.orderRequestUrl, function (res) {
                    window.UIFeatures.pureReplaceTemplate(thisRef.orderTemplateContainer, null, null, res.template, thisRef.orderRequestUrl);
                    if (!res.action.Result) {
                        var messagesContainer = $(messagesContainerSelector);
                        window.app.temporaryMessage(messagesContainer, window.UIFeatures.makeMessageHtml(res.action, 'warning'));
                    }
                    thisRef.recalculationRequired = res.collection;
                });
            }
 

 
FbAccountLink
Akcja odpowiedzialna za połączenie konta w sklepie z kontem na Facebooku. Parametry:
  • userID (int).
    function connectFb(e) {
    if (fbLoginStatus.status === 'connected') {
        var userIdNum = fbLoginStatus.authResponse.userID;
        var data = {
            __csrf: __CSRF,
            __action: 'External/FbAccountLink',
            userID: userIdNum
        };
        $.post(null, data, function (result) {
            if (result.action.Result) {
                location.reload();
            } else {
                application.createMessage(result.action);
            }
        });
    } else {
        var loginMessage = $(e.currentTarget).data('error-msg');
        application.createMessage(loginMessage);
    }
}
 

 
FbAccountUnlink
Akcja odpowiedzialna za rozłączenie konta w sklepie z kontem na Facebooku.
function disconnectFb() {
    var data = {
        __csrf: __CSRF,
        __action: 'External/FbAccountUnlink'
    };
    $.post(null, data, function (result) {
        if (result.action.Result) {
            location.reload();
        } else {
            application.createMessage(result.action);
        }
    });
}
 

 
FbLogin
Akcja odpowiedzialna za zalogowanie. Parametry:
    • response (string, pole obowiązkowe).
function connectToFb(response) {
    FB.api('/me', {
        fields: 'email,name'
    }, function (u) {
        response.user = u;
        $.post(null, {
            __csrf: __CSRF,
            __action: 'external/fblogin',
            response: JSON.stringify(response)
        }, function (result) {
            if (result.action.Result) {
                window.location.replace('');
            } else if (result.action.Code != 100) {
                application.createMessage(result.action);
            }
        });
    });
}
 

 
GoogleAccountLink
Akcja odpowiedzialna za połączenie konta w sklepie z kontem Google. Parametry:
    • userID (int).
  $('#linkGoogleAccount').off().click(function(){
                bodyTag.style.cursor = 'wait';
                au.signIn().then(function(googleUser){
                    return googleUser.getBasicProfile().getId();
                }).then(function (value) {
                    setTimeout(function() {
                        $.post(null,{ __action: 'External/GoogleAccountLink', __csrf: __CSRF, userID: value },function(result){
                            if (result.action.Result) {
                                location.reload();
                            } else {
                                createMessage(result);
                                bodyTag.style.cursor = 'default';
                            }
                        });
                    }, 1000);
                });
            });
 

 
GoogleAccountUnlink
Akcja odpowiedzialna za rozłączenie konta w sklepie z kontem Google.
 $('#unlinkGoogleAccount').off().click(function(){
                $.post(null,{ __action: 'External/GoogleAccountUnlink', __csrf: __CSRF },function(result){
                    if (result.action.Result) {
                        location.reload();
                    } else {
                        createMessage(result);
                        bodyTag.style.cursor = 'default';
                    }
                });
            });
 

 
GoogleLogin
Akcja odpowiedzialna za zalogowanie. Parametry:
  • id_token (int, pole obowiązkowe).
   $('#google-signin').off().click(function(){
                bodyTag.style.cursor = 'wait';
                au.signIn().then(function(googleUser){
                    return googleUser.getAuthResponse().id_token;
                }).then(function (value) {
                    setTimeout(function() {
                        $.post(null,{ __action: 'External/GoogleLogin', __csrf: __CSRF, id_token: value },function(result){
                            if (result.action.Result) {
                                window.location.replace('');
                            } else if (result.action.Code === 108) {
                                var errMsg = document.querySelector('#google-signin').dataset.errorMsg;
                                application.createMessage(errMsg);
                                bodyTag.style.cursor = 'default';
                            } else {
                                createMessage(result);
                                bodyTag.style.cursor = 'default';
                            }
                        });
                    }, 4000);
                });
            });
 

 
Exec
Akcja odpowiedzialna za pobieranie danych bezpośrednio z ERP. Parametry:
  • message (string, pole obowiązkowe),
  • worker (string) - maksymalna długość to 32 znaki.
  var data = {
    __action: 'sync/exec',
    __CSRF: __CSRF,
    worker: 'erpData',
    message: JSON.stringify({
        command: 'CDN.eShop_GetOrders',
        parameters: { 
            DateFrom: '2019-01-01', 
            DateTo: '2019-12-31', 
            LanguageId: __lngId, 
            PageNo: '1'
       }
    }) 
};

function getData() {
  $.post(null, data, function (d) {
	 if (!d.action.Result) {  
		console.log(JSON.stringify(d));
		return;
	 } else {
		console.log(JSON.stringify(d));

		var res = d.action.Object[0];
		console.log(JSON.stringify(res));

		var res2 = d.action.Object[1];
		console.log(JSON.stringify(res2));

		var res3 = d.action.Object[2];
		console.log(JSON.stringify(res3));
	 }
  });
}
 
 
Add
Akcja odpowiedzialna za dodawanie zapytań ofertowych. Parametry:
  • email (string, pole obowiązkowe) - maksymalna długość to 192 znaki,
  • phoneNo (string) - maksymalna długość to 20 znaków,
  • name (string, pole obowiązkowe) - maksymalna długość to 128 znaków,
  • message (string) - maksymalna długość to 2000 znaków,
  • tos (int),
  • channelKey (string).
<input aria-label="action-inquiry-add" type="hidden" name="__action" value="Inquiry/Add" />
{% for tos in config.TOS.Consents.Inquiries -%}
    <div class="tos-container-js {% if tos.Statement -%} statement-ui statement-lq {% endif -%}" >
        {% if tos.Statement -%}
            {{ tos.Text }}
        {% else -%}
            <label class="checkbox-ui tos-js">
                <input aria-label="tos" type="checkbox" name="tos" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} />
                <span class="label-ui">{% if tos.Required -%}<span class="required-ui">*</span> {% endif -%}{{ tos.Text }}</span>
                {% if tos.Required -%}
                    <span class="error-ui validation-info-js validation-required-js hidden-js">{{ translations.RequiredField }}</span>
                {% endif -%}
            </label>
        {% endif -%}
        {% assign channelsSize = tos.Channels | Size -%}
        {% if channelsSize > 0 -%}
            {% assign onlyEmail = false -%}
            {% if channelsSize == 1 and tos.Channels[0].Type == 1 -%}
                {% assign onlyEmail = true -%}
            {% endif -%}
            {% if onlyEmail == false -%}
                <span class="error-ui validation-info-js validation-channel-js hidden-js">{{ translations.ChooseOption }}</span>
            {% endif -%}
        {% endif -%}
        {% for channel in tos.Channels -%}
            <label class="checkbox-ui channel-ui {% if onlyEmail == false -%} channel-js {% endif -%} {% if tos.Statement == false -%} disabled-channel-js {% endif -%}">
                {% if onlyEmail == false -%}
                    <input aria-label="channelKey" type="checkbox" name="channelKey" value="{{ channel.Key }}" {% if tos.Statement == false -%} disabled {% endif -%} />
                {% else -%}
                    <input aria-label="channelKey" type="hidden" name="channelKey" value="{{ channel.Key }}" checked />
                    <input aria-label="channelKey" type="checkbox" checked disabled />
                {% endif -%}
                <span class="label-ui">{{ channel.Name }}</span>
            </label>
        {% endfor -%}
    </div>
{% endfor -%}
<small class="mb10-ui block-ui"><span class="required-ui">*</span> {{ translations.RequiredFields }}</small>
<button aria-label="inquiry-recalculate" class="order-button-ui parent-container-reload-js add-inquiry-js" data-products-quantity="{{order.Products | Size}}" data-date="{{config.Now | Date:dateFormat}}">
    {{translations.AddInquiry}}
</button>
 
 
CartMerge
Akcja odpowiedzialna za dodanie koszyka do zapytania ofertowego. Parametry:
  • inquiryId (int, pole obowiązkowe).
function produceOffer(e) {
    var id = $(e.currentTarget).data('id');
    var url = $(e.currentTarget).data('redirect-url');
    var data = {
        __action: 'Inquiry/CartMerge',
        __csrf: __CSRF,
        inquiryId: id
    }
    $.post('', data, function(result) {
        if (result.action.Result) {
            app.replace(url);
        }
    });
};
 

 
Set
Akcja odpowiedzialna za ustawienie koszyka jako zapytanie. Parametry:
  • inquiry (bool),
  • cartId (int lub null).
toggleCartType: async function() {
    const trigger = this;
    if(trigger.classList.contains('change-into-cart-js')){
        var inquiry = false;
        if(document.getElementsByClassName('last-inquiry-js').length > 0){
            window.app.setCookie('lastCartId', window.app.getCookie('activeInquiryId'));
            window.app.setCookie('activeInquiryId', -1);
        }
    } else {
        var inquiry = true;
        if(document.getElementsByClassName('last-cart-js').length > 0){
            window.app.setCookie('activeInquiryId', window.app.getCookie('lastCartId'));
            window.app.setCookie('lastCartId', -1);
        }
    }
    const message = trigger.dataset.message;
    const result = await js.post({__action: 'Inquiry/Set', inquiry: inquiry});
    document.body.innerHTML += '<div class="toggle-cart-type-succeed-js message-popup-background-ui">'+
                                    '<div class="message-popup-ui box-ui">'+
                                        '<div class="box-ui" style="padding: 50px">'+
                                            '<i class="va-mid-ui ti-check" style="margin-right: 10px; font-size: 30px; color: #7fba00"></i>'+
                                            '<span class="va-mid-ui line-height-1-ui" style="font-weight: 500; font-size: 18px">'+message+'</span>'+
                                        '</div>'+
                                    '</div>'+
                                '</div>'
},
 
 
Ping
Akcja odpowiada za podtrzymanie sesji użytkownika korzystającego z e-Sklepu. Domyślnie czas bezczynności sesji użytkownika wynosi 15 minut, po upływie których jest usuwana, zaś w szablonach Comarch sesja ta jest podtrzymywana. Poniżej znajduje się przykładowy skrypt, który należy odpowiednio zaimplementować w swoim szablonie, w jednym z plików js. Przykład implementacji akcji Ping w szablonach Comarch znajduje się w artykule: Podtrzymanie sesji użytkownika.
setInterval(() => fetch(document.baseURI + 'xhr?__action=svc/ping'), 600000);

Kompilacja i minifikacja plików

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Kompilacja i minifikacja plików

W standardowych szablonach style napisane są za pomocą preprocesora języka CSS jakim jest Sass. W efekcie style są umieszczane w plikach .scss. Niestety, przeglądarki nie potrafią ich odczytać, dlatego należy je przekompilować do plików .css, które już mogą zostać przez nie zidentyfikowane. Minifikacja plików to inaczej kompresja pliku, dzięki temu zmniejszamy wagę pliku. Zastosowanie minifikacji spowoduje, że strona internetowa będzie działać szybciej. Minifikację można przeprowadzić ręcznie, jednak jest to praca żmudna i mało wydajna. W tym artykule dowiesz się, jak automatycznie kompilować i minifikować pliki. Podczas tych operacji będziesz pracować na plikach lokalnych. Z pomocą przyjdzie Ci narzędzie Liquid Sync.

1. Node.js

Na początku musisz zainstalować Node.js. Instalator dostępny jest tutaj. W efekcie otrzymasz środowisko do dalszej pracy z plikami.

2. Folder nodejs

Po instalacji Node.js, należy dodać specjalny folder w plikach szablonu o nazwie nodejs. W tym folderze będą znajdować się wszystkie pliki wymagane do uruchomienia minifikacji.
Wskazówka
Pracuj na plikach lokalnych na swoim komputerze, a nie na tych znajdujących się w panelu administracyjnym.

3. Gulp

Gulp to narzędzie, które za Ciebie wykona automatyczną kompilację i minifikację plików. W nowym folderze (nodejs) dodaj plik gulpfile.js o zawartości jak poniżej: var gulp = require('gulp'); var gulpsass = require('gulp-sass')(require('sass')); var uglify = require('gulp-uglify-es').default; var rename = require('gulp-rename'); var minify = require('gulp-minify'); var chokidar = require('chokidar'); function sass() { return gulp.src('../scss/**/*.scss') .pipe(gulpsass()) .pipe(gulp.dest('../css')) }; function watch() { gulp.watch('../scss/**/*.scss', sass); }; function css(){ return gulp.src('../scss/**/*.scss') .pipe(rename({suffix: '.min'})) .pipe(gulpsass({outputStyle: 'compressed'})) .pipe(gulp.dest('../css')) }; function js(){ return gulp.src('../js/**/*.js') .pipe(rename({suffix: '.min'})) .pipe(uglify()) .pipe(gulp.dest('../js')) }; const watchSapphireScssFilesDependencies = { "_collection-points.scss": "../scss/collection-points.scss", "_globals1.scss": "../scss/desktop1.scss", "_header.scss": "../scss/desktop1.scss", "_country-flags.scss": "../scss/desktop1.scss", "_tooltip.scss": "../scss/desktop1.scss", "_stepper.scss": "../scss/desktop1.scss", "_pagination.scss": "../scss/desktop1.scss", "_sliders.scss": "../scss/desktop1.scss", "_categories-navigation.scss": "../scss/desktop1.scss", "_home.scss": "../scss/desktop1.scss", "_product-list.scss": "../scss/desktop1.scss", "_categories-map.scss": "../scss/desktop1.scss", "_order.scss": "../scss/desktop1.scss", "_globals2.scss": "../scss/desktop2.scss", "_globals-m.scss": "../scss/mobile.scss", "_offline.scss": "../scss/offline.scss" }; const watchSapphireJsFiles = ['../js/init.js', '../js/init-ui1.js', '../js/init-ui2.js', '../js/js.js']; function watchTopazRelease() { chokidar.watch('../scss/**/*.scss').on('change', (path) => { console.log(`File '${path}' changed.`) return gulp.src('../scss/layout*.scss') .pipe(gulpsass({outputStyle: 'compressed'})) .pipe(gulp.dest('../css/')) }); chokidar.watch('../js/layout!(*.min).js').on('change', (path) => { console.log(`File '${path}' changed.`) return gulp.src(path) .pipe(minify({ mangle: false, compress: false, noSource: true, ext: { min: ".min.js" } })) .pipe(gulp.dest('../js/')) }); }; function watchSapphireRelease() { chokidar.watch(['../js/layout!(*.min).js', ...watchSapphireJsFiles]).on('change', (path) => { console.log(`File '${path}' changed.`) return gulp.src(path) .pipe(minify({ mangle: false, compress: false, noSource: true, ext: { min: ".min.js" } })) .pipe(gulp.dest('../js/')) }); chokidar.watch('../scss/**/*.scss').on('change', (path) => { console.log(`File '${path}' changed.`) let stringsOfRelativePathParts = []; if(path.includes('/')) stringsOfRelativePathParts = path.split("/"); else stringsOfRelativePathParts = path.split("\\"); let fileName = stringsOfRelativePathParts[stringsOfRelativePathParts.length-1]; if(watchSapphireScssFilesDependencies[fileName] !== undefined) { path = watchSapphireScssFilesDependencies[fileName]; stringsOfRelativePathParts = watchSapphireScssFilesDependencies[fileName].split("/"); return gulp.src(path) .pipe(gulpsass({outputStyle: 'compressed'})) .pipe(gulp.dest('../css/')); } else if (path.includes('static-elements') || path.includes('elements') || path.includes('partials')) { return gulp.src('../scss/layout*.scss') .pipe(gulpsass({outputStyle: 'compressed'})) .pipe(gulp.dest('../css/')) } else if(!fileName.includes('global-variables') ) { return gulp.src(path) .pipe(gulpsass({outputStyle: 'compressed'})) .pipe(gulp.dest('../css/')) } }); }; exports.sass = sass; exports.watch = watch; exports.css = css; exports.js = js; exports.minify = gulp.parallel(js, css); exports.watchTopazRelease = watchTopazRelease; exports.watchSapphireRelease = watchSapphireRelease;  

4. NPM

Ostatni krok, to dodanie NPMa (Node Package Manager). Do tej operacji potrzebny jest terminal. Jeśli nie posiadasz programu do edycji kodu, który udostępniałby taki terminal, to nic nie szkodzi. Wystarczy uruchomić terminal, który jest dostępny w systemie w następujący sposób:
Wskazówka
Jeśli używasz narzędzia Liquid Sync to upewnij się, że jest ono wyłączone przed wykonaniem następnego kroku.
  • Otwórz folder nodejs, wciśnij i przytrzymaj na klawiaturze lewy Shift, a następnie kliknij prawym przyciskiem myszy w dowolne pole tego otwartego folderu,
  • Otworzy się lista opcji, na której wybierz: Otwórz okno polecenia tutaj (w systemie Windows 10 opcja ta nazywa się: Otwórz tutaj okno programu PowerShell),
  • Teraz możesz zainstalować NPM w swoim projekcie. Wystarczy, że wpiszesz komendę: npm init, a następnie zatwierdzisz ją klawiszem ENTER,
  • Podczas instalacji pojawią się pola z informacjami do uzupełnienia (m.in. package name, version, description, entry point, test command, git repository, keywords, author, license) oraz pytanie o poprawność wprowadzonych danych. Informacji tych nie trzeba uzupełniać (z wyjątkiem pierwszej, gdzie wystarczy wpisać cokolwiek), można je pomijać klawiszem ENTER,
  • Gdy operacja się zakończy, wpisz kolejną komendę:
    •  npm install –save-dev gulp@4.0.0 chokidar@3.6.0 sass@1.74.1 gulp-minify@3.1.0 gulp-rename@2.0.0 gulp-uglify-es@3.0.0 gulp-sass@5.1.0
  • Powyższa komenda zainstaluje paczki, które umożliwią poprawne działanie funkcji z pliku gulpfile.js. Komendę najlepiej przekopiować do okna polecenia. Jeśli jednak wpisujesz ją ręcznie, to zwróć uwagę, że przed słowem save są dwa myślniki, a nie jeden.
Wskazówka
Jeśli używasz narzędzia Liquid Sync to teraz należy zmienić nazwę folderu z nodejs na .nodejs. Dzięki dodaniu tej kropki na początku nazwy folderu, będzie on pomijany przy synchronizacji plików.
Komendy do kompilacji i minifikacji Po wykonaniu powyższych kroków, możesz już przystąpić do kompilacji i minifikacji. W pliku gulpfile.js jest zdefiniowanych kilka funkcji. Poniżej krótki opis funkcji oraz sposób ich wywołania:
  • Kompilacja plików .scss do .css: (Agat, Bursztyn, Opal)
Komenda gulp sass spowoduje przekompilowanie plików .scss do plików .css. Dzięki temu będziesz mógł edytować style w plikach .scss.
  • Automatyczna kompilacja plików .scss do .css: (Agat, Bursztyn, Opal)
Jeśli komenda gulp sass przypadła Ci do gustu, to ta spodoba Ci się jeszcze bardziej. Komenda gulp watch spowoduje, że automatycznie po każdej zmianie w dowolnym pliku .scss zostanie uruchomiona kompilacja do pliku .css.
  • Minifikacja plików .css: (Agat, Bursztyn, Opal)
Otrzymane pliki .css możemy zminifikować. Odpowiada za to komenda gulp css. Po jej uruchomieniu wszystkie pliki .scss zostaną przekompilowane do plików .min.css. Taki plik będzie dużo mniejszy od zwykłego pliku .css.
  • Minifikacja plików .js: (Agat, Bursztyn, Opal)
Nie tylko pliki ze stylami mogą być zminifikowane. Warto zminifikować również pliki .js. Zrobisz to komendą gulp js. Tworzy ona kopie z dopiskiem .min w nazwie dla wszystkich plików .js (z folderu JS znajdującego się w Twoim szablonie).
  • Minifikacja plików: (Agat, Bursztyn, Opal)
Ostatnia komenda to gulp minify. Minifikuje jednocześnie pliki .css i pliki .js.
  • Automatyczna minifikacja wszystkich plików: (Topaz)
Komenda gulp watchTopazRelease spowoduje, że automatycznie po każdej zmianie w dowolnym pliku .scss oraz .js zostanie utworzona jego zminifikowana wersja.
  • Automatyczna minifikacja wszystkich plików: (Szafir)
Komenda gulp watchSapphireRelease ma takie same działanie jak powyższa.

Obsługa akcji Product/DeliveryCostGet

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Obsługa akcji Product/DeliveryCostGet

W tym artykule dowiesz się jak zmodyfikować swój szablon, aby obsłużyć akcję Product/DeliveryCostGet, w zamian za pole o nazwie DeliveryCost na obiekcie ze szczegółami towarów.

Dla kogo przeznaczona jest poniższa instrukcja i kiedy warto z niej skorzystać?

Akcja Product/DeliveryCostGet informuje o minimalnych kosztach dostawy dla wybranego towaru. W standardowych szablonach Comarch informacja ta prezentowana jest na szczegółach towaru.
Przykład zastosowania akcji w szablonie Topaz
Jeżeli chcesz prezentować informacje na temat minimalnych kosztów dostawy dla swoich towarów to zaktualizuj swój szablon do najnowszej wersji (zalecane) lub skorzystaj z poniższej instrukcji i dokonaj jego samodzielnej modyfikacji.

Topaz

W zależności od wybranego widoku szczegółów towaru instrukcja będzie się lekko różnić. Wspólnym dla wszystkich widoków jest: Krok 1. W panelu administracyjnym przejdź do sekcji Wygląd sklepu/ Ustawienia/ Edytuj ustawienia zaawansowane/ Edytuj HML.

Obiekt product-details-1

Krok 2.W pliku elements/productDetails/product-details-1/html.js znajdź warunek {% if product.DeliveryCost != null and product.DeliveryCost > 0 -%} i usuń go wraz z całą jego zawartością a w jego miejsce wklej poniższy kod:

Obiekt product-details-2

Krok 2.W pliku elements/productDetails/product-details-2/html.js znajdź warunek {% if product.DeliveryCost != null and product.DeliveryCost > 0 -%} i usuń go wraz z całą jego zawartością a w jego miejsce wklej poniższy kod:

Obiekt product-details-3

Krok 2.W pliku elements/productDetails/product-details-3/html.js znajdź warunek {% if product.DeliveryCost != null and product.DeliveryCost > 0 -%} i usuń go wraz z całą jego zawartością a w jego miejsce wklej poniższy kod:

Agat

Krok 1. W panelu administracyjnym przejdź do sekcji Wygląd sklepu/ Ustawienia/ Edytuj ustawienia zaawansowane/ Edytuj HML. Krok 2.W pliku partials/product/product-popup.html znajdź klasę info-container i usuń kontener z tą klasą wraz z całą jego zawartością a w jego miejsce wklej poniższy kod:
{% if product.StockLevel.Control -%} {% if product.StockLevel.Type != 4 and product.StockLevel.Text == '' -%} {% assign noText = true -%} {% endif -%}
{{ translations.Com_StockLvl }} {{ product.StockLevel.Text }}
{% endif -%}
{{ translations.Com_Availability }} {{ product.Availability.Text }} {{ product.Availability.Text }}

Bursztyn i Opal

Krok 1. W panelu administracyjnym przejdź do sekcji Wygląd sklepu/ Ustawienia/ Edytuj ustawienia zaawansowane/ Edytuj HML. Krok 2.W pliku productdetails.html znajdź warunek {% if _pd.DeliveryCost > 0 -%} i usuń go wraz z całą jego zawartością a w jego miejsce wklej poniższy kod:
Wskazówka
Po wprowadzeniu zmian pamiętaj o ich zapisaniu oraz publikacji.

Dodanie konfigurowalności strony głównej w szablonie Szafir

Dodanie konfigurowalności strony głównej w szablonie Szafir

W tym artykule dowiesz się jak zmodyfikować szablon Szafir, aby strona główna była konfigurowalna.
Wskazówka
Instrukcja przeznaczona jest dla sklepów od wersji 2022.4, które posiadają starsze szablony. Artykuł przeprowadzi Cię przez proces modyfikacji plików js oraz scss. Dodatkowe informacje o kompilacji i minifikacji znajdziesz w centrum pomocy.

Krok 1.

W panelu administracyjnym przejdź do sekcji Wygląd sklepu/Ustawienia. Następnie, mając wybrany szablon Szafir, w prawym górnym rogu wybierz więcej, po czym przejdź do Edytuj ustawienia zaawansowane/więcej/edytuj HTML.

Krok 2.

Odnajdź plik __settings.liquid. Następnie w drugiej linijce dodaj poniższy kod: {% assign homepage = "Strona główna" -%} {% assign elementsAtHomepage = "Lista elementów na stronie głównej sklepu" -%} {% assign name = "Nazwa" -%} {% assign parameters = "Parametry" -%} {% assign mainBanner = "Baner główny" -%} {% assign mainBannerLink = "Przejdź do edycji tego bannera" -%} {% assign newsSection = "Sekcja Nowości" -%} {% assign newsSectionLink = "Przejdź do edycji zawartości tej sekcji" -%} {% assign newsletter = "Newsletter" -%} {% assign manufacturersSlider = "Slider Producenci" -%} {% assign news = "Aktualności" -%} {% assign newsLink = "Przejdź do listy artykułów bloga" -%} {% assign infographicBanner = "Banner infografika" -%} {% assign infographicBannerLink = "Przejdź do edycji tego bannera" -%} {% assign animationOnHover = "Animacja na hoverze" -%} {% assign brandsSlider = "Slider Marki" -%} Następnie wyszukaj linijkę border-bottom: 1px solid #ddd; i pod nią dodaj display: flex;. Parę linijek niżej znajduje się kod: #lg-settings-content .row::after { display: block; clear: both; content: ''; } #lg-settings-content .cell { border-left: 1px solid #ddd; display: inline-block; vertical-align: middle; width: calc((100% - 308px)/4); min-height: 20px; padding: 10px; float: left; } Usuń go, a następnie wklej następujący kod: #lg-settings-content .cell { border-left: 1px solid #ddd; width: calc((100% - 308px)/4); padding: 10px; } #lg-settings-content .elements-at-homepage .cell.name{ width: 130px; } #lg-settings-content .elements-at-homepage .cell.translation{ width: 160px; } #lg-settings-content .elements-at-homepage .cell.parameters{ width: calc(100% - 515px); } #lg-settings-content .elements-at-homepage .cell.goto{ width: 100%; } Wyszukaj frazę {{navigationBarSettings}} i zamień ją na {{homepage}}. Następnie odszukaj frazę {{newsletter}} i usuń całą sekcję fieldset w której się ona znajduje. To samo zrób w przypadku fraz {{homepageBannerTranslation}}, {{blogOnHomepage}} oraz {{categoryMenu}}. Kilka linijek niżej znajdziesz id="tab1Content". Pod tą linijką dodaj poniższy fragment:

{{navigationBarSettings}}

Następnie znajdź frazę id="tab2Content" i dwie linijki wyżej wklej następujący kod:
{{categoryMenu}}

{{categoryMenuInfo}}

{{elementsAtHomepage}}
{{available}}
{{number}}
{{name}}
{{translationId}}
{{parameters}}
{{mainBanner}}

{{animationTypeTranslation}}

{{newsSection}}

{{animationOnHover}}

{{newsletter}}
{{manufacturersSlider}}

{{animationOnHover}}

{{brandsSlider}}

{{animationOnHover}}

{{news}}

{{blogPresentationOnHomepage}}

{{animationOnHover}}

{{infographicBanner}}

{{animationOnHover}}

Teraz wyszukaj funkcję __SaveLiquidSettings i linijkę wyżej wklej poniższy kod: $('.pa-translation-link').each(function(){ var id = $(this).text(); var url = $(this).attr('href').replaceAll('__ID__', id); $(this).attr('href', url); }); $('.pa-link').each(function(){ var id = $(this).data('id'); var url = $(this).attr('href').replaceAll('__ID__', id); $(this).attr('href', url); });

Krok 3.

Następnie w pliku home.html w pierwszych linijkach znajdziesz taki fragment kodu: {% include 'common/banner.html' -%}

{{translations.NewProducts}}

{% if customer.HidePrices -%} {% include 'product/hidden-prices-msg.html' -%} {% endif -%} {% include 'product/minibox-grid.html' -%}
{% unless customer.NewsletterSubscriber or settings.newsletter == 'no' -%}

Przykładowe modyfikacje

Integracja z edrone - dostosowanie szablonu

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.
Darmowe szablony Comarch od wersji 2018.1 posiadają wbudowaną integrację z zaawansowanym systemem do zarządzania relacjami z klientami edrone. Jeżeli korzystasz z innych szablonów, to ten artykuł może być dla Ciebie pomocny. Poniżej znajduje się lista kroków, które należy wykonać w celu integracji z edrone.
  1. Ustawiamy swój App ID z edrone w panelu administracyjnym (Ustawienia/Ustawienia Sklepu/Ogólne/Integracja z edrone)
  2. W głównym folderze szablonu tworzymy folder edrone, w którym umieszczamy pliki, których zawartość znajduje się w kolejnych punktach
  3. W pliku html, na końcu sekcji head includujemy plik edrone/head.html (dodajemy {% include ‘edrone/head.html’ -%} ) {% if config.External.Edrone.AppId != '' -%} <script type="text/javascript"> (function (srcjs) { window._edrone = window._edrone || {}; _edrone.app_id = '{{ config.External.Edrone.AppId }}'; _edrone.version = '1.0.0'; _edrone.platform_version = '{{ config.Version }}'; _edrone.platform = 'comarch'; _edrone.shop_lang = '{{ page.Language }}';{% if page.PageId != config.DefinedPages.Order.Id -%} _edrone.action_type = 'other'; {% if usr.Authenticated -%} {% if customer.Address.Name != '' -%} {% assign FullName = customer.Address.Name -%} {% if FullName contains ' ' -%} {% assign HalfName = FullName | Split:' ' -%} {% endif %} _edrone.first_name = '{% if HalfName[0] -%}{{ HalfName[0] }}{% else %}{{ FullName }}{% endif %}'; {% if HalfName[1] -%} _edrone.last_name = '{{ HalfName[1] }}'; {% endif %} {% endif -%} {% if customer.Address.Country != '' -%} _edrone.country = '{{ customer.Address.Country }}'; {% endif -%} {% if customer.Address.City != '' -%} _edrone.city = '{{ customer.Address.City }}'; {% endif -%} {% if customer.Address.Phone != '' -%} _edrone.phone = '{{ customer.Address.PhoneNo }}'; {% endif -%} _edrone.email = '{{ customer.Email }}'; {% endif -%} {% endif -%}var doc = document.createElement('script'); doc.type = 'text/javascript'; doc.async = true; doc.src = ('https:' == document.location.protocol ? 'https:' : 'http:') + srcjs; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(doc, s); })("//d3bo67muzbfgtl.cloudfront.net/edrone_2_0.js"); </script> {% endif -%}
  4. W pliku html, na końcu sekcji body includujemy pliki edrone/product-presentation.html oraz edrone/subscribe.html
    • product-presentation.html
    {% if page.PageId == config.DefinedPages.ProductDetails.Id and config.External.Edrone.AppId != '' -%} <script type="text/javascript"> {% if productdetails -%} {% assign product-presentation = productdetails -%} {% elseif product-details -%} {% assign product-presentation = product-details -%} {% endif -%} window._edrone = window._edrone || {}; _edrone.action_type = 'product_view'; _edrone.product_ids = '{{ product-presentation.Product.Id }}'; _edrone.product_titles = '{{ product-presentation.Product.Name }}'; {% if product-presentation.Product.ImageId > 0 -%} _edrone.product_images = 'http:{{ page.BaseHref }}img/large/{{ product-presentation.Product.ImageId }}/{% if product-presentation.Product.Images[0].Name != "" -%}{{ product-presentation.Product.Images[0].Name }}{% else %}.jpg{% endif %}'; {% endif -%} {% if product-presentation.Product.Code != '' -%} _edrone.product_skus = '{{ product-presentation.Product.Code }}'; {% endif -%} _edrone.product_urls = '{{ page.CanonicalLink }}'; _edrone.product_category_ids = '{{ page.GroupId }}'; _edrone.product_category_names = '{{ page.CurrentSiteNode.Name }}'; </script> {% endif %}
    Wskazówka
    Jeżeli w swoim szablonie obiekt ze szczegółami produktu ma inną nazwę, to należy zmodyfikować warunek.
    • subscribe.html
    {% if config.External.Edrone.AppId != '' -%} {% if page.PageId == config.DefinedPages.Home.Id or page.PageId == config.DefinedPages.CustomerProfile.Id -%} <script type="text/javascript"> $(document).ajaxSuccess(function(a,b,c,d) { if(d && d.action && (d.action.Action == 'Newsletter/Subscribe' || d.action.Action == 'newsletter/subscribe') && d.action.Result){ var queryString = c.data.split('&'); for(i=0; i<queryString.length; i++){ if(queryString[i].indexOf('email') != -1){ var email = queryString[i].split('=')[1].replace('%40','@'); } } _edrone.customer_tags = 'From Newsletter Subscribe'; _edrone.email = email; _edrone.subscriber_status = '1'; _edrone.action_type = 'subscribe'; _edrone.init(); } }); </script> {% endif %} {% if page.PageId == config.DefinedPages.CustomerProfile.Id -%} <script type="text/javascript"> $(document).ajaxSuccess(function(a,b,c,d) { if(d && d.action && (d.action.Action == 'Newsletter/Unsubscribe' || d.action.Action == 'newsletter/unsubscribe') && d.action.Result){ var queryString = c.data.split('&'); for(i=0; i<queryString.length; i++){ if(queryString[i].indexOf('email') != -1){ var email = queryString[i].split('=')[1].replace('%40','@'); } } _edrone.customer_tags = 'From Newsletter Subscribe'; _edrone.email = email; _edrone.subscriber_status = '0'; _edrone.action_type = 'subscribe'; _edrone.init(); } }); </script> {% endif %} {% endif %}
    Wskazówka
    Jeżeli w swoim szablonie umożliwiasz zapis do newslettera z innych stron niż strona główna i profil klienta oraz pozwalasz na wypisanie poza profilem klienta, to należy zmodyfikować powyższy plik.
    Uwaga
    W wersji 2018.7 z domyślnych szablonów Comarch usunięto akcję dotyczącą zapisu i wypisu z newslettera, ponieważ dane przekazywane są przez Comarch e-Sklep w tle.
  5. W szablonach Agat, Bursztyn i Opal, w tym samym miejscu includujemy również plik edrone/add-to-cart.html {% if page.PageId == config.DefinedPages.ProductDetails.Id and config.External.Edrone.AppId != '' -%} <script type="text/javascript"> $(document).ajaxSuccess(function(a,b,c,d) { if(d && d.action && (d.action.Action == 'Cart/Add' || d.action.Action == 'cart/add') && d.action.Result ){ _edrone.action_type = 'add_to_cart'; _edrone.init(); } }); </script> {% endif %}
    Wskazówka
    Plik należy dodać do wszystkich szablonów, które nie są oparte o najnowszą wersję szablonu Szafir (w tym szablonie dodawanie do koszyka w edrone obsłużone jest bezpośrednio w funkcjach szablonu – spowodowane jest to możliwością dodawania kilku towarów jednocześnie czego inne szablony nie posiadają).
  6. W szablonie Bursztyn, w tym samym miejscu includujemy również plik edrone/add-to-cart-with-data.html {% if config.External.Edrone.AppId != '' -%} {% if page.PageId == config.DefinedPages.Home.Id or page.PageId == config.DefinedPages.ProductList.Id -%} <script type="text/javascript"> $(document).ajaxSuccess(function(a,b,c,d) { if(d && d.action && (d.action.Action == 'Cart/Add' || d.action.Action == 'cart/add') && d.action.Result ){ window._edrone = window._edrone || {};var products = d.collection["customer.Cart"].Products; var size = products.length; var product = products[size-1];_edrone.product_ids = product.Id; _edrone.product_titles = product.NameNoHtml; if(product.ImageId > 0){ _edrone.product_images = 'http:{{ page.BaseHref }}img/large/'+product.ImageId+'/.jpg'; } if(product.Code != ''){ _edrone.product_skus = product.Code; } _edrone.product_urls = 'http:{{ page.BaseHref }}'+product.Url; _edrone.product_category_ids = product.DefaultGroup; _edrone.action_type = 'add_to_cart'; _edrone.init(); } }); </script> {% endif %} {% endif %}
    Wskazówka
    Kod działa dla dodawania do koszyka ze strony głównej i listy towarów. Jeżeli pozwalasz na dodawanie do koszyka z innych stron, należy go zmodyfikować.
  7. W pliku z podziękowaniami za zakup (Agat – partials/cart/summary.html, Bursztyn i Opal – order/thank-you.html, Szafir – order/thx.html), na końcu pliku (tuż pod includem rich-snippetów), includujemy plik edrone/order.html {% if config.External.Edrone.AppId != '' -%} <script type="text/javascript"> _edrone.action_type = 'order';{% if cart -%} {% assign order = cart -%} {% endif -%}{% assign FullName = order.Customer.DeliveryAddress.Name -%} {% if FullName contains ' ' -%} {% assign HalfName = FullName | Split:' ' -%} {% endif %} _edrone.first_name = '{% if HalfName[0] -%}{{ HalfName[0] }}{% else %}{{ FullName }}{% endif %}'; {% if HalfName[1] -%} _edrone.last_name = '{{ HalfName[1] }}'; {% endif %} _edrone.country = '{{ order.Customer.DeliveryAddress.Country }}'; {% if order.Customer.DeliveryAddress.City != '' -%} _edrone.city = '{{ order.Customer.DeliveryAddress.City }}'; {% endif %} {% if order.Customer.DeliveryAddress.PhoneNo != '' -%} _edrone.phone = '{{ order.Customer.DeliveryAddress.PhoneNo }}'; {% endif %} _edrone.email = '{{ order.Customer.Email }}'; {% assign size = order.PlacedOrder.Products | Size -%} var ids = ''; var titles = ''; var images = ''; var skus = ''; var urls = ''; var categoryIds = ''; var counts = ''; {% for product in order.PlacedOrder.Products -%} ids += '{{ product.Id }}{% if forloop.index != size -%}|{% endif -%}'; titles += '{{ product.NameNoHtml }}{% if forloop.index != size -%}|{% endif -%}'; images += '{% if product.ImageId > 0 -%}http:{{ page.BaseHref }}img/large/{{ product.ImageId }}/.jpg{% endif -%}{% if forloop.index != size -%}|{% endif -%}'; skus += '{{ product.Code }}{% if forloop.index != size -%}|{% endif -%}'; urls += 'http:{{ page.BaseHref }}{{ product.Url }}{% if forloop.index != size -%}|{% endif -%}'; categoryIds += '{{ product.DefaultGroup }}{% if forloop.index != size -%}|{% endif -%}'; counts += '{{ product.Quantity | Normalize }}{% if forloop.index != size -%}|{% endif -%}'; {% endfor -%} _edrone.product_ids = ids; _edrone.product_titles = titles; _edrone.product_images = images; _edrone.product_skus = skus; _edrone.product_urls = urls; _edrone.product_category_ids = categoryIds; _edrone.product_counts = counts; _edrone.order_id = '{{ order.PlacedOrder.Id }}'; _edrone.base_currency = '{{ order.Currency }}'; _edrone.order_currency = '{{ order.Currency }}'; _edrone.base_payment_value = '{{ order.OrderTotalValue | ToString | Replace:",","." }}'; _edrone.order_payment_value = '{{ order.OrderTotalValue | ToString | Replace:",","." }}'; _edrone.init(); </script> {% endif -%}
    Wskazówka
    Jeżeli w swoim szablonie używasz dla koszyka innej nazwy obiektu niż cart lub order, to powyższy kod należy zmodyfikować.
  Edrone i dodawanie towarów w szablonie Szafir:
  1. Plik js/init-ui1.js
  • Funkcja serialAddingToCart
Na samym początku funkcji znajduje się pętla “each”, a w niej instrukcja warunkowa „if (quantity > 0)”. Na końcu tej instrukcji warunkowej wklejamy poniższy kod: if(typeof _edrone !== 'undefined') { var product = form.parents('.product-item-lq'); var base = $('[data-base]').data('base'); if (first) { _edrone.product_ids = productId; _edrone.product_titles = product.find('.product-name-lq').text(); _edrone.product_images = base + product.find('img').data('src'); _edrone.product_skus = product.find('.product-code-lq').text(); _edrone.product_urls = base + product.find('a').attr('href'); _edrone.product_category_ids = $('[data-group-id]').data('group-id'); _edrone.product_category_names = $('[data-group-name]').data('group-name'); first = false; } else { _edrone.product_ids += '|' + productId; _edrone.product_titles += '|' + product.find('.product-name-lq').text(); _edrone.product_images += '|' + base + product.find('img').data('src'); _edrone.product_skus += '|' + product.find('.product-code-lq').text(); _edrone.product_urls += '|' + base + product.find('a').attr('href'); _edrone.product_category_ids += '|' + $('[data-group-id]').data('group-id'); _edrone.product_category_names += '|' + $('[data-group-name]').data('group-name'); } } Kilkanaście linijek niżej (w tej samej funkcji) jest instrukcja warunkowa “if (resGuardian)”. Na początku tej instrukcji warunkowej wklejamy poniższy kod: if(typeof _edrone !== 'undefined') { _edrone.action_type = 'add_to_cart'; _edrone.init(); }
  • Funkcja addManyProducts
Na samym początku funkcji znajduje się pętla “for(var i=0; i<products.length; i++)” iterująca po produktach. Tuż przed nią należy dodać poniższą linijkę: var first = true; Następnie, w tej pętli znajduje się instrukcja warunkowa „if(products[i].askForPriceChild == false && products[i].quantity > 0)”. Na samym jej końcu należy dodać poniższy kod: if(parameters && !validationError && products[i].supply != undefined && typeof _edrone !== 'undefined'){ if(first){ _edrone.product_ids = products[i].supply; _edrone.product_images = products[i].img; _edrone.product_skus = products[i].code; var name = _edrone.product_titles; var url = _edrone.product_urls; var categoryId = _edrone.product_category_ids; var categoryName = _edrone.product_category_names; first = false; } else { _edrone.product_ids += '|' + products[i].supply; _edrone.product_images += '|' + products[i].img; _edrone.product_skus += '|' + products[i].code; _edrone.product_titles += '|' + name; _edrone.product_urls += '|' + url; _edrone.product_category_ids += '|' + categoryId; _edrone.product_category_names += '|' + categoryName; } } Kilkanaście linijek niżej (w tej samej funkcji) jest “$.post”. Na samym jego początku należy dodać poniższy kod: if(typeof _edrone !== 'undefined') { _edrone.action_type = 'add_to_cart'; _edrone.init(); }
  • Dodanie funkcji simpleAddToCartSuccess
Na końcu pliku js/init-ui1.js należy dodać poniższy kod: function simpleAddToCartSuccess(e){ updateClientArea(); if(typeof _edrone !== 'undefined') { if ($('.add-from-presentation-lq').index() == -1) { var product = $(e.currentTarget).parents('.product-item-lq'); var base = product.parents('[data-base]').data('base'); _edrone.product_ids = product.data('product-id'); _edrone.product_titles = product.find('.product-name-lq').text(); _edrone.product_images = base + product.find('img').attr('src'); _edrone.product_skus = product.find('.product-code-lq').text(); _edrone.product_urls = base + product.find('a').attr('href'); _edrone.product_category_ids = product.parents('[data-group-id]').data('group-id'); _edrone.product_category_names = product.parents('[data-group-name]').data('group-name'); } _edrone.action_type = 'add_to_cart'; _edrone.init(); } } Następnie należy zmodyfikować “event”, który jest wywoływany przy kliknięciu w element z klasą “add-to-cart-update-client-area-lq”. Zmieniamy zawartość tego eventa na: app.post(e, simpleAddToCartSuccess, e); Cały event powinien wyglądać następująco: $('body').on('click', '.add-to-cart-update-client-area-lq', function(e) { app.post(e, simpleAddToCartSuccess, e); });
  1. Plik js/init-ui2.js
  • Funkcja serialAddingFromWishlist
Na samym początku funkcji znajduje się pętla “each”. Tuż przed nią należy dodać poniższą linijkę: var first = true; Następnie, w tej pętli znajduje się instrukcja warunkowa „if (quantity > 0)”. Na samym jej końcu należy dodać poniższy kod: if(typeof _edrone !== 'undefined') { if (first) { _edrone.product_ids = productId; _edrone.product_titles = productContainer.find('.product-name-lq').text(); _edrone.product_images = base + productContainer.find('img').attr('src'); _edrone.product_skus = productContainer.find('.product-code-lq').text(); _edrone.product_urls = base + productContainer.find('a').attr('href'); _edrone.product_category_ids = categoryId; first = false; } else { _edrone.product_ids += '|' + productId; _edrone.product_titles += '|' + productContainer.find('.product-name-lq').text(); _edrone.product_images += '|' + base + productContainer.find('img').attr('src'); _edrone.product_skus += '|' + productContainer.find('.product-code-lq').text(); _edrone.product_urls += '|' + base + productContainer.find('a').attr('href'); _edrone.product_category_ids += '|' + categoryId; } } Kilkanaście linijek niżej (w tej samej funkcji) jest instrukcja warunkowa “if (resGuardian)”. Na początku tej instrukcji warunkowej wklejamy poniższy kod: if(typeof _edrone !== 'undefined') { _edrone.action_type = 'add_to_cart'; _edrone.init(); }

Nowe Inpost API - aktualizacja paczkomatów i punktów odbioru osobistego w szablonach

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Szablon Szafir

Wskazówka
Pliki potrzebne do aktualizacji paczkomatów i punktów odbioru osobistego: Pobierz pliki
  1. Wrzuć pliki „collection-points-scripts.html” i „collection-points-styles.html” do głównego folderu z szablonem (tam gdzie „__layout.html”).
  2. Wrzuć plik „collection-points.js” do folderu „js”.
  3. Wrzuć plik “collection-points.css” do folderu “css”.
  4. Podmień plik “collection-points.html”, który znajduje się w folderze „order/delivery-partials”.
  5. W pliku „__layout.html”, na końcu sekcji „<head>” dodaj poniższą linijkę: {% include 'collection-points-styles.html' %}
  6. W pliku „__layout.html”, na końcu sekcji „<body>” dodaj poniższą linijkę: {% include 'collection-points-scripts.html' %}
  7. Dodaj tłumaczenie: - SearchInpostInfo: "Szukaj po mieście, adresie i nazwie paczkomatu”
  8. (punkt opcjonalny – poprawienie styli – bez niego paczkomaty i POO będą działać ale będzie brzydko wyglądać i każdy to zauważy) W pliku “order/delivery-partials/delivery-section.html”, pod formularzem „<form class="no-message-lq delivery-form-lq">” należy utworzyć nowy kontener “<div class="clear-after-ui"></div>”, a następnie wkleić do niego dwa ostatnie kontenery z klasą “f-left-ui” wraz z ich zawartością. <div class="clear-after-ui"> <div class="f-left-ui half-ui-with-space-ui cart-option-ui delivery-address-lq address-ui delivery-address-ui"> <p> {% if order.SelectedDelivery.CollectionPointTypeId == 0 -%} {{translations.ShippingAddress}} {% else -%} {{translations.MyData}} {% endif -%} </p> <div class="address-template-container-lq" data-address-type="0"> {% assign lackOfPhone = false -%} {% assign countryMismatch = false -%}{% if order.SelectedDelivery.PhoneRequired and deliveryAddress.PhoneNo == '' -%} {% assign lackOfPhone = true -%} {% endif -%} {% comment -%} {% if page.Cookies.deliveryAddressId == null or page.Cookies.deliveryAddressId == '' -%} {% for profileAddress in customer.DeliveryAddresses -%} {% if profileAddress.Default and profileAddress.Country != config.DefaultCountry -%} {% assign countryMismatch = true -%} {% break -%} {% endif -%} {% endfor -%} {% if countryMismatch == false and deliveryAddress.Country != config.DefaultCountry -%} {% assign countryMismatch = true -%} {% endif -%} {% elseif page.Cookies.deliveryAddressId == -1 -%} {% assign countryMismatch = true -%} {% else -%} {% for profileAddress in customer.DeliveryAddresses -%} {% if profileAddress.Id == page.Cookies.deliveryAddressId -%} {% if profileAddress.Country != deliveryAddress.Country %} {% assign countryMismatch = true -%} {% endif -%} {% break -%} {% endif -%} {% endfor -%} {% endif -%} {% endcomment -%} {% if page.Cookies.delivCountryChanged == 'true' -%} {% assign countryMismatch = true -%} {% endif -%} {% if deliveryAddress.Name == '' or lackOfPhone or countryMismatch -%} {% include 'order/delivery-partials/address-form.html' with 'orderDa' -%} {% else -%} {% include 'order/delivery-partials/address-presentation.html' with 'orderDa' -%} {% endif -%} </div> </div> <div class="f-left-ui half-ui-with-space-ui cart-option-ui invoice-address-lq address-ui invoice-address-ui"> <p>{{translations.InvoiceData}}</p> <div class="address-template-container-lq" data-address-type="1"> {% if invoiceAddress.Name == '' and order.Customer.CustomerDetailsEditable -%} {% include 'order/delivery-partials/address-form.html' with 'inv-add' -%} {% else -%} {% include 'order/delivery-partials/address-presentation.html' with 'inv-add'-%} {% endif -%} </div> </div> </div>

Szablon Agat

Wskazówka
Pliki potrzebne do aktualizacji paczkomatów i punktów odbioru osobistego: Pobierz pliki
  1. Podmień plik ‘order.js’, który znajduje się w folderze ‘js’.
  2. Wrzuć plik ‘collection-points.css’ do folderu ‘css’.
  3. a) Jeśli kod szablonu nie był modyfikowany, podmień plik ‘delivery-adress.html’, który znajduje się w folderze ‘partials/cart’. b) Jeśli kod szablonu był modyfikowany, podmień obecny widok mapy z paczkomatami następującym: {% if cart.SelectedDelivery.CollectionPointTypeId == 2 or cart.SelectedDelivery.CollectionPointTypeId == 1 -%} <div class="geowidget-container" id="map"> {% if settings.googleMapsKey == '' or cart.SelectedDelivery.CollectionPointTypeId == 1 -%} <div id="collection-points-searcher" class="collection-points-search-box {% if cart.SelectedDelivery.CollectionPointTypeId == 1 -%} personal-collection-points {% endif -%}"> <input placeholder="{% if cart.SelectedDelivery.CollectionPointTypeId == 1 -%} {{translations.TypeAdress}} {% else -%}{{translations.AddCodeOrAdress}}{% endif -%}" type="search" id="machines-filter-input" class="collection-point-search-input"> <span class="fa fa-search"></span> <div class="collection-points-result hidden"><ul></ul></div> </div> {% elsif settings.googleMapsKey != '' and cart.SelectedDelivery.CollectionPointTypeId == 2 -%} <div id="easypack-map"></div> {% endif -%} </div> {% endif -%}
  4. W pliku ‘_layout.html’, na końcu sekcji ‘<head>’ dodaj poniży kod: {% if page.PageId == config.DefinedPages.Order.Id -%} <link rel="stylesheet" type="text/css" href="https://geowidget.easypack24.net/css/easypack.css"> <link rel="stylesheet" type="text/css" href="css/collection-points.css"> {% endif -%}
  5. W pliku ‘_layout.html’, na końcu sekcji ‘<body>’ dodaj poniży kod: {% if page.PageId == config.DefinedPages.Order.Id -%} <script async src="https://geowidget.easypack24.net/js/sdk-for-javascript.js"></script> {% endif -%}
  6. Dodaj tłumaczenia:  - TypeAdress: "Wpisz adres"  - AddCodeOrAdress: "Wpisz kod paczkomatu lub adres"
  7. Aby paczkomaty działały poprawnie również przy przechodzeniu na poprzedni i następny krok koszyka: a) Jeśli kod szablonu nie był modyfikowany, podmień plik ‘init.js’, który znajduje się w folderze ‘js’. b) Jeśli kod szablonu był modyfikowany, wywołaj funkcje: orderCollectionPoints.easyPackAsyncInit(); orderCollectionPoints.getCollectionPoints(); w tych funkcjach, które są wywoływane przy zmianie sekcji na ‘CustomerData’ w koszyku: Zmienione fragmenty pliku ‘init.js’ to: orderPrevStep: function (e) { var container = $('.shopping-cart'); var data = { __template: 'partials/cart/cart-template.html', __csrf: __CSRF, __action: 'Order/StepPrev' }; $.post(null, data, function (result) { if (result.action.Result) { $('.shopping-cart').html(result.template); if ($('body').find('#invoice-address-data').index() >= 0) { application.uiSetSwitchNameWidthInInvoice(); } if ($('#easypack-map').length > 0) { orderCollectionPoints.easyPackAsyncInit(); } if($('#collection-points-searcher').length > 0) { orderCollectionPoints.getCollectionPoints(); } if ($('.geowidget-container').length > 0) { $('#main-section .save-delivery-address-data').addClass('order-next-step').removeClass('choose-collection-point'); } application.loadImages(); application.uiScrollToTop(container); application.uiCheckLabels(); } else { if (result.action.Code != 100) { if (result.action.Validation != null) { errorMessage = '<div class="title">' + result.action.Message + '</div>' + '<p>' + result.action.Validation[0].Error + '</p>'; } else { errorMessage = '<div class="title">' + result.action.Message + '</div>'; } application.createMessage(errorMessage); } } }); }, orderNextStep: function (e) { if ($('#delivery-address-data').index() >= 0) { var allEdited = true; $('#delivery-address-data input[required]').each(function () { if (allEdited === false) { return; } else { if ($(this).val() == '') { allEdited = false; } } }); if (allEdited === false) { var errorMessage = $(e.currentTarget).next().next().val(); application.createMessage(errorMessage, 3000); return; } else if ($('input[name="invoice"]').hasClass('company') && $('input[name="tin"]').val() == '' && $('input[name="tin"]').prop('required')) { var message = $('input[name="company"]').attr('data-info'); application.createMessage(message, 2000); } else { var data = $('#delivery-address-data').serializeArray(); var validate = application.uiValidateForm($('#delivery-address-data'));if (validate) { $.post(null, data, function (result) { if (result.action.Result) { var container = $('body'); var data = { __template: 'partials/cart/cart-template.html', __csrf: __CSRF, __action: 'Order/StepNext' }; $.post(null, data, function (result) { if (result.action.Result) { $('.shopping-cart').replaceWith(result.template); if ($('body').find('#invoice-address-data').index() >= 0) { application.uiSetSwitchNameWidthInInvoice(); } application.loadImages(); application.uiSetSwitchNameWidthInSummaryCheckboxes(); application.uiScrollToTop(container); application.uiCheckLabels(); if ($('#easypack-map').length > 0) { orderCollectionPoints.easyPackAsyncInit(); } if($('#collection-points-searcher').length > 0) { orderCollectionPoints.getCollectionPoints(); } } else { if (result.action.Code != 100) { if (result.action.Validation != null) { errorMessage = '<div class="title">' + result.action.Message + '</div>' + '<p>' + result.action.Validation[0].Error + '</p>'; } else { errorMessage = '<div class="title">' + result.action.Message + '</div>'; } application.createMessage(errorMessage, 3000); } } }); } else { if (result.action.Code != 100) { if (result.action.Validation != null) { errorMessage = '<div class="title">' + result.action.Message + '</div>' + '<p>' + result.action.Validation[0].Error + '</p>'; } else { errorMessage = '<div class="title">' + result.action.Message + '</div>'; } application.createMessage(errorMessage, 3000); return; } } }); } } } else { var container = $('body'); var data = { __template: 'partials/cart/cart-template.html', __csrf: __CSRF, __action: 'Order/StepNext' }; $.post(null, data, function (result) { if (result.action.Result) { if ((result.template).indexOf('name="sel-del-met" value="' + 1 + '"') !== -1 || (result.template).indexOf('name="sel-del-met" value="' + 2 + '"') !== -1) { application.orderPrevStep(); } else { $('.shopping-cart').replaceWith(result.template); if ($('body').find('#invoice-address-data').index() >= 0) { application.uiSetSwitchNameWidthInInvoice(); } if ($('#easypack-map').length > 0) { orderCollectionPoints.easyPackAsyncInit(); } if($('#collection-points-searcher').length > 0) { orderCollectionPoints.getCollectionPoints(); } application.loadImages(); application.uiSetSwitchNameWidthInSummaryCheckboxes(); application.uiScrollToTop(container); application.uiCheckLabels(); } } else { if (result.action.Code != 100) { if (result.action.Validation != null) { errorMessage = '<div class="title">' + result.action.Message + '</div>' + '<p>' + result.action.Validation[0].Error + '</p>'; } else { errorMessage = '<div class="title">' + result.action.Message + '</div>'; } application.createMessage(errorMessage); } } }); } },

Szablon Opal

Wskazówka
Pliki potrzebne do aktualizacji paczkomatów i punktów odbioru osobistego: Pobierz pliki
  1. Wrzuć plik ‘collection-points.js’ do folderu ‘js’.
  2. Wrzuć plik ‘collection-points.css’ do folderu ‘css’.
  3. Podmień plik ’delivery-points-partial.html’, który znajduje się w folderze ‘order’.
  4. a) Jeśli kod szablonu nie był modyfikowany, podmień plik ‘data-form.html’, który znajduje się w folderze ‘order/cst-data’. b) Jeśli kod szablonu był modyfikowany, podmień obecny widok mapy z paczkomatami linijką: {% include 'order/delivery-points-partial.html' -%}
  5. W pliku ‘_layout.html’, na końcu sekcji ‘<head>’ dodaj poniży kod: {% if page.PageId == config.DefinedPages.Order.Id -%} <link rel="stylesheet" type="text/css" href="https://geowidget.easypack24.net/css/easypack.css"> <link rel="stylesheet" type="text/css" href="css/collection-points.css"> {% endif -%}
  6. W pliku ‘order-cart.html’, do bloku ‘{% block PageBodyEnd -%}’ dodaj poniży kod: <script async src="https://geowidget.easypack24.net/js/sdk-for-javascript.js"></script> <script src="js/collection-points.js"></script>
  7. Dodaj tłumaczenie:  - TypeAdress: "Wpisz adres"
  8. Aby paczkomaty działały poprawnie również przy przechodzeniu na poprzedni i następny krok koszyka: a) Jeśli kod szablonu nie był modyfikowany, podmień plik ‘order.js’, który znajduje się w folderze ‘js’. b) Jeśli kod szablonu był modyfikowany, wywołaj funkcje: orderCollectionPoints.easyPackAsyncInit(); orderCollectionPoints.getCollectionPoints(); w tych funkcjach, które są wywoływane przy zmianie sekcji na ‘customerData’ w koszyku: Zmienione fragmenty pliku ‘order.js’, to: orderForm.on('click', '#customer-data-form', function (e) { e.preventDefault(); $.get('', {__template: 'order/cst-data/data-form.html'}, function (res) { orderForm.find('.content').html(res.template); if ($('#easypack-map').length > 0) { orderCollectionPoints.easyPackAsyncInit(); } if($('#collection-points-searcher').length > 0) { orderCollectionPoints.getCollectionPoints(); } window.sessionStorage.setItem('continueWithoutRegistration', true); }); }); var initStep = (function f(e, step) { if (!$('.order').hasClass('cart-empty')) { stepsLinks(); }if (step && step == 'ThankYou') { $("#order-form").find("script").each(function () { eval($(this).text()); }); if (window.sessionStorage.getItem('continueWithoutRegistration')) { window.sessionStorage.removeItem('continueWithoutRegistration'); } } if (step && step == 'CustomerData') { window.sessionStorage.setItem('toSkip', true); if (window.sessionStorage.getItem('continueWithoutRegistration')) { $.get('', {__template: 'order/cst-data/data-form.html'}, function (res) { orderForm.find('.content').html(res.template); if ($('#easypack-map').length > 0) { orderCollectionPoints.easyPackAsyncInit(); } if($('#collection-points-searcher').length > 0) { orderCollectionPoints.getCollectionPoints(); } }); } } return f; })(); orderForm.on('click', '.recalculate, #remove-points', function (e) { e.preventDefault(); $.post(null, { __collection: 'customer.Cart.Value', __template: 'order/cart.html', __csrf: __CSRF, __action: 'cart/Recalculate' }, function (d) { CreateTooltip(d.action); showTooltip(); $('.order-content').replaceWith(d.template); lazyCheck(); UpdateSmallCrt(d.collection); orderCollectionPoints.checkPointsAvailability(); }); });

Szablon Bursztyn

Wskazówka
Pliki potrzebne do aktualizacji paczkomatów i punktów odbioru osobistego: Pobierz pliki
    1. Wrzuć plik „collectionpoints.js” do folderu „js”.
    2. Wrzuć plik “collectionpoints.css” do folderu “css” .
    3. W pliku html w sekcji <head> pod koniec znaczników <link> dodaj poniższy kod: {% if page.PageId == config.DefinedPages.Order.Id -%} <link rel="stylesheet" type="text/css" href="https://geowidget.easypack24.net/css/easypack.css"> <link rel="stylesheet" type="text/css" href="css/collectionpoints.css"> {% endif -%}
    4. W pliku ‘order-cart.html’, do bloku ‘{% block PageBodyEnd -%}’ dodaj poniży kod: <script async src="https://geowidget.easypack24.net/js/sdk-for-javascript.js"></script> <script src="js/collection-points.js"></script>
    5. Plik cart.html: a) Jeśli kod szablonu nie był modyfikowany, wystarczy podmienić plik, który znajduje się w katalogu ‘order’. b) Jeśli kod szablonu był modyfikowany, podmień obecny widok mapy z paczkomatami następującym kodem: {% if cart.SelectedDelivery.CollectionPointTypeId == 2 or cart.SelectedDelivery.CollectionPointTypeId == 1 -%} <div class="col-sm-12 geowidget-container" id="map"> <h2> {% if cart.SelectedDelivery.CollectionPointTypeId == 1 -%} {{translations.Crt_ChooseCollectionPoint}} {% else -%} {{translations.Crt_ChooseInpostMachine}} {% endif -%} </h2>{% if settings.googleMapsKey == '' or cart.SelectedDelivery.CollectionPointTypeId == 1 -%} <div id="collection-points-searcher" class="collection-points-search-box {% if cart.SelectedDelivery.CollectionPointTypeId == 1 -%} personal-collection-points {% endif -%}"> <input placeholder="{% if cart.SelectedDelivery.CollectionPointTypeId == 1 -%} {{transla-tions.TypeAdress}} {% else -%}{{translations.Crt_MachineCodeOrAdress}}{% endif -%}" type="search" id="machines-filter-input" class="collection-point-search-input"> <span class="fa fa-search"></span> <div class="collection-points-result hidden"><ul></ul></div> </div> {% elsif settings.googleMapsKey != '' and cart.SelectedDelivery.CollectionPointTypeId == 2 -%} <div id="easypack-map"></div> {% endif -%} </div> {% endif -%}
    6. Plik order-short-info.html : a) Jeśli kod szablonu nie był modyfikowany, podmień plik znajdujący się w folderze ‘order’ b) Jeśli kod szablonu był modyfikowany, podmień linijkę {% assign displayOptions = include %} (znajdującą się na początku dokumentu), poniższym kodem: {% if page.POST.__include %} {% assign displayOptions = page.POST.__include %} {% else %} {% assign displayOptions = include %} {% endif %}
    7. Plik cart-products-partial.html: a) Jeśli kod szablonu nie był modyfikowany, podmień plik znajdujący się w folderze ‘order’ b) Jeśli kod szablonu był modyfikowany, proszę usunąć poniższy kod znajdujący się pod koniec znacznika <div class=”custom-collection”> : {% if settings.googleMapsKey != '' and deliveryData.CollectionPoints[deliveryData.CollectionPointId].Latitude <> "" and deliveryData.CollectionPoints[deliveryData.CollectionPointId].Longitude <> "" and step == 'summary' -%} <p class="collection-localization"> <span class="glyphicon glyphicon-map-marker"></span> {{translations.Crt_LocateOnMap}} </p> <div id="map-canvas" data-step="{{step}}" data-type="{{deliveryData.CollectionPointTypeId}}" data-lat="{{deliveryData.CollectionPoints[deliveryData.CollectionPointId].Latitude}}" data-lng="{{deliveryData.CollectionPoints[deliveryData.CollectionPointId].Longitude}}"></div> {% endif -%}
    8. Aby paczkomaty działały poprawnie podczas przechodzenia na poprzedni oraz następny krok koszyka należy: a) Jeśli kod szablonu nie był modyfikowany, podmień plik ‘order.js’ znajdujący się w folderze ‘js’ b) Jeśli kod szablonu był modyfikowany, należy wywołać orderCollectionPoints.cpCheck() oraz orderCollectionPoints .checkPackage() na końcu funkcji, która przenosi użytkownika do poprzedniego kroku koszyka.Funkcja orderCollectionPoints.cpCheck() jest odpowiedzialna za inicjalizację mapy bądź listy paczkomatów na danej stronie. Z kolei orderCollectionPoints.checkPackage() sprawdza czy paczkomat do którego ma być zrealizowane zamówienie został już wybrany.Funkcja orderCollectionPoints.cpCheck() należałoby również dodać do zdarzenia obsługującego zmianę sposobu dostawy.Ostatnią rzeczą jaką trzeba zrobić na koniec zamówienia, kiedy klient zrealizuje już transakcję, to dodanie linijki sessionStorage.removeItem(‘paczka’). Ma ona na celu usunięcia informacji o wybranym paczkomacie.
Wskazówka
Przeczytaj więcej o nowym API serwisu InPost.

Obsługa kanałów do zgody na newsletter w darmowych szablonach graficznych Comarch e-Sklep

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.
Listę zgód wyświetlanych w newsletterze możemy znaleźć w tablicy przechowywanej w obiekcie config.TOS.Consents.Newsletter. Poniższa pętla pozwoli nam wyświetlić wszystkie zgody znajdujące się w obiekcie Newsletter:
{% for tos in config.TOS.Consents.Newsletter -%}
<label class="statement tos-name">{{tos.Text}}</label> {% endif -%}  Jeżeli interesuje nas pokazanie wszystkich kanałów znajdujących się w danej zgodzie to warto najpierw przypisać ich ilość do konkretnej zmiennej liquidowej. W każdej pojedynczej zgodzie kanały możemy znaleźć w obiekcie Channels.
{% assign channelsSize = tos.Channels | Size -%}
Teraz wystarczy tylko napisać prostą pętle „for” Poniżej przykład wykorzystujący listę.
{% if channelsSize > 0 -%}
<ul class="channels disabled">
    {% for chn in tos.Channels -%}
    <li class="channel">
        <input id="channel{{ chn.Key }}" type="checkbox" name="channelKey" value="{{ chn.Key }}" disabled/>
        <div class="channel-switch input-switch "><div class="switch-button"></div></div>
        <label for="channel{{ chn.Key }}">{{chn.Name}}</label>
    </li>
    {% endfor -%}
</ul>
{% endif -%}

Szablon Agat

1.Zmień pętlę for wyświetlającą checkboxy ze zgodami w pliku 'footer.html', który znajduje się w folderze 'partials/common' {% for tos in config.TOS.Consents.Newsletter -%} <div class="input-group switches"> <label class="switch"> <span class="switch-name summary-tos-switch-name">{% if tos.Required -%}* {% endif -%}{{ tos.Text }}</span> <input class="switch-input" type="checkbox" name="tos" value="{{ tos.Id }}" {% if tos.Required -%} data-required="req" {% endif -%}/> <span class="switch-label"></span> <span class="switch-handle"></span> </label> </div> {% endfor -%} {% for tos in config.TOS.Consents.Newsletter -%} {% assign channelsSize = tos.Channels | Size -%} <li class="{% if channelsSize > 0 -%}multiple-choice {% endif -%} {% if tos.Required -%} required-consent{% endif -%}"> <div class="input-group switches"> {% if tos.Statement %} <p class="multiple-switch">{% if tos.Required -%}* {% endif -%}{{ tos.Text }}</p> {% else %} <span class="main-consent-warning tos-warning"><span class="fa fa-exclamation-triangle"></span>{{translations.MainConsentWarning}}</span> <label class="switch"> <span class="switch-name summary-tos-switch-name">{% if tos.Required -%}* {% endif -%}{{ tos.Text }}</span> <input class="switch-input" type="checkbox" name="tos" value="{{ tos.Id }}" {% if tos.Required -%} data-required="req" {% endif -%}/> <span class="switch-label"></span> <span class="switch-handle"></span> </label> {% endif -%} {% if channelsSize > 0 -%} <span class="channel-warning tos-warning"><span class="fa fa-exclamation-triangle"></span>{{translations.ChannelWarning}}</span> {% for chn in tos.Channels -%} <label class="switch channel-switch {% if tos.Statement == false %} unactive-switch{% endif -%}"> <span class="switch-name">{{chn.Name}}</span> <input class="switch-input channel-checkbox" type="checkbox" name="channelKey" value="{{ chn.Key }}" {% if tos.Required -%} data-required="req" {% endif -%} {% if tos.Statement == false %} disabled{% endif -%}/> <span class="switch-label"></span> <span class="switch-handle"></span> </label> {% endfor -%} {% endif -%} </div> </li> {% endfor -%} 2.W pliku 'init.js' uzupełnij funkcję uiValidateForm o walidację pól kanałów. Plik znajduje się w folderze 'js'. uiValidateForm: function (form) { var formRequiredInputs = form.find('input[required], textarea[required]'); var tosInputs = form.find('input[type="checkbox"]'); var formInvalidInfo = form.data('invalid'); var emailInvalidInfo = form.data('email-invalid'); var postCodeInvalidInfo = form.data('pcode-invalid'); var tinInvalidInfo = form.data('tin-invalid'); var tosRequiredInfo = form.data('tos-invalid'); var warningTosInfos = form.find('.tos-warning'); var tosRequiredValid = true; var tinInputValid = true; var emailInputValid = true; var postCodeInputValid = true; var isEmpty = false; var checkedChannels = []; var channelsInputs; $.each(formRequiredInputs, function (key, value) { $(value).addClass('validationStyles'); if ($(value).val() == '') { isEmpty = true; } if ($(value).attr('name') === 'email') { emailInputValid = application.uiValidateEmail($(value).val()); } if ($(value).attr('name') === 'zipCode') { postCodeInputValid = application.uiValidatePostCode($(value).val(), $(value).attr('pattern')); } if ($(value).attr('name') === 'tin') { tinInputValid = application.uiValidateTinCode($(value).val(), $(value).attr('pattern')); } }); $.each(tosInputs, function (key, value) { if ($(value).data('required') === 'req') { if (!$(value).prop('checked')) { $(value).closest('label').addClass('required-checkbox-warning'); } if ($(value).hasClass('channel-checkbox')) { channelsInputs = $(value).closest('.input-group').find('.channel-checkbox'); $.each(channelsInputs, function (key, value) { if ($(value).prop('checked')) { checkedChannels.push($(value)); } }); if (checkedChannels.length > 0) { tosRequiredValid = true } else { tosRequiredValid = false } if (warningTosInfos.length > 0) { $.each(warningTosInfos, function (key, value) { if ($(value).is(":visible")) { tosRequiredValid = false; } }); } } else if (!$(value).prop('checked')) { tosRequiredValid = false; } } }); if (tosRequiredValid && tinInputValid && postCodeInputValid && emailInputValid && !isEmpty) { return true; } else if (!emailInputValid) { application.createMessage(emailInvalidInfo); } else if (!postCodeInputValid) { application.createMessage(postCodeInvalidInfo); } else if (!tinInputValid) { application.createMessage(tinInvalidInfo); } else if (!tosRequiredValid) { application.createMessage(tosRequiredInfo); } else { application.createMessage(formInvalidInfo); } }, uiValidateForm: function (form) { var formRequiredInputs = form.find('input[required], textarea[required]'); var tosInputs = form.find('input[type="checkbox"]'); var formInvalidInfo = form.data('invalid'); var emailInvalidInfo = form.data('email-invalid'); var postCodeInvalidInfo = form.data('pcode-invalid'); var tinInvalidInfo = form.data('tin-invalid'); var tosRequiredInfo = form.data('tos-invalid'); var warningTosInfos = form.find('.tos-warning'); var tosRequiredValid = true; var tinInputValid = true; var emailInputValid = true; var postCodeInputValid = true; var isEmpty = false; var checkedChannels = []; var channelsInputs; $.each(formRequiredInputs, function (key, value) { $(value).addClass('validationStyles'); if ($(value).val() == '') { isEmpty = true; } if ($(value).attr('name') === 'email') { emailInputValid = application.uiValidateEmail($(value).val()); } if ($(value).attr('name') === 'zipCode') { postCodeInputValid = application.uiValidatePostCode($(value).val(), $(value).attr('pattern')); } if ($(value).attr('name') === 'tin') { tinInputValid = application.uiValidateTinCode($(value).val(), $(value).attr('pattern')); } }); $.each(tosInputs, function (key, value) { if ($(value).data('required') === 'req') { if (!$(value).prop('checked')) { $(value).closest('label').addClass('required-checkbox-warning'); } if ($(value).hasClass('channel-checkbox')) { channelsInputs = $(value).closest('.input-group').find('.channel-checkbox'); $.each(channelsInputs, function (key, value) { if ($(value).prop('checked')) { checkedChannels.push($(value)); } }); if (checkedChannels.length > 0) { tosRequiredValid = true } else { tosRequiredValid = false } if (warningTosInfos.length > 0) { $.each(warningTosInfos, function (key, value) { if ($(value).is(":visible")) { tosRequiredValid = false; } }); } } else if (!$(value).prop('checked')) { tosRequiredValid = false; } } }); if (tosRequiredValid && tinInputValid && postCodeInputValid && emailInputValid && !isEmpty) { return true; } else if (!emailInputValid) { application.createMessage(emailInvalidInfo); } else if (!postCodeInputValid) { application.createMessage(postCodeInvalidInfo); } else if (!tinInputValid) { application.createMessage(tinInvalidInfo); } else if (!tosRequiredValid) { application.createMessage(tosRequiredInfo); } else { application.createMessage(formInvalidInfo); } }, 3.Aby walidacja działała poprawnie, dodaj dodatkowe funkcje w pliku 'init.js', w obiekcie application (uicheckIfParentChecked, uicheckIfTosChannelChecked) uicheckIfParentChecked: function(e) { var parentBox = $(e.currentTarget).closest('.multiple-choice'); var elementParentTos = parentBox.find('input[name=tos]'); var consentWarning = parentBox.find('.main-consent-warning'); var channelWarning = parentBox.find('.channel-warning'); var tosChannels = parentBox.find('.channel-checkbox'); var checkedChannels = []; var elementParentTosChecked, parentTosName; if (elementParentTos.length > 0) { elementParentTosChecked = $(elementParentTos[0]).prop('checked'); parentTosName = parentBox.find('.input-group > label .switch-name'); consentWarning = $(elementParentTos[0]).closest('.input-group').find('.main-consent-warning'); if (!elementParentTosChecked) { $(parentTosName[0]).css({ 'color': '#ff3a3a', 'transition': '200ms' }); $(consentWarning[0]).show(); } if (!$(e.currentTarget).prop('checked') || elementParentTosChecked) { $(parentTosName[0]).css({ 'color': '', 'transition': '200ms' }); $(consentWarning[0]).hide(); } if (!$(e.currentTarget).prop('checked') && !elementParentTosChecked) { $(parentTosName[0]).css({ 'color': '', 'transition': '200ms' }); $(consentWarning[0]).hide(); $(e.currentTarget).prop('disabled', true); $(e.currentTarget).closest('.channel-switch').addClass('unactive-switch'); } if ($(e.currentTarget).prop('checked')) { $(channelWarning[0]).hide(); } else { $.each(tosChannels, function (key, value) { if ($(value).prop('checked')) { checkedChannels.push($(value)); } }); if (checkedChannels.length === 0 && elementParentTosChecked) { $(channelWarning[0]).show(); } } } }, uicheckIfTosChannelChecked: function (e) { var parentBox = $(e.currentTarget).closest('.multiple-choice'); var tosChannels = parentBox.find('.channel-checkbox'); var checkedChannels = []; var channelWarning = parentBox.find('.channel-warning'); var consentWarning = parentBox.find('.main-consent-warning'); var isChecked = $(e.currentTarget).prop('checked'); var tosName = $(e.currentTarget).closest('label').find('.switch-name'); $.each(tosChannels, function (key, value) { if ($(value).prop('checked')) { checkedChannels.push($(value)); } }); if (checkedChannels.length > 0 && !isChecked) { $(channelWarning[0]).hide(); $.each(tosChannels, function (key, value) { $(value).closest('.channel-switch').addClass('unactive-switch'); $(value).prop('disabled', true); $(value).prop("checked", false); }); } if (checkedChannels.length > 0 && isChecked) { $(channelWarning[0]).hide(); $(tosName[0]).css({ 'color': '', 'transition': '200ms' }); $(consentWarning[0]).hide(); } if (checkedChannels.length === 0 && isChecked) { $(channelWarning[0]).show(); $.each(tosChannels, function (key, value) { $(value).closest('.channel-switch').removeClass('unactive-switch'); $(value).removeAttr('disabled'); }); } if (checkedChannels.length === 0 && !isChecked) { $(channelWarning[0]).hide(); $.each(tosChannels, function (key, value) { $(value).closest('.channel-switch').addClass('unactive-switch'); $(value).prop('disabled', true); }); } }, 4.Wywołaj nowe funkcje w pliku 'init.js', w obiekcie application.events $('body').on('click', '.channel-checkbox', function (e) { self.uicheckIfParentChecked(e); }); $('body').on('click', '.multiple-choice .input-group > label .switch-input[name=tos]', function (e) { self.uicheckIfTosChannelChecked(e); }); 5.Dodaj tłumaczenia: - MainConsentWarning: "Wyraź zgodę" - ChannelWarning: "Wybierz przynajmniej jeden kanał"   6.Uzupełnij plik '480plus.css', który znajduje się w folderze 'css', o style: .multiple-switch { margin: 0 0 20px; } .multiple-choice .main-consent-warning, .multiple-choice .channel-warning, .input-group.switches .main-consent-warning, .input-group.switches .channel-warning { display: none; position: relative; font-size: 11px; color: #ff3a3a; top: -20px; left: -51px; } .multiple-choice .main-consent-warning .fa, .multiple-choice .channel-warning .fa, .input-group.switches .main-consent-warning .fa, .input-group.switches .channel-warning .fa { margin: 0 5px 0 0; } .input-group label.required-checkbox-warning .switch-name { color: #ff3a3a !important; } .input-group label.required-checkbox-warning .switch-name a.cp_link { color: #ff3a3a; } form .input-group .switch.unactive-switch { opacity: .5; cursor: not-allowed; }

Szablon Bursztyn

W pliku homepage.html proszę zastąpić poniższy kod: {% for tos in config.TOS.Consents.Newsletter -%} {% if tos.Statement -%} <label>{{tos.Text}}</label> {% else -%} <input name="tos" id="tos{{ tos.Id }}" type="checkbox" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} /> <div class="input-switch "><div class="switch-button"></div></div> <label for="tos{{ tos.Id }}">{% if tos.Required -%}*{% endif -%} {{tos.Text}}</label> {% endif -%} {% endfor -%} następującym: {% for tos in config.TOS.Consents.Newsletter -%} {% assign channelsSize = tos.Channels | Size -%} <div class="single-tos {% if channelsSize > 0 -%} channels {% endif %}"> {% if tos.Statement -%} <label class="statement tos-name">{{tos.Text}}</label> {% else -%} <div class="tos-switch"> <input name="tos" id="tos{{ tos.Id }}" type="checkbox" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} /> <div class="input-switch "><div class="switch-button"></div></div> <label for="tos{{ tos.Id }}">{% if tos.Required -%}*{% endif -%} {{tos.Text}}</label> </div> {% endif -%} {% if channelsSize > 0 -%} <ul class="channels disabled"> {% for chn in tos.Channels -%} <li class="channel"> <input id="channel{{ chn.Key }}" type="checkbox" name="channelKey" value="{{ chn.Key }}" disabled/> <div class="channel-switch input-switch "><div class="switch-button"></div></div> <label for="channel{{ chn.Key }}">{{chn.Name}}</label> </li> {% endfor -%} </ul> {% endif -%} </div> {% endfor -%}

Szablon Opal

W pliku homepage.html proszę zastąpić poniższy kod: {% for tos in config.TOS.Consents.Newsletter -%} {% if tos.Statement -%} <label>{{tos.Text}}</label> {% else -%} <input name="tos" id="tos{{ tos.Id }}" type="checkbox" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} /> <div class="input-switch "><div class="switch-button"></div></div> <label for="tos{{ tos.Id }}">{% if tos.Required -%}*{% endif -%} {{tos.Text}}</label> {% endif -%} {% endfor -%} następującym: {% for tos in config.TOS.Consents.Newsletter -%} {% assign channelsSize = tos.Channels | Size -%} <div class="single-tos"> {% if tos.Statement -%} <label class="statement-reg tos-name">{{tos.Text}}</label> {% else -%} <div class="tos-switch single-switch"> <input name="tos" id="tos{{ tos.Id }}" type="checkbox" value="{{ tos.Id }}" {% if tos.Required -%} required {% endif -%} /> <div class="input-switch "><div class="switch-button"></div></div> <label for="tos{{ tos.Id }}">{% if tos.Required -%}*{% endif -%} {{tos.Text}}</label> </div> {% endif -%} {% if channelsSize > 0 -%} <ul class="channels-list"> {% for chn in tos.Channels -%} <li class="channel single-switch"> <input id="channel{{ chn.Key }}" type="checkbox" name="channelKey" value="{{ chn.Key }}"/> <div class="input-switch "><div class="switch-button"></div></div> <label for="channel{{ chn.Key }}">{{chn.Name}}</label> </li> {% endfor -%} </ul> {% endif -%} </div> {% endfor -%}

Kanał e-mail

Jeśli wprowadziłeś powyższe zmiany, a w swoich zgodach posiadasz tylko kanał e-mail i chcesz zaoszczędzić zbędnego klikania swoim klientom to poniżej znajduje się instrukcja co należy zmienić w kodzie. Te zmiany sprawią, że kanał e-mail będzie zawsze zaznaczony i nie będzie się go dało odznaczyć.

Szafir

Plik init-ui2.js
Znajdź funkcję toggleChannels. W niej jest zdeklarowana zmienna var inputs = container.find('[name=channelKey]');. Zmień ją na var inputs = container.find('[name=channelKey]:not([type=hidden])');
Pliki home.html, sign-up-no-address.html, common/address-form-register-full.html, customer-profile/your-account/employee-update.html, order/cart.html, __loginconsents.liquid
Znajdź w tych plikach taki fragment kodu: {% if channelsSize > 0 -%} {{ translations.ChooseOption }} {% endif -%} {% for channel in tos.Channels -%} {% endfor -%} Usuń go, a w jego miejsce wklej ten fragment kodu: {% if channelsSize > 0 -%} {% assign onlyEmail = false -%} {% if channelsSize == 1 and tos.Channels[0].Type == 1 -%} {% assign onlyEmail = true -%} {% endif -%} {% if onlyEmail == false -%} {{ translations.ChooseOption }} {% endif -%} {% endif -%} {% for channel in tos.Channels -%} {% endfor -%}

Agat

Pliki partials/cart/delivery-and-payment.html, partials/common/footer.html, partials/common/registration-consents.html, __loginconsents.liquid
Znajdź w tych plikach taki fragment kodu: {% if channelsSize > 0 -%} {{translations.ChannelWarning}} {% for chn in tos.Channels -%} {% endfor -%} {% endif -%} Usuń go, a w jego miejsce wklej ten fragment kodu: {% if channelsSize > 0 -%} {% assign onlyEmail = false -%} {% if channelsSize == 1 and tos.Channels[0].Type == 1 -%} {% assign onlyEmail = true -%} {% endif -%} {% if onlyEmail == false -%} {{translations.ChannelWarning}} {% endif -%} {% for chn in tos.Channels -%} {% endfor -%} {% endif -%}

Bursztyn

Plik init.js
Wyszukaj frazę channels i zamień wszystkie jej wystąpienia w tym pliku na channels:not(.only-email)
Pliki homepage.html, customer/registration.html, order/stepsummary.html, __loginconsents.liquid
Znajdź w tych plikach taki fragment kodu: {% if channelsSize > 0 -%}
    • {% for chn in tos.Channels -%}
{% endfor -%} {% endif -%} Usuń go, a w jego miejsce wklej ten fragment kodu: {% if channelsSize > 0 -%} {% assign onlyEmail = false -%} {% if channelsSize == 1 and tos.Channels[0].Type == 1 -%} {% assign onlyEmail = true -%} {% endif -%}
    • {% for chn in tos.Channels -%}
    • {% if onlyEmail == false -%} {% else -%} {% endif -%}
{% endfor -%} {% endif -%}

Opal

Plik init.js
Wyszukaj frazę channels-list i zamień wszystkie jej wystąpienia w tym pliku na channels-list:not(.only-email)
Pliki homepage.html, customer/registration.html, order/stepsummary.html, __loginconsents.liquid
Znajdź w tych plikach taki fragment kodu: {% if channelsSize > 0 -%}
    • {% for chn in tos.Channels -%}
{% endfor -%} {% endif -%} Usuń go, a w jego miejsce wklej ten fragment kodu: {% if channelsSize > 0 -%} {% assign onlyEmail = false -%} {% if channelsSize == 1 and tos.Channels[0].Type == 1 -%} {% assign onlyEmail = true -%} {% endif -%}
    • {% for chn in tos.Channels -%}
    • {% if onlyEmail == false -%} {% else -%} {% endif -%}
{% endfor -%} {% endif -%}

Jak dostosować szablony do integracji z Google Tag Manager?

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

1. Wstęp

W związku ze zmianami w Comarch e-Sklep od wersji 2018.6, które poszerzają zakres integracji z Google Tag Manager, szablony w wersji starszej będą wymagały wprowadzenia zmian, które pozwolą na wykorzystanie w pełni funkcjonalności opisanych w artykule Integracja z Google Tag Manager.
Uwaga
Poniższa konfiguracja przeznaczona jest dla użytkowników posiadających e-Sklep w wersji 2018.6 lub wyższej ale z szablonami w starszej wersji. Pliki szablonu, fragmenty ich kodu oraz modyfikacje przedstawione w instrukcji dotyczą darmowych szablonów Comarch. W przypadku szablonów indywidualnych miejsce wklejenia skryptów niezbędnych do dostosowania szablonu powinien wskazać twórca szablonu

2. Implementacja skryptów

Jeżeli przed wersją 2018.6 integracja była już konfigurowana to konieczne będzie usunięcie starego skryptu dodanego do ostatniej strony zamówienia. W tym celu w panelu administracyjnym sklepu przejdź do obszaru Wygląd sklepu / Ustawienia / Edytuj ustawienia zaawansowane / Edytuj HTML i usuń z pliku lastpagescripts.html poniższy skrypt: <script> dataLayer.push({{ page.GTMDataLayer }}); dataLayer.push({event:'UaTrack',VirtualPath:null}); </script> W zależności od szablonu plik lastpagescripts.html będzie zlokalizowany w innym miejscu w strukturze plików:
  • Szablon Bursztyn, Opal i Szafir - order / lastpagescripts.html
  • Szablon Agat - partials / cart / lastpagescripts.html
Następnym krokiem będzie implementacja dwóch nowych skryptów. W pliku _layout.html znajdującym się bezpośrednio w obszarze Edytuj HTML zamień istniejący skrypt znajdujący się na początku sekcji <body> <script>var dataLayer=[{{ page.GTMDataLayer }}];</script> na nowy: <script>var dataLayer={{ page.GtmDL }};</script> Kolejny skrypt należy umieścić w pliku odpowiedzialnym za koszyk <script> (function(){ var i,dl={{ page.GtmDL }}; for(i in dl) dataLayer.push(dl[i]); })(); </script> W zależności od szablonu będzie to inny plik - nazwa i lokalizacja pliku oraz miejsce wklejenia powyższego skryptu wskazane poniżej:
  • Szablon Bursztyn, Opal - order-cart-container.html
  • Szablon Agat - partials / cart / cart-template.html
  • Szablon Szafir - order / cart.html
oraz w pliku order / thx.html  
Wskazówka
Pamiętaj o zapisaniu i publikacji wszystkich zmian wykonanych w szablonie. Po przygotowaniu szablonu zgodnie z powyższymi instrukcjami możesz przejść do konfiguracji integracji Twojego sklepu z Google Tag Manager opisanej w artykule Integracja z Google Tag Manager.

3. Przydatne linki

Google Tag Manager: Pomoc Strona serwisu Dokumentacja programistyczna Google Analytics: Strona serwisu Dokumentacja programistyczna

Dodawanie kanałów do płatności online w szablonach

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Dodawanie kanałów do płatności online

Kanały w płatnościach online to inaczej sposób zapłaty. W tym artykule dowiesz się, jak je dodać w swoim szablonie.

1. Bursztyn i Opal

W pliku order/cart.html dodaj poniższy kod: {% for delivery in cart.DeliveryMethods %} {% for payment in delivery.Payments %} {% if payment.Channels[0] and payment.Id == cart.SelectedDeliveryPaymentId %}
{% for channel in payment.Channels -%} {% endfor -%}
{% endif %} {% endfor %} {% endfor %} Następnie konieczne jest również ostylowanie dodanego fragmentu, aby był spójny z resztą szablonu. Na końcu pliku scss/main2.scss dodaj poniższe style: .payment-channels{ background-color: $middleColor; display: flex; flex-wrap: wrap; margin-top: 11px; } .payment-channel{ display: inline-block; width: calc(100%/6 - 30px); min-width: 100px; height: 50px; margin: 15px; position: relative; [type=radio]{ position: absolute; opacity: 0; width: 0; height: 0; & + img{ cursor: pointer; max-width: 100px; max-height: 50px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } &:checked + img{ outline: 1px solid $primaryColor; } } }
Wskazówka
O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.
Gdy kanały są już dodane oraz dobrze wyświetlają się w szablonie, kolejny krok to włączenie ich działania. W tym celu na końcu pliku js/order.js należy wkleić poniższy kod: $('body').on('change', '.payment-channels [name=channel]', function (e) { e.preventDefault(); var id = $('.payment-channels').data('id'); var channel = $(e.currentTarget).val(); $.post(null, { __csrf: __CSRF, __action: 'Order/DeliveryChange', id: id, channel: channel }); });
Wskazówka
O tym jak zminifikować pliki js dowiesz się z artykułu o kompilacji i minifikacji plików.
Na koniec dodaj walidację, dzięki której nie będzie się dało złożyć zamówienia, jeśli żaden kanał nie został wybrany. W pliku js/order.js odnajdź funkcję oznaczoną komentarzem //next i dodaj w niej (w pierwszym warunku if ($(this).hasClass('start'))) w zależności od szablonu: Bursztyn: if($('.payment-channels').index() != -1 && $('.payment-channels [name=channel]:checked').index() == -1){ var tt = $('
'); tt.append('
'+$('.payment-channels').data('validation')+'
'); $('body').append(tt); setTimeout(function(){tt.fadeOut(function(){tt.remove();});},3000); return tt; } Opal: if($('.payment-channels').index() != -1 && $('.payment-channels [name=channel]:checked').index() == -1){ var tt; if (sessionStorage.getItem('tooltip') != null){ tt = $(".tt.err"); } else { tt = $('
'); tt.append(''+$('.payment-channels').data('validation')+''); $('body').append(tt); sessionStorage.setItem('tooltip', 'err'); } showTooltip(); return; } Ostatnim krokiem jest dodanie komunikatu, który będzie wyświetlany w przypadku niezaznaczenia żadnego kanału. W tym celu w panelu administracyjnym (Wygląd sklepu/ Ustawienia/ Tłumaczenia) dodaj tłumaczenie o kluczu ChoosePaymentChannel i treści Wybierz sposób zapłaty (lub jakiejkolwiek innej, którą uważasz za stosowną).

2. Agat:

W pliku partials/cart/cart-content.html dodaj poniższy kod: {% for deliveryMethodLvl in cart.DeliveryMethods -%} {% if deliveryMethodLvl.Name == cart.SelectedDelivery.Name %} {% for payment in deliveryMethodLvl.Payments -%} {% if payment.Channels[0] and payment.Id == cart.SelectedDeliveryPaymentId %}
{% for channel in payment.Channels -%} {% endfor -%}
{% endif %} {% endfor -%} {% endif %} {% endfor -%} Następnie konieczne jest również ostylowanie dodanego fragmentu, aby był spójny z resztą szablonu. Na końcu pliku scss/main2.scss dodaj poniższe style: .payment-channels{ background-color: $bgColor; border: 1px solid $lighterColor; box-shadow: 2px 2px 1px 0 $bgColorFont; margin: 0 auto 20px; display: inline-flex; flex-wrap: wrap; width: calc(100% - 2px); @media only screen and (min-width: 481px) { width: calc(50% - 22px); min-width: 298px; margin: 0 10px 20px } @media only screen and (min-width: 769px) { width: calc(100% - 22px); } @media only screen and (min-width: 1441px) { width: calc(75% - 22px); } } .payment-channel{ display: inline-block; width: calc(100%/6 - 30px); min-width: 100px; height: 50px; margin: 15px; position: relative; [type=radio]{ position: absolute; opacity: 0; width: 0; height: 0; & + img{ cursor: pointer; max-width: 100px; max-height: 50px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } &:checked + img{ outline: 1px solid $primaryColor; } } }
Wskazówka
O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.
Gdy kanały są już dodane oraz dobrze wyświetlają się w szablonie, kolejny krok to włączenie ich działania. W tym celu na końcu pliku js/order.js należy wkleić poniższy kod: $('body').on('change', '.payment-channels [name=channel]', function (e) { e.preventDefault(); var id = $('.payment-channels ').data('id'); var channel = $(e.currentTarget).val(); $.post(null, { __csrf: __CSRF, __action: 'Order/DeliveryChange', id: id, channel: channel }); });
Wskazówka
O tym jak zminifikować pliki js dowiesz się z artykułu o kompilacji i minifikacji plików.
Na koniec dodaj walidację, dzięki której nie będzie się dało złożyć zamówienia, jeśli żaden kanał nie został wybrany. W pliku js/order.js odnajdź funkcję orderNextStep i dodaj w niej (na początku else'a warunku if ($('#delivery-address-data').index() >= 0)) kolejny warunek do sprawdzenia: if($('.payment-channels').index() != -1 && $('.payment-channels [name=channel]:checked').index() == -1){ application.createMessage($('.payment-channels').data('validation'), 3000); return; } Ostatnim krokiem jest dodanie komunikatu, który będzie wyświetlany w przypadku niezaznaczenia żadnego kanału. W tym celu w panelu administracyjnym (Wygląd sklepu/ Ustawienia/ Tłumaczenia) dodaj tłumaczenie o kluczu ChoosePaymentChannel i treści Wybierz sposób zapłaty (lub jakiejkolwiek innej, którą uważasz za stosowną).

3. Szafir

W pliku order/delivery-partials/delivery-section.html dodaj poniższy kod: {% for indexString in matchedDeliveriesIndexesArray -%} {% assign index = indexString | ToInt -%} {% if order.SelectedDelivery.Name == order.DeliveryMethods[index].Name -%} {% for payment in order.DeliveryMethods[index].Payments -%} {% if payment.Id == order.SelectedDelivery.Payment.Id and payment.Channels[0] -%}
{% for channel in payment.Channels -%} {% endfor -%}
{% endif -%} {% endfor -%} {% endif -%} {% endfor -%} Następnie konieczne jest również ostylowanie dodanego fragmentu, aby był spójny z resztą szablonu. Na końcu pliku scss/globals/_globals2.scss dodaj poniższe style: .order-ui .payment-channels-ui{ padding: 0; margin: 0 30px 15px 0; width: calc(100% - 30px); display: flex; flex-wrap: wrap; .message-bar-ui{ width: 100%; margin: 0; } } .payment-channel-ui:not(.checkbox-ui):not(.radio-ui){ width: calc(100%/6 - 30px); min-width: 100px; height: 50px; margin: 15px; position: relative; [type=radio]{ position: absolute; opacity: 0; width: 0; height: 0; & + img{ cursor: pointer; max-width: 100px; max-height: 50px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } &:checked + img{ outline: 1px solid $primaryColor; } } } oraz w pliku scss/globals/_globals-m.scss: .order-ui .payment-channels-ui { margin-right: 0; width: 100%; }
Wskazówka
O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.
Gdy kanały są już dodane oraz dobrze wyświetlają się w szablonie, kolejny krok to włączenie ich działania. W tym celu na końcu pliku js/init-ui2.js należy wkleić poniższy kod: function choosePaymentChannel(e) { var form = $('.delivery-form-lq'); var data = form.serializeArray(); data.push({ name: '__csrf', value: __CSRF }); data.push({ name: 'channel', value: $(e.currentTarget).val() }); $.post('', data); $('.payment-channels-lq .form-error-lq').remove(); }; $('body').on('change', '.payment-channel-lq [name=channel]', function (e) { choosePaymentChannel(e); });
Wskazówka
O tym jak zminifikować pliki js dowiesz się z artykułu o kompilacji i minifikacji plików.
Na koniec dodaj walidację, dzięki której nie będzie się dało złożyć zamówienia, jeśli żaden kanał nie został wybrany. W pliku js/init-ui1.js odnajdź funkcję addOrder i dodaj w niej (zaraz pod pierwszym warunkiem if (ajaxModalSelector && this.hiddingClass)) kolejny warunek do sprawdzenia: if ($('.payment-channels-lq').index() != -1 && $('.payment-channel-lq [name=channel]:checked').index() == -1) { $('.payment-channels-lq').append('
' + __translations.ChoosePaymentMethod + '
'); guardian = false; } Ostatnim krokiem jest dodanie komunikatu, który będzie wyświetlany w przypadku niezaznaczenia żadnego kanału. W tym celu w pliku _layout.html odnajdź skrypt ze zmienną __translations i dopisz w nim kolejną linijkę: ChoosePaymentMethod: '{{ translations.ChoosePaymentMethod | H }}'. Następnie w panelu administracyjnym (Wygląd sklepu/ Ustawienia/ Tłumaczenia) dodaj tłumaczenie o kluczu ChoosePaymentMethod i treści Wybierz sposób zapłaty (lub jakiejkolwiek innej, którą uważasz za stosowną).

Obsługa towaru archiwalnego

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Obsługa towaru archiwalnego

W tym artykule dowiesz się jak obsłużyć towar archiwalny na stronie ze szczegółami towaru w swoim szablonie.

Szafir

W pliku product/product-presentation-data.html wyszukaj frazę header. Jest to element, w którym trzeba dodać warunek, aby ostatecznie wyglądało to tak: {% if product.Archival == false -%} . . . {% endif -%} Następnie wyszukaj frazę add-to-cart-container-ui. Jest to kontener, w którym na samym początku wyświetlane są punkty lojalnościowe i flagi. Trzeba je uwarunkować, żeby nie pojawiały się przy towarze archiwalnym. Zamiast nich powinna się pojawić informacja o tym, że jest to towar archiwalny. Początek tego kontenera powinien wyglądać następująco: {% if product.Archival -%}
{{ translations.ArchivalProductInfo }}
{% else -%} {% if activeProduct.Points != null and usr.Authenticated -%} {% capture quantityUnit -%}1 {{ product.SaleUnit }}{% endcapture -%}
{{ translations.EarnLoyaltyPoints | Format:quantityUnit }}: {{ activeProduct.Points }} {{ translations.PointsShortcut }}
{% endif -%}
    • {% assign flagsQuantity = product.Flags | Size -%} {% for flag in product.Flags limit: 3 -%}
    • {% if flag.Type == "Reward" -%} {{ translations.PointsProduct }}{% if usr.Authenticated and activeProduct.PointsPrice != null -%}: {{ activeProduct.PointsPrice }} {{ translations.PointsShortcut }}/{{ product.SaleUnit }}{% endif -%} {% else -%} {{ flag.Text }} {% endif -%}
{% endfor -%} {% endif -%}   Parę linijek niżej znajdują się etykiety {{ translations.ChooseProductVariant }} i {{ translations.Availability }}: {{ activeProduct.Availability.Text }}. Trzeba zmodyfikować ich warunki tak, aby nie wyświetlały się w przypadku towaru archiwalnego. Powinno to wyglądać w ten sposób: {% if tableView and product.Archival == false -%} {{ translations.ChooseProductVariant }} {% endif -%} {% if activeProduct.Availability.Text != '' and product.Archival == false -%}
{{ translations.Availability }}: {{ activeProduct.Availability.Text }}
{% endif -%} W podobny sposób należy ukryć całą resztę dotyczącą różnych danych o towarze. Aby to zrobić należy wyszukać taki warunek {% if activeProduct.StockLevel.Control and tableView == false -%} i linijkę wyżej dopisać {% if product.Archival == false -%}. Natomiast zamknięcie tego warunku trzeba będzie dopisać dużo dalej. Aby znaleźć odpowiednie miejsce należy wyszukać taką frazę CheaperInSet. Jest to etykieta przycisku przewijającego do sekcji z zestawami (o ile takowe istnieją dla danego towaru). Pod tym przyciskiem znajduje się {% endif -%}, który zamyka warunek sprawdzający właśnie istnienie owych zestawów. Pod nim trzeba dopisać jeszcze jedno {% endif -%}, aby zamknąć warunek, który dodaliśmy wyżej. Ostatecznie powinno to wyglądać tak: {% if product.Archival == false -%} {% if activeProduct.StockLevel.Control and tableView == false -%} . . . {% if product.Sets != null and product.Sets != empty -%}
{{ translations.CheaperInSet }}
{% endif -%} {% endif -%} . . . Na końcu pliku scss/globals/_globals2.scss wklej taki kod: .archival-product-info-ui{ position: absolute; top: -40px; right: 0; text-transform: uppercase; color: $primaryColor; font-style: italic; } A na końcu pliku scss/globals/_globals-m.scss wklej taki kod: .archival-product-info-ui{ right: 20px; }
Wskazówka
Zwróć uwagę, aby ten styl znajdował się wewnątrz głównej klamry, która otwiera się w pierwszej linijce pliku i zamyka w ostatniej
Wskazówka
Pamiętaj, że pliki scss należy zminifikować. O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.

Agat

W pliku product-page.html wyszukaj frazę button-container. Jest to klasa kontenera, w którym znajdują się najważniejsze dane związane z towarem. Pod tym kontenerem wklej taki kod: {% if product.Archival -%}
{{translations.ArchivalProductInfo}}
{% endif -%} Pozostając w tym samym pliku (product-page.html) wyszukaj frazę config.Reviews.Enabled. Jest to część warunku, odpowiedzialnego za dodawanie opinii o produkcie. Zmodyfikuj go tak, aby wyglądał następująco: {% if product.Archival -%} {% if config.Reviews.Enabled == true and productD.Archival == false -%} {% endif -%} W pliku partials/product/product-popup.html wyszukaj frazę usr.Authenticated. W tym pliku będą dwa wystąpienia takiej frazy. W obu to część warunku. W obu przypadkach zmodyfikuj te warunki, aby wyglądały tak: {% if usr.Authenticated and product.Archival == false -%} W tym samym pliku (partials/product/product-popup.html) wyszukaj frazę add-to-cart-popup. Jest to klasa kontenera, który trzeba zmodyfikować, aby wyglądał tak:
Dalej w tym samym pliku (partials/product/product-popup.html) wyszukaj frazę AddToCartForm. Jest to ID formularza odpowiedzialnego za dodawanie towaru do koszyka. Linijkę wyżej otwórz taki warunek: {% if product.Archival == false -%} Będzie on obejmował resztę kodu znajdującego się w tym pliku. Na końcu znajdziesz kontener z klasą ask-for-price-popup. Pod tym kontenerem zamknij wcześniej otworzony warunek dopisując linijkę niżej {% endif -%}. Na końcu pliku scss/main2.scss wklej taki kod: .archival{ padding-bottom: 20px; } .archival-info{ background: $pageNameColor; color: $primaryColor; padding: 20px; margin-bottom: 20px; text-transform: uppercase; @media only screen and (min-width: 481px) { box-shadow: 2px 2px 1px 0 $bgColorFont; } }
Wskazówka
Pamiętaj, że pliki scss należy zminifikować. O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.

Bursztyn

W pliku productdetails.html wyszukaj frazę itemprop="offers". Jest to jeden z atrybutów kontenera, na którego początku trzeba wkleić taki kod: {% if _pd.Archival -%}
{{ translations.ArchivalProductInfo }}
{% endif %} W tym samym pliku (productdetails.html) wyszukaj frazę usr.Authenticated. W tym pliku będą dwa wystąpienia takiej frazy. W obu to część warunku. W obu przypadkach zmodyfikuj te warunki, aby wyglądały tak: {% if usr.Authenticated and _pd.Archival == false -%} Dalej w tym samym pliku (productdetails.html) wyszukaj frazę class="availability". Linijkę wyżej nad elementem, który ma taką klasę dopisz {% if _pd.Archival == false %}. Będzie to początek warunku, który trzeba zakończyć trochę niżej. Aby znaleźć to miejsce wyszukaj frazę {% if customer.HidePrices %}. Jest to warunek przed, którym trzeba zakończyć ten nasz nowy, który właśnie dodaliśmy. Aby tego dokonać należy linijkę wyżej dopisać {% endif %}. Kolejną frazą w tym pliku (productdetails.html), którą trzeba wyszukać jest add-to-cart. Jest to klasa przycisku dodawania towaru do koszyka. Będą dwa wystąpienia. Interesuje nas tylko pierwsze, które dotyczy danego towaru. Drugie wystąpienie dotyczy zestawów i znajduje się w warunku {% if set.Price <> null %}. To nas nie interesuje więc zostańmy przy tym pierwszym. Linijkę wyżej dopisz {% if _pd.Archival == false %}. Pod tym przyciskiem znajdują się jeszcze dwa przyciski (powiadamiania o dostępności i pytania o cenę). Pod tym drugim należy zamknąć warunek dopisując linijkę niżej {% endif %}. Będąc przy tych przyciskach możemy zauważyć element nav z klasą options. Linijkę wyżej wklej {% if _pd.Archival == false %}, a zaraz za końcem tego elementu dopisz linijkę niżej {% endif %}. Ostatni warunek w tym pliku (productdetails.html), który trzeba zmienić znajdziesz wyszukując frazę productuserreviews.TotalItems. Trzeba ją podmienić, aby wyglądała tak: {% unless productuserreviews.TotalItems == 0 and _pd.Archival %} Plik productdetails/opinions-partial.html należy zmodyfikować tak, żeby wyglądał w ten sposób: {% if productuserreviews.TotalItems == 0 %} {% if _pd.Archival == false -%} . . . {% endif -%} {% else %} {% for o in productuserreviews.Reviews %} . . . {% endfor %} {% if _pd.Archival == false -%} {% endif -%} {% endif%} Na końcu pliku scss/main2.scss wklej: .archival-product-info{ padding: 15px 20px; border-radius: 5px 0 0 5px; box-shadow: rgba(0,0,0,.2) -2px 2px 10px; background: #F5F5F5; position: relative; right: -20px; left: -20px; width: calc(100% + 40px); margin: 10px 0 30px; font-style: italic; }
Wskazówka
Pamiętaj, że pliki scss należy zminifikować. O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.

Opal

W pliku productdetails.html wyszukaj frazę details-section. Jest to klasa kontenera, nad którym trzeba wkleić linijkę wyżej taki kod: {% if _pd.Archival -%}
{{ translations.ArchivalProductInfo }}
{% endif %} Następnie wyszukaj frazę usr.Authenticated. W tym pliku będą dwa wystąpienia takiej frazy. W obu to część warunku. W obu przypadkach zmodyfikuj te warunki, aby wyglądały tak: {% if usr.Authenticated and _pd.Archival == false -%} Kolejna fraza to class="stock". Będzie to klasa elementu, który trzeba "ubrać" w warunek {% if _pd.Archival == false %}. Będzie to początek warunku, który trzeba zakończyć linijkę pod elementem poprzez dopisanie {% endif %}. Teraz wyszukaj frazę class="attributes". Linijkę wyżej nad elementem, który ma taką klasę dopisz {% if _pd.Archival == false %}. Będzie to początek warunku, który trzeba zakończyć trochę niżej. Aby znaleźć to miejsce wyszukaj frazę {% if customer.HidePrices %}. Jest to warunek przed, którym trzeba zakończyć ten nasz nowy, który właśnie dodaliśmy. Aby tego dokonać należy linijkę wyżej dopisać {% endif %}. Następna fraza to add-to-cart. Jest to klasa przycisku dodawania towaru do koszyka. Będą dwa wystąpienia. Interesuje nas tylko pierwsze, które dotyczy danego towaru. Drugie wystąpienie dotyczy zestawów i znajduje się w warunku {% if set.Price <> null %}. To nas nie interesuje więc zostańmy przy tym pierwszym. Linijkę wyżej dopisz {% if _pd.Archival == false %}. Pod tym przyciskiem znajdują się jeszcze dwa przyciski (powiadamiania o dostępności i pytania o cenę). Pod tym drugim należy zamknąć warunek dopisując linijkę niżej {% endif %}. Będąc przy tych przyciskach możemy zauważyć element nav z klasą options. Linijkę wyżej wklej {% if _pd.Archival == false %}, a zaraz za końcem tego elementu dopisz linijkę niżej {% endif %}. Na końcu pliku scss/main2.scss wklej: .archival-product-info{ background: #f7f7f7; color: $placeholderColorFont; padding: 20px; margin-top: 20px; text-align: center; }
Wskazówka
Pamiętaj, że pliki scss należy zminifikować. O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.

Topaz

Wzależności od wybranego wariantu szczegółów towaru zmiany będą inne. Wersja z miniaturkami zdjęć po lewej W pliku elements/product/product-details-1.html wyszukaj frazę product-details__images. Zastąp kontener z tą klasą poniższym kodem:
{% for flag in product.Flags -%} {{ flag.Text }} {% endfor %}
{% if product.Images[1] -%}
    • {% for image in product.Images -%}
    • {% if image.Id != -1 -%} {{image | Img: 'compact'}} {% else -%} {{'css/img/img-placeholder.jpg' | Img, translations.DefaultImage}} {% endif -%}
{% endfor -%}
{% for image in product.Images -%}
{% if image.Id != -1 -%} {{image | Img: 'grande'}} {% else -%} {{'css/img/img-placeholder.jpg' | Img, translations.DefaultImage}} {% endif -%} {% if product.Archival -%}
{{translations.ArchivalProduct}}
{% endif -%}
{% endfor -%}
{% elseif product.Images[0] -%}
{{product.Images[0] | Img: 'grande'}} {% if product.Archival -%}
{{translations.ArchivalProduct}}
{% endif -%}
{% else -%}
{{'css/img/img-placeholder.jpg' | Img, translations.DefaultImage}} {% if product.Archival -%}
{{translations.ArchivalProduct}}
{% endif -%}
{% endif -%} {% if product.Images[0] -%} {% endif -%} {% if product.Archival == false -%}
{% if product.DeliveryCost != null and product.DeliveryCost > 0 -%} | {% endif -%} {% if stockLevel.Control -%}
{{ translations.Com_StockLvl }}:  {% unless stockLevel.Type == 2 or stockLevel.Type == 4 or stockLevel.Text == null -%} {{ stockLevel.Text }} {% endunless -%} {% if stockLevel.Type == 4 -%} {{ stockLevel.Value | Normalize }} {{ product.SaleUnit }} {% endif -%} {% if stockLevel.Type == 1 or stockLevel.Type == 2 -%} {% unless stockLevel.ImageUrl == null -%} {{stockLevel.ImageUrl | Img: '', stockLevel.Text}} {% endunless -%} {% endif -%}
| {% endif -%}
{{ translations.Com_Availability }}:  {% unless product.Availability.Text == '' or product.Availability.Type == 2 -%} {{ product.Availability.Text }} {% endunless -%} {% if product.Availability.Type == 1 or product.Availability.Type == 2 -%} {{product.Availability.ImageUrl | Img: '', product.Availability.Text}} {% endif -%} {% unless product.Availability.Date == null -%} ({{ product.Availability.Date | Date:'d' }}) {% endunless -%}
{% endif -%}
  Następnie wyszukaj frazę product-details__add-to-cart. Na początku kontenera z tą klasą wklej poniższy kod: {% if product.Archival -%}
{{translations.ArchivalProductInfo}}
{% endif -%} Kawałek niżej znajdziesz kontener z klasą product-details__reviewsContainer. Podmień go poniższym kodem: {% unless product.Archival and product.RatingCount == 0 -%}
{% include 'partials/common/product-rating.html', rating: product.Rating -%} ({{ product.RatingCount }})
{% endunless -%} Teraz wyszukiaj basic-unit-ratio. Podmień wszystko co jest pod tą linijką, aż do linijki, w której znajduje się kontener z klasą product-details__info-container (tej linijki nie podmieniaj) poniższym kodem: {% if product.Archival == false -%} {% if product.Clip or product.Batch -%}
{% for attribute in product.Supplies.AttributeNames -%} {{ attribute.Name | H }}
{% endfor -%}
{% elseif product.AttributesPolyvalent != empty -%} {% for attribute in product.AttributesPolyvalent -%}
{{ attribute.Name }}
{% for value in attribute.Values -%} {{ value.Value | H }} {% endfor -%}
{% endfor -%} {% endif -%} {% if product.Batch == null or product.Batch == false -%} {% if product.AttributesEditable != empty -%} {% assign i = 0 -%} {% for attribute in product.AttributesEditable -%}
{% assign i = i | Plus: 1 -%} {% endfor -%} {% endif -%} {% endif -%} {% if product.Units[1] -%}
{{ translations.Com_MeasureUnit }} {% for unit in product.Units -%} {% endfor -%}
{% endif -%} {% endif -%} Następnie znajdź kontener z klasą product-details__other-options i podmień go (wraz z jego zawartością) poniższym kodem: <codeclass="lang:ruby decode:true"> {% if product.Archival == false -%}
{{ translations.Com_RecommendProduct }}
{{ translations.Com_AskAboutProduct }}
{% endif -%} Teraz znajdź kontener z klasą product-details__prices. Na samym początku w tym kontenerze będzie warunek {% if customer.Authenticated == true -%}. Zmień go na {% if customer.Authenticated == true and product.Archival == false -%}. Następnie znajdź kontener z klasą product-details__button-group i podmień go (wraz z jego zawartością) na poniższy kod: {% if product.Archival == false -%}
{% if product.AskForPrice == false or customer.HidePrices == false -%} {% unless product.Availability.Status == 3 or noProductInStock == true -%}
{% if stockLevel -%} {% assign stockValue = stockLevel.Value | ToString | Split: "," -%} {% endif -%} {% if stockLevel and stockLevel.Control -%} {% assign stockValue = stockLevel.Value | ToString | Split: ',' -%} {% endif -%}
{% endunless -%} {% endif -%} {% if customer.HidePrices == true -%} {% else -%} {% endif -%}
{% else -%} {{translations.ArchivalProductCheckInfo}} {% endif -%} Teraz w pliku css/layout.css dodaj poniższy kod: .product-details .product-details__image__archival{position:absolute;bottom:0;left:0;right:0;padding:20px;font-size:18px;background:rgba(204,204,204,0.9);color:#fff;text-align:center}.product-details .product-details__archivalProductInfo{background:{{settings.$breadcrumbsBgColor}};color:{{settings.breadcrumbsFontColor}};padding:30px;margin-bottom:30px;text-align:center}.product-details .parent-category-link{color:{{settings.linkFontColor}};margin-top:50px;display:inline-block}.product-details .parent-category-link svg{fill:{{settings.linkFontColor}};height:19px;width:19px;vertical-align:middle} Wersja z miniaturkami zdjęć pod głównym zdjęciem W pliku elements/product/product-details-2.html wyszukaj frazę product-details__images. Zastąp kontener z tą klasą poniższym kodem:
{% for flag in product.Flags -%} {{ flag.Text }} {% endfor %}
{% if product.Images[1] -%}
{% for image in product.Images -%}
{% if image.Id != -1 -%} {{image | Img: 'grande'}} {% else -%} {{'css/img/img-placeholder.jpg' | Img, translations.DefaultImage}} {% endif -%} {% if product.Archival -%}
{{translations.ArchivalProduct}}
{% endif -%}
{% endfor -%}
    • {% for image in product.Images -%}
    • {% if image.Id != -1 -%} {{image | Img: 'compact'}} {% else -%} {{'css/img/img-placeholder.jpg' | Img, translations.DefaultImage}} {% endif -%}
{% endfor -%} {% elseif product.Images[0] -%}
{{product.Images[0] | Img: 'grande'}} {% if product.Archival -%}
{{translations.ArchivalProduct}}
{% endif -%}
{% else -%}
{{'css/img/img-placeholder.jpg' | Img, translations.DefaultImage}} {% if product.Archival -%}
{{translations.ArchivalProduct}}
{% endif -%}
{% endif -%} {% if product.Archival == false -%}
{{ translations.Com_RecommendProduct }}
{{ translations.Com_AskAboutProduct }}
{% endif -%} {% if product.Images[0] -%} {% endif -%}
  Następnie wyszukaj frazę product-details__add-to-cart. Na początku kontenera z tą klasą wklej poniższy kod: {% if product.Archival -%}
{{translations.ArchivalProductInfo}}
{% endif -%} Teraz wyszukiaj {% if product.Clip or product.Batch -%}. Podmień wszystko co jest pod tą linijką (łącznie z nią), aż do linijki {% include 'partials/common/after-adding-to-cart-popup.html' %} (jej nie podmieniaj) poniższym kodem: {% if product.Archival == false -%} {% if product.Clip or product.Batch -%}
{% for attribute in product.Supplies.AttributeNames -%} {{ attribute.Name | H }}
{% endfor -%}
{% elseif product.AttributesPolyvalent != empty -%} {% for attribute in product.AttributesPolyvalent -%}
{{ attribute.Name }}
{% for value in attribute.Values -%} {{ value.Value | H }} {% endfor -%}
{% endfor -%} {% endif -%} {% if product.Batch == null or product.Batch == false -%} {% if product.AttributesEditable != empty -%} {% assign i = 0 -%} {% for attribute in product.AttributesEditable -%}
{% assign i = i | Plus: 1 -%} {% endfor -%} {% endif -%} {% endif -%} {% endif -%} {% if product.Units[1] -%}
{{ translations.Com_MeasureUnit }} {% for unit in product.Units -%} {% endfor -%}
{% endif -%} {% if product.Archival == false -%}
{% if stockLevel.Control -%}
{{ translations.Com_StockLvl }}:  {% unless stockLevel.Type == 2 or stockLevel.Type == 4 or stockLevel.Text == null -%} {{ stockLevel.Text }} {% endunless -%} {% if stockLevel.Type == 4 -%} {{ stockLevel.Value | Normalize }} {{ product.SaleUnit }} {% endif -%} {% if stockLevel.Type == 1 or stockLevel.Type == 2 -%} {% unless stockLevel.ImageUrl == null -%} {{stockLevel.ImageUrl | Img: '', stockLevel.Text}} {% endunless -%} {% endif -%}
{% endif -%}
{{ translations.Com_Availability }} {% unless product.Availability.Text == '' or product.Availability.Type == 2 -%} {{ product.Availability.Text }}:  {% endunless -%} {% if product.Availability.Type == 1 or product.Availability.Type == 2 -%} {{product.Availability.ImageUrl | Img: '', product.Availability.Text}} {% endif -%} {% unless product.Availability.Date == null -%} ({{ product.Availability.Date | Date:'d' }}) {% endunless -%}
{% if product.DeliveryCost != null and product.DeliveryCost > 0 -%} {% endif -%}
{% if product.AskForPrice == false or customer.HidePrices == false -%} {% unless product.Availability.Status == 3 or noProductInStock == true -%}
{% if stockLevel -%} {% assign stockValue = stockLevel.Value | ToString | Split: "," -%} {% endif -%} {% if stockLevel and stockLevel.Control -%} {% assign stockValue = stockLevel.Value | ToString | Split: ',' -%} {% endif -%}
{% endunless -%} {% endif -%}
{% if customer.HidePrices == true -%} {% else -%} {% endif -%} {% if customer.Authenticated == true -%} {% endif -%}
{% else -%} {{translations.ArchivalProductCheckInfo}} {% endif -%}   Teraz w pliku css/layout.css dodaj poniższy kod: .product-details .product-details__image__archival{position:absolute;bottom:0;left:0;right:0;padding:20px;font-size:18px;background:rgba(204,204,204,0.9);color:#fff;text-align:center}.product-details .product-details__archivalProductInfo{background:{{settings.$breadcrumbsBgColor}};color:{{settings.breadcrumbsFontColor}};padding:30px;margin-bottom:30px;text-align:center}.product-details .parent-category-link{color:{{settings.linkFontColor}};margin-top:50px;display:inline-block}.product-details .parent-category-link svg{fill:{{settings.linkFontColor}};height:19px;width:19px;vertical-align:middle}

Obsługa funkcji autocomplete w wyszukiwarce szablonu

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Obsługa funkcji autocomplete w wyszukiwarce szablonu

W tym artykule dowiesz się jak zaimplementować funkcję autocomplete w swoim szablonie. Funkcja ta wyświetli klientowi listę towarów, które będą najlepiej pasowały do wpisanej przez niego frazy w wyszukiwarce.

Szafir

W pliku common/header/header.html wyszukaj frazę quick-search-form-lq. Zmodyfikuj element, do którego należy ta klasa, aby wyglądał tak:
Na końcu pliku js/init-ui2.js wklej ten kod:
<class="lang:ruby decode:true">function autocomplete(e) { var phrase = $(e.currentTarget).val().replace(/[!@#$%^&*()+={}\[\]:;"'<,>.?\~`\\|]*/gi, ''); if (phrase != '' && phrase.length > 1) { $.get(location.pathname, { __action: 'Get/SearchAutocomplete', search: phrase }).then(function (res) { if($(window).width() > 1280){ var right = 'right: 50px'; } else if($(window).width() > 680){ var right = ''; } else { var right = 'right: 61px'; } var loader = ''; $('.quick-search-form-lq.autocomplete-form-lq').append(loader); var url = res.action.Redirect302; $.get(url, {__csrf:__CSRF, __collection:'products.Products|page.BaseHref|currency|config.Products.ShowCode'}, function(res) { $('.autocomplete-lq').remove(); var list = res.collection['products.Products']; var showCode = res.collection['config.Products.ShowCode']; if (list.length > 0){ if (list.length > 5) { var size = 5; } else { var size = list.length; } var baseHref = res.collection['page.BaseHref']; var currency = res.collection['currency']; var autocompleteList = '
 
'; var regPhrase = '(' + phrase.split(' ').join('|') + ')'; var reg = new RegExp(regPhrase, 'gi'); for (i = 0; i < size; i++) { var nameNoQuotes = list[i].Name.replace(/"/g, '"'); var name = list[i].Name.replace(reg, function(str) {return ''+str+''}); if(showCode){ var code = list[i].Code.replace(reg, function(str) {return ''+str+''}); } else { var code = ''; } if(list[i].Price){ var price = list[i].Price.toPrice() + ' ' + currency; } else { var price = ''; } if(list[i].ImageId != -1){ var img = ''; } else { var img = ''; } var product = ' ' + '
' + img + '
' + '
' + '
' + name + '
' + '
' + code + '
' + '
' + '
' + price + '
' + ''; autocompleteList += product; } autocompleteList += '
'; $('.quick-search-form-lq.autocomplete-form-lq').append(autocompleteList); } $('.loader-for-autocomplete-lq').remove(); }); }); } else { $('.autocomplete-lq').remove(); $('.loader-for-autocomplete-lq').remove(); } }; $('body').on('input', '.quick-search-form-lq.autocomplete-form-lq [name="search"]', function (e) { if(timeOutAutocomplete!=null){ clearTimeout(timeOutAutocomplete); timeOutAutocomplete=null; } timeOutAutocomplete = setTimeout(function(){ autocomplete(e); }, 300); }); //variable to clearTimeout in autocomplete function var timeOutAutocomplete = null; $('body').on('blur', '.quick-search-form-lq.autocomplete-form-lq [name="search"]', function () { setTimeout(function () { $('.autocomplete-lq').remove(); $('.loader-for-autocomplete-lq').remove(); },200); });
Na końcu pliku scss/globals/_header.scss wklej ten kod: .autocomplete-ui{ position: absolute; z-index: 1000; width: 100%; box-shadow: 0px 8px 10px 0px rgba(0, 0, 0, 0.2); @media only screen and (max-width: 1280px) { max-width: 550px; left: 50%; transform: translateX(calc(-50% - 25px)); text-align: left; } @media only screen and (max-width: 680px) { left: auto; transform: none; } .product-ui{ display: block; padding: 10px; background: $bgColor; border: 1px solid $lightBorderColor; border-bottom: none; font-size: 16px; color: $primaryColorFont; transition: all ease 300ms; &:last-child{ border-bottom: 1px solid $lightBorderColor; } > div{ display: inline-block; vertical-align: top; margin-right: 10px; &:last-child{ width: 100px; margin-right: 0; text-align: right; } } .img-ui{ width: 50px; height: 50px; position: relative; } img{ max-width: 100%; max-height: 100%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .names-ui{ width: calc(100% - 50px - 100px - 20px); } .name-ui{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: $primaryColor; transition: all ease 300ms; } .code-ui{ font-size: 12px; color: $bgColorFont; transition: all ease 300ms; } &:hover{ background: $btnSolidHoverBgColor; color: $btnSolidHoverTextColor; .name-ui, .code-ui{ color: $btnSolidHoverTextColor; } } } }
Wskazówka
Pamiętaj, że pliki scss i js należy zminifikować. O tym jak skompilować i zminifikować pliki scss i js dowiesz się z artykułu o kompilacji i minifikacji plików.

Agat

W pliku partials/common/header.html wyszukaj frazę id="search-form". Zmodyfikuj element, do którego należy to ID, aby wyglądał tak: W pliku js/init.js wyszukaj frazę events:. Linijkę wyżej wklej kod:
<class="lang:ruby decode:true ">autocomplete: function(e){ var phrase = $(e.currentTarget).val().replace(/[!@#$%^&*()+={}\[\]:;"'<,>.?\~`\\|]*/gi, ''); if (phrase != '' && phrase.length > 1) { $.get(location.pathname, { __action: 'Get/SearchAutocomplete', search: phrase }).then(function (result) { if (result.action.Result) { var loader = ''; $('#search-form').append(loader); var url = result.action.Redirect302; $.get(url, {__csrf:__CSRF, __collection:'products.Products|page.BaseHref|currency'}, function(res) { $('.autocomplete').remove(); var list = res.collection['products.Products']; if (list.length > 0){ if (list.length > 5) { var size = 5; } else { var size = list.length; } var baseHref = res.collection['page.BaseHref']; var currency = res.collection['currency']; var autocompleteList = '
 
'; var regPhrase = '(' + phrase.split(' ').join('|') + ')'; var reg = new RegExp(regPhrase, 'gi'); for (i = 0; i < size; i++) { var nameNoQuotes = list[i].Name.replace(/"/g, '"'); var name = list[i].Name.replace(reg, function(str) {return ''+str+''}); if(list[i].Price){ var price = list[i].Price.toPrice() + ' ' + currency; } else { var price = ''; } if(list[i].ImageId != -1){ var img = '' } else { var img = ''; } var product = '' + '
' + img + '
' + '
' + '
' + name + '
' + '
' + price + '
' + '
' + ''; autocompleteList += product; } autocompleteList += '
'; $('#search-form').append(autocompleteList); } $('.loader-for-autocomplete').remove(); }); } else if (result.action.Code != 100) { application.createMessage(result.action); } }); } else { $('.autocomplete').remove(); $('.loader-for-autocomplete').remove(); } },
Natomiast pod koniec pliku tuż pod takim kodem: $('body').on('blur', 'input', function () { application.uiCheckLabels(); }); Wklej taki kod: $('body').on('input', '#header-section #search-form.autocomplete-form [name="search"]', function (e) { if(timeOutAutocomplete!=null){ clearTimeout(timeOutAutocomplete); timeOutAutocomplete=null; } timeOutAutocomplete = setTimeout(function(){ self.autocomplete(e); }, 300); });
//variable to clearTimeout in autocomplete function var timeOutAutocomplete = null;$('body').on('blur', '#header-section #search-form.autocomplete-form [name="search"]', function () { setTimeout(function () { $('.autocomplete').remove(); $('.loader-for-autocomplete').remove(); }, 200); });
Na końcu pliku scss/main2.scss wklej kod: .autocomplete{ position: absolute; z-index: 101; width: 100%; @media only screen and (max-width: 1024px) { width: calc(100% - 240px); } @media only screen and (max-width: 768px) { width: calc(100% - 20px); } box-shadow: 0px 8px 10px 0px rgba(0, 0, 0, 0.2); .product{ display: block; padding: 10px; background: $bgColor; border: 1px solid $primaryColor; border-bottom: none; font-size: 16px; color: $bgDarkerColorFont; &:last-child{ border-bottom: 1px solid $primaryColor; } > div{ display: inline-block; vertical-align: top; margin-right: 10px; &:last-child{ margin-right: 0; } } .img{ width: 50px; height: 50px; position: relative; } img{ max-width: 100%; max-height: 100%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .names{ width: calc(100% - 50px - 10px); } .name{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .price{ margin-top: 5px; font-size: 12px; color: $primaryColor; opacity: 0.63; } } }
Wskazówka
Pamiętaj, że pliki scss i js należy zminifikować. O tym jak skompilować i zminifikować pliki scss i js dowiesz się z artykułu o kompilacji i minifikacji plików.

Bursztyn

W pliku page/header.html wyszukaj frazę SearchForm. Zmodyfikuj element, do którego należy to ID, aby wyglądał tak: Na końcu pliku js/init2.js wklej ten kod:
<class="lang:ruby decode:true ">$('header').on('input', '#SearchForm.autocomplete-form [name="search"]', function (e) { if(timeOutAutocomplete!=null){ clearTimeout(timeOutAutocomplete); timeOutAutocomplete=null; } timeOutAutocomplete = setTimeout(function(){ var phrase = $(e.currentTarget).val().replace(/[!@#$%^&*()+={}\[\]:;"'<,>.?\~`\\|]*/gi, ''); if (phrase != '' && phrase.length > 1) { $.get(location.pathname, { __action: 'Get/SearchAutocomplete', search: phrase }).then(function (d) { var a = d.action; if (!a.Result) CreateTooltip(a); else if (a.Redirect302){ var loader = ''; $('#SearchForm').append(loader); var url = a.Redirect302; $.get(url, {__csrf:__CSRF, __collection:'productlist.Products|page.BaseHref|currency'}, function(res) { $('.autocomplete').remove(); var list = res.collection['productlist.Products']; if (list.length > 0){ if (list.length > 5) { var size = 5; } else { var size = list.length; } var baseHref = res.collection['page.BaseHref']; var currency = res.collection['currency']; var autocompleteList = '
 
'; var regPhrase = '(' + phrase.split(' ').join('|') + ')'; var reg = new RegExp(regPhrase, 'gi'); for (i = 0; i < size; i++) { var nameNoQuotes = list[i].Name.replace(/"/g, '"'); var name = list[i].Name.replace(reg, function(str) {return ''+str+''}); if(list[i].Price){ var price = list[i].Price.toPrice() + ' ' + currency; } else { var price = ''; } if(list[i].ImageId != -1){ var img = '' } else { var img = ''; } var product = ' ' + '
' + img + '
' + '
' + '
' + name + '
' + '
' + price + '
' + '
' + ''; autocompleteList += product; } autocompleteList += '
'; $('#SearchForm').append(autocompleteList); } $('.loader-for-autocomplete').remove(); }); } }); } else { $('.autocomplete').remove(); $('.loader-for-autocomplete').remove(); } }, 300); }); //variable to clearTimeout in autocomplete function var timeOutAutocomplete = null; $('header').on('blur', '#SearchForm.autocomplete-form [name="search"]', function () { setTimeout(function () { $('.autocomplete').remove(); $('.loader-for-autocomplete').remove(); }, 200); });
Na końcu pliku scss/main2.scss wklej ten kod:
<class="lang:ruby decode:true ">.autocomplete{ position: absolute; top: 43px; left: 0; z-index: 101; width: 100%; box-shadow: 0px 8px 10px 0px rgba(0, 0, 0, 0.2); .product{ display: block; padding: 10px; background: $bgColor; border: 1px solid $primaryColor; border-bottom: none; font-size: 14px; color: $secondaryColorFont; transition: all ease 300ms; &:last-child{ border-bottom: 1px solid $primaryColor; } > div{ display: inline-block; vertical-align: top; margin-right: 10px; &:last-child{ margin-right: 0; } } .img{ width: 50px; height: 50px; position: relative; } img{ max-width: 100%; max-height: 100%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .names{ width: calc(100% - 50px - 10px); } .name{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .price{ margin-top: 5px; font-size: 12px; color: $primaryColor; opacity: 0.63; transition: all ease 300ms; } &:hover{ background: $primaryColor; color: $primaryColorFont; .price{ color: $primaryColorFont; opacity: 1; } } } }
Wskazówka
Pamiętaj, że pliki scss i js należy zminifikować. O tym jak skompilować i zminifikować pliki scss i js dowiesz się z artykułu o kompilacji i minifikacji plików.

Opal

W pliku page/header.html wyszukaj frazę SearchForm. Zmodyfikuj element, do którego należy to ID, aby wyglądał tak: Na końcu pliku js/init2.js wklej ten kod:
<class="lang:ruby decode:true ">$('header').on('input', '#SearchForm.autocomplete-form [name="search"]', function (e) { if(timeOutAutocomplete!=null){ clearTimeout(timeOutAutocomplete); timeOutAutocomplete=null; } timeOutAutocomplete = setTimeout(function(){ var phrase = $(e.currentTarget).val().replace(/[!@#$%^&*()+={}\[\]:;"'<,>.?\~`\\|]*/gi, ''); if (phrase != '' && phrase.length > 1) { $.get(location.pathname, { __action: 'Get/SearchAutocomplete', search: phrase }).then(function (d) { var a = d.action; if (!a.Result) CreateTooltip(a); else if (a.Redirect302){ var loader = ''; $('#SearchForm').append(loader); var url = a.Redirect302; $.get(url, {__csrf:__CSRF, __collection:'productlist.Products|page.BaseHref|currency|config.Products.ShowCode'}, function(res) { $('.autocomplete').remove(); var list = res.collection['productlist.Products']; var showCode = res.collection['config.Products.ShowCode']; if (list.length > 0){ if (list.length > 5) { var size = 5; } else { var size = list.length; } var baseHref = res.collection['page.BaseHref']; var currency = res.collection['currency']; var input = $('#SearchForm').find('[name=search]'); var width = input.width(); var top = input.offset().top + input.height() - 16; var autocompleteList = '
 
'; var regPhrase = '(' + phrase.split(' ').join('|') + ')'; var reg = new RegExp(regPhrase, 'gi'); for (i = 0; i < size; i++) { var nameNoQuotes = list[i].Name.replace(/"/g, '"'); var name = list[i].Name.replace(reg, function(str) {return ''+str+''}); if(showCode){ var code = list[i].Code.replace(reg, function(str) {return ''+str+''}); } else { var code = ''; } if(list[i].Price){ var price = list[i].Price.toPrice() + ' ' + currency; } else { var price = ''; } if(list[i].ImageId != -1){ var img = '' } else { var img = ''; } var product = ' ' + '
' + img + '
' + '
' + '
' + name + '
' + '
' + code + '
' + '
' + '
' + price + '
' + ''; autocompleteList += product; } autocompleteList += '
'; $('#SearchForm').parent().append(autocompleteList); } $('.loader-for-autocomplete').remove(); }); } }); } else { $('.autocomplete').remove(); $('.loader-for-autocomplete').remove(); } }, 300); }); //variable to clearTimeout in autocomplete function var timeOutAutocomplete = null; $('header').on('blur', '#SearchForm.autocomplete-form [name="search"]', function () { setTimeout(function () { $('.autocomplete').remove(); $('.loader-for-autocomplete').remove(); }, 200); });
Na końcu pliku scss/main2.scss wklej ten kod:
<class="lang:ruby decode:true ">.autocomplete{ position: absolute; left: calc(50% - 20px); transform: translateX(-50%); z-index: 1000; box-shadow: 0px 8px 10px 0px rgba(0, 0, 0, 0.2); .product{ display: block; padding: 10px; background: $bgColor; border: 1px solid $primaryColor; border-bottom: none; font-size: 16px; color: $secondaryColorFont; transition: all 300ms ease; &:last-child{ border-bottom: 1px solid $primaryColor; } > div{ display: inline-block; vertical-align: top; margin-right: 10px; &:last-child{ width: 100px; margin-right: 0; text-align: right; } } .img{ width: 50px; height: 50px; position: relative; } img{ max-width: 100%; max-height: 100%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .names{ width: calc(100% - 50px - 100px - 20px); } .name{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .code{ font-size: 12px; opacity: 0.63; } &:hover{ background: $primaryColor; color: $primaryColorFont; } } }
Wskazówka
Pamiętaj, że pliki scss i js należy zminifikować. O tym jak skompilować i zminifikować pliki scss i js dowiesz się z artykułu o kompilacji i minifikacji plików.

Obsługa szczegółów zamówienia dla klienta niezalogowanego

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Obsługa szczegółów zamówienia dla klienta niezalogowanego

W tym artykule dowiesz się jak zmodyfikować szablon, aby klienci niezalogowani mogli w profilu klienta zobaczyć szczegóły zamówienia do którego posiadają link.

Szafir

W pliku customer-profile.html w pierwszym warunku dopisz and customer-profile.Order == null tak żeby warunek wyglądał w ten sposób: {% if customer.Authenticated == false and config.DefinedPages.CustomerProfile.Id == page.PageId and customer-profile.Order == null -%} W pliku customer-profile/orders/order-details.html wyszukaj frazę {{ page.Url }}?{{ pageQueryName }}. Będzie to część atrybutu przypisanego do przycisku powrotu do listy zamówień. Ten przycisk trzeba uwarunkować, aby zamiast niego pojawiał się link prowadzący do strony głównej sklepu. Ostatecznie powinno to wyglądać tak jak poniższy kod: {% if customer.Authenticated -%} {% else -%} {{ translations.BackToShopping }} {% endif -%} Pozostając dalej w tym samym pliku (customer-profile/orders/order-details.html) wyszukaj frazę Order/Cancel. Jest to nazwa jednej z interesujących nas akcji. Kawałek dalej znajdują się pozostałe dwie (Order/Accept i Order/RestorePayment). Pod każdą z nich wklej: Nadal w tym samym pliku (customer-profile/orders/order-details.html) wyszukaj frazę copy-to-cart-lq. Jest to klasa przycisku odpowiedzialnego za kopiowanie zamówienia do koszyka. Trzeba w nim dodać atrybut data-hash="{{ order.Hash }}" tak, aby ostatecznie przycisk wyglądał następująco: Następnie w pliku js/init-ui2.js znajdź funkcję copyToCart i zmodyfikuj jej początek, aby wyglądała tak: var id = $(e.currentTarget).data('id'); var hash = $(e.currentTarget).data('hash'); var data = { orderId: id, hash: hash, __csrf: __CSRF, __action: 'Order/Copy' };
Wskazówka
Pamiętaj, że pliki js należy zminifikować. O tym jak skompilować i zminifikować pliki js dowiesz się z artykułu o kompilacji i minifikacji plików.

Bursztyn lub Opal

W pliku customerprofile.html podmień warunek, aby wyglądał tak: {% if customer.Authenticated and page.PageId == config.DefinedPages.CustomerProfile.Id %}
{% include 'customer/profile.html' %}
{% elseif customer.Authenticated == false and page.PageId == config.DefinedPages.CustomerProfile.Id and customerprofile.Order != null %}
{% include 'customer/profile.html' %}
{% else %}
{% include 'customer/login.html' %}
{% endif %} W pliku customer/profile-orders.html wyszukaj frazę Order/RestorePayment. Jest to nazwa jednej z interesujących nas akcji. Kawałek dalej znajdują się pozostałe dwie (Order/Cancel i Order/Accept). Pod każdą z nich wklej: Nadal w tym samym pliku (customer/profile-orders.html) wyszukaj frazę copy-to-cart. Jest to klasa przycisku odpowiedzialnego za kopiowanie zamówienia do koszyka. Trzeba go zmodyfikować tak, aby wyglądał następująco: Następnie w pliku js/profile.js znajdź funkcję copyToCart i zmodyfikuj jej początek, aby wyglądała tak: var id = $(e.currentTarget).data('id'); var hash = $(e.currentTarget).data('hash'); var newLocation = $(e.currentTarget).data('url'); var added = $(e.currentTarget).data('added'); var copy = $(e.currentTarget).data('copy'); var notCopied = $(e.currentTarget).data('not-copied'); var data = [ { name: '__action', value: 'Order/Copy' }, { name: 'orderId', value: id }, { name: 'hash', value: hash }, { name: '__csrf', value: __CSRF } ];
Wskazówka
Pamiętaj, że pliki js należy zminifikować. O tym jak skompilować i zminifikować pliki js dowiesz się z artykułu o kompilacji i minifikacji plików.

Agat

W pliku customer-profile.html podmień warunek, aby wyglądał tak: {% if page.PageId == config.DefinedPages.CustomerProfile.Id and customer-profile.Order != null %} {% include 'partials/customer/order-details.html' -%} {% elseif customer.Authenticated and page.PageId == config.DefinedPages.CustomerProfile.Id %} W pliku partials/customer/order-details.html wyszukaj frazę Order/Accept. Jest to nazwa jednej z interesujących nas akcji. Kawałek dalej znajdują się pozostałe dwie (Order/RestorePayment i Order/Cancel). Pod każdą z nich wklej: Będąc przy akcji Order/Cancel dodaj warunek do inputa z templatką tak, aby wyglądał następująco: {% if customer.Authenticated == false and page.PageId == config.DefinedPages.CustomerProfile.Id and customer-profile.Order != null -%} {% else -%} {% endif -%} Nadal będąc przy tej akcji (Order/Cancel) zmodyfikuj przycisk odpowiadający za anulowanie zamówienia tak, aby wyglądał jak tu: Pozostając w tym samym pliku (partials/customer/order-details.html) wyszukaj frazę copy-to-cart. Jest to klasa przycisku odpowiedzialnego za kopiowanie zamówienia do koszyka. Trzeba w nim dodać atrybut data-hash="{{ order.Hash }}" tak, aby ostatecznie przycisk wyglądał następująco: Następnie w pliku js/init2.js znajdź funkcję copyToCart i zmodyfikuj jej początek, aby wyglądała tak: var copyButton = $(e.currentTarget); var copySection = copyButton.parents('.copy-section'); var id = copyButton.data('id'); var hash = copyButton.data('hash'); var data = [ { name: '__action', value: 'Order/Copy' }, { name: 'orderId', value: id }, { name: 'hash', value: hash }, { name: '__csrf', value: __CSRF } ]; W pliku js/init.js znajdź funkcję cancelOrder i podmień w niej posta, żeby wyglądał tak: $.post(url, data, function (result) { if (result.action.Result) { if($(e.currentTarget).hasClass('not-authenticated')){ application.createMessage(message); $('#main-section').html(result.template); application.loadImages(); } else { window.templateChanged['under-execution'] = true; application.createMessage(message); if (parent.index() != -1) { $('.under-execution').eq(1).replaceWith(result.template); } application.uiPreventScrolling(); } } else if (result.action.Code != 100) { application.createMessage(result.action); } }); W pliku partials/customer/order-details-products.html do kontenera z klasą cart-items dodaj warunek, tak aby ostatecznie kontener wyglądał następująco:
Na końcu pliku scss/main2.scss dodaj taki kod: @media only screen and (min-width: 481px) { .cart-items.not-authenticated .cart-item { width: calc(50% - 40px); display: inline-block; } } @media only screen and (min-width: 769px) { .cart-items.not-authenticated .cart-item { width: calc(50% - 25px); } } @media only screen and (min-width: 1025px) { .cart-items.not-authenticated { width: 66%; } } Na końcu pliku scss/mobile2.scss dodaj taki kod: .cart-items.not-authenticated{ text-align: center; margin: 20px auto; }
Wskazówka
Pamiętaj, że pliki js i scss należy zminifikować. O tym jak skompilować i zminifikować pliki js i scss dowiesz się z artykułu o kompilacji i minifikacji plików.

Obsługa funkcji przypomnienia o wystawieniu opinii za zakupiony towar

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Obsługa funkcji przypomnienia o wystawieniu opinii za zakupiony towar

W wersji sklepu oznaczonej numerkiem 2019.5 w Panelu Administracyjnym doszła funkcja przypomnienia o wystawieniu opinii za zakupiony towar. Ta funkcja będzie wysyłać maila z owym przypomnieniem. W tym mailu będzie również link do szczegółów danego towaru. W tym artykule dowiesz się jak zmodyfikować swój szablon, aby po kliknięciu w ten link otworzyła się strona ze szczegółami danego towaru, a w niej był już otwarty i gotowy do uzupełnienia formularz wystawienia opinii.

Agat

W pliku js/init.js znajdź funkcję addReview i w niej zaraz pod zmienną validate dodaj taki kod: if(window.location.hash.includes('#rate')){ var hash = window.location.hash.split('&')[1].split('=')[1]; data.push({ name: 'orderHash', value: hash }); } A następnie w pliku js/init2.js na samym końcu dodaj taki kod: function autoOpenReviewsForm(){ $('.new-review-label').trigger('click'); $('html, body').animate({ scrollTop: $('.new-review-label').offset().top - 81 }, 500); } $(document).ready(function () { if(window.location.hash.includes('#rate')){ autoOpenReviewsForm(); } });
Wskazówka
Z tego artykułu dowiesz się jak zminifikować swoje pliki js

Bursztyn

W pliku js/init.js wyszukaj frazę #opinion-form .primary-action. Będzie to trigger funkcji do wystawiania opinii. W tej funkcji pod zmienną data dodaj taki kod: if(window.location.hash.includes('#rate')){ var hash = window.location.hash.split('&')[1].split('=')[1]; data.push({ name: 'orderHash', value: hash }); } A następnie w pliku js/details.js na samym końcu dodaj taki kod: $(document).ready(function () { if(window.location.hash.includes('#rate')){ $('#add-first-review').trigger('click'); } });
Wskazówka
Z tego artykułu dowiesz się jak zminifikować swoje pliki js

Opal

W pliku js/init.js wyszukaj frazę #opinion-form .primary-action. Będzie to trigger funkcji do wystawiania opinii. W tej funkcji pod zmienną data dodaj taki kod: if(window.location.hash.includes('#rate')){ var hash = window.location.hash.split('&')[1].split('=')[1]; data.push({ name: 'orderHash', value: hash }); } A następnie w pliku js/details.js na samym końcu dodaj taki kod: $(document).ready(function () { if(window.location.hash.includes('#rate')){ $('#main-rating > .glyphicon').trigger('click'); } });
Wskazówka
Z tego artykułu dowiesz się jak zminifikować swoje pliki js

Obsługa załączników do zamówienia

Obsługa załączników do zamówienia

W tym artykule dowiesz się jak zmodyfikować swój szablon, aby było możliwe dodanie załączników do składanego zamówienia.
Wskazówka
W tym artykule trzeba będzie wprowadzać zmiany w plikach js oraz scss. Z tego artykułu dowiesz się jak je kompilować i minifikować.

Szafir

Na potrzeby tej funkcji zdecydowaliśmy się na drobne zmiany w wyglądzie elementów związanych z dodawaniem notatki do zamówienia. Poniższe fragmenty kodu uwzględniają owe zmiany. Na początku dodaj w swoim szablonie nowe frazy w zakładce Tłumaczenia: AddAttachement - Dodaj załącznik AddMessage - Dodaj wiadomość YourMessage - Twoja wiadomość AttachementsNotAdded - Nie dodano wszystkich załączników Attachements - Załączniki W pliku _layout.html w elemencie head znajduje się skrypt, który dodaje do zmiennej __translations różne tłumaczenia. Dodaj tam taką linijkę: AttachementsNotAdded: "{{ translations.AttachementsNotAdded | H }}", Jeśli miałeś w swoim szablonie funkcję do importowania koszyka z pliku to w pliku common/navigation-bars/main-navigation-bar-partial.html wyszukaj frazę id="file", a następnie w tym inpucie, w którym występuje to ID dodaj klasę import-cart-input-lq. Następnie w pliku js/init.js wyszukaj frazę [name="file"] i zamień ją na .import-cart-input-lq. W pliku order/cart.html wyszukaj frazę note-lq. Jest to klasa kontenera, w którym znajdują się wszystkie elementy związane z dodawaniem notatki do zamówienia. Wytnij cały ten kontener czyli taki kod: {% if usr.Authenticated -%}
{% if order.Note == '' -%} {% include 'order/note-partials/note-form.html' -%} {% else -%} {% include 'order/note-partials/note-presentation.html' -%} {% endif -%}
{% endif -%}
i wklej go pod taką linijką: {% include 'common/order-summary.html' -%} Następnie trzeba w całości podmienić zawartość plików order/note-partials/note-form.html oraz order/note-partials/note-presentation.html. Poniżej właściwa zawartość obu plików: order/note-partials/note-form.html {% assign isExpanded = include -%}
{% if config.Orders.AttachmentsEnabled -%}
{% endif -%} {% if isExpanded == true or isExpanded == 'true' -%} {% else -%} {% endif -%} {% if config.Orders.AttachmentsEnabled -%}
{% endif -%}
{% if config.Orders.AttachmentsEnabled -%}
{% include 'order/attachements.html' -%}
{% endif -%} order/note-partials/note-presentation.html {% if config.Orders.AttachmentsEnabled -%}
{% endif -%} {% if config.Orders.AttachmentsEnabled -%}
{% endif -%}
{{order.Note}}
{% if config.Orders.AttachmentsEnabled -%}
{% include 'order/attachements.html' -%}
{% endif -%}
Kolejnym krokiem będzie dodanie nowego pliku HTML o nazwie attachements. Należy go dodać do folderu order. Poniżej zawartość tego pliku: order/attachements.html {% for file in order.Attachments -%} {% assign type = file.Name | Split: '.' | Last -%} {% if type == "jfif" or type == "jpe" or type == "jpeg" or type == "jpg" -%} {% assign icon = 'ti-image' -%} {% elseif type == "csv" or type == "txt" -%} {% assign icon = 'ti-receipt' -%} {% elseif type == "docx" or type == "odt" -%} {% assign icon = 'ti-write' -%} {% elseif type == "xlsx" or type == "ods" -%} {% assign icon = 'ti-bar-chart' -%} {% elseif type == "pdf" -%} {% assign icon = 'ti-agenda' -%} {% else -%} {% assign icon = 'ti-file' -%} {% endif -%}
{{ file.Name }}
{% endfor -%}
Następnie w pliku customer-profile/orders/order-details.html wyszukaj frazę {% if order.Note != "" -%}. W tym warunku znajdują się dodane notatki do zamówienia. Pod tym warunkiem wklej poniższy kod: {% if config.Orders.AttachmentsEnabled -%}
{% for file in order.Attachments -%} {% assign type = file.Name | Split: '.' | Last -%} {% if type == "jfif" or type == "jpe" or type == "jpeg" or type == "jpg" -%} {% assign icon = 'ti-image' -%} {% elseif type == "csv" or type == "txt" -%} {% assign icon = 'ti-receipt' -%} {% elseif type == "docx" or type == "odt" -%} {% assign icon = 'ti-write' -%} {% elseif type == "xlsx" or type == "ods" -%} {% assign icon = 'ti-bar-chart' -%} {% elseif type == "pdf" -%} {% assign icon = 'ti-agenda' -%} {% else -%} {% assign icon = 'ti-file' -%} {% endif -%} {% endfor -%}
{% endif -%}
Na samym końcu pliku js/init-ui2.js dodaj poniższy kod: function processFilesList(fileInput, fileList) { var file = fileList.pop(); if (file) { var fd = new FormData(); fd.append('__CSRF',__CSRF); fd.append('__action','Order/AttachmentAdd'); fd.append('__template','order/attachements.html'); fd.append('file', file); $.ajax({data: fd, processData: false, contentType: false, type: 'POST', success: function(data){ fileInput.val(''); if(data.action.Result){ $('.attachements-lq').html(data.template); } else { if(window.AttachementsNotAdded == undefined){ window.AttachementsNotAdded = []; } var attachement = ' '+file.name+': '+data.action.Message+' '; window.AttachementsNotAdded.push(attachement); } processFilesList(fileInput, fileList); } }); } else { $('.during-ajax-modal-lq').addClass('hidden-lq'); fileInput.removeClass('prevent-double-change-lq'); if(window.AttachementsNotAdded){ var popup = ' '+ ' '+ ' '+ __translations.AttachementsNotAdded+ ''+ ' '+ window.AttachementsNotAdded.join('')+ ' '+ ' '; $('body').append(popup); $('body').addClass('modal-opened-ui'); window.AttachementsNotAdded = undefined; } } }; function addAttachementInOrder(e) { $('.during-ajax-modal-lq').removeClass('hidden-lq'); var fileInput = $(e.currentTarget); fileInput.addClass('prevent-double-change-lq'); var fileList = Object.values(e.currentTarget.files); processFilesList(fileInput, fileList); }; $('body').on('change', '.add-attachement-in-order-lq:not(.prevent-double-change-lq)', function (e) { addAttachementInOrder(e); }); function removeAttachementInOrder(e) { $.post('', {__csrf: __CSRF, __action: 'Order/AttachmentDelete', id: $(e.currentTarget).data('id')}, function(result) { $(e.currentTarget).parents('.file-container-lq').remove(); }); }; $('body').on('click', '.remove-attachement-in-order-lq', function (e) { removeAttachementInOrder(e); }); W pliku scss/globals/_globals-m.scss wyszukaj frazę &.confirm-in-cart-ui. Zmień tam top: 93px na top: 70px. Usuń też right: 20px. W pliku scss/globals/_globals2.scss wyszukaj frazę .add-note-in-cart-ui. Dopisz do niej po spacji w tej samej linijce .ti-notepad a następnie usuń margin-top: -10px i dodaj font-size: 20px. W pliku scss/globals/partials/_order.scss wyszukaj frazę .note-ui. Nadpisz wszystkie style znajdujące się w tej klasie poniższym kodem: margin-top: 20px; border-top: 1px solid $lightBorderColor; border-bottom: 1px solid $lightBorderColor; padding: 15px; .half-ui{ padding: 10px; float: left; &:first-child{ border-right: 1px solid $lightBorderColor; } } button { padding: 0; line-height: 1; } .note-in-order-ui{ margin-top: 20px; position: relative; .edit-ui{ margin-left: 15px; vertical-align: baseline; } } .label-note-in-cart-ui{ color: $labelsColor; cursor: default; } .form-to-confirm-in-cart-ui{ resize: none; } .confirm-in-cart-ui{ top: -20px; } .file-container-ui{ background: $bgColor; border: 1px solid $lightBorderColor; border-radius: 20px; margin: 0 10px 10px 0; padding: 5px 15px 10px; display: inline-block; &:first-child{ margin-top: 20px; } .icon-ui{ font-size: 20px; vertical-align: middle; } .remove-attachement-in-order-ui{ vertical-align: middle; margin-left: 10px; cursor: pointer !important; } }

Dodawanie wyboru działu na formularzu kontaktowym

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.
Ta instrukcja przeznaczona jest dla standardowych szablonów Comarch starszych niż wersja 2019.6. Jeśli posiadasz w sklepie kilka adresów do kontaktu, możesz umożliwić swoim klientom wybór jednego z nich na formularzu kontaktowym. Aby to zrobić, skorzystaj z poniższych instrukcji. Poszczególne pliki, które należy zmodyfikować znajdują się w Panelu administracyjnym w sekcji: Wygląd sklepu/ Ustawienia/ Więcej/ Edytuj ustawienia zaawansowane następnie Więcej/ Edytuj HTML.
Wskazówka
Pamiętaj, aby wprowadzone zmiany w szablonie Zapisać i Opublikować.

1. Bursztyn i Opal

1.1. W pliku contact.html odnajdź element z id "ContactSendForm" i powyżej pola e-mail dodaj poniższy kod: {% if config.Contact.Contacts[0] -%} <select name="contactId" class="department" required> {% for contact in config.Contact.Contacts -%} <option value="{{ contact.Id }}">{{ contact.Name }}</option> {% endfor -%} </select> {% endif -%} 1.2. Aby wygląd nowego pola był spójny z resztą formularza, w pliku scss/contact.scss odnajdź selektor ".contact-info .contact-form input, .contact-info .contact-form textarea" i zamień go na: .contact-info .contact-form input, .contact-info .contact-form textarea, .contact-info .contact-form select 1.3. Skompiluj i zminifikuj pliki scss.
Wskazówka
O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.
1.4. Aby walidacja działała poprawnie, w pliku js/init.js, odnajdź funkcję resetForm(form) i podmień ją na: function resetForm(form) { var inputs = form.find('input:not([disabled]):not([type=hidden]), select:not([disabled]):not(".department"), textarea:not([disabled])'); inputs.each(function () { $(this).val(''); }); $('.loader-icon').remove(); $('.send-contact-form').removeClass('posting'); } 1.5. Zminifikuj pliki js.
Wskazówka
O tym jak zminifikować pliki js dowiesz się z artykułu o kompilacji i minifikacji plików.
 

2. Agat

2.1. W pliku contact.html odnajdź element z id "contact-form" i powyżej pola e-mail dodaj poniższy kod: {% if config.Contact.Contacts[0] -%} <div class="input-group"> <span class="required-fields-info">{{ translations.Department }} *</span> <select name="contactId" required> {% for contact in config.Contact.Contacts -%} <option value="{{ contact.Id }}">{{ contact.Name }}</option> {% endfor -%} </select> </div> {% endif -%} 2.2. Aby wygląd nowego pola był spójny z resztą formularza, w pliku scss/mobile1.scss odnajdź selektor "input, textarea" i zamień go na: input, textarea, .contact-form-popup select 2.3. Skompiluj i zminifikuj pliki scss.
Wskazówka
O tym jak skompilować i zminifikować pliki scss dowiesz się z artykułu o kompilacji i minifikacji plików.
2.4. Dodaj tłumaczenie dla frazy Department [Dział] Tłumaczenie należy dodać w Panelu administracyjnym: Wygląd sklepu/ Ustawienia na zakładce Tłumaczenia.

3. Szafir

3.1. W pliku common/navigation-bars/navigation-contact.html odnajdź element z klasą "form-lq form-ui" i wewnątrz niego dodaj poniższy kod: {% if config.Contact.Contacts[0] -%} <div> <label>{{ translations.Department }}<span class='required-ui'>*</span></label> <span class="select-background-ui w100-ui"> <select name="contactId" required> {% for contact in config.Contact.Contacts -%} <option value="{{ contact.Id }}">{{ contact.Name }}</option> {% endfor -%} </select> </span> <i class="ti-angle-down select-arrow-ui"></i> </div> {% endif -%} 3.2. Dodaj tłumaczenie dla frazy Department [Dział] Tłumaczenie należy dodać w Panelu administracyjnym: Wygląd sklepu/ Ustawienia na zakładce Tłumaczenia. 3.3. Aby walidacja działała poprawnie, w pliku js/init-ui2.js, odnajdź funkcję sendContactForm(e) i podmień ją na: function sendContactForm(e) { if(app.validationBeforePost(e) != 'error'){ $('.during-ajax-modal-lq').removeClass('hidden-lq'); var form = $(e.currentTarget).parents('.form-lq'); var inputs = form.find('input, textarea, select'); var data = inputs.serializeArray(); data.push({name: "__csrf", value: __CSRF}); $.post('', data, function(result) { $('.during-ajax-modal-lq').addClass('hidden-lq'); if (result.action.Result) { var message = form.data('success'); app.temporaryMessage(form, message); $.each(inputs, function (index, value) { if ($(value).attr('name') !== 'contactId' && $(value).attr('name') !== '__action') { $(value).val(''); } }); form.find('.message-lq').remove(); } else { var message = '<p>' + result.action.Message + '</p>'; if(result.action.Code != 100){ app.message(form, message); } } }); $(e.currentTarget).removeClass('error-lq'); } else { $(e.currentTarget).addClass('error-lq'); } } 3.4. Zminifikuj pliki js.
Wskazówka
O tym jak zminifikować pliki js dowiesz się z artykułu o kompilacji i minifikacji plików.

Obsługa cross-sellingu po złożeniu zamówienia

Obsługa cross-sellingu po złożeniu zamówienia

W tym artykule dowiesz się jak zmodyfikować swój szablon, aby po złożeniu zamówienia wyświetliła się sekcja z Cross-Sellingiem.
Wskazówka
W tym artykule trzeba będzie wprowadzać zmiany w plikach js oraz scss. Z tego artykułu dowiesz się jak je kompilować i minifikować.

Szafir

W pliku order/thx.html wyszukaj frazę date-format.html. Pod linijką z tą frazą będzie się znajdował warunek, który trzeba zastąpić poniższym kodem: {% if order.SelectedDelivery.Payment.MethodType == 2 and order.PlacedOrder.ExternalPayment.Success == false -%} {% assign externalPaymentError = true -%} {% endif -%} {% if externalPaymentError or crossSellingSize > 0 -%} Dalej w tym samym pliku (order/thx.html) wyszukaj frazę lastpagescripts.html. Nad linijką z tą frazą będzie się znajdowało zamknięcie warunku, które trzeba zastąpić poniższym kodem: {% elseif crossSellingSize > 0 -%}{{ translations.CrossSellingInfo }} {% for product in cross-selling.Products -%} {{ product | Img:'compact' }} {{ product | Img:'large' }} {{ product.Name }} {% unless customer.HidePrices -%} {% if product.Price == null or product.AskForPrice -%} {{ translations.AskForPrice }} {% else -%} product.Price -%} class="price-container-ui" {% endif -%}> {{ product.Price | ToPrice }} {{ currency }} {% if customer.Cart.SubtotalPrices -%} {{ translations.Netto | Downcase }} {% else -%} {{ translations.Brutto | Downcase }} {% endif -%} {% if product.PreviousPrice > product.Price -%} {{ product.PreviousPrice | ToPrice }} {{ currency }} {% if customer.Cart.SubtotalPrices -%} {{ translations.Netto | Downcase }} {% else -%} {{ translations.Brutto | Downcase }} {% endif -%} {% endif -%} {% endif -%} {% endunless -%}{% endfor -%} Następnie w pliku js/init-ui1.js wyszukaj frazę 1019. Będzie to linijka z warunkiem dotyczącym kodu błędu. Pod tym warunkiem wklej poniższy kod: if ($('.crossselling-slider-in-cart-lq').length) { window.UIFeatures.initSlider('.crossselling-slider-in-cart-lq', { dots: true, slidesToShow: 3, slidesToScroll: 3, arrows: false, infinite: false, responsive: [{ breakpoint: 1279, settings: { slidesToShow: 1.7, slidesToScroll: 1, arrows: false, infinite: false, dots: false } }] }); $('.crossselling-slider-in-cart-lq img').each(function () { var src = $(this).data('src'); $(this).attr('src', src); }) } Na samym końcu pliku js/init-ui2.js wklej poniższy kod: $(document).ready(function () { if ($('.crossselling-slider-in-cart-lq').length) { UIFeatures.initSlider('.crossselling-slider-in-cart-lq', { dots: true, slidesToShow: 3, slidesToScroll: 3, arrows: false, infinite: false, responsive: [{ breakpoint: 1279, settings: { slidesToShow: 1.7, slidesToScroll: 1, arrows: false, infinite: false, dots: false } }] }); $('.crossselling-slider-in-cart-lq img').each(function () { var src = $(this).data('src'); $(this).attr('src', src); }) } }); Na końcu pliku scss/globals/_globals2.scss wklej poniższy kod: .cross-selling-ui{ padding: 40px 0; .minibox-product-container-ui{ padding: 10px; } .minibox-product-ui{ margin: 0; height: 300px; width: 100%; } }

Topaz

W Panelu Administratora przejdź do zakładki Tłumaczenia (Wygląd sklepu -> Ustawienia -> Tłumaczenia) i dodaj tam frazę CrossSellingInfo - Inni kupili również. Następnie przejdź do zakładki Obiekty (Wygląd sklepu -> Ustawienia -> Trzykropek w prawym górnym rogu -> Edytuj ustawienia zaawansowane -> Obiekty) i dodaj tam nowy obiekt typu Nowości i Promocje o nazwie cross-selling. Po jego dodaniu wejdź w jego ustawienia i wybierz Typ Cross-Selling. Następnie pozostając w tych ustawieniach przejdź na zakładkę Strony i zaznacz tam check-box Zamówienie. Zapisz to wszystko kliknięciem w dyskietkę w prawym górnym rogu. W pliku partials/product-item.html wyszukaj frazę config.Products.ShowCode, a następnie usuń warunek (wraz z jego zawartością), którego częścią jest ta fraza. Następnie w pliku staticElements/cart/cart.html wyszukaj frazę cart--step-five. Zastąp kontener z tą klasą (wraz z jego zawartością) poniższym kodem:
<class="cart cart--step-five {% if crossSellingSize ><p> 0 -%} with-crossselling {% endif -%}"> <class="cart--step-five-content-container">{{translations.Thx}}, {{ translations.Crt_Order }} nr {{ cart.PlacedOrder.Id }} {{translations.Crt_BeenPlaced}}{{ translations.Crt_DetailsOnMail }} {% if cart.NotDeterminedDeliveryCost or cart.SelectedDelivery.NotDeterminedDeliveryCost %} {{ translations.Crt_NotDeterminedDeliveryCostInfo }}. {% endif -%} {{ translations.Crt_CheckSPAM }}{{ translations.Crt_BackToShop }} {% if cart.SelectedDelivery.Payment.MethodType == 2 and cart.PlacedOrder.ExternalPayment.Success == false -%} <class="cart cart--unfinished-payment">

{{ translations.Crt_RestoreTitle }}

{{ translations.Crt_RestoreText }}

<class="shoppingCart__form--restore inputs-container-js"> {{ translations.IPay }} {{ translations.Crt_BackToShop }} {% endif -%} {% if crossSellingSize > 0 -%} <class="cart--step-five-crossselling-container"> {{ translations.CrossSellingInfo }} <class="cart--step-five-crossselling-container"> {% include 'partials/product-item.html' with product -%} <class="cart--step-five-crossselling-container">{% assign products = cross-selling.Products | Randomize -%} {% for product in products -%} {% unless product.Url == null and product.Url == '' -%} {% endunless -%} {% endfor -%}{% endif -%}
Teraz w pliku js/layout1.js (lub layout0.js jeśli nie ma layout1.js, lub layout.js jeśli nie ma dwóch poprzednich) wyszukaj zmienną var cartFunctions. W niej należy znaleźć funkcję init (zaraz na samym początku) i dodać na jej końcu linijkę this.initializeCrossSellingSlider();. Następnie trzeba wyszukać linijkę z frazą $('.activeCart').removeClass('activeCart'); (będzie w funkcji placeOrder) i pod nią dodać cartFunctions.initializeCrossSellingSlider();. Teraz trzeba dodać poniższy kod pod funkcją placeOrder: initializeCrossSellingSlider: function () { $('.crossselling-slider').slick({ infinite: false, slidesToShow: 3, slidesToScroll: 1, responsive: [ { breakpoint: 1441, settings: { slidesToShow: 2 } }, { breakpoint: 769, settings: { slidesToShow: 1 } } ] }); }, Następnie w pliku css/layout.css dodaj poniższy kod: .cart--step-five.with-crossselling{display:block}.cart--step-five a{display:block;width:calc(100% - 50px);max-width:387px;margin-bottom:35px}.crossselling-slider{padding:0}.crossselling-slider .slick-track{margin:0 -20px}.crossselling-slider .slick-prev,.crossselling-slider .slick-next{background:{{settings.sliderBgColor}}}.crossselling-slider .slick-prev:before,.crossselling-slider .slick-next:before{border:solid {{settings.sliderArrowColor}};border-width:0 1px 1px 0;display:inline-block;padding:3px;width:4px;height:4px;top:14px;content:" "}.crossselling-slider .slick-prev:hover,.crossselling-slider .slick-next:hover{background:{{settings.sliderHoverBgColor}}}.crossselling-slider .slick-prev:hover:before,.crossselling-slider .slick-next:hover:before{border-color:{{settings.sliderHoverArrowColor}}}.crossselling-slider .slick-prev{left:-40px}.crossselling-slider .slick-prev:before{left:16px;transform:rotate(135deg);-webkit-transform:rotate(135deg)}.crossselling-slider .slick-next{right:-40px}.crossselling-slider .slick-next:before{left:14px;transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.crossselling-slider button.slick-prev.slick-arrow.slick-disabled,.crossselling-slider button.slick-arrow.slick-disabled{display:none !important} Teraz w pliku css/layout-m.css dodaj poniższy kod: .cart--step-five-crossselling-container{margin-top:60px}.crossselling-slider .slick-prev{left:0}.crossselling-slider .slick-next{right:0} Następnie w pliku css/layout-d.css dodaj poniższy kod: .cart.with-crossselling{display:block}.cart--step-five.with-crossselling .cart--step-five-content-container{width:30%;margin-right:9%;display:inline-block;vertical-align:top}.cart--step-five-crossselling-container{display:inline-block;width:60%;vertical-align:top}

Obsługa dodawania załączników do reklamacji i zwrotów

Obsługa dodawania załączników do reklamacji i zwrotów

W tym artykule dowiesz się jak zmodyfikować swój szablon, aby przy składaniu reklamacji i zwrotów było możliwe dołączenie załączników.
Wskazówka
Na podstawie tego artykułu trzeba będzie wprowadzać zmiany w plikach js oraz scss. Pamiętaj, że te pliki należy zminifikować. O tym jak skompilować i zminifikować pliki js oraz scss dowiesz się z artykułu o kompilacji i minifikacji plików.

Szafir

W pliku product/cart-product.html wyszukaj frazę note-ui. Nad linijką z tą frazą wklej poniższy kod:
{% if config.Complaints.AttachmentsEnabled -%}
<div>
<label class="add-attachement-label-ui" for="file"><i class="ti-clip"></i> {{ translations.AddAttachement }}</label> {% capture maxSize -%}{{config.Complaints.AttachmentMaxSize}}B{% endcapture -%} {% for i in (1..config.Complaints.AttachmentsMaxCount) -%}
<div class="input-file-container-ui"><input class="add-attachement-in-complaint-ui add-attachement-in-complaint-lq" accept="{{ config.Complaints.AttachmentExtensions }}" name="file" type="file" data-file-size="{{ config.Complaints.AttachmentMaxSize }}" data-size-exceeded="{{ translations.Com_FileSizeExceeded | Format: maxSize }}" data-invalid-file="{{ translations.Com_InvalidFile | Format: config.Complaints.AttachmentExtensions }}" /> <i class="ti-close clear-file-input-ui clear-file-input-lq hidden-lq"></i></div>
{% endfor -%}
</div>
{% endif -%}
  Następnie w pliku customer-profile/complaints/complaints.html wyszukaj frazę complaint.Response. Będzie to linijka z warunkiem. Pod tym warunkiem wklej poniższy kod:
{% assign complaintsSize = customer-profile.Complaint.Attachments | Size -%}
{% if config.Complaints.AttachmentsEnabled and complaintsSize &gt; 0 -%}</code>
<div class="attachements-ui remarks-ui">

{% for file in customer-profile.Complaint.Attachments -%} {% assign type = file.Name | Split: '.' | Last -%} {% if type == "jfif" or type == "jpe" or type == "jpeg" or type == "jpg" -%} {% assign icon = 'ti-image' -%} {% elseif type == "csv" or type == "txt" -%} {% assign icon = 'ti-receipt' -%} {% elseif type == "docx" or type == "odt" -%} {% assign icon = 'ti-write' -%} {% elseif type == "xlsx" or type == "ods" -%} {% assign icon = 'ti-bar-chart' -%} {% elseif type == "pdf" -%} {% assign icon = 'ti-agenda' -%} {% else -%} {% assign icon = 'ti-file' -%} {% endif -%}
<div class="file-container-ui file-container-lq"><a href="{{ file.Url }}"><i class="{{ icon }} icon-ui"></i> <span class="line-height-1-ui va-mid-ui">{{ file.Name }}</span></a></div>
{% endfor -%}

</div>
{% endif -%}
  Teraz w pliku js/init-ui2.js wyszukaj frazę sendComplaintSuccess(e). Będzie to funkcja, którą należy usunąć. Usuń również jej wywołanie, które jest tuż pod nią. Na samym końcu tego pliku (js/init-ui2.js) wklej poniższy kod:
function addAttachementInComplaint(e) {
window.attachementsInComplaint = [];
var filesArr = $(e.currentTarget).parents('.form-lq').find('.add-attachement-in-complaint-lq');
filesArr.each(function () {
if(this.files.length &gt; 0){
var maxSize = $(this).data('file-size');
if(this.files[0].size &gt; maxSize){
var message = $(this).data('size-exceeded');
var popup = '</code>
<div class="message-popup-background-ui errors-lq cancel-lq container-to-delete-lq" style="overflow: auto;">

'+ '
<div class="message-popup-ui box-ui after-adding-to-cart-popup-ui message-popup-on-background-lq" style="position: absolute; top: 0; transform: none; margin: 10% auto;">

'+ '
<div class="box-ui product-added-to-cart-ui" style="position: relative; padding: 20px;">'+ __translations.AttachementsNotAdded+ '<i class="ti-close cancel-lq" style="position: absolute; right: 20px; top: 20px; cursor: pointer;"></i>'+ '</div>
'+ '
<div style="padding: 20px;"><strong>'+this.files[0].name+'</strong>: '+message+'</div>
'+ '

</div>
'+ '

</div>
'; $('body').append(popup); $('body').addClass('modal-opened-ui'); $(this).val(''); } else { window.attachementsInComplaint.push(this.files[0]); $(this).next().removeClass('hidden-lq'); } } }); }; $('body').on('change', '.add-attachement-in-complaint-lq', function (e) { addAttachementInComplaint(e); }); function sendComplaint(e) { if(app.validationBeforePost(e) != 'error'){ var form = $(e.currentTarget).parents('.form-lq'); var dataFromHTML = form.find('input:not([disabled]), select:not([disabled]), textarea:not([disabled])').serializeArray(); var fileList = window.attachementsInComplaint; if(fileList != undefined){ var filesSize = fileList.length; } var fd = new FormData(); fd.append('__csrf', __CSRF); for(var i=0; i&lt;dataFromHTML.length; i++){ fd.append(dataFromHTML[i].name,dataFromHTML[i].value); } if (filesSize &gt; 0) { window.AttachementsErrors = 0; function addAttachementError(file, message) { if(window.AttachementsNotAdded == undefined){ window.AttachementsNotAdded = []; } var attachement = '
<div style="padding: 20px;"><strong>'+file.name+'</strong>: '+message+'</div>
'; window.AttachementsNotAdded.push(attachement); window.AttachementsErrors += 1; }; var input = form.find('[name=file]').eq(0); var extensions = input.attr('accept').split(', '); var fileSize = input.data('file-size'); for (var i=0; i&lt;filesSize; i++) { var file = fileList.pop(); if(file.size &lt; fileSize){ var extensionArr = file.name.split('.'); var extension = '.' + extensionArr[extensionArr.length - 1].toLowerCase(); var wrongExtension = true; for(var j=0; j&lt;extensions.length; j++){ if(extension == extensions[j]){ fd.append('file'+i, file); var wrongExtension = false; } } if(wrongExtension){ var message = input.data('invalid-file'); addAttachementError(file, message); } } else { var message = input.data('size-exceeded'); addAttachementError(file, message); } } if(window.AttachementsNotAdded){ var popup = '
<div class="message-popup-background-ui errors-lq cancel-lq container-to-delete-lq" style="overflow: auto;">

'+ '
<div class="message-popup-ui box-ui after-adding-to-cart-popup-ui message-popup-on-background-lq" style="position: absolute; top: 0; transform: none; margin: 10% auto;">

'+ '
<div class="box-ui product-added-to-cart-ui" style="position: relative; padding: 20px;">'+ __translations.AttachementsNotAdded+ '<i class="ti-close cancel-lq" style="position: absolute; right: 20px; top: 20px; cursor: pointer;"></i>'+ '</div>
'+ window.AttachementsNotAdded.join('')+ '

</div>
'+ '

</div>
'; $('body').append(popup); $('body').addClass('modal-opened-ui'); window.AttachementsNotAdded = undefined; window.AttachementsErrors = undefined; } } $.ajax({ data: fd, processData: false, contentType: false, type: 'POST', success: function (data) { $('.add-attachement-in-complaint-lq').val(''); if (data.action.Result) { form.parents('.add-complaint-form-lq').find('.success-message-lq').removeClass('hidden-lq'); form.addClass('hidden-lq'); } else { app.serverMessage(data, form, e); } } }); } }; $('body').on('click', '.send-complaint-lq', function(e) { sendComplaint(e); }); $('body').on('click', '.clear-file-input-lq', function(e) { var index = $(e.currentTarget).parent().index(); $(e.currentTarget).prev().val(''); window.attachementsInComplaint.splice(index - 1, 1); $(e.currentTarget).addClass('hidden-lq'); });
  W plikach scss/globals/_globals2.scss i scss/globals/_globals-m.scss znajdź linijkę z frazą .select-background-ui, input[type="date"]{ i zamień ją na .select-background-ui, input[type="date"], input[type="file"]{.

Topaz

W Panelu Administratora przejdź do zakładki Tłumaczenia (Wygląd sklepu/ Ustawienia/ Tłumaczenia) i dodaj tam trzy frazy:
  • ReportDetails – Szczegóły zgłoszenia,
  • ReportSuccessInfo – Na adres e-mail zostało wysłane potwierdzenie. Oczekuj kolejnych wiadomości e-mail o zmianie statusu zgłoszenia.,
  • AttachementsNotAdded – Nie dodano wszystkich załączników.
W pliku partials/customer/order-content.html wyszukaj frazę popupDialog__complain. Kontener z wyszukaną klasą podmień (wraz z zawartością) poniższym kodem:
<div class="popupDialog popupDialog__complain popupDialog-js">
<div class="popupDialog__wrapper">

<span class="popupDialog__title">{{ translations.SendComplaintOrReturn }}</span>
<div class="complain__product">

<figure><img class="productImage-js" alt="" /></figure>

</div>

<div class="form complain__form inputs-container-js" data-success-info="{{ translations.ReportSuccessInfo }}">

<div class="form__checkBox checkBoxes__container checkBoxes__container--radio radioContainer-js">

<div class="radioComplaint-js"><input id="radio-complaint" class="checkbox-input" name="__action" type="radio" value="Order/ComplaintAdd" data-name="complaint" /> <label for="radio-complaint"> {{ translations.Prf_OrderComplaint }} </label></div>

<div class="radioReturn-js"><input id="radio-return" class="checkbox-input" name="__action" type="radio" value="Order/ReturnAdd" data-name="return" /> <label for="radio-return"> {{ translations.Prf_OrderReturn }} </label></div>


</div>
<strong>{{ translations.ReportDetails }}</strong>
<div class="form__input-wrapper complaintInputWrapper-js">

{% if config.Complaints.Defects &lt;&gt; null -%} {% assign defectsSize = config.Complaints.Defects | Size -%}<select class="form__input-value form__input-value-js" name="defectId" required="">{% if defectsSize &gt; 1 -%}
<option value="-1">{% if defectsSize &gt; 1 -%}* {% endif -%} {{translations.ChooseComplaintCause}}</option>{% endif -%} {% for def in config.Complaints.Defects -%}
<option value="{{def.Id}}">{{def.Name}}</option>{% endfor -%}
</select>

{% endif -%}
<p class="form__invalid-input form__validation-required-js" style="display: none;">{{ translations.Com_FieldIsMandatory }}</p>


</div>

<div class="form__input-wrapper complaintInputWrapper-js"><input id="defectDate" class="form__input-value form__icon_padding form__input-value-js" max="{{config.Now | Date: 'yyyy-MM-dd'}}" min="{{order.Date | Date: 'yyyy-MM-dd'}}" name="defectDate" type="date" value="{{config.Now | Date: 'yyyy-MM-dd'}}" placeholder="yyyy-MM-dd" /> <label class="form__input-info" for="defectDate">* {{translations.Prf_DefectDate}}</label></div>

<div class="form__input-wrapper complaintInputWrapper-js">

{% if config.Complaints.Requests &lt;&gt; null -%} {% assign requestsSize = config.Complaints.Requests | Size -%}<select class="form__input-value form__input-value-js" name="requestId" required="">{% if requestsSize &gt; 1 -%}
<option value="-1">{% if requestsSize &gt; 1 -%}* {% endif %} {{translations.Prf_ComplainRequest}}</option>{% endif %} {% for req in config.Complaints.Requests -%}
<option value="{{req.Id}}">{{req.Name}}</option>{% endfor -%}
</select>

{% endif -%}
<p class="form__invalid-input form__validation-required-js" style="display: none;">{{ translations.Com_FieldIsMandatory }}</p>


</div>
{% assign returnTypes = config.Complaints.Returns | Size -%} {% if returnTypes &gt; 1 -%}
<div class="form__input-wrapper returnInputWrapper-js">

<select class="form__input-value form__input-value-js" name="returnId" required="">
<option value="-1">{% if returnTypes &gt; 1 -%}* {% endif %} {{translations.ChooseReturn}}</option>{% for return in config.Complaints.Returns -%}
<option value="{{return.Id}}">{{return.Name}}</option>{% endfor -%}
</select>
<p class="form__invalid-input form__validation-required-js" style="display: none;">{{ translations.Com_FieldIsMandatory }}</p>


</div>
{% endif %}
<div class="form__input-wrapper min-js"><label class="quantityField__label">{{translations.Com_Quantity}}</label> <button class="button-minus-add-product" type="button" data-field="quantity"> </button> <input class="quantity-field quantity__field-js" max="" min="1" name="quantity" type="number" value="1" data-decimal="false" /> <button class="button-plus-add-product" type="button" data-field="quantity"> </button></div>

<div class="form__input-wrapper"><input id="accountNumber" class="form__input-value form__input-value-js" maxlength="50" name="accountNumber" type="text" /> <label class="form__input-info form__input-info-js" for="accountNumber">{{translations.Crt_BankAccountNumber}}</label></div>

<div class="form__input-wrapper">{{translations.Prf_AdditionalInfo}} <textarea class="form__input-value" name="message"></textarea></div>

<div class="form__input-wrapper"><span class="form__requiredFields--info">* {{ translations.Com_RequiredFields }}</span></div>
{% if config.Complaints.AttachmentsEnabled -%}
<div class="form__input-wrapper attachementsInputWrapper" data-not-added-info="{{translations.AttachementsNotAdded}}">

<div class="form__attachementsLabel">{{ translations.AddAttachment }}</div>
{% capture maxSize -%}{{config.Complaints.AttachmentMaxSize}}B{% endcapture -%} {% for i in (1..config.Complaints.AttachmentsMaxCount) -%}
<div class="form__attachement-input-container"><input class="addAttachementInComplaint-js" accept="{{ config.Complaints.AttachmentExtensions }}" name="file" type="file" data-file-size="{{ config.Complaints.AttachmentMaxSize }}" data-size-exceeded="{{ translations.Com_FileSizeExceeded | Format: maxSize }}" data-invalid-file="{{ translations.Com_InvalidFile | Format: config.Complaints.AttachmentExtensions }}" /></div>
{% endfor -%}

</div>
{% endif -%} <input class="productId-js" name="no" type="hidden" value="" /> <input name="orderId" type="hidden" value="{{order.Id}}" /> <button class="primary-action-button orderComplaintOrReturnAdd-js" type="button" data-id="{{order.Id}}">{{translations.Report}}</button>
</div>
</div>
</div>
  Teraz w pliku js/layout1.js (lub layout0.js jeśli nie ma layout1.js, lub layout.js jeśli nie ma dwóch poprzednich) znajdź zmienną var customerProfile, a w niej funkcję events. Tuż przed nią dodaj poniższy kod:
addAttachementInComplaint: function(e) {
window.attachementsInComplaint = [];
var filesArr = $(e.currentTarget).parents('.inputs-container-js').find('.addAttachementInComplaint-js');
filesArr.each(function () {
if(this.files.length &gt; 0){
var maxSize = $(this).data('file-size');
if(this.files[0].size &gt; maxSize){
var message = $('[data-not-added-info]').data('not-added-info') + '. </code></code><strong>' + this.files[0].name + '</strong><code class="lang:ruby decode:true ">: ' + $(this).data('size-exceeded');
app.showTemporaryPopup(message, 'error', '', 8000);
$(this).val('');
$(this).next().hide();
} else {
window.attachementsInComplaint.push(this.files[0]);
$(this).next().show();
}
}
});
},
sendComplaint: function(e) {
if(app.validationBeforePost(e) != 'error'){
var form = $(e.currentTarget).parents('.inputs-container-js');
var dataFromHTML = form.find('input:not([disabled]), select:not([disabled]), textarea:not([disabled])').serializeArray();
var fileList = window.attachementsInComplaint;
if(fileList != undefined){
var filesSize = fileList.length;
}
var fd = new FormData();
fd.append('__csrf', __CSRF);
for(var i=0; i&lt;dataFromHTML.length; i++){ fd.append(dataFromHTML[i].name,dataFromHTML[i].value); } if (filesSize &gt; 0) {
window.AttachementsErrors = 0;
function addAttachementError(file, message) {
if(window.AttachementsNotAdded == undefined){
window.AttachementsNotAdded = [];
}
var attachement = '</code>
<div style="padding: 20px;"><strong>'+file.name+'</strong>: '+message+'</div>
'; window.AttachementsNotAdded.push(attachement); window.AttachementsErrors += 1; }; var input = form.find('[name=file]').eq(0); var extensions = input.attr('accept').split(', '); var fileSize = input.data('file-size'); for (var i=0; i&lt;filesSize; i++) { var file = fileList.pop(); if(file.size &lt; fileSize){ var extensionArr = file.name.split('.'); var extension = '.' + extensionArr[extensionArr.length - 1].toLowerCase(); var wrongExtension = true; for(var j=0; j&lt;extensions.length; j++){ if(extension == extensions[j]){ fd.append('file'+i, file); var wrongExtension = false; } } if(wrongExtension){ var message = input.data('invalid-file'); addAttachementError(file, message); } } else { var message = input.data('size-exceeded'); addAttachementError(file, message); } } if(window.AttachementsNotAdded){ var message = $('[data-not-added-info]').data('not-added-info') + window.AttachementsNotAdded.join(''); app.showTemporaryPopup(message, 'error', '', 8000); window.AttachementsNotAdded = undefined; window.AttachementsErrors = undefined; } } $.ajax({ data: fd, processData: false, contentType: false, type: 'POST', success: function (data) { $('.addAttachementInComplaint-js').val(''); if (data.action.Result) { var message = form.data('success-info'); app.showTemporaryPopup(message, 'success', '', 8000); $('.clearFileInput-js').hide(); app.hidePopup(e); sessionStorage.removeItem('complains'); sessionStorage.removeItem('order' + (e.currentTarget).dataset.id); $('.order' + (e.currentTarget).dataset.id).remove(); customerProfile.showOrderDetails(e); } else { app.showTemporaryPopup(result.action.Description, 'error', '', 8000); } } }); } },
  Następnie w funkcji events dodaj poniższy kod:
mainSection.on('change', '.addAttachementInComplaint-js', function (e) {
customerProfile.addAttachementInComplaint(e);
});
mainSection.on('click', '.orderComplaintOrReturnAdd-js', function(e) {
customerProfile.sendComplaint(e);
});
mainSection.on('click', '.clearFileInput-js', function(e) {
var index = $(e.currentTarget).parent().index();
$(e.currentTarget).prev().val('');
window.attachementsInComplaint.splice(index - 1, 1);
$(e.currentTarget).hide();
});
Teraz wyszukaj funkcję orderComplaintOrReturnAdd i usuń ją. Następnie wyszukaj wywołanie tej funkcji (w funkcji events) i również usuń. Następnie w pliku css/layout.css dodaj poniższy kod:
.customer .popupDialog__complain .popupDialog__wrapper{max-width:700px;padding-bottom:0}.customer .complain__product{width:40%;padding:0;margin:40px 0;vertical-align:top;display:inline-block;border:none}.customer .complain__product figure{width:100%;height:auto;margin:0 0 20px}.customer .complain__form{width:calc(60% - 84px);display:inline-block;margin:40px}.customer .complain__form>strong{display:block;margin-bottom:20px}.customer .complain__form textarea{margin-top:10px;padding:10px}.customer .customer__orderContent .checkBoxes__container--radio{margin-top:0}.customer .form__attachement-input-container{position:relative}.customer .form__clear-attachement-input{position:absolute;top:11px;cursor:pointer}
Teraz w pliku css/layout-m.css dodaj poniższy kod:
.customer .complain__product{width:100%;margin:20px 0}.customer .complain__form{width:100%;margin:20px 0}
 

Obsługa dostawy o typie negocjowalnym w szablonach

Wskazówka
Od 1 czerwca 2025 roku zakończyliśmy aktualizację oraz wydawanie nowych wersji szablonów Bursztyn, Agat i Opal, a tym samym ich wsparcie, aby skupić się na nowoczesnych rozwiązaniach, które jeszcze lepiej odpowiadają na potrzeby dynamicznie rozwijającego się rynku e-commerce. Zachęcamy Was do przejścia na nasze nowe, udoskonalone szablony. Dla sklepów B2C polecamy szablony Topaz, One Page Shop oraz Dla Gastronomii, natomiast dla platform B2B idealnym wyborem będą Rubin i Szafir.

Obsługa dostawy o typie negocjowalnym w szablonach

W tym artykule dowiesz się jak zmodyfikować swój szablon, aby obsłużyć dostawy o typie negocjowalnym.

Szafir

Na samym początku pliku common/order-summary.html jest warunek z kilkoma assignami. W warunku dodaj taką linijkę {% assign notDeterminedDeliveryCost = order.Delivery.NotDeterminedDeliveryCost -%}, a w elsie dodaj taką {% assign notDeterminedDeliveryCost = order.SelectedDelivery.NotDeterminedDeliveryCost -%}. Kawałek niżej znajduje się warunek {% if order.NotDeterminedDeliveryCost and order.OrderStep != 'Start' -%}. Zamień go na poniższy kod: {% if order.NotDeterminedDeliveryCost or order.SelectedDelivery.NotDeterminedDeliveryCost -%} {% assign notDeterminedDeliveryCost = true -%} {% endif -%} {% if notDeterminedDeliveryCost and order.OrderStep == 'Start' -%} Następnie w tym samym pliku wyszukaj frazę {% unless order.NotDeterminedDeliveryCost -%} i zamień ją na warunek {% if order.NotDeterminedDeliveryCost == false and notDeterminedDeliveryCost == false -%}. Pamiętaj aby kilka linijek niżej zamienić {% endunless -%} na {% endif -%}. Kawałek dalej znajduje się warunek {% if paymentCost != null -%}. Zamień go na {% if paymentCost != null and order.NotDeterminedDeliveryCost == false and notDeterminedDeliveryCost == false -%} Teraz w pliku order/delivery-partials/delivery-section.html, wyszukaj warunek {% if order.NotDeterminedDeliveryCost == false -%} i zamień go na {% if order.NotDeterminedDeliveryCost == false and deliveryMethod.NotDeterminedDeliveryCost == false -%}. Następnie wyszukaj warunek {% if order.NotDeterminedDeliveryCost == false -%} i zamień go na {% if order.NotDeterminedDeliveryCost == false and order.SelectedDelivery.NotDeterminedDeliveryCost == false -%} W pliku order/cart.html znajdź warunek {% if order.NotDeterminedDeliveryCost and order.OrderStep == 'Start' -%}. Zamień go na poniższy kod: {% if order.NotDeterminedDeliveryCost or order.SelectedDelivery.NotDeterminedDeliveryCost -%} {% assign notDeterminedDeliveryCost = true -%} {% endif -%} {% if notDeterminedDeliveryCost and order.OrderStep == 'Start' -%}

Agat

W pliku partials/cart/cart-content.html znajdź warunek {% if cart.NotDeterminedDeliveryCost == true %} i zamień go na {% if cart.NotDeterminedDeliveryCost or cart.SelectedDelivery.NotDeterminedDeliveryCost %}. Kawałek dalej w tym samym pliku znajdź warunek {% if cart.NotDeterminedDeliveryCost == false %}. Zamień go na poniższy kod: {% if deliveryMethod.Name == cart.SelectedDelivery.Name %} {% assign notDeterminedDeliveryCost = cart.SelectedDelivery.NotDeterminedDeliveryCost -%} {% else %} {% assign notDeterminedDeliveryCost = deliveryMethod.NotDeterminedDeliveryCost -%} {% endif %} {% if cart.NotDeterminedDeliveryCost == false and notDeterminedDeliveryCost == false %} Kawałek niżej znajdź warunek {% if cart.NotDeterminedDeliveryCost == false %} i zamień go na {% if cart.NotDeterminedDeliveryCost == false and deliveryMethodLvl.NotDeterminedDeliveryCost == false %}. Dalej w tym samym pliku (partials/cart/cart-content.html), oraz w plikach partials/cart/delivery-and-payment.html i partials/cart/summary.html znajdź frazę {% unless cart.NotDeterminedDeliveryCost -%} i zamień ją na {% if cart.NotDeterminedDeliveryCost == false and cart.SelectedDelivery.NotDeterminedDeliveryCost == false -%}. Pamiętaj aby kilka linijek niżej zamienić {% endunless -%} na {% endif -%}. We wszystkich przypadkach przesuń ten {% endif -%} tak aby warunek obejmował też dane związane z kosztami płatności. Podobną zmianę należy wprowadzić w pliku partials/customer/order-details.html. Frazę {% unless customer-profile.Order.NotDeterminedDeliveryCost -%} należy zamienić na {% if customer-profile.Order.NotDeterminedDeliveryCost == false and customer-profile.Order.Delivery.NotDeterminedDeliveryCost == false -%} W plikach partials/cart/delivery-and-payment.html i partials/cart/summary.html znajdź warunek {% if cart.NotDeterminedDeliveryCost -%} i zamień go na {% if cart.NotDeterminedDeliveryCost or cart.SelectedDelivery.NotDeterminedDeliveryCost %}

Bursztyn lub Opal

Na początku pliku order/cart.html znajdź warunek {% if cart.NotDeterminedDeliveryCost %} i zamień go na {% if cart.NotDeterminedDeliveryCost or cart.SelectedDelivery.NotDeterminedDeliveryCost %}. Następnie trochę dalej znajdź warunek {% if cart.NotDeterminedDeliveryCost == false %} i zamień go na {% if cart.NotDeterminedDeliveryCost == false and delivery.NotDeterminedDeliveryCost == false %}. Kawałek dalej znajdziesz warunek {% if delivery.FreeDeliveryFrom > cart.ProductsTotalValue and cart.NotDeterminedDeliveryCost == false and delivery.TotalValue > 0 %}. Zamień go na {% if delivery.FreeDeliveryFrom > cart.ProductsTotalValue and cart.NotDeterminedDeliveryCost == false and delivery.NotDeterminedDeliveryCost == false and delivery.TotalValue > 0 %} Następnie w pliku order/stepsummary.html znajdź frazę {{translations.Crt_DeliveryCost}} i całą linijkę z tą frazą nadpisz poniższym kodem: {% if deliveryData.NotDeterminedDeliveryCost == false %}{{translations.Crt_DeliveryCost}}{{deliveryData.TotalValue|ToPrice}} {{cartCurrency}}{% endif %}

Topaz

W pliku staticElements/cart/cart.html znajdź warunek (występuje dwa razy) {% if cart.NotDeterminedDeliveryCost == true %} i zamień go na {% if cart.NotDeterminedDeliveryCost or cart.SelectedDelivery.NotDeterminedDeliveryCost %} (w obu przypadkach). Następnie wyszukaj frazę {{deliveryMethod.DateText}}. Pod linijką z tą frazą znajduje się warunek. Zastąp go wraz z jego zawartością poniższym kodem: {% if deliveryMethod.NotDeterminedDeliveryCost == false and cart.NotDeterminedProductsDeliveryCost == false -%} {{ deliveryMethod.TotalValue | ToPrice }} {{ currency }} {% endif -%} Teraz wyszukaj frazę {{ payment.DueDateText }}. Pod linijką z tą frazą znajduje się warunek. Zastąp go wraz z jego zawartością poniższym kodem: {% if deliveryMethodLvl.NotDeterminedDeliveryCost == false and cart.NotDeterminedProductsDeliveryCost == false -%} {{ payment.TotalValue | ToPrice }} {{ currency }} {% endif -%}  

Obsługa lookbooka w szablonie Topaz

Obsługa lookbooka w szablonie Topaz

W tym artykule dowiesz się jak zmodyfikować swój szablon, aby obsługiwał lookbooka.

Topaz

W Panelu Administratora przejdź do zakładki Tłumaczenia (Wygląd sklepu -> Ustawienia -> Tłumaczenia) i dodaj tam dwie frazy. ShowProducts - Pokaż towary, Lookbook - Lookbook. Następnie przejdź do zakładki Bannery (Wygląd sklepu -> Ustawienia -> Bannery) i dodaj tam banner o nazwie lookbook. Po jego dodaniu wejdź w jego ustawienia i zaznacz Lookbook zamiast Standardowy. Resztę uzupełnij wedle własnego uznania. W polu Nazwa (Lookbook) będzie nazwa lookbooka, która będzie się wyświetlać w sklepie. Teraz przejdź do zakładki Strony (Wygląd sklepu -> Ustawienia -> Trzykropek w prawym górnym rogu -> Edytuj ustawienia zaawansowane -> Strony) i przy stronie Lookbook wpisz lookbook.html, a następnie wejdź w ustawienia danej strony i zaznacz check-box header [Nagłówek]. Zapisz to wszystko kliknięciem w dyskietkę w prawym górnym rogu. W pliku elements/header/header-1.html (lub header-2.html - w zależności od wybranej w szablonie wersji nagłówka) wyszukaj frazę config.DefinedPages.Contact. Pod linijką z tą frazą wklej poniższy kod: {% for banner in config.Banners -%} {% assign imagesQuantity = banner.Images | Size -%} {% if banner.Name == 'lookbook' and imagesQuantity == 0 -%} {% assign fakeLookbook = true -%} {% endif -%} {% endfor -%} {% assign lookbooksQuantity = config.Lookbook.List | Size -%} {% if lookbooksQuantity > 1 -%} {{ translations.Lookbook }}
{% elseif lookbooksQuantity == 1 or fakeLookbook -%} {{ config.DefinedPages.Lookbook | A }} {% endif -%}
Następnie w folderze staticElements dodaj folder lookbook, a w nim plik lookbook.html, który będzie zawierał poniższy kod: {% include 'partials/common/breadcrumbs.html' -%} {% assign lookbooksQuantity = config.Lookbook.List | Size -%} {% if lookbooksQuantity > 1 -%} {% assign lookbook = config.Lookbook.Current -%} {% elseif lookbooksQuantity == 1 -%} {% assign lookbook = config.Lookbook.List[0] -%} {% endif -%}
{% if lookbooksQuantity > 0 -%}

{{ lookbook.Text }}

{% for image in lookbook.Images -%}
{% if image.JSON != "" -%}
{{translations.ShowProducts | Upcase}}
{% endif -%}
{% endfor -%}
{% else -%}

{{ translations.Lookbook }}

{{'css/img/img-placeholder.jpg' | Img: '', translations.DefaultImage}}
560x630
{{'css/img/img-placeholder.jpg' | Img: '', translations.DefaultImage}}
700x850
{{'css/img/img-placeholder.jpg' | Img: '', translations.DefaultImage}}
1260x540
{{'css/img/img-placeholder.jpg' | Img: '', translations.DefaultImage}}
630x950
{{'css/img/img-placeholder.jpg' | Img: '', translations.DefaultImage}}
560x630
{% endif -%}
Teraz w pliku css/layout.css dodaj poniższy kod: .lookbookSection{width:85%;max-width:1400px;margin:50px auto 150px}.lookbook__name{margin-bottom:100px}.lookbook__imageContainer{position:relative;vertical-align:top}.lookbook__imageContainer:nth-child(5n+1){display:inline-block;width:40%;margin-right:calc(10% - 5px)}.lookbook__imageContainer:nth-child(5n+2){display:inline-block;width:50%}.lookbook__imageContainer:nth-child(5n+3){width:90%}.lookbook__imageContainer:nth-child(5n+4){display:inline-block;width:45%;margin-right:calc(15% - 5px)}.lookbook__imageContainer:nth-child(5n){display:inline-block;width:40%}.lookbook__imageContainer img{max-width:100%;max-height:100%;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.lookbook__imagePlaceholder{background-color:#f2f2f2}.lookbook__imagePlaceholderSize{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.lookbook__productsToggleButton{position:absolute;right:0;bottom:0;padding:20px;background:#fff;width:250px;text-align:center;cursor:pointer}.lookbook__productsContainer{position:absolute;right:0;bottom:59px;padding:0 20px;background:#fff;width:250px}.lookbook__product{position:relative;padding:20px 0;border-bottom:1px solid #f2f2f2}.lookbook__productName{color:{{settings.inputLabelColor}};overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:10px}.lookbook__productPrice{font-size:18px;font-weight:700;display:inline-block;width:calc(100% - 50px)}.lookbook__checkProductLink{position:absolute;right:0;bottom:20px;color:{{settings.linkFontColor}}} Następnie w pliku css/layout-m.css dodaj poniższy kod: .lookbookSection{margin:20px auto}.lookbookSection .lookbook__imageContainer{width:100%;margin:0 0 100px}.lookbookSection .lookbook__imageContainer:last-child{margin-bottom:20px}.lookbook__name{margin-bottom:20px}.lookbook__showProductsButton{bottom:0;right:auto;left:50%;transform:translate(-50%, 50%);border:1px solid #f2f2f2}.lookbook__hideProductsButton,.lookbook__productsContainer{position:fixed;width:calc(100% - 40px);z-index:102}.lookbook__productsContainerBackgroundMobile{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(255,255,255,0.8);z-index:101} Teraz w pliku js/layout1.js (lub layout0.js jeśli nie ma layout1.js, lub layout.js jeśli nie ma dwóch poprzednich) dodaj poniższy kod: if($('.lookbookImageContainer-js').length > 0){ var setLookbookImages = function () { $('.lookbookImageContainer-js').each(function(index){ if(index == 0){ var heightRatio = 1.13; } else if(index == 1){ var heightRatio = 1.22; var marginTopRatio = 0.39; } else if(index == 2){ var heightRatio = 0.43; var marginTopRatio = 0.25; var marginBottomRatio = 0.36; } else if(index == 3){ var heightRatio = 1.52; } else if(index == 4){ var heightRatio = 1.13; var marginTopRatio = 0.46; } var width = $(this).width(); var height = width * heightRatio; $(this).css('height', height); if($(window).width() > 768){ if(marginTopRatio){ var marginTop = height * marginTopRatio; $(this).css('margin-top', marginTop); } if(marginBottomRatio){ var marginBottom = height * marginBottomRatio; $(this).css('margin-bottom', marginBottom); } } else { if(marginTopRatio){ $(this).css('margin-top', 0); } if(marginBottomRatio){ $(this).css('margin-bottom', 100); } } }) }; setLookbookImages(); $(window).resize(function() { setLookbookImages(); }); var addLookbookProducts = function () { var url = $('[data-product-details-url]').data('product-details-url'); var checkTranslation = $('[data-check-translation]').data('check-translation'); $('[data-lookbook-products]').each(function(){ var productContainer = $(this); var products = JSON.stringify(productContainer.data('lookbook-products')); var objProducts = JSON.parse(products); $.each(objProducts, function (index, value) { var productUrl = url + ',,' + value.id; var data = {__collection: 'product-details.Product.Name|product-details.Product.Price'}; $.get(productUrl, data, function (res) { productContainer.append( '
'+ '
'+res.collection['product-details.Product.Name']+'
'+ '
'+res.collection['product-details.Product.Price']+' '+__curr+'
'+ ''+checkTranslation+'
'+ '
' ); }); }); }); }; addLookbookProducts(); $('body').on('click', '.showLookbookProducts-js', function (e) { $(e.currentTarget).siblings().show(); $(e.currentTarget).hide(); }); $('body').on('click', '.hideLookbookProducts-js', function (e) { $(e.currentTarget).siblings().hide(); $(e.currentTarget).next().show(); $(e.currentTarget).hide(); }); } Następnie w pliku js/layout0.js (lub layout.js jeśli nie ma layout0.js) znajdź zmienną var headerFunctions i podmień ją na jeden z poniższych kodów. Pierwszy jest do nagłówka z domyślnie ukrytą wyszukiwarką, a drugi do nagłówka z domyślnie odkrytą wyszukiwarką. header-1 var headerFunctions = { init: function () { headerFunctions.events(); }, events: function () { var pageHeader = $('.pageHeader-js'); pageHeader.on('click', '.showSearchSection-js', function() { $('.pageHeader-js .headerSearchForm-js').toggle(200); $('.pageHeader-js .sitesNavigation-js').hide(200); $('.pageHeader-js .mainNavigation-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').hide(200); $('.openCategoryMenu-js, .openPagesMenu-js, .openLookbooksMenu-js').removeClass('activeButton-js'); $('.searchFormPhrase-js').focus(); }); pageHeader.on('click', '.showMenuSection-js', function() { $('.pageHeader-js .headerMainMenu-js').toggle(200); }); pageHeader.on('click', '.mainMenuMobileCloseBtn-js', function() { $('.pageHeader-js .headerMainMenu-js').hide(200); }); pageHeader.on('click', '.openCategoryMenu-js', function() { $('.pageHeader-js .sitesNavigation-js').hide(200); $('.pageHeader-js .languageAndCurrencyMenu-js').hide(200); $('.pageHeader-js .headerSearchForm-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').hide(200); $('.pageHeader-js .mainNavigation-js').toggle(200); $('.openLanguageAndCurrencyMenu-js, .openPagesMenu-js, .openLookbooksMenu-js').removeClass('activeButton-js'); $(this).toggleClass('activeButton-js'); app.loadImages(); }); pageHeader.on('click', '.openLanguageAndCurrencyMenu-js', function() { $('.pageHeader-js .sitesNavigation-js').hide(200); $('.pageHeader-js .mainNavigation-js').hide(200); $('.pageHeader-js .headerSearchForm-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').hide(200); $('.pageHeader-js .languageAndCurrencyMenu-js').toggle(200); $('.openCategoryMenu-js, .openPagesMenu-js, .openLookbooksMenu-js').removeClass('activeButton-js'); $(this).toggleClass('activeButton-js'); }); pageHeader.on('click', '.openPagesMenu-js', function() { $('.pageHeader-js .mainNavigation-js').hide(200); $('.pageHeader-js .languageAndCurrencyMenu-js').hide(200); $('.pageHeader-js .headerSearchForm-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').hide(200); $('.pageHeader-js .sitesNavigation-js').toggle(200); $('.openCategoryMenu-js, .openLanguageAndCurrencyMenu-js, .openLookbooksMenu-js').removeClass('activeButton-js'); $(this).toggleClass('activeButton-js'); }); pageHeader.on('click', '.openLookbooksMenu-js', function() { $('.pageHeader-js .mainNavigation-js').hide(200); $('.pageHeader-js .languageAndCurrencyMenu-js').hide(200); $('.pageHeader-js .headerSearchForm-js').hide(200); $('.pageHeader-js .sitesNavigation-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').toggle(200); $('.openCategoryMenu-js, .openLanguageAndCurrencyMenu-js, .openPagesMenu-js').removeClass('activeButton-js'); $(this).toggleClass('activeButton-js'); }); pageHeader.on('change', '.customerLanguageChange-js', function(e) { if($(this).is(':checked')) {app.customerLanguageChange(e)} }); pageHeader.on('change', '.customerCurrencyChange-js', function(e) { if($(this).is(':checked')) {app.customerCurrencyChange(e)} }); pageHeader.on('click', '.openUndercategoryMenu-js', function(e) { var undercategory = $(e.currentTarget).closest('li').find('ul').first(); $(undercategory).toggle(200); }); } }; header-2 var headerFunctions = { init: function () { headerFunctions.events(); }, events: function () { var pageHeader = $('.pageHeader-js'); pageHeader.on('click', '.showSearchSection-js', function() { $('.pageHeader-js .headerSearchForm-js').toggle(200); $('.searchFormPhrase-js').focus(); }); pageHeader.on('click', '.showMenuSection-js', function() { $('.pageHeader-js .headerMainMenu-js').toggle(200); }); pageHeader.on('click', '.mainMenuMobileCloseBtn-js', function() { $('.pageHeader-js .headerMainMenu-js').hide(200); }); pageHeader.on('click', '.openCategoryMenu-js', function() { $('.pageHeader-js .sitesNavigation-js').hide(200); $('.pageHeader-js .languageAndCurrencyMenu-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').hide(200); $('.pageHeader-js .mainNavigation-js').toggle(200); $('.openLanguageAndCurrencyMenu-js, .openPagesMenu-js, .openLookbooksMenu-js').removeClass('activeButton-js'); $(this).toggleClass('activeButton-js'); app.loadImages(); }); pageHeader.on('click', '.openLanguageAndCurrencyMenu-js', function() { $('.pageHeader-js .sitesNavigation-js').hide(200); $('.pageHeader-js .mainNavigation-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').hide(200); $('.pageHeader-js .languageAndCurrencyMenu-js').toggle(200); $('.openCategoryMenu-js, .openPagesMenu-js, .openLookbooksMenu-js').removeClass('activeButton-js'); $(this).toggleClass('activeButton-js'); }); pageHeader.on('click', '.openPagesMenu-js', function() { $('.pageHeader-js .mainNavigation-js').hide(200); $('.pageHeader-js .languageAndCurrencyMenu-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').hide(200); $('.pageHeader-js .sitesNavigation-js').toggle(200); $('.openCategoryMenu-js, .openLanguageAndCurrencyMenu-js, .openLookbooksMenu-js').removeClass('activeButton-js'); $(this).toggleClass('activeButton-js'); }); pageHeader.on('click', '.openLookbooksMenu-js', function() { $('.pageHeader-js .mainNavigation-js').hide(200); $('.pageHeader-js .languageAndCurrencyMenu-js').hide(200); $('.pageHeader-js .sitesNavigation-js').hide(200); $('.pageHeader-js .lookbooksNavigation-js').toggle(200); $('.openCategoryMenu-js, .openLanguageAndCurrencyMenu-js, .openPagesMenu-js').removeClass('activeButton-js'); $(this).toggleClass('activeButton-js'); }); pageHeader.on('change', '.customerLanguageChange-js', function(e) { if($(this).is(':checked')) {app.customerLanguageChange(e)} }); pageHeader.on('change', '.customerCurrencyChange-js', function(e) { if($(this).is(':checked')) {app.customerCurrencyChange(e)} }); pageHeader.on('click', '.openUndercategoryMenu-js', function(e) { var undercategory = $(e.currentTarget).closest('li').find('ul').first(); $(undercategory).toggle(200); }); } };