invoicing_payments_processing 1.1.8 → 1.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 151f5edd003ddd2e88cedc7222761de649a78202
4
- data.tar.gz: 7b1345402c7424ec9c7b9dd9350c5d4a8438cdb8
3
+ metadata.gz: 079660aadfbd7106fcc74787e3d86002375ec4b2
4
+ data.tar.gz: 281a650e189be44ed7e91ca2bf439e876f014eb8
5
5
  SHA512:
6
- metadata.gz: 568e022a591e4272e4f6ab92928a16a901f7dc6eaf6d186ad223c4fb34a0a3f10feec25442b032f196166b0251ac78de5070435dcae34c5537990c98907a1970
7
- data.tar.gz: f734ddee71a72789691e231d6e79aae60d5bc4aa30da2f9b2d4e93e5e5747b4ecc7ad44f0e809db9b6f5eaaec86b637440f0fc9751fd3a74421ee864624d2e54
6
+ metadata.gz: 025fd8f5d7060f21b8bdd2e2d1d087ee57d3ac587c32b8c0aaf03f53fba263da0904b21a00d85d5c6d6fe9c220155783e9541bf2ba5dbf8c49aff3c0e58bea82
7
+ data.tar.gz: 875037f5c24e6702cfcb8c39bca913d22761e2f1a7ca3d8efe6707edc30a8a8ec0c12e24fdc22da2fb4fa7d1517f5c0463d85aed2744429de5ff77ffa5ecda14
@@ -294,6 +294,7 @@ module BlackStack
294
294
 
295
295
  # le asigno el id_buffer_paypal_notification
296
296
  i.id_buffer_paypal_notification = b.id
297
+ i.subscr_id = b.subscr_id
297
298
  i.save
298
299
 
299
300
  # marco la factura como pagada
@@ -10,9 +10,112 @@ module BlackStack
10
10
 
11
11
  # 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.
12
12
  def consume(product_code, number_of_credits=1, description=nil)
13
- DB.execute("exec reduceDebt '#{product_code.to_sql}', '#{self.id}', #{number_of_credits.to_s}, '#{description.to_s.to_sql}'")
13
+ # create the consumtion
14
+ total_credits = 0.to_f - BlackStack::Balance.new(self.id, product_code).credits.to_f
15
+ total_amount = 0.to_f - BlackStack::Balance.new(self.id, product_code).amount.to_f
16
+ ratio = total_credits == 0 ? 0.to_f : total_amount.to_f / total_credits.to_f
17
+ amount = number_of_credits.to_f * ratio
18
+ cons = BlackStack::Movement.new
19
+ cons.id = guid()
20
+ cons.id_client = self.id
21
+ cons.create_time = now()
22
+ cons.type = BlackStack::Movement::MOVEMENT_TYPE_CANCELATION
23
+ cons.description = description.nil? ? 'Consumption' : description
24
+ cons.paypal1_amount = 0
25
+ cons.bonus_amount = 0
26
+ cons.amount = amount
27
+ cons.credits = number_of_credits
28
+ cons.profits_amount = -amount
29
+ cons.product_code = product_code
30
+ cons.expiration_time = nil
31
+ cons.save
32
+ # if there is negative credits
33
+ prod = BlackStack::InvoicingPaymentsProcessing.product_descriptor(product_code)
34
+ total_credits = 0.to_f - BlackStack::Balance.new(self.id, product_code).credits.to_f
35
+ total_amount = 0.to_f - BlackStack::Balance.new(self.id, product_code).amount.to_f
36
+ sleep(2) # delay to ensure the time of the bonus movement will be later than the time of the consumption movement
37
+ if total_credits < 0
38
+ self.adjustment(product_code, total_amount, total_credits, 'Adjustment Because Quota Has Been Exceeded.')
39
+ end
40
+ # recaculate amounts in both consumptions and expirations - CANCELADO - Se debe hacer offline
41
+ #self.recalculate(product_code)
42
+ # return
43
+ cons
14
44
  end
