@sommpicks/sommpicks-shopify 24.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Logger.ts +18 -0
- package/README.md +258 -0
- package/addTypings.sh +2 -0
- package/bitbucket-pipelines.yml +38 -0
- package/index.ts +132 -0
- package/package.json +57 -0
- package/publish.sh +20 -0
- package/services/CacheWrapper.ts +30 -0
- package/services/CountryCodeService.ts +507 -0
- package/shopify/ShopifyAppService.ts +109 -0
- package/shopify/ShopifyAssetService.ts +20 -0
- package/shopify/ShopifyBillingService.ts +73 -0
- package/shopify/ShopifyCartTrasnformationService.ts +207 -0
- package/shopify/ShopifyCollectionService.ts +523 -0
- package/shopify/ShopifyCustomerService.ts +472 -0
- package/shopify/ShopifyDeliveryCustomisationService.ts +220 -0
- package/shopify/ShopifyDiscountService.ts +131 -0
- package/shopify/ShopifyDraftOrderService.ts +125 -0
- package/shopify/ShopifyFulfillmentService.ts +41 -0
- package/shopify/ShopifyFunctionsProductDiscountsService.ts +166 -0
- package/shopify/ShopifyInventoryService.ts +415 -0
- package/shopify/ShopifyLocationService.ts +29 -0
- package/shopify/ShopifyOrderRefundsService.ts +138 -0
- package/shopify/ShopifyOrderRiskService.ts +19 -0
- package/shopify/ShopifyOrderService.ts +1143 -0
- package/shopify/ShopifyPageService.ts +62 -0
- package/shopify/ShopifyProductService.ts +772 -0
- package/shopify/ShopifyShippingZonesService.ts +37 -0
- package/shopify/ShopifyShopService.ts +101 -0
- package/shopify/ShopifyTemplateService.ts +30 -0
- package/shopify/ShopifyThemeService.ts +33 -0
- package/shopify/ShopifyUtils.ts +56 -0
- package/shopify/ShopifyWebhookService.ts +110 -0
- package/shopify/base/APIVersion.ts +4 -0
- package/shopify/base/AbstractService.ts +152 -0
- package/shopify/base/ErrorHelper.ts +24 -0
- package/shopify/errors/InspiraShopifyCustomError.ts +7 -0
- package/shopify/errors/InspiraShopifyError.ts +15 -0
- package/shopify/errors/InspiraShopifyUnableToReserveInventoryError.ts +7 -0
- package/shopify/helpers/ShopifyProductServiceHelper.ts +450 -0
- package/shopify/product/ShopifyProductCountService.ts +110 -0
- package/shopify/product/ShopifyProductListService.ts +333 -0
- package/shopify/product/ShopifyProductMetafieldsService.ts +405 -0
- package/shopify/product/ShopifyProductPublicationsService.ts +112 -0
- package/shopify/product/ShopifyVariantService.ts +584 -0
- package/shopify/router/ShopifyMandatoryRouter.ts +37 -0
- package/shopify/router/ShopifyRouter.ts +85 -0
- package/shopify/router/ShopifyRouterBis.ts +85 -0
- package/shopify/router/ShopifyRouterBisBis.ts +85 -0
- package/shopify/router/ShopifyRouterBisBisBis.ts +85 -0
- package/shopify/router/ShopifyRouterBisBisBisBis.ts +85 -0
- package/shopify/router/WebhookSkipMiddleware.ts +73 -0
- package/shopify/router/services/CryptoService.ts +26 -0
- package/shopify/router/services/HmacValidator.ts +36 -0
- package/shopify/router/services/OauthService.ts +17 -0
- package/shopify/router/services/RestUtils.ts +13 -0
- package/shopify/router/services/rateLimiter/MemoryStores.ts +46 -0
- package/shopify/router/services/rateLimiter/StoreRateLimiter.ts +46 -0
- package/test/README.md +223 -0
- package/test/router/ShopifyRouter.test.ts +71 -0
- package/test/router/WebhookSkipMiddleware.test.ts +86 -0
- package/test/router/services/HmacValidator.test.ts +24 -0
- package/test/router/services/RestUtils.test.ts +13 -0
- package/test/router/services/rateLimiter/StoreRateLimiter.test.ts +62 -0
- package/test/services/CacheWrapper.test.ts +30 -0
- package/test/shopify/ShopifyOrderService.test.ts +29 -0
- package/test/shopify/ShopifyProductService.test.ts +118 -0
- package/test/shopify/ShopifyWebhookService.test.ts +105 -0
- package/tsconfig.json +10 -0
- package/typings/axios.d.ts +8 -0
- package/typings/index.d.ts +1682 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { AxiosInstance, AxiosResponse } from 'axios';
|
|
2
|
+
import { Logger } from '../Logger';
|
|
3
|
+
import ErrorHelper from './base/ErrorHelper';
|
|
4
|
+
import * as LinkHeader from 'parse-link-header';
|
|
5
|
+
import APIVersion from './base/APIVersion';
|
|
6
|
+
import { ShopifyOrderService } from './ShopifyOrderService';
|
|
7
|
+
import { ShopifyInventoryService } from './ShopifyInventoryService';
|
|
8
|
+
import { ShopifyProductService } from './ShopifyProductService';
|
|
9
|
+
import InspiraShopifyError from './errors/InspiraShopifyError';
|
|
10
|
+
|
|
11
|
+
export class ShopifyOrderRefundsService {
|
|
12
|
+
|
|
13
|
+
private shopifyOrderService: ShopifyOrderService = null;
|
|
14
|
+
private shopifyInventoryService: ShopifyInventoryService = null;
|
|
15
|
+
private shopifyProductService: ShopifyProductService = null;
|
|
16
|
+
|
|
17
|
+
constructor(private axiosInstance: AxiosInstance) {
|
|
18
|
+
this.shopifyOrderService = new ShopifyOrderService(axiosInstance);
|
|
19
|
+
this.shopifyInventoryService = new ShopifyInventoryService(axiosInstance);
|
|
20
|
+
this.shopifyProductService = new ShopifyProductService(axiosInstance);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Gets all refunds from an order
|
|
25
|
+
*
|
|
26
|
+
* @param {number} orderId
|
|
27
|
+
* @param {number} limit is a test param to test the page limitation works.
|
|
28
|
+
* @returns Promise
|
|
29
|
+
*/
|
|
30
|
+
public getOrderRefunds = async (orderId: number, limit?: number): Promise<IRefund[]> => {
|
|
31
|
+
return new Promise<IRefund[]>(async (resolve, reject) => {
|
|
32
|
+
try {
|
|
33
|
+
if(!limit) { limit = 250; }
|
|
34
|
+
Logger.info(`getOrderRefunds for order ID ${orderId}`);
|
|
35
|
+
let response = await this.axiosInstance.get(`/orders/${orderId}/refunds.json?limit=${limit}`);
|
|
36
|
+
let refunds = response.data.refunds;
|
|
37
|
+
|
|
38
|
+
while(response.headers['Link'] && response.data && response.data.refunds.length > 0) {
|
|
39
|
+
Logger.info('There seems to be another refunds page');
|
|
40
|
+
const headerLinkParsed = LinkHeader(response.headers['Link']);
|
|
41
|
+
if(headerLinkParsed['next']) {
|
|
42
|
+
response = await this.getOrderRefundsByNextUrl(headerLinkParsed['next'].url);
|
|
43
|
+
refunds = refunds.concat(response.data.refunds);
|
|
44
|
+
} else {
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
resolve(refunds);
|
|
49
|
+
} catch (error) { Logger.error(error, ErrorHelper.getErrorFromResponse(error)); reject(new InspiraShopifyError(error)); }
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create a refund against an order.
|
|
55
|
+
*
|
|
56
|
+
* If quantity is bigger than the line item quantity - the quantity already refunded it will only refund the available quantity not yet refunded.
|
|
57
|
+
* It will also refund the shipping if all items have already been refunded.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} note of the refund
|
|
60
|
+
* @param {boolean} notifyCustomer when refund has been made
|
|
61
|
+
* @param {number} orderId
|
|
62
|
+
* @param {number} lineItemId of the refund
|
|
63
|
+
* @param {number} quantity of the refund. I can not be greater then the quantity of the line item.
|
|
64
|
+
* @param {number} restockQty If true will restock qty refunded to the location of the variant. (restockType = 'cancel' or restockType = 'no_restock')
|
|
65
|
+
* @returns Promise
|
|
66
|
+
*/
|
|
67
|
+
public createRefunds = async (note: string, notifyCustomer: boolean, orderId: number, lineItemId: number, quantity: number, restockQty: boolean): Promise<IRefund> => {
|
|
68
|
+
return new Promise<IRefund>(async (resolve, reject) => {
|
|
69
|
+
try {
|
|
70
|
+
const order = await this.shopifyOrderService.getById(orderId);
|
|
71
|
+
const refunds = order.refunds;
|
|
72
|
+
const lineItemToRefund = order.line_items.find((lineItem) => lineItem.id === lineItemId);
|
|
73
|
+
const lineItemQuantity = lineItemToRefund.quantity;
|
|
74
|
+
const lineItemRefundedQuantity = refunds.reduce((r, refund) => refund.refund_line_items.reduce((i, refLineItem) => refLineItem.line_item_id === lineItemId ? refLineItem.quantity : 0, 0), 0);
|
|
75
|
+
let quantityToRefund = quantity;
|
|
76
|
+
if(quantityToRefund > (lineItemQuantity - lineItemRefundedQuantity)) {
|
|
77
|
+
quantityToRefund = lineItemQuantity - lineItemRefundedQuantity;
|
|
78
|
+
}
|
|
79
|
+
if(quantityToRefund < 1) {
|
|
80
|
+
resolve({} as any);
|
|
81
|
+
} else {
|
|
82
|
+
let refundShipping = (lineItemRefundedQuantity + quantityToRefund) === lineItemQuantity;
|
|
83
|
+
if(refundShipping) {
|
|
84
|
+
Logger.info(`Refunding all quantity of the line item. Already refunded ${lineItemRefundedQuantity} + quantity to refund ${quantityToRefund}. Line item total qty ${lineItemQuantity}`);
|
|
85
|
+
for(const item of order.line_items) {
|
|
86
|
+
if(item.id !== lineItemId) {
|
|
87
|
+
Logger.info(`Checking item ${item.id}`);
|
|
88
|
+
let refundLines: IRefundLineItem[] = [];
|
|
89
|
+
for(const ref of refunds) {
|
|
90
|
+
refundLines = refundLines.concat(ref.refund_line_items.filter((rl) => rl.line_item_id === item.id));
|
|
91
|
+
}
|
|
92
|
+
const totalQtyRefunded = refundLines.reduce((r, rl) => rl.quantity, 0);
|
|
93
|
+
Logger.info(`Checking item ${item.id}. Total refunded ${totalQtyRefunded} and item qty ${item.quantity}`);
|
|
94
|
+
if(item.quantity !== totalQtyRefunded) {
|
|
95
|
+
Logger.info(`Checking item ${item.id}. No total refunded so no refunding Shipping!`);
|
|
96
|
+
refundShipping = false;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
Logger.info(`createRefunds for order ID ${orderId}. Already refunded ${lineItemRefundedQuantity} and line item quantity ${lineItemQuantity}. Quantity to refund ${quantityToRefund}`);
|
|
103
|
+
let restockType = 'no_restock';
|
|
104
|
+
let locationId = null;
|
|
105
|
+
const refundedLineItem: IRefundLineItem = { line_item_id: lineItemId, quantity: quantityToRefund };
|
|
106
|
+
if(restockQty) {
|
|
107
|
+
restockType = 'cancel';
|
|
108
|
+
const product = await this.shopifyProductService.list.getById(lineItemToRefund.product_id, { add_body_html: false, add_images: false, add_options: false, add_tags: false, add_title: false, add_variants: true, add_weight: false });
|
|
109
|
+
const variant = product.variants.find( (v) => v.id === lineItemToRefund.variant_id);
|
|
110
|
+
const levels = await this.shopifyInventoryService.getLevel(variant.inventory_item_id);
|
|
111
|
+
locationId = levels[0].location_id;
|
|
112
|
+
refundedLineItem.restock_type = restockType as any;
|
|
113
|
+
refundedLineItem.location_id = locationId;
|
|
114
|
+
} else {
|
|
115
|
+
refundedLineItem.restock_type = restockType as any;
|
|
116
|
+
}
|
|
117
|
+
const refundToPost = { refund: { notify: notifyCustomer, note: note, shipping:{ full_refund: refundShipping },
|
|
118
|
+
refund_line_items: [refundedLineItem] }};
|
|
119
|
+
Logger.info('Refunt to post', refundToPost);
|
|
120
|
+
const response = await this.axiosInstance.post(`/orders/${orderId}/refunds.json`, refundToPost );
|
|
121
|
+
resolve(response.data.refund);
|
|
122
|
+
}
|
|
123
|
+
} catch (error) { Logger.error(error, ErrorHelper.getErrorFromResponse(error)); reject(new InspiraShopifyError(error)); }
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
private getOrderRefundsByNextUrl = async (url: string): Promise<AxiosResponse> => {
|
|
128
|
+
return new Promise<AxiosResponse>(async (resolve, reject) => {
|
|
129
|
+
try {
|
|
130
|
+
Logger.info(`getOrderRefundsByNextUrl for url ${url}`);
|
|
131
|
+
const uri = url.substring(url.indexOf(APIVersion.API_URL) + APIVersion.API_URL.length);
|
|
132
|
+
Logger.info(`getOrderRefundsByNextUrl for uri ${uri}`);
|
|
133
|
+
const response = await this.axiosInstance.get(`${uri}`);
|
|
134
|
+
resolve(response);
|
|
135
|
+
} catch (error) { Logger.error(error, ErrorHelper.getErrorFromResponse(error)); reject(new InspiraShopifyError(error)); }
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AxiosInstance } from 'axios';
|
|
2
|
+
import { Logger } from '../Logger';
|
|
3
|
+
import ErrorHelper from './base/ErrorHelper';
|
|
4
|
+
import InspiraShopifyError from './errors/InspiraShopifyError';
|
|
5
|
+
|
|
6
|
+
export class ShopifyOrderRiskService {
|
|
7
|
+
|
|
8
|
+
constructor(private axiosInstance: AxiosInstance) { }
|
|
9
|
+
|
|
10
|
+
public getFromOrderById = async (orderId: number): Promise<IRisk[]> => {
|
|
11
|
+
return new Promise<IRisk[]>(async (resolve, reject) => {
|
|
12
|
+
try {
|
|
13
|
+
Logger.info(`getting order Risks for ID ${orderId}`);
|
|
14
|
+
const response = await this.axiosInstance.get(`/orders/${orderId}/risks.json`);
|
|
15
|
+
resolve(response.data.risks);
|
|
16
|
+
} catch (error) { Logger.error(error, ErrorHelper.getErrorFromResponse(error)); reject(new InspiraShopifyError(error)); }
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
}
|