E-commerce, Praca w IT

Jak od środka wygląda praca programisty w branży e-commerce

First Line Software

Na pierwszy rzut oka mogłoby się wydawać, że projekty tworzone na potrzeby klienta z branży e-commerce są do siebie mocno zbliżone. Oczywiście do pewnego stopnia jest to prawda i ten wspólny kontekst jest odzwierciedlony w platformach, takich jak Optimizely czy Znode. Zapewniają one obsługę całego procesu sprzedaży. Mimo wszystko konkretne wymagania klienta generują potrzeby rozszerzania i dostosowywania platformy do tychże wymagań.

Poniżej kilka przykładów tego, na czym polega praca programisty w branży e-commerce.

Rozszerzanie funkcjonalności strony 

Często przy pracy z projektami e-commerce natrafiamy na potrzeby dostosowania projektu bardziej pod kątem samej strony internetowej niż części commerce. W takich przypadkach możemy skorzystać z wbudowanych możliwości systemu, jak np. atrybuty globalne w Znode.

Niedawno dla klienta ze Stanów Zjednoczonych implementowaliśmy możliwość aktualizacji polityki prywatności oraz mechanizm dbający o to, aby użytkownik zaakceptował najnowszą politykę prywatności, zanim zacznie korzystać ze strony. 

Aby osiągnąć powyższe założenia, skorzystaliśmy z trzech atrybutów globalnych dodanych za pomocą sekcji „global attributes” w panelu administratora. Najpierw zostały dodane atrybuty: PrivacyPolicyDate oraz PrivacyPolicyText reprezentujące kolejno datę ostatniej aktualizacji treści polityki prywatności oraz właśnie jej treść. Nowe pola zostały zgrupowane w grupę PrivacyPolicy oraz dodane do rodziny atrybutów „Default Store Family” reprezentującej ustawienia na poziomie sklepu. Ustawienia te można znaleźć w panelu administratora w  zakładce „Manage Store” -> „Additional Attributes”.

Następnie na poziomie użytkownika dodana została grupa atrybutów UserPrivacyPolicy zawierająca pole PrivacyPolicyAcceptDate. Jest ona widoczna z Panelu administratora w zakładce „Manage User” -> „Additional Attributes”.

Idea tego rozwiązania jest prosta. Przy ładowaniu strony sprawdzamy datę aktualizacji polityki prywatności. Jeżeli data akceptacji polityki prywatności przez użytkownika jest pusta lub starsza niż data aktualizacji treści polityki prywatności, wtedy pokazujemy użytkownikowi okienko z najnowszą polityką prywatności do zaakceptowania. Kiedy użytkownik akceptuje najnowszą treść, wtedy automatycznie zapisujemy datę akceptacji przypisaną do tej osoby.

Aby pobrać datę aktualizacji treści polityki prywatności w kodzie, możemy użyć wewnętrznego API w następujący sposób: 

PortalAgent.CurrentPortal.GlobalAttributes.Attributes.FirstOrDefault(a => a.AttributeCode == "PrivacyPolicyDate").AttributeValue;

Z kolei, aby manipulować datą zaakceptowania polityki prywatności przez użytkownika, możemy skorzystać z interfejsu IGlobalAttributeGroupEntityService. Wykorzystując przy tym metody GetEntityAttributeDetails (int entityId, string entityType) oraz SaveEntityAttributeDetails (EntityAttributeModel model). Przykładowe pobranie wartości z właściwości z poziomu użytkownika:

var userAcceptDate = _service.GetEntityAttributeDetails(userId,"User").Attributes
.FirstOrDefault(a => a.AttributeCode =="PrivacyPolicyAcceptDate")
.AttributeValue;

Potrzeby wynikające z integracji

Nieodłączną częścią pracy w projektach e-commerce są integracje z zewnętrznymi systemami, między innymi w celach przechowywania informacji o produktach, zamówieniach, dostępności poszczególnych przedmiotów. Często w związku z tym wytwarza się potrzeba przechowywania dodatkowych informacji o produkcie. Na jednym z projektów u klienta wywiązała się niedawno taka potrzeba. 

