Class: BlackStack::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/extend_client_by_invoicing_payments_processing.rb

Instance Method Summary collapse

Instance Method Details

#add_bonus(id_user_creator, product_code, bonus_credits, description, expiration_time) ⇒ Object



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
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 300

def add_bonus(id_user_creator, product_code, bonus_credits, description, expiration_time)
  bonus_amount = 0
    #    balance = BlackStack::Balance.new(self.id, product_code)

    #    amount = balance.amount.to_f

    #    credits = balance.credits.to_f

    #    if amount>=0 && credits>=0

    #      bonus_amount = (amount / credits) * bonus_credits

    ##    else

    ##      h = BlackStack::InvoicingPaymentsProcessing.product_descriptor(product_code)

    ##      bonus_amount = h[:default_fee_per_unit].to_f

    #    end

  m = BlackStack::Movement.new(
    :id_client => self.id,
    :create_time => now(),
    :type => BlackStack::Movement::MOVEMENT_TYPE_ADD_BONUS,
    :id_user_creator => id_user_creator,
    :description => description,
    :paypal1_amount => 0,
    :bonus_amount => bonus_amount,
    :amount => 0-bonus_amount,
    :credits => 0-bonus_credits,
    :profits_amount => 0,
    :product_code => product_code,
    :expiration_time => expiration_time
  )
  m.id = guid()
  m.save
end

#adjustment(product_code, adjustment_amount = 0, adjustment_credits = 0, description = nil, type = BlackStack::Movement::MOVEMENT_TYPE_ADJUSTMENT, registraton_time = nil) ⇒ Object

crea un registro en la tabla movment, reduciendo la cantidad de creditos con saldo importe 0, para el producto indicado en product_code.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 144

def adjustment(product_code, adjustment_amount=0, adjustment_credits=0, description=nil, type=BlackStack::Movement::MOVEMENT_TYPE_ADJUSTMENT, registraton_time=nil)
        adjust = BlackStack::Movement.new
        adjust.id = guid()
        adjust.id_client = self.id
        adjust.create_time = registraton_time.nil? ? now() : registraton_time
        adjust.type = type
        adjust.description = description.nil? ? 'Adjustment' : description
        adjust.paypal1_amount = 0
        adjust.bonus_amount = 0
        adjust.amount = adjustment_amount
        adjust.credits = adjustment_credits
        adjust.profits_amount = -adjustment_amount
        adjust.product_code = product_code
        adjust.expiration_time = nil
        adjust.save
        adjust
end

#bonus(product_code, expiration, number_of_credits = 1, description = nil) ⇒ Object

crea un registro en la tabla movment, reduciendo la cantidad de creditos con saldo importe 0, para el producto indicado en product_code.



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 120

def bonus(product_code, expiration, number_of_credits=1, description=nil)       
        bonus_amount = 0 # Los bonos siempre son por un importa igual a 0.

        
        bonus = BlackStack::Movement.new
        bonus.id = guid()
        bonus.id_client = self.id
        bonus.create_time = now()
        bonus.type = BlackStack::Movement::MOVEMENT_TYPE_ADD_BONUS
        bonus.description = description.nil? ? 'Bonus' : description
        bonus.paypal1_amount = 0
        bonus.bonus_amount = bonus_amount
        bonus.amount = -bonus_amount
        bonus.credits = -number_of_credits
        bonus.profits_amount = 0
        bonus.product_code = product_code
        bonus.expiration_time = expiration
        bonus.save
        # recalculate - CANCELADO

        #bonus.recalculate

        # return

        bonus
end

#consume(product_code, number_of_credits = 1, description = nil, datetime = nil) ⇒ Object

crea/actualiza un registro en la tabla movment, reduciendo la cantidad de creditos y saldo que tiene el cliente, para el producto indicado en product_code.



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
113
114
115
116
117
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 83

