Class: Comee::Core::CustomerOrderService

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

Instance Method Summary collapse

Instance Method Details

#accept(id, accepted_by = nil) ⇒ Object

Raises:

  • (StandardError)


136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'app/services/comee/core/customer_order_service.rb', line 136

def accept(id, accepted_by = nil)
  order = CustomerOrder.find_by(id: id)
  raise(StandardError, "Customer order with id `#{id}` not found.") unless order

  if CustomerOrder.statuses[order.status] == CustomerOrder.statuses[:accepted]
    raise(StandardError, "Customer order is already in accepted state.")
  end

  allowed_statuses = [CustomerOrder.statuses[:submitted], CustomerOrder.statuses[:awaiting_confirmation]]
  unless allowed_statuses.include?(CustomerOrder.statuses[order.status])
    raise(StandardError, "Customer order should be in submitted or awaiting confirmation state.")
  end

  if order.customer_order_items.count.zero? ||
     order.customer_order_items.all?(&:canceled?)
    raise(StandardError, "Customer order does not have any items.")
  end

  sales_order = nil
  CustomerOrder.transaction do
    sales_order = SalesOrder.create!(
      order_date: order.order_date,
      customer_order: order,
      status: SalesOrder.statuses[:draft],
      client: order.client,
      order_terms: order.order_terms,
      shipment_address: order.shipment_address,
      invoice_address: order.invoice_address,
      delivery_address: order.delivery_address,
      destination: order.final_destination,
      handover_date: order.handover_date,
      shipping_date: order.shipping_date,
      delivery_date: order.final_delivery_date,
      consignee: order.consignee,
      created_by: accepted_by || "",
      consolidator_date: order.consolidator_date,
      voyage_no: order.voyage_no,
      shipping_arrangement: order.shipping_arrangement
    )
    order_items = order.customer_order_items.includes(:product, :unit)
    client_id = order.client.parent_id || order.client_id
    product_ids = order_items.map(&:product_id).uniq
    client_prices = ClientPrice.where(
      client_id: client_id,
      product_id: product_ids,
      status: ClientPrice.statuses[:current]
    )
    master_prices = MasterPrice.includes(:supplier).where(primary: true, status: Price.statuses[:current],
                                                          product_id: product_ids)

    items = order_items.each_with_object([]) do |item, res|
      next if item.canceled?

      default_unit = item.product.default_unit
      unit_id = default_unit ? default_unit["id"] : item.unit_id
      quantity = convert_quantity(item.quantity, item.unit_id, unit_id)
      client_price = client_prices.find { |price| price.product_id == item.product_id }
      master_price = master_prices.find { |price| price.product_id == item.product_id }
      raise(StandardError, "No primary supplier found for product #{item.customer_item_no}") unless master_price

      product_lookup = master_price.product_lookup
      order_price = convert_price(item.price, item.unit_id, unit_id)
      price = if client_price
                convert_price(client_price.price, client_price.unit_id, unit_id)
              else
                convert_price(master_price.selling_price, master_price.unit_id, unit_id)
              end

      res << {
        sales_order_id: sales_order.id,
        customer_order_item_id: item.id,
        product_id: item.product_id,
        unit_id: unit_id,
        serial_no: item.serial_no,
        customer_item_no: item.customer_item_no,
        customer_item_alias: item.customer_item_alias,
        customer_item_description: item.customer_item_description,
        quantity: quantity,
        price: price,
        price_diff: price - order_price,
        total_price: quantity * price,
        delivery_date: item.delivery_date,
        handover_date: order.handover_date,
        lead_time: master_price&.lead_time,
        use_alias: item.use_alias,
        additional_details: {
          supplier_id: master_price.supplier_id,
          supplier_name: master_price.supplier.name,
          supplier_item_no: product_lookup&.code,
          supplier_description: product_lookup&.item_description,
          country_of_origin: master_price&.country_of_origin
        }
      }
    end
    SalesOrderItem.insert_all!(items)
    order.update!(status: CustomerOrder.statuses[:accepted])
    sales_order.calculate_total_price
    sales_order.calculate_vat
    sales_order.save!
  end
  sales_order
end

#cancel(id) ⇒ Object

Raises:

  • (StandardError)


239
240
241
242
243
244
245
246
247
248
249
# File 'app/services/comee/core/customer_order_service.rb', line 239

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

  if CustomerOrder.statuses[order.status] == CustomerOrder.statuses[:canceled]
    raise(StandardError, "Customer order is already canceled.")
  end

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

#convert_price(price, unit_id, new_unit_id) ⇒ Numeric

This method converts a price value per a unit of measure to a price value per another unit of measure.

Parameters:

  • price (Numeric)

    the price value

  • unit (Numeric)

    the unit id of measure for the price

  • new_unit (Numeric)

    the new unit id of measure

Returns:

  • (Numeric)

    the converted price for the new unit



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'app/services/comee/core/customer_order_service.rb', line 39