Przy integracji z Microsoft Dynamics 365 potrzebowaliśmy informacji o rodzaju produktu w celu pobrania jego poprawnej dostępności z magazynu. W tym celu skorzystaliśmy z wbudowanej funkcjonalności Znode „Product Attributes”. Dodaliśmy atrybut CustomProductType pozwalający na wybór rodzaju produktu z predefiniowanej listy. W obecnej chwili obecna lista pozwala na wybór opcji „Standard” oraz „Kit”.

W zależności od tego czy produkt reprezentuje pojedynczy przedmiot, czy zestaw wysyłamy dwa różne żądania REST API w celu otrzymania informacji zwrotnej o stanie magazynowym. W przypadku zestawu najpierw odpytujemy API zwracające informację o produktach zawartych w pakiecie, a następnie wysyłamy zapytanie o stan magazynowy poszczególnych produktów, aby ustalić liczbę możliwych do skompletowania zestawów.

Do pobrania nowo dodanego typu produktu możemy użyć metody pomocniczej:

product.ProductAttributes.ValueFromSelectValue("CustomProductType");

Gdzie product może być zarówno typem PublishProductModel, jak i ShoppingCartItemModel, co w praktyce oznacza, że atrybuty w kodzie są dostępne zarówno w kontekście zarządzania produktami jak również podczas procesowania koszyka.

Dodawanie prostych właściwości produktu 

Podstawą każdego sklepu internetowego jest jego asortyment, ta część systemów e-commerce jest w zasadzie zawsze rozszerzana i dostosowywana do potrzeb danego sprzedawcy. Optimizely dostarcza pod tym kątem bardzo wygodną architekturę z perspektywy programisty. 

Załóżmy, że nasz sklep handluje artykułami biurowymi i chcemy jak najlepiej opisać te produkty na naszej stronie. Przykładowo, chcemy, aby na stronie produktu dla notatnika znajdowała się informacja o tym, ile kartek posiada dany wariant. Wykorzystujemy w tym celu założenia polimorfizmu, implementując własną klasę reprezentująca notatnik dziedzicząca po klasie bazowej Optimizely: VariationContent.

public class NotebookVariant : VariationContent
 {
    [Display(GroupName = SystemTabNames.Content, Name = "Number of Pages", Order = 100)]
    public virtual int NumberOfPages { get; set; }
 }

To rozwiązanie pozwala nam korzystać z klasy bazowej wszędzie, gdzie pobieramy listę wariantów lub produktów. Natomiast po sprawdzeniu typu danego obiektu możemy korzystać warunkowo z rozszerzonych atrybutów konkretnej implementacji klasy, na przykład właśnie, aby wyświetlić liczbę stron jeśli dany produkt jest notatnikiem.

Po dodaniu nowej właściwości produktu w kodzie edytorzy będą mieli możliwość ustawić, ile stron ma każdy z wariantów notatnika. Dodatkowo dekorator w postaci atrybutów zawartych w nawiasach kwadratowych pozwala ustalić, w jakiej zakładce w panelu administratora będzie widoczna nowa właściwość produktu, określić nazwę nowego pola oraz kolejność wyświetlania tych pól.

Dodawanie złożonych właściwości produktu

Rozszerzając poprzednią sekcję – możemy również natrafić na sytuację, w której potrzebujemy stworzyć właściwość produktu, która powinna umożliwiać wybór z predefiniowanej listy. Dobrym przykładem może być tutaj rodzaj medium w sklepie z książkami. 

Wyobraźmy sobie, że nasz sklep sprzedaje książki papierowe, audiobooki oraz e-booki. Aby jasno określić rodzaj sprzedawanej książki, potrzebujemy stworzyć atrybut pozwalający wybrać z trzech różnych wspomnianych wcześniej typów. Możemy w tym celu stworzyć własną pulę selekcji dla typu książki w następujący sposób:

public class BookTypeSelectionFactory : ISelectionFactory
{
  public IEnumerable GetSelections(ExtendedMetadata metadata)
  {
    return new ISelectItem[]
    {
       new SelectItem { Text = "Paper book", Value = "PaperBook" },
       new SelectItem { Text = "E-book", Value = "eBook" },
       new SelectItem { Text = "Audiobook", Value = "Audiobook" },
    };
  }
}

