3737import com .github .rholder .retry .WaitStrategies ;
3838import com .shopify .exceptions .ShopifyClientException ;
3939import com .shopify .exceptions .ShopifyErrorResponseException ;
40+ import com .shopify .exceptions .ShopifyIncompatibleApiException ;
41+ import com .shopify .exceptions .ShopifyEmptyLineItemsException ;
42+ import com .shopify .mappers .LegacyToFulfillmentOrderMapping ;
4043import com .shopify .mappers .ResponseEntityToStringMapper ;
4144import com .shopify .mappers .ShopifySdkObjectMapper ;
4245import com .shopify .model .Count ;
5962import com .shopify .model .ShopifyCustomersRoot ;
6063import com .shopify .model .ShopifyFulfillment ;
6164import com .shopify .model .ShopifyFulfillmentCreationRequest ;
65+ import com .shopify .model .ShopifyFulfillmentOrder ;
66+ import com .shopify .model .ShopifyFulfillmentOrderMoveRequestRoot ;
67+ import com .shopify .model .ShopifyFulfillmentOrderMoveResponseRoot ;
68+ import com .shopify .model .ShopifyFulfillmentOrdersRoot ;
69+ import com .shopify .model .ShopifyFulfillmentPayloadRoot ;
6270import com .shopify .model .ShopifyFulfillmentRoot ;
6371import com .shopify .model .ShopifyFulfillmentUpdateRequest ;
6472import com .shopify .model .ShopifyGetCustomersRequest ;
96104import com .shopify .model .ShopifyShop ;
97105import com .shopify .model .ShopifyTransaction ;
98106import com .shopify .model .ShopifyTransactionsRoot ;
107+ import com .shopify .model .ShopifyUpdateFulfillmentPayloadRoot ;
99108import com .shopify .model .ShopifyVariant ;
100109import com .shopify .model .ShopifyVariantMetafieldCreationRequest ;
101110import com .shopify .model .ShopifyVariantRoot ;
@@ -129,12 +138,15 @@ public class ShopifySdk {
129138 static final String RECURRING_APPLICATION_CHARGES = "recurring_application_charges" ;
130139 static final String ORDERS = "orders" ;
131140 static final String FULFILLMENTS = "fulfillments" ;
141+ static final String FULFILLMENT_ORDERS = "fulfillment_orders" ;
132142 static final String ACTIVATE = "activate" ;
133143 static final String IMAGES = "images" ;
134144 static final String SHOP = "shop" ;
135145 static final String COUNT = "count" ;
136146 static final String CLOSE = "close" ;
137147 static final String CANCEL = "cancel" ;
148+ static final String MOVE = "move" ;
149+ static final String UPDATE_TRACKING = "update_tracking" ;
138150 static final String METAFIELDS = "metafields" ;
139151 static final String RISKS = "risks" ;
140152 static final String LOCATIONS = "locations" ;
@@ -199,28 +211,34 @@ public class ShopifySdk {
199211 public static interface OptionalsStep {
200212
201213 /**
202- * The Shopify SDK uses random waits in between retry attempts. Minimum duration
203- * time to wait before retrying a failed request. Value must also be less than
204- * {@link #withMaximumRequestRetryRandomDelay(int, TimeUnit) Maximum Request
205- * Retry Random Delay}.<br>
214+ * The Shopify SDK uses random waits in between retry attempts. Minimum
215+ * duration time to wait before retrying a failed request. Value must
216+ * also be less than
217+ * {@link #withMaximumRequestRetryRandomDelay(int, TimeUnit) Maximum
218+ * Request Retry Random Delay}.<br>
206219 * Default value is: 1 second.
207220 *
208221 * @param duration
222+ * of the minimum retry delay
209223 * @param timeUnit
210- * @return {@link OptionalsStep}
224+ * the time unit to be used (miliseconds, seconds, etc...)
225+ * @return {@link OptionalsStep} the OptionalsStep interface
211226 */
212227 OptionalsStep withMinimumRequestRetryRandomDelay (int duration , TimeUnit timeUnit );
213228
214229 /**
215- * The Shopify SDK uses random waits in between retry attempts. Maximum duration
216- * time to wait before retrying a failed request. Value must also be more than
217- * {@link #withMinimumRequestRetryRandomDelay(int, TimeUnit) Minimum Request
218- * Retry Random Delay}.<br>
230+ * The Shopify SDK uses random waits in between retry attempts. Maximum
231+ * duration time to wait before retrying a failed request. Value must
232+ * also be more than
233+ * {@link #withMinimumRequestRetryRandomDelay(int, TimeUnit) Minimum
234+ * Request Retry Random Delay}.<br>
219235 * Default value is: 5 seconds.
220236 *
221237 * @param duration
238+ * of the maximum retry delay
222239 * @param timeUnit
223- * @return {@link OptionalsStep}
240+ * the time unit to be used (miliseconds, seconds, etc...)
241+ * @return {@link OptionalsStep} the OptionalsStep interface
224242 */
225243 OptionalsStep withMaximumRequestRetryRandomDelay (int duration , TimeUnit timeUnit );
226244
@@ -229,8 +247,10 @@ public static interface OptionalsStep {
229247 * Default value is: 3 minutes.
230248 *
231249 * @param duration
250+ * of the request timeout
232251 * @param timeUnit
233- * @return {@link OptionalsStep}
252+ * the time unit to be used (miliseconds, seconds, etc...)
253+ * @return {@link OptionalsStep} the OptionalsStep interface
234254 */
235255 OptionalsStep withMaximumRequestRetryTimeout (int duration , TimeUnit timeUnit );
236256
@@ -239,8 +259,10 @@ public static interface OptionalsStep {
239259 * Default value is: 1 minute.
240260 *
241261 * @param duration
262+ * of the connection timeout
242263 * @param timeUnit
243- * @return {@link OptionalsStep}
264+ * the time unit to be used (miliseconds, seconds, etc...)
265+ * @return {@link OptionalsStep} the OptionalsStep interface
244266 */
245267 OptionalsStep withConnectionTimeout (int duration , TimeUnit timeUnit );
246268
@@ -249,20 +271,23 @@ public static interface OptionalsStep {
249271 * Default value is: 15 seconds.
250272 *
251273 * @param duration
274+ * of the duration to be considered
252275 * @param timeUnit
253- * @return {@link OptionalsStep}
276+ * the time unit to be used (miliseconds, seconds, etc...)
277+ * @return {@link OptionalsStep} the OptionalsStep interface
254278 */
255279 OptionalsStep withReadTimeout (int duration , TimeUnit timeUnit );
256280
257281 /**
258- * String representation of the version you want to use. If not populated, this
259- * will use shopify oldest stable version. Although this is not recommended so
260- * you can target a set of shopify features. Ex: '2020-10' '2020-07' '2020-04'.
261- * If you are specifying the API URL ensure you leave off the version if you are
262- * using this.
282+ * String representation of the version you want to use. If not
283+ * populated, this will use shopify oldest stable version. Although this
284+ * is not recommended so you can target a set of shopify features. Ex:
285+ * '2020-10' '2020-07' '2020-04'. If you are specifying the API URL
286+ * ensure you leave off the version if you are using this.
263287 *
264288 * @param apiVersion
265- * @return
289+ * current apiVersion value
290+ * @return {@link OptionalsStep} the OptionalsStep interface
266291 */
267292 OptionalsStep withApiVersion (final String apiVersion );
268293
@@ -688,24 +713,75 @@ public ShopifyPage<ShopifyOrder> getOrders(final String pageInfo, final int page
688713 return getOrders (response );
689714 }
690715
716+ /**
717+ * Creates a fulfillment in shopify
718+ *
719+ * @deprecated starting in March 01, 2023 this method will be obsolete
720+ * @param shopifyFulfillmentCreationRequest
721+ * the fulfillment creaton request
722+ * @return the newly created fulfillment
723+ */
724+ @ Deprecated
691725 public ShopifyFulfillment createFulfillment (
692726 final ShopifyFulfillmentCreationRequest shopifyFulfillmentCreationRequest ) {
727+ return this .createFulfillmentWithLegacyApi (shopifyFulfillmentCreationRequest );
728+ }
729+
730+ /**
731+ * Creates a fulfillment in shopify starting with api 2023-04
732+ *
733+ * @param shopifyFulfillmentCreationRequest
734+ * the fulfillment creaton request
735+ *
736+ * @param fulfillmentOrders
737+ * the fulfillment orders list to create the new fulfillment
738+ * @return the newly created fulfillment
739+ * @throws ShopifyEmptyLineItemsException
740+ * in case we have a fulfillment associated with a
741+ * fulfillmentOrder without supported action
742+ */
743+ public ShopifyFulfillment createFulfillment (
744+ final ShopifyFulfillmentCreationRequest shopifyFulfillmentCreationRequest ,
745+ List <ShopifyFulfillmentOrder > fulfillmentOrders ) throws ShopifyEmptyLineItemsException {
746+ return this .createFulfillmentWithFulfillmentOrderApi (shopifyFulfillmentCreationRequest , fulfillmentOrders );
747+ }
748+
749+ /**
750+ * Updates a fulfillment in shopify
751+ *
752+ * @deprecated starting in March 01, 2023 this method will be obsolete
753+ * @param shopifyFulfillmentUpdateRequest
754+ * the fulfillment update request
755+ * @return the newly updated fulfillment
756+ */
757+ @ Deprecated
758+ public ShopifyFulfillment updateFulfillment (final ShopifyFulfillmentUpdateRequest shopifyFulfillmentUpdateRequest ) {
693759 final ShopifyFulfillmentRoot shopifyFulfillmentRoot = new ShopifyFulfillmentRoot ();
694- final ShopifyFulfillment shopifyFulfillment = shopifyFulfillmentCreationRequest .getRequest ();
695-
760+ final ShopifyFulfillment shopifyFulfillment = shopifyFulfillmentUpdateRequest .getRequest ();
696761 shopifyFulfillmentRoot .setFulfillment (shopifyFulfillment );
697- final Response response = post (buildOrdersEndpoint ().path (shopifyFulfillment .getOrderId ()).path (FULFILLMENTS ),
698- shopifyFulfillmentRoot );
762+ final Response response = put (buildOrdersEndpoint ().path (shopifyFulfillment .getOrderId ()).path (FULFILLMENTS )
763+ . path ( shopifyFulfillment . getId ()), shopifyFulfillmentRoot );
699764 final ShopifyFulfillmentRoot shopifyFulfillmentRootResponse = response .readEntity (ShopifyFulfillmentRoot .class );
700765 return shopifyFulfillmentRootResponse .getFulfillment ();
701766 }
702767
703- public ShopifyFulfillment updateFulfillment (final ShopifyFulfillmentUpdateRequest shopifyFulfillmentUpdateRequest ) {
704- final ShopifyFulfillmentRoot shopifyFulfillmentRoot = new ShopifyFulfillmentRoot ();
768+ /**
769+ * Based on the api starting from 2023-04 it only updates tracking
770+ * information
771+ *
772+ * @param shopifyFulfillmentUpdateRequest
773+ * the information needed to update the fulfillment's tracking
774+ * info
775+ * @return the updated version of the shopify fulfillment
776+ */
777+ public ShopifyFulfillment updateFulfillmentTrackingInfo (
778+ final ShopifyFulfillmentUpdateRequest shopifyFulfillmentUpdateRequest ) {
705779 final ShopifyFulfillment shopifyFulfillment = shopifyFulfillmentUpdateRequest .getRequest ();
706- shopifyFulfillmentRoot .setFulfillment (shopifyFulfillment );
707- final Response response = put (buildOrdersEndpoint ().path (shopifyFulfillment .getOrderId ()).path (FULFILLMENTS )
708- .path (shopifyFulfillment .getId ()), shopifyFulfillmentRoot );
780+ final ShopifyUpdateFulfillmentPayloadRoot payload = LegacyToFulfillmentOrderMapping
781+ .toUpdateShopifyFulfillmentPayloadRoot (shopifyFulfillment );
782+
783+ final Response response = post (
784+ getWebTarget ().path (FULFILLMENTS ).path (shopifyFulfillment .getId ()).path (UPDATE_TRACKING ), payload );
709785 final ShopifyFulfillmentRoot shopifyFulfillmentRootResponse = response .readEntity (ShopifyFulfillmentRoot .class );
710786 return shopifyFulfillmentRootResponse .getFulfillment ();
711787 }
@@ -996,7 +1072,7 @@ private Response invokeResponseCallable(final Callable<Response> responseCallabl
9961072 }
9971073
9981074 private Retryer <Response > buildResponseRetyer () {
999- return RetryerBuilder .<Response >newBuilder ().retryIfResult (ShopifySdk ::shouldRetryResponse ).retryIfException ()
1075+ return RetryerBuilder .<Response > newBuilder ().retryIfResult (ShopifySdk ::shouldRetryResponse ).retryIfException ()
10001076 .withWaitStrategy (WaitStrategies .randomWait (minimumRequestRetryRandomDelayMilliseconds ,
10011077 TimeUnit .MILLISECONDS , maximumRequestRetryRandomDelayMilliseconds , TimeUnit .MILLISECONDS ))
10021078 .withStopStrategy (
@@ -1156,4 +1232,50 @@ private String getQueryParam(final URI uri, final String key) {
11561232 private WebTarget buildOrdersEndpoint () {
11571233 return getWebTarget ().path (ORDERS );
11581234 }
1235+
1236+ public List <ShopifyFulfillmentOrder > getFulfillmentOrdersFromOrder (final String shopifyOrderId ) {
1237+ final List <ShopifyFulfillmentOrder > fulfillmentOrders = new LinkedList <>();
1238+ final Response response = get (buildOrdersEndpoint ().path (shopifyOrderId ).path (FULFILLMENT_ORDERS ));
1239+ final ShopifyFulfillmentOrdersRoot shopifyFulfillmentOrdersRoot = response
1240+ .readEntity (ShopifyFulfillmentOrdersRoot .class );
1241+
1242+ fulfillmentOrders .addAll (shopifyFulfillmentOrdersRoot .getFulfillmentOrders ());
1243+
1244+ return fulfillmentOrders ;
1245+ }
1246+
1247+ public ShopifyFulfillmentOrder moveFulfillmentOrder (final String newLocationId ,
1248+ final ShopifyFulfillmentOrder shopifyFulfillmentOrder ) throws ShopifyIncompatibleApiException {
1249+ final ShopifyFulfillmentOrderMoveRequestRoot payload = LegacyToFulfillmentOrderMapping
1250+ .toShopifyMoveFulfillmentOrder (newLocationId , shopifyFulfillmentOrder );
1251+
1252+ final Response response = post (
1253+ getWebTarget ().path (FULFILLMENT_ORDERS ).path (shopifyFulfillmentOrder .getId ()).path (MOVE ), payload );
1254+ final ShopifyFulfillmentOrderMoveResponseRoot shopifyFulfillmentRootResponse = response
1255+ .readEntity (ShopifyFulfillmentOrderMoveResponseRoot .class );
1256+ return shopifyFulfillmentRootResponse .getOriginalFulfillmentOrder ();
1257+ }
1258+
1259+ private ShopifyFulfillment createFulfillmentWithLegacyApi (
1260+ final ShopifyFulfillmentCreationRequest shopifyFulfillmentCreationRequest ) {
1261+ final ShopifyFulfillmentRoot shopifyFulfillmentRoot = new ShopifyFulfillmentRoot ();
1262+ final ShopifyFulfillment shopifyFulfillment = shopifyFulfillmentCreationRequest .getRequest ();
1263+ shopifyFulfillmentRoot .setFulfillment (shopifyFulfillment );
1264+ final Response response = post (buildOrdersEndpoint ().path (shopifyFulfillment .getOrderId ()).path (FULFILLMENTS ),
1265+ shopifyFulfillmentRoot );
1266+ final ShopifyFulfillmentRoot shopifyFulfillmentRootResponse = response .readEntity (ShopifyFulfillmentRoot .class );
1267+ return shopifyFulfillmentRootResponse .getFulfillment ();
1268+ }
1269+
1270+ private ShopifyFulfillment createFulfillmentWithFulfillmentOrderApi (
1271+ final ShopifyFulfillmentCreationRequest shopifyFulfillmentCreationRequest ,
1272+ final List <ShopifyFulfillmentOrder > fulfillmentOrders ) throws ShopifyEmptyLineItemsException {
1273+ final ShopifyFulfillmentPayloadRoot payload = LegacyToFulfillmentOrderMapping
1274+ .toShopifyFulfillmentPayloadRoot (shopifyFulfillmentCreationRequest .getRequest (), fulfillmentOrders );
1275+
1276+ final Response response = post (getWebTarget ().path (FULFILLMENTS ), payload );
1277+ final ShopifyFulfillmentRoot shopifyFulfillmentRootResponse = response .readEntity (ShopifyFulfillmentRoot .class );
1278+
1279+ return shopifyFulfillmentRootResponse .getFulfillment ();
1280+ }
11591281}
0 commit comments