Class: Auth::System::Wrapper

Inherits:
Object
  • Object
show all
Includes:
Concerns::SystemConcern
Defined in:
app/models/auth/system/wrapper.rb

Instance Method Summary collapse

Instance Method Details

#add_addressesObject



578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
# File 'app/models/auth/system/wrapper.rb', line 578

def add_addresses
  _level = 0
  self.levels.each do |level|
    level.address = "l" + _level.to_s
    _branch = 0
    level.branches.each do |branch|
      branch.address = level.address + ":b" + _branch.to_s
      branch.definitions.each do |definition|
        _definition = 0
        definition.address = branch.address + ":d" + _definition.to_s
        _unit = 0
        definition.units.each do |unit|
          unit.address = definition.address + ":u" + _unit.to_s
          _unit+=1
        end
        _definition+=1
      end
      _branch+=1
    end
    _level+=1
  end  
end

#add_cart_items(cart_item_ids) ⇒ Object

@return _branches : an array of branch addresses, where the items were added.



558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
# File 'app/models/auth/system/wrapper.rb', line 558

def add_cart_items(cart_item_ids)
  _branches = []
  cart_item_ids.each do |cid|
    branch_located = false
    cart_item = Auth.configuration.cart_item_class.constantize.find(cid)
    self.levels.each do |level|
      level.branches.each do |branch|
        if branch.product_bunch == cart_item.bunch
          branch.input_object_ids << cid
          _branches << branch.address unless _branches.include? branch.address
          branch_located = true
        end
      end
    end
    raise "could not find a branch for #{cid}" unless branch_located
  end
  _branches 
end

#applicable_query_ids(query_result_id, category_combination_query_ids) ⇒ Object

@param query_result_id : the id of the incoming query result. @param category_combination_query_ids : the query_ids of the category_combination inside the applicable minute in the overflow hash. @return applicable_query_ids : the query ids which are applicable to @query_result_id.



270
271
272
273
274
275
# File 'app/models/auth/system/wrapper.rb', line 270

def applicable_query_ids(query_result_id,category_combination_query_ids)

  ## for now this returns the whole combination of shit.
  return category_combination_query_ids

end

#filter_query_results(query_result, query_array, query_id) ⇒ Object

will first convert the query result into an array



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
# File 'app/models/auth/system/wrapper.rb', line 298

