Passed
Push — 6.4 ( a2ab34...70d76f )
by Christian
13:23 queued 14s
created

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

Complexity

Total Complexity 49
Complexity/F 1.48

Size

Lines of Code 308
Function Count 33

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 238
dl 0
loc 308
rs 8.48
c 0
b 0
f 0
wmc 49
mnd 16
bc 16
fnc 33
bpm 0.4848
cpm 1.4847
noi 0

33 Functions

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