app/Services/OrderService.ts   A
last analyzed

Complexity

Total Complexity 9
Complexity/F 0

Size

Lines of Code 175
Function Count 0

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 9
eloc 86
mnd 9
bc 9
fnc 0
dl 0
loc 175
bpm 0
cpm 0
noi 0
c 0
b 0
f 0
rs 10
1
import { AuthContract } from '@ioc:Adonis/Addons/Auth'
2
import Product from 'App/Models/Product'
3
import Ingredient from 'App/Models/Ingredient'
4
import Order from 'App/Models/Order'
5
import Event from '@ioc:Adonis/Core/Event'
6
7
type ORDER = {
8
  product_id: number,
9
  quantity: number
10
} | undefined
11
12
/**
13
 * Add Order To Collection.
14
 *
15
 * @param  Array<any> validated
16
 * @return Map<number, \App\Models\ORDER>
17
 */
18
export const addOrderToCollection = (validated: Array<any>): Map<number, ORDER> => {
19
  const collection = new Map()
20
21
  validated.map((ele: ORDER) => {
22
    if (ele !== undefined) {
23
      if (collection.has(ele.product_id)) {
24
        ele.quantity = ele.quantity + collection.get(ele.product_id).quantity
25
      }
26
27
      collection.set(ele.product_id, ele)
28
    }
29
  })
30
31
  return collection
32
}
33
34
/**
35
 * Filter ProductIDs.
36
 *
37
 * @param Map<number, \App\Models\ORDER> collection
38
 * @return Array<number>
39
 */
40
export const filterProductIDs = (collection: Map<number, ORDER>): Array<number> => {
41
  return Array.from(collection.keys())
42
}
43
44
/**
45
 * Get Products.
46
 *
47
 * @param Array<number> productIDs
48
 * @return Promise<\App\Model\Product[]>
49
 */
50
export const getProducts = async (productIDs: Array<number>): Promise<Product[]> => {
51
  return await Product.query().whereIn('id', productIDs).exec()
52
}
53
54
/**
55
 * Get Orders.
56
 *
57
 * @param \App\Models\Product[] products
58
 * @param Map<number, \App\Models\ORDER> collection
59
 * @param AuthContract auth
60
 * @return Promise<\App\Models\Order[]>
61
 */
62
export const getOrders = async (products: Product[], collection: Map<number, ORDER>, auth: AuthContract): Promise<Order[]> => {
63
  return await Promise.all(
64
    products.map(async (product: Product) => {
65
      return await processOrder(product, collection, auth)
66
    })
67
  )
68
}
69
70
/**
71
 * Get Order Row.
72
 *
73
 * @param \App\Models\Product product
74
 * @param Map<number, \App\Models\ORDER> collection
75
 * @return \App\Models\ORDER
76
 */
77
const getOrderRow = (product: Product, collection: Map<number, ORDER>): ORDER => {
78
  return collection.get(product.id)
79
}
80
81
/**
82
 * Get Product Ingredients.
83
 *
84
 * @param \App\Models\Product product
85
 * @param Map<number, \App\Models\ORDER> collection
86
 * @return Promise<\App\Models\Ingredient[]|null>
87
 */
88
const getProductIngredients = async (product: Product, collection: Map<number, ORDER>): Promise<Ingredient[]|null> => {
89
  const row: ORDER = getOrderRow(product, collection)
90
  const ingredients = await product.related('ingredients').query()
91
        .pivotColumns(['quantity']).exec()
92
93
  const isQuantityOkay = ingredients.every((ingredient: Ingredient) => {
94
    if (row !== undefined) {
95
      const quantity = row.quantity * ingredient.pivotQuantity
96
      return ingredient.quantityAvailable > quantity
97
    }
98
99
    return false
100
  })
101
102
  if (!isQuantityOkay) {
103
    return null
104
  }
105
106
  return ingredients
107
}
108
109
/**
110
 * Save Order.
111
 *
112
 * @param \App\Models\Product product
113
 * @param Map<number, \App\Models\ORDER> collection
114
 * @param AuthContract auth
115
 * @param \bool status
116
 * @return Promise<\App\Models\Order>
117
 */
118
const saveOrder = async (product: Product, collection: Map<number, ORDER>, auth: AuthContract, status: boolean = true): Promise<Order> => {
119
  const row: ORDER = getOrderRow(product, collection)
120
121
  return await Order.create({
122
    userId: auth.use('api').user?.id,
123
    productId: product.id,
124
    quantity: row?.quantity,
125
    isSuccessful: status ? 1 : 0
126
  })
127
}
128
129
/**
130
 * Process Order.
131
 *
132
 * @param \App\Models\Product product
133
 * @param Map<number, \App\Models\ORDER> collection
134
 * @param AuthContract auth
135
 * @return Promise<\App\Models\Order>
136
 */
137
const processOrder = async (product: Product, collection: Map<number, ORDER>, auth: AuthContract): Promise<Order> =>
138
{
139
  const ingredients = await getProductIngredients(product, collection)
140
141
  if (ingredients === null) {
142
      return await saveOrder(product, collection, auth, false)
143
  }
144
145
  ingredients.map(async (ingredient: Ingredient) => {
146
    await updateIngredientQuantity(product, collection, ingredient)
147
  })
148
149
  return await saveOrder(product, collection, auth)
150
}
151
152
/**
153
 * Update Ingredient Quantity.
154
 *
155
 * @param \App\Models\Product product
156
 * @param Map<number, \App\Models\ORDER> collection
157
 * @param \App\Models\Ingredient ingredient
158
 * @return Promise<void>
159
 */
160
const updateIngredientQuantity = async (product: Product, collection: Map<number, ORDER>, ingredient: Ingredient): Promise<void> => {
161
  const row: ORDER = getOrderRow(product, collection)
162
163
  if (row !== undefined) {
164
    const quantityTaken = row.quantity * ingredient.pivotQuantity
165
166
    await ingredient.merge({
167
        quantityAvailable: ingredient.quantityAvailable - quantityTaken,
168
        lastReorderAt: ingredient.lastReorderAt
169
    }).save()
170
  }
171
172
  //Dispatch event
173
  Event.emit('merchant:reorderlevel', ingredient)
174
}
175