15
-
45
+
46
+ # crea un registro en la tabla movment, reduciendo la cantidad de creditos con saldo importe 0, para el producto indicado en product_code.
47
+ def bonus(product_code, expiration, number_of_credits=1, description=nil)
48
+ bonus_amount = 0 # Los bonos siempre son por un importa igual a 0.
49
+
50
+ bonus = BlackStack::Movement.new
51
+ bonus.id = guid()
52
+ bonus.id_client = self.id
53
+ bonus.create_time = now()
54
+ bonus.type = BlackStack::Movement::MOVEMENT_TYPE_ADD_BONUS
55
+ bonus.description = description.nil? ? 'Bonus' : description
56
+ bonus.paypal1_amount = 0
57
+ bonus.bonus_amount = bonus_amount
58
+ bonus.amount = -bonus_amount
59
+ bonus.credits = -number_of_credits
60
+ bonus.profits_amount = 0
61
+ bonus.product_code = product_code
62
+ bonus.expiration_time = expiration
63
+ bonus.save
64
+ # recalculate - CANCELADO
65
+ #bonus.recalculate
66
+ # return
67
+ bonus
68
+ end
69
+
70
+ # crea un registro en la tabla movment, reduciendo la cantidad de creditos con saldo importe 0, para el producto indicado en product_code.
71
+ def adjustment(product_code, adjustment_amount=0, adjustment_credits=0, description=nil, type=BlackStack::Movement::MOVEMENT_TYPE_ADJUSTMENT)
72
+ adjust = BlackStack::Movement.new
73
+ adjust.id = guid()
74
+ adjust.id_client = self.id
75
+ adjust.create_time = now()
76
+ adjust.type = type
77
+ adjust.description = description.nil? ? 'Adjustment' : description
78
+ adjust.paypal1_amount = 0
79
+ adjust.bonus_amount = 0
80
+ adjust.amount = adjustment_amount
81
+ adjust.credits = adjustment_credits
82
+ adjust.profits_amount = -adjustment_amount
83
+ adjust.product_code = product_code
84
+ adjust.expiration_time = nil
85
+ adjust.save
86
+ adjust
87
+ end
88
+
89
+ # recalculate the amount for all the consumptions, expirations, and adjustments
90
+ def recalculate(product_code)
91
+ #
92
+ amount_paid = 0.to_f
93
+ credits_paid = 0
94
+
95
+ #total_credits = 0.to_f - BlackStack::Balance.new(self.id, product_code).credits.to_f
96
+ #total_amount = 0.to_f - BlackStack::Balance.new(self.id, product_code).amount.to_f
97
+
98
+ self.movements.select { |o|
99
+ o.product_code.upcase == product_code.upcase
100
+ }.sort_by { |o| o.create_time }.each { |o|
101
+ #if o.credits.to_f < 0 # payment or bonus
102
+ # if o.credits.to_f > 0 && ( o.type==BlackStack::Movement::MOVEMENT_TYPE_CANCELATION || o.type==BlackStack::Movement::MOVEMENT_TYPE_EXPIRATION ) # consumption or expiration
103
+ # consumption or expiration or bonus
104
+ if (
105
+ o.type==BlackStack::Movement::MOVEMENT_TYPE_CANCELATION ||
106
+ o.type==BlackStack::Movement::MOVEMENT_TYPE_EXPIRATION ||
107
+ o.type==BlackStack::Movement::MOVEMENT_TYPE_ADJUSTMENT
108
+ )
109
+ x = credits_paid.to_f == 0 ? 0 : o.credits.to_f * ( amount_paid.to_f / credits_paid.to_f )
110
+ o.amount = x
111
+ o.profits_amount = -x
112
+ o.save
113
+ end
114
+ amount_paid += 0.to_f - o.amount.to_f
115
+ credits_paid += 0.to_i - o.credits.to_i
116
+ }
117
+ end
118
+
16
119
  # TODO: el cliente deberia tener una FK a la tabla division. La relacion no puede ser N-N.
17
120
  # TODO: se debe preguntar a la central
18
121
  def division
@@ -11,6 +11,7 @@ module BlackStack
11
11
  many_to_one :buffer_paypal_notification, :class=>:'BlackStack::BufferPayPalNotification', :key=>:id_buffer_paypal_notification
12
12
  many_to_one :client, :class=>:'BlackStack::Client', :key=>:id_client