def consume(product_code, number_of_credits=1, description=nil, datetime=nil)
        dt = datetime.nil? ? now() : datetime.to_time.to_sql
        
        # create the consumtion

        total_credits = 0.to_f - BlackStack::Balance.new(self.id, product_code).credits.to_f
        total_amount = 0.to_f - BlackStack::Balance.new(self.id, product_code).amount.to_f
        ratio = total_credits == 0 ? 0.to_f : total_amount.to_f / total_credits.to_f
        amount = number_of_credits.to_f * ratio
        cons = BlackStack::Movement.new
        cons.id = guid()
        cons.id_client = self.id
        cons.create_time = dt
        cons.type = BlackStack::Movement::MOVEMENT_TYPE_CANCELATION
        cons.description = description.nil? ? 'Consumption' : description
        cons.paypal1_amount = 0
        cons.bonus_amount = 0
        cons.amount = amount
        cons.credits = number_of_credits
        cons.profits_amount = -amount
        cons.product_code = product_code
        cons.expiration_time = nil
        cons.save
        # if there is negative credits

        prod = BlackStack::InvoicingPaymentsProcessing.product_descriptor(product_code)
        total_credits = 0.to_f - BlackStack::Balance.new(self.id, product_code).credits.to_f
        total_amount = 0.to_f - BlackStack::Balance.new(self.id, product_code).amount.to_f
        sleep(2) # delay to ensure the time of the bonus movement will be later than the time of the consumption movement

        if total_credits < 0
          self.adjustment(product_code, total_amount, total_credits, 'Adjustment Because Quota Has Been Exceeded (1).')
        end
        # recaculate amounts in both consumptions and expirations - CANCELADO - Se debe hacer offline

        #self.recalculate(product_code) 

        # return

        cons
end

#deserve_trialObject

retorna true si este cliente no tiene ninguna generada con productos LGB2



215
216
217
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 215

def deserve_trial()
  self.disabled_for_trial_ssm != true
end

#deserve_trial?Boolean

Returns:

  • (Boolean)


220
221
222
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 220

def deserve_trial?
  self.deserve_trial()
end

#divisionObject

TODO: el cliente deberia tener una FK a la tabla division. La relacion no puede ser N-N. TODO: se debe preguntar a la central



203
204
205
206
207
208
209
210
211
212
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 203

def division
  q = 
  "SELECT d.id as id " +
  "FROM division d " +
  "JOIN user_division ud ON d.id=ud.id_division " +
  "JOIN [user] u ON u.id=ud.id_user " +
  "WHERE u.id_client = '#{self.id}' "
  row = DB[q].first
  BlackStack::Division.where(:id=>row[:id]).first    
end

#get_balanceObject



225
226
227
228
229
230
231
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 225

def get_balance()
  n = 0
  BlackStack::InvoicingPaymentsProcessing::products_descriptor.each { |code| 
    n += BlackStack::Balance.new(self.id, code).amount 
  }
  n
end

#get_movements(from_time, to_time, product_code = nil) ⇒ Object



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 234

def get_movements(from_time, to_time, product_code=nil)
  if from_time > to_time
    raise "From time must be earlier than To time"
  end
  #if to_time.prev_year > from_time

  #  raise "The time frame cannot be longer than 1 year."

  #end

  to_time += 1
