mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-25 00:44:03 -04:00
Compare commits
5 Commits
master
...
fix/pr-430
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d71b69f6d8 | ||
|
|
46185a6d44 | ||
|
|
50fd9d5da0 | ||
|
|
22e3548fea | ||
|
|
fe6601b351 |
@@ -137,6 +137,26 @@ class Items extends Secure_Controller
|
||||
echo json_encode(['total' => $total_rows, 'rows' => $data_rows]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to serve images with proper headers
|
||||
* @param string $imagePath
|
||||
* @return void
|
||||
*/
|
||||
private function serveImage(string $imagePath): void
|
||||
{
|
||||
if (!file_exists($imagePath)) {
|
||||
$this->response->setStatusCode(404);
|
||||
$this->response->send();
|
||||
return;
|
||||
}
|
||||
|
||||
$mimeType = mime_content_type($imagePath);
|
||||
$this->response->setContentType($mimeType);
|
||||
$this->response->setHeader('Content-Length', filesize($imagePath));
|
||||
$this->response->setBody(file_get_contents($imagePath));
|
||||
$this->response->send();
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX function. Processes thumbnail of image. Called via tabular_helper
|
||||
* @param string $pic_filename
|
||||
@@ -147,27 +167,54 @@ class Items extends Secure_Controller
|
||||
{
|
||||
helper('file');
|
||||
|
||||
$file_extension = pathinfo($pic_filename, PATHINFO_EXTENSION);
|
||||
$images = glob("./uploads/item_pics/$pic_filename");
|
||||
$base_path = './uploads/item_pics/' . pathinfo($pic_filename, PATHINFO_FILENAME);
|
||||
$fileExtension = pathinfo($pic_filename, PATHINFO_EXTENSION);
|
||||
$uploadPath = FCPATH . 'uploads/item_pics/';
|
||||
|
||||
$images = empty($fileExtension)
|
||||
? glob($uploadPath . $pic_filename . '.*')
|
||||
: glob($uploadPath . $pic_filename);
|
||||
|
||||
if (sizeof($images) > 0) {
|
||||
$image_path = $images[0];
|
||||
$thumb_path = $base_path . "_thumb.$file_extension";
|
||||
$imagePath = $images[0];
|
||||
$actualExtension = pathinfo($imagePath, PATHINFO_EXTENSION);
|
||||
$basePath = $uploadPath . pathinfo($pic_filename, PATHINFO_FILENAME);
|
||||
$thumbPath = $basePath . "_thumb.$actualExtension";
|
||||
|
||||
if (sizeof($images) < 2 && !file_exists($thumb_path)) {
|
||||
$image = Services::image('gd2');
|
||||
$image->withFile($image_path)
|
||||
->resize(52, 32, true, 'height')
|
||||
->save($thumb_path);
|
||||
// Try to create thumbnail if it doesn't exist
|
||||
if (!file_exists($thumbPath)) {
|
||||
try {
|
||||
$image = Services::image('gd2');
|
||||
$image->withFile($imagePath)
|
||||
->resize(52, 32, true, 'height')
|
||||
->save($thumbPath);
|
||||
} catch (Exception $e) {
|
||||
// If thumbnail creation fails, serve original image
|
||||
log_message('error', 'Thumbnail creation failed: ' . $e->getMessage());
|
||||
$this->serveImage($imagePath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->setContentType(mime_content_type($thumb_path));
|
||||
$this->response->setBody(file_get_contents($thumb_path));
|
||||
$this->response->send();
|
||||
// Serve thumbnail if it exists, otherwise serve original
|
||||
if (file_exists($thumbPath)) {
|
||||
$this->serveImage($thumbPath);
|
||||
} else {
|
||||
$this->serveImage($imagePath);
|
||||
}
|
||||
} else {
|
||||
// No image found, serve default
|
||||
$defaultImage = FCPATH . 'public/images/no-img.png';
|
||||
if (file_exists($defaultImage)) {
|
||||
$this->serveImage($defaultImage);
|
||||
} else {
|
||||
// Return 404 if no default image
|
||||
$this->response->setStatusCode(404);
|
||||
$this->response->send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gives search suggestions based on what is being searched for
|
||||
* @noinspection PhpUnused
|
||||
|
||||
@@ -461,18 +461,36 @@ function get_item_data_row(object $item): array
|
||||
|
||||
$controller = get_controller();
|
||||
|
||||
$image = null;
|
||||
if (!empty($item->pic_filename)) {
|
||||
$ext = pathinfo($item->pic_filename, PATHINFO_EXTENSION);
|
||||
|
||||
$images = $ext == ''
|
||||
? glob("./uploads/item_pics/$item->pic_filename.*")
|
||||
: glob("./uploads/item_pics/$item->pic_filename");
|
||||
|
||||
if (sizeof($images) > 0) {
|
||||
$image .= '<a class="rollover" href="' . base_url($images[0]) . '"><img alt="Image thumbnail" src="' . site_url('items/PicThumb/' . pathinfo($images[0], PATHINFO_BASENAME)) . '"></a>';
|
||||
}
|
||||
|
||||
$image = '';
|
||||
if (!empty($item->pic_filename)) {
|
||||
$uploadPath = FCPATH . 'uploads/item_pics/';
|
||||
$ext = pathinfo($item->pic_filename, PATHINFO_EXTENSION);
|
||||
|
||||
// If no extension in filename, search for any file with that name
|
||||
if (empty($ext)) {
|
||||
$pattern = $uploadPath . $item->pic_filename . '.*';
|
||||
} else {
|
||||
$pattern = $uploadPath . $item->pic_filename;
|
||||
}
|
||||
|
||||
$images = glob($pattern);
|
||||
|
||||
if (!empty($images)) {
|
||||
$relPath = 'uploads/item_pics/' . basename($images[0]);
|
||||
|
||||
// Use direct image path instead of getPicThumb
|
||||
$image = '<a class="rollover" href="' . base_url($relPath) . '">
|
||||
<img src="' . base_url($relPath) . '"
|
||||
onerror="this.src=\''.base_url('public/images/no-img.png').'\';this.onerror=null;"
|
||||
style="max-width:40px;max-height:40px; object-fit: cover;">
|
||||
</a>';
|
||||
} else {
|
||||
$image = '<img src="'.base_url('public/images/no-img.png').'" style="max-width:40px;max-height:40px;">';
|
||||
}
|
||||
} else {
|
||||
$image = '<img src="'.base_url('public/images/no-img.png').'" style="max-width:40px;max-height:40px;">';
|
||||
}
|
||||
|
||||
if ($config['multi_pack_enabled']) {
|
||||
$item->name .= NAME_SEPARATOR . $item->pack_name;
|
||||
|
||||
@@ -341,7 +341,8 @@ class Receiving_lib
|
||||
'price' => $price,
|
||||
'receiving_quantity' => $receivingQuantity,
|
||||
'receiving_quantity_choices' => $receivingQuantityChoices,
|
||||
'total' => $this->get_item_total($quantity, $price, $discount, $discountType, $receivingQuantity)
|
||||
'total' => $this->get_item_total($quantity, $price, $discount, $discountType, $receivingQuantity),
|
||||
'pic_filename' => $itemInfo->pic_filename,
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
@@ -1097,7 +1097,8 @@ class Sale_lib
|
||||
'stock_type' => $stock_type,
|
||||
'item_type' => $item_type,
|
||||
'hsn_code' => $item_info->hsn_code,
|
||||
'tax_category_id' => $item_info->tax_category_id
|
||||
'tax_category_id' => $item_info->tax_category_id,
|
||||
'pic_filename' => $item_info->pic_filename,
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
@@ -63,7 +63,8 @@ use App\Models\Employee;
|
||||
onLoadSuccess: function(response) {
|
||||
$('a.rollover').imgPreview({
|
||||
imgCSS: {
|
||||
width: 200
|
||||
width: 200,
|
||||
|
||||
},
|
||||
distanceFromCursor: {
|
||||
top: 10,
|
||||
@@ -124,7 +125,7 @@ use App\Models\Employee;
|
||||
</div>
|
||||
|
||||
<div id="table_holder">
|
||||
<table id="table"></table>
|
||||
<table id="table" style="padding:10px;"></table>
|
||||
</div>
|
||||
|
||||
<?= view('partial/footer') ?>
|
||||
|
||||
@@ -27,6 +27,9 @@ if (isset($error_message)) {
|
||||
echo view('partial/print_receipt', ['print_after_sale', $print_after_sale, 'selected_printer' => 'receipt_printer']) ?>
|
||||
|
||||
<div class="print_hide" id="control_buttons" style="text-align: right;">
|
||||
<button type="button" class="btn btn-warning btn-sm receipt-avatar-toggle-btn" id="toggle_avatar_button">
|
||||
<span class="glyphicon glyphicon-picture"> </span><span id="avatar_toggle_text">Hide Avatar</span>
|
||||
</button>
|
||||
<a href="javascript:printdoc();">
|
||||
<div class="btn btn-info btn-sm" id="show_print_button"><?= '<span class="glyphicon glyphicon-print"> </span>' . lang('Common.print') ?></div>
|
||||
</a>
|
||||
@@ -64,41 +67,49 @@ echo view('partial/print_receipt', ['print_after_sale', $print_after_sale, 'sele
|
||||
|
||||
<table id="receipt_items">
|
||||
<tr>
|
||||
<th style="width: 40%;"><?= lang('Items.item') ?></th>
|
||||
<th class="receipt-avatar-column" style="width: 15%;"><?= lang('Items.image') ?></th>
|
||||
<th style="width: 35%;"><?= lang('Items.item') ?></th>
|
||||
<th style="width: 20%;"><?= lang('Common.price') ?></th>
|
||||
<th style="width: 20%;"><?= lang('Sales.quantity') ?></th>
|
||||
<th style="width: 15%;"><?= lang('Sales.quantity') ?></th>
|
||||
<th style="width: 15%; text-align: right;"><?= lang('Sales.total') ?></th>
|
||||
</tr>
|
||||
|
||||
<?php foreach (array_reverse($cart, true) as $line => $item) { ?>
|
||||
<tr>
|
||||
<td class="receipt-avatar-column">
|
||||
|
||||
<?php if (!empty($item['pic_filename'])): ?>
|
||||
<img src="<?= base_url('uploads/item_pics/' . esc($item['pic_filename'], 'url')) ?>" alt="avatar" style="height:40px;max-width:40px;">
|
||||
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= esc($item['name'] . ' ' . $item['attribute_values']) ?></td>
|
||||
<td><?= to_currency($item['price']) ?></td>
|
||||
<td><?= to_quantity_decimals($item['quantity']) . ' ' . ($show_stock_locations ? ' [' . esc($item['stock_name']) . ']' : '') ?> x <?= $item['receiving_quantity'] != 0 ? to_quantity_decimals($item['receiving_quantity']) : 1 ?></td>
|
||||
<td><div class="total-value"><?= to_currency($item['total']) ?></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?= esc($item['serialnumber']) ?></td>
|
||||
<td colspan="2"><?= esc($item['serialnumber']) ?></td>
|
||||
</tr>
|
||||
<?php if ($item['discount'] > 0) { ?>
|
||||
<tr>
|
||||
<?php if ($item['discount_type'] == FIXED) { ?>
|
||||
<td colspan="3" class="discount"><?= to_currency($item['discount']) . ' ' . lang('Sales.discount') ?></td>
|
||||
<td colspan="4" class="discount"><?= to_currency($item['discount']) . ' ' . lang('Sales.discount') ?></td>
|
||||
<?php } elseif ($item['discount_type'] == PERCENT) { ?>
|
||||
<td colspan="3" class="discount"><?= to_decimals($item['discount']) . ' ' . lang('Sales.discount_included') ?></td>
|
||||
<td colspan="4" class="discount"><?= to_decimals($item['discount']) . ' ' . lang('Sales.discount_included') ?></td>
|
||||
<?php } ?>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right; border-top: 2px solid #000000;"><?= lang('Sales.total') ?></td>
|
||||
<td colspan="4" style="text-align: right; border-top: 2px solid #000000;"><?= lang('Sales.total') ?></td>
|
||||
<td style="border-top: 2px solid #000000;">
|
||||
<div class="total-value"><?= to_currency($total) ?></div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ($mode != 'requisition') { ?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right;"><?= lang('Sales.payment') ?></td>
|
||||
<td colspan="4" style="text-align: right;"><?= lang('Sales.payment') ?></td>
|
||||
<td>
|
||||
<div class="total-value"><?= esc($payment_type) ?></div>
|
||||
</td>
|
||||
@@ -106,14 +117,14 @@ echo view('partial/print_receipt', ['print_after_sale', $print_after_sale, 'sele
|
||||
|
||||
<?php if (isset($amount_change)) { ?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right;"><?= lang('Sales.amount_tendered') ?></td>
|
||||
<td colspan="4" style="text-align: right;"><?= lang('Sales.amount_tendered') ?></td>
|
||||
<td>
|
||||
<div class="total-value"><?= to_currency($amount_tendered) ?></div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right;"><?= lang('Sales.change_due') ?></td>
|
||||
<td colspan="4" style="text-align: right;"><?= lang('Sales.change_due') ?></td>
|
||||
<td>
|
||||
<div class="total-value"><?= $amount_change ?></div>
|
||||
</td>
|
||||
@@ -132,4 +143,41 @@ echo view('partial/print_receipt', ['print_after_sale', $print_after_sale, 'sele
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// Avatar toggle functionality
|
||||
const STORAGE_KEY = 'avatarColumnVisible';
|
||||
|
||||
// Get saved state from localStorage, default to visible (true)
|
||||
let isAvatarVisible = localStorage.getItem(STORAGE_KEY) !== 'false';
|
||||
|
||||
// Apply initial state (also handle header visibility)
|
||||
updateAvatarVisibility(isAvatarVisible);
|
||||
|
||||
// Handle toggle button click
|
||||
$('#toggle_avatar_button').click(function(e) {
|
||||
e.preventDefault();
|
||||
isAvatarVisible = !isAvatarVisible;
|
||||
updateAvatarVisibility(isAvatarVisible);
|
||||
localStorage.setItem(STORAGE_KEY, isAvatarVisible);
|
||||
});
|
||||
|
||||
function updateAvatarVisibility(visible) {
|
||||
const $avatarElements = $('.receipt-avatar-column');
|
||||
const $toggleButton = $('#toggle_avatar_button');
|
||||
const $toggleText = $('#avatar_toggle_text');
|
||||
|
||||
if (visible) {
|
||||
$avatarElements.removeClass('hidden');
|
||||
$toggleButton.removeClass('active');
|
||||
$toggleText.text('Hide Avatar');
|
||||
} else {
|
||||
$avatarElements.addClass('hidden');
|
||||
$toggleButton.addClass('active');
|
||||
$toggleText.text('Show Avatar');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?= view('partial/footer') ?>
|
||||
|
||||
@@ -96,6 +96,11 @@ if (isset($success)) {
|
||||
<span class="glyphicon glyphicon-tag"> </span><?= lang('Sales.new_item') ?>
|
||||
</button>
|
||||
</li>
|
||||
<li class="pull-right">
|
||||
<button type="button" class="btn btn-warning btn-sm receipt-avatar-toggle-btn" id="toggle_avatar_button">
|
||||
<span class="glyphicon glyphicon-picture"> </span><span id="avatar_toggle_text">Hide Avatar</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -106,14 +111,15 @@ if (isset($success)) {
|
||||
<table class="sales_table_100" id="register">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 6%;" class="avatar-header"><?= lang('Items.image') ?></th>
|
||||
<th style="width: 5%;"><?= lang('Common.delete') ?></th>
|
||||
<th style="width: 15%;"><?= lang('Sales.item_number') ?></th>
|
||||
<th style="width: 23%;"><?= lang(ucfirst($controller_name) . '.item_name') ?></th>
|
||||
<th style="width: 12%;"><?= lang('Sales.item_number') ?></th>
|
||||
<th style="width: 20%;"><?= lang(ucfirst($controller_name) . '.item_name') ?></th>
|
||||
<th style="width: 10%;"><?= lang(ucfirst($controller_name) . '.cost') ?></th>
|
||||
<th style="width: 8%;"><?= lang(ucfirst($controller_name) . '.quantity') ?></th>
|
||||
<th style="width: 10%;"><?= lang(ucfirst($controller_name) . '.ship_pack') ?></th>
|
||||
<th style="width: 14%;"><?= lang(ucfirst($controller_name) . '.discount') ?></th>
|
||||
<th style="width: 10%;"><?= lang(ucfirst($controller_name) . '.total') ?></th>
|
||||
<th style="width: 12%;"><?= lang(ucfirst($controller_name) . '.discount') ?></th>
|
||||
<th style="width: 12%;"><?= lang(ucfirst($controller_name) . '.total') ?></th>
|
||||
<th style="width: 5%;"><?= lang(ucfirst($controller_name) . '.update') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -121,7 +127,7 @@ if (isset($success)) {
|
||||
<tbody id="cart_contents">
|
||||
<?php if (count($cart) == 0) { ?>
|
||||
<tr>
|
||||
<td colspan="9">
|
||||
<td colspan="10">
|
||||
<div class="alert alert-dismissible alert-info"><?= lang('Sales.no_items_in_cart') ?></div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -133,6 +139,13 @@ if (isset($success)) {
|
||||
<?= form_open("$controller_name/editItem/$line", ['class' => 'form-horizontal', 'id' => "cart_$line"]) ?>
|
||||
|
||||
<tr>
|
||||
<td class="avatar-column">
|
||||
|
||||
<?php if (!empty($item['pic_filename'])): ?>
|
||||
<img src="<?= base_url('uploads/item_pics/' . esc($item['pic_filename'], 'url')) ?>" alt="avatar" style="height:40px;max-width:40px;">
|
||||
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= anchor("$controller_name/deleteItem/$line", '<span class="glyphicon glyphicon-trash"></span>') ?></td>
|
||||
<td><?= esc($item['item_number']) ?></td>
|
||||
<td style="text-align: center;">
|
||||
@@ -207,7 +220,7 @@ if (isset($success)) {
|
||||
?>
|
||||
<td style="color: #2F4F4F;"><?= lang('Sales.description_abbrv') . ':' ?></td>
|
||||
<?php } ?>
|
||||
<td colspan="2" style="text-align: left;">
|
||||
<td colspan="3" style="text-align: left;">
|
||||
<?php
|
||||
if ($item['allow_alt_description'] == 1) { // TODO: ===?
|
||||
echo form_input([
|
||||
@@ -538,6 +551,25 @@ if (isset($success)) {
|
||||
$('#cart_' + $(this).attr('data-line')).submit();
|
||||
});
|
||||
|
||||
// Avatar toggle functionality
|
||||
const isAvatarVisible = localStorage.getItem('avatarColumnVisible') !== 'false';
|
||||
if (!isAvatarVisible) {
|
||||
$('.avatar-column').hide();
|
||||
$('.avatar-header').hide();
|
||||
$('#avatar_toggle_text').text('Show Avatar');
|
||||
}
|
||||
|
||||
$('#toggle_avatar_button').click(function(e) {
|
||||
e.preventDefault();
|
||||
const isVisible = $('.avatar-column').is(':visible');
|
||||
$('.avatar-column').toggle();
|
||||
$('.avatar-header').toggle();
|
||||
localStorage.setItem('avatarColumnVisible', !isVisible);
|
||||
$(this).toggleClass('active');
|
||||
var $toggleText = $('#avatar_toggle_text');
|
||||
$toggleText.text(isVisible ? 'Show Avatar' : 'Hide Avatar');
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -42,9 +42,49 @@ if (isset($error_message)) {
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// Avatar toggle functionality
|
||||
const STORAGE_KEY = 'avatarColumnVisible';
|
||||
|
||||
// Get saved state from localStorage, default to visible (true)
|
||||
let isAvatarVisible = localStorage.getItem(STORAGE_KEY) !== 'false';
|
||||
|
||||
// Apply initial state (also handle header visibility)
|
||||
updateAvatarVisibility(isAvatarVisible);
|
||||
|
||||
// Handle toggle button click
|
||||
$('#toggle_avatar_button').click(function(e) {
|
||||
e.preventDefault();
|
||||
isAvatarVisible = !isAvatarVisible;
|
||||
updateAvatarVisibility(isAvatarVisible);
|
||||
localStorage.setItem(STORAGE_KEY, isAvatarVisible);
|
||||
});
|
||||
|
||||
function updateAvatarVisibility(visible) {
|
||||
const $avatarElements = $('.receipt-avatar-column');
|
||||
const $toggleButton = $('#toggle_avatar_button');
|
||||
const $toggleText = $('#avatar_toggle_text');
|
||||
|
||||
if (visible) {
|
||||
$avatarElements.removeClass('hidden');
|
||||
$toggleButton.removeClass('active');
|
||||
$toggleText.text('Hide Avatar');
|
||||
} else {
|
||||
$avatarElements.addClass('hidden');
|
||||
$toggleButton.addClass('active');
|
||||
$toggleText.text('Show Avatar');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?= view('partial/print_receipt', ['print_after_sale' => $print_after_sale, 'selected_printer' => 'receipt_printer']) ?>
|
||||
|
||||
<div class="print_hide" id="control_buttons" style="text-align: right;">
|
||||
<button type="button" class="btn btn-warning btn-sm receipt-avatar-toggle-btn" id="toggle_avatar_button">
|
||||
<span class="glyphicon glyphicon-picture"> </span><span id="avatar_toggle_text">Hide Avatar</span>
|
||||
</button>
|
||||
<a href="javascript:printdoc();">
|
||||
<div class="btn btn-info btn-sm" id="show_print_button"><?= '<span class="glyphicon glyphicon-print"> </span>' . lang('Common.print') ?></div>
|
||||
</a>
|
||||
|
||||
@@ -50,13 +50,22 @@
|
||||
</div>
|
||||
|
||||
<table id="receipt_items">
|
||||
<?php
|
||||
// Calculate colspan for totals based on visible columns
|
||||
// Avatar(1) + Description(1) + Price(1) + Quantity(1) = 4 columns before Total
|
||||
// When avatar is hidden via CSS, we still need to account for it in colspan
|
||||
$item_colspan = 4; // avatar + description + price + quantity
|
||||
// Summary rows need to account for tax indicator column when enabled
|
||||
$summary_colspan = $item_colspan + ($config['receipt_show_tax_ind'] ? 1 : 0);
|
||||
?>
|
||||
<tr>
|
||||
<th class="receipt-avatar-column" style="width: 10%;"><?= lang('Items.image') ?></th>
|
||||
<th style="width: 40%;"><?= lang('Sales.description_abbrv') ?></th>
|
||||
<th style="width: 20%;"><?= lang('Sales.price') ?></th>
|
||||
<th style="width: 20%;"><?= lang('Sales.quantity') ?></th>
|
||||
<th style="width: 15%;"><?= lang('Sales.price') ?></th>
|
||||
<th style="width: 15%;"><?= lang('Sales.quantity') ?></th>
|
||||
<th style="width: 20%;" class="total-value"><?= lang('Sales.total') ?></th>
|
||||
<?php if ($config['receipt_show_tax_ind']) { ?>
|
||||
<th style="width: 20%;"></th>
|
||||
<th style="width: 10%;"></th>
|
||||
<?php } ?>
|
||||
</tr>
|
||||
<?php
|
||||
@@ -64,6 +73,12 @@
|
||||
if ($item['print_option'] == PRINT_YES) {
|
||||
?>
|
||||
<tr>
|
||||
<td class="receipt-avatar-column">
|
||||
<?php if (!empty($item['pic_filename'])): ?>
|
||||
<img src="<?= base_url('uploads/item_pics/' . esc($item['pic_filename'], 'url')) ?>" alt="avatar" style="height:40px;max-width:40px;">
|
||||
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= esc(ucfirst($item['name'] . ' ' . $item['attribute_values'])) ?></td>
|
||||
<td><?= to_currency($item['price']) ?></td>
|
||||
<td><?= to_quantity_decimals($item['quantity']) ?></td>
|
||||
@@ -74,7 +89,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<?php if ($config['receipt_show_description']) { ?>
|
||||
<td colspan="2"><?= esc($item['description']) ?></td>
|
||||
<td colspan="<?= $item_colspan - 1 ?>"><?= esc($item['description']) ?></td>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($config['receipt_show_serialnumber']) { ?>
|
||||
@@ -84,9 +99,9 @@
|
||||
<?php if ($item['discount'] > 0) { ?>
|
||||
<tr>
|
||||
<?php if ($item['discount_type'] == FIXED) { ?>
|
||||
<td colspan="3" class="discount"><?= to_currency($item['discount']) . " " . lang('Sales.discount') ?></td>
|
||||
<td colspan="<?= $item_colspan ?>" class="discount"><?= to_currency($item['discount']) . " " . lang('Sales.discount') ?></td>
|
||||
<?php } elseif ($item['discount_type'] == PERCENT) { ?>
|
||||
<td colspan="3" class="discount"><?= to_decimals($item['discount']) . " " . lang('Sales.discount_included') ?></td>
|
||||
<td colspan="<?= $item_colspan ?>" class="discount"><?= to_decimals($item['discount']) . " " . lang('Sales.discount_included') ?></td>
|
||||
<?php } ?>
|
||||
<td class="total-value"><?= to_currency($item['discounted_total']) ?></td>
|
||||
</tr>
|
||||
@@ -98,23 +113,23 @@
|
||||
|
||||
<?php if ($config['receipt_show_total_discount'] && $discount > 0) { ?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right; border-top: 2px solid #000000;"><?= lang('Sales.sub_total') ?></td>
|
||||
<td style="text-align: right; border-top:2px solid #000000;"><?= to_currency($prediscount_subtotal) ?></td>
|
||||
<td colspan="<?= $summary_colspan ?>" style="text-align: right;"><?= lang('Sales.sub_total') ?></td>
|
||||
<td style="text-align: right; border-top: 2px solid black;"><?= to_currency($prediscount_subtotal) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="total-value"><?= lang('Sales.customer_discount') ?>:</td>
|
||||
<td colspan="<?= $summary_colspan ?>" class="total-value"><?= lang('Sales.customer_discount') ?>:</td>
|
||||
<td class="total-value"><?= to_currency($discount * -1) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($config['receipt_show_taxes']) { ?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right; border-top: 2px solid #000000;"><?= lang('Sales.sub_total') ?></td>
|
||||
<td style="text-align: right; border-top: 2px solid #000000;"><?= to_currency($subtotal) ?></td>
|
||||
<td colspan="<?= $summary_colspan ?>" style="text-align: right;"><?= lang('Sales.sub_total') ?></td>
|
||||
<td style="text-align: right;"><?= to_currency($subtotal) ?></td>
|
||||
</tr>
|
||||
<?php foreach ($taxes as $tax_group_index => $tax) { ?>
|
||||
<tr>
|
||||
<td colspan="3" class="total-value"><?= (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?>:</td>
|
||||
<td colspan="<?= $summary_colspan ?>" class="total-value"><?= (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?>:</td>
|
||||
<td class="total-value"><?= to_currency_tax($tax['sale_tax_amount']) ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
@@ -122,16 +137,14 @@
|
||||
}
|
||||
?>
|
||||
|
||||
<tr></tr>
|
||||
|
||||
<?php $border = (!$config['receipt_show_taxes'] && !($config['receipt_show_total_discount'] && $discount > 0)); ?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right;<?= $border ? ' border-top: 2px solid black;' : '' ?>"><?= lang('Sales.total') ?></td>
|
||||
<td colspan="<?= $summary_colspan ?>" style="text-align: right;<?= $border ? ' border-top: 2px solid black;' : '' ?>"><?= lang('Sales.total') ?></td>
|
||||
<td style="text-align: right;<?= $border ? ' border-top: 2px solid black;' : '' ?>"><?= to_currency($total) ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="4"> </td>
|
||||
<td colspan="<?= $summary_colspan + 1 ?>"> </td>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
@@ -143,23 +156,21 @@
|
||||
$show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right;"><?= $splitpayment[0] ?> </td>
|
||||
<td colspan="<?= $summary_colspan ?>" style="text-align: right;"><?= $splitpayment[0] ?> </td>
|
||||
<td class="total-value"><?= to_currency($payment['payment_amount'] * -1) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<tr>
|
||||
<td colspan="4"> </td>
|
||||
</tr>
|
||||
|
||||
|
||||
<?php if (isset($cur_giftcard_value) && $show_giftcard_remainder) { ?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right;"><?= lang('Sales.giftcard_balance') ?></td>
|
||||
<td colspan="<?= $summary_colspan ?>" style="text-align: right;"><?= lang('Sales.giftcard_balance') ?></td>
|
||||
<td class="total-value"><?= to_currency($cur_giftcard_value) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
<tr>
|
||||
<td colspan="3" style="text-align: right;"> <?= lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> </td>
|
||||
<td colspan="<?= $summary_colspan ?>" style="text-align: right;"> <?= lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> </td>
|
||||
<td class="total-value"><?= to_currency($amount_change) ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -89,13 +89,17 @@ helper('url');
|
||||
<?= form_dropdown('stock_location', $stock_locations, $stock_location, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
|
||||
</li>
|
||||
<?php } ?>
|
||||
|
||||
<li class="pull-right">
|
||||
<button class="btn btn-default btn-sm modal-dlg" id="show_suspended_sales_button" data-href="<?= esc("$controller_name/suspended") ?>"
|
||||
title="<?= lang(ucfirst($controller_name) . '.suspended_sales') ?>">
|
||||
<span class="glyphicon glyphicon-align-justify"> </span><?= lang(ucfirst($controller_name) . '.suspended_sales') ?>
|
||||
</button>
|
||||
</li>
|
||||
<li class="pull-right">
|
||||
<button type="button" class="btn btn-warning btn-sm receipt-avatar-toggle-btn" id="toggle_avatar_button">
|
||||
<span class="glyphicon glyphicon-picture"> </span><span id="avatar_toggle_text">Hide Avatar</span>
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<?php
|
||||
$employee = model(Employee::class);
|
||||
@@ -140,12 +144,13 @@ helper('url');
|
||||
<table class="sales_table_100" id="register">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="avatar-header" style="width: 8%;" ><?= lang('Items.image') ?></th>
|
||||
<th style="width: 5%;"><?= lang('Common.delete') ?></th>
|
||||
<th style="width: 15%;"><?= lang(ucfirst($controller_name) . '.item_number') ?></th>
|
||||
<th style="width: 30%;"><?= lang(ucfirst($controller_name) . '.item_name') ?></th>
|
||||
<th style="width: 12%;"><?= lang(ucfirst($controller_name) . '.item_number') ?></th>
|
||||
<th style="width: 27%;"><?= lang(ucfirst($controller_name) . '.item_name') ?></th>
|
||||
<th style="width: 10%;"><?= lang(ucfirst($controller_name) . '.price') ?></th>
|
||||
<th style="width: 10%;"><?= lang(ucfirst($controller_name) . '.quantity') ?></th>
|
||||
<th style="width: 15%;"><?= lang(ucfirst($controller_name) . '.discount') ?></th>
|
||||
<th style="width: 13%;"><?= lang(ucfirst($controller_name) . '.discount') ?></th>
|
||||
<th style="width: 10%;"><?= lang(ucfirst($controller_name) . '.total') ?></th>
|
||||
<th style="width: 5%;"><?= lang(ucfirst($controller_name) . '.update') ?></th>
|
||||
</tr>
|
||||
@@ -154,7 +159,7 @@ helper('url');
|
||||
<tbody id="cart_contents">
|
||||
<?php if (count($cart) == 0) { ?>
|
||||
<tr>
|
||||
<td colspan="8">
|
||||
<td colspan="9">
|
||||
<div class="alert alert-dismissible alert-info"><?= lang(ucfirst($controller_name) . '.no_items_in_cart') ?></div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -164,6 +169,11 @@ helper('url');
|
||||
?>
|
||||
<?= form_open("$controller_name/editItem/$line", ['class' => 'form-horizontal', 'id' => "cart_$line"]) ?>
|
||||
<tr>
|
||||
<td class="avatar-column">
|
||||
<?php if (!empty($item['pic_filename'])): ?>
|
||||
<img src="<?= base_url('uploads/item_pics/' . esc($item['pic_filename'], 'url')) ?>" alt="avatar" style="height:40px;max-width:40px;">
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
echo anchor("$controller_name/deleteItem/$line", '<span class="glyphicon glyphicon-trash"></span>');
|
||||
@@ -565,14 +575,34 @@ helper('url');
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
const redirect = function() {
|
||||
window.location.href = "<?= site_url('sales'); ?>";
|
||||
};
|
||||
$(document).ready(function() {
|
||||
// Initialize avatar column visibility from localStorage or default to visible
|
||||
const isAvatarVisible = localStorage.getItem('avatarColumnVisible') !== 'false';
|
||||
if (!isAvatarVisible) {
|
||||
$('.avatar-column').hide();
|
||||
$('.avatar-header').hide();
|
||||
$('#avatar_toggle_text').text('Show Avatar');
|
||||
}
|
||||
|
||||
$("#remove_customer_button").click(function() {
|
||||
$.post("<?= site_url('sales/removeCustomer'); ?>", redirect);
|
||||
});
|
||||
// Handle avatar toggle button click
|
||||
$('#toggle_avatar_button').click(function(e) {
|
||||
e.preventDefault();
|
||||
const isVisible = $('.avatar-column').is(':visible');
|
||||
$('.avatar-column').toggle();
|
||||
$('.avatar-header').toggle();
|
||||
localStorage.setItem('avatarColumnVisible', !isVisible);
|
||||
$(this).toggleClass('active');
|
||||
var $toggleText = $('#avatar_toggle_text');
|
||||
$toggleText.text(isVisible ? 'Show Avatar' : 'Hide Avatar');
|
||||
});
|
||||
|
||||
const redirect = function() {
|
||||
window.location.href = "<?= site_url('sales'); ?>";
|
||||
};
|
||||
|
||||
$("#remove_customer_button").click(function() {
|
||||
$.post("<?= site_url('sales/removeCustomer'); ?>", redirect);
|
||||
});
|
||||
|
||||
$(".delete_item_button").click(function() {
|
||||
const item_id = $(this).data('item-id');
|
||||
|
||||
@@ -31,17 +31,50 @@
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
#receipt_items td {
|
||||
position: relative;
|
||||
padding: 3px;
|
||||
margin-bottom: 5px;
|
||||
padding: 1px 0px;
|
||||
margin: 0;
|
||||
border: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#receipt_items th {
|
||||
padding: 1px 0px;
|
||||
margin: 0;
|
||||
border: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#receipt_items tr {
|
||||
margin-bottom: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Remove all spacing between specific columns */
|
||||
#receipt_items td:nth-child(2), /* Description column */
|
||||
#receipt_items th:nth-child(2) {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
#receipt_items td:nth-child(3), /* Price column */
|
||||
#receipt_items th:nth-child(3) {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
#receipt_items td:nth-child(4), /* Quantity column */
|
||||
#receipt_items th:nth-child(4) {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
#receipt_items td:nth-child(5), /* Total column */
|
||||
#receipt_items th:nth-child(5) {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#sale_return_policy {
|
||||
@@ -62,3 +95,40 @@
|
||||
.discount {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Avatar toggle functionality */
|
||||
.receipt-avatar-column {
|
||||
display: table-cell;
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.receipt-avatar-column.hidden {
|
||||
display: none !important;
|
||||
width: 0 !important;
|
||||
}
|
||||
|
||||
/* When avatar column is hidden, redistribute the width */
|
||||
.receipt-avatar-column.hidden ~ th:nth-child(2) {
|
||||
width: 50% !important; /* Description gets more space */
|
||||
}
|
||||
|
||||
.receipt-avatar-column.hidden ~ th:nth-child(3) {
|
||||
width: 17% !important; /* Price */
|
||||
}
|
||||
|
||||
.receipt-avatar-column.hidden ~ th:nth-child(4) {
|
||||
width: 17% !important; /* Quantity */
|
||||
}
|
||||
|
||||
.receipt-avatar-column.hidden ~ th:nth-child(5) {
|
||||
width: 16% !important; /* Total */
|
||||
}
|
||||
|
||||
.receipt-avatar-toggle-btn {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.receipt-avatar-toggle-btn.active {
|
||||
background-color: #d9534f;
|
||||
border-color: #d43f3a;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user