This repository has been archived by the owner on May 26, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathshopeego.go
1973 lines (1796 loc) · 65 KB
/
shopeego.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
package shopeego
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"regexp"
"strings"
jsoniter "github.com/json-iterator/go"
)
var json = jsoniter.ConfigCompatibleWithStandardLibrary
var (
// There are errors in the input parameters
ErrParams = errors.New("shopeego: there are errors in the input parameters")
// The request is not authenticated. Ex: signature is wrong
ErrAuth = errors.New("shopeego: the request is not authenticated. Ex: signature is wrong")
// An error has occurred
ErrServer = errors.New("shopeego: an error has occurred")
// Too many request.Exceed 1000 request per min will be banned for an hour
ErrTooManyRequest = errors.New("shopeego: too many request.Exceed 1000 request per min will be banned for an hour")
// Not support action
ErrNotSupport = errors.New("shopeego: not support action")
// An inner error has occurred
ErrInnerError = errors.New("shopeego: an inner error has occurred")
// No Permission
ErrPermission = errors.New("shopeego: no permission")
// Not exist
ErrNotExists = errors.New("shopeego: not exists")
)
const (
// ClientVersionV1 for Open API V1, see: https://open.shopee.com/documents?module=63&type=2&id=53.
ClientVersionV1 ClientVersion = iota
// ClientVersionV2 for Open API V2, see: https://open.shopee.com/documents?module=63&type=2&id=56.
ClientVersionV2
)
// ClientVersion is the API version of the client should be using.
type ClientVersion int
const (
urlTestSandbox string = "https://partner.uat.shopeemobile.com/"
urlStandard string = "https://partner.shopeemobile.com/"
)
type ClientOptions struct {
Secret string
// 非必要
//PartnerID int64
// 非必要
//ShopID int64
//
IsSandbox bool
//
Version ClientVersion
}
// CONSTS
func NewClient(opts *ClientOptions) Client {
return &ShopeeClient{
Secret: opts.Secret,
IsSandbox: opts.IsSandbox,
Version: opts.Version,
}
}
// Client 定義了一個蝦皮的客戶端該有什麼功能。
type Client interface {
// SetAccessToken(t string) *ShopeeClient
//=======================================================
// Shop
//=======================================================
// GetShopInfo Use this call to get information of shop
GetShopInfo(*GetShopInfoRequest) (*GetShopInfoResponse, error)
// UpdateShopInfo Use this call to update information of shop
UpdateShopInfo(*UpdateShopInfoRequest) (*UpdateShopInfoResponse, error)
// Performance Shop performance includes the indexes from "My Performance" of Seller Center.
Performance(*PerformanceRequest) (*PerformanceResponse, error)
// SetShopInstallmentStatus Only for TW whitelisted shop.Use this API to set the installment status of shop.
SetShopInstallmentStatus(*SetShopInstallmentStatusRequest) (*SetShopInstallmentStatusResponse, error)
//
AuthPartner(*AuthPartnerRequest) string
//=======================================================
// ShopCategory
//=======================================================
// AddShopCategory Use this call to add a new collecion
AddShopCategory(*AddShopCategoryRequest) (*AddShopCategoryResponse, error)
// GetShopCategories Use this call to get list of in-shop categories
GetShopCategories(*GetShopCategoriesRequest) (*GetShopCategoriesResponse, error)
// DeleteShopCategory Use this call to delete a existing collecion
DeleteShopCategory(*DeleteShopCategoryRequest) (*DeleteShopCategoryResponse, error)
// UpdateShopCategory Use this call to update a existing collecion
UpdateShopCategory(*UpdateShopCategoryRequest) (*UpdateShopCategoryResponse, error)
// AddItems Use this call to add items list to certain shop_category
AddItems(*AddItemsRequest) (*AddItemsResponse, error)
// GetItems Use this call to get items list of certain shop_category
GetItems(*GetItemsRequest) (*GetItemsResponse, error)
// DeleteItems Use this api to delete items from shop category
DeleteItems(*DeleteItemsRequest) (*DeleteItemsResponse, error)
//=======================================================
// Item
//=======================================================
// GetCategories Use this call to get categories of product item
GetCategories(*GetCategoriesRequest) (*GetCategoriesResponse, error)
// GetAttributes Use this call to get attributes of product item
GetAttributes(*GetAttributesRequest) (*GetAttributesResponse, error)
// Add Use this call to add a product item. Should get dependency by calling below API first
// shopee.item.GetCategories
// shopee.item.GetAttributes
// shopee.logistics.GetLogistics
Add(*AddRequest) (*AddResponse, error)
// Delete Use this call to delete a product item.
Delete(*DeleteRequest) (*DeleteResponse, error)
// UnlistItem Use this api to unlist or list items in batch.
UnlistItem(*UnlistItemRequest) (*UnlistItemResponse, error)
// AddVariations Use this call to add item variations, it only supports non-tier-variation items.
AddVariations(*AddVariationsRequest) (*AddVariationsResponse, error)
// DeleteVariation Use this call to delete item variation
DeleteVariation(*DeleteVariationRequest) (*DeleteVariationResponse, error)
// GetItemsList Use this call to get a list of items
GetItemsList(*GetItemsListRequest) (*GetItemsListResponse, error)
// GetItemDetail Use this call to get detail of item
GetItemDetail(*GetItemDetailRequest) (*GetItemDetailResponse, error)
// UpdateItem Use this call to update a product item. Should get dependency by calling below API first
// shopee.item.GetItemDetail
UpdateItem(*UpdateItemRequest) (*UpdateItemResponse, error)
// AddItemImg Use this call to add product item images.
AddItemImg(*AddItemImgRequest) (*AddItemImgResponse, error)
// UpdateItemImg Override and update all the existing images of an item.
UpdateItemImg(*UpdateItemImgRequest) (*UpdateItemImgResponse, error)
// InsertItemImg Use this call to add one item image in assigned position.
InsertItemImg(*InsertItemImgRequest) (*InsertItemImgResponse, error)
// DeleteItemImg Use this call to delete a product item image.
DeleteItemImg(*DeleteItemImgRequest) (*DeleteItemImgResponse, error)
// UpdatePrice Use this call to update item price
UpdatePrice(*UpdatePriceRequest) (*UpdatePriceResponse, error)
// UpdateStock Use this call to update item stock
UpdateStock(*UpdateStockRequest) (*UpdateStockResponse, error)
// UpdateVariationPrice Use this call to update item variation price
UpdateVariationPrice(*UpdateVariationPriceRequest) (*UpdateVariationPriceResponse, error)
// UpdateVariationStock Use this call to update item variation stock
UpdateVariationStock(*UpdateVariationStockRequest) (*UpdateVariationStockResponse, error)
// UpdatePriceBatch Update items price in batch.
UpdatePriceBatch(*UpdatePriceBatchRequest) (*UpdatePriceBatchResponse, error)
// UpdateStockBatch Update items stock in batch.
UpdateStockBatch(*UpdateStockBatchRequest) (*UpdateStockBatchResponse, error)
// UpdateVariationPriceBatch Update variations price in batch.
UpdateVariationPriceBatch(*UpdateVariationPriceBatchRequest) (*UpdateVariationPriceBatchResponse, error)
// UpdateVariationStockBatch Update variations stock in batch.
UpdateVariationStockBatch(*UpdateVariationStockBatchRequest) (*UpdateVariationStockBatchResponse, error)
// InitTierVariation Initialize a non-tier-variation item to a tier-variation item, upload variation image and initialize stock and price for each variation. This API cannot edit existed tier_variation and variation price/stock.
InitTierVariation(*InitTierVariationRequest) (*InitTierVariationResponse, error)
// AddTierVariation Use this api to add new tier variations in batch. Tier variation index of variations in the same item must be unique.
AddTierVariation(*AddTierVariationRequest) (*AddTierVariationResponse, error)
// GetVariation Use this call to get tier-variation basic information under an item
GetVariation(*GetVariationRequest) (*GetVariationResponse, error)
// UpdateTierVariationList Use this api to update tier-variation list or upload variation image of a tier-variation item.
UpdateTierVariationList(*UpdateTierVariationListRequest) (*UpdateTierVariationListResponse, error)
// UpdateTierVariationIndex Use this api to update existing tier index under the same variation_id.
UpdateTierVariationIndex(*UpdateTierVariationIndexRequest) (*UpdateTierVariationIndexResponse, error)
// BoostItem Use this api to boost multiple items at once.
BoostItem(*BoostItemRequest) (*BoostItemResponse, error)
// GetBoostedItem Use this api to get all boosted items.
GetBoostedItem(*GetBoostedItemRequest) (*GetBoostedItemResponse, error)
// SetItemInstallmentTenures Only for TW whitelisted shop. Use this API to set the installment tenures of items.
SetItemInstallmentTenures(*SetItemInstallmentTenuresRequest) (*SetItemInstallmentTenuresResponse, error)
// GetPromotionInfo Use this api to get ongoing and upcoming promotions.
GetPromotionInfo(*GetPromotionInfoRequest) (*GetPromotionInfoResponse, error)
// GetRecommendCats Use this API to get recommended category ids according to item name.
GetRecommendCats(*GetRecommendCatsRequest) (*GetRecommendCatsResponse, error)
// GetComment Use this api to get comment by shopid/itemid/comment_id
GetComment(*GetCommentRequest) (*GetCommentResponse, error)
// ReplyComments Use this api to reply comments from buyers in batch
ReplyComments(*ReplyCommentsRequest) (*ReplyCommentsResponse, error)
//=======================================================
// Image
//=======================================================
// UploadImg Use this optional API to pre-validate your image urls and convert them to Shopee image url to use in item upload APIs. This way your potential invalid urls will not block your item upload process.
UploadImg(*UploadImgRequest) (*UploadImgResponse, error)
//=======================================================
// Discount
//=======================================================
// AddDiscount Use this api to add shop discount activity
AddDiscount(*AddDiscountRequest) (*AddDiscountResponse, error)
// AddDiscountItem Use this api to add shop discount item
AddDiscountItem(*AddDiscountItemRequest) (*AddDiscountItemResponse, error)
// DeleteDiscount Use this api to delete one discount activity BEFORE it starts.
DeleteDiscount(*DeleteDiscountRequest) (*DeleteDiscountResponse, error)
// DeleteDiscountItem Use this api to delete items of the discount activity
DeleteDiscountItem(*DeleteDiscountItemRequest) (*DeleteDiscountItemResponse, error)
// GetDiscountDetail Use this api to get one shop discount activity detail
GetDiscountDetail(*GetDiscountDetailRequest) (*GetDiscountDetailResponse, error)
// GetDiscountsList Use this api to get shop discount activity list
GetDiscountsList(*GetDiscountsListRequest) (*GetDiscountsListResponse, error)
// UpdateDiscount Use this api to update one discount information
UpdateDiscount(*UpdateDiscountRequest) (*UpdateDiscountResponse, error)
// UpdateDiscountItems Use this api to update items of the discount activity
UpdateDiscountItems(*UpdateDiscountItemsRequest) (*UpdateDiscountItemsResponse, error)
//=======================================================
// Orders
//=======================================================
// GetOrdersList GetOrdersList is the recommended call to use for order management. Use this call to retrieve basic information of all orders which are updated within specific period of time. More details of each order can be retrieved from GetOrderDetails. [Only the recent one month orders can be fetch through this API. Please use GetOrderBySatus API to fetch more orders.]
GetOrdersList(*GetOrdersListRequest) (*GetOrdersListResponse, error)
// GetOrdersByStatus GetOrdersByStatus is the recommended call to use for order management. Use this call to retrieve basic information of all orders which are specific status. More details of each order can be retrieved from GetOrderDetails.
GetOrdersByStatus(*GetOrdersByStatusRequest) (*GetOrdersByStatusResponse, error)
// GetOrderDetails Use this call to retrieve detailed information about one or more orders based on OrderSN.
GetOrderDetails(*GetOrderDetailsRequest) (*GetOrderDetailsResponse, error)
// GetEscrowDetails Use this call to retrieve detailed escrow information about one order based on OrderSN.
GetEscrowDetails(*GetEscrowDetailsRequest) (*GetEscrowDetailsResponse, error)
// AddOrderNote Use this call to add note for an order
AddOrderNote(*AddOrderNoteRequest) (*AddOrderNoteResponse, error)
// CancelOrder Use this call to cancel an order from the seller side.
CancelOrder(*CancelOrderRequest) (*CancelOrderResponse, error)
// AcceptBuyerCancellation Use this call to accept buyer cancellation
AcceptBuyerCancellation(*AcceptBuyerCancellationRequest) (*AcceptBuyerCancellationResponse, error)
// RejectBuyerCancellation Use this call to reject buyer cancellation
RejectBuyerCancellation(*RejectBuyerCancellationRequest) (*RejectBuyerCancellationResponse, error)
// GetForderInfo Use this call to retrieve detailed information of all the fulfill orders(forder) under a single regular order based on ordersn.
GetForderInfo(*GetForderInfoRequest) (*GetForderInfoResponse, error)
// GetEscrowReleasedOrders Use this api to get orders' release time and escrow amount.
GetEscrowReleasedOrders(*GetEscrowReleasedOrdersRequest) (*GetEscrowReleasedOrdersResponse, error)
// SplitOrder Use this API to split order into fulfillment orders. This feature is only enabled for whitelisted shops.
SplitOrder(*SplitOrderRequest) (*SplitOrderResponse, error)
// UndoSplitOrder Use this API to cancel split order from the seller side.
UndoSplitOrder(*UndoSplitOrderRequest) (*UndoSplitOrderResponse, error)
// GetUnbindOrderList Use this call to get a list of unbind orders.
GetUnbindOrderList(*GetUnbindOrderListRequest) (*GetUnbindOrderListResponse, error)
// MyIncome Use this API to fetch the accounting detail of order.
MyIncome(*MyIncomeRequest) (*MyIncomeResponse, error)
//=======================================================
// Logistics
//=======================================================
// GetLogistics Use this call to get all supported logistic channels.
GetLogistics(*GetLogisticsRequest) (*GetLogisticsResponse, error)
// UpdateShopLogistics Configure shop level logistics
UpdateShopLogistics(*UpdateShopLogisticsRequest) (*UpdateShopLogisticsResponse, error)
// GetParameterForInit Use this call to get all required param for logistic initiation.
GetParameterForInit(*GetParameterForInitRequest) (*GetParameterForInitResponse, error)
// GetAddress For integrated logistics channel, use this call to get pickup address for pickup mode order.
GetAddress(*GetAddressRequest) (*GetAddressResponse, error)
// GetTimeSlot For integrated logistics channel, use this call to get pickup timeslot for pickup mode order.
GetTimeSlot(*GetTimeSlotRequest) (*GetTimeSlotResponse, error)
// GetBranch For integrated logistics channel, use this call to get dropoff location for dropoff mode order.
GetBranch(*GetBranchRequest) (*GetBranchResponse, error)
// GetLogisticInfo Get all the logistics info of an order to Init.
// This API consolidates the output of GetParameterForInit, GetAddresss, GetTimeSlot and GetBranch based on each order so that developer can get all the required parameters ready in this API for Init.This API is an alternative of GetParameterForInit, GetAddresss, GetTimeSlot and GetBranch as a set.
GetLogisticInfo(*GetLogisticInfoRequest) (*GetLogisticInfoResponse, error)
// Init Use this call to initiate logistics including arrange Pickup, Dropoff or shipment for non-integrated logistic channels. Should call shopee.logistics.GetLogisticInfo to fetch all required param first. It's recommended to initiate logistics one hour AFTER the orders were placed since there is one-hour window buyer can cancel any order without request to seller.
Init(*InitRequest) (*InitResponse, error)
// GetAirwayBill Use this API to get airway bill for orders. AirwayBill is only fetchable when the order status is under READY_TO_SHIP and RETRY_SHIP.
GetAirwayBill(*GetAirwayBillRequest) (*GetAirwayBillResponse, error)
// GetOrderLogistics Use this call to fetch the logistics information of an order, these info can be used for airwaybill printing. Dedicated for crossborder SLS order airwaybill. May not be applicable for local channel airwaybill.
GetOrderLogistics(*GetOrderLogisticsRequest) (*GetOrderLogisticsResponse, error)
// GetLogisticsMessage Use this call to get the logistics tracking information of an order.
GetLogisticsMessage(*GetLogisticsMessageRequest) (*GetLogisticsMessageResponse, error)
// GetForderWaybill Use this API to get airwaybill for fulfillment orders.
GetForderWaybill(*GetForderWaybillRequest) (*GetForderWaybillResponse, error)
// SetAddress Use this API to set default_address/pick_up_address/return_address of shop. Please use GetAddress API to fetch the address_id.
SetAddress(*SetAddressRequest) (*SetAddressResponse, error)
// DeleteAddress Use this API to delete the default/pick_up/return address of shop by address_id. Please use GetAddress API to fetch the address_id.
DeleteAddress(*DeleteAddressRequest) (*DeleteAddressResponse, error)
//=======================================================
// Returns
//=======================================================
// ConfirmReturn Confirm return
ConfirmReturn(*ConfirmReturnRequest) (*ConfirmReturnResponse, error)
// DisputeReturn Dispute return
DisputeReturn(*DisputeReturnRequest) (*DisputeReturnResponse, error)
// GetReturnList Get return list
GetReturnList(*GetReturnListRequest) (*GetReturnListResponse, error)
// GetReturnDetail Use this api to get detail information of a returned order
GetReturnDetail(*GetReturnDetailRequest) (*GetReturnDetailResponse, error)
//=======================================================
// Public
//=======================================================
// GetShopsByPartner Use this call to get basic info of shops which have authorized to the partner.
GetShopsByPartner(*GetShopsByPartnerRequest) (*GetShopsByPartnerResponse, error)
// GetCategoriesByCountry Use this api to get categories list filtered by country and cross border without using shopID.
GetCategoriesByCountry(*GetCategoriesByCountryRequest) (*GetCategoriesByCountryResponse, error)
// GetPaymentList The supported payment method list by country
GetPaymentList(*GetPaymentListRequest) (*GetPaymentListResponse, error)
//=======================================================
// TopPicks
//=======================================================
// GetTopPicksList Get the list of all collections.
GetTopPicksList(*GetTopPicksListRequest) (*GetTopPicksListResponse, error)
// AddTopPicks Add one collection. One shop can have up to 10 collections.
AddTopPicks(*AddTopPicksRequest) (*AddTopPicksResponse, error)
// UpdateTopPicks Use this API to update the collection name, the item list in a collection, or to activate a collection.
UpdateTopPicks(*UpdateTopPicksRequest) (*UpdateTopPicksResponse, error)
// DeleteTopPicks Delete a collection
DeleteTopPicks(*DeleteTopPicksRequest) (*DeleteTopPicksResponse, error)
//=======================================================
// FirstMileTracking
//=======================================================
// GenerateFMTrackingNo Use this API to generate first-mile tracking number for the shipment method of pickup. Please note that the prerequisite for using this API is that the order status is ready_to_ship and the tracking number of order has been obtained. Only applicable to cross-border sellers in China.
GenerateFMTrackingNo(*GenerateFMTrackingNoRequest) (*GenerateFMTrackingNoResponse, error)
// GetShopFMTrackingNo Use this API to fetch first-mile tracking numbers of the shop. Only applicable to cross-border sellers in China.
GetShopFMTrackingNo(*GetShopFMTrackingNoRequest) (*GetShopFMTrackingNoResponse, error)
// FirstMileCodeBindOrder Use this API to bind orders with the first-mile tracking number. Only applicable to cross-border sellers in China.
FirstMileCodeBindOrder(*FirstMileCodeBindOrderRequest) (*FirstMileCodeBindOrderResponse, error)
// GetFmTnDetail Use this API to fetch the detailed information of first-mile tracking number. Only applicable to cross-border sellers in China.
GetFmTnDetail(*GetFmTnDetailRequest) (*GetFmTnDetailResponse, error)
// GetFMTrackingNoWaybill Use the API to get the waybill of first-mile tracking number.Please note that this API only used for the shipment method of pickup. Only applicable to cross-border sellers in China.
GetFMTrackingNoWaybill(*GetFMTrackingNoWaybillRequest) (*GetFMTrackingNoWaybillResponse, error)
// GetShopFirstMileChannel Use this call to get all supported logistic channels for first mile. Only applicable to cross-border sellers in China.
GetShopFirstMileChannel(*GetShopFirstMileChannelRequest) (*GetShopFirstMileChannelResponse, error)
// FirstMileUnbind Use this API to unbind orders with the first-mile tracking number. Only applicable to cross-border sellers in China.
FirstMileUnbind(*FirstMileUnbindRequest) (*FirstMileUnbindResponse, error)
//=======================================================
// Payment
//=======================================================
// GetTransactionList Use this API to get the transaction records of wallet.
GetTransactionList(*GetTransactionListRequest) (*GetTransactionListResponse, error)
//=======================================================
// Push
//=======================================================
// GetPushConfig Use this API to get the configuration information of push service.
GetPushConfig(*GetPushConfigRequest) (*GetPushConfigResponse, error)
// SetPushConfig Use this API to set the configuration information of push service.
SetPushConfig(*SetPushConfigRequest) (*SetPushConfigResponse, error)
//=======================================================
// Auth (V2)
//=======================================================
// GetAccessToken Use this API and the code to obtain the access_token and refresh_token.
GetAccessToken(*GetAccessTokenRequest) (*GetAccessTokenResponse, error)
// RefreshAccessToken Use this API to refresh the access_token after it expires.
RefreshAccessToken(*RefreshAccessTokenRequest) (*RefreshAccessTokenResponse, error)
}
// ShopeeClient represents a client to Shopee
type ShopeeClient struct {
Secret string
accessToken string
IsSandbox bool
Version ClientVersion
}
// ResponseError defines a error response
type ResponseError struct {
RequestID string `json:"request_id,omitempty"`
Msg string `json:"msg,omitempty"`
ErrorType string `json:"error,omitempty"`
Message string `json:"message,omitempty"`
}
func (e ResponseError) Error() string {
// 如果 `msg` 是空的,就試試看 V2 的 `message`
msg := e.Msg
if msg == "" {
msg = e.Message
}
return fmt.Sprintf("shopeego: %s - %s", e.ErrorType, msg)
}
//
func (s *ShopeeClient) getPath(method string) string {
var host string
if s.IsSandbox {
host = urlTestSandbox
} else {
host = urlStandard
}
// 依照不同版本處理 API 前輟。
switch s.Version {
case ClientVersionV1:
return fmt.Sprintf("%sapi/v1/%s", host, availablePaths[method])
default:
return fmt.Sprintf("%sapi/v2/%s", host, availablePaths[method])
}
}
// signV1 會簽署 V1 API。
func (s *ShopeeClient) signV1(url string, body []byte) string {
h := hmac.New(sha256.New, []byte(s.Secret))
io.WriteString(h, fmt.Sprintf("%s|%s", url, string(body)))
return fmt.Sprintf("%x", h.Sum(nil))
}
// signV2 會簽署 V2 API。
func (s *ShopeeClient) signV2(url string, b []byte) string {
h := hmac.New(sha256.New, []byte(s.Secret))
p := s.getBodyPart(b)
if s.IsSandbox {
url = "/api/" + strings.TrimLeft(url, urlTestSandbox)
} else {
url = "/api/" + strings.TrimLeft(url, urlStandard)
}
io.WriteString(h, fmt.Sprintf("%d%s%d%s%d", p.partnerID, url, p.timestamp, s.accessToken, p.shopID))
return fmt.Sprintf("%x", h.Sum(nil))
}
type bodyPart struct {
partnerID int64
timestamp int
shopID int64
}
//
func (s *ShopeeClient) getBodyPart(b []byte) bodyPart {
var p bodyPart
var t map[string]interface{}
err := json.Unmarshal(b, &t)
if err != nil {
return p
}
if v, ok := t["partner_id"].(float64); ok {
p.partnerID = int64(v)
}
if v, ok := t["timestamp"].(float64); ok {
p.timestamp = int(v)
}
if v, ok := t["shopid"].(float64); ok {
p.shopID = int64(v)
}
if v, ok := t["shop_id"].(float64); ok {
p.shopID = int64(v)
}
return p
}
func (s *ShopeeClient) SetAccessToken(t string) *ShopeeClient {
s.accessToken = t
return s
}
//
func (s *ShopeeClient) makeV2Query(url string, b []byte) string {
p := s.getBodyPart(b)
q := fmt.Sprintf("?partner_id=%d&shop_id=%d×tamp=%d&sign=%s", p.partnerID, p.shopID, p.timestamp, s.signV2(url, b))
if s.accessToken != "" {
q += fmt.Sprintf("&access_token=%s", s.accessToken)
}
return q
}
//
func (s *ShopeeClient) post(method string, in interface{}) ([]byte, error) {
body, err := json.Marshal(in)
if err != nil {
return nil, err
}
url := s.getPath(method)
req, err := http.NewRequest("POST", url, strings.NewReader(string(body)))
req.Header.Add("Content-Type", "application/json")
switch s.Version {
// 如果是 V1 就在 Header 安插 Sign。
case ClientVersionV1:
req.Header.Add("Authorization", s.signV1(url, body))
// 如果是 V2 的 API,就在 Body 中自動安插 Sign。
case ClientVersionV2:
req, err = http.NewRequest("POST", fmt.Sprintf("%s%s", url, s.makeV2Query(url, body)), bytes.NewReader(body))
req.Header.Add("Authorization", s.signV1(url, body))
}
//Do request by native lib
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err = ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
var errResp ResponseError
_ = json.Unmarshal(body, &errResp)
if errResp.ErrorType != "" {
return nil, errResp
}
return s.patchFloat(body), nil
}
// patchFloat 會修正無法將 JSON 的字串值轉換成 Float64 型態的錯誤,這主要是因為 Shopee 會在某些時候以 `""`(空字串)當作是 Float64 的零值,
// 但對於 Golang 來說,Float64 的零值必須是 `"0"`,所以這個函式會將 Raw JSON 裡的所有相關(請參閱 `replaces.go` 關鍵詞表) `""` 轉換為 `"0"` 以便正確解析。
//
// 這個函式修正了 `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into float64` 錯誤。
// 相關 Issue: https://github.com/teacat/shopeego/issues/6
func (s *ShopeeClient) patchFloat(body []byte) []byte {
replaceConcat := strings.Join(replaces, "|")
for _, v := range replaces {
body = []byte(strings.ReplaceAll(string(body), fmt.Sprintf(`"%s":""`, v), fmt.Sprintf(`"%s":"0"`, v)))
}
var r = regexp.MustCompile(fmt.Sprintf(`"(%s)":(.*?)(,|})`, replaceConcat))
return []byte(r.ReplaceAllString(string(body), `"$1":"$2"$3`))
}
//=======================================================
// Shop
//=======================================================
// GetShopInfo Use this call to get information of shop
func (s *ShopeeClient) GetShopInfo(req *GetShopInfoRequest) (resp *GetShopInfoResponse, err error) {
b, err := s.post("GetShopInfo", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateShopInfo Use this call to update information of shop
func (s *ShopeeClient) UpdateShopInfo(req *UpdateShopInfoRequest) (resp *UpdateShopInfoResponse, err error) {
b, err := s.post("UpdateShopInfo", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// Performance Shop performance includes the indexes from "My Performance" of Seller Center.
func (s *ShopeeClient) Performance(req *PerformanceRequest) (resp *PerformanceResponse, err error) {
b, err := s.post("Performance", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// SetShopInstallmentStatus Only for TW whitelisted shop.Use this API to set the installment status of shop.
func (s *ShopeeClient) SetShopInstallmentStatus(req *SetShopInstallmentStatusRequest) (resp *SetShopInstallmentStatusResponse, err error) {
b, err := s.post("SetShopInstallmentStatus", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// AuthPartner for V2.
func (s *ShopeeClient) AuthPartner(req *AuthPartnerRequest) string {
url := s.getPath("AuthPartner")
switch s.Version {
// V1
case ClientVersionV1:
h := sha256.Sum256([]byte(fmt.Sprintf("%s%s", s.Secret, req.Redirect)))
token := fmt.Sprintf("%x", h[:])
return fmt.Sprintf("%s?id=%d&token=%s&redirect=%s", url, req.PartnerID, token, req.Redirect)
// V2
default:
h := hmac.New(sha256.New, []byte(s.Secret))
io.WriteString(h, fmt.Sprintf("%d%s%d", req.PartnerID, "/api/v2/shop/auth_partner", req.Timestamp))
token := fmt.Sprintf("%x", h.Sum(nil))
return fmt.Sprintf("%s?partner_id=%d&redirect=%s&sign=%s×tamp=%d", url, req.PartnerID, req.Redirect, token, req.Timestamp)
}
}
//=======================================================
// ShopCategory
//=======================================================
// AddShopCategory Use this call to add a new collecion
func (s *ShopeeClient) AddShopCategory(req *AddShopCategoryRequest) (resp *AddShopCategoryResponse, err error) {
b, err := s.post("AddShopCategory", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// GetShopCategories Use this call to get list of in-shop categories
func (s *ShopeeClient) GetShopCategories(req *GetShopCategoriesRequest) (resp *GetShopCategoriesResponse, err error) {
b, err := s.post("GetShopCategories", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// DeleteShopCategory Use this call to delete a existing collecion
func (s *ShopeeClient) DeleteShopCategory(req *DeleteShopCategoryRequest) (resp *DeleteShopCategoryResponse, err error) {
b, err := s.post("DeleteShopCategory", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateShopCategory Use this call to update a existing collecion
func (s *ShopeeClient) UpdateShopCategory(req *UpdateShopCategoryRequest) (resp *UpdateShopCategoryResponse, err error) {
b, err := s.post("UpdateShopCategory", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// AddItems Use this call to add items list to certain shop_category
func (s *ShopeeClient) AddItems(req *AddItemsRequest) (resp *AddItemsResponse, err error) {
b, err := s.post("AddItems", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// GetItems Use this call to get items list of certain shop_category
func (s *ShopeeClient) GetItems(req *GetItemsRequest) (resp *GetItemsResponse, err error) {
b, err := s.post("GetItems", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// DeleteItems Use this api to delete items from shop category
func (s *ShopeeClient) DeleteItems(req *DeleteItemsRequest) (resp *DeleteItemsResponse, err error) {
b, err := s.post("DeleteItems", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
//=======================================================
// Item
//=======================================================
// GetCategories Use this call to get categories of product item
func (s *ShopeeClient) GetCategories(req *GetCategoriesRequest) (resp *GetCategoriesResponse, err error) {
b, err := s.post("GetCategories", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// GetAttributes Use this call to get attributes of product item
func (s *ShopeeClient) GetAttributes(req *GetAttributesRequest) (resp *GetAttributesResponse, err error) {
b, err := s.post("GetAttributes", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// Add Use this call to add a product item. Should get dependency by calling below API first
// shopee.item.GetCategories
// shopee.item.GetAttributes
// shopee.logistics.GetLogistics
func (s *ShopeeClient) Add(req *AddRequest) (resp *AddResponse, err error) {
b, err := s.post("Add", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// Delete Use this call to delete a product item.
func (s *ShopeeClient) Delete(req *DeleteRequest) (resp *DeleteResponse, err error) {
b, err := s.post("Delete", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UnlistItem Use this api to unlist or list items in batch.
func (s *ShopeeClient) UnlistItem(req *UnlistItemRequest) (resp *UnlistItemResponse, err error) {
b, err := s.post("UnlistItem", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// AddVariations Use this call to add item variations
func (s *ShopeeClient) AddVariations(req *AddVariationsRequest) (resp *AddVariationsResponse, err error) {
b, err := s.post("AddVariations", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// DeleteVariation Use this call to delete item variation
func (s *ShopeeClient) DeleteVariation(req *DeleteVariationRequest) (resp *DeleteVariationResponse, err error) {
b, err := s.post("DeleteVariation", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// GetItemsList Use this call to get a list of items
func (s *ShopeeClient) GetItemsList(req *GetItemsListRequest) (resp *GetItemsListResponse, err error) {
b, err := s.post("GetItemsList", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// GetItemDetail Use this call to get detail of item
func (s *ShopeeClient) GetItemDetail(req *GetItemDetailRequest) (resp *GetItemDetailResponse, err error) {
b, err := s.post("GetItemDetail", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateItem Use this call to update a product item. Should get dependency by calling below API first
// shopee.item.GetItemDetail
func (s *ShopeeClient) UpdateItem(req *UpdateItemRequest) (resp *UpdateItemResponse, err error) {
b, err := s.post("UpdateItem", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// AddItemImg Use this call to add product item images.
func (s *ShopeeClient) AddItemImg(req *AddItemImgRequest) (resp *AddItemImgResponse, err error) {
b, err := s.post("AddItemImg", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateItemImg Override and update all the existing images of an item.
func (s *ShopeeClient) UpdateItemImg(req *UpdateItemImgRequest) (resp *UpdateItemImgResponse, err error) {
b, err := s.post("UpdateItemImg", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// InsertItemImg Use this call to add one item image in assigned position.
func (s *ShopeeClient) InsertItemImg(req *InsertItemImgRequest) (resp *InsertItemImgResponse, err error) {
b, err := s.post("InsertItemImg", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// DeleteItemImg Use this call to delete a product item image.
func (s *ShopeeClient) DeleteItemImg(req *DeleteItemImgRequest) (resp *DeleteItemImgResponse, err error) {
b, err := s.post("DeleteItemImg", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdatePrice Use this call to update item price
func (s *ShopeeClient) UpdatePrice(req *UpdatePriceRequest) (resp *UpdatePriceResponse, err error) {
b, err := s.post("UpdatePrice", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateStock Use this call to update item stock
func (s *ShopeeClient) UpdateStock(req *UpdateStockRequest) (resp *UpdateStockResponse, err error) {
b, err := s.post("UpdateStock", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateVariationPrice Use this call to update item variation price
func (s *ShopeeClient) UpdateVariationPrice(req *UpdateVariationPriceRequest) (resp *UpdateVariationPriceResponse, err error) {
b, err := s.post("UpdateVariationPrice", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateVariationStock Use this call to update item variation stock
func (s *ShopeeClient) UpdateVariationStock(req *UpdateVariationStockRequest) (resp *UpdateVariationStockResponse, err error) {
b, err := s.post("UpdateVariationStock", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdatePriceBatch Update items price in batch.
func (s *ShopeeClient) UpdatePriceBatch(req *UpdatePriceBatchRequest) (resp *UpdatePriceBatchResponse, err error) {
b, err := s.post("UpdatePriceBatch", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateStockBatch Update items stock in batch.
func (s *ShopeeClient) UpdateStockBatch(req *UpdateStockBatchRequest) (resp *UpdateStockBatchResponse, err error) {
b, err := s.post("UpdateStockBatch", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateVariationPriceBatch Update variations price in batch.
func (s *ShopeeClient) UpdateVariationPriceBatch(req *UpdateVariationPriceBatchRequest) (resp *UpdateVariationPriceBatchResponse, err error) {
b, err := s.post("UpdateVariationPriceBatch", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// UpdateVariationStockBatch Update variations stock in batch.
func (s *ShopeeClient) UpdateVariationStockBatch(req *UpdateVariationStockBatchRequest) (resp *UpdateVariationStockBatchResponse, err error) {
b, err := s.post("UpdateVariationStockBatch", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)
if err != nil {
return
}
return
}
// InitTierVariation Initialize a non-tier-variation item to a tier-variation item, upload variation image and initialize stock and price for each variation. This API cannot edit existed tier_variation and variation price/stock.
func (s *ShopeeClient) InitTierVariation(req *InitTierVariationRequest) (resp *InitTierVariationResponse, err error) {
b, err := s.post("InitTierVariation", req)
if err != nil {
return
}
err = json.Unmarshal(b, &resp)