13
13
  many_to_one :paypal_subscription, :class=>:'BlackStack::PayPalSubscription', :key=>:id_paypal_subscription
14
+ many_to_one :previous, :class=>:'BlackStack::Invoice', :key=>:id_previous_invoice
14
15
  one_to_many :items, :class=>:'BlackStack::InvoiceItem', :key=>:id_invoice
15
16
 
16
17
  # compara 2 planes, y retorna TRUE si ambos pueden coexistir en una misma facutra, con un mismo enlace de PayPal
@@ -269,24 +270,67 @@ module BlackStack
269
270
  self.save()
270
271
  end
271
272
 
272
- # cambia el estado de la factura de UNPAID a PAID
273
- # verifica que el estado de la factura sea NULL o UNPAID
274
- # crea los registros contables por el pago de esta factura
275
- def getPaid()
273
+ # Verifica que el estado de la factura sea NULL o UNPAID.
274
+ # Cambia el estado de la factura de UNPAID a PAID.
275
+ # Crea los registros contables por el pago de esta factura: un registro por cada item, y por cada bono del plan en cada item.
276
+ # Los registros en la table de movimientos se registraran con la fecha del parametro sql_payment_datetime.
277
+ # Las fechas de expiracion de los movimientos se calculan seguin la fecha del pago.
278
+ #
279
+ # sql_payment_datetime: Fecha-hora del pago. Por defecto es la fecha-hora actual.
280
+ #
281
+ def getPaid(payment_time=nil)
282
+ payment_time = Time.now() if payment_time.nil?
283
+
276
284
  if self.canBePaid? == false
277
285
  raise "Method BlackStack::Invoice::getPaid requires the current status is nil or unpaid."
278
286
  end
279
287
  # marco la factura como pagada
280
288
  self.status = BlackStack::Invoice::STATUS_PAID
281
289
  self.save
290
+ # expiracion de creditos de la factura anterior
291
+ i = self.previous
292
+ if !i.nil?
293
+ InvoiceItem.where(:id_invoice=>i.id).all { |item|
294
+ #
295
+ BlackStack::Movement.where(:id_invoice_item => item.id).all { |mov|
296
+ #
297
+ mov.expire if mov.expiration_on_next_payment == true
298
+ #
299
+ DB.disconnect
300
+ GC.start
301
+ } # BlackStack::Movement.where(:id_invoice_item => item.id).all { |mov|
302
+ #
303
+ DB.disconnect
304
+ GC.start
305
+ } # InvoiceItem.where(:id_invoice=>i.id).all { |item|
306
+ end
282
307
  # registro los asientos contables
