/** * Converted to WP 2.0 * Archives an invoice, or multiple invoices. * * @global type $wpdb * * @param type $invoice_id * * @return type */ function wpi_archive_invoice($invoice_id) { //** Check to see if array is passed or single. */ if (is_array($invoice_id)) { $counter = 0; foreach ($invoice_id as $single_invoice_id) { $this_invoice = new WPI_Invoice(); $this_invoice->load_invoice("id={$single_invoice_id}"); $this_invoice->set("status=archive"); $this_invoice->add_entry(__("Archived.", WPI)); if ($this_invoice->save_invoice()) { $counter++; } } return __("{$counter} invoice(s) archived.", WPI); } else { $this_invoice = new WPI_Invoice(); $this_invoice->load_invoice("id={$invoice_id}"); $this_invoice->set("status=archive"); $this_invoice->add_entry(__("Archived.", WPI)); if ($this_invoice->save_invoice()) { return __('Successfully archived.', WPI); } } }
/** Converted to WP 2.0 Archives an invoice, or multiple invoices. */ function wpi_archive_invoice($invoice_id) { global $wpdb; // Check to see if array is passed or single. if(is_array($invoice_id)) { $counter=0; foreach ($invoice_id as $single_invoice_id) { $this_invoice = new WPI_Invoice(); $this_invoice->load_invoice("id=$single_invoice_id"); $this_invoice->set("status=archive"); $this_invoice->add_entry(__("Archived.", WPI)); if($this_invoice->save_invoice()) $counter++; } return __("$counter invoice(s) archived.", WPI); } else { $this_invoice = new WPI_Invoice(); $this_invoice->load_invoice("id=$invoice_id"); $this_invoice->set("status=archive"); $this_invoice->add_entry(__("Archived.", WPI)); if($this_invoice->save_invoice()) return __('Successfully archived.', WPI); } }
/** * Revalidate all the invoices * * @author korotkov@ud * @global object $wpdb */ function total_revalidate() { global $wpdb; /** Recalculate all invoices */ $invoices = $wpdb->get_col(" SELECT ID FROM {$wpdb->posts} WHERE post_type = 'wpi_object' "); foreach ($invoices as $post_id) { $invoice_id = wpi_post_id_to_invoice_id($post_id); $this_invoice = new WPI_Invoice(); $this_invoice->load_invoice("id={$invoice_id}"); $this_invoice->save_invoice(); } }
/** * */ static function server_callback() { global $wpdb; //** Get request body */ $body = @file_get_contents('php://input'); $event_object = json_decode($body); switch ($event_object->type) { //** Used only for subscriptions since single payments processed without Webhook */ case 'charge.succeeded': $post_id = $wpdb->get_col("SELECT post_id\r\n FROM {$wpdb->postmeta}\r\n WHERE meta_key = '_stripe_customer_id'\r\n AND meta_value = '{$event_object->data->object->customer}'"); $invoice_object = new WPI_Invoice(); $invoice_object->load_invoice("id=" . $post_id[0]); if (empty($invoice_object->data['ID'])) { die("Can't load invoice"); } if (!class_exists('Stripe')) { require_once WPI_Path . '/third-party/stripe/lib/Stripe.php'; } $pk = trim($invoice_object->data['billing']['wpi_stripe']['settings'][$invoice_object->data['billing']['wpi_stripe']['settings']['mode']['value'] . '_secret_key']['value']); Stripe::setApiKey($pk); $event = Stripe_Event::retrieve($event_object->id); if ($event->data->object->paid == 1) { $event_amount = (double) ($event->data->object->amount / 100); $event_note = WPI_Functions::currency_format(abs($event_amount), $invoice_object->data['invoice_id']) . ' ' . __('Stripe Subscription Payment', WPI); $event_type = 'add_payment'; $invoice_object->add_entry("attribute=balance¬e={$event_note}&amount={$event_amount}&type={$event_type}"); $invoice_object->save_invoice(); } break; case 'customer.subscription.deleted': $post_id = $wpdb->get_col("SELECT post_id\r\n FROM {$wpdb->postmeta}\r\n WHERE meta_key = '_stripe_customer_id'\r\n AND meta_value = '{$event_object->data->object->customer}'"); $invoice_object = new WPI_Invoice(); $invoice_object->load_invoice("id=" . $post_id[0]); if (empty($invoice_object->data['ID'])) { die("Can't load invoice"); } if (!class_exists('Stripe')) { require_once WPI_Path . '/third-party/stripe/lib/Stripe.php'; } $pk = trim($invoice_object->data['billing']['wpi_stripe']['settings'][$invoice_object->data['billing']['wpi_stripe']['settings']['mode']['value'] . '_secret_key']['value']); Stripe::setApiKey($pk); $event = Stripe_Event::retrieve($event_object->id); if ($event->data->object->status == 'canceled') { $invoice_object->add_entry("attribute=invoice¬e=" . __('Stripe Subscription has been canceled', WPI) . "&type=update"); $invoice_object->save_invoice(); wp_invoice_mark_as_paid($invoice_object->data['invoice_id']); } break; default: break; } }
/** * Run import process * * @global object $wpdb * @global array $wpi_settings */ function do_import() { global $wpdb, $wpi_settings; /* Get plugin Singleton object */ $core = WPI_Core::getInstance(); /* Try to import General Plugin Settings from old version */ $legacy_settings = self::get_legacy_settings(); if (!empty($legacy_settings)) { $core->Settings->SaveSettings($legacy_settings); $core->Functions->log(__("Web Invoice setting options were successfully imported.", WPI)); } /* Boolean variables which show 'legacy logs' data migration's status */ $legacy_logs = false; $legacy_logs_import_error = false; /* Try to import Invoices from Web Invoice plugin */ $legacy_invoices = self::get_legacy_invoices(); if (is_array($legacy_invoices) && !empty($legacy_invoices)) { $errors = false; foreach ($legacy_invoices as $i) { $invoice_id = $core->Functions->save_invoice($i, array('type' => 'import')); if ($invoice_id) { //* Try to get Logs of Invoices from the old version */ $logs = self::get_legacy_logs_by_id($invoice_id); if (!empty($logs)) { /* Imports logs to new table. */ if (self::import_logs($logs)) { $legacy_logs = true; } else { $legacy_logs_import_error = true; } } //* If invoice has 'paid' status we should add log of payment. */ if ($i['post_status'] == 'paid') { $invoice = new WPI_Invoice(); $invoice->load_invoice("id={$invoice_id}"); if ($i['recurring']['active'] == 'on' && !empty($i['recurring']['cycles'])) { $event_amount = $i['amount'] * $i['recurring']['cycles']; } else { $event_amount = $i['amount']; } $event_note = "Automatically created using Web Invoice log data"; $event_note = $core->Functions->currency_format(abs($event_amount), $invoice_id) . " paid in - {$event_note}"; $timestamp = time(); $invoice->add_entry("attribute=balance¬e={$event_note}&amount={$event_amount}&type=add_payment&time={$timestamp}"); $invoice->save_invoice(); } } else { $errors = true; } } if ($errors == true) { $core->Functions->log(__("Invoices from Web Invoice plugin were migrated with errors.", WPI)); } else { $core->Functions->log(__("Invoices from Web Invoice plugin were successfully migrated.", WPI)); } } if ($legacy_logs == true) { if ($legacy_logs_import_error == false) { $core->Functions->log(__("Log data from Web Invoice plugin were successfully migrated.", WPI)); } else { $core->Functions->log(__("Log data from Web Invoice plugin were migrated with errors.", WPI)); } } //* Mark as imported */ update_option('wpi_web_invoice_imported', 1); }
/** * Handler for Silent Post Url */ static function server_callback() { $arb = false; $fields = array(); foreach ($_REQUEST as $name => $value) { $fields[$name] = $value; if ($name == 'x_subscription_id') { $arb = true; } } // Handle recurring billing payments if ($arb == true && $fields['x_response_code'] == 1) { $paynum = $fields['x_subscription_paynum']; $subscription_id = $fields['x_subscription_id']; $amount = $fields['x_amount']; $invoice_id = wpi_post_id_to_invoice_id(wpi_subscription_id_to_post_id($subscription_id)); $invoice_obj = new WPI_Invoice(); $invoice_obj->load_invoice("id={$invoice_id}"); // Add payment amount $event_note = WPI_Functions::currency_format(abs($amount), $invoice_id) . ". ARB payment {$paynum} of {$invoice_obj->data['recurring']['wpi_authorize']['cycles']}"; $event_amount = $amount; $event_type = 'add_payment'; $invoice_obj->add_entry("attribute=balance¬e={$event_note}&amount={$event_amount}&type={$event_type}"); // Complete subscription if last payment done if ($invoice_obj->data['recurring']['wpi_authorize']['cycles'] <= $paynum) { WPI_Functions::log_event(wpi_invoice_id_to_post_id($invoice_id), 'invoice', 'update', '', __('Subscription completely paid', WPI)); wp_invoice_mark_as_paid($invoice_id); } $invoice_obj->save_invoice(); } }
/** * Update invoice by ID * * @global Array $wpi_settings * * @param Array $args * * @return WP_Error|WPI_Invoice */ function update_invoice($args = array()) { global $wpi_settings; //** Default arguments */ $defaults = array('ID' => false, 'subject' => false, 'description' => false, 'type' => false, 'deposit' => false, 'due_date' => false, 'tax' => false, 'tax_method' => false, 'recurring' => false, 'discount' => false, 'items' => array(), 'charges' => array()); //** Parse arguments */ extract($args = wp_parse_args($args, $defaults)); //** Check */ if (!$ID) { return new WP_Error('wp.invoice', __('Argument "ID" is required.', WPI), $args); } //** New Invoice object */ $invoice = new WPI_Invoice(); //** Load invoice by ID */ $invoice->load_invoice(array('id' => $ID)); $set = array(); //** Subject */ if ($subject) { $subject = trim($subject); if (!empty($subject)) { $set['subject'] = $subject; $set['post_title'] = $subject; } } //** Description */ if ($description) { $description = trim($description); if (!empty($description)) { $set['description'] = $description; } } if ($type) { //** If type is registered */ if (!array_key_exists($type, $wpi_settings['types'])) { return new WP_Error('wp.invoice', __('Unknown invoice type.', WPI), $args); } //** If recurring */ if ($type == 'recurring') { $recurring = array_filter($recurring); if (empty($recurring['unit']) || empty($recurring['cycles'])) { return new WP_Error('wp.invoice', __('Method requires correct "recurring" argument if "type" is recurring.', WPI), $args); } if (!empty($deposit)) { return new WP_Error('wp.invoice', __('Cannot use "deposit" with "recurring" type.', WPI), $args); } } //** If quote */ if ($type == 'quote') { if (!empty($deposit)) { return new WP_Error('wp.invoice', __('Cannot use "deposit" with "quote" type.', WPI), $args); } } $set['type'] = $type; //** If quote */ if ($type == 'quote') { $set['status'] = $type; $set['is_quote'] = 'true'; } //** Recurring */ if ($type == 'recurring') { $invoice->create_schedule($recurring); } } //** Partial payments */ if ($deposit) { $set['deposit_amount'] = (double) $deposit; } if ($due_date) { $set['due_date_year'] = $due_date['year']; $set['due_date_month'] = $due_date['month']; $set['due_date_day'] = $due_date['day']; } if ($tax) { $set['tax'] = $tax; } if ($tax_method) { if ($tax_method != 'before_discount' && $tax_method != 'after_discount') { return new WP_Error('wp.invoice', __('Unknown "tax_method".', WPI), $args); } $set['tax_method'] = $tax_method; } if ($discount) { if (empty($discount['name'])) { return new WP_Error('wp.invoice', __('Discount name is required.', WPI), $args); } if (empty($discount['type'])) { return new WP_Error('wp.invoice', __('Discount type is required. ("amount" or "percent").', WPI), $args); } if (empty($discount['amount'])) { return new WP_Error('wp.invoice', __('Discount amount is required.', WPI), $args); } $invoice->data['discount'] = array(); $invoice->add_discount($discount); } if ($items) { //** Items */ foreach ($items as $item) { //** Do not allow to save melformed items */ if (empty($item['name']) || empty($item['quantity']) || empty($item['price'])) { return new WP_Error('wp.invoice', __('One or more "items" have malformed structure. Cannot create Invoice.', WPI), $args); } //** Global tax has higher priority */ if (!empty($tax)) { $item['tax_rate'] = $tax; } //** Check types */ if (!is_numeric($item['quantity'])) { return new WP_Error('wp.invoice', __('One or more "items" have wrong "quantity" value. Cannot create Invoice.', WPI), $args); } if (!is_numeric($item['price'])) { return new WP_Error('wp.invoice', __('One or more "items" have wrong "price" value. Cannot create Invoice.', WPI), $args); } if (!empty($item['tax_rate'])) { if (!is_numeric($item['tax_rate'])) { return new WP_Error('wp.invoice', __('One or more "items" have wrong "tax_rate" value. Cannot create Invoice.', WPI), $args); } } } } if ($charges) { //** Charges */ foreach ($charges as $charge) { //** Do not allow to save melformed items */ if (empty($charge['name']) || empty($charge['amount'])) { return new WP_Error('wp.invoice', __('One or more "charges" have malformed structure. Cannot create Invoice.', WPI), $args); } //** Global tax has higher priority */ if (!empty($tax)) { $charge['tax'] = $tax; } //** Check types */ if (!is_numeric($charge['amount'])) { return new WP_Error('wp.invoice', __('One or more "charges" have wrong "amount" value. Cannot create Invoice.', WPI), $args); } if (!empty($charge['tax'])) { if (!is_numeric($charge['tax'])) { return new WP_Error('wp.invoice', __('One or more "charges" have wrong "tax" value. Cannot create Invoice.', WPI), $args); } } } } //** If passed validation - save item */ if ($charges) { $invoice->data['itemized_charges'] = array(); foreach ($charges as $charge) { $invoice->line_charge($charge); } } if ($items) { $invoice->data['itemized_list'] = array(); foreach ($items as $item) { $invoice->line_item($item); } } $invoice->set($set); $invoice->save_invoice(); $invoice = new WPI_Invoice(); //** Load invoice by ID */ $invoice->load_invoice(array('id' => $ID)); return $invoice; }
/** Process special invoice-related event */ function process_manual_event() { global $wpdb; $invoice_id = $_REQUEST['invoice_id']; $event_type = $_REQUEST['event_type']; $event_amount = $_REQUEST['event_amount']; $event_note = $_REQUEST['event_note']; $event_date = $_REQUEST['event_date']; $event_time = $_REQUEST['event_time']; $event_tax = $_REQUEST['event_tax']; $timestamp = strtotime( $event_date.' '.$event_time ); if(empty($event_note) || empty($event_amount) || !is_numeric($event_amount)) { die( json_encode( array('success' => 'false', 'message' => __('Please enter a note and numeric amount.', WPI)) ) ); } if($event_type == 'add_payment' && !empty($event_amount)) { $event_amount = $event_amount; $event_note = WPI_Functions::currency_format(abs($event_amount), $invoice_id)." " . __('paid in', WPI) . " - $event_note"; } if($event_type == 'add_charge' && !empty($event_amount)) { $name = $event_note; $event_note = "".WPI_Functions::currency_format($event_amount, $invoice_id)." " . __('charge added', WPI) . " - $event_note"; $core = WPI_Core::getInstance(); $charge_item = $core->Functions->add_itemized_charge( $invoice_id, $name, $event_amount, $event_tax ); } if($event_type == 'do_adjustment' && !empty($event_amount)) { $event_note = WPI_Functions::currency_format($event_amount, $invoice_id)." " . __('adjusted', WPI) . " - $event_note"; } $invoice = new WPI_Invoice(); $invoice->load_invoice("id=$invoice_id"); $insert_id = $invoice->add_entry("attribute=balance¬e=$event_note&amount=$event_amount&type=$event_type&time=$timestamp"); if($insert_id) { $response = array( 'success' => 'true', 'message' => sprintf(__('Event Added: %1s.', WPI), $event_note)); } else { $response = array( 'success' => 'false', 'message' => sprintf(__('Could not save entry in invoice log. %1s', WPI), '')); } $invoice->save_invoice(); if ( !empty( $charge_item ) && $event_type == 'add_charge' ) { $response['charge_item'] = $charge_item; } die( json_encode( $response ) ); }
/** * Process special invoice-related event */ static function process_manual_event() { $invoice_id = $_REQUEST['invoice_id']; $event_type = $_REQUEST['event_type']; $event_amount = $_REQUEST['event_amount']; $event_note = $_REQUEST['event_note']; $event_date = $_REQUEST['event_date']; $event_time = $_REQUEST['event_time']; $event_tax = $_REQUEST['event_tax']; $timestamp = strtotime($event_date . ' ' . $event_time) - get_option('gmt_offset') * 60 * 60; if (empty($event_note) || empty($event_amount) || !is_numeric($event_amount)) { die(json_encode(array('success' => 'false', 'message' => __('Please enter a note and numeric amount.', WPI)))); } switch ($event_type) { case WPI_EVENT_TYPE_ADD_PAYMENT: if (!empty($event_amount)) { $event_note = WPI_Functions::currency_format(abs($event_amount), $invoice_id) . " " . __('paid in', WPI) . " - {$event_note}"; } break; case WPI_EVENT_TYPE_ADD_CHARGE: if (!empty($event_amount)) { $name = $event_note; $event_note = WPI_Functions::currency_format($event_amount, $invoice_id) . " " . (!empty($event_tax) ? '+' . $event_tax . '%' : '') . " " . __('charge added', WPI) . " - {$event_note}"; $core = WPI_Core::getInstance(); $charge_item = $core->Functions->add_itemized_charge($invoice_id, $name, $event_amount, $event_tax); } break; case WPI_EVENT_TYPE_ADD_ADJUSTMENT: if (!empty($event_amount)) { $event_note = WPI_Functions::currency_format($event_amount, $invoice_id) . " " . __('adjusted', WPI) . " - {$event_note}"; } break; case WPI_EVENT_TYPE_ADD_REFUND: if (!empty($event_amount)) { $event_amount = abs((double) $event_amount); $event_note = WPI_Functions::currency_format($event_amount, $invoice_id) . " " . __('refunded', WPI) . " - {$event_note}"; } break; default: break; } $invoice = new WPI_Invoice(); $invoice->load_invoice("id={$invoice_id}"); $insert_id = $invoice->add_entry(array('attribute' => 'balance', 'note' => $event_note, 'amount' => $event_amount, 'type' => $event_type, 'time' => $timestamp)); if ($insert_id) { $response = array('success' => 'true', 'message' => sprintf(__('Event Added: %1s.', WPI), $event_note)); } else { $response = array('success' => 'false', 'message' => sprintf(__('Could not save entry in invoice log. %1s', WPI), '')); } $invoice->save_invoice(); if (!empty($charge_item) && $event_type == 'add_charge') { $response['charge_item'] = $charge_item; } die(json_encode($response)); }
/** * Handles saving and updating * Can also handle AJAX save/update function * * @param type $invoice * @param type $args * * @return boolean */ static function save_invoice($invoice, $args = '') { //** Set function additional params */ $defaults = array('type' => 'default'); extract(wp_parse_args($args, $defaults), EXTR_SKIP); if ($type != 'import') { if (!wp_verify_nonce($_REQUEST['nonce'], 'wpi-update-invoice')) { die('Security check'); } } //** Init New Invoice object from passed variables */ $ni = new WPI_Invoice(); //** ID */ $ni->set(array('ID' => $invoice['ID'])); //** invoice_id */ $ni->set(array('invoice_id' => $invoice['invoice_id'])); //** subject */ $ni->set(array('subject' => $invoice['subject'])); //** description */ $ni->set(array('description' => $invoice['description'])); //** deposit */ if ($invoice['deposit'] == 'on' || $invoice['deposit'] == 'true') { $ni->set(array('deposit_amount' => $invoice['deposit_amount'])); } else { $ni->set(array('deposit_amount' => 0)); } //** Due date */ $ni->set(array('due_date_year' => $invoice['due_date_year'])); $ni->set(array('due_date_month' => $invoice['due_date_month'])); $ni->set(array('due_date_day' => $invoice['due_date_day'])); //** Currency */ $ni->set(array('default_currency_code' => $invoice['default_currency_code'])); //** Terms? */ if (!empty($invoice['meta']['terms'])) { $ni->set(array('terms' => $invoice['meta']['terms'])); } //** Tax */ $ni->set(array('tax' => $invoice['meta']['tax'])); //** Custom ID */ $ni->set(array('custom_id' => $invoice['meta']['custom_id'])); //** type is 'invoice' by default */ $invoice_type = 'invoice'; //** If $invoice object has type definition then use it */ if (!empty($invoice['type'])) { $invoice_type = $invoice['type']; } //** Save status of invoice (quote or not quote) */ if (isset($invoice['quote'])) { if ($invoice['quote'] == "on") { $ni->set(array('status' => 'quote')); $ni->set(array('is_quote' => 'true')); $invoice_type = 'quote'; } else { $ni->set(array('status' => 'null')); } } //** But if recurring settings are defined then invoice type should be recurring */ if ($invoice['recurring']['active'] == 'on' && !empty($invoice['recurring'])) { $ni->create_schedule($invoice['recurring']); $invoice_type = 'recurring'; } //** Finally set invoice type */ $ni->set(array('type' => $invoice_type)); //** Set invoice status */ $status = !empty($invoice['post_status']) ? $invoice['post_status'] : 'active'; $ni->set(array('post_status' => $status)); //** Add discounts if exist */ if (is_array($invoice['meta']['discount'])) { foreach ($invoice['meta']['discount'] as $discount) { if (!empty($discount['name']) && !empty($discount['amount'])) { $ni->add_discount(array('name' => $discount['name'], 'type' => $discount['type'], 'amount' => $discount['amount'])); } } } //** Ability to change payment method */ if (!empty($invoice['client_change_payment_method'])) { $ni->set(array('client_change_payment_method' => $invoice['client_change_payment_method'])); } //** Ability to turn off all payment methods and turn on manual that way */ if (!empty($invoice['use_manual_payment'])) { $ni->set(array('use_manual_payment' => $invoice['use_manual_payment'])); } //** Default payment method */ $ni->set(array('default_payment_method' => $invoice['default_payment_method'])); //** Tax method */ $ni->set(array('tax_method' => $invoice['tax_method'])); //** Manually set billing settings due to the complexity of the hierarchy */ $ni->data['billing'] = !empty($invoice['billing']) ? $invoice['billing'] : array(); //** Add line items */ foreach ($invoice['itemized_list'] as $line_item) { $ni->line_item(array('name' => $line_item['name'], 'description' => $line_item['description'], 'quantity' => $line_item['quantity'], 'price' => $line_item['price'], 'tax_rate' => $line_item['tax'])); } //** Add line items for charges */ if (!empty($invoice['itemized_charges'])) { foreach ($invoice['itemized_charges'] as $charge_item) { $ni->line_charge(array('name' => $charge_item['name'], 'amount' => $charge_item['amount'], 'tax' => $charge_item['tax'])); } } /** * Save Invoice Object to DB and update user * (trimming is a precaution because it could cause problems in inserted in DB w/ whitespace on end) */ $ni->set(array('user_email' => trim($invoice['user_data']['user_email']))); if ($type != 'import') { WPI_Functions::update_user($invoice['user_data']); } $invoice_id = $ni->save_invoice(); if ($invoice_id) { return $invoice_id; } else { return false; } }