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



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

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.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 151

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.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 127

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.



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
118
119
120
121
122
123
124
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 90

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



222
223
224
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 222

def deserve_trial()
  self.disabled_for_trial_ssm != true
end

#deserve_trial?Boolean

Returns:

  • (Boolean)


227
228
229
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 227

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



210
211
212
213
214
215
216
217
218
219
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 210

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



232
233
234
235
236
237
238
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 232

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



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
298
299
300
301
302
303
304
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 241

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.



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 338

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



364
365
366
367
368
369
370
# File 'lib/extend_client_by_invoicing_payments_processing.rb', line 364

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



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

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
81
82
83
84
85
86
87
# 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|
      row1 = DB["
        select isnull(sum(isnull(m.credits,0)),0) as credits  
        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
      row2 = DB["
        select 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 = row1[:credits]
      amount = row2[: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