283
- InvoiceItem.where(:id_invoice=>self.id).all { |item|
284
- BlackStack::Movement.new().parse(item, BlackStack::Movement::MOVEMENT_TYPE_ADD_PAYMENT, "Invoice Payment").save()
308
+ InvoiceItem.where(:id_invoice=>self.id).all { |item|
309
+ # obtengo descriptor del plan
310
+ plan = BlackStack::InvoicingPaymentsProcessing.plan_descriptor(item.item_number)
311
+ # obtengo descriptor del producto
312
+ prod = BlackStack::InvoicingPaymentsProcessing.product_descriptor(plan[:product_code])
313
+ # registro el pago
314
+ BlackStack::Movement.new().parse(item, BlackStack::Movement::MOVEMENT_TYPE_ADD_PAYMENT, "Invoice Payment", payment_time, item.id).save()
315
+ # agrego los bonos de este plan
316
+ plan[:bonus_plans].each { |h|
317
+ plan_bonus = BlackStack::InvoicingPaymentsProcessing.plan_descriptor(h[:item_number])
318
+ raise "bonus plan not found" if plan_bonus.nil?
319
+ bonus = BlackStack::InvoiceItem.new
320
+ bonus.id = guid()
321
+ bonus.id_invoice = self.id
322
+ bonus.product_code = plan_bonus[:product_code]
323
+ bonus.unit_price = 0
324
+ bonus.units = plan_bonus[:credits]
325
+ bonus.amount = 0
326
+ bonus.item_number = plan_bonus[:item_number]
327
+ BlackStack::Movement.new().parse(bonus, BlackStack::Movement::MOVEMENT_TYPE_ADD_BONUS, 'Payment Bonus', payment_time, item.id).save()
328
+ }
285
329
  #
286
330
  DB.disconnect
287
331
  GC.start
288
332
  }
289
- end
333
+ end # def getPaid
290
334
 
291
335
  # Verify if I can add this item_number to this invoice.
292
336
  # Otherwise, it raise an exception.
@@ -450,10 +494,10 @@ module BlackStack
450
494
  # en este caso la factura se genera antes del pago.
451
495
  # crea uno o mas registros en la tabla invoice_item.
452
496
  def next(i)
453
- b = i.buffer_paypal_notification
454
- if b == nil
455
- raise "Method BlackStack::Invoice::next requires the previous invoice (i) is linked to a record in the table buffer_paypal_notification."
456
- end
497
+ # b = i.buffer_paypal_notification
498
+ # if b == nil
499
+ # raise "Method BlackStack::Invoice::next requires the previous invoice (i) is linked to a record in the table buffer_paypal_notification."
500
+ # end
457
501
 
458
502
  id_client = i.id_client
459
503
  c = BlackStack::Client.where(:id=>id_client).first
@@ -474,7 +518,8 @@ module BlackStack
474
518
  self.create_time = now()
475
519
  self.id_client = c.id
476
520
  self.id_buffer_paypal_notification = nil
477
- self.subscr_id = b.subscr_id
521
+ self.id_previous_invoice = i.id
522
+ self.subscr_id = i.subscr_id
478
523
  self.disabled_for_add_remove_items = true
479
524
 
480
525
  i.items.each { |t|
@@ -527,17 +572,14 @@ module BlackStack
527
572
  # cargo la factura
528
573
  i = BlackStack::Invoice.where(:id=>id_invoice).first
529
574
  raise "Invoice not found (#{id_invoice})" if i.nil?
530
-
531
575
  # obtengo el total de la factura
532
576
  total = i.total.to_f
533
-
534
577
  # Si existe un item, y solo uno, con importe igual al reembolso, entonces se aplica todo el reembolso a ese item. Y termina la funcion.
535
578
  # Si existen mas de un item con igual importe que el reembolso, entonces se levanta una excepcion.
536
579
  matched_items = i.items.select { |o| o.amount.to_f == -payment_gross.to_f }
537
-
580
+ #
538
581
  if total < -payment_gross
539
582
  raise "The refund is higher than the invoice amount (invoice #{id_invoice}, #{total.to_s}, #{payment_gross.to_s})"
540
-
541
583
  # Si el monto del reembolso es igual al total de la factura, se hace un reembolso total de todos los items. Y termina la funcion.
542
584
  # Si el monto de la factura es distinto al moneto del reembolso, entonces se levanta una excepcion.
543
585
  elsif total == -payment_gross
@@ -555,39 +597,28 @@ module BlackStack
555
597
  item1.detail = u.detail.to_s
556
598
  item1.description = u.description.to_s
557
599
  item1.save()
558
- BlackStack::Movement.new().parse(item1, BlackStack::Movement::MOVEMENT_TYPE_REFUND_BALANCE).save()
600
+ BlackStack::Movement.new().parse(item1, BlackStack::Movement::MOVEMENT_TYPE_REFUND_BALANCE, 'Full Refund').save()
601
+ # si el balance quedo en negativo, entonces aplico otro ajuste
602
+ net_amount = 0.to_f - BlackStack::Balance.new(self.client.id, u.product_code.to_s).amount.to_f
603
+ net_credits = 0.to_f - BlackStack::Balance.new(self.client.id, u.product_code.to_s).credits.to_f
604
+ if net_amount < 0 && net_credits < 0
605
+ adjust = self.client.adjustment(u.product_code.to_s, net_amount, net_credits, 'Adjustment for Negative Balance after Refund')
606
+ adjust.id_invoice_item = item1.id
607
+ adjust.save
608
+ end # if net_amount < 0
559
609
  # release resources
560
610
  DB.disconnect
561
611
  GC.start
562
- }
563
- =begin
564
- # si existe al menos un item que coincida el total con el monto del reembolso,
565
- # entonces selecciono el primero
566
- elsif matched_items.size > 0
567
- t = matched_items.first
568
- h = BlackStack::InvoicingPaymentsProcessing::plans_descriptor.select { |obj| obj[:item_number] == t.item_number }.first
569
- raise "Plan not found" if h.nil?
570
- item1 = BlackStack::InvoiceItem.new()
571
- item1.id = guid()
572
- item1.id_invoice = self.id
573
- item1.unit_price = t.unit_price.to_f
574
- item1.units = -t.units
575
- item1.amount = -t.amount.to_f
576
- item1.product_code = t.product_code.to_s
577
- item1.item_number = t.item_number.to_s
578
- item1.detail = t.detail.to_s
579
- item1.description = t.description.to_s
580
- item1.save()
581
- BlackStack::Movement.new().parse(item1, BlackStack::Movement::MOVEMENT_TYPE_REFUND_BALANCE).save()
582
- =end
612
+ } # i.items.each { |u|
583
613
  # reembolso parcial de una factura con un unico item
