invoicing_payments_processing 1.1.5 → 1.1.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bufferpaypalnotification.rb +11 -4
- data/lib/extend_client_by_invoicing_payments_processing.rb +105 -2
- data/lib/invoice.rb +90 -45
- data/lib/movement.rb +128 -65
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7e4d7194c2ac3594193e231417821a28b0daa0c
|
4
|
+
data.tar.gz: 8cc60962a9ef7fc84ad96465544970d3e7e571ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab7b6a9840757feec565f44f1de5d8d84be2c0d295debfe16f19c6b6013dd41c64eca89f4709f76f415dd25790e537e2420ee50a78217f15b4e3d57b7cbdffd2
|
7
|
+
data.tar.gz: c5c6a98c57439ebda830e94e5e1b44080b4a9998f44b66c3c6ccc6bae63e6fcf7f57e5ab692d3e7d462eb94ad4d9969be9713fa0660afbf903a38594d1003def
|
@@ -43,13 +43,19 @@ module BlackStack
|
|
43
43
|
def get_client()
|
44
44
|
# obtengo el cliente que machea con este perfil
|
45
45
|
c = nil
|
46
|
-
if
|
46
|
+
if c.nil?
|
47
|
+
if self.invoice.guid?
|
48
|
+
i = BlackStack::Invoice.where(:id=>self.invoice).first
|
49
|
+
c = i.client if !i.nil?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
if c.nil?
|
47
53
|
cid = self.invoice.split(".").first.to_s
|
48
54
|
if cid.guid?
|
49
55
|
c = BlackStack::Client.where(:id=>cid).first
|
50
56
|
end
|
51
57
|
end
|
52
|
-
if
|
58
|
+
if c.nil?
|
53
59
|
c = BlackStack::Client.where(:paypal_email=>self.payer_email).first
|
54
60
|
if (c == nil)
|
55
61
|
u = User.where(:email=>self.payer_email).first
|
@@ -58,13 +64,13 @@ module BlackStack
|
|
58
64
|
end
|
59
65
|
end
|
60
66
|
end
|
61
|
-
if
|
67
|
+
if c.nil?
|
62
68
|
s = BlackStack::PayPalSubscription.where(:payer_email=>self.payer_email).first
|
63
69
|
if (s!=nil)
|
64
70
|
c = s.client
|
65
71
|
end
|
66
72
|
end
|
67
|
-
if
|
73
|
+
if c.nil?
|
68
74
|
# obtengo el cliente - poco elegante
|
69
75
|
q =
|
70
76
|
"SELECT TOP 1 i.id_client AS cid " +
|
@@ -288,6 +294,7 @@ module BlackStack
|
|
288
294
|
|
289
295
|
# le asigno el id_buffer_paypal_notification
|
290
296
|
i.id_buffer_paypal_notification = b.id
|
297
|
+
i.subscr_id = b.subscr_id
|
291
298
|
i.save
|
292
299
|
|
293
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
|
-
|
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
|
data/lib/invoice.rb
CHANGED
@@ -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
|
-
#
|
273
|
-
#
|
274
|
-
#
|
275
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/movement.rb
CHANGED
@@ -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
|
-
|
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 = item.invoice.billing_period_from #payment_time
|
60
65
|
self.type = type
|
61
66
|
if (type != MOVEMENT_TYPE_ADD_BONUS)
|
62
67
|
self.paypal1_amount = item.amount.to_f
|
@@ -70,69 +75,127 @@ module BlackStack
|
|
70
75
|
self.product_code = item.product_code
|
71
76
|
self.profits_amount = 0
|
72
77
|
self.description = description
|
73
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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|
|
112
|
+
o.credits.to_f > 0 &&
|
113
|
+
o.product_code.upcase == self.product_code.upcase
|
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
|
96
135
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
103
154
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
113
190
|
|
114
|
-
|
115
|
-
|
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
|
116
199
|
|
117
|
-
# si el monto expirado es positivo, entonces registro
|
118
|
-
# una cancelacion de saldo
|
119
|
-
if z>0
|
120
|
-
amount = ( m.amount.to_f / m.credits.to_f ) * z.to_f
|
121
|
-
m = BlackStack::Movement.new(
|
122
|
-
:id_client => m.client.id,
|
123
|
-
:create_time => now(),
|
124
|
-
:type => BlackStack::Movement::MOVEMENT_TYPE_EXPIRATION,
|
125
|
-
:description => "Expiration of #{m.id.to_guid}",
|
126
|
-
:paypal1_amount => 0,
|
127
|
-
:bonus_amount => 0,
|
128
|
-
:amount => amount,
|
129
|
-
:credits => z,
|
130
|
-
:profits_amount => -amount,
|
131
|
-
:product_code => p[:code],
|
132
|
-
)
|
133
|
-
m.id = guid()
|
134
|
-
m.save
|
135
|
-
end # z>0
|
136
|
-
end # def expire
|
137
200
|
end # class Movement
|
138
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.
|
4
|
+
version: 1.1.15
|
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-
|
11
|
+
date: 2020-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: websocket
|