Po dodaniu powyższej fabryki opcji możemy użyć jej w naszej klasie reprezentującej wariant książki:

public class BookVariant : VariationContent
{
  [Display(Name = "Book Type", GroupName = SystemTabNames.Content, Order = 100)]
  [SelectOne(SelectionFactoryType = typeof(BookTypeSelectionFactory))]
  public virtual string BookType { get; set; }
}

Powyższa implementacja umożliwi edytorom wybór rodzaju książki z listy trzech dostępnych opcji podczas edycji wariantu. Identyfikacja typu książki pozwoli nie tylko na wyświetlenie tej informacji użytkownikowi końcowemu, ale również zapewni poprawną identyfikację podczas procesów takich jak sprzedaż oraz dostawa. Przykładowo dostawa papierowej książki będzie wiązała się z fizyczną przesyłką natomiast e-book oraz audiobook mogą zostać dostarczone do odbiorcy cyfrowo.

Implementacja metod dostawy 

Kolejną częścią e-commerce, którą zazwyczaj należy dostosować do konkretnego projektu, są metody dostawy. W tej kwestii korzystając z Optimizely mamy dwa poziomy możliwości. Po pierwsze możemy dodać nową metodę dostawy z poziomu panelu administratora i uzupełnić dane takie jak nazwa, język, waluta, oraz rodzaj obliczania kosztu dostawy. Dostępne są dwa rodzaje obliczania kosztów dostawy: Generic Gateway oraz Weight/Jurisdiction Gateway

Pierwszy rodzaj bazuje na ustalonej cenie przesyłki, drugi natomiast posiada cenę bazową, do której dodawana jest dodatkowa opłata bazująca na lokalizacji dostawy oraz na wadze paczki. Zazwyczaj dodanie metody dostawy ze stałą ceną jest wystarczające, gdyż większość kurierów ma z góry ustalone ceny lub ewentualnie ceny są jednoznacznie zależne od wagi. Czasem jednak potrzebujemy dostosować opcje dostawy w większym stopniu, wtedy możemy skorzystać z własnej bramki dostawczej.

Drugim poziomem dostosowywania metod dostawy jest możliwość implementacji własnej bramki (rodzaju obliczania kosztów). W tym celu możemy zaimplementować interfejs IShippingGateway lub IShippingPlugin, z czego Optimizely zaleca implementowanie tego drugiego, ponieważ głównym celem pierwszego jest kompatybilność wsteczna. Interfejs zawiera tylko jedną metodę i jest ona odpowiedzialna za wyliczenie kosztów dostawy.

ShippingRate GetRate(IMarket market, Guid methodId, IShipment shipment, ref string message)

Wewnątrz tej metody możemy wykonać wszelkie obliczenia związane z ustaleniem ceny przesyłki. Metoda ta zwraca obiekt klasy ShippingRate zawierający następujące pola:

  • Id – identyfikator powiązanej metody wysyłki,
  • Money – cena oraz waluta przesyłki,
  • Name – nazwa powiązanej metody wysyłki.

Dostosowywanie wyników wyszukiwania 

Jednym z najczęściej używanych elementów strony internetowej reprezentującej sklep jest globalna wyszukiwarka. Jak wiele wcześniej wspomnianych obszarów i ona może być dostosowywana pod konkretne potrzeby. Jeśli korzystamy z domyślnych funkcjonalności wyszukiwania Optimizely Search & Navigation możemy w łatwy sposób manipulować, które pola produktów czy wariantów mają być indeksowane i dostępne do wyszukiwania. Jeżeli chcemy wykluczyć którąś właściwość tak, aby nie dało się po niej wyszukać wyników, możemy użyć dekoratora [JsonIgnore] nad danym atrybutem:

[JsonIgnore] 
public string AdditionalNotes { get; set; }

Możemy również skorzystać z konfiguracji konwencji wyszukiwania:

//using EPiServer.Find.ClientConventions; 
searchClient.Conventions.ForInstancesOf().ExcludeField(x => x.AdditionalNotes );

Jeżeli natomiast chcemy dodać możliwość wyszukania przedmiotu poprzez pole, które nie jest bezpośrednio częścią klasy reprezentującej ten przedmiot, również mamy taką opcję. Nawiązując do przykładu z poprzednich sekcji, wyobraźmy sobie, że mamy książkę reprezentowaną przez klasę BookProduct:

