get_unpaid_payment_records(); foreach ($records as $record) { $address = $record['address']; $orderAmount = $record['order_amount']; $orderId = $record['order_id']; $txHash = AGC_Blockchain::verify_exact_ether_transaction_amount($address, $orderAmount, $requiredConfirmations); // if matching transaction was found if ($txHash !== '' && AGC_tx_hash_valid($txHash)) { // complete order $order = new WC_Order($orderId); $orderNote = sprintf( 'Order payment of %s %s verified at %s.', AGC_Cryptocurrencies::get_price_string('ETH', $orderAmount), 'ETH', date('Y-m-d H:i:s', time())); $order->update_status('wc-processing', $orderNote); AGC_Util::log(__FILE__, __LINE__, 'completed order #' . $orderId); $repo->set_payment_status($orderId, $orderAmount, 'paid'); } else { AGC_Util::log(__FILE__, __LINE__, 'did not find valid transaction for order #' . $orderId); } } } function AGC_tx_hash_valid($txHash) { return strlen($txHash) > 30; } function AGC_buffer_electrum_ready_addresses($cryptoId, $mpk, $amount) { $repo = new AGC_MPK_Repo($cryptoId, $mpk); $readyCount = $repo->count_ready_addresses($mpk); $neededAddresses = $amount - $readyCount; for ($i = 0; $i < $neededAddresses; $i++) { try { AGC_Util::force_new_electrum_address($cryptoId, $mpk); } catch ( \Exception $e ) { AGC_Util::log(__FILE__, __LINE__, $e->getMessage()); } } } function AGC_check_for_cancelled_orders($cryptoId, $mpk, $orderCancellationTime) { global $woocommerce; $repo = new AGC_MPK_Repo($cryptoId, $mpk); $assignedRecords = $repo->get_assigned_electrum_address_records(); foreach ($assignedRecords as $record) { $assignedAt = $record['assigned_at']; $totalReceived = $record['total_received']; $address = $record['address']; $orderId = $record['order_id']; $assignedFor = time() - $assignedAt; AGC_Util::log(__FILE__, __LINE__, 'address ' . $address . ' has been assigned for ' . $assignedFor . '... cancel time: ' . $orderCancellationTime); if ($assignedFor > $orderCancellationTime && $totalReceived == 0) { // since order was cancelled we can re-use the address, set status to ready $repo->set_address_status($address, 'ready'); $repo->set_address_order_amount($address, 0.0); $order = new WC_Order($orderId); $orderNote = sprintf( 'Your order was cancelled because you were unable to pay for %s minutes. Please do not send any funds to the payment address.', round($orderCancellationTime/60, 0), $address); add_filter('woocommerce_email_subject_customer_note', 'AGC_change_cancelled_email_note_subject_line', 1, 2); add_filter('woocommerce_email_heading_customer_note', 'AGC_change_cancelled_email_heading', 1, 2); // this will send the email to customer $order->add_order_note($orderNote, true); $order->update_status('wc-cancelled'); AGC_Util::log(__FILE__, __LINE__, 'Cancelled order: ' . $orderId . ' which was using address: ' . $address . 'due to non-payment.'); } } } function AGC_check_orders_for_payment($cryptoId, $mpk, $requiredConfirmations, $percentToVerify) { global $woocommerce; $repo = new AGC_MPK_Repo($cryptoId, $mpk); $pendingRecords = $repo->get_pending_electrum_address_records(); foreach ($pendingRecords as $record) { try { $blockchainTotalReceived = AGC_Blockchain::get_total_received_for_address($cryptoId, $record['address'], $requiredConfirmations); } catch ( \Exception $e ) { // just go to next record if the endpoint is not responding continue; } $recordTotalReceived = $record['total_received']; $newPaymentAmount = $blockchainTotalReceived - $recordTotalReceived; // if we received a new payment if ($newPaymentAmount > 0.0000001) { $address = $record['address']; $orderAmount = $record['order_amount']; AGC_Util::log(__FILE__, __LINE__, 'Address ' . $address . ' received a new payment of ' . AGC_Cryptocurrencies::get_price_string($cryptoId, $newPaymentAmount) . ' ' . $cryptoId); // set total in database because we received a payment $repo->set_address_total_received($address, $blockchainTotalReceived); $amountToVerify = ((float) $orderAmount) * $percentToVerify; $paymentAmountVerified = $blockchainTotalReceived >= $amountToVerify; // if new total is enough to process the order if ($paymentAmountVerified) { $order_id = $record['order_id']; $order = new WC_Order( $order_id ); $orderNote = sprintf( 'Order payment of %s %s verified at %s.', AGC_Cryptocurrencies::get_price_string($cryptoId, $blockchainTotalReceived), $cryptoId, date('Y-m-d H:i:s', time())); $order->update_status('wc-processing', $orderNote); //$order->payment_complete(); $repo->set_address_status($address, 'complete'); } // we received payment but it was not enough to meet store admin's processing requirement else { $order_id = $record['order_id']; $order = new WC_Order( $order_id ); // handle multiple underpayments, just add a new note if ($record['status'] === 'underpaid') { $orderNote = sprintf( 'New payment was received but is still under order total. Received payment of %s %s. Remaining payment required: %s Wallet Address: %s', AGC_Cryptocurrencies::get_price_string($cryptoId, $newPaymentAmount), $cryptoId, AGC_Cryptocurrencies::get_price_string($cryptoId, $amountToVerify - $blockchainTotalReceived), $address); add_filter('woocommerce_email_subject_customer_note', 'AGC_change_partial_email_note_subject_line', 1, 2); add_filter('woocommerce_email_heading_customer_note', 'AGC_change_partial_email_heading', 1, 2); $order->add_order_note($orderNote, true); } // handle first underpayment, update status to pending payment (since we use on-hold for orders with no payment yet) else { $orderNote = sprintf( 'Payment of %s %s received at %s. This is under the amount required to process this order. Remaining payment required: %s Wallet Address: %s', AGC_Cryptocurrencies::get_price_string($cryptoId, $blockchainTotalReceived), $cryptoId, date('Y-m-d H:i:s', time()), AGC_Cryptocurrencies::get_price_string($cryptoId, $amountToVerify - $blockchainTotalReceived), $address); add_filter('woocommerce_email_subject_customer_note', 'AGC_change_partial_email_note_subject_line', 1, 2); add_filter('woocommerce_email_heading_customer_note', 'AGC_change_partial_email_heading', 1, 2); $order->add_order_note($orderNote, true); $repo->set_address_status($address, 'underpaid'); } } } } } function AGC_get_time_passed($startTime) { return time() - $startTime; } ?>