diff --git a/application/helpers/pdf_helper.php b/application/helpers/pdf_helper.php
index 327d44a02..3e2601820 100644
--- a/application/helpers/pdf_helper.php
+++ b/application/helpers/pdf_helper.php
@@ -258,3 +258,41 @@ function generate_quote_pdf($quote_id, $stream = true, $quote_template = null)
return pdf_create($html, trans('quote') . '_' . str_replace(array('\\', '/'), '_', $quote->quote_number), $stream, $quote->quote_password);
}
+
+/**
+ * Generate the PDF for the statement
+ *
+ * @param Mdl_Clients $client
+ * @param Mdl_Statement $statement
+ * @param $notes
+ *
+ * @return string
+ * @throws \Mpdf\MpdfException
+ */
+function generate_statement_pdf($client, $statement, $notes)
+{
+ $CI = &get_instance();
+
+ // Override language with system language
+ set_language($client->client_language);
+
+ $statement_template = "InvoicePlane";
+ if (!$statement_template) {
+ $statement_template = $CI->mdl_settings->setting('pdf_statement_template');
+ }
+
+ $data = array(
+ 'client' => $client,
+ 'statement' => $statement,
+ 'notes' => $notes,
+ );
+
+ $html = $CI->load->view('statement_templates/pdf/' . $statement_template, $data, true);
+
+ $CI->load->helper('mpdf');
+
+ $pdf_password = null;
+ $stream = true;
+
+ return pdf_create($html, trans('statement') . '_' . str_replace(array('\\', '/'), '_', $statement->GetStatement_number()), $stream, $pdf_password);
+}
diff --git a/application/language/english/ip_lang.php b/application/language/english/ip_lang.php
index 705638552..6f70461aa 100644
--- a/application/language/english/ip_lang.php
+++ b/application/language/english/ip_lang.php
@@ -260,6 +260,7 @@
'invoice_items' => 'Invoice Items',
'invoice_logo' => 'Invoice Logo',
'invoice_not_found' => 'Invoice Not Found',
+ 'invoice_number' => 'Invoice Number',
'invoice_overview' => 'Invoice Overview',
'invoice_overview_period' => 'Invoice Overview Period',
'invoice_password' => 'PDF password (optional)',
@@ -272,6 +273,7 @@
'invoice_tax_rate' => 'Invoice Tax Rate',
'invoice_template' => 'Invoice Template',
'invoice_terms' => 'Invoice Terms',
+ 'invoice_total' => 'Invoice Total',
'invoiced' => 'Invoiced',
'invoiceplane_news' => 'InvoicePlane News',
'invoices' => 'Invoices',
@@ -436,6 +438,7 @@
'record_successfully_updated' => 'Record successfully updated',
'recurring' => 'Recurring',
'recurring_invoices' => 'Recurring Invoices',
+ 'reference' => 'Reference',
'reject' => 'Reject',
'reject_this_quote' => 'Reject This Quote',
'rejected' => 'Rejected',
@@ -512,6 +515,11 @@
'sql_file' => 'SQL File',
'start_date' => 'Start Date',
'state' => 'State',
+ 'statement' => 'Statement',
+ 'statement_date' => 'Statement Date',
+ 'statement_end_date' => 'Statement End Date',
+ 'statement_number' => 'Statement Number',
+ 'statement_start_date' => 'Statement Start Date',
'status' => 'Status',
'stop' => 'Stop',
'street_address' => 'Street Address',
@@ -550,6 +558,7 @@
'total_balance' => 'Total Balance',
'total_billed' => 'Total Billed',
'total_paid' => 'Total Paid',
+ 'transaction_type' => 'Transaction Type',
'try_again' => 'Try Again',
'type' => 'Type',
'unknown' => 'Unknown',
diff --git a/application/modules/clients/views/partial_client_table.php b/application/modules/clients/views/partial_client_table.php
index a82aec30c..d278a206a 100644
--- a/application/modules/clients/views/partial_client_table.php
+++ b/application/modules/clients/views/partial_client_table.php
@@ -56,6 +56,11 @@
+
+
+
+
+
diff --git a/application/modules/invoices/models/Mdl_invoices.php b/application/modules/invoices/models/Mdl_invoices.php
index 57d7d360a..739c3bc36 100644
--- a/application/modules/invoices/models/Mdl_invoices.php
+++ b/application/modules/invoices/models/Mdl_invoices.php
@@ -526,6 +526,27 @@ public function by_client($client_id)
return $this;
}
+ /**
+ * Filter query in a date range.
+ * The filter can be open ended on one end by not supplied a value
+ * Dates must be in unixtime format
+ *
+ * @param time $start_date
+ * @param time $end_date
+ * @return Mdl_Invoices
+ */
+ public function by_date_range($start_date = null, $end_date = null)
+ {
+ if (!empty($start_date)) {
+ $this->filter_where("invoice_date_created >= '" . $start_date . "' ");
+ }
+ if (!empty($end_date)) {
+ $this->filter_where("invoice_date_created <= '" . $end_date . "' ");
+ }
+
+ return $this;
+ }
+
/**
* @param $invoice_id
*/
diff --git a/application/modules/payments/models/Mdl_payments.php b/application/modules/payments/models/Mdl_payments.php
index 4c8323d45..76f5aff46 100755
--- a/application/modules/payments/models/Mdl_payments.php
+++ b/application/modules/payments/models/Mdl_payments.php
@@ -223,4 +223,25 @@ public function by_client($client_id)
return $this;
}
+ /**
+ * Filter query in a date range.
+ * The filter can be open ended on one end by not supplied a value
+ * Dates must be in unixtime format
+ *
+ * @param time $start_date
+ * @param time $end_date
+ * @return Mdl_Payments
+ */
+ public function by_date_range($start_date = null, $end_date = null)
+ {
+ if (!empty($start_date)) {
+ $this->filter_where("payment_date >= '" . $start_date . "' ");
+ }
+ if (!empty($end_date)) {
+ $this->filter_where("payment_date <= '" . $end_date . "' ");
+ }
+
+ return $this;
+ }
+
}
diff --git a/application/modules/statements/controllers/Statements.php b/application/modules/statements/controllers/Statements.php
new file mode 100644
index 000000000..aace9bf55
--- /dev/null
+++ b/application/modules/statements/controllers/Statements.php
@@ -0,0 +1,376 @@
+load->model('clients/mdl_clients');
+ }
+
+ public function index($client_id)
+ {
+ $this->view($client_id);
+ }
+
+ /**
+ * @param $client_id
+ *
+ */
+ public function view($client_id)
+ {
+ $this->load->model('custom_fields/mdl_client_custom');
+
+ /*
+ * Load the client
+ */
+ $client = $this->mdl_clients
+ ->where('ip_clients.client_id', $client_id)
+ ->get()->row();
+
+ if (!$client) {
+ show_404();
+ }
+
+ $custom_fields = $this->mdl_client_custom->get_by_client($client_id)->result();
+
+ $this->mdl_client_custom->prep_form($client_id);
+
+ if($this->input->method() === 'post')
+ {
+
+ if (!empty($this->input->post('statement_start_date'))) {
+ // BUG : strtotime is not recognising the date format d M,Y" and changing the date
+ // $statement_start_date = strtotime($this->input->post('statement_start_date'));
+ $date_time = date_create_from_format("d M,Y", $this->input->post('statement_start_date'));
+ $statement_start_date = $date_time->getTimestamp();
+
+ } else {
+ $statement_start_date = strtotime($this->input->post('sdate'));
+ }
+ $statement_end_date = $this->input->post('edate');
+
+ // BUG : strtotime is not recognising the date format d M,Y" and changing the date
+ // $statement_date = strtotime($this->input->post('statement_date_created'));
+ $date_time = date_create_from_format("d M,Y", $this->input->post('statement_date_created'));
+ $statement_date = $date_time->getTimestamp();
+
+ $statement_number = $this->input->post('statement_number');
+ $notes = $this->input->post('notes');
+
+ } else {
+
+ $statement_start_date = null;
+ $statement_end_date = null;
+
+ $statement_number = null;
+ $statement_date = null;
+ $notes = null;
+
+ }
+
+ $statement = $this->build_statement($client_id, $statement_start_date, $statement_end_date, $statement_date, $statement_number);
+
+ $this->layout->set(
+ array(
+
+ 'client' => $client,
+ 'statement_start_date' => $statement->getStatement_start_date(),
+ 'statement_end_date' => $statement->getStatement_end_date(),
+ 'statement_date' => $statement->getStatement_date(),
+ 'custom_fields' => $custom_fields,
+ 'statement_transactions' => $statement->getStatement_transactions(),
+ 'opening_balance' => $statement->getOpening_balance(),
+ 'client_total_balance' => $statement->getStatement_balance(),
+ 'statement_number' => $statement->getStatement_number(),
+
+ )
+ );
+
+ $this->layout->buffer(
+ array(
+ array('content', 'statements/view')
+ )
+ );
+
+ $this->layout->render();
+
+ }
+
+ /**
+ * Populate the Statement model
+ *
+ *
+ * @param Mdl_Clients $client
+ * @param $statement_start_date
+ * @param $statement_end_date
+ * @param $statement_date,
+ * @param $statement_number
+ *
+ */
+ private function build_statement($client_id, $statement_start_date = null, $statement_end_date = null, $statement_date = null, $statement_number = null)
+ {
+ $this->load->model('mdl_statement');
+
+ $this->load->model('invoices/mdl_invoices');
+ $this->load->model('payments/mdl_payments');
+
+
+ /*
+ * Use the user supplied start date, or set the start date to a month ago
+ */
+ if (empty($statement_start_date)) {
+ $statement_start_date = strtotime("-1 month");
+ }
+
+ /*
+ * Use the user supplied end date, or draw the statement up to now
+ */
+ if (empty($statement_end_date)) {
+ $statement_end_date = time();
+ }
+
+ /*
+ * Use the user supplied statament date, or use the current date
+ */
+ if (empty($statement_date)) {
+ $statement_date = time();
+ }
+
+ /*
+ * Create the statement number based on the client id and date, or overwrite it with the user value.
+ */
+ if (!empty($statement_number)) {
+ $this->mdl_statement->setStatement_number($statement_number);
+ } else {
+ $this->mdl_statement->setStatement_number( 'STM-' . $client_id . '-' . date('ymd'));
+ }
+
+ /*
+ * Set the statement date to now, or overwrite it with the user value.
+ */
+ $this->mdl_statement->setStatement_date($statement_date);
+
+
+ /*
+ * Calculate the opening statement as from the start of the user account to the start of the statement period
+ */
+ $opening_balance_start_date = null;
+ $opening_balance_end_date = $statement_start_date;
+
+
+ $client_invoices = $this->mdl_invoices
+ ->by_client($client_id)
+ ->by_date_range(date('Y-m-d', $opening_balance_start_date), date('Y-m-d', $opening_balance_end_date))
+ ->get()
+ ->result();
+ $client_payments = $this->mdl_payments
+ ->by_client($client_id)
+ ->by_date_range(date('Y-m-d', $opening_balance_start_date), date('Y-m-d', $opening_balance_end_date))
+ ->get()
+ ->result();
+
+
+ $client_invoice_total = 0;
+ foreach ($client_invoices as $invoice_entry) {
+ $client_invoice_total += $invoice_entry->invoice_total;
+ }
+
+ $client_payment_total = 0;
+ foreach ($client_payments as $payment_entry) {
+ $client_payment_total += $payment_entry->payment_amount;
+ }
+
+ $client_opening_balance = $client_invoice_total - $client_payment_total;
+
+ $this->mdl_statement->setOpening_balance($client_opening_balance);
+
+
+ $this->mdl_statement->setStatement_start_date($statement_start_date);
+ $this->mdl_statement->setStatement_end_date($statement_end_date);
+
+ /*
+ * NOTE: These two calls brings back all invoices and payments over the
+ * ...date range, and we manually sum up the totals
+ */
+
+ $client_invoices = $this->mdl_invoices
+ ->by_client($client_id)
+ ->by_date_range(date('Y-m-d', $statement_start_date), date('Y-m-d', $statement_end_date))
+ ->get()
+ ->result();
+ $client_payments = $this->mdl_payments
+ ->by_client($client_id)
+ ->by_date_range(date('Y-m-d', $statement_start_date), date('Y-m-d', $statement_end_date))
+ ->get()
+ ->result();
+
+
+ $statement_transactions = array();
+ $client_total_balance = $client_opening_balance;
+ foreach ($client_invoices as $invoice_entry) {
+
+ $transaction = [
+ 'transaction_type' => self::TRANSACTION_TYPE_INVOICE,
+ 'transaction_date' => $invoice_entry->invoice_date_created,
+ 'transaction_amount' => $invoice_entry->invoice_total,
+
+ 'invoice_id' => $invoice_entry->invoice_id,
+ 'client_id' => $invoice_entry->client_id,
+ 'user_company' => $invoice_entry->user_company,
+ 'invoice_amount_id' => $invoice_entry->invoice_amount_id,
+ 'invoice_item_subtotal' => $invoice_entry->invoice_item_subtotal,
+ 'invoice_item_tax_total' => $invoice_entry->invoice_item_tax_total,
+ 'invoice_total' => $invoice_entry->invoice_total,
+ 'invoice_sign' => $invoice_entry->invoice_sign,
+ 'invoice_status_id' => $invoice_entry->invoice_status_id,
+ 'invoice_date_created' => $invoice_entry->invoice_date_created,
+ 'invoice_time_created' => $invoice_entry->invoice_time_created,
+ 'invoice_number' => $invoice_entry->invoice_number,
+ ];
+
+ $client_total_balance += $invoice_entry->invoice_total;
+
+ $statement_transactions[] = $transaction;
+
+ }
+
+ foreach ($client_payments as $payment_entry) {
+
+ $transaction = [
+ 'transaction_type' => self::TRANSACTION_TYPE_PAYMENT,
+ 'transaction_date' => $payment_entry->payment_date,
+ 'transaction_amount' => $payment_entry->payment_amount,
+
+
+ 'invoice_id' => $payment_entry->invoice_id,
+ 'client_id' => $payment_entry->client_id,
+ 'invoice_date_created' => $payment_entry->invoice_date_created,
+ 'invoice_item_subtotal' => $payment_entry->invoice_item_subtotal,
+ 'invoice_item_tax_total' => $payment_entry->invoice_item_tax_total,
+ 'invoice_total' => $payment_entry->invoice_total,
+ 'invoice_sign' => $payment_entry->invoice_sign,
+ 'invoice_number' => $payment_entry->invoice_number,
+ 'payment_id' => $payment_entry->payment_id,
+ 'payment_method_id' => $payment_entry->payment_method_id,
+ 'payment_method_name' => $payment_entry->payment_method_name,
+ 'payment_date' => $payment_entry->payment_date,
+ 'payment_amount' => $payment_entry->payment_amount,
+
+ ];
+
+ $statement_transactions[] = $transaction;
+
+ $client_total_balance -= $payment_entry->payment_amount;
+
+ }
+
+ usort($statement_transactions, array($this, "compare_statement_dates"));
+
+ $this->mdl_statement->setStatement_transactions($statement_transactions);
+
+ $this->mdl_statement->setStatement_balance($client_total_balance);
+
+ return $this->mdl_statement;
+
+ }
+
+
+ /**
+ * Controller action to print pdf. From POST action.
+ *
+ */
+ public function generate_pdf()
+ {
+ $this->load->model('clients/mdl_clients');
+ $this->load->helper('country');
+
+ $client_id = $this->input->post('cid');
+ $statement_number = $this->input->post('statement_number');
+
+ if (!empty($this->input->post('statement_start_date'))) {
+ //$statement_start_date = strtotime($this->input->post('statement_start_date'));
+ $date_time = date_create_from_format("d M,Y", $this->input->post('statement_start_date'));
+ $statement_start_date = $date_time->getTimestamp();
+
+ } else {
+ $statement_start_date = strtotime($this->input->post('sdate'));
+ }
+ $statement_end_date = strtotime($this->input->post('edate'));
+
+ // BUG : strtotime is not recognising the date format d M,Y" and changing the date
+ // $statement_date = strtotime($this->input->post('statement_date_created'));
+ $date_time = date_create_from_format("d M,Y", $this->input->post('statement_date_created'));
+ $statement_date = $date_time->getTimestamp();
+
+
+ $notes = $this->input->post('notes');
+
+ /*
+ * Load the client
+ */
+ $client = $this->mdl_clients
+ ->where('ip_clients.client_id', $client_id)
+ ->get()->row();
+
+ if (!$client) {
+ show_404();
+ }
+
+ $statement = $this->build_statement($client->client_id, $statement_start_date, $statement_end_date);
+
+ $this->load->helper('pdf');
+
+ generate_statement_pdf($client, $statement, $notes);
+ }
+
+
+
+ /**
+ * Compare 2 dates
+ *
+ * NOTE: I am not sure if $this is the correct scope for this function.
+ *
+ * @param string $a The first date in string format
+ * @param string $b The second date in string format
+ * @return number
+ * 0 is the dates are the same
+ * 1 if date A > date B
+ * -1 if date A < date B
+ */
+ private function compare_statement_dates($a, $b)
+ {
+ $timeA = strtotime($a['transaction_date']);
+ $timeB = strtotime($b['transaction_date']);
+
+ if($timeA == $timeB) {
+ return 0;
+ }
+
+ return $timeA < $timeB ? -1 : 1;
+ }
+
+}
diff --git a/application/modules/statements/models/Mdl_statement.php b/application/modules/statements/models/Mdl_statement.php
new file mode 100644
index 000000000..ba9a7b958
--- /dev/null
+++ b/application/modules/statements/models/Mdl_statement.php
@@ -0,0 +1,150 @@
+statement_number;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStatement_transactions()
+ {
+ return $this->statement_transactions;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStatement_start_date()
+ {
+ return $this->statement_start_date;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStatement_end_date()
+ {
+ return $this->statement_end_date;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStatement_date()
+ {
+ return $this->statement_date;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getOpening_balance()
+ {
+ return $this->opening_balance;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getStatement_balance()
+ {
+ return $this->statement_balance;
+ }
+
+ /**
+ * @param mixed $statement_number
+ */
+ public function setStatement_number($statement_number)
+ {
+ $this->statement_number = $statement_number;
+ }
+
+ /**
+ * @param mixed $statement_transactions
+ */
+ public function setStatement_transactions($statement_transactions)
+ {
+ $this->statement_transactions = $statement_transactions;
+ }
+
+ /**
+ * @param mixed $statement_start_date
+ */
+ public function setStatement_start_date($statement_start_date)
+ {
+ $this->statement_start_date = $statement_start_date;
+ }
+
+ /**
+ * @param mixed $statement_end_date
+ */
+ public function setStatement_end_date($statement_end_date)
+ {
+ $this->statement_end_date = $statement_end_date;
+ }
+
+ /**
+ * @param mixed $statement_date
+ */
+ public function setStatement_date($statement_date)
+ {
+ $this->statement_date = $statement_date;
+ }
+
+ /**
+ * @param mixed $opening_balance
+ */
+ public function setOpening_balance($opening_balance)
+ {
+ $this->opening_balance = $opening_balance;
+ }
+
+ /**
+ * @param mixed $statement_balance
+ */
+ public function setStatement_balance($statement_balance)
+ {
+ $this->statement_balance = $statement_balance;
+ }
+}
diff --git a/application/modules/statements/views/index.php b/application/modules/statements/views/index.php
new file mode 100644
index 000000000..d71c1d11e
--- /dev/null
+++ b/application/modules/statements/views/index.php
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+ layout->load_view('quotes/partial_quote_table', array('quotes' => $quotes)); ?>
+
+
+
diff --git a/application/modules/statements/views/partial_item_table.php b/application/modules/statements/views/partial_item_table.php
new file mode 100644
index 000000000..5ee19def8
--- /dev/null
+++ b/application/modules/statements/views/partial_item_table.php
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/application/modules/statements/views/statement_templates/pdf/.gitignore b/application/modules/statements/views/statement_templates/pdf/.gitignore
new file mode 100644
index 000000000..193ab4cca
--- /dev/null
+++ b/application/modules/statements/views/statement_templates/pdf/.gitignore
@@ -0,0 +1,3 @@
+*
+!InvoicePlane.php
+!.gitignore
diff --git a/application/modules/statements/views/statement_templates/pdf/InvoicePlane.php b/application/modules/statements/views/statement_templates/pdf/InvoicePlane.php
new file mode 100644
index 000000000..1a52ca7f2
--- /dev/null
+++ b/application/modules/statements/views/statement_templates/pdf/InvoicePlane.php
@@ -0,0 +1,191 @@
+
+
+
+
+
+ getStatement_number(); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+ client_name); ?>
+
+ client_vat_id) {
+ echo '
' . trans('vat_id_short') . ': ' . $client->client_vat_id . '
';
+ }
+ if ($client->client_tax_code) {
+ echo '
' . trans('tax_code_short') . ': ' . $client->client_tax_code . '
';
+ }
+ if ($client->client_address_1) {
+ echo '
' . htmlsc($client->client_address_1) . '
';
+ }
+ if ($client->client_address_2) {
+ echo '
' . htmlsc($client->client_address_2) . '
';
+ }
+ if ($client->client_city || $client->client_state || $client->client_zip) {
+ echo '
';
+ if ($client->client_city) {
+ echo htmlsc($client->client_city) . ' ';
+ }
+ if ($client->client_state) {
+ echo htmlsc($client->client_state) . ' ';
+ }
+ if ($client->client_zip) {
+ echo htmlsc($client->client_zip);
+ }
+ echo '
';
+ }
+ if ($client->client_state) {
+ echo '
' . htmlsc($client->client_state) . '
';
+ }
+ if ($client->client_country) {
+ echo '
' . get_country_name(trans('cldr'), $client->client_country) . '
';
+ }
+
+ echo '
';
+
+ if ($client->client_phone) {
+ echo '
' . trans('phone_abbr') . ': ' . htmlsc($client->client_phone) . '
';
+ } ?>
+
+
+
+
+
+
+
+
+
+
+ |
+ getStatement_date()); ?> |
+
+
+ |
+ getStatement_start_date()); ?> |
+
+
+ |
+ getStatement_end_date()); ?> |
+
+
+
+
+
+ getStatement_number(); ?>
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+ getOpening_balance())) {
+ ?>
+
+
+ |
+ GetStatement_start_date(); ?>
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+ getOpening_balance()); ?>
+ |
+
+
+
+
+
+ GetStatement_transactions() as $transaction) {
+
+
+ if ($transaction['transaction_type'] == Statements::TRANSACTION_TYPE_INVOICE) {
+ $balance += $transaction['transaction_amount'];
+ } else {
+ $balance -= $transaction['transaction_amount'];
+ }
+ ?>
+
+
+ |
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ | |
+
+
+ |
+ getStatement_balance()); ?> |
+
+
+ | |
+
+
+
+
+
+
+
+
+
+
diff --git a/application/modules/statements/views/statement_templates/public/.gitignore b/application/modules/statements/views/statement_templates/public/.gitignore
new file mode 100644
index 000000000..8a8e758a3
--- /dev/null
+++ b/application/modules/statements/views/statement_templates/public/.gitignore
@@ -0,0 +1,3 @@
+*
+!InvoicePlane_Web.php
+!.gitignore
diff --git a/application/modules/statements/views/view.php b/application/modules/statements/views/view.php
new file mode 100644
index 000000000..17bfcc2a1
--- /dev/null
+++ b/application/modules/statements/views/view.php
@@ -0,0 +1,172 @@
+
+
+
+
+
+ layout->load_view('layout/alerts'); ?>
+
+
+