Konuyu Oyla:
  • Derecelendirme: 0/5 - 0 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Delphi İle Shopify Entegrasyonu
#1
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.

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('ProcessBig GrineleteCollection_Id Json:%s',[xGetJson]),True);
 except
   on e:Exception do
   begin
     LogAdd(Format('ProcessBig GrineleteCollection_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('ProcessBig GrineleteProduct_Id Json:%s',[xGetJson]),True);
 except
   on e:Exception do
   begin
     LogAdd(Format('ProcessBig GrineleteProduct_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..
Cevapla
#2
Teşekkürler elinize sağlık
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  yapay zeka delphi kl007 9 626 26-02-2026, Saat: 09:12
Son Yorum: mrmarman
  Win 11 ve Delphi 7 Minimize sorunu. enigma 7 498 11-02-2026, Saat: 10:27
Son Yorum: RAD Coder
Question Delphi formunu nasıl otomatik tam ekran yapabilirim ? erdemklt0 2 324 23-01-2026, Saat: 10:02
Son Yorum: csunguray
  PAVO Pos Cihaz Entegrasyonu (Yeni Nesil ÖKC) RAD Coder 3 1.090 26-12-2025, Saat: 17:06
Son Yorum: rmzgenius
  Delphi SLL kullanım sorunu Bay_Y 12 1.317 22-12-2025, Saat: 18:11
Son Yorum: Bay_Y



Konuyu Okuyanlar: 1 Ziyaretçi