=begin
:id => movement.id,
:id_client => movement.id_client,
:product_code => movement.product_code,
:create_time => movement.create_time,
:type => movement.type.to_i,
:description => movement.description,
:paypal1_amount => movement.paypal1_amount.to_f,
:bonus_amount => movement.bonus_amount.to_f,
:amount => movement.amount.to_f,
:credits => movement.credits.to_f,
:profits_amount => movement.profits_amount.to_f,
:expiration_time => movement.expiration_time,
:expiration_description => movement.expiration_time.nil? ? '-' : ((movement.expiration_time - Time.now()).to_f / 60.to_f).to_i.to_time_spent 
=end  

  q =
  "SELECT " +
  " m.id_client, " +
  " YEAR(m.create_time) AS creation_year, " + 
  " MONTH(m.create_time) AS creation_month, " + 
  " DAY(m.create_time) AS creation_day, " +
  " YEAR(m.expiration_time) AS expiration_year, " + 
  " MONTH(m.expiration_time) AS expiration_month, " + 
  " DAY(m.expiration_time) AS expiration_day, " +
  " m.type, " +
  " m.product_code, " +
  " CAST(m.description AS VARCHAR(500)) AS description, " +
  " CAST(m.expiration_description AS VARCHAR(500)) AS expiration_description, " +
  " SUM(ISNULL(m.paypal1_amount,0)) AS paypal1_amount, " + 
  " SUM(ISNULL(m.bonus_amount,0)) AS bonus_amount, " + 
  " SUM(ISNULL(m.amount,0)) AS amount, " + 
  " SUM(ISNULL(m.credits,0)) AS credits, " + 
  " SUM(ISNULL(m.profits_amount,0)) AS profits_amount " + 
  "FROM movement m WITH (NOLOCK) " +
  "WHERE m.id_client = '#{self.id}' "
  
  q += "AND m.product_code = '#{product_code}' " if !product_code.nil?
  
  q +=
  "AND create_time >= '#{from_time.to_sql}' " +
  "AND create_time <= '#{to_time.to_sql}' " +
  "GROUP BY " +
  " m.id_client, " + 
  " YEAR(m.create_time), " + 
  " MONTH(m.create_time), " + 
  " DAY(m.create_time), " +
  " YEAR(m.expiration_time), " + 
  " MONTH(m.expiration_time), " + 
  " DAY(m.expiration_time), " +
  " m.type, " +
  " m.product_code, " +
  " CAST(m.description AS VARCHAR(500)), " +
  " CAST(m.expiration_description AS VARCHAR(500)) "

  DB[q].all
end

#has_item(item_number, amount = nil) ⇒ Object

retorna true si existe algun item de factura relacionado al ‘plan’ (‘item_number’). si el atributo ‘amount’ ademas es distinto a nil, se filtran items por ese monto.



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 331

def has_item(item_number, amount=nil)
  h = BlackStack::InvoicingPaymentsProcessing::plans_descriptor.select { |obj| obj[:item_number].to_s == item_number.to_s }.first
  raise "Plan not found" if h.nil?
      
  q = 
  "SELECT i.id " + 
  "FROM invoice i "
    
  # si el plan tiene un trial, entnces se pregunta si ya existe un item de factura por el importe del trial.

  # si el plan no tiene un trial, entnces se pregunta si ya existe un item de factura por el importe del plan.

  if amount.nil? 
    q +=
    "JOIN invoice_item t ON ( i.id=t.id_invoice AND t.item_number='#{item_number}' ) "
  else
    q +=
    "JOIN invoice_item t ON ( i.id=t.id_invoice AND t.item_number='#{item_number}' AND t.amount=#{amount.to_s} ) "
  end
  
  q +=
  "WHERE i.id_client='#{self.id}' " +
  "AND i.delete_time IS NULL "
  
  return !DB[q].first.nil?
end

#movementsObject

This method replace the line: one_to_many :movements, :class=>:‘BlackStack::Movement’, :key=>:id_client

Because when you have a large number of records in the table movement, for a client, then the call to this attribute client.movements can take too much time and generates a query timeout exception.

The call to this method may take too much time, but ti won’t raise a query timeout.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 19

def movements
  i = 0 
  ret = []
  BlackStack::Movement.where(:id_client=>self.id).each { |o| 
    ret << o
    i += 1
    if i == 1000
      i = 0
      GC.start
      DB.disconnect
    end
  }
  ret
end

#plansObject

retorna los planes estandar definidos en el array BlackStack::InvoicingPaymentsProcessing::plans_descriptor, y le concatena los arrays customizados de este cliente definidos en la tabla custom_plan



357
358
359
360
361
362
363
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 357

def plans
  a = BlackStack::InvoicingPaymentsProcessing::plans_descriptor 
  self.customplans.each { |p|
    a << p.to_hash
  }
  a
end

#recalculate(product_code) ⇒ Object

recalculate the amount for all the consumptions, expirations, and adjustments



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
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 163