def convert_price(price, unit_id, new_unit_id)
  return price if unit_id == new_unit_id

  conversions = UnitConversion.where("from_id = ? AND to_id = ?", unit_id, new_unit_id)
                              .or(UnitConversion.where("from_id = ? AND to_id = ?", new_unit_id, unit_id))
  unless conversions.count.positive?
    units = Unit.where(id: [unit_id, new_unit_id]).select(:code)
    raise(StandardError, "There is no conversion factor between #{units[0].code} and #{units[1].code}.")
  end

  conversion = conversions.first
  return (price / conversion.factor).round(2) if unit_id == conversion.from_id && new_unit_id == conversion.to_id

  (price * conversion.factor).round(2)
end

#convert_quantity(quantity, unit_id, new_unit_id) ⇒ Numeric

This method converts a price value per a unit of measure to a price value per another unit of measure.

Parameters:

  • quantity (Numeric)

    the price value

  • unit_id (Numeric)

    the unit id of measure for the price

  • new_unit_id (Numeric)

    the new unit id of measure

Returns:

  • (Numeric)

    the converted price for the new unit



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'app/services/comee/core/customer_order_service.rb', line 65

def convert_quantity(quantity, unit_id, new_unit_id)
  return quantity if unit_id == new_unit_id

  conversions = UnitConversion.where("from_id = ? AND to_id = ?", unit_id, new_unit_id)
                              .or(UnitConversion.where("from_id = ? AND to_id = ?", new_unit_id, unit_id))

  unless conversions.count.positive?
    units = Unit.where(id: [unit_id, new_unit_id])
    raise(StandardError, "There is no conversion factor between #{units[0].code} and #{units[1].code}.")
  end

  conversion = conversions.first
  return (quantity * conversion.factor).round if unit_id == conversion.from_id && new_unit_id == conversion.to_id

  (quantity / conversion.factor).round
end

#create(params) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'app/services/comee/core/customer_order_service.rb', line 4

def create(params)
  ActiveRecord::Base.transaction do
    prev_order = Comee::Core::CustomerOrder.find_by(order_number: params[:order_number])

    if prev_order && Comee::Core::CustomerOrderItem.exists?(customer_order_id: prev_order.id)
      Comee::Core::CustomerOrderItem.where(customer_order_id: prev_order.id).delete_all
      prev_order.delete
    end
  end
  order = nil
  params = params.to_h.with_indifferent_access
  ActiveRecord::Base.transaction do
    order_params = params.except(:items)
    order = Comee::Core::CustomerOrder.create(**order_params)
    items = params.slice(:items)[:items]
    items.each do |item|
      item[:customer_order_id] = order.id
      item[:total_price] = item[:quantity] * item[:price] unless item.key?(:total_price) && !item[:total_price].nil?
    end

    Comee::Core::CustomerOrderItem.insert_all!(items)
  end
  order
end

#submit(id) ⇒ Object

Raises:

  • (StandardError)


108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'app/services/comee/core/customer_order_service.rb', line 108

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

  unless CustomerOrder.statuses[order.status] == CustomerOrder.statuses[:draft]
    raise(StandardError, "Customer order should be in draft state.")
  end

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

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

#submit_for_confirmation(id) ⇒ Object

Raises:

  • (StandardError)


122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'app/services/comee/core/customer_order_service.rb', line 122

def submit_for_confirmation(id)
  order = CustomerOrder.find_by(id: id)
  raise(StandardError, "Customer order with id `#{id}` not found.") unless order

  unless CustomerOrder.statuses[order.status] == CustomerOrder.statuses[:submitted]
    raise(StandardError, "Customer order should be in submitted state.")
  end

  raise(StandardError, "Customer order does not have any items.") if order.customer_order_items.count.zero?

  order.update!(status: CustomerOrder.statuses[:awaiting_confirmation])
  order
end

#suggest_values(item_id, from_id, to_id, quantity, old_price = nil) ⇒ Object

Raises:

  • (StandardError)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'app/services/comee/core/customer_order_service.rb', line 82

def suggest_values(item_id, from_id, to_id, quantity, old_price = nil)
  item = SalesOrderItem.includes(:product, sales_order: :client)
                       .find_by(id: item_id)
  raise(StandardError, "Order item with id `#{item_id}` not found.") unless item

  client = item.sales_order.client
  client_id = client.parent_id || client.id

  client_price = old_price
  unless client_price
    client_price = ClientPrice.find_by(product_id: item.product_id, client_id: client_id)
    if client_price
      client_price = convert_price(client_price.price, client_price.unit_id, from_id)
    else
      master_price = MasterPrice.find_by(product_id: item.product_id, primary: true)
      raise(StandardError, "No price entry could be found for product `#{item.product.code}`.") unless master_price

      client_price = convert_price(master_price.selling_price, master_price.unit_id, from_id)
    end
  end

  price = convert_price(client_price, from_id, to_id)
  new_quantity = convert_quantity(quantity, from_id, to_id)
  {quantity: new_quantity, price: price, total_price: (new_quantity * price).round(2)}
end