|
1
|
|
|
<?php |
|
2
|
|
|
$defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; |
|
3
|
|
|
|
|
4
|
|
|
class Transaction extends Base { |
|
5
|
|
|
protected $table = 'transactions'; |
|
6
|
|
|
public $num_rows = 0, $insert_id = 0; |
|
7
|
|
|
|
|
8
|
|
|
/** |
|
9
|
|
|
* Add a new transaction to our class table |
|
10
|
|
|
* We also store the inserted ID in case the user needs it |
|
11
|
|
|
* @param account_id int Account ID to book transaction for |
|
12
|
|
|
* @param amount float Coin amount |
|
13
|
|
|
* @param type string Transaction type [Credit, Debit_AP, Debit_MP, Fee, Donation, Orphan_Credit, Orphan_Fee, Orphan_Donation] |
|
14
|
|
|
* @param block_id int Block ID to link transaction to [optional] |
|
15
|
|
|
* @param coin_address string Coin address for this transaction [optional] |
|
16
|
|
|
* @return bool |
|
17
|
|
|
**/ |
|
18
|
|
|
public function addTransaction($account_id, $amount, $type='Credit', $block_id=NULL, $coin_address=NULL, $txid=NULL) { |
|
19
|
|
|
$amount = number_format($amount, $this->coin->getCoinValuePrevision(), '.', ''); |
|
|
|
|
|
|
20
|
|
|
$stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, amount, block_id, type, coin_address, txid) VALUES (?, ?, ?, ?, ?, ?)"); |
|
21
|
|
|
if ($this->checkStmt($stmt) && $stmt->bind_param("isisss", $account_id, $amount, $block_id, $type, $coin_address, $txid) && $stmt->execute()) { |
|
22
|
|
|
$this->insert_id = $stmt->insert_id; |
|
23
|
|
|
return true; |
|
24
|
|
|
} |
|
25
|
|
|
return $this->sqlError(); |
|
26
|
|
|
} |
|
27
|
|
|
|
|
28
|
|
|
/** |
|
29
|
|
|
* Update a transaction with a RPC transaction ID |
|
30
|
|
|
* @param id integer Transaction ID |
|
31
|
|
|
* @param txid string RPC Transaction Identifier |
|
32
|
|
|
* @return bool true or false |
|
33
|
|
|
**/ |
|
34
|
|
|
public function setRPCTxId($transaction_id, $rpc_txid=NULL) { |
|
35
|
|
|
$stmt = $this->mysqli->prepare("UPDATE $this->table SET txid = ? WHERE id = ?"); |
|
36
|
|
|
if ($this->checkStmt($stmt) && $stmt->bind_param('si', $rpc_txid, $transaction_id) && $stmt->execute()) |
|
37
|
|
|
return true; |
|
38
|
|
|
return $this->sqlError(); |
|
39
|
|
|
} |
|
40
|
|
|
|
|
41
|
|
|
/* |
|
42
|
|
|
* Mark transactions of a user as archived |
|
43
|
|
|
* @param account_id int Account ID |
|
44
|
|
|
* @param txid int Transaction ID to start from |
|
45
|
|
|
* @param bool boolean True or False |
|
46
|
|
|
**/ |
|
47
|
|
View Code Duplication |
public function setArchived($account_id, $txid) { |
|
|
|
|
|
|
48
|
|
|
// Update all paid out transactions as archived |
|
49
|
|
|
$stmt = $this->mysqli->prepare(" |
|
50
|
|
|
UPDATE $this->table AS t |
|
51
|
|
|
LEFT JOIN " . $this->block->getTableName() . " AS b |
|
|
|
|
|
|
52
|
|
|
ON b.id = t.block_id |
|
53
|
|
|
SET t.archived = 1 |
|
54
|
|
|
WHERE t.archived = 0 |
|
55
|
|
|
AND ( |
|
56
|
|
|
( t.account_id = ? AND t.id <= ? AND b.confirmations >= ? ) |
|
57
|
|
|
OR ( t.account_id = ? AND t.id <= ? AND b.confirmations = -1 ) |
|
58
|
|
|
OR ( t.account_id = ? AND t.id <= ? AND t.type IN ( 'Credit_PPS', 'Donation_PPS', 'Fee_PPS', 'TXFee', 'Debit_MP', 'Debit_AP' ) ) |
|
59
|
|
|
)"); |
|
60
|
|
|
if ($this->checkStmt($stmt) && $stmt->bind_param('iiiiiii', $account_id, $txid, $this->config['confirmations'], $account_id, $txid, $account_id, $txid) && $stmt->execute()) |
|
|
|
|
|
|
61
|
|
|
return true; |
|
62
|
|
|
return $this->sqlError(); |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
/** |
|
66
|
|
|
* Fetch a transaction summary by type with total amounts |
|
67
|
|
|
* @param account_id int Account ID, NULL for all |
|
68
|
|
|
* @return data array type and total |
|
69
|
|
|
**/ |
|
70
|
|
|
public function getTransactionSummary($account_id=NULL) { |
|
71
|
|
|
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; |
|
|
|
|
|
|
72
|
|
|
$sql = " |
|
73
|
|
|
SELECT |
|
74
|
|
|
SUM(t.amount) AS total, t.type AS type |
|
75
|
|
|
FROM $this->table AS t |
|
76
|
|
|
LEFT OUTER JOIN " . $this->block->getTableName() . " AS b |
|
77
|
|
|
ON b.id = t.block_id |
|
78
|
|
|
WHERE ( b.confirmations > 0 OR b.id IS NULL )"; |
|
79
|
|
|
if (!empty($account_id)) { |
|
80
|
|
|
$sql .= " AND t.account_id = ? "; |
|
81
|
|
|
$this->addParam('i', $account_id); |
|
82
|
|
|
} |
|
83
|
|
|
$sql .= " GROUP BY t.type"; |
|
84
|
|
|
$stmt = $this->mysqli->prepare($sql); |
|
85
|
|
|
if (!empty($account_id)) { |
|
86
|
|
View Code Duplication |
if (!($this->checkStmt($stmt) && call_user_func_array( array($stmt, 'bind_param'), $this->getParam()) && $stmt->execute())) |
|
|
|
|
|
|
87
|
|
|
return false; |
|
|
|
|
|
|
88
|
|
|
$result = $stmt->get_result(); |
|
89
|
|
|
} else { |
|
90
|
|
|
if (!($this->checkStmt($stmt) && $stmt->execute())) |
|
91
|
|
|
return false; |
|
|
|
|
|
|
92
|
|
|
$result = $stmt->get_result(); |
|
93
|
|
|
} |
|
94
|
|
|
if ($result) { |
|
95
|
|
|
$aData = NULL; |
|
96
|
|
|
while ($row = $result->fetch_assoc()) { |
|
97
|
|
|
$aData[$row['type']] = $row['total']; |
|
98
|
|
|
} |
|
99
|
|
|
// Cache data for a while, query takes long on many rows |
|
100
|
|
|
return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData, 60); |
|
101
|
|
|
} |
|
102
|
|
|
return $this->sqlError(); |
|
|
|
|
|
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
|
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* Fetch a transaction summary by user with total amounts |
|
108
|
|
|
* @param account_id int Account ID, NULL for all |
|
109
|
|
|
* @return data array type and total |
|
110
|
|
|
**/ |
|
111
|
|
View Code Duplication |
public function getTransactionTypebyTime($account_id=NULL) { |
|
|
|
|
|
|
112
|
|
|
$this->debug->append("STA " . __METHOD__, 4); |
|
113
|
|
|
if ($data = $this->memcache->get(__FUNCTION__)) return $data; |
|
114
|
|
|
$stmt = $this->mysqli->prepare(" |
|
115
|
|
|
SELECT |
|
116
|
|
|
IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourCredit, |
|
117
|
|
|
IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourBonus, |
|
118
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDebitMP, |
|
119
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDebitAP, |
|
120
|
|
|
IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourTXFee, |
|
121
|
|
|
IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourFee, |
|
122
|
|
|
IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDonation, |
|
123
|
|
|
|
|
124
|
|
|
IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourCredit, |
|
125
|
|
|
IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourBonus, |
|
126
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDebitMP, |
|
127
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDebitAP, |
|
128
|
|
|
IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourTXFee, |
|
129
|
|
|
IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourFee, |
|
130
|
|
|
IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDonation, |
|
131
|
|
|
|
|
132
|
|
|
IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekCredit, |
|
133
|
|
|
IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekBonus, |
|
134
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDebitMP, |
|
135
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDebitAP, |
|
136
|
|
|
IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekTXFee, |
|
137
|
|
|
IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekFee, |
|
138
|
|
|
IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDonation, |
|
139
|
|
|
|
|
140
|
|
|
IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthCredit, |
|
141
|
|
|
IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthBonus, |
|
142
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDebitMP, |
|
143
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDebitAP, |
|
144
|
|
|
IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthTXFee, |
|
145
|
|
|
IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthFee, |
|
146
|
|
|
IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDonation, |
|
147
|
|
|
|
|
148
|
|
|
IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearCredit, |
|
149
|
|
|
IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearBonus, |
|
150
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDebitMP, |
|
151
|
|
|
IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDebitAP, |
|
152
|
|
|
IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearTXFee, |
|
153
|
|
|
IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearFee, |
|
154
|
|
|
IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDonation |
|
155
|
|
|
FROM $this->table AS t |
|
156
|
|
|
LEFT OUTER JOIN " . $this->block->getTableName() . " AS b ON b.id = t.block_id |
|
157
|
|
|
WHERE |
|
158
|
|
|
t.account_id = ? AND (b.confirmations > 0 OR b.id IS NULL)"); |
|
159
|
|
|
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result()) |
|
160
|
|
|
return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc(), 60); |
|
161
|
|
|
return $this->sqlError(); |
|
|
|
|
|
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* Get all transactions from start for account_id |
|
166
|
|
|
* @param start int Starting point, id of transaction |
|
167
|
|
|
* @param filter array Filter to limit transactions |
|
168
|
|
|
* @param limit int Only display this many transactions |
|
169
|
|
|
* @param account_id int Account ID |
|
170
|
|
|
* @return data array Database fields as defined in SELECT |
|
171
|
|
|
**/ |
|
172
|
|
|
public function getTransactions($start=0, $filter=NULL, $limit=30, $account_id=NULL) { |
|
173
|
|
|
$this->debug->append("STA " . __METHOD__, 4); |
|
174
|
|
|
$sql = " |
|
175
|
|
|
SELECT |
|
176
|
|
|
t.id AS id, |
|
177
|
|
|
a.username as username, |
|
178
|
|
|
t.type AS type, |
|
179
|
|
|
t.amount AS amount, |
|
180
|
|
|
t.coin_address AS coin_address, |
|
181
|
|
|
t.timestamp AS timestamp, |
|
182
|
|
|
t.txid AS txid, |
|
183
|
|
|
b.height AS height, |
|
184
|
|
|
b.blockhash AS blockhash, |
|
185
|
|
|
b.confirmations AS confirmations |
|
186
|
|
|
FROM $this->table AS t |
|
187
|
|
|
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id |
|
188
|
|
|
LEFT JOIN " . $this->user->getTableName() . " AS a ON t.account_id = a.id"; |
|
|
|
|
|
|
189
|
|
|
if (!empty($account_id)) { |
|
190
|
|
|
$sql .= " WHERE ( t.account_id = ? ) "; |
|
191
|
|
|
$this->addParam('i', $account_id); |
|
192
|
|
|
} |
|
193
|
|
|
if (is_array($filter)) { |
|
194
|
|
|
$aFilter = array(); |
|
195
|
|
|
foreach ($filter as $key => $value) { |
|
196
|
|
|
if (!empty($value)) { |
|
197
|
|
|
switch ($key) { |
|
198
|
|
|
case 'type': |
|
199
|
|
|
$aFilter[] = "( t.type = ? )"; |
|
200
|
|
|
$this->addParam('s', $value); |
|
201
|
|
|
break; |
|
202
|
|
|
case 'status': |
|
203
|
|
|
switch ($value) { |
|
204
|
|
|
case 'Confirmed': |
|
205
|
|
|
if (empty($filter['type']) || ($filter['type'] != 'Debit_AP' && $filter['type'] != 'Debit_MP' && $filter['type'] != 'TXFee' && $filter['type'] != 'Credit_PPS' && $filter['type'] != 'Fee_PPS' && $filter['type'] != 'Donation_PPS')) { |
|
206
|
|
|
$aFilter[] = "( b.confirmations >= " . $this->config['confirmations'] . " OR ISNULL(b.confirmations) )"; |
|
207
|
|
|
} |
|
208
|
|
|
break; |
|
209
|
|
|
case 'Unconfirmed': |
|
210
|
|
|
$aFilter[] = "( b.confirmations < " . $this->config['confirmations'] . " AND b.confirmations >= 0 )"; |
|
211
|
|
|
break; |
|
212
|
|
|
case 'Orphan': |
|
213
|
|
|
$aFilter[] = "( b.confirmations = -1 )"; |
|
214
|
|
|
break; |
|
215
|
|
|
} |
|
216
|
|
|
break; |
|
217
|
|
|
case 'account': |
|
218
|
|
|
$aFilter[] = "( LOWER(a.username) = LOWER(?) )"; |
|
219
|
|
|
$this->addParam('s', $value); |
|
220
|
|
|
break; |
|
221
|
|
|
case 'address': |
|
222
|
|
|
$aFilter[] = "( t.coin_address = ? )"; |
|
223
|
|
|
$this->addParam('s', $value); |
|
224
|
|
|
break; |
|
225
|
|
|
} |
|
226
|
|
|
} |
|
227
|
|
|
} |
|
228
|
|
|
if (!empty($aFilter)) { |
|
229
|
|
|
empty($account_id) ? $sql .= " WHERE " : $sql .= " AND "; |
|
230
|
|
|
$sql .= implode(' AND ', $aFilter); |
|
231
|
|
|
} |
|
232
|
|
|
} |
|
233
|
|
|
$sql .= " ORDER BY id DESC LIMIT ?,?"; |
|
234
|
|
|
// Add some other params to query |
|
235
|
|
|
$this->addParam('i', $start); |
|
236
|
|
|
$this->addParam('i', $limit); |
|
237
|
|
|
$stmt = $this->mysqli->prepare($sql); |
|
238
|
|
|
if ($this->checkStmt($stmt) && call_user_func_array( array($stmt, 'bind_param'), $this->getParam()) && $stmt->execute() && $result = $stmt->get_result()) |
|
239
|
|
|
return $result->fetch_all(MYSQLI_ASSOC); |
|
240
|
|
|
return $this->sqlError(); |
|
|
|
|
|
|
241
|
|
|
} |
|
242
|
|
|
|
|
243
|
|
|
/** |
|
244
|
|
|
* Get all different transaction types |
|
245
|
|
|
* @return mixed array/bool Return types on succes, false on failure |
|
246
|
|
|
**/ |
|
247
|
|
|
public function getTypes() { |
|
248
|
|
|
$stmt = $this->mysqli->prepare("SELECT DISTINCT type FROM $this->table"); |
|
249
|
|
View Code Duplication |
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { |
|
|
|
|
|
|
250
|
|
|
$aData = array('' => ''); |
|
251
|
|
|
while ($row = $result->fetch_assoc()) { |
|
252
|
|
|
$aData[$row['type']] = $row['type']; |
|
253
|
|
|
} |
|
254
|
|
|
return $aData; |
|
255
|
|
|
} |
|
256
|
|
|
return $this->sqlError(); |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
/** |
|
260
|
|
|
* Get all donation transactions |
|
261
|
|
|
* Used on donors page |
|
262
|
|
|
* return data array Donors and amounts |
|
263
|
|
|
**/ |
|
264
|
|
|
public function getDonations() { |
|
265
|
|
|
$this->debug->append("STA " . __METHOD__, 4); |
|
266
|
|
|
$stmt = $this->mysqli->prepare(" |
|
267
|
|
|
SELECT |
|
268
|
|
|
SUM(t.amount) AS donation, |
|
269
|
|
|
a.username AS username, |
|
270
|
|
|
a.is_anonymous AS is_anonymous, |
|
271
|
|
|
ROUND(a.donate_percent, 2) AS donate_percent |
|
272
|
|
|
FROM $this->table AS t |
|
273
|
|
|
LEFT JOIN " . $this->user->getTableName() . " AS a |
|
274
|
|
|
ON t.account_id = a.id |
|
275
|
|
|
LEFT JOIN " . $this->block->getTableName() . " AS b |
|
276
|
|
|
ON t.block_id = b.id |
|
277
|
|
|
WHERE |
|
278
|
|
|
( |
|
279
|
|
|
( t.type = 'Donation' AND b.confirmations >= " . $this->config['confirmations'] . " ) OR |
|
280
|
|
|
t.type = 'Donation_PPS' |
|
281
|
|
|
) |
|
282
|
|
|
GROUP BY a.username |
|
283
|
|
|
ORDER BY donation DESC |
|
284
|
|
|
"); |
|
285
|
|
|
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) |
|
286
|
|
|
return $result->fetch_all(MYSQLI_ASSOC); |
|
287
|
|
|
return $this->sqlError(); |
|
288
|
|
|
} |
|
289
|
|
|
|
|
290
|
|
|
/** |
|
291
|
|
|
* Get total balance for all users locked in wallet |
|
292
|
|
|
* This includes any outstanding unconfirmed transactions! |
|
293
|
|
|
* @param none |
|
294
|
|
|
* @return data double Amount locked for users |
|
295
|
|
|
**/ |
|
296
|
|
|
public function getLockedBalance() { |
|
297
|
|
|
$this->debug->append("STA " . __METHOD__, 4); |
|
298
|
|
|
$stmt = $this->mysqli->prepare(" |
|
299
|
|
|
SELECT |
|
300
|
|
|
( |
|
301
|
|
|
SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR t.type = 'Credit_PPS', t.amount, 0 ) ) - |
|
302
|
|
|
SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - |
|
303
|
|
|
SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) |
|
304
|
|
|
) AS balance |
|
305
|
|
|
FROM $this->table AS t |
|
306
|
|
|
LEFT JOIN " . $this->block->getTableName() . " AS b |
|
307
|
|
|
ON t.block_id = b.id |
|
308
|
|
|
WHERE archived = 0"); |
|
309
|
|
View Code Duplication |
if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $this->config['confirmations'], $this->config['confirmations']) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch()) |
|
|
|
|
|
|
310
|
|
|
return $dBalance; |
|
|
|
|
|
|
311
|
|
|
return $this->sqlError(); |
|
|
|
|
|
|
312
|
|
|
} |
|
313
|
|
|
|
|
314
|
|
|
/** |
|
315
|
|
|
* Get an accounts total balance, ignore archived entries |
|
316
|
|
|
* @param account_id int Account ID |
|
317
|
|
|
* @return data float Credit - Debit - Fees - Donation |
|
318
|
|
|
**/ |
|
319
|
|
|
public function getBalance($account_id) { |
|
320
|
|
|
$this->debug->append("STA " . __METHOD__, 4); |
|
321
|
|
|
$stmt = $this->mysqli->prepare(" |
|
322
|
|
|
SELECT |
|
323
|
|
|
IFNULL(( |
|
324
|
|
|
SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR t.type = 'Credit_PPS', t.amount, 0 ) ) - |
|
325
|
|
|
SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - |
|
326
|
|
|
SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) |
|
327
|
|
|
), 0) AS confirmed, |
|
328
|
|
|
IFNULL(( |
|
329
|
|
|
SUM( IF( t.type IN ('Credit','Bonus') AND b.confirmations < ? AND b.confirmations >= 0, t.amount, 0 ) ) - |
|
330
|
|
|
SUM( IF( t.type IN ('Donation','Fee') AND b.confirmations < ? AND b.confirmations >= 0, t.amount, 0 ) ) |
|
331
|
|
|
), 0) AS unconfirmed, |
|
332
|
|
|
IFNULL(( |
|
333
|
|
|
SUM( IF( t.type IN ('Credit','Bonus') AND b.confirmations = -1, t.amount, 0) ) - |
|
334
|
|
|
SUM( IF( t.type IN ('Donation','Fee') AND b.confirmations = -1, t.amount, 0) ) |
|
335
|
|
|
), 0) AS orphaned |
|
336
|
|
|
FROM $this->table AS t |
|
337
|
|
|
LEFT JOIN " . $this->block->getTableName() . " AS b |
|
338
|
|
|
ON t.block_id = b.id |
|
339
|
|
|
WHERE t.account_id = ? |
|
340
|
|
|
AND archived = 0 |
|
341
|
|
|
"); |
|
342
|
|
|
if ($this->checkStmt($stmt) && $stmt->bind_param("iiiii", $this->config['confirmations'], $this->config['confirmations'], $this->config['confirmations'], $this->config['confirmations'], $account_id) && $stmt->execute() && $result = $stmt->get_result()) |
|
343
|
|
|
return $result->fetch_assoc(); |
|
344
|
|
|
return $this->sqlError(); |
|
|
|
|
|
|
345
|
|
|
} |
|
346
|
|
|
|
|
347
|
|
|
/** |
|
348
|
|
|
* Get our Auto Payout queue |
|
349
|
|
|
* @param none |
|
350
|
|
|
* @return data array Account settings and confirmed balances |
|
351
|
|
|
**/ |
|
352
|
|
|
public function getAPQueue($limit=250) { |
|
353
|
|
|
$this->debug->append("STA " . __METHOD__, 4); |
|
354
|
|
|
$stmt = $this->mysqli->prepare(" |
|
355
|
|
|
SELECT |
|
356
|
|
|
a.id, |
|
357
|
|
|
a.username, |
|
358
|
|
|
ca.ap_threshold, |
|
359
|
|
|
ca.coin_address, |
|
360
|
|
|
IFNULL( |
|
361
|
|
|
( |
|
362
|
|
|
SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= " . $this->config['confirmations'] . ") OR t.type = 'Credit_PPS', t.amount, 0 ) ) - |
|
363
|
|
|
SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - |
|
364
|
|
|
SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= " . $this->config['confirmations'] . ") OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) |
|
365
|
|
|
), 0 |
|
366
|
|
|
) AS confirmed |
|
367
|
|
|
FROM $this->table AS t |
|
368
|
|
|
LEFT JOIN " . $this->block->getTableName() . " AS b |
|
369
|
|
|
ON t.block_id = b.id |
|
370
|
|
|
LEFT JOIN " . $this->user->getTableName() . " AS a |
|
371
|
|
|
ON t.account_id = a.id |
|
372
|
|
|
LEFT JOIN " . $this->coin_address->getTableName() . " AS ca |
|
|
|
|
|
|
373
|
|
|
ON ca.account_id = a.id |
|
374
|
|
|
WHERE t.archived = 0 AND ca.ap_threshold > 0 AND ca.coin_address IS NOT NULL AND ca.coin_address != '' AND ca.currency = ? |
|
375
|
|
|
GROUP BY t.account_id |
|
376
|
|
|
HAVING confirmed > ca.ap_threshold AND confirmed > " . $this->config['txfee_auto'] . " |
|
377
|
|
|
LIMIT ?"); |
|
378
|
|
View Code Duplication |
if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result()) |
|
|
|
|
|
|
379
|
|
|
return $result->fetch_all(MYSQLI_ASSOC); |
|
380
|
|
|
return $this->sqlError(); |
|
|
|
|
|
|
381
|
|
|
} |
|
382
|
|
|
|
|
383
|
|
|
|
|
384
|
|
|
/** |
|
385
|
|
|
* Debit a user account |
|
386
|
|
|
* @param account_id int Account ID |
|
387
|
|
|
* @param coin_address string Coin Address |
|
388
|
|
|
* @param amount float Balance to record |
|
389
|
|
|
* @return int Debit transaction ID or false |
|
390
|
|
|
**/ |
|
391
|
|
|
public function createDebitMPRecord($account_id, $coin_address, $amount) { |
|
392
|
|
|
return $this->createDebitRecord($account_id, $coin_address, $amount, 'Debit_MP'); |
|
393
|
|
|
} |
|
394
|
|
|
public function createDebitAPRecord($account_id, $coin_address, $amount) { |
|
395
|
|
|
return $this->createDebitRecord($account_id, $coin_address, $amount, 'Debit_AP'); |
|
396
|
|
|
} |
|
397
|
|
|
private function createDebitRecord($account_id, $coin_address, $amount, $type) { |
|
398
|
|
|
// Calculate and deduct txfee from amount |
|
399
|
|
|
$type == 'Debit_MP' ? $txfee = $this->config['txfee_manual'] : $txfee = $this->config['txfee_auto']; |
|
400
|
|
|
$amount = $amount - $txfee; |
|
401
|
|
|
// Add Debit record |
|
402
|
|
View Code Duplication |
if (!$this->addTransaction($account_id, $amount, $type, NULL, $coin_address, NULL)) { |
|
|
|
|
|
|
403
|
|
|
$this->setErrorMessage('Failed to create ' . $type . ' transaction record in database'); |
|
404
|
|
|
return false; |
|
405
|
|
|
} |
|
406
|
|
|
// Fetch the inserted record ID so we can return this at the end |
|
407
|
|
|
$transaction_id = $this->insert_id; |
|
408
|
|
|
// Add TXFee record |
|
409
|
|
View Code Duplication |
if ($txfee > 0) { |
|
|
|
|
|
|
410
|
|
|
if (!$this->addTransaction($account_id, $txfee, 'TXFee', NULL, $coin_address)) { |
|
411
|
|
|
$this->setErrorMessage('Failed to create TXFee transaction record in database: ' . $this->getError()); |
|
412
|
|
|
return false; |
|
413
|
|
|
} |
|
414
|
|
|
} |
|
415
|
|
|
// Mark transactions archived |
|
416
|
|
|
if (!$this->setArchived($account_id, $this->insert_id)) { |
|
417
|
|
|
$this->setErrorMessage('Failed to mark transactions <= #' . $this->insert_id . ' as archived. ERROR: ' . $this->getError()); |
|
418
|
|
|
return false; |
|
419
|
|
|
} |
|
420
|
|
|
// Recheck the users balance to make sure it is now 0 |
|
421
|
|
|
if (!$aBalance = $this->getBalance($account_id)) { |
|
422
|
|
|
$this->setErrorMessage('Failed to fetch balance for account ' . $account_id . '. ERROR: ' . $this->getCronError()); |
|
423
|
|
|
return false; |
|
424
|
|
|
} |
|
425
|
|
|
if ($aBalance['confirmed'] > 0) { |
|
426
|
|
|
$this->setErrorMessage('User has a remaining balance of ' . $aBalance['confirmed'] . ' after a successful payout!'); |
|
427
|
|
|
return false; |
|
428
|
|
|
} |
|
429
|
|
|
// Notify user via mail |
|
430
|
|
|
$aMailData['email'] = $this->user->getUserEmailById($account_id); |
|
|
|
|
|
|
431
|
|
|
$aMailData['subject'] = $type . ' Completed'; |
|
432
|
|
|
$aMailData['amount'] = $amount; |
|
433
|
|
|
$aMailData['currency'] = $this->config['currency']; |
|
434
|
|
|
if (!$this->notification->sendNotification($account_id, 'payout', $aMailData)) { |
|
435
|
|
|
$this->setErrorMessage('Failed to send notification email to users address: ' . $aMailData['email'] . 'ERROR: ' . $this->notification->getCronError()); |
|
|
|
|
|
|
436
|
|
|
} |
|
437
|
|
|
return $transaction_id; |
|
438
|
|
|
} |
|
439
|
|
|
|
|
440
|
|
|
/** |
|
441
|
|
|
* Get all new, unprocessed manual payout requests |
|
442
|
|
|
* @param none |
|
443
|
|
|
* @return data Associative array with DB Fields |
|
444
|
|
|
**/ |
|
445
|
|
|
public function getMPQueue($limit=250) { |
|
446
|
|
|
$stmt = $this->mysqli->prepare(" |
|
447
|
|
|
SELECT |
|
448
|
|
|
a.id, |
|
449
|
|
|
a.username, |
|
450
|
|
|
ca.ap_threshold, |
|
451
|
|
|
ca.coin_address, |
|
452
|
|
|
p.id AS payout_id, |
|
453
|
|
|
IFNULL( |
|
454
|
|
|
( |
|
455
|
|
|
SUM( IF( ( t.type IN ('Credit','Bonus') AND b.confirmations >= " . $this->config['confirmations'] . ") OR t.type = 'Credit_PPS', t.amount, 0 ) ) - |
|
456
|
|
|
SUM( IF( t.type IN ('Debit_MP', 'Debit_AP'), t.amount, 0 ) ) - |
|
457
|
|
|
SUM( IF( ( t.type IN ('Donation','Fee') AND b.confirmations >= " . $this->config['confirmations'] . ") OR ( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') ), t.amount, 0 ) ) |
|
458
|
|
|
), 0 |
|
459
|
|
|
) AS confirmed |
|
460
|
|
|
FROM " . $this->payout->getTableName() . " AS p |
|
|
|
|
|
|
461
|
|
|
JOIN " . $this->user->getTableName() . " AS a |
|
462
|
|
|
ON p.account_id = a.id |
|
463
|
|
|
JOIN " . $this->getTableName() . " AS t |
|
464
|
|
|
ON t.account_id = p.account_id |
|
465
|
|
|
LEFT JOIN " . $this->block->getTableName() . " AS b |
|
466
|
|
|
ON t.block_id = b.id |
|
467
|
|
|
LEFT JOIN " . $this->coin_address->getTableName() . " AS ca |
|
468
|
|
|
ON ca.account_id = a.id |
|
469
|
|
|
WHERE p.completed = 0 AND t.archived = 0 AND ca.currency = ? AND ca.coin_address IS NOT NULL AND ca.coin_address != '' |
|
470
|
|
|
GROUP BY t.account_id |
|
471
|
|
|
HAVING confirmed > " . $this->config['txfee_manual'] . " |
|
472
|
|
|
LIMIT ?"); |
|
473
|
|
View Code Duplication |
if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result()) |
|
|
|
|
|
|
474
|
|
|
return $result->fetch_all(MYSQLI_ASSOC); |
|
475
|
|
|
return $this->sqlError('E0050'); |
|
|
|
|
|
|
476
|
|
|
} |
|
477
|
|
|
} |
|
478
|
|
|
|
|
479
|
|
|
$transaction = new Transaction(); |
|
480
|
|
|
$transaction->setMemcache($memcache); |
|
481
|
|
|
$transaction->setNotification($notification); |
|
482
|
|
|
$transaction->setSetting($setting); |
|
483
|
|
|
$transaction->setDebug($debug); |
|
484
|
|
|
$transaction->setCoin($coin); |
|
485
|
|
|
$transaction->setCoinAddress($coin_address); |
|
486
|
|
|
$transaction->setMysql($mysqli); |
|
487
|
|
|
$transaction->setConfig($config); |
|
488
|
|
|
$transaction->setBlock($block); |
|
489
|
|
|
$transaction->setUser($user); |
|
490
|
|
|
$transaction->setPayout($oPayout); |
|
491
|
|
|
$transaction->setErrorCodes($aErrorCodes); |
|
492
|
|
|
|
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: