- Moment uruchomienia skryptu
- Modyfikacja danych po stronie systemu źródłowego
- Modyfikacja danych po stronie systemu docelowego
- Modyfikacja danych przed aktualizacją w systemie docelowym
- Przypadki użycia
MSDK w stanach magazynowych
Synchronizacja stanów magazynowych jest jednym z podstawowych procesów w każdej firmie prowadzącej sprzedaż internetową, ze względu na potrzeby takich firm jak np. wczytywanie danych z zewnętrznych plików, posiadanie wielu formatów plików XML, czy skomplikowane algorytmy obliczania stanu dla produktu, zostały wprowadzone 3 miejsca w której można uruchomić skrypty i zmodyfikować odpowiednie dane.
Moment uruchomienia skryptu
W przypadku synchronizacji stanów magazynowych, skrypt uruchamiany jest po wykonaniu funkcjonalności wykorzystywanych w scenariuszu konfiguracyjnym (Zastosowany jest wzorzec Łańcucha odpowiedzialności), w związku z tym dane, które skrypt otrzyma mogą zostać już wcześniej przez nas przetworzone, np.:
Zaznaczono w konfiguracji, żeby pomijać Towar, który nie posiada jakieś cechy lub atrybutu, w związku z czym został przez nas odfiltrowany i skrypt nie otrzyma go do dalszego przetworzenia.
Modyfikacja danych po stronie systemu źródłowego
Niezależnie od używanego języka skryptowego podczas uruchomienia zostanie przekazany następujący format XMLa:
<products>
<product>
<id>1</id>
<symbol>PESO20</symbol>
<name>So perfumy 20ml</name>
<ean>5902812179392</ean>
<unit>szt.</unit>
<quantity>1</quantity>
<reserved>1</reserved>
<inStock>2</inStock>
<features>zielony,szklana butelka,zapach trawy</features>
<warehouses></warehouses>
<customFields>
<field key="Rok produkcji">2001</field>
<field key="W sprzedaży">Tak</field>
<field key="W hurtowni">1</field>
<field key="Z zwrotu">4</field>
<field key="Uszkodzone opakowania">2</field>
</customFields>
</product>
<product>
<id>2</id>
<symbol>PESO30</symbol>
<name>So perfumy 30ml</name>
<ean>5902812134391</ean>
<unit>szt.</unit>
<quantity>7</quantity>
<reserved>3</reserved>
<inStock>10</inStock>
<features>czerwony,plastikowa butelka,zapach róż</features>
<warehouses></warehouses>
<customFields>
<field key="Rok produkcji">2003</field>
<field key="W sprzedaży">Nie</field>
<field key="W hurtowni">0</field>
<field key="Z zwrotu">0</field>
<field key="Uszkodzone opakowania">3</field>
</customFields>
</product>
</products>
Po wywołaniu metody właściwości które ponownie ustawimy na źródle to:
- Symbol (string)
- Nazwa (string)
- Ean (string)
- Jednostka miary (string)
- Ilość do sprzedaży (decimal)
- Ilość zarezerwowana (decimal)
- Ilość na stanie (decimal)
Kod w języku C#
using System;
using System.Xml.Linq;
using System.Linq;
namespace Sellintegro
{
public class External
{
public XElement ProcessSourceData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
return bodyXml;
}
}
}
Istotne jest aby namespace nazywał się Sellintegro, a publiczna klasa External, w przeciwnym wypadku integracja nie uruchomi się. Ważne jest by metoda nazywała się ProcessSourceData i przyjmowała podane parametry.
Jeżeli metoda zwróci produkty, które nie istniały w momencie przekazania ich do metody, lista ta zostanie uzupełniona. Produkty w momencie podmiany danych są rozpoznawane po wartości <id>
ze zwróconego XMLa
Kod w języku VBScript
Set xmlConfigObj = CreateObject("Microsoft.XMLDOM")
xmlConfigObj.async = "false"
xmlConfigObj.LoadXml(xml)
Set Root = xmlConfigObj.documentElement
result = Root.xml
W przypadku języka VBScript wejściową zmienną jest xml
oraz istotne jest przekazanie przetworzonego XMLa do zmiennej result
Jeżeli metoda zwróci produkty, które nie istniały w momencie przekazania ich do metody, lista ta zostanie uzupełniona. Produkty w momencie podmiany danych są rozpoznawane po wartości <id>
ze zwróconego XMLa
Modyfikacja danych po stronie systemu docelowego
Niezależnie od używanego języka skryptowego podczas uruchomienia zostanie przekazany następujący format XMLa:
<products>
<product>
<id>1</id>
<variant_id />
<symbol>PESO20</symbol>
<name>So perfumy 20ml</name>
<ean>5902812179392</ean>
<unit>szt.</unit>
<quantity>1</quantity>
<reserved>1</reserved>
<inStock>2</inStock>
<features>zielony,szklana butelka,zapach trawy</features>
<warehouses></warehouses>
<customFields>
<field key="Rok produkcji">2001</field>
<field key="W sprzedaży">Tak</field>
<field key="W hurtowni">1</field>
<field key="Z zwrotu">4</field>
<field key="Uszkodzone opakowania">2</field>
</customFields>
</product>
<product>
<id>2</id>
<variant_id />
<symbol>PESO30</symbol>
<name>So perfumy 30ml</name>
<ean>5902812134391</ean>
<unit>szt.</unit>
<quantity>7</quantity>
<reserved>3</reserved>
<inStock>10</inStock>
<features>czerwony,plastikowa butelka,zapach róż</features>
<warehouses></warehouses>
<customFields>
<field key="Rok produkcji">2003</field>
<field key="W sprzedaży">Nie</field>
<field key="W hurtowni">0</field>
<field key="Z zwrotu">0</field>
<field key="Uszkodzone opakowania">3</field>
</customFields>
</product>
</products>
Po wywołaniu metody właściwości które ponownie ustawimy na źródle to:
- Symbol (string)
- Nazwa (string)
- Ean (string)
- Jednostka miary (string)
- Ilość na stanie (decimal)
Kod w języku C#
using System;
using System.Xml.Linq;
using System.Linq;
namespace Sellintegro
{
public class External
{
public XElement ProcessTargetData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
return bodyXml;
}
}
}
Istotne jest aby namespace nazywał się Sellintegro, a publiczna klasa External, w przeciwnym wypadku integracja nie uruchomi się. Ważne jest by metoda nazywała się ProcessTargetData i przyjmowała podane parametry.
Jeżeli metoda zwróci produkty, które nie istniały w momencie przekazania ich do metody, lista ta zostanie uzupełniona. Produkty w momencie podmiany danych są rozpoznawane po wartości <id>
oraz variant_id
z zwróconego XMLa
Kod w języku VBScript
Set xmlConfigObj = CreateObject("Microsoft.XMLDOM")
xmlConfigObj.async = "false"
xmlConfigObj.LoadXml(xml)
Set Root = xmlConfigObj.documentElement
result = Root.xml
W przypadku języka VBScript wejściową zmienną jest xml
oraz istotne jest przekazanie przetworzonego XMLa do zmiennej result
Jeżeli metoda zwróci produkty, które nie istniały w momencie przekazania ich do metody, lista ta zostanie uzupełniona. Produkty w momencie podmiany danych są rozpoznawane po wartości <id>
oraz variant_id
z zwróconego XMLa
Modyfikacja danych przed aktualizacją w systemie docelowym
Niezależnie od używanego języka skryptowego podczas uruchomienia zostanie przekazany następujący format XMLa:
<products>
<product>
<id>28050165</id>
<variant_id />
<symbol>A_GAZ_ZIEMNY</symbol>
<name>Gaz ziemny</name>
<ean></ean>
<unit />
<new_quantity>105</new_quantity>
<old_quantity>5</old_quantity>
<enabled>true</enabled>
</product>
<product>
<id>28050166</id>
<variant_id />
<symbol>A_OLEJ</symbol>
<name>Olej napędowy</name>
<ean></ean>
<unit />
<new_quantity>105</new_quantity>
<old_quantity>5</old_quantity>
<enabled>true</enabled>
</product>
</products>
Po wywołaniu metody właściwości które ponownie ustawimy na źródle to:
- Symbol (string)
- Nazwa (string)
- Ean (string)
- Jednostka miary (string)
- Nowa ilość (decimal)
- Czy produkt jest widoczny/aktywny (bool)
Na tym etapie podmieniamy wartości na liście nie usuwamy ani nie dodajemy nowych, wyznacznikiem podmiany jest <id>
wraz z <variant_id>
.
Kod w języku C#
using System;
using System.Xml.Linq;
using System.Linq;
namespace Sellintegro
{
public class External
{
public XElement ProcessFinalData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
return bodyXml;
}
}
}
Istotne jest aby namespace nazywał się Sellintegro, a publiczna klasa External, w przeciwnym wypadku integracja nie uruchomi się. Ważne jest by metoda nazywała się ProcessFinalData i przyjmowała podane parametry.
Kod w języku VBScript
Set xmlConfigObj = CreateObject("Microsoft.XMLDOM")
xmlConfigObj.async = "false"
xmlConfigObj.LoadXml(xml)
Set Root = xmlConfigObj.documentElement
result = Root.xml
W przypadku języka VBScript wejściową zmienną jest xml
oraz istotne jest przekazanie przetworzonego XMLa do zmiennej result
Przypadki użycia
Poniżej przedstawiamy popularne przypadki zaimplementowane dla stanów magazynowych, które pojawiły się w SellIntegro.
Dodaj 5 sztuk do stanu, dla każdego towaru
Pania Jadzia dolicza sobie zawsze do każdego produktu +5 sztuk, ponieważ mają otwarty “kredyt” u dostawców i na magazynie zawsze jest towar ze zwrotu, przez co musi ustawiać stan na aukcjach ręcznie.
Kod w języku C#
using System;
using System.Xml.Linq;
using System.Linq;
namespace Sellintegro
{
public class External
{
public XElement ProcessSourceData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
foreach (XElement item in bodyXml.Elements("product"))
{
decimal quantity = 0;
decimal.TryParse(item.Element("quantity").Value.Replace(".",","), out quantity);
writeInfo("Po przetwarzaniu = " + quantity);
item.Element("quantity").Value = (quantity + 5).ToString();
}
return bodyXml;
}
}
}
Kod w języku VBScript
Set xmlConfigObj = CreateObject("Microsoft.XMLDOM")
xmlConfigObj.async = "false"
xmlConfigObj.LoadXml(xml)
Set Root = xmlConfigObj.documentElement
Set NodeList = Root.getElementsByTagName("product")
For Each Elem In NodeList
Elem.SelectSingleNode("quantity").Text = CDbl(Replace( Elem.SelectSingleNode("quantity").Text ,".",",")) +5
Next
result = Root.xml
Zewnętrzny plik z produktami
Pan Janusz ma dodatkowy plik z produktami, o który chciałby uzupełnić listę produktów do synchronizacji, bo teraz produkty są sprzedawane jako “wiecznie dostępne”
Kod w języku C#
using System;
using System.Xml.Linq;
using System.IO;
using System.Collections.Generic;
using System.Linq;
namespace Sellintegro
{
public class External
{
public XElement ProcessSourceData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
var data = "";
using(StreamReader reader =
new StreamReader(@"C:\Users\Admin\Desktop\PlikDoIntegracji.txt"))
{
data = reader.ReadToEnd();
}
var parsedData = XElement.Parse(data);
foreach (var item in parsedData.Elements("Towar"))
{
bodyXml.Add(new XElement("product",
new XElement("id", -1),
new XElement("symbol", item.Element("Symbol").Value),
new XElement("name", "Name"),
new XElement("ean", "Ean"),
new XElement("unit", "A unit"),
new XElement("quantity", item.Element("Ilosc").Value),
new XElement("reserved", item.Element("Ilosc").Value),
new XElement("inStock", item.Element("Ilosc").Value),
new XElement("features", ""),
new XElement("customFields", new Dictionary<string, string>())
));
}
return bodyXml;
}
}
}
Kod w języku VBScript
Set objXMLDoc = CreateObject("Microsoft.XMLDOM")
objXMLDoc.async = False
objXMLDoc.load("C:\Users\test\Desktop\PlikDoIntegracji.txt")
Set Root = objXMLDoc.documentElement
Set NodeList = Root.getElementsByTagName("Towar")
Set mainXml = CreateObject("Microsoft.XMLDOM")
mainXml.async = False
mainXml.LoadXml(xml)
For Each Elem In NodeList
Set objProductNode = mainXml.createElement("product")
Set objNewId = mainXml.createElement("id")
Set objNewIdValue = mainXml.createTextNode(Elem.SelectSingleNode("Id").text)
objNewId.appendChild(objNewIdValue)
objProductNode.appendChild(objNewId)
Set objNewSymbol = mainXml.createElement("symbol")
Set objNewSymbolValue = mainXml.createTextNode(Elem.SelectSingleNode("Symbol").text)
objNewSymbol.appendChild(objNewSymbolValue)
objProductNode.appendChild(objNewSymbol)
Set objNewName = mainXml.createElement("name")
Set objNewNameValue = mainXml.createTextNode(Elem.SelectSingleNode("Nazwa").text)
objNewName.appendChild(objNewNameValue)
objProductNode.appendChild(objNewName)
Set objNewEan = mainXml.createElement("ean")
Set objNewEanValue = mainXml.createTextNode(Elem.SelectSingleNode("Kod_Kreskowy").text)
objNewEan.appendChild(objNewEanValue)
objProductNode.appendChild(objNewEan)
Set objNewUnit = mainXml.createElement("unit")
Set objNewUnitValue = mainXml.createTextNode(Elem.SelectSingleNode("Jednostka").text)
objNewUnit.appendChild(objNewUnitValue)
objProductNode.appendChild(objNewUnit)
Set objNewReserverd = mainXml.createElement("reserved")
Set objNewReserverdValue = mainXml.createTextNode(Elem.SelectSingleNode("Zarezerwowane").text)
objNewReserverd.appendChild(objNewReserverdValue)
objProductNode.appendChild(objNewReserverd)
Set objNewInStock = mainXml.createElement("inStock")
Set objNewInStockValue = mainXml.createTextNode(Elem.SelectSingleNode("Na_Stanie").text)
objNewInStock.appendChild(objNewInStockValue)
objProductNode.appendChild(objNewInStock)
Set objNewQuantity = mainXml.createElement("quantity")
Set objNewQuantityValue = mainXml.createTextNode(Elem.SelectSingleNode("Ilosc").text)
objNewQuantity.appendChild(objNewQuantityValue)
objProductNode.appendChild(objNewQuantity)
Set objNewFeatures = mainXml.createElement("features")
objProductNode.appendChild(objNewFeatures)
Set objNewCustomFields = mainXml.createElement("customFields")
objProductNode.appendChild(objNewCustomFields)
Set objCurrNode = mainXml.documentElement
objCurrNode.appendChild(objProductNode)
Next
result = mainXml.documentElement.xml
Zewnętrzny plik z stanami
Pan Arek ma dodatkowy plik z stanami, z którym chciałby sumować listę stanów do synchronizacji.
Kod w języku C#
using System;
using System.Xml.Linq;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
namespace Sellintegro
{
public class External
{
public XElement ProcessSourceData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
var data = "";
using(StreamReader reader = new
StreamReader(@"C:\Users\Admin\Desktop\PlikDoIntegracjiArek.txt"))
{
data = reader.ReadToEnd();
}
var parsedData = XElement.Parse(data);
foreach (var item in parsedData.Elements("Towar"))
{
var originalProduct = bodyXml.Elements("product")
.Where(x => x.Element("symbol")
.Value == item.Element("Symbol").Value).FirstOrDefault();
if (originalProduct != null)
{
decimal originalQuantity = 0;
decimal additionalQuantity = 0;
decimal.TryParse(originalProduct.Element("quantity").Value,
NumberStyles.Any,
CultureInfo.InvariantCulture,
out originalQuantity);
decimal.TryParse(item.Element("Ilosc").Value,
NumberStyles.Any,
CultureInfo.InvariantCulture,
out additionalQuantity);
originalProduct.Element("quantity")
.Value = (originalQuantity + additionalQuantity).ToString();
originalProduct.Element("reserved")
.Value = (originalQuantity + additionalQuantity).ToString();
originalProduct.Element("inStock")
.Value = (originalQuantity + additionalQuantity).ToString();
}
}
return bodyXml;
}
}
}
Kod w języku VBScript
Set objXMLDoc = CreateObject("Microsoft.XMLDOM")
objXMLDoc.async = False
objXMLDoc.load("C:\Users\test\Desktop\PlikDoIntegracjiSumowanie.txt")
Set Root = objXMLDoc.documentElement
Set NodeList = Root.getElementsByTagName("Towar")
Set mainXml = CreateObject("Microsoft.XMLDOM")
mainXml.async = False
mainXml.LoadXml(xml)
mainXml.setProperty "SelectionLanguage", "XPath"
Set mainXmlRoot = mainXml.documentElement
Set MainNodeList = mainXmlRoot.getElementsByTagName("product")
For Each Elem In NodeList
Set test = mainXml.selectSingleNode("products/product[symbol='"& Elem.SelectSingleNode("Symbol").text & "']")
If Not test Is Nothing Then
test.SelectSingleNode("quantity").Text = CDbl(Replace( Elem.SelectSingleNode("Ilosc").Text ,".",",")) + CDbl(Replace( test.SelectSingleNode("quantity").Text ,".",","))
End if
Next
result = mainXml.documentElement.xml
Zewnętrzny plik z stanami
Pan Arek ma dodatkowy plik z stanami, z którego chciałby sumować listę dostępnych sztuk towarów do synchronizacji.
Kod w języku C#
using System;
using System.Xml.Linq;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
namespace Sellintegro
{
public class External
{
public XElement ProcessSourceData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
var data = "";
using(StreamReader reader = new
StreamReader(@"C:\Users\Admin\Desktop\PlikDoIntegracjiArek.txt"))
{
data = reader.ReadToEnd();
}
var parsedData = XElement.Parse(data);
foreach (var item in parsedData.Elements("Towar"))
{
var originalProduct = bodyXml.Elements("product")
.Where(x => x.Element("symbol")
.Value == item.Element("Symbol").Value).FirstOrDefault();
if (originalProduct != null)
{
decimal originalQuantity = 0;
decimal additionalQuantity = 0;
decimal.TryParse(originalProduct.Element("quantity").Value,
NumberStyles.Any,
CultureInfo.InvariantCulture,
out originalQuantity);
decimal.TryParse(item.Element("Ilosc").Value,
NumberStyles.Any,
CultureInfo.InvariantCulture,
out additionalQuantity);
originalProduct.Element("quantity")
.Value = (originalQuantity + additionalQuantity).ToString();
originalProduct.Element("reserved")
.Value = (originalQuantity + additionalQuantity).ToString();
originalProduct.Element("inStock")
.Value = (originalQuantity + additionalQuantity).ToString();
}
}
return bodyXml;
}
}
}
Kod w języku VBScript
Set objXMLDoc = CreateObject("Microsoft.XMLDOM")
objXMLDoc.async = False
objXMLDoc.load("C:\Users\test\Desktop\PlikDoIntegracjiSumowanie.txt")
Set Root = objXMLDoc.documentElement
Set NodeList = Root.getElementsByTagName("Towar")
Set mainXml = CreateObject("Microsoft.XMLDOM")
mainXml.async = False
mainXml.LoadXml(xml)
mainXml.setProperty "SelectionLanguage", "XPath"
Set mainXmlRoot = mainXml.documentElement
Set MainNodeList = mainXmlRoot.getElementsByTagName("product")
For Each Elem In NodeList
Set test = mainXml.selectSingleNode("products/product[symbol='"& Elem.SelectSingleNode("Symbol").text & "']")
If Not test Is Nothing Then
test.SelectSingleNode("quantity").Text = CDbl(Replace( Elem.SelectSingleNode("Ilosc").Text ,".",",")) + CDbl(Replace( test.SelectSingleNode("quantity").Text ,".",","))
End if
Next
result = mainXml.documentElement.xml
Błędne symbole produktów
Pan Mirek zatrudniał stażystę, który źle uzupełnił kody produktów i teraz trzeba usuwać z nich końcówki takie jak .amz lub .amf, chciałby aby integracja ignorowała pewne ciągi znaków
Kod w języku C#
using System;
using System.Xml.Linq;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
namespace Sellintegro
{
public class External
{
public XElement ProcessSourceData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
foreach (XElement item in bodyXml.Elements("product"))
{
item.Element("symbol")
.Value = item.Element("symbol")
.Value.Replace(".AMZ", "").Replace(".AMF", "");
}
return bodyXml;
}
}
}
Kod w języku VBScript
Set xmlConfigObj = CreateObject("Microsoft.XMLDOM")
xmlConfigObj.async = "false"
xmlConfigObj.LoadXml(xml)
Set Root = xmlConfigObj.documentElement
Set NodeList = Root.getElementsByTagName("product")
For Each Elem In NodeList
Elem.SelectSingleNode("symbol").Text = Replace(Elem.SelectSingleNode("symbol").Text ,".AMZ","")
Elem.SelectSingleNode("symbol").Text = Replace(Elem.SelectSingleNode("symbol").Text ,".AMF","")
Next
result = Root.xml
Przeliczanie opakowań
Pan Łukasz kupuje w kartonach a sprzedaje w sztukach, stąd w kodach produktów ma wpisane “[100]”, chciałby liczby pomiędzy nawiasami wymnożyć przez aktualny stan
Kod w języku C#
using System;
using System.Xml.Linq;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
namespace Sellintegro
{
public class External
{
public XElement ProcessSourceData(Action<string> writeError,
Action<string> writeWarning,
Action<string> writeInfo,
XElement bodyXml)
{
foreach (XElement item in bodyXml.Elements("product"))
{
item.Element("symbol")
.Value = item.Element("symbol")
.Value.Replace(".amz", "").Replace(".amf", "");
try
{
decimal originalQuantity = 0;
decimal multiplier = 0;
var output = item.Element("symbol")
.Value.Split(new char[] { '[', ']' })[1];
decimal.TryParse(item.Element("quantity").Value,
NumberStyles.Any,
CultureInfo.InvariantCulture,
out originalQuantity);
decimal.TryParse(output,
NumberStyles.Any,
CultureInfo.InvariantCulture,
out multiplier);
item.Element("quantity")
.Value = (originalQuantity * multiplier).ToString();
item.Element("reserved")
.Value = (originalQuantity * multiplier).ToString();
item.Element("inStock")
.Value = (originalQuantity * multiplier).ToString();
}
catch (Exception)
{
var symbol = item.Element("symbol").Value;
writeError(symbol + "Nie posiada mnożnika");
}
}
return bodyXml;
}
}
}
Kod w języku VBScript
Set xmlConfigObj = CreateObject("Microsoft.XMLDOM")
xmlConfigObj.async = "false"
xmlConfigObj.LoadXml(xml)
Set Root = xmlConfigObj.documentElement
Set NodeList = Root.getElementsByTagName("product")
Set oRegExp = New RegExp
oRegExp.Pattern = "\[(.*?)\]"
For Each Elem In NodeList
Dim multiplier
Set Matches = oRegExp.Execute(Elem.SelectSingleNode("symbol").Text)
If Matches.Count > 0 Then
mnoznik = Matches(0).SubMatches(0)
Elem.SelectSingleNode("quantity").Text = CDbl(Replace( Elem.SelectSingleNode("quantity").Text ,".",",")) * cint(multiplier)
End If
Next
result = Root.xml