public class BookProduct : ProductContent
{
    public virtual string Author{ get; set; }
}

oraz jej warianty typu BookVariant:

public class BookVariant: VariationContent
{
    public virtual string BookType { get; set; }
}

Załóżmy, że chcemy, aby w wynikach wyszukiwania po nazwie autora znalazły się wszystkie jego książki, zarówno wersje papierowe, jak i e-booki oraz audiobooki. W tym celu chcemy, aby dla każdego wariantu zostało zaindeksowane pole nienależące bezpośrednio do tego obiektu — Author.

Dla tego przykładu możemy skonfigurować klienta wyszukiwania, aby indeksował wybrany atrybut w podany sposób:

//using EPiServer.Find.ClientConventions; client.Conventions.ForInstancesOf().IncludeField(x => x.Author());

Gdzie metoda Author() stanowi metodę rozszerzającą dla klasy BookVariant:

public static string Author(this BookVariant bookVariant)
{
var author = bookVariant.ParentProduct().GetValue("Author");
return author != null ? author.ToString() : string.Empty;
}

Dzięki powyższemu rozwiązaniu, po wpisaniu nazwy autora w pasku wyszukiwania użytkownik końcowy zobaczy wszystkie książki danego autora we wszystkich dostępnych rodzajach nośnika.

Poszerz, dostosuj, modyfikuj, trafiaj w sedno! 

Praca z systemami e-commerce jest bardzo zróżnicowaną specjalizacją w branży IT. Potrzeby klientów bezpośrednio wpływają na rozwiązania projektowe oraz na wszelkiego rodzaju modyfikacje domyślnych funkcji. Każdy sklep ma swój charakter, swoją branżę, swoje wyzwania i swoje własne możliwości. 
Jako programista .NET właśnie w tym sektorze lubię pracować najbardziej. Nie da się trafić na identyczny projekt, za każdym razem trafiamy na coś nowego. Daje to szerokie możliwości rozwoju i po prostu ciężko jest się tym znudzić. 

Powyższy artykuł miał na celu zobrazowanie zróżnicowanej gamy doświadczeń idącej za pracą z systemami e-commerce, ale oczywiście nie wyczerpuje w pełni tematu ich rozszerzalności. Przykładowo warto wspomnieć, iż możemy chociażby tworzyć w pełni dostosowywalne promocje oraz nowe ich rodzaje, czy choćby rozszerzyć kalkulację ceny koszyka oraz zamówienia. Kiedyś przykładowo miałem okazję modyfikować domyślny kalkulator cen, aby zwiększyć cenę końcową o podatek od plastiku dla adekwatnych produktów. Takich przykładów można by wymieniać niemalże w nieskończoność.

Modyfikacje, rozszerzanie funkcjonalności, dostosowywanie do potrzeb klienta – to nasza codzienność, i to niezwykle ważna codzienność. Te aspekty są nieodłącznym elementem pracy z systemami e-commerce i jest to jak najbardziej uzasadnione. Wychodzenie naprzeciw wymaganiom i różnicom jest w naszej branży kluczowe, szczególnie w tym sektorze. Dobry i skuteczny handel elektroniczny to handel dostosowany zarówno do potrzeb sprzedawcy, jak i oczekiwań kupującego. Dlatego zgodnie z duchem tego artykułu, moja pożegnalna rada dla każdego programisty z branży e-commerce: Poszerz, dostosuj, modyfikuj, trafiaj w sedno!

Software Developer (.NET) w First Line Software

Programista z ponad 5-letnim doświadczeniem. Obecnie pracuje w First Line Software (FLS), gdzie miał możliwość wykazać się przy pracy z systemami e-commerce oraz CMS z wykorzystaniem różnorodnych narzędzi. Będąc członkiem grupy FLS Influencers udziela się aktywnie w procesie rekrutacji między innymi poprzez prowadzenie rozmów technicznych z kandydatami.

Podobne artykuły

[wpdevart_facebook_comment curent_url="https://justjoin.it/blog/jak-od-srodka-wyglada-praca-programisty-w-branzy-e-commerce/" order_type="social" width="100%" count_of_comments="8" ]