def filter_query_results(query_result,query_array,query_id)
  query_result = query_result.to_a
  ## this is going to be a hash
  ## the problem is that we wont have the types
  ## how to know the type ?
  ## we need to know what is the 
  categories_searched_for = query_array.first["categories"].map{|c| c = c["category"]}

  category_quantities = query_array.first["categories"].map{|c| 
    c = [c["category"].to_sym,(c["transport_capacity"] || c["capacity"])]
  }.to_h


    
  consumables_searched_for = []
  if query_array.first["consumables"]
    consumables_searched_for = query_array.first["consumables"].map{|c| c = Auth.configuration.consumable_class.constantize.new(c)}
  end

  indices_of_minutes_to_prune = {}

  query_result.each_with_index {|location,location_index|
    
    indices_of_minutes_to_prune[location_index] = []

    location_overlap_hash = self.overlap_hash[location["_id"].to_s.to_sym]
    
    next unless location_overlap_hash

    sorted_minutes = location_overlap_hash.keys.map{|c| c = c.to_s.to_i}.sort { |a, b| a<=>b }

    location["minutes"].each_with_index{|minute_hash,index|

      ## if you require only one type per category, then there is no problem.
      ## we can just double it, whatever is coming in.
      category_requirements = categories_searched_for.map{|c| c = [c.to_sym,{}]}.to_h


      
      ### have to initialize it with whatever were our entity requirements for the current query.
      ### but i dont know that exact combination.
      ## that is the issue.
      ## so here there are two options.
      ## one is that we have to know the type before hand
      ## or two it has to know if this type fits.
      ## 

      consumable_requirements = consumables_searched_for.map{|c| c = [c.product_id.to_s,c.quantity]}.to_h if consumables_searched_for

      minute_object = Auth.configuration.minute_class.constantize.new(minute_hash)

      incoming_minute_category_entity_type = 
            minute_object.get_category_entity_types

      minute = minute_object.minute
      
      
      minute_categories = minute_object.get_categories_to_capacity
      minute_consumables = minute_object.get_consumable_to_quantity 
      
      applicable_minute = nil

      if sorted_minutes.include? minute
        applicable_minute = minute
      else
        ## iterate and the minute you find something less than this, black it out.
        sorted_minutes.each_with_index {|s,k|
          if s > minute
            if k > 0
              applicable_minute = sorted_minutes[k-1]
            end
            break
          end
        }
      end

      #puts "applicable minute is: #{applicable_minute}"
      next unless applicable_minute
      
      location_overlap_hash[applicable_minute.to_s.to_sym][:categories].keys.each do |k|
        
        ## split the categories on "_"
        categories_in_this_key = location_overlap_hash[applicable_minute.to_s.to_sym][:categories][k][:category_names]


        puts "categories in this key: #{categories_in_this_key}"

        puts "categories searched for : #{categories_searched_for}"

        common_categories = categories_in_this_key & categories_searched_for

        puts "common categories :#{common_categories}"

        unless common_categories.empty?
          
          ## does the minute hash i.e in the query result contain all the categories in the combination?
          minute_hash_contains_all_categories_in_this_key = categories_in_this_key & minute_categories.keys

          puts "minute hash contains all the categories in this key : #{minute_hash_contains_all_categories_in_this_key}"

          ## if it does, then it means that this minute has to satisfy the requirements of this combination.
          if minute_hash_contains_all_categories_in_this_key.size == categories_in_this_key.size
              
            puts "size is equal."
            ## the minute in the result, we want to get the hash of the categories to their entity types, with their capacities.
            

            puts "incoming entity types:" 
            puts incoming_minute_category_entity_type

            ## now we will look which query ids from the overlap hash for the applicable minute are applicable to the current query id.

            ## so this applicable query ids, should just return an array of the applicable query ids to this query id.

            if increment_by = applicable_query_ids(query_id,location_overlap_hash[applicable_minute.to_s.to_sym][:categories][k][:query_ids].keys)  

              puts "increment by is: #{increment_by}"

              ## increment all the category requirements of the common categories by that much.
              
              ## now we have to search inside those query ids, for the types
              ## if we have the same types in any of the categories, then we have to go for it.
              ## for each category, in the common categories, see if it is there in the 
              ## we have to increment the type requirement incase it is the same type.
              common_categories.each do |cc|
                increment_by.each do |qid|




                  location_overlap_hash[applicable_minute.to_s.to_sym][:categories][k][:query_ids][qid].keys.each do |cat|

                    ## so this is the category.
                    if incoming_minute_category_entity_type[cat]

                      location_overlap_hash[applicable_minute.to_s.to_sym][:categories][k][:query_ids][qid][cat].keys.each do |entity_type|

                        puts incoming_minute_category_entity_type.to_s

                        puts "cat is :#{cat}"
                        puts "entity type is: #{entity_type}"

                        ## it is the same for consumables as well.
                        if incoming_minute_category_entity_type[cat][entity_type]


                          
                          ## the incoming minute has the same entity.
                          ## then we must add it to the requirements.

                          ## category_requirements will be incremented.
                          if category_requirements[cat][entity_type]

                            category_requirements[cat][entity_type] += location_overlap_hash[applicable_minute.to_s.to_sym][:categories][k][:query_ids][qid][cat][entity_type] 
                          else
                            category_requirements[cat][entity_type]
                            category_requirements[cat][entity_type] = (location_overlap_hash[applicable_minute.to_s.to_sym][:categories][k][:query_ids][qid][cat][entity_type] + category_quantities[cat])
                          end

                        end

                      end

                    end 

                  end
                  
                end
              end

              ## only whichever queries are applicable.
              ## see what is already there in overlap hash, 
              consumables_searched_for.each do |consumable|

                ## pick up for each of these from overlap hash, and create total combined requirements.
                if existing_in_overlap_hash = location_overlap_hash[applicable_minute.to_s.to_sym][:consumables][consumable.product_id]

                  existing_in_overlap_hash.each do |defi|

                    ## if the query id is applicable, then increment the consumable minute_requirement
                    if applicable_query_ids(query_id,[defi[:query_id]])

                      consumable_requirements[consumable.product_id.to_s] += defi[:quantity]

                    end

                  end                    

                end

              end

            end 

          end
        end


      end

      puts "category requirements are:"
      puts category_requirements.to_s

      category_requirements.keys.each do |cat|
        category_requirements[cat].keys.each do |type|

          indices_of_minutes_to_prune[location_index] << index if incoming_minute_category_entity_type[cat][type] < category_requirements[cat][type]


        end
      end


      consumable_requirements.keys.each do |c|

        indices_of_minutes_to_prune[location_index] << index unless (minute_consumables[c] >= consumable_requirements[c])

      end
      
    }

  }


  

  indices_of_minutes_to_prune.keys.each do |location_index|
    indices_of_minutes_to_prune[location_index].each do |min_index|
      query_result[location_index.to_i]["minutes"][min_index] = {}
    end
  end

  puts JSON.pretty_generate(query_result)

  puts "-- INDICES TO PRUNE -->"
  puts JSON.pretty_generate(indices_of_minutes_to_prune)

  ## OKAY SO NOW WE WANT TO GIVE THE CAPACITY AVAILABLE IN THE MINUTE COMING IN TO BE LESS THAN WHATEVER WE CAN AFFORD.
  ## 

  query_result

