Class: Comee::Core::SalesOrderService

Inherits:
Object
  • Object
show all
Defined in:
app/services/comee/core/sales_order_service.rb

Instance Method Summary collapse

Instance Method Details

#accept(id) ⇒ Object

Raises:

  • (StandardError)


182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'app/services/comee/core/sales_order_service.rb', line 182

def accept(id)
  order = SalesOrder.find_by(id: id)
  raise(StandardError, "Sales order with id `#{id}` not found.") unless order

  raise(StandardError, "Sales order should be in confirmed state.") unless order.confirmed?

  raise(StandardError, "Sales order should have at least one item.") unless order.sales_order_items.count.positive?

  raise(StandardError, "All items are canceled for sales order.") if order.sales_order_items.all?(&:canceled?)

  order.update!(status: SalesOrder.statuses[:accepted])
  order
end

#aggregate_back_order_item(items, supplier_id, back_order_id, delivery_date) ⇒ Object

This method returns items aggregated by product for a supplier. It recieves items, supplier_id and back_order_id as a parameter

The +items+ is an array containing list of back order items
  The +items+ param looks like [{product_id: '', requested_quantity: ''},...]
The +supplier_id+ is the id of the supplier under which the items belong to
The +back_order_id+ is the id of the backer order under which the items belong to


86
87
88
89
90
91
92
# File 'app/services/comee/core/sales_order_service.rb', line 86

def aggregate_back_order_item(items, supplier_id, back_order_id, delivery_date)
  items.group_by { |item| item[:product_id] }.map do |product_id, aggregated_items|
    total_quantity = aggregated_items.reduce(0) { |sum, agg_item| agg_item[:requested_quantity] + sum }
    {product_id: product_id, requested_quantity: total_quantity, supplier_quantity: total_quantity, supplier_id: supplier_id,
     back_order_id: back_order_id, delivery_date: delivery_date}
  end
end

#assign_price_to_items(items) ⇒ Object

This method assigns current purchase price for a product under a given supplier. It recieves items containing array of products along with the corresponding suppliers The items param looks like [

{product_id: '', requested_quantity: '', supplier_quantity: '', supplier_id: '', back_order_id: '' },
...

] It assigns price by first fetching the price of products in the items array and then iterate through the items array and find the corresponding price from the fetched price



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'app/services/comee/core/sales_order_service.rb', line 103

def assign_price_to_items(items)
  queries = []
  items.map { |bo_item| queries << {supplier_id: bo_item[:supplier_id], product_id: bo_item[:product_id]} }
  master_prices = queries.inject(Comee::Core::MasterPrice.none) do |conditions, condition|
    conditions.or(Comee::Core::MasterPrice.where(condition))
  end
  items.each do |item|
    mp = master_prices.find { |price| price.supplier_id == item[:supplier_id] && price.product_id == item[:product_id] }
    item[:requested_unit_price] = mp.purchase_price
    item[:supplier_unit_price] = mp.purchase_price
    item[:from] = mp.valid_from
    item[:to] = mp.valid_from
    item.delete(:supplier_id)
  end
end

#bulk_create_back_order(params) ⇒ Object

This method returns { success: true} if all back orders in the params created successfully. The params contain array of back orders with the corresponding products. The exact structure of params looks like the following [”, order_number: ”, order_date: ”, delivery_date: ”, delivery_address: ”, invoice_address: ”,

back_order_items: [{product_id: '', requested_quantity: '',...] }...]

This method uses insert_all method to create back order and its items in bulk



126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'app/services/comee/core/sales_order_service.rb', line 126

def bulk_create_back_order(params)
  back_orders = params.map { |p| {**p.except(:back_order_items), created_at: Time.now, updated_at: Time.now} }
  result = Comee::Core::BackOrder.insert_all!(back_orders, returning: %w[id supplier_id delivery_date])
  aggregated_items = []
  result.pluck("id", "supplier_id", "delivery_date").each do |r|
    supplier_detail = params.find { |p| p[:supplier_id].to_i == r[1] }
    aggregated_items << aggregate_back_order_item(supplier_detail[:back_order_items], r[1], r[0], r[2])
  end
  Comee::Core::BackOrderItem.insert_all!(assign_price_to_items(aggregated_items.flatten))
  {success: true}
rescue StandardError => e
  {success: false, error: e.message}
end

#cancel(id) ⇒ Object

Raises:

  • (StandardError)


196
197
198
199
200
201
202
203
204
# File 'app/services/comee/core/sales_order_service.rb', line 196

def cancel(id)
  order = SalesOrder.find_by(id: id)
  raise(StandardError, "Sales order with id `#{id}` not found.") unless order

  raise(StandardError, "Sales order is already canceled.") if order.canceled?

  order.update!(status: SalesOrder.statuses[:canceled])
  order
end

#check_duplicate_order_number(params) ⇒ Object

This method returns false if there is no duplicate order number, otherwise it raises an error. The params contain array of back orders with the corresponding products. The exact structure of params looks like the following [”, order_number: ”, order_date: ”, delivery_date: ”, delivery_address: ”, invoice_address: ”,

back_order_items: [{product_id: '', requested_quantity: '',...] }...]

The method first checks if there is duplicate order number within in the params array, and if not then it checks for duplicate order number from back order table.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'app/services/comee/core/sales_order_service.rb', line 62

