I am trying to show order details for successful orders on success page but unable to do so. Another answer here suggests to modify success.php and success.tpl but it's not working on Opencart 2.
What have I tried?
catalog/controller/checkout/success.php
and added new lines in the following code:
public function index() {
$this->data['order_id'] = 0; // <-- NEW LINE
$this->data['total'] = 0; // <-- NEW LINE
if (isset($this->session->data['order_id'])) {
$this->data['order_id'] = $this->session->data['order_id']; // <-- NEW LINE
$this->data['total'] = $this->cart->getTotal(); // <-- NEW LINE
$this->cart->clear();
unset($this->session->data['shipping_method']);
unset($this->session->data['shipping_methods']);
unset($this->session->data['payment_method']);
unset($this->session->data['payment_methods']);
unset($this->session->data['guest']);
unset($this->session->data['comment']);
unset($this->session->data['order_id']);
unset($this->session->data['coupon']);
unset($this->session->data['reward']);
unset($this->session->data['voucher']);
unset($this->session->data['vouchers']);
}
$this->language->load('checkout/success');
Now added the following code into success.tpl
<?php if($order_id) { ?>
<script type="text/javascript">
// Some code here
arr.push([
"create_order",
{order_id: '<?php echo $order_id; ?>', sum: '<?php echo $total; ?>'}
]);
But it doesn't show anything on success page. The above code is to show order ID and total but I want to show all details of order including name, address, products, total, shipping, etc. Just like in the order invoice.
Any help will be appreciated. Thank you
What I did on pre 2.0 versions was to actually set a new variable to the session for the order id as I found that $this->session->data['order_id'] wasn't consistent and sometimes was getting unset by the time the user reached ControllerCheckoutSuccess.
If you'd like to use this approach, edit your catalog/model/checkout/order.php file. At or about line 302 (within the addOrderHistory method) you'll see where the script checks for order status ids to determine if it should complete the order.
Within that statement, set a new session variable of your choice to the order id passed in, perhaps $this->session->data['customer_order_id'] = $order_id
Now you have a session variable that you know will remain consistent since you've created it yourself and OpenCart won't mess with it.
If you're finding that the session order id IS remaining consistent in 2.1 > then don't worry about this, just go ahead and use the default session order id variable built in.
The next step will be for you to decide how you want your invoice data loaded, via PHP or Ajax. I wouldn't recommend using Ajax as since this could be manipulated with browser developer tools and may expose other's customer's information. By using PHP and the session you eliminate this risk since a random hacker won't have access to another customer's session.
REQUIRED FOR BOTH OPTIONS BELOW:
Open catalog/controller/checkout/success.php
Right after the language file is loaded in your index method add the following:
$order_id = false;
// If NOT using the custom variable mentioned SKIP this
if (isset($this->session->data['customer_order_id'])) {
$order_id = $this->session->data['customer_order_id'];
}
If you're using the baked in session data order id, set your order id within that statement:
if (isset($this->session->data['order_id'])) {
$this->cart->clear();
$order_id = $this->session->data['order_id'];
OPTION 1:
Add receipt data to checkout/success.
Find this line:
$data['button_continue'] = $this->language->get('button_continue');
Should be around line 77-84 or thereabout.
Here you'll load up and format all your receipt info.
Open catalog/controller/account/order.php
On line 108 you'll find the info method.
Here's where the fun starts :P
Copy all the relevant info from that method into your checkout success controller just after the $data['button_continue'] = $this->language->get('button_continue'); line mentioned above.
You'll need to go through this line by line and tweak it because remember this is designed for logged in customers, so you won't want links for returns or reorders etc.
Next you're going to want to make a new template because the common/success template is generic and used all over the place.
Copy catalog/view/theme/(your theme)/template/common/success.tpl
to: catalog/view/theme/(your theme)/template/checkout/success.tpl
Open catalog/view/theme/default/template/account/order_info.tpl
The tables you'll need to add to your success template start on line 28 and extend to line 139. If you're using a different theme, you'll need to suss this out for yourself.
Don't forget to change the path to your template in your checkout/success controller to your new checkout/success tpl file.
NOTE:
It's important to remember that all this SHOULD be done in a modification package and NOT in your core files, but I don't know your situation so that's up to you to decide.
OPTION 2:
Create your own module.
In my opinion having built for this system since version 1.4 this is the best option.
Create new controller in modules, let's call it ControllerModuleReceipt:
<?php
/**
* Controller class for displaying a receipt on checkout success.
*/
class ControllerModuleReceipt extends Controller
{
/**
* Replicates the ControllerAccountOrder::info
* method for displaying order info in our
* ControllerCheckoutSuccess::index method
*
* #param int $order_id our order id
* #return mixed receipt view
*/
public function index($setting)
{
$this->load->language('account/order');
$this->load->model('account/order');
if (empty($setting['order_id'])) {
return;
}
$order_id = $setting['order_id'];
$order_info = $this->model_account_order->getOrder($order_id);
if ($order_info) {
$data['text_order_detail'] = $this->language->get('text_order_detail');
$data['text_invoice_no'] = $this->language->get('text_invoice_no');
$data['text_order_id'] = $this->language->get('text_order_id');
$data['text_date_added'] = $this->language->get('text_date_added');
$data['text_shipping_method'] = $this->language->get('text_shipping_method');
$data['text_shipping_address'] = $this->language->get('text_shipping_address');
$data['text_payment_method'] = $this->language->get('text_payment_method');
$data['text_payment_address'] = $this->language->get('text_payment_address');
$data['text_history'] = $this->language->get('text_history');
$data['text_comment'] = $this->language->get('text_comment');
$data['column_name'] = $this->language->get('column_name');
$data['column_model'] = $this->language->get('column_model');
$data['column_quantity'] = $this->language->get('column_quantity');
$data['column_price'] = $this->language->get('column_price');
$data['column_total'] = $this->language->get('column_total');
$data['column_action'] = $this->language->get('column_action');
$data['column_date_added'] = $this->language->get('column_date_added');
$data['column_status'] = $this->language->get('column_status');
$data['column_comment'] = $this->language->get('column_comment');
$data['invoice_no'] = '';
if ($order_info['invoice_no']) {
$data['invoice_no'] = $order_info['invoice_prefix'] . $order_info['invoice_no'];
}
$data['order_id'] = $order_id;
$data['date_added'] = date($this->language->get('date_format_short'), strtotime($order_info['date_added']));
$format = '{firstname} {lastname}' . "\n" . '{company}' . "\n" . '{address_1}' . "\n" . '{address_2}' . "\n" . '{city} {postcode}' . "\n" . '{zone}' . "\n" . '{country}';
if ($order_info['payment_address_format']) {
$format = $order_info['payment_address_format'];
}
$find = array(
'{firstname}',
'{lastname}',
'{company}',
'{address_1}',
'{address_2}',
'{city}',
'{postcode}',
'{zone}',
'{zone_code}',
'{country}'
);
$replace = array(
'firstname' => $order_info['payment_firstname'],
'lastname' => $order_info['payment_lastname'],
'company' => $order_info['payment_company'],
'address_1' => $order_info['payment_address_1'],
'address_2' => $order_info['payment_address_2'],
'city' => $order_info['payment_city'],
'postcode' => $order_info['payment_postcode'],
'zone' => $order_info['payment_zone'],
'zone_code' => $order_info['payment_zone_code'],
'country' => $order_info['payment_country']
);
$data['payment_address'] = str_replace(array("\r\n", "\r", "\n"), '<br />', preg_replace(array("/\s\s+/", "/\r\r+/", "/\n\n+/"), '<br />', trim(str_replace($find, $replace, $format))));
$data['payment_method'] = $order_info['payment_method'];
$format = '{firstname} {lastname}' . "\n" . '{company}' . "\n" . '{address_1}' . "\n" . '{address_2}' . "\n" . '{city} {postcode}' . "\n" . '{zone}' . "\n" . '{country}';
if ($order_info['shipping_address_format']) {
$format = $order_info['shipping_address_format'];
}
$find = array(
'{firstname}',
'{lastname}',
'{company}',
'{address_1}',
'{address_2}',
'{city}',
'{postcode}',
'{zone}',
'{zone_code}',
'{country}'
);
$replace = array(
'firstname' => $order_info['shipping_firstname'],
'lastname' => $order_info['shipping_lastname'],
'company' => $order_info['shipping_company'],
'address_1' => $order_info['shipping_address_1'],
'address_2' => $order_info['shipping_address_2'],
'city' => $order_info['shipping_city'],
'postcode' => $order_info['shipping_postcode'],
'zone' => $order_info['shipping_zone'],
'zone_code' => $order_info['shipping_zone_code'],
'country' => $order_info['shipping_country']
);
$data['shipping_address'] = str_replace(array("\r\n", "\r", "\n"), '<br />', preg_replace(array("/\s\s+/", "/\r\r+/", "/\n\n+/"), '<br />', trim(str_replace($find, $replace, $format))));
$data['shipping_method'] = $order_info['shipping_method'];
$this->load->model('catalog/product');
$this->load->model('tool/upload');
// Products
$data['products'] = array();
$products = $this->model_account_order->getOrderProducts($this->request->get['order_id']);
foreach ($products as $product) {
$option_data = array();
$options = $this->model_account_order->getOrderOptions($this->request->get['order_id'], $product['order_product_id']);
foreach ($options as $option) {
$value = false;
if ($option['type'] == 'file') {
$upload_info = $this->model_tool_upload->getUploadByCode($option['value']);
if ($upload_info) {
$value = $upload_info['name'];
}
}
if (! $value) {
$value = $option['value'];
}
$option_data[] = array(
'name' => $option['name'],
'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value)
);
}
$product_info = $this->model_catalog_product->getProduct($product['product_id']);
$data['products'][] = array(
'name' => $product['name'],
'model' => $product['model'],
'option' => $option_data,
'quantity' => $product['quantity'],
'price' => $this->currency->format($product['price'] + ($this->config->get('config_tax') ? $product['tax'] : 0), $order_info['currency_code'], $order_info['currency_value']),
'total' => $this->currency->format($product['total'] + ($this->config->get('config_tax') ? ($product['tax'] * $product['quantity']) : 0), $order_info['currency_code'], $order_info['currency_value'])
);
}
// Voucher
$data['vouchers'] = array();
$vouchers = $this->model_account_order->getOrderVouchers($this->request->get['order_id']);
foreach ($vouchers as $voucher) {
$data['vouchers'][] = array(
'description' => $voucher['description'],
'amount' => $this->currency->format($voucher['amount'], $order_info['currency_code'], $order_info['currency_value'])
);
}
// Totals
$data['totals'] = array();
$totals = $this->model_account_order->getOrderTotals($this->request->get['order_id']);
foreach ($totals as $total) {
$data['totals'][] = array(
'title' => $total['title'],
'text' => $this->currency->format($total['value'], $order_info['currency_code'], $order_info['currency_value']),
);
}
$data['comment'] = nl2br($order_info['comment']);
if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/receipt.tpl')) {
return $this->load->view($this->config->get('config_template') . '/template/module/receipt.tpl', $data);
} else {
return $this->load->view('default/template/module/receipt.tpl', $data);
}
}
}
}
TEMPLATE:
Next let's create the template in catalog/views/theme/default/module/receipt.tpl
<table class="table table-bordered table-hover">
<thead>
<tr>
<td class="text-left" colspan="2"><?= $text_order_detail; ?></td>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left" style="width: 50%;"><?php if ($invoice_no): ?>
<b><?= $text_invoice_no; ?></b> <?= $invoice_no; ?><br />
<?php endif; ?>
<b><?= $text_order_id; ?></b> #<?= $order_id; ?><br />
<b><?= $text_date_added; ?></b> <?= $date_added; ?></td>
<td class="text-left"><?php if ($payment_method): ?>
<b><?= $text_payment_method; ?></b> <?= $payment_method; ?><br />
<?php endif; ?>
<?php if ($shipping_method): ?>
<b><?= $text_shipping_method; ?></b> <?= $shipping_method; ?>
<?php endif; ?></td>
</tr>
</tbody>
</table>
<table class="table table-bordered table-hover">
<thead>
<tr>
<td class="text-left" style="width: 50%;"><?= $text_payment_address; ?></td>
<?php if ($shipping_address): ?>
<td class="text-left"><?= $text_shipping_address; ?></td>
<?php endif; ?>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left"><?= $payment_address; ?></td>
<?php if ($shipping_address): ?>
<td class="text-left"><?= $shipping_address; ?></td>
<?php endif; ?>
</tr>
</tbody>
</table>
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<td class="text-left"><?= $column_name; ?></td>
<td class="text-left"><?= $column_model; ?></td>
<td class="text-right"><?= $column_quantity; ?></td>
<td class="text-right"><?= $column_price; ?></td>
<td class="text-right"><?= $column_total; ?></td>
<?php if ($products): ?>
<td style="width: 20px;"></td>
<?php endif; ?>
</tr>
</thead>
<tbody>
<?php foreach ($products as $product): ?>
<tr>
<td class="text-left"><?= $product['name']; ?>
<?php foreach ($product['option'] as $option): ?>
<br />
<small> - <?= $option['name']; ?>: <?= $option['value']; ?></small>
<?php endforeach; ?></td>
<td class="text-left"><?= $product['model']; ?></td>
<td class="text-right"><?= $product['quantity']; ?></td>
<td class="text-right"><?= $product['price']; ?></td>
<td class="text-right"><?= $product['total']; ?></td>
<td class="text-right" style="white-space: nowrap;"><?php if ($product['reorder']): ?>
<i class="fa fa-shopping-cart"></i>
<?php endif; ?>
<i class="fa fa-reply"></i></td>
</tr>
<?php endforeach; ?>
<?php foreach ($vouchers as $voucher): ?>
<tr>
<td class="text-left"><?= $voucher['description']; ?></td>
<td class="text-left"></td>
<td class="text-right">1</td>
<td class="text-right"><?= $voucher['amount']; ?></td>
<td class="text-right"><?= $voucher['amount']; ?></td>
<?php if ($products): ?>
<td></td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<?php foreach ($totals as $total): ?>
<tr>
<td colspan="3"></td>
<td class="text-right"><b><?= $total['title']; ?></b></td>
<td class="text-right"><?= $total['text']; ?></td>
<?php if ($products): ?>
<td></td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
</tfoot>
</table>
</div>
<?php if ($comment): ?>
<table class="table table-bordered table-hover">
<thead>
<tr>
<td class="text-left"><?= $text_comment; ?></td>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left"><?= $comment; ?></td>
</tr>
</tbody>
</table>
<?php endif; ?>
Once again, if using your own theme you'll need to adjust this.
ADD MODULE TO CHECKOUT SUCCESS
Back in the checkout success controller we need to add the module.
Find $data['content_bottom'] = $this->load->controller('common/content_bottom');
After that line add this:
$data['receipt'] = false;
if ($order_id) {
$data['receipt'] = $this->load->controller('module/receipt', array('order_id' => $order_id));
}
ADD TO SUCCESS TEMPLATE
Open catalog/view/theme/default/common/success.tpl
After <?php echo $text_message; ?> add:
<?php if ($receipt): ?>
<?= $receipt; ?>
<?php endif; ?>
And that should be it. Once again it's best to add the changes to core files via a modification, but by creating your own module it's MUCH easier to add a modification, much less to deal with.
I haven't tested the code above but it should work or have minimal errors. Feel free to post any errors and I'll be happy to help fix them.
The awesome code that Vince post works!
But I found some Errors and PHP Notices and product table was not showing up, so i did some modifications in the code and it works 100% now.
I used the OPTION 2 and Opencart 2.2 for the tests.
Here is the code:
Receipit.php in CONTROLLER/MODULE
<?php
/**
* Controller class for displaying a receipt on checkout success.
*/
class ControllerModuleReceipt extends Controller
{
/**
* Replicates the ControllerAccountOrder::info
* method for displaying order info in our
* ControllerCheckoutSuccess::index method
*
* #param int $order_id our order id
* #return mixed receipt view
*/
public function index($setting)
{
$this->load->language('account/order');
$this->load->model('account/order');
if (empty($setting['order_id'])) {
return;
}
$order_id = $setting['order_id'];
$order_info = $this->model_account_order->getOrder($order_id);
if ($order_info) {
$data['text_order_detail'] = $this->language->get('text_order_detail');
$data['text_invoice_no'] = $this->language->get('text_invoice_no');
$data['text_order_id'] = $this->language->get('text_order_id');
$data['text_date_added'] = $this->language->get('text_date_added');
$data['text_shipping_method'] = $this->language->get('text_shipping_method');
$data['text_shipping_address'] = $this->language->get('text_shipping_address');
$data['text_payment_method'] = $this->language->get('text_payment_method');
$data['text_payment_address'] = $this->language->get('text_payment_address');
$data['text_history'] = $this->language->get('text_history');
$data['text_comment'] = $this->language->get('text_comment');
$data['column_name'] = $this->language->get('column_name');
$data['column_model'] = $this->language->get('column_model');
$data['column_quantity'] = $this->language->get('column_quantity');
$data['column_price'] = $this->language->get('column_price');
$data['column_total'] = $this->language->get('column_total');
$data['column_action'] = $this->language->get('column_action');
$data['column_date_added'] = $this->language->get('column_date_added');
$data['column_status'] = $this->language->get('column_status');
$data['column_comment'] = $this->language->get('column_comment');
$data['invoice_no'] = '';
if ($order_info['invoice_no']) {
$data['invoice_no'] = $order_info['invoice_prefix'] . $order_info['invoice_no'];
}
$data['order_id'] = $order_id;
$data['date_added'] = date($this->language->get('date_format_short'), strtotime($order_info['date_added']));
$format = '{firstname} {lastname}' . "\n" . '{company}' . "\n" . '{address_1}' . "\n" . '{address_2}' . "\n" . '{city} {postcode}' . "\n" . '{zone}' . "\n" . '{country}';
if ($order_info['payment_address_format']) {
$format = $order_info['payment_address_format'];
}
$find = array(
'{firstname}',
'{lastname}',
'{company}',
'{address_1}',
'{address_2}',
'{city}',
'{postcode}',
'{zone}',
'{zone_code}',
'{country}'
);
$replace = array(
'firstname' => $order_info['payment_firstname'],
'lastname' => $order_info['payment_lastname'],
'company' => $order_info['payment_company'],
'address_1' => $order_info['payment_address_1'],
'address_2' => $order_info['payment_address_2'],
'city' => $order_info['payment_city'],
'postcode' => $order_info['payment_postcode'],
'zone' => $order_info['payment_zone'],
'zone_code' => $order_info['payment_zone_code'],
'country' => $order_info['payment_country']
);
$data['payment_address'] = str_replace(array("\r\n", "\r", "\n"), '<br />', preg_replace(array("/\s\s+/", "/\r\r+/", "/\n\n+/"), '<br />', trim(str_replace($find, $replace, $format))));
$data['payment_method'] = $order_info['payment_method'];
$format = '{firstname} {lastname}' . "\n" . '{company}' . "\n" . '{address_1}' . "\n" . '{address_2}' . "\n" . '{city} {postcode}' . "\n" . '{zone}' . "\n" . '{country}';
if ($order_info['shipping_address_format']) {
$format = $order_info['shipping_address_format'];
}
$find = array(
'{firstname}',
'{lastname}',
'{company}',
'{address_1}',
'{address_2}',
'{city}',
'{postcode}',
'{zone}',
'{zone_code}',
'{country}'
);
$replace = array(
'firstname' => $order_info['shipping_firstname'],
'lastname' => $order_info['shipping_lastname'],
'company' => $order_info['shipping_company'],
'address_1' => $order_info['shipping_address_1'],
'address_2' => $order_info['shipping_address_2'],
'city' => $order_info['shipping_city'],
'postcode' => $order_info['shipping_postcode'],
'zone' => $order_info['shipping_zone'],
'zone_code' => $order_info['shipping_zone_code'],
'country' => $order_info['shipping_country']
);
$data['shipping_address'] = str_replace(array("\r\n", "\r", "\n"), '<br />', preg_replace(array("/\s\s+/", "/\r\r+/", "/\n\n+/"), '<br />', trim(str_replace($find, $replace, $format))));
$data['shipping_method'] = $order_info['shipping_method'];
$this->load->model('catalog/product');
$this->load->model('tool/upload');
// Products
$data['products'] = array();
$products = $this->model_account_order->getOrderProducts($order_id);
foreach ($products as $product) {
$option_data = array();
$options = $this->model_account_order->getOrderOptions($order_id, $product['order_product_id']);
foreach ($options as $option) {
$value = false;
if ($option['type'] == 'file') {
$upload_info = $this->model_tool_upload->getUploadByCode($option['value']);
if ($upload_info) {
$value = $upload_info['name'];
}
}
if (! $value) {
$value = $option['value'];
}
$option_data[] = array(
'name' => $option['name'],
'value' => (utf8_strlen($value) > 20 ? utf8_substr($value, 0, 20) . '..' : $value)
);
}
$product_info = $this->model_catalog_product->getProduct($product['product_id']);
$data['products'][] = array(
'name' => $product['name'],
'model' => $product['model'],
'option' => $option_data,
'quantity' => $product['quantity'],
'price' => $this->currency->format($product['price'] + ($this->config->get('config_tax') ? $product['tax'] : 0), $order_info['currency_code'], $order_info['currency_value']),
'total' => $this->currency->format($product['total'] + ($this->config->get('config_tax') ? ($product['tax'] * $product['quantity']) : 0), $order_info['currency_code'], $order_info['currency_value'])
);
}
// Voucher
$data['vouchers'] = array();
$vouchers = $this->model_account_order->getOrderVouchers($order_id);
foreach ($vouchers as $voucher) {
$data['vouchers'][] = array(
'description' => $voucher['description'],
'amount' => $this->currency->format($voucher['amount'], $order_info['currency_code'], $order_info['currency_value'])
);
}
// Totals
$data['totals'] = array();
$totals = $this->model_account_order->getOrderTotals($order_id);
foreach ($totals as $total) {
$data['totals'][] = array(
'title' => $total['title'],
'text' => $this->currency->format($total['value'], $order_info['currency_code'], $order_info['currency_value']),
);
}
$data['comment'] = nl2br($order_info['comment']);
if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/receipt.tpl')) {
return $this->load->view($this->config->get('config_template') . '/template/module/receipt.tpl', $data);
} else {
return $this->load->view('/module/receipt.tpl', $data);
}
}
}
}
Receipit.tpl in TEMPLATES/MODULE
<table class="table table-bordered table-hover">
<thead>
<tr>
<td class="text-left" colspan="2"><?= $text_order_detail; ?></td>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left" style="width: 50%;"><?php if ($invoice_no): ?>
<b><?= $text_invoice_no; ?></b> <?= $invoice_no; ?><br />
<?php endif; ?>
<b><?= $text_order_id; ?></b> #<?= $order_id; ?><br />
<b><?= $text_date_added; ?></b> <?= $date_added; ?></td>
<td class="text-left"><?php if ($payment_method): ?>
<b><?= $text_payment_method; ?></b> <?= $payment_method; ?><br />
<?php endif; ?>
<?php if ($shipping_method): ?>
<b><?= $text_shipping_method; ?></b> <?= $shipping_method; ?>
<?php endif; ?></td>
</tr>
</tbody>
</table>
<table class="table table-bordered table-hover">
<thead>
<tr>
<td class="text-left" style="width: 50%;"><?= $text_payment_address; ?></td>
<?php if ($shipping_address): ?>
<td class="text-left"><?= $text_shipping_address; ?></td>
<?php endif; ?>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left"><?= $payment_address; ?></td>
<?php if ($shipping_address): ?>
<td class="text-left"><?= $shipping_address; ?></td>
<?php endif; ?>
</tr>
</tbody>
</table>
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<td class="text-left" style="display: table-cell"><?= $column_name; ?></td>
<td class="text-left" style="display: none"><?= $column_model; ?></td>
<td class="text-right" style="display: table-cell"><?= $column_quantity; ?></td>
<td class="text-right" style="display: table-cell"><?= $column_price; ?></td>
<td class="text-right" style="display: table-cell"><?= $column_total; ?></td>
</tr>
</thead>
<tbody>
<?php foreach ($products as $product): ?>
<tr>
<td class="text-left" style="display: table-cell"><?= $product['name']; ?>
<?php foreach ($product['option'] as $option): ?>
<br />
<small> - <?= $option['name']; ?>: <?= $option['value']; ?></small>
<?php endforeach; ?></td>
<td class="text-left" style="display: none"><?= $product['model']; ?></td>
<td class="text-right" style="display: table-cell"><?= $product['quantity']; ?></td>
<td class="text-right" style="display: table-cell"><?= $product['price']; ?></td>
<td class="text-right" style="display: table-cell"><?= $product['total']; ?></td>
</tr>
<?php endforeach; ?>
<?php foreach ($vouchers as $voucher): ?>
<tr>
<td class="text-left"><?= $voucher['description']; ?></td>
<td class="text-left"></td>
<td class="text-right">1</td>
<td class="text-right"><?= $voucher['amount']; ?></td>
<td class="text-right"><?= $voucher['amount']; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<?php foreach ($totals as $total): ?>
<tr>
<td colspan="2"></td>
<td class="text-right"><b><?= $total['title']; ?></b></td>
<td class="text-right"><?= $total['text']; ?></td>
</tr>
<?php endforeach; ?>
</tfoot>
</table>
</div>
<?php if ($comment): ?>
<table class="table table-bordered table-hover">
<thead>
<tr>
<td class="text-left"><?= $text_comment; ?></td>
</tr>
</thead>
<tbody>
<tr>
<td class="text-left"><?= $comment; ?></td>
</tr>
</tbody>
</table>
<?php endif; ?>
NOTE
Before entering the codes in your store, test on a backup to make sure that your store will not be impaired.
If this code has any flaws, please let me know here
Thanks!
I've been trying for ages to simply calculate the "weight" field we have added to an invoice plugin called sliced invoices. All I need is for it to total the weight based on the value in the table.
The weight field has the div class, "adjust". Here's a link to the forms PDF and you'll see the empty table field - Weight. http://cavcon.co.za/sliced_quote/346-2/?create=pdf&id=346&print_pdf=8d39bfe988
Here's the code I'm working with:
<?php
$count = 0;
$items = sliced_get_invoice_line_items(); // gets quote and invoice
if( !empty( $items ) ) :
foreach ( $items[0] as $item ) {
$class = ($count % 2 == 0) ? 'even' : 'odd';
$item_tax = isset( $item['tax'] ) ? $item['tax'] : 0;
$line_total = $shared->get_line_item_sub_total( $item['qty'], $item['amount']);
?>
<tr class="row_<?php echo $class; ?> sliced-item">
<td class="qty"><?php echo esc_html( $item['qty'] ); ?></td>
<td class="service"><?php echo esc_html( isset( $item['title'] ) ? $item['title'] : '' ); ?>
<?php if ( isset( $item['description'] ) ) : ?>
<br/><span class="description"><?php echo esc_html( $item['description']); ?></span>
<?php endif; ?>
</td>
<td class="rate"><?php echo esc_html( $shared->get_formatted_currency( $item['amount'] ) ); ?></td>
<?php if ( sliced_hide_adjust_field() === false) { ?>
<td class="adjust"><?php echo esc_html( $item_tax ? $item['tax'] . 'kg' : '-' ); ?></td>
<?php } ?>
<td class="total"><?php echo esc_html( $shared->get_formatted_currency( $line_total ) ); ?></td>
</tr>
<?php $count++;
}
endif; ?>
</tbody>
</table>
<?php
}
endif;
if ( ! function_exists( 'sliced_display_invoice_totals' ) ) :
function sliced_display_invoice_totals() { ?>
<table class="table table-sm table-bordered" id="new-table">
<tbody>
<?php do_action( 'sliced_invoice_before_totals' ); ?>
<tr class="row-sub-total">
<td class="rate"><?php echo _e( 'Total Weight', 'sliced-invoices' ); ?></td>
<td class="total-weight"><?php echo esc_html( $item['weight'] ); ?>
</td>
</tr>
<tr class="row-sub-total">
<td class="rate"><?php echo _e( 'Sub Total', 'sliced-invoices' ); ?></td>
<td class="total"><?php echo esc_html( sliced_get_invoice_sub_total() ); ?></td>
</tr>
<tr class="row-tax">
<td class="rate"><?php echo esc_html( sliced_get_tax_name() ); ?></td>
<td class="total"><?php echo esc_html( sliced_get_invoice_tax() ); ?></td>
</tr>
<tr class="table-active row-total">
<td class="rate"><strong><?php echo _e( 'Total', 'sliced-invoices' ); ?></strong></td>
<td class="total"><strong><?php echo esc_html( sliced_get_invoice_total() ); ?></strong></td>
</tr>
<?php do_action( 'sliced_invoice_after_totals' ); ?>
</tbody>
</table>
<?php
}
endif;
THIS IS WHERE I'M AT
if ( ! function_exists( 'sliced_display_invoice_totals' ) ) :
$total_weight = 0;
foreach ( $items[0] as $item ) {
$total_weight = $total_weight + $item['tax'];
}
function sliced_display_invoice_totals() { ?>
<table class="table table-sm table-bordered" id="new-table">
<tbody>
<?php do_action( 'sliced_invoice_before_totals' ); ?>
<tr class="row-sub-total">
<td class="rate"><?php echo _e( 'Total Weight', 'sliced-
invoices' ); ?></td>
<td class="total-weight"><?php echo esc_html(
$total_weight . 'kg') ?>
</td>
If you run PHP version 5.5 or above, you can sum the weights in this way:
if( !empty( $items ) ) :
foreach ( $items[0] as $item ) {
(...)
}
$total_weight = array_sum( array_column( $items, 'tax' ) );
endif; ?>
Otherwise, you have to increment $total_weight inside foreach loop:
$total_weight = 0;
foreach ( $items[0] as $item ) {
$total_weight = $total_weight + $item['tax'];
(...)
}
If you output total weight in the same scope of above script, simply put echo $total_weight; where you want to print it (or echo esc_html( $total_weight . 'kg');, according with your other prints).
But maybe your totals is output through sliced_display_invoice_totals function (although I don't see any call to this function in your code); in this case, the $total_weight variable is not directly available in the function, due to different scope. You have to print it in this way:
function sliced_display_invoice_totals() { ?>
(...)
echo $GLOBALS['total_weight']; // or echo esc_html( $GLOBALS['total_weight'] . 'kg');
(...)
}
Pleae careful note:
In your code, the function sliced_display_invoice_totals declaration is prepended by condition if ( ! function_exists( 'sliced_display_invoice_totals' ) ): this means that, if the function is already defined, your function modification will be ignored: in this case, you have to modify the already declare function instead.
To see if the function is already declared, place this temporary code before if condition:
if( function_exists( 'sliced_display_invoice_totals' ) )
{
$reflFunc = new ReflectionFunction( 'sliced_display_invoice_totals' );
die( $reflFunc->getFileName() . ':' . $reflFunc->getStartLine() );
}
In this way you can see the filePath and line in which the function is defined and modify it.
See more about array_sum
See more about array_column
See more about Variables scope
See more about Reflection class
Here is a list of things to change:
1. Unpaired HTML tags
The code in your question does not include the <table> nor <tbody> tags which you later close. I assume they are present in your original code.
2. Unpaired braces
Maybe also just an error while drafting your question, but after the </table> there is a closing PHP } and endif which have no matching opening statements.
3. Use of _e
According to the documentation of _e() on wordpress.org:
Displays the returned translated text from translate()
[...]
This function does not return a value.
So you are not supposed to write echo _e(...), you should just write _e(...) instead.
4. Function sliced_display_invoice_totals
You define this function that displays the totals, but you never call it. If you intend to display that table then do just that, without function definition.
5. When $items is empty
You have a condition so that the first table is only produced when $items is not empty. However, the totals table is produced outside that context, so it would also be produced when $items is empty. This might not be what you want. Consider moving the code for the second table inside that if block.
6. Mixed use of normal and alternative syntax
You use often the : ... endif syntax, which can indeed be helpful to read code that is interrupted by HTML code. But you don't use it consistently. I suggest using it for all if statements and for the foreach construct as well.
7. Calculate and display the $total_weight
Inside your existing foreach loop, add the weight of each line to $total_weight. You must also initialise this value just before starting the loop with 0.
Then in the second table display that $total_weight with the same format as you display the individual weights in the first table.
Here is the code that has all of the above applied:
<table class="table table-sm table-bordered" id="detail-table">
<tbody>
<?php
$count = 0;
$items = sliced_get_invoice_line_items(); // gets quote and invoice
// *** add this line ***
$total_weight = 0;
if( !empty( $items ) ) :
foreach ( $items[0] as $item ) :
$class = ($count % 2 == 0) ? 'even' : 'odd';
$item_tax = isset( $item['tax'] ) ? $item['tax'] : 0;
// *** add this line ***
$total_weight += $item_tax;
$line_total = $shared->get_line_item_sub_total( $item['qty'], $item['amount']);
?>
<tr class="row_<?php echo $class; ?> sliced-item">
<td class="qty"><?php echo esc_html( $item['qty'] ); ?></td>
<td class="service"><?php echo esc_html( isset( $item['title'] ) ? $item['title'] : '' ); ?>
<?php if ( isset( $item['description'] ) ) :
?> <br/><span class="description"><?php echo esc_html( $item['description']); ?></span>
<?php endif;
?> </td>
<td class="rate"><?php echo esc_html( $shared->get_formatted_currency( $item['amount'] ) ); ?></td>
<?php if ( sliced_hide_adjust_field() === false) :
?> <td class="adjust"><?php echo esc_html( $item_tax ? $item['tax'] . 'kg' : '-' ); ?></td>
<?php endif;
?>
<td class="total"><?php echo esc_html( $shared->get_formatted_currency( $line_total ) ); ?></td>
</tr>
<?php $count++;
endforeach; // use consistent syntax (alternative)
?>
</tbody>
</table>
<?php
// **** Remove the IF and the FUNCTION. You want to execute this now. ***
?>
<table class="table table-sm table-bordered" id="new-table">
<tbody>
<?php do_action( 'sliced_invoice_before_totals' ); ?>
<tr class="row-sub-total">
<td class="rate"><?php _e( 'Total Weight', 'sliced-invoices' ); ?></td>
<td class="total-weight"><?php echo esc_html( $total_weight ? $total_weight . 'kg' : '-' ); ?></td>
</tr>
<tr class="row-sub-total">
<td class="rate"><?php _e( 'Sub Total', 'sliced-invoices' ); ?></td>
<td class="total"><?php echo esc_html( sliced_get_invoice_sub_total() ); ?></td>
</tr>
<tr class="row-tax">
<td class="rate"><?php echo esc_html( sliced_get_tax_name() ); ?></td>
<td class="total"><?php echo esc_html( sliced_get_invoice_tax() ); ?></td>
</tr>
<tr class="table-active row-total">
<td class="rate"><strong><?php _e( 'Total', 'sliced-invoices' ); ?></strong></td>
<td class="total"><strong><?php echo esc_html( sliced_get_invoice_total() ); ?></strong></td>
</tr>
<?php do_action( 'sliced_invoice_after_totals' ); ?>
</tbody>
</table>
<?php
// **** Consider closing the if (!empty($items)) here ***
endif;
?>
You did not specify the code for the many functions you call, like sliced_get_tax_name, sliced_get_invoice_tax,... etc. Unless there is a problem with any of these functions, the above code should work.