def recalculate(product_code)
  # 

  amount_paid = 0.to_f
  credits_paid = 0

  #total_credits = 0.to_f - BlackStack::Balance.new(self.id, product_code).credits.to_f

  #total_amount = 0.to_f - BlackStack::Balance.new(self.id, product_code).amount.to_f        


  self.movements.select { |o| 
    o.product_code.upcase == product_code.upcase
  }.sort_by { |o| [o.create_time, o.type] }.each { |o| # se ordena por o.create_time, pero tmabien por o.type para procesar primero los pagos y bonos

    #if o.credits.to_f < 0 # payment or bonus

#         if o.credits.to_f > 0 && ( o.type==BlackStack::Movement::MOVEMENT_TYPE_CANCELATION || o.type==BlackStack::Movement::MOVEMENT_TYPE_EXPIRATION ) # consumption or expiration

    # consumption or expiration or bonus

    if ( 
      o.type==BlackStack::Movement::MOVEMENT_TYPE_CANCELATION || 
      o.type==BlackStack::Movement::MOVEMENT_TYPE_EXPIRATION || 
      o.type==BlackStack::Movement::MOVEMENT_TYPE_ADJUSTMENT
    )
      x = credits_paid.to_f == 0 ? 0 : o.credits.to_f * ( amount_paid.to_f / credits_paid.to_f )
      o.amount = x
      o.profits_amount = -x
      o.save
    end
    amount_paid += 0.to_f - o.amount.to_f
    credits_paid += 0.to_i - o.credits.to_i

    # if there is negative credits

    total_credits = credits_paid
    total_amount = amount_paid
    if total_credits < 0
      self. adjustment(product_code, total_amount, total_credits, 'Adjustment Because Quota Has Been Exceeded (2).', BlackStack::Movement::MOVEMENT_TYPE_ADJUSTMENT, o.create_time)
      amount_paid = 0.to_f
      credits_paid = 0.to_i
    end
  }
end

#stat_balance_delay_minutesObject

how many minutes ago should have updated the table stat_balance with the amount and credits of this client, for each product. return a positive integer if either:

  1. the client didn’t update stats in the last 24 hours, or

  2. the client has a new record in the table movements after its last update in the table stat_balance.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 38

def stat_balance_delay_minutes
  row = DB[
    "SELECT TOP 1 m.id " +
    "FROM client c WITH (NOLOCK) " +
    "JOIN movement m WITH (NOLOCK INDEX(IX_movement__id_client__create_time_desc)) ON ( " +
    " c.id=m.id_client AND " +
    " m.create_time > ISNULL(c.last_stat_balance_update_time, '1900-01-01') " +
    ") " +
    "WHERE c.id = '#{self.id}' " +
    "ORDER BY m.create_time DESC "
  ].first
  
  if row.nil?
    return 0
  else
    return DB["SELECT DATEDIFF(MI, m.create_time, GETDATE()) AS n FROM movement m WITH (NOLOCK) WHERE m.id='#{row[:id]}'"].first[:n]
  end
end

#update_stat_balance(product_code = nil) ⇒ Object

update the table stat_balance with the amount and credits of this client, for each product.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 58

def update_stat_balance(product_code=nil)
    c = self
    product_descriptors = BlackStack::InvoicingPaymentsProcessing::products_descriptor.clone     
    product_descriptors.select! { |hprod| hprod[:code] == product_code } if !product_code.nil?
    product_descriptors.each { |hprod|
      row = DB[
        "select isnull(sum(isnull(m.credits,0)),0) as credits, isnull(sum(isnull(m.amount,0)),0) as amount " +
        "from movement m with (nolock index(IX_movement__id_client__product_code)) " + 
        #"from movement m with (nolock) " + 

        "where m.id_client='#{c.id}' " +
        "and m.product_code='#{hprod[:code]}' "
      ].first
      credits = row[:credits]
      amount = row[:amount]
      row = DB["SELECT * FROM stat_balance WHERE id_client='#{c.id}' AND product_code='#{hprod[:code]}'"].first
      if row.nil?
        DB.execute("INSERT INTO stat_balance (id_client, product_code, amount, credits) VALUES ('#{c.id}', '#{hprod[:code]}', #{amount.to_s}, #{credits.to_s})")
      else
        DB.execute("UPDATE stat_balance SET amount=#{amount.to_s}, credits=#{credits.to_s} WHERE id_client='#{c.id}' AND product_code='#{hprod[:code]}'")
      end
      DB.execute("UPDATE client SET last_stat_balance_update_time=GETDATE() WHERE [id]='#{c.id}'")
    }
end