Passed
Push — trunk ( 61b9d3...670c99 )
by Christian
12:39 queued 11s
created

src/Administration/Resources/app/administration/src/module/sw-order/state/order.store.ts   C

Complexity

Total Complexity 54
Complexity/F 1.59

Size

Lines of Code 316
Function Count 34

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 246
dl 0
loc 316
rs 6.4799
c 0
b 0
f 0
wmc 54
mnd 20
bc 20
fnc 34
bpm 0.5881
cpm 1.5882
noi 0

34 Functions

Rating   Name   Duplication   Size   Complexity  
A order.store.ts ➔ updateContextParameters 0 10 5
A order.store.ts ➔ addPromotionCode 0 8 1
A order.store.ts ➔ invalidPromotionCodes 0 3 1
A order.store.ts ➔ mergeEmptyAndExistingLineItems 0 6 1
A order.store.ts ➔ updateOrderContext 0 5 1
A order.store.ts ➔ getContext 0 4 1
A order.store.ts ➔ setCart 0 5 1
A order.store.ts ➔ setContext 0 3 1
A order.store.ts ➔ setTestOrder 0 3 1
A order.store.ts ➔ cartErrors 0 3 5
A order.store.ts ➔ updateCustomerContext 0 5 1
A order.store.ts ➔ isCustomerActive 0 2 3
A order.store.ts ➔ isCartTokenAvailable 0 3 3
A order.store.ts ➔ setCurrency 0 4 1
A order.store.ts ➔ currencyId 0 3 4
A order.store.ts ➔ removeLineItems 0 9 1
A order.store.ts ➔ getCart 0 13 2
A order.store.ts ➔ setCustomer 0 3 1
A order.store.ts ➔ reverseLineItems 0 3 1
A order.store.ts ➔ filterEmptyLineItems 0 3 1
A order.store.ts ➔ removeInvalidPromotionCodes 0 3 1
A order.store.ts ➔ setDefaultSalesChannel 0 3 1
A order.store.ts ➔ saveOrder 0 4 1
A order.store.ts ➔ saveLineItem 0 8 1
A order.store.ts ➔ cancelCart 0 7 2
A order.store.ts ➔ createCart 0 15 1
A order.store.ts ➔ setCartLineItems 0 3 1
A order.store.ts ➔ remindPayment 0 4 1
A order.store.ts ➔ setPromotionCodes 0 3 1
A order.store.ts ➔ modifyShippingCosts 0 10 1
A order.store.ts ➔ setCartToken 0 3 1
A order.store.ts ➔ selectExistingCustomer 0 3 4
A order.store.ts ➔ setDisabledAutoPromotion 0 3 1
A order.store.ts ➔ removeEmptyLineItem 0 3 1

How to fix   Complexity   

Complexity