584
614
  elsif i.items.size == 1
585
615
  t = i.items.first
586
-
616
+ #
587
617
  amount = -payment_gross.to_f
588
618
  unit_price = t.amount.to_f / t.units.to_f
589
- units = (amount / unit_price.to_f).round.to_i
590
-
619
+ float_units = (amount / unit_price.to_f)
620
+ units = float_units.round.to_i
621
+ #
591
622
  h = BlackStack::InvoicingPaymentsProcessing::plans_descriptor.select { |obj| obj[:item_number] == t.item_number }.first
592
623
  raise "Plan not found" if h.nil?
593
624
  item1 = BlackStack::InvoiceItem.new()
@@ -601,13 +632,27 @@ module BlackStack
601
632
  item1.detail = t.detail.to_s
602
633
  item1.description = t.description.to_s
603
634
  item1.save()
604
- BlackStack::Movement.new().parse(item1, BlackStack::Movement::MOVEMENT_TYPE_REFUND_BALANCE).save()
605
-
635
+ BlackStack::Movement.new().parse(item1, BlackStack::Movement::MOVEMENT_TYPE_REFUND_BALANCE, 'Partial Refund').save()
636
+ # agrego un ajuste por el redondeo a una cantidad entera de creditos
637
+ if float_units.to_f != units.to_f
638
+ adjustment_amount = unit_price.to_f * (units.to_f - float_units.to_f)
639
+ adjust = self.client.adjustment(t.product_code.to_s, adjustment_amount, 0, 'Adjustment for Partial Refund', BlackStack::Movement::MOVEMENT_TYPE_REFUND_ADJUSTMENT)
640
+ adjust.id_invoice_item = item1.id
641
+ adjust.save
642
+ end
643
+ # si el balance quedo en negativo, entonces aplico otro ajuste
644
+ net_amount = 0.to_f - BlackStack::Balance.new(self.client.id, t.product_code.to_s).amount.to_f
645
+ net_credits = 0.to_f - BlackStack::Balance.new(self.client.id, t.product_code.to_s).credits.to_f
646
+ if net_amount < 0 && net_credits < 0
647
+ adjust = self.client.adjustment(t.product_code.to_s, net_amount, net_credits, 'Adjustment for Negative Balance')
648
+ adjust.id_invoice_item = item1.id
649
+ adjust.save
650
+ end # if net_amount < 0
651
+ # recalculo todos los consumos y expiraciones - CANCELADO - Debe hacerse offline
652
+ # self.client.recalculate(t.product_code.to_s)
606
653
  else
607
654
  raise "Refund amount is not matching with the invoice total (#{total.to_s}) and the invoice has more than 1 item."
608
-
609
655
  end
610
-
611
656
  # release resources
612
657
  DB.disconnect
613
658
  GC.start
@@ -10,8 +10,10 @@ module BlackStack
10
10
  MOVEMENT_TYPE_ADD_BONUS = 1
11
11
  MOVEMENT_TYPE_REASSIGN_BALANCE = 2
12
12
  MOVEMENT_TYPE_REFUND_BALANCE = 3
