protected function _execute() { // Independently validate $this->_date_billed if ($this->_date_billed and $this->_date_billed != date("Y-m-d", strtotime($this->_date_billed))) { throw new Exception("Invalid invoice date: must be in YYYY-MM-DD format."); } // Three laws. $temp_date_created = isset($this->_data->date_created) ? $this->_data->date_created : date("Y-m-d"); if ($temp_date_created != date("Y-m-d", strtotime($temp_date_created))) { throw new Exception("Invalid sale date: must be in YYYY-MM-DD format."); } if ($this->_date_billed and strtotime($this->_date_billed) < strtotime($temp_date_created)) { throw new Exception("Invalid invoice date: must on or after the date of the sale order."); } if ($this->_date_due and $this->_date_due != date("Y-m-d", strtotime($this->_date_due))) { throw new Exception("Invalid due date: must be in YYYY-MM-DD format."); } if ($this->_date_due and strtotime($this->_date_due) < strtotime($this->_date_billed)) { throw new Exception("Invalid due date: must be on or after the bill date."); } $this->_sale->entity_id = isset($this->_data->customer_id) ? (int) $this->_data->customer_id : NULL; $this->_sale->account_id = isset($this->_data->account_id) ? $this->_data->account_id : NULL; $this->_sale->refund_form_id = isset($this->_data->refund_sale_id) ? $this->_data->refund_sale_id : NULL; $this->_sale->sent = isset($this->_data->sent) ? $this->_data->sent : NULL; $this->_sale->date_created = isset($this->_data->date_created) ? $this->_data->date_created : NULL; $this->_sale->code = (isset($this->_data->sale_number) and $this->_data->sale_number) ? $this->_data->sale_number : "AUTOGENERATE"; $this->_sale->reference = isset($this->_data->order_number) ? $this->_data->order_number : NULL; $this->_sale->alt_reference = isset($this->_data->po_number) ? $this->_data->po_number : NULL; $this->_sale->aux_reference = isset($this->_data->quote_number) ? $this->_data->quote_number : NULL; $this->_sale->tax_exempt = (isset($this->_data->tax_exempt) and $this->_data->tax_exempt) ? TRUE : FALSE; $this->_sale->tax_exempt_reason = ($this->_sale->tax_exempt and isset($this->_data->tax_exempt_reason) and $this->_data->tax_exempt_reason) ? $this->_data->tax_exempt_reason : NULL; $this->_sale->billing_address_id = isset($this->_data->billing_address_id) ? (int) $this->_data->billing_address_id : NULL; $this->_sale->shipping_address_id = isset($this->_data->shipping_address_id) ? (int) $this->_data->shipping_address_id : NULL; // Handle Default Account Receivable // Customer Default Account Receivable if ($this->_sale->account_id === NULL) { $customer = $this->_load_customer($this->_sale->entity_id); if ($customer->loaded() and $customer->default_account_id) { $this->_sale->account_id = $customer->default_account_id; } } // Default Account Receivable if ($this->_sale->account_id === NULL) { $this->_sale->account_id = $this->_beans_setting_get('account_default_receivable'); } // Make sure we have good sale information before moving on. $this->_validate_customer_sale($this->_sale); $this->_sale->total = 0.0; $this->_sale->amount = 0.0; if (!isset($this->_data->lines) or !is_array($this->_data->lines) or !count($this->_data->lines)) { throw new Exception("Invalid sale line items: none provided."); } if (isset($this->_data->taxes)) { if (!is_array($this->_data->taxes)) { throw new Exception("Invalid sale taxes: must be an array."); } foreach ($this->_data->taxes as $sale_tax) { $new_sale_tax = $this->_default_form_tax(); $new_sale_tax->tax_id = isset($sale_tax->tax_id) ? (int) $sale_tax->tax_id : NULL; if (!$new_sale_tax->tax_id) { throw new Exception("Invalid sale tax ID: none provided."); } $tax = $this->_load_tax($new_sale_tax->tax_id); if (!$tax->loaded()) { throw new Exception("Invalid sale tax ID: tax not found."); } $new_sale_tax->tax_percent = $tax->percent; $new_sale_tax->form_line_amount = 0.0; $new_sale_tax->form_line_taxable_amount = 0.0; $new_sale_tax->total = 0.0; if (!isset($this->_sale_taxes[$new_sale_tax->tax_id])) { $this->_sale_taxes[$new_sale_tax->tax_id] = $new_sale_tax; } } } foreach ($this->_data->lines as $sale_line) { $new_sale_line = $this->_default_form_line(); $new_sale_line->account_id = isset($sale_line->account_id) ? (int) $sale_line->account_id : NULL; $new_sale_line->tax_exempt = $this->_sale->tax_exempt || (isset($sale_line->tax_exempt) and $sale_line->tax_exempt) ? TRUE : FALSE; $new_sale_line->description = isset($sale_line->description) ? $sale_line->description : NULL; $new_sale_line->amount = isset($sale_line->amount) ? $this->_beans_round($sale_line->amount) : NULL; $new_sale_line->quantity = isset($sale_line->quantity) ? (double) $sale_line->quantity : NULL; // Handle Default Income Account if ($new_sale_line->account_id === NULL) { $new_sale_line->account_id = $this->_beans_setting_get('account_default_income'); } $this->_validate_customer_sale_line($new_sale_line); $new_sale_line->total = $this->_beans_round($new_sale_line->amount * $new_sale_line->quantity); if (!$new_sale_line->tax_exempt) { foreach ($this->_sale_taxes as $tax_id => $sale_tax) { $this->_sale_taxes[$tax_id]->form_line_taxable_amount = $this->_beans_round($this->_sale_taxes[$tax_id]->form_line_taxable_amount + $new_sale_line->total); } } $this->_sale->amount = $this->_beans_round($this->_sale->amount + $new_sale_line->total); $this->_sale_lines[] = $new_sale_line; } $this->_sale->total = $this->_beans_round($this->_sale->total + $this->_sale->amount); foreach ($this->_sale_taxes as $tax_id => $sale_tax) { $this->_sale_taxes[$tax_id]->total = $this->_beans_round($sale_tax->tax_percent * $sale_tax->form_line_taxable_amount); $this->_sale_taxes[$tax_id]->form_line_amount = $this->_sale->amount; $this->_sale->total = $this->_beans_round($this->_sale->total + $this->_sale_taxes[$tax_id]->total); } // Validate Totals if ($this->_sale->refund_form_id) { $refund_form = $this->_load_customer_sale($this->_sale->refund_form_id); if (!$refund_form->loaded()) { throw new Exception("That refund_sale_id was not found."); } $original_sale = $refund_form; $refund_sale = $this->_sale; if ($original_sale->total > 0.0 and $refund_sale->total > 0.0 or $original_sale->total < 0.0 and $refund_sale->total < 0.0) { throw new Exception("Refund and original sale totals must offset each other ( they cannot both be positive or negative )."); } if (abs($refund_sale->total) > abs($original_sale->total)) { throw new Exception("The refund total cannot be greater than the original sale total."); } } // Save Sale + Children $this->_sale->save(); foreach ($this->_sale_lines as $j => $sale_line) { $sale_line->form_id = $this->_sale->id; $sale_line->save(); } foreach ($this->_sale_taxes as $tax_id => $sale_tax) { $this->_sale_taxes[$tax_id]->form_id = $this->_sale->id; $this->_sale_taxes[$tax_id]->save(); } if ($this->_sale->code == "AUTOGENERATE") { $this->_sale->code = $this->_sale->id; } $this->_sale->save(); $sale_calibrate = new Beans_Customer_Sale_Calibrate($this->_beans_data_auth((object) array('ids' => array($this->_sale->id)))); $sale_calibrate_result = $sale_calibrate->execute(); if (!$sale_calibrate_result->success) { // We've had an account transaction failure and need to delete the sale we just created. $delete_sale = new Beans_Customer_Sale_Delete($this->_beans_data_auth((object) array('id' => $this->_sale->id))); $delete_sale_result = $delete_sale->execute(); // TODO - 100PERCENTWORKING if (!$delete_sale_result->success) { throw new Exception("Error creating account transaction for sale. COULD NOT DELETE SALE! " . $delete_sale_result->error); } throw new Exception("Error trying to create sale: " . $sale_calibrate_result->error); } // Reload the sale. $this->_sale = $this->_load_customer_sale($this->_sale->id); if ($this->_date_billed) { $customer_sale_invoice = new Beans_Customer_Sale_Invoice($this->_beans_data_auth((object) array('id' => $this->_sale->id, 'date_billed' => $this->_date_billed, 'date_due' => $this->_date_due ? $this->_date_due : FALSE))); $customer_sale_invoice_result = $customer_sale_invoice->execute(); // If it fails - we undo everything ( this was a single request, after all ). if (!$customer_sale_invoice_result->success) { $delete_sale = new Beans_Customer_Sale_Delete($this->_beans_data_auth((object) array('id' => $this->_sale->id))); $delete_sale_result = $delete_sale->execute(); // TODO - 100PERCENTWORKING if (!$delete_sale_result->success) { throw new Exception("Error creating account transaction for sale. COULD NOT DELETE SALE! " . $delete_sale_result->error); } throw new Exception("Error creating sale invoice: " . $customer_sale_invoice_result->error); } return $this->_beans_return_internal_result($customer_sale_invoice_result); } // We need to reload the sale so that we can get the correct balance, etc. $this->_sale = $this->_load_customer_sale($this->_sale->id); return (object) array("sale" => $this->_return_customer_sale_element($this->_sale)); }
public function action_saleinvoice() { $sale_id = $this->request->post('sale_id'); $send_none = $this->request->post('send-none') ? TRUE : FALSE; $send_email = $this->request->post('send-email') ? TRUE : FALSE; $email = $this->request->post('email'); $send_mail = $this->request->post('send-mail') ? TRUE : FALSE; $send_done = $this->request->post('send-done') ? TRUE : FALSE; if (!$sale_id) { return $this->_return_error("ERROR: No sale ID provided."); } if (!$send_none and !$send_email and !$send_mail and !$send_done) { return $this->_return_error("ERROR: Please select at least one option."); } // Invoice $customer_sale_invoice = new Beans_Customer_Sale_Invoice($this->_beans_data_auth((object) array('id' => $sale_id))); $customer_sale_invoice_result = $customer_sale_invoice->execute(); if (!$customer_sale_invoice_result->success) { return $this->_return_error("An error occurred when converting that sale to an invoice:<br>" . $this->_beans_result_get_error($customer_sale_invoice_result)); } if ($send_none) { $html = new View_Partials_Customers_Sales_Sale(); $html->sale = $customer_sale_invoice_result->data->sale; $html->invoice_view = $this->request->post('invoice_view'); $this->_return_object->data->sale = $customer_sale_invoice_result->data->sale; $this->_return_object->data->sale->html = $html->render(); return; } if ($send_done) { $customer_sale_update_sent = new Beans_Customer_Sale_Update_Sent($this->_beans_data_auth((object) array('id' => $customer_sale_invoice_result->data->sale->id, 'sent' => 'both'))); $customer_sale_update_sent_result = $customer_sale_update_sent->execute(); $html = new View_Partials_Customers_Sales_Sale(); $html->sale = $customer_sale_update_sent_result->data->sale; $html->invoice_view = $this->request->post('invoice_view'); $this->_return_object->data->sale = $customer_sale_update_sent_result->data->sale; $this->_return_object->data->sale->html = $html->render(); return; } if ($send_email) { if (!$email or !filter_var($email, FILTER_VALIDATE_EMAIL)) { return $this->_return_error("Please provide a valid email address."); } $company_settings = new Beans_Setup_Company_List($this->_beans_data_auth()); $company_settings_result = $company_settings->execute(); if (!$company_settings_result->success) { return $this->_return_error($this->_beans_result_get_error($company_settings_result)); } // Shorten for sanity's sake... $settings = $company_settings_result->data->settings; if (!isset($settings->company_email) or !strlen($settings->company_email)) { return $this->_return_error("Email cannot be sent until you set an email address for your company within 'Setup'."); } $message = Swift_Message::newInstance(); $message->setSubject($settings->company_name . ' - ' . $customer_sale_invoice_result->data->sale->title)->setFrom(array($settings->company_email))->setTo(array($email)); $customers_print_sale = new View_Customers_Print_Sale(); $customers_print_sale->setup_company_list_result = $company_settings_result; $customers_print_sale->sale = $customer_sale_invoice_result->data->sale; $customers_print_sale->swift_email_message = $message; $message = $customers_print_sale->render(); try { if (!Email::connect()) { return $this->_return_error("Could not send email. Does your config have correct email settings?"); } if (!Email::sendMessage($message)) { return $this->_return_error("Could not send email. Does your config have correct email settings?"); } } catch (Exception $e) { return $this->_return_error("An error occurred when sending the email: " . $e->getMessage() . "<br><br>Have you setup email properly in config.php?"); } } // Update sale attributes only. $customer_sale_update_sent_data = new stdClass(); $customer_sale_update_sent_data->id = $sale_id; if ($send_done or $send_email and $send_mail or $send_email and $customer_sale_invoice_result->data->sale->sent == "print" or $send_mail and $customer_sale_invoice_result->data->sale->sent == "email") { $customer_sale_update_sent_data->sent = 'both'; } else { if ($send_email) { $customer_sale_update_sent_data->sent = 'email'; } else { if ($send_mail) { $customer_sale_update_sent_data->sent = 'print'; } } } $customer_sale_update_sent = new Beans_Customer_Sale_Update_Sent($this->_beans_data_auth($customer_sale_update_sent_data)); $customer_sale_update_sent_result = $customer_sale_update_sent->execute(); if (!$customer_sale_update_sent_result->success) { return $this->_return_error("An error occurred when updating that sale:<br>" . $this->_beans_result_get_error($customer_sale_update_sent_result)); } $html = new View_Partials_Customers_Sales_Sale(); $html->sale = $customer_sale_update_sent_result->data->sale; $html->invoice_view = $this->request->post('invoice_view'); $this->_return_object->data->sale = $customer_sale_update_sent_result->data->sale; $this->_return_object->data->sale->html = $html->render(); }