13-02-2025, Saat: 11:03
Merhabalar, uzun zamandır hayatımdaki artan tempo nedeniyle paylaşım yapmıyordum,. Shopify ile ürün entegrasyonu yapmam gerekti, birilerine de lazım olur diye buraya bırakıyorum. Saygılar.
Kullanım Örneği Stok Gönderimi;
Kullanım Örneği ÜrünListesi;
unit ShopifyLib;
interface
uses SysUtils, Classes, REST.Types, REST.Client, Data.Bind.Components, Data.Bind.ObjectScope, Soap.XSBuiltIns, Dialogs, superobject, Math, DateUtils;
type TShopifyLogProc = procedure (const AHandle: Cardinal; const ADirName, AValue: String; const AMemoLog: Boolean);
type
TShopifyVariant = record
product_id : String;
id : String;
title : String;
price : Extended;
position : Integer;
sku : String; // Stock code
inventory_quantity : Extended; // Envanter
end;
type TShopifyVariantList = Array of TShopifyVariant;
type
TShopifyProduct = record
id : String;
title : String;
status : String;
vendor : String;
handle : String;
created_at : TDateTime;
updated_at : TDateTime;
variants : TShopifyVariantList;
end;
type TShopifyProductList = Array of TShopifyProduct;
type
TNewOption = record
name : String;
values : Array of String;
end;
type TNewOptionList = Array of TNewOption;
type
TNewImages = record
base64 : String;
end;
type TNewImagesList = Array of TNewImages;
type
TNewVariant = record
option1 : String;
option2 : String;
option3 : String;
title : String;
price : Extended;
barcode : String;
sku : String;
requires_shipping : Boolean;
taxable : Boolean;
inventory_management : String;
inventory_policy : String;
inventory_quantity : Extended;
VariantImageSet : Boolean;
images : TNewImagesList;
end;
type TNewVariantList = Array of TNewVariant;
type
TNewProduct = record
title : String;
body_html : String;
published_scope : String;
tags : String;
status : String;
vendor : String;
shopifyProductId : String;
options : TNewOptionList;
variants : TNewVariantList;
end;
type
TShopifyCollectionRules = record
column : String;
relation : String;
condition : String;
end;
type TShopifyCollectionRulesList = Array of TShopifyCollectionRules;
type
TShopifyCollection = record
id : String;
title : String;
rules : TShopifyCollectionRulesList;
end;
type TShopifyCollectionList = Array of TShopifyCollection;
type
TNewRules = record
column : String;
relation : String;
condition : String;
end;
type TNewRulesList = Array of TNewRules;
type
TNewCollection = record
title : String;
shopifyCollectionId : String;
imageBase64 : String;
rules : TShopifyCollectionRulesList;
end;
type
TNewCollectionResult = record
id : String;
errormessage : String;
end;
type
TNewImagesResult = record
id : String;
end;
type TNewImagesResultList = Array of TNewImagesResult;
type
TNewVariantResult = record
id : String;
sku : String;
end;
type TNewVariantResultList = Array of TNewVariantResult;
type
TNewProductResult = record
id : String;
errormessage : String;
variants : TNewVariantResultList;
images : TNewImagesResultList;
end;
type
TShopify = class(TComponent)
private
FMainUrl: String;
FVendor: String;
FAccessToken: String;
FRateLimitList : TStringList;
procedure LogAdd(const AValue:String; const AMemo:Boolean);
function UTCTimeToDateTime(const AUTCTime:String):TDateTime;
function ShopifyStrToFloat(const AStr:String):Extended;
function ShopifyFloatToStr(const AFloat:Extended):String;
function ShopifyRequest(const AUrl,ARequestType,ABody:String;AHeaderName,AHeaderValue,AParamName,AParamValue:Array of String):String;
public
FLogFormHandle : Cardinal;
FLogProc : TShopifyLogProc;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function GetProductList_Id(const AProductId,AFields:String; var ASuccess:Boolean):TShopifyProductList;
function DeleteProduct_Id(const AProductId:String):Boolean;
function SetProduct(const AProduct:TNewProduct;var AProductJson,AResultJson:String):TNewProductResult;
function UpdateVariantImage_Id(const AProductId,AImageId,AVariantId:String):Boolean;
function GetCollectionList_Id(const ACollectId,AFields:String; var ASuccess:Boolean):TShopifyCollectionList;
function DeleteCollection_Id(const ACollectId:String):Boolean;
function SetCollection(const ACollection:TNewCollection;var ACollectionJson,AResultJson:String):TNewCollectionResult;
published
property MainUrl:String read FMainUrl write FMainUrl;
property Vendor:String read FVendor write FVendor;
property AccessToken:String read FAccessToken write FAccessToken;
end;
implementation
{ TShopify }
constructor TShopify.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FLogFormHandle := 0;
FRateLimitList := TStringList.Create;
end;
function TShopify.DeleteCollection_Id(const ACollectId: String): Boolean;
var
xGetJson : String;
begin
Result := False;
try
xGetJson := ShopifyRequest(Format('/admin/api/2025-01/smart_collections/%s.json',[ACollectId]),'DELETE','',['X-Shopify-Access-Token'],[AccessToken],[],[]);
Result := Copy(xGetJson,1,2) = 'OK';
if not Result then
LogAdd(Format('Process
eleteCollection_Id Json:%s',[xGetJson]),True);
except
on e:Exception do
begin
LogAdd(Format('Process
eleteCollection_Id Message:%s Json:%s',[e.Message,xGetJson]),True);
end;
end;
end;
function TShopify.DeleteProduct_Id(const AProductId: String): Boolean;
var
xGetJson : String;
begin
Result := False;
try
xGetJson := ShopifyRequest(Format('/admin/api/2025-01/products/%s.json',[AProductId]),'DELETE','',['X-Shopify-Access-Token'],[AccessToken],[],[]);
Result := Copy(xGetJson,1,2) = 'OK';
if not Result then
LogAdd(Format('Process
eleteProduct_Id Json:%s',[xGetJson]),True);
except
on e:Exception do
begin
LogAdd(Format('Process
eleteProduct_Id Message:%s Json:%s',[e.Message,xGetJson]),True);
end;
end;
end;
destructor TShopify.Destroy;
begin
FRateLimitList.Free;
inherited;
end;
function TShopify.GetCollectionList_Id(const ACollectId, AFields: String; var ASuccess: Boolean): TShopifyCollectionList;
var
xGetJson : String;
xParamName,xParamValue : Array of String;
Ind, Ind2 : Integer;
xSO : ISuperObject;
xSACollect : TSuperArray;
xSARules : TSuperArray;
xHighP, xHighV : Integer;
begin
ASuccess := False;
SetLength(Result,0);
try
if not ACollectId.Trim.Equals('') then
begin
SetLength(xParamName,1);
SetLength(xParamValue,1);
xParamName[0] := 'ids';
xParamValue[0] := ACollectId;
end;
if not AFields.Trim.Equals('') then
begin
SetLength(xParamName,Length(xParamName)+1);
SetLength(xParamValue,Length(xParamValue)+1);
xParamName[Pred(Length(xParamName))] := 'fields';
xParamValue[Pred(Length(xParamName))] := AFields;
end;
xGetJson := ShopifyRequest('/admin/api/2025-01/smart_collections.json','GET','',['X-Shopify-Access-Token'],[AccessToken],xParamName,xParamValue);
if Copy(xGetJson,1,2) = 'OK' then
begin
xGetJson := Copy(xGetJson,4,MaxInt);
xSO := SO(xGetJson);
if xSO <> nil then
begin
ASuccess := True;
{$REGION 'Products'}
xSACollect := xSO.A['smart_collections'];
for Ind := 0 to Pred(xSACollect.Length) do
begin
SetLength(Result,Succ(Length(Result)));
xHighP := Pred(Length(Result));
with Result[xHighP] do
begin
id := xSACollect[Ind].S['id'];
title := xSACollect[Ind].S['title'];
end;
if xSACollect[Ind].O['rules'] <> nil then
begin
{$REGION 'rules'}
xSARules := xSACollect[Ind].A['rules'];
for Ind2 := 0 to Pred(xSARules.Length) do
begin
SetLength(Result[xHighP].rules,Succ(Length(Result[xHighP].rules)));
xHighV := Pred(Length(Result[xHighP].rules));
with Result[xHighP].rules[xHighV] do
begin
column := xSARules[Ind2].S['column'];
relation := xSARules[Ind2].S['relation'];
condition := xSARules[Ind2].S['condition'];
end;
end;
{$ENDREGION}
end;
end;
{$ENDREGION}
end
else
LogAdd(Format('Process:GetCollectionList_Id JsonParseError:%s',[xGetJson]),True);
end
else
LogAdd(Format('Process:GetCollectionList_Id Json:%s',[xGetJson]),True);
except
on e:Exception do
begin
LogAdd(Format('Process:GetCollectionList_Id Message:%s Json:%s',[e.Message,xGetJson]),True);
end;
end;
end;
function TShopify.GetProductList_Id(const AProductId, AFields: String; var ASuccess:Boolean): TShopifyProductList;
var
xGetJson : String;
xParamName,xParamValue : Array of String;
Ind, Ind2 : Integer;
xSO : ISuperObject;
xSAProducts : TSuperArray;
xSAVariants : TSuperArray;
xHighP, xHighV : Integer;
begin
ASuccess := False;
SetLength(Result,0);
try
if not AProductId.Trim.Equals('') then
begin
SetLength(xParamName,1);
SetLength(xParamValue,1);
xParamName[0] := 'ids';
xParamValue[0] := AProductId;
end;
if not AFields.Trim.Equals('') then
begin
SetLength(xParamName,Length(xParamName)+1);
SetLength(xParamValue,Length(xParamValue)+1);
xParamName[Pred(Length(xParamName))] := 'fields';
xParamValue[Pred(Length(xParamName))] := AFields;
end;
xGetJson := ShopifyRequest('/admin/api/2025-01/products.json','GET','',['X-Shopify-Access-Token'],[AccessToken],xParamName,xParamValue);
if Copy(xGetJson,1,2) = 'OK' then
begin
xGetJson := Copy(xGetJson,4,MaxInt);
xSO := SO(xGetJson);
if xSO <> nil then
begin
ASuccess := True;
{$REGION 'Products'}
xSAProducts := xSO.A['products'];
for Ind := 0 to Pred(xSAProducts.Length) do
begin
SetLength(Result,Succ(Length(Result)));
xHighP := Pred(Length(Result));
with Result[xHighP] do
begin
id := xSAProducts[Ind].S['id'];
title := xSAProducts[Ind].S['title'];
status := xSAProducts[Ind].S['status'];
vendor := xSAProducts[Ind].S['vendor'];
handle := xSAProducts[Ind].S['handle'];
if not xSAProducts[Ind].S['created_at'].Trim.Equals('') then
created_at := UTCTimeToDateTime(xSAProducts[Ind].S['created_at']);
if not xSAProducts[Ind].S['updated_at'].Trim.Equals('') then
updated_at := UTCTimeToDateTime(xSAProducts[Ind].S['updated_at']);
end;
if xSAProducts[Ind].O['variants'] <> nil then
begin
{$REGION 'Variants'}
xSAVariants := xSAProducts[Ind].A['variants'];
for Ind2 := 0 to Pred(xSAVariants.Length) do
begin
SetLength(Result[xHighP].variants,Succ(Length(Result[xHighP].variants)));
xHighV := Pred(Length(Result[xHighP].variants));
with Result[xHighP].variants[xHighV] do
begin
product_id := xSAVariants[Ind2].S['product_id'];
id := xSAVariants[Ind2].S['id'];
title := xSAVariants[Ind2].S['title'];
price := ShopifyStrToFloat(xSAVariants[Ind2].S['price']);
position := xSAVariants[Ind2].I['position'];
sku := xSAVariants[Ind2].S['sku'];
inventory_quantity := xSAVariants[Ind2].D['inventory_quantity'];
end;
end;
{$ENDREGION}
end;
end;
{$ENDREGION}
end
else
LogAdd(Format('Process:GetProductList_Id JsonParseError:%s',[xGetJson]),True);
end
else
LogAdd(Format('Process:GetProductList_Id Json:%s',[xGetJson]),True);
except
on e:Exception do
begin
LogAdd(Format('Process:GetProductList_Id Message:%s Json:%s',[e.Message,xGetJson]),True);
end;
end;
end;
procedure TShopify.LogAdd(const AValue: String; const AMemo: Boolean);
begin
if (FLogFormHandle > 0) and Assigned(FLogProc) then
begin
FLogProc(FLogFormHandle,'ShopifyLibLog',AValue,AMemo);
end;
end;
function TShopify.SetCollection(const ACollection: TNewCollection; var ACollectionJson, AResultJson: String): TNewCollectionResult;
var
Ind : Integer;
xUrl,xMethod : String;
xUpdate : Boolean;
xGetJson : String;
GccSuccess : Boolean;
xSOMain, xSOCollect : ISuperObject;
xSARules : TSuperArray;
xSOTmpItem : ISuperObject;
xSOResult : ISuperObject;
begin
Result.id := '';
Result.errormessage := '';
try
xUpdate := False;
if not ACollection.shopifyCollectionId.Trim.Equals('') then
begin
xUpdate := Length(GetCollectionList_Id(ACollection.shopifyCollectionId,'id',GccSuccess)) > 0;
if not GccSuccess then
begin
Result.errormessage := Format('Process:SetCollection update collection->GetCollectionList_Id get error!',[]);
LogAdd(Result.errormessage,True);
Exit;
end;
end;
if not xUpdate then
begin
xUrl := '/admin/api/2025-01/smart_collections.json';
xMethod := 'POST';
end
else
begin
xUrl := Format('/admin/api/2025-01/smart_collections/%s.json',[ACollection.shopifyCollectionId]);
xMethod := 'PUT';
end;
xSOMain := SO();
xSOMain.O['smart_collection'] := SO();
xSOCollect := xSOMain.O['smart_collection'];
xSOCollect.S['title'] := ACollection.title;
xSOCollect.B['disjunctive'] := True; // any condition
if Length(ACollection.rules) > 0 then
begin
xSOCollect.O['rules'] := SA([]);
xSARules := xSOCollect.A['rules'];
for Ind := Low(ACollection.rules) to High(ACollection.rules) do
begin
xSOTmpItem := SO();
xSOTmpItem.S['column'] := ACollection.rules[Ind].column;
xSOTmpItem.S['relation'] := ACollection.rules[Ind].relation;
xSOTmpItem.S['condition'] := ACollection.rules[Ind].condition;
xSARules.Add(xSOTmpItem);
end;
end;
if not ACollection.imageBase64.Trim.Equals('') then
begin
xSOMain.O['image'] := SO();
xSOMain.O['image'].S['attachment'] := ACollection.imageBase64;
end;
xGetJson := ShopifyRequest(xUrl,xMethod,xSOMain.AsJSon(),['X-Shopify-Access-Token'],[AccessToken],[],[]);
ACollectionJson := xSOMain.AsJSon();
AResultJson := xGetJson;
if Copy(xGetJson,1,2) = 'OK' then
begin
xGetJson := Copy(xGetJson,4,MaxInt);
xSOResult := SO(xGetJson);
if xSOResult <> nil then
begin
Result.id := xSOResult.O['smart_collection'].S['id'];
end
else
begin
Result.errormessage := Format('Process:SetCollection JsonParseError:%s',[xGetJson]);
LogAdd(Result.errormessage,True);
end;
end
else
begin
Result.errormessage := Format('Process:SetCollection Json:%s',[xGetJson]);
LogAdd(Result.errormessage,True);
end;
except
on e:Exception do
begin
Result.errormessage := Format('Process:SetCollection Message:%s Json:%s',[e.Message,xGetJson]);
LogAdd(Result.errormessage,True);
end;
end;
end;
function TShopify.SetProduct(const AProduct: TNewProduct; var AProductJson, AResultJson: String): TNewProductResult;
var
Ind,Ind2,Ind3 : Integer;
xUrl,xMethod : String;
xUpdate : Boolean;
xGetJson : String;
CountIndex, GccIndex : Integer;
GccSuccess : Boolean;
xSOMain, xSOProduct : ISuperObject;
xSAOptions, xSAVariants, xSAImages : TSuperArray;
xSOTmpItem : ISuperObject;
xSOResult : ISuperObject;
begin
Result.id := '';
Result.errormessage := '';
SetLength(Result.variants,0);
try
xUpdate := False;
if not AProduct.shopifyProductId.Trim.Equals('') then
begin
xUpdate := Length(GetProductList_Id(AProduct.shopifyProductId,'id',GccSuccess)) > 0;
if not GccSuccess then
begin
Result.errormessage := Format('Process:SetProduct update product->GetProductList_Id get error!',[]);
LogAdd(Result.errormessage,True);
Exit;
end;
end;
if not xUpdate then
begin
xUrl := '/admin/api/2025-01/products.json';
xMethod := 'POST';
end
else
begin
xUrl := Format('/admin/api/2025-01/products/%s.json',[AProduct.shopifyProductId]);
xMethod := 'PUT';
end;
xSOMain := SO();
xSOMain.O['product'] := SO();
xSOProduct := xSOMain.O['product'];
xSOProduct.S['title'] := AProduct.title;
xSOProduct.S['body_html'] := AProduct.body_html;
xSOProduct.S['published_scope'] := AProduct.published_scope;
xSOProduct.S['tags'] := AProduct.tags;
xSOProduct.S['status'] := AProduct.status;
xSOProduct.S['vendor'] := AProduct.vendor;
if Length(AProduct.options) > 0 then
begin
xSOProduct.O['options'] := SA([]);
xSAOptions := xSOProduct.A['options'];
for Ind := Low(AProduct.options) to High(AProduct.options) do
begin
xSOTmpItem := SO();
xSOTmpItem.S['name'] := AProduct.options[Ind].name;
xSOTmpItem.O['values'] := SA([]);
for Ind2 := Low(AProduct.options[Ind].values) to High(AProduct.options[Ind].values) do
xSOTmpItem.A['values'].Add(AProduct.options[Ind].values[Ind2]);
xSAOptions.Add(xSOTmpItem);
end;
end;
xSOProduct.O['variants'] := SA([]);
xSAVariants := xSOProduct.A['variants'];
for Ind := Low(AProduct.variants) to High(AProduct.variants) do
begin
xSOTmpItem := SO();
if not AProduct.variants[Ind].option1.Trim.Equals('') then
xSOTmpItem.S['option1'] := AProduct.variants[Ind].option1
else
xSOTmpItem.O['option1'] := TSuperObject.Create(stNull);
if not AProduct.variants[Ind].option2.Trim.Equals('') then
xSOTmpItem.S['option2'] := AProduct.variants[Ind].option2
else
xSOTmpItem.O['option2'] := TSuperObject.Create(stNull);
if not AProduct.variants[Ind].option3.Trim.Equals('') then
xSOTmpItem.S['option3'] := AProduct.variants[Ind].option3
else
xSOTmpItem.O['option3'] := TSuperObject.Create(stNull);
xSOTmpItem.S['title'] := AProduct.variants[Ind].title;
xSOTmpItem.S['price'] := ShopifyFloatToStr(AProduct.variants[Ind].price);
xSOTmpItem.S['barcode'] := AProduct.variants[Ind].barcode;
xSOTmpItem.B['requires_shipping'] := AProduct.variants[Ind].requires_shipping;
xSOTmpItem.B['taxable'] := AProduct.variants[Ind].taxable;
xSOTmpItem.S['sku'] := AProduct.variants[Ind].sku;
xSOTmpItem.S['inventory_management'] := AProduct.variants[Ind].inventory_management;
xSOTmpItem.S['inventory_policy'] := AProduct.variants[Ind].inventory_policy;
xSOTmpItem.I['inventory_quantity'] := Trunc(AProduct.variants[Ind].inventory_quantity);
xSAVariants.Add(xSOTmpItem);
end;
xSOProduct.O['images'] := SA([]);
xSAImages := xSOProduct.A['images'];
for Ind := Low(AProduct.variants) to High(AProduct.variants) do
begin
for Ind2 := Low(AProduct.variants[Ind].images) to High(AProduct.variants[Ind].images) do
begin
xSOTmpItem := SO();
xSOTmpItem.S['attachment'] := AProduct.variants[Ind].images[Ind2].base64;
xSAImages.Add(xSOTmpItem);
end;
end;
xGetJson := ShopifyRequest(xUrl,xMethod,xSOMain.AsJSon(),['X-Shopify-Access-Token'],[AccessToken],[],[]);
AProductJson := xSOMain.AsJSon();
AResultJson := xGetJson;
if Copy(xGetJson,1,2) = 'OK' then
begin
xGetJson := Copy(xGetJson,4,MaxInt);
xSOResult := SO(xGetJson);
if xSOResult <> nil then
begin
Result.id := xSOResult.O['product'].S['id'];
if xSOResult.O['product'].O['variants'] <> nil then
begin
SetLength(Result.variants,xSOResult.O['product'].A['variants'].Length);
for Ind := 0 to Pred(xSOResult.O['product'].A['variants'].Length) do
begin
Result.variants[Ind].id := xSOResult.O['product'].A['variants'][Ind].S['id'];
Result.variants[Ind].sku := xSOResult.O['product'].A['variants'][Ind].S['sku'];
end;
end;
if xSOResult.O['product'].O['images'] <> nil then
begin
SetLength(Result.images,xSOResult.O['product'].A['images'].Length);
for Ind := 0 to Pred(xSOResult.O['product'].A['images'].Length) do
begin
Result.images[Ind].id := xSOResult.O['product'].A['images'][Ind].S['id'];
end;
end;
{$REGION 'Variant First Image Set'}
for Ind := Low(AProduct.variants) to High(AProduct.variants) do
begin
if AProduct.variants[Ind].VariantImageSet and (Length(AProduct.variants[Ind].images) > 0) and (not AProduct.variants[Ind].sku.Trim.Equals('')) then
begin
CountIndex := -1;
GccIndex := -1;
for Ind2 := Low(AProduct.variants) to High(AProduct.variants) do
begin
if GccIndex > -1 then
Break;
for Ind3 := Low(AProduct.variants[Ind2].images) to High(AProduct.variants[Ind2].images) do
begin
Inc(CountIndex);
if AProduct.variants[Ind].sku = AProduct.variants[Ind2].sku then
begin
GccIndex := CountIndex;
Break;
end;
end;
end;
if GccIndex > -1 then
begin
if High(Result.images)>=GccIndex then
begin
UpdateVariantImage_Id(Result.id,Result.images[GccIndex].id,Result.variants[Ind].id);
end;
end;
end;
end;
{$ENDREGION}
end
else
begin
Result.errormessage := Format('Process:SetProduct JsonParseError:%s',[xGetJson]);
LogAdd(Result.errormessage,True);
end;
end
else
begin
Result.errormessage := Format('Process:SetProduct Json:%s',[xGetJson]);
LogAdd(Result.errormessage,True);
end;
except
on e:Exception do
begin
Result.errormessage := Format('Process:SetProduct Message:%s Json:%s',[e.Message,xGetJson]);
LogAdd(Result.errormessage,True);
end;
end;
end;
function TShopify.ShopifyFloatToStr(const AFloat: Extended): String;
begin
Result := StringReplace(FloatToStr(SimpleRoundTo(AFloat,-2)),',','.',[rfReplaceAll]);
end;
function TShopify.ShopifyRequest(const AUrl, ARequestType, ABody: String; AHeaderName, AHeaderValue, AParamName, AParamValue: array of String): String;
var
GccDateTime : TDateTime;
SecondReqCount : Integer;
Ind : Integer;
xRESTClient: TRESTClient;
xRESTRequest: TRESTRequest;
xRESTResponse: TRESTResponse;
begin
{$REGION 'Rate Limit'}
// 1 second max 2 req or 60 second max 40 req
while True do
begin
SecondReqCount := 0;
for Ind := FRateLimitList.Count-1 downto 0 do
begin
GccDateTime := StrToDateTime(FRateLimitList[Ind]);
if MilliSecondsBetween(Now,GccDateTime) <= 1000 then
Inc(SecondReqCount);
if MilliSecondsBetween(Now,StrToDateTime(FRateLimitList[Ind])) > 60000 then
FRateLimitList.Delete(Ind);
end;
if (SecondReqCount>=2) or (FRateLimitList.Count>=40) then
Sleep(1000)
else
Break;
end;
{$ENDREGION}
Result := '';
try
xRESTClient := TRESTClient.Create(nil);
xRESTResponse := TRESTResponse.Create(nil);
xRESTRequest := TRESTRequest.Create(nil);
try
with xRESTClient do
begin
BaseURL := FMainUrl + AUrl;
ConnectTimeout := 10000;
ReadTimeout := 30000;
end;
with xRESTRequest do
begin
AssignedValues := [TAssignedValue.rvConnectTimeout, TAssignedValue.rvReadTimeout];
Client := xRESTClient;
Response := xRESTResponse;
ConnectTimeout := 10000;
ReadTimeout := 30000;
if ARequestType = 'POST' then
begin
Method := rmPOST;
if ABody.Trim <> '' then
Params.AddItem('BodyPost',ABody, TRESTRequestParameterKind.pkREQUESTBODY, [], TRESTContentType.ctAPPLICATION_JSON);
end
else if ARequestType = 'PUT' then
begin
Method := rmPUT;
if ABody.Trim <> '' then
Params.AddItem('BodyPost',ABody, TRESTRequestParameterKind.pkREQUESTBODY, [], TRESTContentType.ctAPPLICATION_JSON);
end
else if ARequestType = 'GET' then
Method := rmGET
else if ARequestType = 'DELETE' then
Method := rmDELETE;
for Ind := Low(AHeaderName) to High(AHeaderName) do
Params.AddHeader(AHeaderName[Ind],AHeaderValue[Ind]);
for Ind := Low(AParamName) to High(AParamName) do
Params.AddItem(AParamName[Ind],AParamValue[Ind],pkGETorPOST,[]);
end;
FRateLimitList.Add(DateTimeToStr(Now));
xRESTRequest.Execute;
if xRESTResponse.StatusCode in [200,201] then
Result := 'OK=' + xRESTResponse.Content
else
Result := 'ERROR=' + Format('Process:ShopifyRequest Url:%s, Method:%s, Status:%d, Content:%s',[AUrl,ARequestType,xRESTResponse.StatusCode,xRESTResponse.Content]);
finally
FreeAndNil(xRESTRequest);
FreeAndNil(xRESTResponse);
FreeAndNil(xRESTClient);
end;
except
on e:Exception do
begin
Result := 'ERROR=' + Format('Process:ShopifyRequest Url:%s, Method:%s, Message:%s',[AUrl,ARequestType,e.Message]);
end;
end;
end;
function TShopify.ShopifyStrToFloat(const AStr: String): Extended;
begin
try
Result := StrToFloatDef(StringReplace(AStr,'.',FormatSettings.DecimalSeparator,[rfReplaceAll]),0);
except
Result := 0;
end;
end;
function TShopify.UpdateVariantImage_Id(const AProductId, AImageId, AVariantId: String): Boolean;
var
xGetJson : String;
xSO : ISuperObject;
begin
Result := False;
try
xSO := SO();
xSO.O['image'] := SO();
xSO.O['image'].O['variant_ids'] := SA([]);
xSO.O['image'].A['variant_ids'].Add(AVariantId);
xGetJson := ShopifyRequest(Format('//admin/api/2025-01/products/%s/images/%s.json',[AProductId,AImageId]),'PUT',xSO.AsJSon(),['X-Shopify-Access-Token'],[AccessToken],[],[]);
Result := Copy(xGetJson,1,2) = 'OK';
if not Result then
LogAdd(Format('Process:UpdateVariantImage_Id Json:%s',[xGetJson]),True);
except
on e:Exception do
begin
LogAdd(Format('Process:UpdateVariantImage_Id Message:%s Json:%s',[e.Message,xGetJson]),True);
end;
end;
end;
function TShopify.UTCTimeToDateTime(const AUTCTime: String): TDateTime;
var
xDateTime : TXSDateTime;
begin
try
xDateTime := TXSDateTime.Create;
try
xDateTime.XSToNative(AUTCTime);
Result := xDateTime.AsDateTime;
finally
FreeAndNil(xDateTime);
end;
except
Result := 0;
end;
end;
end.
Kullanım Örneği Stok Gönderimi;
procedure TForm4.Button3Click(Sender: TObject);
var
Ind : Integer;
xShopify : TShopify;
xProduct : TNewProduct;
xResult : TNewProductResult;
xProductJson, xResponseJson : String;
begin
Memo1.Lines.Clear;
xShopify := TShopify.Create(Self);
try
xShopify.MainUrl := 'https://xxx.myshopify.com';
xShopify.Vendor := 'MyFirm';
xShopify.AccessToken := 'xxx';
xProduct.title := 'Megane 2 Oksijen Sensörü';
xProduct.body_html := '<strong> Açıklama Test</strong>';
xProduct.published_scope := 'global';
xProduct.tags := 'Renault, Megane';
xProduct.status := 'active';
xProduct.vendor := 'MyFirm';
xProduct.shopifyProductId := '7916363153468';
SetLength(xProduct.options,2);
xProduct.options[0].name := 'Marka';
SetLength(xProduct.options[0].values,2);
xProduct.options[0].values[0] := 'Bosch';
xProduct.options[0].values[1] := 'KrofWall';
xProduct.options[1].name := 'Pin';
SetLength(xProduct.options[1].values,2);
xProduct.options[1].values[0] := '3 Pin';
xProduct.options[1].values[1] := '4 Pin';
SetLength(xProduct.variants,2);
xProduct.variants[0].option1 := 'Bosch';
xProduct.variants[0].option2 := '4 Pin';
xProduct.variants[0].title := 'Ürün A';
xProduct.variants[0].price := 1499.99;
xProduct.variants[0].barcode := '';
xProduct.variants[0].sku := 'stok_kodu1';
xProduct.variants[0].requires_shipping := True;
xProduct.variants[0].taxable := True;
xProduct.variants[0].inventory_management := 'shopify';
xProduct.variants[0].inventory_policy := 'continue';
xProduct.variants[0].inventory_quantity := 5;
xProduct.variants[0].VariantImageSet := True;
SetLength(xProduct.variants[0].images,1);
xProduct.variants[0].images[0].base64 := Image1Text;
xProduct.variants[1].option1 := 'KrofWall';
xProduct.variants[1].option2 := '4 Pin';
xProduct.variants[1].title := 'Ürün B';
xProduct.variants[1].price := 1099;
xProduct.variants[1].barcode := '';
xProduct.variants[1].sku := 'stok_kodu2';
xProduct.variants[1].requires_shipping := True;
xProduct.variants[1].taxable := True;
xProduct.variants[1].inventory_management := 'shopify';
xProduct.variants[1].inventory_policy := 'continue';
xProduct.variants[1].inventory_quantity := 10;
xProduct.variants[1].VariantImageSet := True;
SetLength(xProduct.variants[1].images,1);
xProduct.variants[1].images[0].base64 := Image2Text;
xResult := xShopify.SetProduct(xProduct,xProductJson,xResponseJson);
// ShowMessage('ProductJson' + sLineBreak + xProductJson);
// ShowMessage('ResponseJson' + sLineBreak + xResponseJson);
Memo1.Lines.Add(Format('productid: %s',[xResult.id]));
for Ind := Low(xResult.variants) to High(xResult.variants) do
Memo1.Lines.Add(Format('---> variantid: %s, variantsku: %s',[xResult.variants[Ind].id,xResult.variants[Ind].sku]));
finally
xShopify.Free;
end;
end;
Kullanım Örneği ÜrünListesi;
procedure TForm4.Button1Click(Sender: TObject);
var
Ind,Ind2 : Integer;
GccSuccess : Boolean;
xShopify : TShopify;
xProducts : TShopifyProductList;
begin
Memo1.Lines.Clear;
xShopify := TShopify.Create(Self);
try
xShopify.MainUrl := 'https://xxx.myshopify.com';
xShopify.Vendor := 'MyFirm';
xShopify.AccessToken := 'xxx';
xProducts := xShopify.GetProductList_Id('7914936467516','',GccSuccess);
for Ind := Low(xProducts) to High(xProducts) do
begin
Memo1.Lines.Add
(
Format(
'id:%s, title:%s'
,[xProducts[Ind].id,xProducts[Ind].title]
)
);
for Ind2 := Low(xProducts[Ind].variants) to High(xProducts[Ind].variants) do
Memo1.Lines.Add
(
Format(
'--->variant id:%s, sku:%s, title:%s, price:%s'
,[xProducts[Ind].variants[Ind2].id, xProducts[Ind].variants[Ind2].sku
,xProducts[Ind].variants[Ind2].title, FloatToStr(xProducts[Ind].variants[Ind2].price)
]
)
);
end;
finally
xShopify.Free;
end;
end;
Yalnızım ama bir kente yürüyen ordu gibiyim, edebiyattan kaçınmalıyım..

