On the way to have the offline deposits and withdrawals
[breadcrumbs.git] / src / lib / Bcd / Data / Deposits.pm
blob48ce99863d8f2511d604440ce94bd7b8e9bc34e7
1 package Bcd::Data::Deposits;
3 # This file is part of the breadcrumbs daemon (bcd).
4 # Copyright (C) 2007 Pasqualino Ferrentino
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
21 # Contact: lino.ferrentino@yahoo.it (in Italian, English or German).
23 use strict;
24 use warnings;
26 #use Math::BigInt lib => "GMP";
28 use Bcd::Constants::DepositsConstants;
29 use Bcd::Data::Token;
30 use Bcd::Data::Bank;
32 use Digest::SHA1;
34 use constant {
36 INSERT_DEPOSIT_OR_WITHDRAWAL_REQUEST =>
37 qq{INSERT into deposits_and_withdrawals(id_user, is_deposit, amount, status, booking_token, }.
38 qq{full_receipt_token, secret_token) }.
39 qq{values (?, ?, ?, } . Bcd::Constants::DepositsConstants::CREATION_STATE . qq{, ?, ?, ?)},
41 SELECT_DEPOSIT_OR_WITHDRAWAL_USER_BOOKING =>
42 qq{SELECT * from deposits_and_withdrawals where id_user = ? and is_deposit = ? and booking_token = ?},
44 SELECT_BOOKING_FROM_TOKEN =>
45 qq{SELECT * from deposits_and_withdrawals where booking_token = ?},
47 SELECT_BOOKING_FROM_ID =>
48 qq{SELECT * from deposits_and_withdrawals where id = ?},
50 SELECT_COUNT_PENDING_USERS_REQUESTS =>
51 qq{SELECT count(*) from deposits_and_withdrawals where id_user=? and }.
52 qq{status !=}.Bcd::Constants::DepositsConstants::COLLECTED,
54 SELECT_PENDING_USERS_REQUEST =>
55 qq{SELECT * from deposits_and_withdrawals where id_user=? and }.
56 qq{status !=}.Bcd::Constants::DepositsConstants::COLLECTED,
58 DELETE_BOOKING_ID =>
59 qq{DELETE FROM deposits_and_withdrawals WHERE id = ? },
61 SELECT_ALL_ANT_NEST_BOOKINGS_STATUS =>
62 qq{SELECT d.booking_token, d.amount FROM deposits_and_withdrawals AS d, users as u WHERE }.
63 qq{ d.id_user = u.id AND u.id_ant_nest = ? AND d.is_deposit = ? AND d.status = ? }.
64 qq{ ORDER BY d.id },
66 SELECT_ALL_ANT_NEST_BOOKINGS_STATUS_OFFLINE =>
67 qq{SELECT d.booking_token, d.amount, d.full_receipt_token FROM deposits_and_withdrawals AS d, users as u WHERE }.
68 qq{ d.id_user = u.id AND u.id_ant_nest = ? AND d.is_deposit = ? AND d.status = ? }.
69 qq{ ORDER BY d.booking_token },
74 use constant{
75 SELECT_USER_DEPOSIT_TO_CLAIM => "Deposits_select_user_deposit_to_claim",
76 CLAIM_USER_DEPOSIT => "Deposits_claim_user_deposit",
77 INSERT_NEW_DEPOSIT_REQUEST => "Deposits_insert_deposit_request",
78 CHANGE_STATE_TO_DEPOSIT => "Deposits_change_state_to_deposit",
79 SELECT_DEPOSIT_USER_WITH_TOKEN => "Deposits_select_deposit_user_with_token",
80 SELECT_DEPOSIT_WITH_ID => "Deposits_select_deposit_with_id",
83 #this function is one shot... so it does not put the commands in the
84 #stash
85 sub init_db{
86 my ($self, $stash) = @_;
87 my $conn = $stash->get_connection();
89 #ok, now I should insert the values in the table...
90 my $sth = $conn->prepare(qq{insert into deposit_withdrawal_statuses values(?,?)});
92 foreach (Bcd::Constants::DepositsConstants::LIST_DEPOSITS_STATES){
93 $sth->bind_param(1, $_->[0]);
94 $sth->bind_param(2, $_->[1]);
95 $sth->execute();
98 $sth->finish();
102 sub get_deposits_to_do_offline_ds{
103 my ($self, $stash, $ant_nest) = @_;
105 return $self->_get_bookings_to_collect_offline_ds
106 ($stash, $ant_nest, 1, Bcd::Constants::DepositsConstants::CREATION_STATE);
109 sub get_withdrawals_to_do_offline_ds{
110 my ($self, $stash, $ant_nest) = @_;
112 return $self->_get_bookings_to_collect_offline_ds
113 ($stash, $ant_nest, 0, Bcd::Constants::DepositsConstants::CREATION_STATE);
116 sub _get_bookings_to_collect_offline_ds{
117 my ($self, $stash, $ant_nest, $is_deposit, $status) = @_;
119 my $st = $stash->prepare_cached(SELECT_ALL_ANT_NEST_BOOKINGS_STATUS_OFFLINE);
120 $st->bind_param(1, $ant_nest);
121 $st->bind_param(2, $is_deposit);
122 $st->bind_param(3, $status);
124 $st->execute();
126 my $var = $st->{NAME_lc};
127 my $arr = $st->fetchall_arrayref();
129 #I put at the front of the recordset the columns names.
130 unshift (@{$arr}, $var);
132 return $arr;
136 sub get_withdrawals_to_collect_offline_ds{
137 my ($self, $stash, $ant_nest) = @_;
139 return $self->_select_all_ant_nest_booking_status_ds
140 ($stash, $ant_nest, 0, Bcd::Constants::DepositsConstants::OFFLINE_ACKNOWLEDGED);
143 sub get_all_created_deposits_ant_nest_ds {
144 my ($self, $stash, $ant_nest) = @_;
146 return $self->_select_all_ant_nest_booking_status_ds
147 ($stash, $ant_nest, 1, Bcd::Constants::DepositsConstants::CREATION_STATE);
150 sub get_all_created_withdrawals_ant_nest_ds {
151 my ($self, $stash, $ant_nest) = @_;
153 return $self->_select_all_ant_nest_booking_status_ds
154 ($stash, $ant_nest, 0, Bcd::Constants::DepositsConstants::CREATION_STATE);
157 sub _select_all_ant_nest_booking_status_ds{
158 my ($self, $stash, $ant_nest, $is_deposit, $status) = @_;
160 my $st = $stash->prepare_cached(SELECT_ALL_ANT_NEST_BOOKINGS_STATUS);
161 $st->bind_param(1, $ant_nest);
162 $st->bind_param(2, $is_deposit);
163 $st->bind_param(3, $status);
165 $st->execute();
167 my $var = $st->{NAME_lc};
168 my $arr = $st->fetchall_arrayref();
170 #I put at the front of the recordset the columns names.
171 unshift (@{$arr}, $var);
173 return $arr;
176 sub delete_booking_id{
177 my ($self, $stash, $booking_id) = @_;
179 my $st = $stash->prepare_cached(DELETE_BOOKING_ID);
180 $st->bind_param(1, $booking_id);
181 $st->execute();
184 sub get_pending_booking_from_user_id_arr{
185 my ($self, $stash, $user_id) = @_;
187 my $st = $stash->prepare_cached(SELECT_PENDING_USERS_REQUEST);
188 $st->bind_param(1, $user_id);
190 $st->execute();
191 my $res = $st->fetchrow_arrayref();
192 $st->finish();
194 return $res;
197 =head1 are_there_pending_deposit_for_this_user
199 This function simply looks if the user has already some OR withdrawals active...
201 =cut
202 sub is_there_a_pending_request_for_this_user{
203 my ($self, $stash, $user_id) = @_;
205 my $st = $stash->prepare_cached(SELECT_COUNT_PENDING_USERS_REQUESTS);
206 $st->bind_param(1, $user_id);
208 $st->execute();
209 my $res = $st->fetchrow_arrayref();
210 $st->finish();
212 if ( $res->[0] != 0 ) {
213 return 1;
214 } else {
215 return 0;
220 sub _create_deposit_or_withdrawal_booking{
221 my ($self, $stash, $user_id, $amount, $is_deposit) = @_;
223 my $booking_token = Bcd::Data::Token::generate_new_token();
224 my ($long_token, $blinded_token, $secret_token) = Bcd::Data::Token::generate_long_token();
226 #ok, now I should make the hash of the secret token
227 my $sha = Digest::SHA1->new;
228 $sha->add($secret_token);
229 my $digest = $sha->hexdigest;
231 #ok, now I am ready to insert the data in the table
232 my $st = $stash->prepare_cached(INSERT_DEPOSIT_OR_WITHDRAWAL_REQUEST);
234 $st->bind_param(1, $user_id);
235 $st->bind_param(2, $is_deposit);
236 $st->bind_param(3, $amount);
237 $st->bind_param(4, $booking_token);
239 #if it is a withdrawal I record in the db the blinded token, not the full one
240 if ($is_deposit != 0){
241 $st->bind_param(5, $long_token);
242 } else {
243 $st->bind_param(5, $blinded_token);
246 $st->bind_param(6, $digest);
248 $st->execute();
250 #I return these tokens, but one of them is not returned to the user.
251 return ($booking_token, $long_token, $blinded_token);
254 =head1
256 This function should see create a user deposit
258 =cut
260 sub create_deposit_booking{
261 my ($self, $stash, $user_id, $amount) = @_;
263 my ($booking_token, $long_token, $blinded_token) =
264 $self->_create_deposit_or_withdrawal_booking
265 ($stash, $user_id, $amount, 1);
267 #the long token is NOT returned for the deposits
268 return ($booking_token, $blinded_token);
272 sub create_withdrawal_booking{
274 my ($self, $stash, $user_id, $amount) = @_;
276 my ($booking_token, $long_token, $blinded_token) =
277 $self->_create_deposit_or_withdrawal_booking
278 ($stash, $user_id, $amount, 0);
280 #the blinded_token is NOT returned for the withdrawals
281 return ($booking_token, $long_token);
284 =head2
286 This function simply changes the state of the booking
288 =cut
289 sub treasurer_acknowledged {
290 my ($self, $stash, $booking_id) = @_;
292 my $st = $stash->get_statement(CHANGE_STATE_TO_DEPOSIT, $self);
294 $st->bind_param(1, Bcd::Constants::DepositsConstants::OFFLINE_ACKNOWLEDGED);
295 $st->bind_param(2, $booking_id);
297 return $st->execute();
300 sub get_deposit_booking_from_user_and_token{
302 my ($self, $stash, $user_id, $booking) = @_;
304 return $self->_get_deposit_or_withdrawal_booking_from_user_token
305 ($stash, $user_id, $booking, '1');
308 sub get_withdrawal_booking_from_user_and_token{
310 my ($self, $stash, $user_id, $booking) = @_;
312 return $self->_get_deposit_or_withdrawal_booking_from_user_token
313 ($stash, $user_id, $booking, '0');
316 sub _get_deposit_or_withdrawal_booking_from_user_token{
318 my ($self, $stash, $user_id, $booking, $is_deposit) = @_;
320 my $st = $stash->prepare_cached(SELECT_DEPOSIT_OR_WITHDRAWAL_USER_BOOKING);
322 $st->bind_param(1, $user_id);
323 $st->bind_param(2, $is_deposit);
324 $st->bind_param(3, $booking);
326 $st->execute();
328 my $row = $st->fetchrow_arrayref();
329 $st->finish();
331 return $row;
334 sub get_booking_from_token_arr{
335 my ($self, $stash, $booking) = @_;
337 my $st = $stash->prepare_cached(SELECT_BOOKING_FROM_TOKEN);
339 $st->bind_param(1, $booking);
341 $st->execute();
343 my $arr = $st->fetchrow_arrayref();
344 $st->finish();
346 return $arr;
349 sub get_booking_from_token_hash{
351 my ($self, $stash, $booking) = @_;
353 my $st = $stash->prepare_cached(SELECT_BOOKING_FROM_TOKEN);
355 $st->bind_param(1, $booking);
357 $st->execute();
359 my $hash = $st->fetchrow_hashref();
360 $st->finish();
362 return $hash;
366 sub get_booking_from_id_hash{
367 my ($self, $stash, $id) = @_;
369 my $st = $stash->prepare_cached(SELECT_BOOKING_FROM_ID);
371 $st->bind_param(1, $id);
373 $st->execute();
375 my $hash = $st->fetchrow_hashref();
376 $st->finish();
378 return $hash;
381 sub get_booking_from_id_arr{
382 my ($self, $stash, $id) = @_;
384 my $st = $stash->prepare_cached(SELECT_BOOKING_FROM_ID);
385 $st->bind_param(1, $id);
386 $st->execute();
388 my $arr = $st->fetchrow_arrayref();
389 $st->finish();
390 return $arr;
393 sub _claim_this_booking_object{
394 my ($class, $stash, $ant_nest_code, $booking) = @_;
396 my $ticket_id = $booking->[0];
397 my $user = $booking->[2];
398 my $amount = $booking->[3];
400 my $amount_deposited_or_withdrawn;
401 my $new_total;
403 if ($booking->[1] == 1){
404 ($amount_deposited_or_withdrawn, $new_total) = Bcd::Data::Bank->deposit_user_account
405 ($stash, $user, $ant_nest_code, $amount);
406 } else {
407 ($amount_deposited_or_withdrawn, $new_total) = Bcd::Data::Bank->withdraw_user_account
408 ($stash, $user, $ant_nest_code, $amount);
411 $class->change_state_to_booking
412 ($stash, $ticket_id, Bcd::Constants::DepositsConstants::COLLECTED);
414 return ($amount_deposited_or_withdrawn, $new_total);
417 sub change_state_to_booking{
418 my ($class, $stash, $booking_id, $new_status) = @_;
420 my $st = $stash->get_statement(CHANGE_STATE_TO_DEPOSIT, $class);
422 $st->bind_param(1, $new_status);
423 $st->bind_param(2, $booking_id);
424 $st->execute();
428 sub claim_this_withdrawal_object{
429 my ($class, $stash, $ant_nest_code, $booking) = @_;
430 $class->_claim_this_booking_object($stash, $ant_nest_code, $booking);
433 sub claim_this_deposit_object{
434 my ($class, $stash, $ant_nest_code, $booking) = @_;
435 $class->_claim_this_booking_object($stash, $ant_nest_code, $booking);
438 sub claim_this_ticket{
439 my ($self, $stash, $ant_nest_code, $ticket_id) = @_;
441 #first of all I should get the ticket from the db.
442 my $st = $stash->get_statement(SELECT_DEPOSIT_WITH_ID, $self);
443 $st->bind_param(1, $ticket_id);
445 $st->execute();
447 my $row = $st->fetchrow_arrayref();
448 $st->finish();
451 my $is_deposit = $row->[1];
452 my $user = $row->[2];
453 my $amount = $row->[3];
456 #this should be given to the bank
457 my $amount_deposited_or_withdrawn;
458 my $new_total;
460 if ( $is_deposit == '1'){
461 ($amount_deposited_or_withdrawn, $new_total) = Bcd::Data::Bank->deposit_user_account
462 ($stash, $user, $ant_nest_code, $amount);
463 } else {
464 ($amount_deposited_or_withdrawn, $new_total) = Bcd::Data::Bank->withdraw_user_account
465 ($stash, $user, $ant_nest_code, $amount);
468 #then I should change the status of the ticket
469 $st = $stash->get_statement(CHANGE_STATE_TO_DEPOSIT, $self);
471 $st->bind_param(1, Bcd::Constants::DepositsConstants::COLLECTED);
472 $st->bind_param(2, $ticket_id);
473 $st->execute();
475 return ($amount_deposited_or_withdrawn, $new_total);
478 sub populate_the_stash{
479 my ($self, $db_stash) = @_;
481 my $sql;
483 $sql = qq{INSERT into deposits_and_withdrawals(id_user, is_deposit, amount, status, booking_token, }.
484 qq{full_receipt_token, secret_token) }.
485 qq{values (?, 't', ?, } . Bcd::Constants::DepositsConstants::CREATION_STATE . qq{, ?, ?, ?)};
486 $db_stash->record_this_statement(INSERT_NEW_DEPOSIT_REQUEST, $sql);
488 $sql = qq{UPDATE deposits_and_withdrawals SET status=? where id=?};
489 $db_stash->record_this_statement(CHANGE_STATE_TO_DEPOSIT, $sql);
491 $sql = qq{SELECT * from deposits_and_withdrawals where id_user=? and is_deposit='1' and booking_token = ?};
492 $db_stash->record_this_statement(SELECT_DEPOSIT_USER_WITH_TOKEN, $sql);
494 $sql = qq{SELECT * from deposits_and_withdrawals where id= ?};
495 $db_stash->record_this_statement(SELECT_DEPOSIT_WITH_ID, $sql);