13
- MOVEMENT_TYPE_CANCELATION = 4 # liability with the client is reduced due service delivery
14
- MOVEMENT_TYPE_EXPIRATION = 5 # liability with the client is reduced due credits expiration
13
+ MOVEMENT_TYPE_CANCELATION = 4 # liability with the client is reduced due service delivery. it can be recalculated
14
+ MOVEMENT_TYPE_EXPIRATION = 5 # liability with the client is reduced due credits expiration. it can be recalculated
15
+ MOVEMENT_TYPE_ADJUSTMENT = 6 # it can be recalculated
16
+ MOVEMENT_TYPE_REFUND_ADJUSTMENT = 7 # it cannot be recalculated
15
17
 
16
18
  def typeName()
17
19
  if (self.type==MOVEMENT_TYPE_ADD_PAYMENT)
@@ -46,17 +48,20 @@ module BlackStack
46
48
  end
47
49
 
48
50
  # actualiza el registro con los valores del item de una factura
49
- # type may be either MOVEMENT_TYPE_ADD_PAYMENT or MOVEMENT_TYPE_ADD_BONUS, but not other value
50
- def parse(item, type=MOVEMENT_TYPE_ADD_PAYMENT, description='n/a')
51
- plan = BlackStack::InvoicingPaymentsProcessing.plan_descriptor(item.item_number)
51
+ # type may be either MOVEMENT_TYPE_ADD_PAYMENT or MOVEMENT_TYPE_ADD_BONUS or MOVEMENT_TYPE_REFUND_BALANCE, but not other value
52
+ def parse(item, type=MOVEMENT_TYPE_ADD_PAYMENT, description='n/a', payment_time=nil, id_item=nil)
53
+ # the movment must be a payment or a bonus or a refund
54
+ raise 'Movement must be either a payment or bonus or refund' if type != MOVEMENT_TYPE_ADD_PAYMENT && type != MOVEMENT_TYPE_ADD_BONUS && type != MOVEMENT_TYPE_REFUND_BALANCE
55
+ #
56
+ payment_time = Time.now() if payment_time.nil?
57
+ plan = BlackStack::InvoicingPaymentsProcessing.plan_descriptor(item.item_number)
52
58
  prod = BlackStack::InvoicingPaymentsProcessing.product_descriptor(plan[:product_code])
53
-
54
59
  if (self.id==nil)
55
60
  self.id=guid()
56
61
  end
57
62
  self.id_client = item.invoice.id_client
58
- self.id_invoice_item = item.id
59
- self.create_time = item.invoice.billing_period_from
63
+ self.id_invoice_item = id_item.nil? ? item.id : id_item
64
+ self.create_time = payment_time #item.invoice.billing_period_from
60
65
  self.type = type
61
66
  if (type != MOVEMENT_TYPE_ADD_BONUS)
62
67
  self.paypal1_amount = item.amount.to_f
@@ -70,68 +75,127 @@ module BlackStack
70
75
  self.product_code = item.product_code
71
76
  self.profits_amount = 0
72
77
  self.description = description
73
- self.expiration_time = DB["SELECT DATEADD(#{prod[:credits_expiration_period].to_s}#{prod[:credits_expiration_period].to_s}, +#{prod[:credits_expiration_units].to_s}, GETDATE()) AS d"].first[:d].to_s
78
+ if (type == MOVEMENT_TYPE_ADD_BONUS || type == MOVEMENT_TYPE_ADD_PAYMENT)
79
+ self.expiration_time = DB["SELECT DATEADD(#{prod[:credits_expiration_period].to_s}#{prod[:credits_expiration_period].to_s}, +#{prod[:credits_expiration_units].to_s}, '#{payment_time.to_sql}') AS d"].first[:d].to_s
80
+ end
81
+ self.expiration_on_next_payment = plan[:expiration_on_next_payment]
82
+ self.expiration_lead_period = plan[:expiration_lead_period]
83
+ self.expiration_lead_units = plan[:expiration_lead_units]
84
+ #self.give_away_negative_credits = plan[:give_away_negative_credits]
74
85
  self.save()
86
+ # recalculate - CANCELADO - SE DEBE HACER OFFLINE
87
+ #self.recalculate
88
+ #
89
+ self
75
90
  end
76
91
 