Complex classes like src/Administration/Resources/app/administration/src/module/sw-order/state/order.store.ts often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import type { Module } from 'vuex';
2
import type { AxiosResponse } from 'axios';
3
import type {
4
    CalculatedPrice,
5
    Cart,
6
    CartError,
7
    ContextSwitchParameters,
8
    Currency,
9
    Customer,
10
    LineItem,
11
    PaymentMethod,
12
    PromotionCodeTag,
13
    SalesChannel,
14
    SalesChannelContext,
15
    ShippingMethod,
16
} from '../order.types';
17
18
const { Service } = Shopware;
19
20
function filterEmptyLineItems(items: LineItem[]) {
21
    return items.filter(item => item.label === '');
22
}
23
24
function reverseLineItems(items: LineItem[]) {
25
    return items.slice().reverse();
26
}
27
28
function mergeEmptyAndExistingLineItems(emptyLineItems: LineItem[], lineItems: LineItem[]) {
29
    // Reverse the lineItems so the newly added are at the top for better UX
30
    reverseLineItems(lineItems);
31
32
    return [...emptyLineItems, ...lineItems];
33
}
34
35
interface SwOrderState {
36
    cart: Cart;
37
    disabledAutoPromotion: boolean,
38
    testOrder: boolean,
39
    promotionCodes: PromotionCodeTag[],
40
    defaultSalesChannel: SalesChannel | null,
41
    context: SalesChannelContext,
42
    customer: Customer | null,
43
44
    /**
45
     * @deprecated tag:v6.5.0 - Use `context.currency` instead
46
     */
47
    currency: Currency,
48
}
49
50
const SwOrderStore: Module<SwOrderState, VuexRootState> = {
51
    namespaced: true,
52
53
    state: (): SwOrderState => ({
54
        customer: null,
55
        defaultSalesChannel: null,
56
        cart: {
57
            token: null,
58
            lineItems: [],
59
            price: {
60
                totalPrice: null,
61
            },
62
            deliveries: [],
63
        } as unknown as Cart,
64
        currency: {
65
            shortName: 'EUR',
66
            symbol: '€',
67
            totalRounding: {
68
                decimals: 2,
69
            },
70
        } as unknown as Currency,
71
        context: {
72
            token: '',
73
            customer: null,
74
            paymentMethod: {
75
                translated: {
76
                    distinguishableName: '',
77
                },
78
            } as PaymentMethod,
79
            shippingMethod: {
80
                translated: {
81
                    name: '',
82
                },
83
            } as ShippingMethod,
84
            currency: {
85
                shortName: 'EUR',
86
                symbol: '€',
87
                totalRounding: {
88
                    decimals: 2,
89
                },
90
            } as Currency,
91
            salesChannel: {
92
                id: '',
93
            } as SalesChannel,
94
            context: {
95
                currencyId: '',
96
                languageIdChain: [],
97
            },
98
        },
99
        promotionCodes: [],
100
        disabledAutoPromotion: false,
101
        testOrder: false,
102
    }),
103
104
    mutations: {
105
        setCustomer(state: SwOrderState, customer: Customer) {
106
            state.context.customer = customer;
107
            state.customer = customer;
108
        },
109
110
        setDefaultSalesChannel(state: SwOrderState, salesChannel: SalesChannel) {
111
            state.defaultSalesChannel = salesChannel;
112
        },
113
114
        setCartToken(state: SwOrderState, token: string) {
115
            state.cart.token = token;
116
        },
117
118
        setCart(state: SwOrderState, cart: Cart) {
119
            const emptyLineItems = filterEmptyLineItems(state.cart.lineItems);
120
            state.cart = cart;
121
            state.cart.lineItems = mergeEmptyAndExistingLineItems(emptyLineItems, state.cart.lineItems);
122
        },
123
124
        setCartLineItems(state: SwOrderState, lineItems: LineItem[]) {
125
            state.cart.lineItems = lineItems;
126
        },
127
128
        setCurrency(state: SwOrderState, currency: Currency) {
129
            state.context.currency = currency;
130
            state.currency = currency;
131
        },
132
133
        setContext(state: SwOrderState, context: SalesChannelContext) {
134
            state.context = context;
135
        },
136
137
        setPromotionCodes(state: SwOrderState, promotionCodes: PromotionCodeTag[]) {
138
            state.promotionCodes = promotionCodes;
139
        },
140
141
        removeEmptyLineItem(state: SwOrderState, emptyLineItemKey: string) {
142
            state.cart.lineItems = state.cart.lineItems.filter(item => item.id !== emptyLineItemKey);
143
        },
144
145
        removeInvalidPromotionCodes(state: SwOrderState) {
146
            state.promotionCodes = state.promotionCodes.filter(item => !item.isInvalid);
147
        },
148
149
        setDisabledAutoPromotion(state: SwOrderState, disabledAutoPromotion: boolean) {
150
            state.disabledAutoPromotion = disabledAutoPromotion;
151
        },
152
153
        setTestOrder(state: SwOrderState, testOrder: boolean) {
154
            state.testOrder = testOrder;
155
        },
156
    },
157
158
    getters: {
159
        isCustomerActive(state: SwOrderState): boolean {
160
            return !!state?.context.customer?.active;
161
        },
162
163
        isCartTokenAvailable(state: SwOrderState): boolean {
164
            return !!state?.cart?.token;
165
        },
166
167
        currencyId(state: SwOrderState): string {
168
            return state?.context.context.currencyId ?? '';
169
        },
170
171
        invalidPromotionCodes(state: SwOrderState): PromotionCodeTag[] {
172
            return state.promotionCodes.filter(item => item.isInvalid);
173
        },
174
175
        cartErrors(state: SwOrderState): CartError[] {
176
            return state?.cart?.errors ?? null;
177
        },
178
    },
179
180
    actions: {
181
        selectExistingCustomer({ commit }, { customer }: { customer: Customer }) {
182
            commit('setCustomer', customer);
183
            commit('setDefaultSalesChannel', { ...(customer?.salesChannel ?? null) });
184
        },
185
186
        createCart({ commit }, { salesChannelId }: { salesChannelId: string }) {
187
            return Service('cartStoreService')
188
                .createCart(salesChannelId)
189
                // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
190
                .then((response: AxiosResponse): string => {
191
                    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
192
                    const token = response.data.token as string;
193
                    commit('setCartToken', token);
194
                    return token;
195
                })
196
                .then((contextToken) => {
197
                    return Service('contextStoreService')
198
                        .getSalesChannelContext(salesChannelId, contextToken)
199
                        .then((response: AxiosResponse) => commit('setContext', response.data));
200
                });
201
        },
202
203
        getCart({ commit }, { salesChannelId, contextToken }: { salesChannelId: string, contextToken: string }) {
204
            if (Shopware.Feature.isActive('FEATURE_NEXT_7530') && (`${contextToken}`).length !== 32) {
205
                throw new Error('Invalid context token');
206
            }
207
208
            return Promise.all([
209
                Service('cartStoreService')
210
                    .getCart(salesChannelId, contextToken)
211
                    .then((response: AxiosResponse) => commit('setCart', response.data)),
212
                Service('contextStoreService')
213
                    .getSalesChannelContext(salesChannelId, contextToken)
214
                    .then((response: AxiosResponse) => commit('setContext', response.data)),
215
            ]);
216
        },
217
218
        cancelCart(_, { salesChannelId, contextToken }: { salesChannelId: string, contextToken: string }) {
219
            if (Shopware.Feature.isActive('FEATURE_NEXT_7530') && (`${contextToken}`).length !== 32) {
220
                throw new Error('Invalid context token');
221
            }
222
223
            return Service('cartStoreService').cancelCart(salesChannelId, contextToken);
224
        },
225
226
        updateCustomerContext(_, { customerId, salesChannelId, contextToken }:
227
            { customerId: string, salesChannelId: string, contextToken: string }) {
228
            return Service('contextStoreService')
229
                .updateCustomerContext(customerId, salesChannelId, contextToken);
230
        },
231
232
        updateOrderContext(_, { context, salesChannelId, contextToken }:
233
            { context: ContextSwitchParameters, salesChannelId: string, contextToken: string }) {
234
            return Service('contextStoreService')
235
                .updateContext(context, salesChannelId, contextToken);
236
        },
237
238
        getContext(_, { salesChannelId, contextToken }: { salesChannelId: string, contextToken: string }) {
239
            return Service('contextStoreService')
240
                .getSalesChannelContext(salesChannelId, contextToken);
241
        },
242
243
        saveOrder(_, { salesChannelId, contextToken }: { salesChannelId: string, contextToken: string }) {
244
            return Service('checkoutStoreService')
245
                .checkout(salesChannelId, contextToken);
246
        },
247
248
        removeLineItems(
249
            { commit },
250
            { salesChannelId, contextToken, lineItemKeys }:
251
                { salesChannelId: string, contextToken: string, lineItemKeys: string[] },
252
        ) {
253
            return Service('cartStoreService')
254
                .removeLineItems(salesChannelId, contextToken, lineItemKeys)
255
                .then((response: AxiosResponse) => commit('setCart', response.data));
256
        },
257
258
        saveLineItem(
259
            { commit },
260
            { salesChannelId, contextToken, item }: { salesChannelId: string, contextToken: string, item: LineItem },
261
        ) {
262
            return Service('cartStoreService')
263
                .saveLineItem(salesChannelId, contextToken, item)
264
                .then((response: AxiosResponse) => commit('setCart', response.data));
265
        },
266
267
        addPromotionCode(
268
            { commit },
269
            { salesChannelId, contextToken, code }: { salesChannelId: string, contextToken: string, code: string },
270
        ): Promise<void> {
271
            return Service('cartStoreService')
272
                .addPromotionCode(salesChannelId, contextToken, code)
273
                .then(response => commit('setCart', response.data));
274
        },
275
276
        modifyShippingCosts(
277
            { commit },
278
            { salesChannelId, contextToken, shippingCosts }:
279
                { salesChannelId: string, contextToken: string, shippingCosts: CalculatedPrice },
280
        ) {
281
            return Service('cartStoreService')
282
                .modifyShippingCosts(salesChannelId, contextToken, shippingCosts)
283
                // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
284
                .then((response: AxiosResponse) => commit('setCart', response.data.data));
285
        },
286
287
        remindPayment(_, { orderTransactionId }: { orderTransactionId: string }) {
288
            return Service('orderStateMachineService')
289
                .transitionOrderTransactionState(orderTransactionId, 'remind');
290
        },
291
292
        updateContextParameters({ state }, context: ContextSwitchParameters): void {
293
            context.currencyId = context.currencyId || state.context.context.currencyId;
294
            context.languageId = context.languageId || state.context.context.languageIdChain[0];
295
            context.shippingMethodId = context.shippingMethodId || state.context.shippingMethod.id;
296
            context.paymentMethodId = context.paymentMethodId || state.context.paymentMethod.id;
297
            // eslint-disable-next-line max-len
298
            context.billingAddressId = context.billingAddressId || state.context.customer?.activeBillingAddress?.id || null;
299
            // eslint-disable-next-line max-len
300
            context.shippingAddressId = context.shippingAddressId || state.context.customer?.activeShippingAddress?.id || null;
301
        },
302
    },
303
};
304
305
/**
306
 * @private
307
 */
308
export default SwOrderStore;
309
310
/**
311
 * @private
312
 */
313
export type {
314
    SwOrderState,
315
};
316
317