Merge branch 'develop' into gli-2855
This commit is contained in:
225
AGENTS.md
Normal file
225
AGENTS.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Project Overview
|
||||
|
||||
QloApps is an open-source hotel reservation and property management platform. It enables hotels to manage rooms, bookings, guests, and payments through a web-based system.
|
||||
|
||||
## Purpose of this File
|
||||
|
||||
This document provides guidance for AI coding agents contributing to the QloApps project. It defines conventions, safety rules, and workflows to ensure consistent and secure code generation.
|
||||
|
||||
## Technology Stack
|
||||
|
||||
- **Language:** PHP 8.1–8.4 (backend), Smarty 3.x (templates), JavaScript/jQuery (frontend)
|
||||
- **Database:** MySQL 5.7, 8.0+; MariaDB 10.5, 10.6, 10.11, 11.0, 11.2, 11.4
|
||||
- **Architecture:** MVC with hook-based module system
|
||||
- **License:** OSL-3.0 (core), AFL-3.0 (modules)
|
||||
- **Required PHP Extensions:** PDO_MySQL, cURL, OpenSSL, SOAP, GD, SimpleXML, DOM, Zip, Phar
|
||||
|
||||
## Environment Setup
|
||||
|
||||
Install dependencies:
|
||||
```bash
|
||||
composer install
|
||||
```
|
||||
|
||||
Clear caches:
|
||||
```bash
|
||||
rm -rf cache/smarty/compile/* cache/smarty/cache/*
|
||||
rm -f cache/class_index.php
|
||||
```
|
||||
|
||||
Clear class cache after adding or modifying overrides.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
.
|
||||
├── classes/ # Core models extending ObjectModel
|
||||
├── controllers/ # Front and admin controllers
|
||||
│ ├── admin/
|
||||
│ └── front/
|
||||
├── modules/ # Feature modules with isolated functionality
|
||||
├── override/ # Core class and controller overrides
|
||||
├── themes/ # Smarty templates (.tpl files)
|
||||
├── config/ # Configuration files (settings.inc.php contains secrets)
|
||||
├── cache/ # Generated cache files
|
||||
├── tests/ # PHPUnit test suite
|
||||
```
|
||||
|
||||
**QloApps Agent Skills:** Install reusable development skills using:
|
||||
```bash
|
||||
npx skills add Qloapps/agent-skills
|
||||
```
|
||||
Available skills: module-development, payment-module-development, stats-module-development. Check installed skills before implementing new functionality.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
**MVC Pattern**
|
||||
- Models: classes/ extending ObjectModel
|
||||
- Controllers: FrontController or AdminController
|
||||
- Views: Smarty templates (.tpl)
|
||||
|
||||
**Modules**
|
||||
- Located in modules/<modulename>/
|
||||
- Provide isolated functionality
|
||||
- Integrate using hooks
|
||||
|
||||
**Overrides**
|
||||
- Located in override/
|
||||
- Extend core classes using the Core suffix
|
||||
- Clear class cache after creating overrides
|
||||
|
||||
**Context**
|
||||
- Access runtime objects using Context::getContext()
|
||||
|
||||
## Core vs Module Development Rules
|
||||
|
||||
**When working on a module:**
|
||||
1. Never modify core files directly
|
||||
2. Use **hooks** to integrate module functionality into core features
|
||||
3. If no suitable hook exists, create a **custom hook** — but only if the hook placement is generic and useful for other modules too
|
||||
4. Use **overrides** only as a last resort — overrides can conflict with other module override files and require manual resolution
|
||||
|
||||
**When working on a core feature:**
|
||||
- Make changes directly in core files
|
||||
- Do not use hooks or overrides for core-to-core changes
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
**Classes:** PascalCase — `HotelBookingData`
|
||||
**Methods:** camelCase — `getBookingDetails()`
|
||||
**Variables:** camelCase — `$hotelId`
|
||||
**Constants:** UPPER_SNAKE_CASE — `BOOKING_STATUS_CONFIRMED`
|
||||
**Database Tables:** _DB_PREFIX_ + lowercase_snake — `qlo_hotel_booking`
|
||||
**Config Keys:** MODULENAME_SETTING — `HOTELRESERVATION_ENABLED`
|
||||
**Files:** One class per file, filename matches class name
|
||||
**Templates:** lowercase-hyphens.tpl — `booking-form.tpl`
|
||||
|
||||
Add PHPDoc blocks to all classes and methods.
|
||||
|
||||
## Translation
|
||||
|
||||
Never hardcode user-facing English strings — always wrap them in the appropriate translation method.
|
||||
|
||||
| Context | Method |
|
||||
|---------|--------|
|
||||
| Module main file | `$this->l('string')` |
|
||||
| Module admin controller | `$this->l('string')` |
|
||||
| Module front controller | `$this->module->l('string', 'controllerName')` |
|
||||
| Module classes | `$objModule->l('string', 'ClassName')` |
|
||||
| Core admin controller | `$this->l('string')` |
|
||||
| Core front controller | `Tools::displayError('string')` |
|
||||
| Smarty template (core) | `{l s='string'}` |
|
||||
| Smarty template (module) | `{l s='string' mod='modulename'}` |
|
||||
|
||||
## Multi-language
|
||||
|
||||
- Always include `id_lang` in queries that return translatable content
|
||||
- Use `Context::getContext()->language->id` for the current language
|
||||
|
||||
## Module Development Guidelines
|
||||
|
||||
**Module Location:** modules/<modulename>/
|
||||
|
||||
**Required Files:**
|
||||
- <modulename>.php — Main class extending Module
|
||||
- config.xml — Module metadata
|
||||
|
||||
**Optional Directories:**
|
||||
- classes/ — Module-specific models
|
||||
- controllers/ — Module controllers
|
||||
- views/templates/ — Smarty templates
|
||||
- upgrade/ — Version migration scripts
|
||||
|
||||
**Hook Integration:**
|
||||
- Register hooks in install() method
|
||||
- Unregister hooks in uninstall() method
|
||||
- Keep hook handlers lightweight
|
||||
|
||||
**Configuration:**
|
||||
- Store settings using Configuration::updateValue()
|
||||
- Retrieve settings using Configuration::get()
|
||||
- Prefix config keys with module name
|
||||
|
||||
## Database Rules
|
||||
|
||||
**Table Prefix:** Always use _DB_PREFIX_ constant instead of hardcoding the table prefix
|
||||
|
||||
**Escaping:**
|
||||
- Strings: pSQL($value)
|
||||
- Integers: (int)$value
|
||||
- Table/column names: bqSQL($name)
|
||||
|
||||
**Preferred Access:** Use ObjectModel for CRUD operations instead of raw SQL queries
|
||||
|
||||
**Prohibited:** Never concatenate raw user input into SQL queries.
|
||||
|
||||
## Security Guidelines
|
||||
|
||||
**Input Handling**
|
||||
- Use Tools::getValue() for request parameters
|
||||
- Cast numeric values to (int)
|
||||
- Escape strings using pSQL()
|
||||
- Validate input using Validate class methods
|
||||
|
||||
**Output Escaping**
|
||||
- Use Tools::safeOutput() in PHP
|
||||
- Use Smarty escape modifiers in templates
|
||||
|
||||
**Sensitive Data**
|
||||
- Never expose config/settings.inc.php
|
||||
- Never commit API keys, passwords, or tokens
|
||||
|
||||
**Authorization**
|
||||
- Verify permissions before performing admin operations
|
||||
|
||||
## Testing
|
||||
|
||||
Testing infrastructure is being configured. Check tests/ directory for available tests before running.
|
||||
|
||||
## AI Agent Workflow
|
||||
|
||||
1. Check installed agent skills before implementing new functionality
|
||||
2. Search codebase for similar implementations before creating new code
|
||||
3. Extend existing classes rather than duplicating functionality
|
||||
4. Follow patterns established in surrounding code
|
||||
5. Reuse existing utilities: Tools, Validate, Db, Configuration classes
|
||||
6. Prioritize consistency with existing codebase over new approaches
|
||||
|
||||
After making changes:
|
||||
- Clear caches if modifying templates or overrides
|
||||
- Add PHPDoc to new methods
|
||||
|
||||
## Safety Rules
|
||||
|
||||
**Agents must not:**
|
||||
- Delete files unless explicitly instructed
|
||||
- Run git commands automatically
|
||||
- Modify composer.json without approval
|
||||
- Modify config/settings.inc.php
|
||||
- Execute DROP, TRUNCATE, or destructive SQL
|
||||
- Modify core files directly when working on a module (use hooks or override system)
|
||||
|
||||
**Agents must:**
|
||||
- Use pSQL() for strings and (int) for IDs in SQL
|
||||
- Use Tools::getValue() for request parameters
|
||||
- Escape all output
|
||||
- Check installed agent skills before implementing new functionality
|
||||
- Follow project naming conventions
|
||||
- Validate inputs before processing
|
||||
|
||||
**Agents should ask before:**
|
||||
- Deleting any files
|
||||
- Running git commands
|
||||
- Changing dependencies
|
||||
- Modifying database schema
|
||||
- Altering payment or booking logic
|
||||
|
||||
---
|
||||
|
||||
**Resources:**
|
||||
- Documentation: https://docs.qloapps.com
|
||||
- Forum: https://forums.qloapps.com
|
||||
- GitHub: https://github.com/Qloapps/QloApps
|
||||
- Security Issues: support@qloapps.com
|
||||
@@ -104,7 +104,7 @@
|
||||
<div class="col-lg-1"><span class="pull-right">{include file="controllers/products/multishop/checkbox.tpl" field="name" type="default" multilang="true"}</span></div>
|
||||
<label class="control-label col-lg-2 required" id="name" for="name_{$id_lang}">
|
||||
<span class="label-tooltip" data-toggle="tooltip" title="{l s='Write the name of the Room Type for ex. Delux, Executive etc.'} {l s='Invalid characters:'} <>;=#{}">
|
||||
{l s='Room Type'}
|
||||
{l s='Name'}
|
||||
</span>
|
||||
</label>
|
||||
<div class="col-lg-5">
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
|
||||
function startTree(idElem) {
|
||||
if (typeof $.fn.tree === 'undefined') {
|
||||
setTimeout(startTree, 100);
|
||||
setTimeout(function() { startTree(idElem); }, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +332,14 @@ class CookieCore
|
||||
$this->logout();
|
||||
}
|
||||
|
||||
if (isset($this->_content['id_customer']) && isset($this->_content['passwd']) && (int)$this->_content['id_customer']) {
|
||||
if (Validate::isLoadedObject($objCustomer = new Customer((int)$this->_content['id_customer']))) {
|
||||
if ($objCustomer->passwd != $this->_content['passwd']) {
|
||||
$this->logout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($this->_content['date_add'])) {
|
||||
$this->_content['date_add'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
@@ -2397,7 +2397,7 @@ class AdminControllerCore extends Controller
|
||||
$must_have_module_list = file_get_contents(_PS_ROOT_DIR_.Module::CACHE_FILE_MUST_HAVE_MODULES_LIST);
|
||||
if (!empty($must_have_module_list) && $must_have_module_list_xml = @simplexml_load_string($must_have_module_list)) {
|
||||
$must_have_module_list_array = array();
|
||||
if (is_object($country_module_list_xml->module)) {
|
||||
if (is_object($must_have_module_list_xml->module)) {
|
||||
foreach ($must_have_module_list_xml->module as $l => $mo) {
|
||||
$all_module_list[] = (string)$mo->name;
|
||||
}
|
||||
|
||||
@@ -368,6 +368,54 @@ class AdminOrdersControllerCore extends AdminController
|
||||
'icon' => 'process-icon-new'
|
||||
);
|
||||
}
|
||||
if ($this->display == 'view') {
|
||||
/** @var Order $order */
|
||||
if (Validate::isLoadedObject($order = $this->loadObject())) {
|
||||
// hotel link in header
|
||||
if ($idHotel = HotelBookingDetail::getIdHotelByIdOrder($order->id)) {
|
||||
$this->page_header_toolbar_btn['hotel'] = array(
|
||||
'href' => $this->context->link->getAdminLink('AdminAddHotel').'&id='.$idHotel.'&updatehtl_branch_info',
|
||||
'desc' => $this->l('View Hotel'),
|
||||
'class' => 'icon-building',
|
||||
'target' => true,
|
||||
);
|
||||
}
|
||||
|
||||
if (Configuration::get('PS_INVOICE') && $order->hasInvoice() && !$this->lite_display) {
|
||||
$this->page_header_toolbar_btn['file'] = array(
|
||||
'short' => $this->l('Invoice'),
|
||||
'href' => $this->context->link->getAdminLink('AdminPdf').'&submitAction=generateInvoicePDF&id_order='.$order->id,
|
||||
'desc' => $this->l('View invoice'),
|
||||
'class' => 'icon-file-text',
|
||||
'target' => true,
|
||||
);
|
||||
}
|
||||
|
||||
$this->page_header_toolbar_btn['print'] = array(
|
||||
'short' => $this->l('Print'),
|
||||
'href' => 'javascript:window.print()',
|
||||
'desc' => $this->l('Print order'),
|
||||
'class' => 'icon-print',
|
||||
);
|
||||
|
||||
if ($this->tabAccess['edit'] === 1) {
|
||||
if (((int) $order->isReturnable())
|
||||
&& !$order->hasCompletelyRefunded(Order::ORDER_COMPLETE_CANCELLATION_OR_REFUND_REQUEST_FLAG, 0, 0)
|
||||
) {
|
||||
$orderTotalPaid = $order->getTotalPaid();
|
||||
$orderDiscounts = $order->getCartRules();
|
||||
$hasOrderDiscountOrPayment = ((float)$orderTotalPaid > 0 || $orderDiscounts) ? true : false;
|
||||
$this->page_header_toolbar_btn['cancel'] = array(
|
||||
'short' => ($hasOrderDiscountOrPayment) ? $this->l('Refund') : $this->l('Cancel'),
|
||||
'id' => 'desc-order-standard_refund',
|
||||
'desc' => ($hasOrderDiscountOrPayment) ? $this->l('Initiate refund') : $this->l('Cancel bookings'),
|
||||
'class' => 'icon-exchange',
|
||||
'target' => true,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::initPageHeaderToolbar();
|
||||
}
|
||||
@@ -476,55 +524,6 @@ class AdminOrdersControllerCore extends AdminController
|
||||
|
||||
public function initToolbar()
|
||||
{
|
||||
if ($this->display == 'view') {
|
||||
/** @var Order $order */
|
||||
if (Validate::isLoadedObject($order = $this->loadObject())) {
|
||||
// hotel link in header
|
||||
if ($idHotel = HotelBookingDetail::getIdHotelByIdOrder($order->id)) {
|
||||
$this->toolbar_btn['hotel'] = array(
|
||||
'href' => $this->context->link->getAdminLink('AdminAddHotel').'&id='.$idHotel.'&updatehtl_branch_info',
|
||||
'desc' => $this->l('View Hotel'),
|
||||
'class' => 'icon-building',
|
||||
'target' => true,
|
||||
);
|
||||
}
|
||||
|
||||
if (Configuration::get('PS_INVOICE') && $order->hasInvoice() && !$this->lite_display) {
|
||||
$this->toolbar_btn['file'] = array(
|
||||
'short' => $this->l('Invoice'),
|
||||
'href' => $this->context->link->getAdminLink('AdminPdf').'&submitAction=generateInvoicePDF&id_order='.$order->id,
|
||||
'desc' => $this->l('View invoice'),
|
||||
'class' => 'icon-file-text',
|
||||
'target' => true,
|
||||
);
|
||||
}
|
||||
|
||||
$this->toolbar_btn['print'] = array(
|
||||
'short' => $this->l('Print'),
|
||||
'href' => 'javascript:window.print()',
|
||||
'desc' => $this->l('Print order'),
|
||||
'class' => 'icon-print',
|
||||
);
|
||||
|
||||
if ($this->tabAccess['edit'] === 1) {
|
||||
if (((int) $order->isReturnable())
|
||||
&& !$order->hasCompletelyRefunded(Order::ORDER_COMPLETE_CANCELLATION_OR_REFUND_REQUEST_FLAG, 0, 0)
|
||||
) {
|
||||
$orderTotalPaid = $order->getTotalPaid();
|
||||
$orderDiscounts = $order->getCartRules();
|
||||
$hasOrderDiscountOrPayment = ((float)$orderTotalPaid > 0 || $orderDiscounts) ? true : false;
|
||||
$this->toolbar_btn['cancel'] = array(
|
||||
'short' => ($hasOrderDiscountOrPayment) ? $this->l('Refund') : $this->l('Cancel'),
|
||||
'id' => 'desc-order-standard_refund',
|
||||
'desc' => ($hasOrderDiscountOrPayment) ? $this->l('Initiate refund') : $this->l('Cancel bookings'),
|
||||
'class' => 'icon-exchange',
|
||||
'target' => true,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$res = parent::initToolbar();
|
||||
if (Context::getContext()->shop->getContext() != Shop::CONTEXT_SHOP && isset($this->toolbar_btn['new']) && Shop::isFeatureActive()) {
|
||||
unset($this->toolbar_btn['new']);
|
||||
@@ -3710,6 +3709,7 @@ class AdminOrdersControllerCore extends AdminController
|
||||
'ROOM_STATUS_CHECKED_OUT' => HotelBookingDetail::STATUS_CHECKED_OUT,
|
||||
'ALLOTMENT_MANUAL' => HotelBookingDetail::ALLOTMENT_MANUAL,
|
||||
'order_convenience_fee_services' => $orderConvenienceFeeServices,
|
||||
'page_header_toolbar_btn' => $this->page_header_toolbar_btn,
|
||||
);
|
||||
|
||||
return parent::renderView();
|
||||
|
||||
@@ -714,8 +714,11 @@ class AdminThemesControllerCore extends AdminController
|
||||
}
|
||||
|
||||
$ids_themes = Tools::unSerialize(Configuration::get('PS_ADDONS_THEMES_IDS'));
|
||||
if (array_key_exists($obj->directory, $ids_themes)) {
|
||||
unset($ids_themes[$obj->directory]);
|
||||
|
||||
if(is_array($ids_themes)) {
|
||||
if (array_key_exists($obj->directory, $ids_themes)) {
|
||||
unset($ids_themes[$obj->directory]);
|
||||
}
|
||||
}
|
||||
|
||||
$obj->removeMetas();
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
{/if}
|
||||
<td>{HotelRoomInformation::getRoomStatusTitle($unavail_dtl_v['id_status'])|escape:'htmlall':'UTF-8'}</td>
|
||||
<td>
|
||||
{if $unavail_dtl_v['date_from'] && $unavail_dtl_v['date_to']}
|
||||
{if isset($unavail_dtl_v['date_from']) && isset($unavail_dtl_v['date_to'])}
|
||||
{dateFormat date=$unavail_dtl_v['date_from']} - {dateFormat date=$unavail_dtl_v['date_to']}
|
||||
{else}
|
||||
--
|
||||
|
||||
@@ -137,39 +137,46 @@ class AdminPaypalCommerceTransactionController extends ModuleAdminController
|
||||
$smartyVars = array();
|
||||
$refundData = array();
|
||||
$totalRefunded = 0;
|
||||
$transactionData = WKPayPalCommerceOrder::getTransactionDetails((int)$idTrans);
|
||||
$orderCurrency = new Currency((int)$transactionData['id_currency']);
|
||||
$refundData = WkPaypalCommerceRefund::getRefundListByTransID((int)$idTrans);
|
||||
$totalRefundedFormatted = WkPaypalCommerceRefund::getTotalRefundedAmount((int)$idTrans, true);
|
||||
if ($transactionData = WKPayPalCommerceOrder::getTransactionDetails((int)$idTrans)) {
|
||||
$orderCurrency = new Currency((int)$transactionData['id_currency']);
|
||||
$refundData = WkPaypalCommerceRefund::getRefundListByTransID((int)$idTrans);
|
||||
$totalRefundedFormatted = WkPaypalCommerceRefund::getTotalRefundedAmount((int)$idTrans, true);
|
||||
|
||||
$totalRefunded = WkPaypalCommerceRefund::getTotalRefundedAmount((int)$idTrans, false);
|
||||
$remainingRefund = (float)($transactionData['pp_paid_total'] - $totalRefunded);
|
||||
$response = json_decode($transactionData['response'], true);
|
||||
$totalRefunded = WkPaypalCommerceRefund::getTotalRefundedAmount((int)$idTrans, false);
|
||||
$remainingRefund = (float)($transactionData['pp_paid_total'] - $totalRefunded);
|
||||
$response = Tools::jsonDecode($transactionData['response'], true);
|
||||
|
||||
// Buyer making a payment in a different currency (ex: EUR) which is different from the default currency of merchant (Ex: USD), In all those cross currency cases, After Capture, transaction will fall into Pending state and will require merchant to manually go to his PayPal account and accept the payment.
|
||||
$objPPOrder = new WKPayPalCommerceOrder();
|
||||
if (isset($response['data']['purchase_units'][0]['payments']['captures'][0]['status_details']['reason'])
|
||||
&& ($transactionData['pp_payment_status'] == 'PENDING' || $transactionData['pp_payment_status'] == 'DENIED')
|
||||
&& isset($response['data']['purchase_units'][0]['payments']['captures'][0]['status_details']['reason'])
|
||||
) {
|
||||
if (isset($objPPOrder->ppStatusDetail[$response['data']['purchase_units'][0]['payments']['captures'][0]['status_details']['reason']])) {
|
||||
$smartyVars['ppstatusDetailMsg'] = $objPPOrder->ppStatusDetail[$response['data']['purchase_units'][0]['payments']['captures'][0]['status_details']['reason']];
|
||||
// Buyer making a payment in a different currency (ex: EUR) which is different from the default currency of merchant (Ex: USD), In all those cross currency cases, After Capture, transaction will fall into Pending state and will require merchant to manually go to his PayPal account and accept the payment.
|
||||
$objPPOrder = new WKPayPalCommerceOrder();
|
||||
if (
|
||||
isset($response['data']['purchase_units'][0]['payments']['captures'][0]['status_details']['reason'])
|
||||
&& ($transactionData['pp_payment_status'] == 'PENDING' || $transactionData['pp_payment_status'] == 'DENIED')
|
||||
&& isset($response['data']['purchase_units'][0]['payments']['captures'][0]['status_details']['reason'])
|
||||
) {
|
||||
if (isset($objPPOrder->ppStatusDetail[$response['data']['purchase_units'][0]['payments']['captures'][0]['status_details']['reason']])) {
|
||||
$smartyVars['ppstatusDetailMsg'] = $objPPOrder->ppStatusDetail[$response['data']['purchase_units'][0]['payments']['captures'][0]['status_details']['reason']];
|
||||
}
|
||||
}
|
||||
}
|
||||
$smartyVars['transaction_url'] = $this->context->link->getAdminLink('AdminPaypalCommerceTransaction',Tools::getAdminTokenLite('AdminPaypalCommerceTransaction')).'&viewwk_paypal_commerce_order&id_paypal_commerce_order=' . (int)$idTrans;
|
||||
$smartyVars['transaction_data'] = $transactionData;
|
||||
$smartyVars['refund_data'] = $refundData;
|
||||
$smartyVars['refunded_amount'] = $totalRefundedFormatted;
|
||||
$smartyVars['remaining_refund'] = $remainingRefund;
|
||||
$smartyVars['remaining_refund_format'] = Tools::displayPrice($remainingRefund, $orderCurrency);
|
||||
$smartyVars['currency'] = $orderCurrency;
|
||||
$smartyVars['WK_PAYPAL_COMMERCE_REFUND_TYPE_FULL'] = WkPaypalCommerceRefund::WK_PAYPAL_COMMERCE_REFUND_TYPE_FULL;
|
||||
$smartyVars['WK_PAYPAL_COMMERCE_REFUND_TYPE_PARTIAL'] = WkPaypalCommerceRefund::WK_PAYPAL_COMMERCE_REFUND_TYPE_PARTIAL;
|
||||
|
||||
$smartyVars['transaction_url'] = $this->context->link->getAdminLink('AdminPaypalCommerceTransaction',Tools::getAdminTokenLite('AdminPaypalCommerceTransaction')).'&viewwk_paypal_commerce_order&id_paypal_commerce_order=' . (int)$idTrans;
|
||||
$smartyVars['transaction_data'] = $transactionData;
|
||||
$smartyVars['refund_data'] = $refundData;
|
||||
$smartyVars['refunded_amount'] = $totalRefundedFormatted;
|
||||
$smartyVars['remaining_refund'] = $remainingRefund;
|
||||
$smartyVars['remaining_refund_format'] = Tools::displayPrice($remainingRefund, $orderCurrency);
|
||||
$smartyVars['currency'] = $orderCurrency;
|
||||
$smartyVars['WK_PAYPAL_COMMERCE_REFUND_TYPE_FULL'] = WkPaypalCommerceRefund::WK_PAYPAL_COMMERCE_REFUND_TYPE_FULL;
|
||||
$smartyVars['WK_PAYPAL_COMMERCE_REFUND_TYPE_PARTIAL'] = WkPaypalCommerceRefund::WK_PAYPAL_COMMERCE_REFUND_TYPE_PARTIAL;
|
||||
|
||||
$this->context->smarty->assign($smartyVars);
|
||||
$this->context->smarty->assign($smartyVars);
|
||||
$this->base_tpl_view = 'view.tpl';
|
||||
return parent::renderView();
|
||||
} else {
|
||||
Tools::redirectAdmin(self::$currentIndex . '&token=' . $this->token);
|
||||
}
|
||||
} else {
|
||||
Tools::redirectAdmin(self::$currentIndex . '&token=' . $this->token);
|
||||
}
|
||||
$this->base_tpl_view = 'view.tpl';
|
||||
return parent::renderView();
|
||||
}
|
||||
|
||||
public function postProcess()
|
||||
|
||||
@@ -176,6 +176,7 @@
|
||||
<th style="text-align: center">{l s='Amount' mod='qlopaypalcommerce'}</th>
|
||||
<th style="text-align: center">{l s='Type' mod='qlopaypalcommerce'}</th>
|
||||
<th style="text-align: center">{l s='Status' mod='qlopaypalcommerce'}</th>
|
||||
<th style="text-align: center">{l s='Remark' mod='qlopaypalcommerce'}</th>
|
||||
<th style="text-align: center">{l s='Date' mod='qlopaypalcommerce'}</th>
|
||||
</tr>
|
||||
{if $refund_data}
|
||||
@@ -197,6 +198,7 @@
|
||||
<label class="label label-danger">{$refund.refund_status|escape:'html':'UTF-8'}</label>
|
||||
{/if}
|
||||
</td>
|
||||
<td style="text-align: center">{$refund.refund_reason|escape:'html':'UTF-8'}</td>
|
||||
<td style="text-align: center">{$refund.date_add|escape:'html':'UTF-8'}</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
|
||||
@@ -310,10 +310,14 @@ class StatsSales extends ModuleGraph
|
||||
{
|
||||
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($this->query.$this->getDate().$this->query_group_by.$this->query_having_filter);
|
||||
foreach ($result as $row) {
|
||||
$days = (int)substr($row['invoice_date'], 8, 2);
|
||||
if (!isset($this->_values[$days])) {
|
||||
$this->_values[$days] = 0;
|
||||
}
|
||||
if ($this->option == 1) {
|
||||
$this->_values[(int)substr($row['invoice_date'], 8, 2)] += 1;
|
||||
$this->_values[$days] += 1;
|
||||
} else {
|
||||
$this->_values[(int)substr($row['invoice_date'], 8, 2)] += $row['total_revenue'];
|
||||
$this->_values[$days] += $row['total_revenue'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,19 @@
|
||||
<th class="header small" valign="middle">{l s='Invoice Date' pdf='true'}</th>
|
||||
<th class="header small" valign="middle">{l s='Order Reference' pdf='true'}</th>
|
||||
<th class="header small" valign="middle">{l s='Order date' pdf='true'}</th>
|
||||
{if $addresses.invoice->vat_number}
|
||||
<th class="header small" valign="middle">{l s='VAT Number' pdf='true'}</th>
|
||||
{/if}
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center small white">{$title|escape:'html':'UTF-8'}</td>
|
||||
<td class="center small white">{dateFormat date=$order->invoice_date full=0}</td>
|
||||
<td class="center small white">{$order->getUniqReference()}</td>
|
||||
<td class="center small white">{dateFormat date=$order->date_add full=0}</td>
|
||||
{if $addresses.invoice->vat_number}
|
||||
<td class="center small white">
|
||||
{$addresses.invoice->vat_number|escape:'html':'UTF-8'}
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -5776,10 +5776,13 @@ textarea {
|
||||
background: #fff; }
|
||||
|
||||
#columns {
|
||||
padding: 0;
|
||||
}
|
||||
#columns:has(#center_column > *) {
|
||||
position: relative;
|
||||
padding-bottom: 50px;
|
||||
padding-top: 15px; }
|
||||
|
||||
padding-top: 15px;
|
||||
}
|
||||
#index .tab-content {
|
||||
margin-top: 35px;
|
||||
margin-bottom: 34px; }
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
<span class="htl-address-icon htl-email-icon"></span>{$hotel['email']}
|
||||
</p>
|
||||
<div class="hotel-branch-info-actions">
|
||||
<a href="{$hotel['view_rooms_link']}" target="_blank" class="btn btn-primary view_rooms_btn col-sm-6 col-xs-12">{l s='View Rooms'}</a>
|
||||
<a href="{$hotel['view_rooms_link']}" target="_blank" class="btn btn-primary view_rooms_btn col-sm-6 col-xs-12">{l s='View Property'}</a>
|
||||
{if ($hotel['latitude'] != 0 || $hotel['longitude'] != 0) && $viewOnMap}
|
||||
<a class="btn htl-map-direction-btn col-sm-6 col-xs-12" href="http://maps.google.com/maps?daddr=({$hotel['latitude']},{$hotel['longitude']})" target="_blank">{l s='View on map'}</a>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user