77
- # Creates a new record in the table movement, as an expiration of the unused credits of this movement.
78
- # This movement must be either a payment or a bonus.
79
- # This movement must have an expiration time.
80
- # The expiraton time of this movement is lower than the current date-time.
81
- def expire()
82
- m = self
83
- p = BlackStack::InvoicingPaymentsProcessing::product_descriptor(m.product_code)
84
-
85
- if m.type != MOVEMENT_TYPE_ADD_PAYMENT && m.type != MOVEMENT_TYPE_ADD_BONUS
86
- raise "Movement type mismatch."
87
- end
88
-
89
- if m.expiration_time.nil?
90
- raise "Expiration time is null."
91
- end
92
-
93
- if m.expiration_time >= Time::now()
94
- raise "Expiration time is pending."
95
- end
96
-
97
- if m.expiration_time <= m.create_time
98
- raise "Expiration time is lower then creation time."
99
- end
100
-
101
- # calculo cuantos creditos tiene este cliente
102
- #x = 0.to_f - BlackStack::Balance.new(m.client.id, p[:code]).credits.to_f
103
- # calculo los creditos de este movimiento que voy a cancelar
104
- x = 0.to_f - m.credits.to_f
105
-
106
- # calculo el credito consumido luego de este movimiento que voy a cancelar
107
- y = m.client.movements.select { |o|
92
+ # Returns the number of credits assigned in the movement that have been consumed.
93
+ # The movment must be a payment or a bonus
94
+ def credits_consumed()
95
+ # the movment must be a payment or a bonus
96
+ raise 'Movement must be either a payment or a bonus' if self.type != MOVEMENT_TYPE_ADD_PAYMENT && self.type != MOVEMENT_TYPE_ADD_BONUS
97
+ #puts
98
+ #puts "product_code:#{self.product_code}:."
99
+ # itero los pagos y bonos hechos por este mismo producto, desde el primer dia hasta este movimiento.
100
+ paid = 0
101
+ self.client.movements.select { |o|
102
+ (o.type == MOVEMENT_TYPE_ADD_PAYMENT || o.type == MOVEMENT_TYPE_ADD_BONUS) &&
103
+ o.credits.to_f < 0 &&
104
+ o.product_code.upcase == self.product_code.upcase
105
+ }.sort_by { |o| o.create_time }.each { |o|
106
+ paid += (0.to_f - o.credits.to_f)
107
+ break if o.id.to_guid == self.id.to_guid
108
+ }
109
+ #puts "paid:#{paid.to_s}:."
110
+ # calculo los credito para este producto, desde el primer dia; incluyendo cosumo, expiraciones, ajustes.
111
+ consumed = self.client.movements.select { |o|
108
112
  o.credits.to_f > 0 &&
109
- o.product_code.upcase == p[:code].upcase &&
110
- o.create_time > m.create_time
113
+ o.product_code.upcase == self.product_code.upcase
111
114
  }.inject(0) { |sum, o| sum.to_f + o.credits.to_f }.to_f
115
+ #puts "consumed:#{consumed.to_s}:."
116
+ # calculo los creditos de este movimiento que voy a cancelar
117
+ credits = 0.to_f - self.credits.to_f
118
+ #puts "credits:#{credits.to_s}:."
119
+ #
120
+ if paid - consumed <= 0 # # se consumio todo
121
+ #puts "a"
122
+ return credits
123
+ else # paid - consumed > 0 # todavia no se consumio todo
124
+ if paid - consumed > credits # todavia se estan consumiendo creditos de los pagos anteriores
125
+ #puts "b"
126
+ return 0
127
+ else # paid - consumed >= credits # se consumio una parte del credito
128
+ #puts "c"
129
+ n = credits >= (paid - consumed) ? credits - (paid - consumed) : credits
130
+ #puts "n:#{n.to_s}:."
131
+ return n
132
+ end
133
+ end
134
+ end
135
+
136
+ # returns the real expiration based on expiration_time, expiration_lead_period and expiration_lead_units
137
+ def expiration_lead_time()
138
+ return nil if self.expiration_time.nil?
139
+ return self.expiration_time if self.expiration_lead_period.nil? || self.expiration_lead_units.nil?
140
+ if self.expiration_lead_period == 'H' # hours
141
+ return self.expiration_time + self.expiration_lead_units.to_i * 60*60
142
+ elsif self.expiration_lead_period == 'D' # days
143
+ return self.expiration_time + self.expiration_lead_units.to_i * 24*60*60
144
+ elsif self.expiration_lead_period == 'W' # weeks
145
+ return self.expiration_time + self.expiration_lead_units.to_i * 7*24*60*60
146
+ elsif self.expiration_lead_period == 'M' # months
147
+ return self.expiration_time + self.expiration_lead_units.to_i * 31*24*60*60
148
+ elsif self.expiration_lead_period == 'Y' # years
149
+ return self.expiration_time + self.expiration_lead_units.to_i * 366*24*60*60
150
+ else
151
+ return self.expiration_time
152
+ end
153
+ end
154
+
155
+ # credits expiration
156
+ def expire()
157
+ credits_consumed = self.credits_consumed
158
+ #
159
+ self.expiration_start_time = now()
160
+ self.expiration_tries = self.expiration_tries.to_i + 1
161
+ self.save
162
+ #
163
+ total_credits = 0.to_f - BlackStack::Balance.new(self.client.id, self.product_code).credits.to_f
164
+ total_amount = 0.to_f - BlackStack::Balance.new(self.client.id, self.product_code).amount.to_f
165
+ #
166
+ credits = 0.to_i - self.credits.to_i
167
+ #
168
+ credits_to_expire = credits - credits_consumed.to_i #- (0.to_f - self.credits.to_f)).to_i
169
+ amount_to_expire = total_credits.to_f == 0 ? 0 : credits_to_expire.to_f * ( total_amount.to_f / total_credits.to_f )
170
+ #
171
+ exp = BlackStack::Movement.new
172
+ exp.id = guid()
173
+ exp.id_client = self.client.id
174
+ exp.create_time = now()
175
+ exp.type = BlackStack::Movement::MOVEMENT_TYPE_EXPIRATION
176
+ exp.id_user_creator = self.id_user_creator
177
+ exp.description = 'Expiration Because Allocation is Renewed'
178
+ exp.paypal1_amount = 0
179
+ exp.bonus_amount = 0
180
+ exp.amount = amount_to_expire
181
+ exp.credits = credits_to_expire
182
+ exp.profits_amount = -amount_to_expire
183
+ exp.id_invoice_item = self.id_invoice_item
184
+ exp.product_code = self.product_code
185
+ exp.save
186
+ #
187
+ self.expiration_end_time = now()
188
+ self.save
189
+ end # def expire
112
190
 
113
- # calculo el # de creditos no usados de este movimiento que ha expirado
114
- z = x-y>0 ? x-y : 0
191
+ # recalculate the amount for all the consumptions.
192
+ # The movment must be a payment or a bonus or refund
193
+ def recalculate()
194
+ # the movment must be a payment or a bonus or a refund
195
+ raise 'Movement must be either a payment or bonus or refund' if type != MOVEMENT_TYPE_ADD_PAYMENT && type != MOVEMENT_TYPE_ADD_BONUS && type != MOVEMENT_TYPE_REFUND_BALANCE
196
+ # recalculate amounts for all the consumptions and expirations
197
+ self.client.recalculate(self.product_code)
198
+ end
115
199
 
116
- # si el monto expirado es positivo, entonces registro
117
- # una cancelacion de saldo
118
- if z>0
119
- amount = ( m.amount.to_f / m.credits.to_f ) * z.to_f
120
- m = BlackStack::Movement.new(
121
- :id_client => m.client.id,
122
- :create_time => now(),
123
- :type => BlackStack::Movement::MOVEMENT_TYPE_EXPIRATION,
124
- :description => "Expiration of #{m.id.to_guid}",
125
- :paypal1_amount => 0,
126
- :bonus_amount => 0,
127
- :amount => amount,
128
- :credits => z,
129
- :profits_amount => -amount,
130
- :product_code => p[:code],
131
- )
132
- m.id = guid()
133
- m.save
134
- end # z>0
135
- end # def expire
136
200
  end # class Movement
137
201
  end # module BlackStack
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: invoicing_payments_processing
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 1.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leandro Daniel Sardi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-11 00:00:00.000000000 Z
11
+ date: 2020-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: websocket