def check_duplicate_order_number(params)
  order_numbers = params.map { |param| param[:order_number] }
  unless order_numbers.uniq.count == order_numbers.count
    raise(StandardError, "Duplicate order number(s) #{order_numbers.select do |e|
                                                        order_numbers.count(e) > 1
                                                      end.uniq.join(', ')} exist in the payload.")
  end

  duplicate_order_numbers = Comee::Core::BackOrder.where(order_number: order_numbers)
  unless duplicate_order_numbers.count.zero?
    raise(StandardError,
          "Duplicate order number(s) #{duplicate_order_numbers.map(&:order_number).join(', ')} exist in the back order table.")
  end

  false
end

#check_product_prices(params) ⇒ Object

This method returns true if all products under each back order in params have active price in the master price table. The params contain array of back orders with the corresponding products. The exact structure of params looks like the following [”, order_number: ”, order_date: ”, delivery_date: ”, delivery_address: ”, invoice_address: ”,

back_order_items: [{product_id: '', requested_quantity: '',...] }...]

Raises:

  • (StandardError)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'app/services/comee/core/sales_order_service.rb', line 22

def check_product_prices(params)
  queries = []
  params.each do |param|
    param[:back_order_items].map do |bo_item|
      queries << {supplier_id: param[:supplier_id], product_id: bo_item[:product_id]}
    end
  end
  master_prices = queries.inject(Comee::Core::MasterPrice.none) do |conditions, condition|
    conditions.or(Comee::Core::MasterPrice.where(condition))
  end

  raise(StandardError, compose_error_messge(queries, master_prices)) unless queries.count == master_prices.count

  true
end

#compose_error_messge(queries, master_prices) ⇒ Object

This method composes an error message when called from check_product_prices. It recieves queries and master_prices as a parameter

The +queries+ is an array containing list of conditions that will be joined using or connector
  The +queries+ param looks like [{supplier_id: '', product_id: '', active: true},...]
The +master_prices+ param contains master prices fetched by the queries param given above

The message is composed by computing difference b/n the queries and master prices params



45
46
47
48
49
50
51
52
# File 'app/services/comee/core/sales_order_service.rb', line 45

def compose_error_messge(queries, master_prices)
  result = master_prices.map { |mp| {supplier_id: mp[:supplier_id], product_id: mp[:product_id]} }
  diff = queries - result
  product_names = Comee::Core::Product.where(id: diff.map { |dif| dif[:product_id] }).pluck("name").join(", ")
  supplier_names = Comee::Core::Supplier.where(id: diff.map { |dif| dif[:supplier_id] }).pluck("name").join(", ")
  "The following products #{product_names} do not have price entry for the following suppliers" \
  " #{supplier_names} in the master price table or the prices are not valid."
end

#confirm(id) ⇒ Object

order.update!(status: SalesOrder.statuses)

order

end

Raises:

  • (StandardError)


168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'app/services/comee/core/sales_order_service.rb', line 168

def confirm(id)
  order = SalesOrder.find_by(id: id)
  raise(StandardError, "Sales order with id `#{id}` not found.") unless order

  raise(StandardError, "Sales order should be in submitted state.") unless order.

  raise(StandardError, "Sales order should have at least one item.") unless order.sales_order_items.count.positive?

  raise(StandardError, "All items are canceled for sales order.") if order.sales_order_items.all?(&:canceled?)

  order.update!(status: SalesOrder.statuses[:confirmed])
  order
end

#create_back_orders(params) ⇒ Object

This method returns { success: true} if all back orders in the params created successfully. The params contain array of back orders with the corresponding products. The exact structure of params looks like the following [”, order_number: ”, order_date: ”, delivery_date: ”, delivery_address: ”, invoice_address: ”,

back_order_items: [{product_id: '', requested_quantity: '',...] }...]


10
11
12
13
14
# File 'app/services/comee/core/sales_order_service.rb', line 10

def create_back_orders(params)
  check_product_prices(params)
  check_duplicate_order_number(params)
  bulk_create_back_order(params)
end

#revert(id) ⇒ Object

Raises:

  • (StandardError)


206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'app/services/comee/core/sales_order_service.rb', line 206

def revert(id)
  order = SalesOrder.find_by(id: id)
  raise(StandardError, "Sales order with id `#{id}` not found.") unless order

  raise(StandardError, "Sales order should be in draft state.") unless order.draft?

  customer_order = order.customer_order

  ActiveRecord::Base.transaction do
    Comee::Core::SalesOrderItem.where(sales_order: order).delete_all
    order.delete
    customer_order.status = Comee::Core::CustomerOrder.statuses[:draft]
    customer_order.save!
  end
  customer_order
end

#submit(id) ⇒ Object

Raises:

  • (StandardError)


140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'app/services/comee/core/sales_order_service.rb', line 140

def submit(id)
  order = SalesOrder.find_by(id: id)
  raise(StandardError, "Sales order with id `#{id}` not found.") unless order

  raise(StandardError, "Sales order should be in draft state.") unless order.draft?

  raise(StandardError, "Sales order should have at least one item.") unless order.sales_order_items.count.positive?

  raise(StandardError, "All items are canceled for sales order.") if order.sales_order_items.all?(&:canceled?)

  order.update!(status: SalesOrder.statuses[:submitted])
  order
end