end

#manage_minute(minute_hash_to_insert, minute, location_id) ⇒ Object

@param minute_hash_to_insert : the query id and the categories for the minute we are wanting to insert. e.g : => {:categories => [array_of_categories], query_ids => [query_id]} @param minute : either the start or end_minute. @param location_id : the id of the location. @return



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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
# File 'app/models/auth/system/wrapper.rb', line 118

def manage_minute(minute_hash_to_insert,minute,location_id)
      
  puts "this is the minute to insert."
  puts "minute to insert is: #{minute}"

  location_id = location_id.to_s.to_sym

  ## it depends if the location already exists in the location hash.
  self.overlap_hash[location_id] = {} unless self.overlap_hash[location_id]

  existing_minutes = self.overlap_hash[location_id].keys.map{|c| c = c.to_s.to_i}.sort { |a, b| a <=> b }

  if existing_minutes.size > 0

    equal_to_minute = minute.to_i if existing_minutes.include? minute.to_i

    less_than_minute = nil

    greater_than_minute = nil

    unless equal_to_minute
      existing_minutes.each_with_index {|min,index|
        ## if you find something greater
        ## then stop
        ## whatever is before was less
        if (min > minute.to_i)
          greater_than_minute = min
          ## if we have something before, i.e if the index is >= 1
          less_than_minute = existing_minutes[index - 1] if index >=1
          break
        else
          if index == (existing_minutes.size - 1)
            less_than_minute = min.to_i
          end
        end
      }
    end


    ## suppose there is an equal to , then we have to fuse it with that.
    ## **(minute).............
    if equal_to_minute 


      self.overlap_hash[location_id][minute.to_s.to_sym] =  merge_minute_hash(self.overlap_hash[location_id][minute.to_s.to_sym],minute_hash_to_insert)
    
    else

      ## only less than or only greater than, and equal to is nil.
      ## **..........(minute) || (minute)............**
      if ((less_than_minute && greater_than_minute.nil?) || (less_than_minute.nil? && greater_than_minute))
        #puts "EITHER ONLY LESS OR ONLY GREATER."
        self.overlap_hash[location_id][minute.to_s.to_sym] = minute_hash_to_insert 
      end

      ## less than and greater than, and equal to is nil
      ## **................(minute)...............**
      if greater_than_minute && less_than_minute
        #puts "------- GOT THE LESS THAN AND GREATER THAN BOTH ---- "
        ## in this case we want to fuse in the less than minute with this one and add it in.
        fused_hash = merge_minute_hash(self.overlap_hash[location_id][less_than_minute.to_s.to_sym],minute_hash_to_insert)

        self.overlap_hash[location_id][minute.to_s.to_sym] = fused_hash
      end

    end

    ## there is one more possibility where there is nothing else.
    ## in that case, we have to add the start and end minute direct.
  else
    self.overlap_hash[location_id][minute.to_s.to_sym] = minute_hash_to_insert 
  end

end

#merge_minute_hash(fused, incoming) ⇒ Object

@param existing : the existing hash at the minute. @param incoming : the incoming hash that we want to merge, this will be with two keys : => {. :consumables_hash => {}} @return existing : after merging in the incoming hash.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
107
108
109
110
111
112
# File 'app/models/auth/system/wrapper.rb', line 37

def merge_minute_hash(fused,incoming)
  existing = fused.deep_dup
  
  puts "existing is:"
  puts JSON.pretty_generate(existing)

  puts "incoming is:"
  puts JSON.pretty_generate(incoming)

  ## now comes the question of how we are going to merge this stuff exactly ?
  ## 
  ## check the category combination.

  incoming[:categories].keys.each do |category_combination|
    if existing[:categories][category_combination]
      puts "found category combination #{category_combination}"

      incoming[:categories][category_combination][:query_ids].keys.each do |q_id|

        puts "searching query id: #{q_id}"

        if existing[:categories][category_combination][:query_ids][q_id]

          puts "query id exists #{q_id}"

          incoming[:categories][category_combination][:query_ids][q_id].keys.each do |cat|


            ## we will have to search all the query ids, in the existing for this category, and if we find it , then we can proceed.
            if existing[:categories][category_combination][:query_ids][q_id][cat]

              incoming[:categories][category_combination][:query_ids][q_id][cat].keys.each do |type|

                if existing[:categories][category_combination][:query_ids][q_id][cat][type]

                  existing[:categories][category_combination][:query_ids][q_id][cat][type] += incoming[:categories][category_combination][:query_ids][q_id][cat][type] 
                
                else

                  existing[:categories][category_combination][:query_ids][q_id][cat][type] = incoming[:categories][category_combination][:query_ids][q_id][cat][type] 

                end

              end

            else
              existing[:categories][category_combination][:query_ids][q_id][type] = incoming[:categories][category_combination][:query_ids][q_id][cat]
            end

          end

        else
      
          existing[:categories][category_combination][:query_ids][q_id] = incoming[:categories][category_combination][:query_ids][q_id]
        end
      end

    else
      
      existing[:categories][category_combination] = incoming[:categories][category_combination]
    end
  end


  incoming[:consumables].keys.each do |product_id|
    ## do we already have this product_id ?
    if existing[:consumables][product_id]
      existing[:consumables][product_id] << incoming[:consumables][product_id]
    else
      existing[:consumables][product_id] =  incoming[:consumables][product_id]
    end
  end

  existing

end

#process_query_results(query_result, categories_searched_for, query_id, consumables_searched_for) ⇒ Object

THIS IS THE ONLY FUNCTION THAT IS TO BE CALLED. @param query_result : A mongo aggregation result object, on which to_a has been called. @param categories_searched_for : array of strings , the entity categories that were searched for. @param query_id : the id of the query, used in the filtering process. @param consumables_searched_for : this is the array of consumable objects. Auth::Workflow::Consumable.



547
548
549
550
551
552
# File 'app/models/auth/system/wrapper.rb', line 547

def process_query_results(query_result,categories_searched_for,query_id,consumables_searched_for)
  ## first we can do for categories , then for consumables ?
  ## or simultaneously, simultaneously
  #query_result = filter_query_results(query_result,categories_searched_for,query_id,consumables_searched_for)
  #update_overlap_hash(query_result,categories_searched_for,query_id,consumables_searched_for)
end

#update_intervening_minutes(minute_hash_to_insert, start_minute, end_minute, location_id) ⇒ Object

finds all the minutes in between the newly inserted start and end minute, and fuses the minute_hash into them. @param minute_hash_to_insert : the query id and the categories for the minute we are wanting to insert. e.g : => {:categories => [array_of_categories], query_ids => [query_id]} @param start_minute : the start_minute for the location_id. @param end_minute : the end_minute for the location_id. @param location_id : the location id. @return



199
200
201
202
203
204
205
206
207
208
209
210
# File 'app/models/auth/system/wrapper.rb', line 199

def update_intervening_minutes(minute_hash_to_insert,start_minute,end_minute,location_id)
  location_id = location_id.to_s.to_sym

  existing_minutes = self.overlap_hash[location_id].keys.map{|c| c = c.to_s.to_i}.sort { |a, b| a <=> b }

  existing_minutes.each do |min|
    if ((min > start_minute) && (min < end_minute))
      self.overlap_hash[location_id][min.to_s.to_sym] = merge_minute_hash(self.overlap_hash[location_id][min.to_s.to_sym],minute_hash_to_insert)
    end
  end

end

#update_overlap_hash(query_result, query_array, query_id) ⇒ Object

Adds the results of the query to the overlap hash, these results should be pre-filtered. @param query_result : the result of the mongodb aggregation. @param categories_searched_for : the categories_searched_for in the query. @param query_id : the arbitarily assigned id to the query. @param consumables_searched_for : array of consumable objects. @return



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'app/models/auth/system/wrapper.rb', line 223

def update_overlap_hash(query_result,query_array,query_id)
  query_result.each do |location|
    
    puts JSON.pretty_generate(location)
    
    location_id = location["_id"]
    
    start_minute = Auth::Workflow::Minute.new(location["minutes"].first)
    end_minute = Auth::Workflow::Minute.new(location["minutes"].last)


    if (start_minute && end_minute)
    
      manage_minute(end_minute.minute_to_insert(query_id),end_minute.minute,location_id)

      if(start_minute.minute != end_minute.minute)
        manage_minute(start_minute.minute_to_insert(query_id),start_minute.minute,location_id)
        update_intervening_minutes(start_minute.minute_to_insert(query_id),start_minute.minute,end_minute.minute,location_id)
      end
    
    end

  end


end