Compare commits

..

8 Commits

Author SHA1 Message Date
Ollama
4c55e7fcbd fix: Pin nesbot/carbon to ^2.72 for PHP 8.2 compatibility
The num-num/ubl-invoice package allows Carbon 2.x or 3.x, but Carbon 3.x
pulls in Symfony 8.x components that require PHP 8.4+. Pinning Carbon to
2.x ensures compatibility with OSPOS's PHP 8.2 requirement.
2026-05-18 15:28:03 +02:00
jekkos
4d9540633a Add Peppol (UBL) invoice support for Phase 1
Implementation of UBL 2.1 invoice generation to comply with Belgium's 2026 Peppol mandate.

Key changes:
- Add num-num/ubl-invoice dependency via composer.json
- Create Ubl_generator library to convert OSPOS sale data to UBL format
- Create country_helper.php to map country names to ISO 3166-1 alpha-2 codes
- Extend Email_lib to support multiple attachments for PDF+UBL emails
- Add getUblInvoice() method in Sales controller for UBL download
- Modify getSendPdf() to optionally attach UBL based on invoice_format config
- Add database migration for invoice_format configuration (pdf_only/ubl_only/both)
- Add UBL download button to invoice view
- Add UBL download link to sales manage table
- Add language keys for UBL-related UI elements

Data mapping:
- Company name/address -> Supplier Party
- account_number -> Company VAT number
- Customer address/country -> Customer Party with ISO country code
- Customer tax_id -> Customer VAT number
- Cart items -> InvoiceLines
- Taxes -> TaxCategory and TaxTotal
- Totals -> LegalMonetaryTotal

Features:
- Generate valid UBL 2.1 XML invoices
- Download UBL from invoice view and manage table
- Email with PDF, UBL, or both based on configuration
- Support for multiple customer countries with ISO code mapping
- Graceful handling of missing optional customer fields
2026-05-18 15:05:30 +02:00
jekkos
093ec7fb13 fix: validate attributeId > 0 in saveAttributeLink() (#4508)
- Add early validation to reject attributeId <= 0
- Ensure consistent handling of invalid attribute_id in INSERT/UPDATE paths
- Prevent foreign key constraint violations from invalid attribute references

Fixes #4460

Co-authored-by: Ollama <ollama@steganos.dev>
Co-authored-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
2026-05-18 14:13:20 +02:00
jekkos
9c89a2e2cb fix: Capture CSV import failures in save_tax_data and save_inventory_quantities (#4507)
* fix: capture CSV import failures in save_tax_data and save_inventory_quantities

- Change save_tax_data() return type from void to bool
- Change save_inventory_quantities() return type from void to bool
- Accumulate failure status with &= operator in save_inventory_quantities
- Update postImportCsvFile() to capture return values and set isFailedRow
- Properly propagate failures to failCodes array

Fixes #4475

* fix: Change isset to !empty for items_taxes_data check

- isset was always true since array was initialized
- Use !empty to properly check if there are tax items to save

Address CodeRabbit review feedback

* fix: Capture inventory insert result in save_inventory_quantities

- Combine inventory insert result with success tracking
- Use &= operator to accumulate failures from both operations
- Ensure failures from inventory inserts are propagated

Address CodeRabbit review feedback

---------

Co-authored-by: Ollama <ollama@steganos.dev>
2026-05-17 22:23:43 +02:00
jekkos
2f51c4ef52 fix(security): SQL injection and path traversal vulnerabilities (#4539)
Security fixes for two vulnerabilities:

1. SQL Injection in Summary Sales Taxes Report (GHSA-5j9m-2f98-cjqw)
   - Fixed unsanitized user input concatenation in getData() method
   - Applied proper escaping using $this->db->escape() for start_date/end_date
   - Consistent with existing _where() method implementation

2. Path Traversal in Receipt Template (GHSA-h6wm-fhw2-m3q3)
   - Added ALLOWED_RECEIPT_TEMPLATES whitelist constant
   - Added isValidReceiptTemplate() validation method
   - Validate receipt_template before saving in Config controller
   - Validate receipt_template before rendering in receipt view
   - Default to 'receipt_default' for invalid values
   - Consistent with invoice_type fix pattern (commit 31d25e06d)

Affected files:
- app/Models/Reports/Summary_sales_taxes.php
- app/Libraries/Sale_lib.php
- app/Controllers/Config.php
- app/Views/sales/receipt.php

Co-authored-by: Ollama <ollama@steganos.dev>
2026-05-15 23:10:04 +02:00
jekkos
def0c27a0e fix(security): Path traversal vulnerability in getPicThumb (#4545)
Security impact:
- Authenticated attackers could read arbitrary files on the server
- Path traversal via unsanitized pic_filename parameter
- Could read .env, config files, encryption keys

Fix:
- Apply basename() to strip directory components
- Validate file extension to allowlist image types only
- Add explicit error response for invalid file types

CVE: Pending
Affected: <= 3.4.2
Reported by: Kamran Saifullah (VulDB)

Co-authored-by: Ollama <ollama@steganos.dev>
2026-05-15 22:04:29 +02:00
BhojKamal
90c981b6b7 feat: Bank transfer and wallet payment option added #4540 (#4547)
---------

Co-authored-by: Lotussoft Youngtech <lotussoftyoungtech@gmail.com>
Co-authored-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
2026-05-15 20:50:34 +02:00
jekkos
6ff28d8a4d docs: Update SECURITY.md with disclosure process (#4549)
* docs: Update SECURITY.md with disclosure process and advisory template

- Update published advisories table with CVE-2026-41306 and CVE-2026-41307
- Add disclosure process timeline
- Add vulnerability template for researchers
- Explain GitHub advisory creation workflow
- Document security best practices for researchers

This streamlines the vulnerability reporting process by allowing
researchers to create draft advisories directly on GitHub, reducing
triage overhead.

* docs: Update SECURITY.md with CVE process and reporter acknowledgments

- Add CVE request procedure through GitHub
- Document that existing CVEs should be shared in reports
- Clarify no bug bounty program (voluntary triage)
- Add security best practices for researchers
- Thank security researchers for contributions
- Explain vulnerability template format

* docs: Simplify SECURITY.md - remove CVE table, link to GitHub advisories

---------

Co-authored-by: Ollama <ollama@steganos.dev>
2026-05-15 12:24:39 +02:00
137 changed files with 10291 additions and 6414 deletions

View File

@@ -1,10 +1,6 @@
<p align="center"><img src="https://raw.githubusercontent.com/opensourcepos/opensourcepos/master/branding/emblem.svg" alt="Open Source Point of Sale Logo" width="auto" height="200"></p>
<h3 align="center">Open Source Point of Sale</h3>
## ☢️ Bootstrap 5 conversion WIP
This is a heavily under-construction build converting OSPOS from Bootstrap 3 to Bootstrap 5. Please do not use!
<p align="center">
<a href="#-introduction">Introduction</a> · <a href="#-live-demo">Demo</a> · <a href="#-installation">Installation</a> ·
<a href="#-contributing">Contributing</a> · <a href="#-reporting-bugs">Bugs</a> · <a href="#-faq">FAQ</a> ·

View File

@@ -5,8 +5,9 @@
- [Supported Versions](#supported-versions)
- [Security Advisories](#security-advisories)
- [Reporting a Vulnerability](#reporting-a-vulnerability)
- [Disclosure Process](#disclosure-process)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- END doctoc generated TOC please keep comment here to allow update -->
# Security Policy
@@ -21,26 +22,116 @@ We release patches for security vulnerabilities.
## Security Advisories
The following security vulnerabilities have been published:
### High Severity
| CVE | Vulnerability | CVSS | Published | Fixed In | Credit |
|-----|--------------|------|-----------|----------|--------|
| [CVE-2025-68434](https://github.com/opensourcepos/opensourcepos/security/advisories/GHSA-wjm4-hfwg-5w5r) | CSRF leading to Admin Creation | 8.8 | 2025-12-17 | 3.4.2 | @Nixon-H, @jekkos |
| [CVE-2025-68147](https://github.com/opensourcepos/opensourcepos/security/advisories/GHSA-xgr7-7pvw-fpmh) | Stored XSS in Return Policy | 8.1 | 2025-12-17 | 3.4.2 | @Nixon-H, @jekkos |
| [CVE-2025-66924](https://github.com/opensourcepos/opensourcepos/security/advisories/GHSA-gv8j-f6gq-g59m) | Stored XSS in Item Kits | 7.2 | 2026-03-04 | 3.4.2 | @hungnqdz, @omkaryepre |
### Medium Severity
| CVE | Vulnerability | CVSS | Published | Fixed In | Credit |
|-----|--------------|------|-----------|----------|--------|
| [CVE-2025-68658](https://github.com/opensourcepos/opensourcepos/security/advisories/GHSA-32r8-8r9r-9chw) | Stored XSS in Company Name | 4.3 | 2026-01-13 | 3.4.2 | @hungnqdz |
For a complete list including draft advisories, see our [GitHub Security Advisories page](https://github.com/opensourcepos/opensourcepos/security/advisories).
For a complete list of published and draft security advisories with CVE details, see our [GitHub Security Advisories page](https://github.com/opensourcepos/opensourcepos/security/advisories).
## Reporting a Vulnerability
Please report (suspected) security vulnerabilities to **[jeroen@steganos.dev](mailto:jeroen@steganos.dev)**.
**Option 1: GitHub Security Advisory (Preferred)**
You will receive a response from us within 48 hours. If the issue is confirmed, we will release a patch as soon as possible depending on complexity but historically within a few days.
1. Create a draft security advisory directly on GitHub:
- Go to https://github.com/opensourcepos/opensourcepos/security/advisories
- Click "New draft security advisory"
- Fill in the vulnerability details using our [template below](#vulnerability-template)
- Submit as **draft** (not published)
2. Notify us for triage:
- Send an email to **[jeroen@steganos.dev](mailto:jeroen@steganos.dev)** with:
- Subject: `[GHSA] Brief description of vulnerability`
- Link to the draft advisory
- Brief summary
**Option 2: Email Report**
Send vulnerability details to **[jeroen@steganos.dev](mailto:jeroen@steganos.dev)**.
You will receive a response within 48 hours. Confirmed vulnerabilities will be patched within a few days depending on complexity.
## Disclosure Process
### Timeline
| Step | Timeline | Action |
|------|----------|--------|
| 1. Report received | Day 0 | We acknowledge within 48 hours |
| 2. Triage & confirmation | Day 1-3 | We validate the vulnerability |
| 3. Fix development | Day 3-7 | We develop and test the fix |
| 4. Patch release | Day 7-10 | We release a security patch |
| 5. CVE request | Day 7-14 | We request CVE from GitHub (if applicable) |
| 6. Advisory published | Day 14 | We publish the advisory with credit |
| 7. Public disclosure | Day 14+ | Full disclosure after patch release |
### CVE Process
**We request CVE identifiers through GitHub's security advisory system.** This is the preferred and easiest method:
1. After we confirm and fix the vulnerability, we'll request a CVE through GitHub
2. GitHub coordinates with MITRE on our behalf
3. The CVE is automatically linked to the advisory
4. You'll be credited as the reporter in the published advisory
**Already have a CVE?** If you've already obtained a CVE from another source (e.g., VulDB, CVE.MITRE.ORG), please include it in your report or advisory. We'll update our advisory to reference the existing CVE.
### No Bug Bounty Program
**Important:** Open Source Point of Sale does not offer a bug bounty program.
- All security research and vulnerability triage is done on a **voluntary basis** in our free time
- We do not offer monetary rewards for vulnerability reports
- We do credit reporters in published advisories (unless anonymity is requested)
- We greatly appreciate the security research community's efforts to help improve project security
### Security Best Practices for Researchers
- **Do not** access, modify, or delete data that doesn't belong to you
- **Do not** perform denial of service attacks
- **Do not** publicly disclose vulnerabilities before we've had time to fix them
- **Do** provide sufficient information to reproduce the vulnerability
- **Do** allow us reasonable time to fix before public disclosure
- **Do** report through official channels (GitHub advisories or email)
### Vulnerability Template
When creating a draft advisory, please include:
```
## Summary
[Brief description of the vulnerability]
## Impact
- **Confidentiality:** [High/Medium/Low - what data can be exposed]
- **Integrity:** [High/Medium/Low - what can be modified]
- **Availability:** [High/Medium/Low - service disruption potential]
- **Privilege Required:** [None/Low/High - authentication level needed]
- **CVSS v3.1:** [Score] ([Vector string])
## Details
[Technical details about the vulnerability]
**Affected Code:**
```php
// Path to affected file and vulnerable code
```
**Attack Vector:**
[How an attacker can exploit this]
## Proof of Concept
```bash
# Steps to reproduce
```
## Patch
[Suggested fix or approach]
## Affected Versions
- OpenSourcePOS X.Y.Z and earlier
## Credit
[Your GitHub username or preferred name]
```
---
**Thank you to all security researchers who have contributed to making Open Source Point of Sale more secure.** Your voluntary efforts help protect thousands of users worldwide and contribute to a safer, more trustworthy free and open-source software ecosystem. We deeply appreciate your responsible disclosure and the time you invest in improving our project.
If you've reported a vulnerability and would like to discuss CVE coordination or have questions about the process, please reach out to us at [jeroen@steganos.dev](mailto:jeroen@steganos.dev).

View File

@@ -371,6 +371,8 @@ class Config extends Secure_Controller
public function postSaveGeneral(): ResponseInterface
{
$batchSaveData = [
'theme' => $this->request->getPost('theme'),
'login_form' => $this->request->getPost('login_form'),
'default_sales_discount_type' => $this->request->getPost('default_sales_discount_type') != null,
'default_sales_discount' => parse_decimals($this->request->getPost('default_sales_discount')),
'default_receivings_discount_type' => $this->request->getPost('default_receivings_discount_type') != null,
@@ -378,6 +380,8 @@ class Config extends Secure_Controller
'enforce_privacy' => $this->request->getPost('enforce_privacy') != null,
'receiving_calculate_average_price' => $this->request->getPost('receiving_calculate_average_price') != null,
'lines_per_page' => $this->request->getPost('lines_per_page', FILTER_SANITIZE_NUMBER_INT),
'notify_horizontal_position' => $this->request->getPost('notify_horizontal_position'),
'notify_vertical_position' => $this->request->getPost('notify_vertical_position'),
'image_max_width' => $this->request->getPost('image_max_width', FILTER_SANITIZE_NUMBER_INT),
'image_max_height' => $this->request->getPost('image_max_height', FILTER_SANITIZE_NUMBER_INT),
'image_max_size' => $this->request->getPost('image_max_size', FILTER_SANITIZE_NUMBER_INT),
@@ -421,26 +425,6 @@ class Config extends Secure_Controller
return $this->response->setJSON(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]);
}
/**
* Saves Appearance configuration. Used in app/Views/configs/appearance_config.php
*/
public function postSaveAppearance(): ResponseInterface
{
$batch_save_data = [
'theme' => $this->request->getPost('theme'),
'login_form' => $this->request->getPost('login_form'),
'notify_horizontal_position' => $this->request->getPost('notify_horizontal_position'),
'notify_vertical_position' => $this->request->getPost('notify_vertical_position'),
'color_mode' => $this->request->getPost('color_mode'),
'config_menu_position' => $this->request->getPost('config_menu_position'),
'responsive_design' => $this->request->getPost('responsive_design') != null
];
$success = $this->appconfig->batch_save($batch_save_data);
return $this->response->setJSON(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]);
}
/**
* Checks a number against the currently selected locale. Used in app/Views/configs/locale_config.php
*
@@ -497,7 +481,6 @@ class Config extends Secure_Controller
'currency_code' => $this->request->getPost('currency_code'),
'language_code' => $exploded[0],
'language' => $exploded[1],
'rtl_language' => $this->request->getPost('rtl_language') != null,
'timezone' => $this->request->getPost('timezone'),
'dateformat' => $this->request->getPost('dateformat'),
'timeformat' => $this->request->getPost('timeformat'),
@@ -941,7 +924,9 @@ class Config extends Secure_Controller
public function postSaveReceipt(): ResponseInterface
{
$batch_save_data = [
'receipt_template' => $this->request->getPost('receipt_template'),
'receipt_template' => Sale_lib::isValidReceiptTemplate($this->request->getPost('receipt_template'))
? $this->request->getPost('receipt_template')
: 'receipt_default',
'receipt_font_size' => $this->request->getPost('receipt_font_size', FILTER_SANITIZE_NUMBER_INT),
'print_delay_autoreturn' => $this->request->getPost('print_delay_autoreturn', FILTER_SANITIZE_NUMBER_INT),
'email_receipt_check_behaviour' => $this->request->getPost('email_receipt_check_behaviour'),

View File

@@ -154,8 +154,23 @@ class Items extends Secure_Controller
{
helper('file');
$pic_filename = rawurldecode($pic_filename);
$file_extension = pathinfo($pic_filename, PATHINFO_EXTENSION);
// Security: Sanitize filename to prevent path traversal
// Use basename() to strip directory components and prevent '../' attacks
$pic_filename = basename(rawurldecode($pic_filename));
$file_extension = strtolower(pathinfo($pic_filename, PATHINFO_EXTENSION));
// Validate file extension against system-configured allowed image types
// Handle both legacy pipe-separated and current comma-separated formats
// Fallback to types that GD library can process for thumbnail generation
$allowed_types = $this->config['image_allowed_types'] ?? 'jpg,jpeg,gif,png,webp,bmp,tif,tiff';
$allowed_extensions = strpos($allowed_types, '|') !== false
? explode('|', $allowed_types)
: explode(',', $allowed_types);
if (!in_array($file_extension, $allowed_extensions, true)) {
return $this->response->setStatusCode(400)->setBody('Invalid file type');
}
$images = glob("./uploads/item_pics/$pic_filename");
$base_path = './uploads/item_pics/' . pathinfo($pic_filename, PATHINFO_FILENAME);
@@ -1040,14 +1055,20 @@ class Items extends Secure_Controller
});
if (!$isFailedRow && $this->item->save_value($itemData, $itemId)) {
$this->save_tax_data($row, $itemData);
$this->save_inventory_quantities($row, $itemData, $allowedStockLocations, $employeeId);
if (!$this->save_tax_data($row, $itemData)) {
$isFailedRow = true;
}
if (!$this->save_inventory_quantities($row, $itemData, $allowedStockLocations, $employeeId)) {
$isFailedRow = true;
}
$csvAttributeValues = $this->extractAttributeData($row);
$isFailedRow = !$this->attribute->saveCSVRowAttributeData($csvAttributeValues, $itemData, $attributeData);
if (!$this->attribute->saveCSVRowAttributeData($csvAttributeValues, $itemData, $attributeData)) {
$isFailedRow = true;
}
if ($isFailedRow) {
$failedRow = $key + 2;
$failCodes[] = $failedRow;
log_message('error', "CSV Item import failed on line $failedRow while saving attributes.");
log_message('error', "CSV Item import failed on line $failedRow while saving item.");
continue;
}
@@ -1237,13 +1258,15 @@ class Items extends Secure_Controller
* @param array $item_data
* @param array $allowed_locations
* @param int $employee_id
* @return bool Returns true on success, false on failure
* @throws ReflectionException
*/
private function save_inventory_quantities(array $row, array $item_data, array $allowed_locations, int $employee_id): void
private function save_inventory_quantities(array $row, array $item_data, array $allowed_locations, int $employee_id): bool
{
// Quantities & Inventory Section
$comment = lang('Items.inventory_CSV_import_quantity');
$is_update = (bool)$row['Id'];
$success = true;
foreach ($allowed_locations as $location_id => $location_name) {
$item_quantity_data = ['item_id' => $item_data['item_id'], 'location_id' => $location_id];
@@ -1257,20 +1280,22 @@ class Items extends Secure_Controller
if (!empty($row["location_$location_name"]) || $row["location_$location_name"] === '0') {
$item_quantity_data['quantity'] = $row["location_$location_name"];
$this->item_quantity->save_value($item_quantity_data, $item_data['item_id'], $location_id);
$success &= $this->item_quantity->save_value($item_quantity_data, $item_data['item_id'], $location_id);
$csv_data['trans_inventory'] = $row["location_$location_name"];
$this->inventory->insert($csv_data, false);
$success &= (bool)$this->inventory->insert($csv_data, false);
} elseif ($is_update) {
return;
continue;
} else {
$item_quantity_data['quantity'] = 0;
$this->item_quantity->save_value($item_quantity_data, $item_data['item_id'], $location_id);
$success &= $this->item_quantity->save_value($item_quantity_data, $item_data['item_id'], $location_id);
$csv_data['trans_inventory'] = 0;
$this->inventory->insert($csv_data, false);
$success &= (bool)$this->inventory->insert($csv_data, false);
}
}
return (bool)$success;
}
/**
@@ -1278,8 +1303,9 @@ class Items extends Secure_Controller
*
* @param array $row
* @param array $item_data
* @return bool Returns true on success, false on failure
*/
private function save_tax_data(array $row, array $item_data): void
private function save_tax_data(array $row, array $item_data): bool
{
$items_taxes_data = [];
@@ -1291,9 +1317,11 @@ class Items extends Secure_Controller
$items_taxes_data[] = ['name' => $row['Tax 2 Name'], 'percent' => $row['Tax 2 Percent']];
}
if (isset($items_taxes_data)) {
$this->item_taxes->save_value($items_taxes_data, $item_data['item_id']);
if (!empty($items_taxes_data)) {
return $this->item_taxes->save_value($items_taxes_data, $item_data['item_id']);
}
return true;
}
/**

View File

@@ -1246,13 +1246,15 @@ class Reports extends Secure_Controller
public function get_payment_type(): array
{
return [
'all' => lang('Common.none_selected_text'),
'cash' => lang('Sales.cash'),
'due' => lang('Sales.due'),
'check' => lang('Sales.check'),
'credit' => lang('Sales.credit'),
'debit' => lang('Sales.debit'),
'invoices' => lang('Sales.invoice')
'all' => lang('Common.none_selected_text'),
'cash' => lang('Sales.cash'),
'due' => lang('Sales.due'),
'check' => lang('Sales.check'),
'credit' => lang('Sales.credit'),
'debit' => lang('Sales.debit'),
'bank_transfer' => lang('Sales.bank_transfer'),
'wallet' => lang('Sales.wallet'),
'invoices' => lang('Sales.invoice')
];
}
@@ -1308,9 +1310,9 @@ class Reports extends Secure_Controller
'comment' => $row['comment'],
'edit' => anchor(
'sales/edit/' . $row['sale_id'],
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch print_hide',
'class' => 'modal-dlg print_hide',
$button_key => $button_label,
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Sales.update')
@@ -1435,9 +1437,9 @@ class Reports extends Secure_Controller
'comment' => $row['comment'],
'edit' => anchor(
'sales/edit/' . $row['sale_id'],
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch print_hide',
'class' => 'modal-dlg print_hide',
$button_key => $button_label,
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Sales.update')
@@ -1567,9 +1569,9 @@ class Reports extends Secure_Controller
'comment' => $row['comment'],
'edit' => anchor(
'sales/edit/' . $row['sale_id'],
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch print_hide',
'class' => 'modal-dlg print_hide',
$button_key => $button_label,
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Sales.update')
@@ -1655,9 +1657,9 @@ class Reports extends Secure_Controller
'comment' => $report_data['comment'],
'edit' => anchor(
'sales/edit/' . $report_data['sale_id'],
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch print_hide',
'class' => 'modal-dlg print_hide',
$button_key => $button_label,
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Sales.update')
@@ -1831,9 +1833,9 @@ class Reports extends Secure_Controller
'comment' => $row['comment'],
'edit' => anchor(
'sales/edit/' . $row['sale_id'],
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch print_hide',
'class' => 'modal-dlg print_hide',
$button_key => $button_label,
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Sales.update')
@@ -1911,9 +1913,9 @@ class Reports extends Secure_Controller
'comment' => $report_data['comment'],
'edit' => anchor(
'receivings/edit/' . $report_data['receiving_id'],
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch print_hide',
'class' => 'modal-dlg print_hide',
'data-btn-submit' => lang('Common.submit'),
'data-btn-delete' => lang('Common.delete'),
'title' => lang('Receivings.update')
@@ -1971,9 +1973,9 @@ class Reports extends Secure_Controller
'comment' => $row['comment'],
'edit' => anchor(
'receivings/edit/' . $row['receiving_id'],
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch print_hide',
'class' => 'modal-dlg print_hide',
'data-btn-delete' => lang('Common.delete'),
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Receivings.update')

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class AddUBLConfig extends Migration
{
public function up(): void
{
log_message('info', 'Adding UBL configuration.');
$config_values = [
['key' => 'invoice_format', 'value' => 'pdf_only'],
];
$this->db->table('app_config')->ignore(true)->insertBatch($config_values);
}
public function down(): void
{
$this->db->table('app_config')->whereIn('key', ['invoice_format'])->delete();
}
}

View File

@@ -79,14 +79,10 @@ INSERT INTO `ospos_app_config` (`key`, `value`) VALUES
('smtp_timeout', '5'),
('smtp_crypto', 'ssl'),
('receipt_template', 'receipt_default'),
('theme', 'bootstrap'),
('theme', 'flatly'),
('statistics', '1'),
('language', 'english'),
('language_code', 'en'),
('rtl_language', '0'),
('color_mode', 'light'),
('config_menu_position', 'start'),
('responsive_design', '1');
('language_code', 'en');
-- --------------------------------------------------------

View File

@@ -0,0 +1,229 @@
<?php
use Config\OSPOS;
/**
* Country code helper for mapping country names to ISO 3166-1 alpha-2 codes
*/
if (!function_exists('getCountryCode')) {
/**
* Convert country name to ISO 3166-1 alpha-2 code
*
* @param string $countryName Country name (full name in English)
* @return string ISO 3166-1 alpha-2 code, or 'BE' as default for Belgium
*/
function getCountryCode(string $countryName): string
{
if (empty($countryName)) {
return 'BE'; // Default to Belgium
}
$countryMap = [
// Major countries
'Belgium' => 'BE',
'Belgique' => 'BE',
'België' => 'BE',
'United States' => 'US',
'USA' => 'US',
'United States of America' => 'US',
'United Kingdom' => 'GB',
'UK' => 'GB',
'Great Britain' => 'GB',
'France' => 'FR',
'Germany' => 'DE',
'Deutschland' => 'DE',
'Netherlands' => 'NL',
'The Netherlands' => 'NL',
'Nederland' => 'NL',
'Italy' => 'IT',
'Italia' => 'IT',
'Spain' => 'ES',
'España' => 'ES',
'Poland' => 'PL',
'Polska' => 'PL',
'Portugal' => 'PT',
'Sweden' => 'SE',
'Sverige' => 'SE',
'Norway' => 'NO',
'Norge' => 'NO',
'Denmark' => 'DK',
'Danmark' => 'DK',
'Finland' => 'FI',
'Suomi' => 'FI',
'Switzerland' => 'CH',
'Suisse' => 'CH',
'Schweiz' => 'CH',
'Austria' => 'AT',
'Österreich' => 'AT',
'Ireland' => 'IE',
'Luxembourg' => 'LU',
'Greece' => 'GR',
'Czech Republic' => 'CZ',
'Czechia' => 'CZ',
'Hungary' => 'HU',
'Romania' => 'RO',
'Bulgaria' => 'BG',
'Slovakia' => 'SK',
'Slovenia' => 'SI',
'Estonia' => 'EE',
'Latvia' => 'LV',
'Lithuania' => 'LT',
'Croatia' => 'HR',
'Serbia' => 'RS',
'Montenegro' => 'ME',
'Bosnia and Herzegovina' => 'BA',
'North Macedonia' => 'MK',
'Albania' => 'AL',
'Kosovo' => 'XK',
'Turkey' => 'TR',
'Türkiye' => 'TR',
'Russia' => 'RU',
'Russian Federation' => 'RU',
'Ukraine' => 'UA',
'Belarus' => 'BY',
'Moldova' => 'MD',
'Georgia' => 'GE',
'Armenia' => 'AM',
'Azerbaijan' => 'AZ',
'Kazakhstan' => 'KZ',
'Uzbekistan' => 'UZ',
// Other major economies
'China' => 'CN',
'Japan' => 'JP',
'South Korea' => 'KR',
'Korea' => 'KR',
'India' => 'IN',
'Australia' => 'AU',
'New Zealand' => 'NZ',
'Canada' => 'CA',
'Mexico' => 'MX',
'Brazil' => 'BR',
'Argentina' => 'AR',
'Chile' => 'CL',
'Colombia' => 'CO',
'Peru' => 'PE',
'South Africa' => 'ZA',
'Egypt' => 'EG',
'Nigeria' => 'NG',
'Kenya' => 'KE',
'Morocco' => 'MA',
// If already ISO code, return as-is
'BE' => 'BE',
'US' => 'US',
'GB' => 'GB',
'FR' => 'FR',
'DE' => 'DE',
'NL' => 'NL',
'IT' => 'IT',
'ES' => 'ES',
'PT' => 'PT',
'SE' => 'SE',
'NO' => 'NO',
'DK' => 'DK',
'FI' => 'FI',
'CH' => 'CH',
'AT' => 'AT',
'IE' => 'IE',
'LU' => 'LU',
'GR' => 'GR',
'CZ' => 'CZ',
'HU' => 'HU',
'RO' => 'RO',
'BG' => 'BG',
'SK' => 'SK',
'SI' => 'SI',
'EE' => 'EE',
'LV' => 'LV',
'LT' => 'LT',
'HR' => 'HR',
'RS' => 'RS',
'ME' => 'ME',
'BA' => 'BA',
'MK' => 'MK',
'AL' => 'AL',
'TR' => 'TR',
'RU' => 'RU',
'UA' => 'UA',
];
// Try exact match first
$normalized = trim($countryName);
if (isset($countryMap[$normalized])) {
return $countryMap[$normalized];
}
// Try case-insensitive match
$normalizedLower = strtolower($normalized);
foreach ($countryMap as $key => $code) {
if (strtolower($key) === $normalizedLower) {
return $code;
}
}
// Try partial match (e.g., "United States" → "US")
foreach ($countryMap as $key => $code) {
if (stripos($key, $normalized) !== false || stripos($normalized, $key) !== false) {
return $code;
}
}
// Try matching ISO code directly
if (preg_match('/^[A-Z]{2}$/i', $normalized)) {
return strtoupper($normalized);
}
// Check if the country_codes config has a default
$config = config(OSPOS::class)->settings;
if (isset($config['country_codes']) && !empty($config['country_codes'])) {
$countries = explode(',', $config['country_codes']);
if (!empty($countries)) {
return strtoupper(trim($countries[0]));
}
}
// Default to Belgium (for Peppol compliance in Belgium)
return 'BE';
}
}
if (!function_exists('getCurrencyCode')) {
/**
* Get ISO 4217 currency code for a country
*
* @param string $countryCode ISO 3166-1 alpha-2 country code
* @return string ISO 4217 currency code
*/
function getCurrencyCode(string $countryCode): string
{
$currencyMap = [
'BE' => 'EUR',
'FR' => 'EUR',
'DE' => 'EUR',
'NL' => 'EUR',
'IT' => 'EUR',
'ES' => 'EUR',
'PT' => 'EUR',
'IE' => 'EUR',
'AT' => 'EUR',
'LU' => 'EUR',
'FI' => 'EUR',
'GR' => 'EUR',
'US' => 'USD',
'GB' => 'GBP',
'CH' => 'CHF',
'JP' => 'JPY',
'CN' => 'CNY',
'CA' => 'CAD',
'AU' => 'AUD',
'NZ' => 'NZD',
'IN' => 'INR',
'BR' => 'BRL',
'MX' => 'MXN',
'ZA' => 'ZAR',
];
return $currencyMap[$countryCode] ?? 'EUR'; // Default to EUR
}
}

View File

@@ -272,6 +272,9 @@ function get_payment_options(): array
$payments[lang('Sales.upi')] = lang('Sales.upi');
}
$payments[lang('Sales.bank_transfer')] = lang('Sales.bank_transfer');
$payments[lang('Sales.wallet')] = lang('Sales.wallet');
return $payments;
}

View File

@@ -85,6 +85,7 @@ function get_sales_manage_table_headers(): string
if ($config['invoice_enable']) {
$headers[] = ['invoice_number' => lang('Sales.invoice_number')];
$headers[] = ['invoice' => '', 'sortable' => false, 'escape' => false];
$headers[] = ['ubl' => '', 'sortable' => false, 'escape' => false];
}
$headers[] = ['receipt' => '', 'sortable' => false, 'escape' => false];
@@ -118,21 +119,28 @@ function get_sale_data_row(object $sale): array
? '-'
: anchor(
"$controller/invoice/$sale->sale_id",
'<i class="bi bi-file-text"></i>',
'<span class="glyphicon glyphicon-list-alt"></span>',
['title' => lang('Sales.show_invoice')]
);
$row['ubl'] = empty($sale->invoice_number)
? '-'
: anchor(
"$controller/ublInvoice/$sale->sale_id",
'<span class="glyphicon glyphicon-download"></span>',
['title' => lang('Sales.download_ubl'), 'target' => '_blank']
);
}
$row['receipt'] = anchor(
"$controller/receipt/$sale->sale_id",
'<i class="bi bi-receipt"></i>',
'<span class="glyphicon glyphicon-usd"></span>',
['title' => lang('Sales.show_receipt')]
);
$row['edit'] = anchor(
"$controller/edit/$sale->sale_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch print_hide',
'class' => 'modal-dlg print_hide',
'data-btn-delete' => lang('Common.delete'),
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
@@ -232,18 +240,18 @@ function get_person_data_row(object $person): array
? ''
: anchor(
"Messages/view/$person->person_id",
'<i class="bi bi-telephone"></i>',
'<span class="glyphicon glyphicon-phone"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Messages.sms_send')
]
),
'edit' => anchor(
"$controller/view/$person->person_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . '.update') // TODO: String interpolation
]
@@ -299,18 +307,18 @@ function get_customer_data_row(object $person, object $stats): array
? ''
: anchor(
"Messages/view/$person->person_id",
'<i class="bi bi-telephone"></i>',
'<span class="glyphicon glyphicon-phone"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Messages.sms_send')
]
),
'edit' => anchor(
"$controller/view/$person->person_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]
@@ -369,18 +377,18 @@ function get_supplier_data_row(object $supplier): array
? ''
: anchor(
"Messages/view/$supplier->person_id",
'<i class="bi bi-telephone"></i>',
'<span class="glyphicon glyphicon-phone"></span>',
[
'class' => "modal-launch",
'class' => "modal-dlg",
'data-btn-submit' => lang('Common.submit'),
'title' => lang('Messages.sms_send')
]
),
'edit' => anchor(
"$controller/view/$supplier->person_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => "modal-launch",
'class' => "modal-dlg",
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]
@@ -498,26 +506,26 @@ function get_item_data_row(object $item): array
$icons = [
'inventory' => anchor(
"$controller/inventory/$item->item_id",
'<i class="bi bi-box"></i>',
'<span class="glyphicon glyphicon-pushpin"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".count")
]
),
'stock' => anchor(
"$controller/countDetails/$item->item_id",
'<i class="bi bi-info-square"></i>',
'<span class="glyphicon glyphicon-list-alt"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'title' => lang(ucfirst($controller) . ".details_count")
]
),
'edit' => anchor(
"$controller/view/$item->item_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]
@@ -561,9 +569,9 @@ function get_giftcard_data_row(object $giftcard): array
'value' => to_currency($giftcard->value),
'edit' => anchor(
"$controller/view/$giftcard->giftcard_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]
@@ -607,9 +615,9 @@ function get_item_kit_data_row(object $item_kit): array
'total_unit_price' => to_currency($item_kit->total_unit_price),
'edit' => anchor(
"$controller/view/$item_kit->item_kit_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]
@@ -715,9 +723,9 @@ function get_attribute_definition_data_row(object $attribute_row): array
'definition_flags' => $definition_flags,
'edit' => anchor(
"$controller/view/$attribute_row->definition_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]
@@ -755,9 +763,9 @@ function get_expense_category_data_row(object $expense_category): array
'category_description' => $expense_category->category_description,
'edit' => anchor(
"$controller/view/$expense_category->expense_category_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]
@@ -809,9 +817,9 @@ function get_expenses_data_row(object $expense): array
'created_by' => $expense->first_name . ' ' . $expense->last_name,
'edit' => anchor(
"$controller/view/$expense->expense_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]
@@ -904,16 +912,16 @@ function get_cash_up_data_row(object $cash_up): array
'close_date' => to_datetime(strtotime($cash_up->close_date)),
'close_employee_id' => $cash_up->close_first_name . ' ' . $cash_up->close_last_name,
'closed_amount_cash' => to_currency($cash_up->closed_amount_cash),
'note' => $cash_up->note ? '<i class="bi bi-check-lg"></i>' : '<i class="bi bi-x-lg"></i>',
'note' => $cash_up->note ? '<span class="glyphicon glyphicon-ok"></span>' : '<span class="glyphicon glyphicon-remove"></span>',
'closed_amount_due' => to_currency($cash_up->closed_amount_due),
'closed_amount_card' => to_currency($cash_up->closed_amount_card),
'closed_amount_check' => to_currency($cash_up->closed_amount_check),
'closed_amount_total' => to_currency($cash_up->closed_amount_total),
'edit' => anchor(
"$controller/view/$cash_up->cashup_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller) . ".update")
]

View File

@@ -36,9 +36,9 @@ function get_tax_code_data_row($tax_code_row): array
'state' => $tax_code_row->state,
'edit' => anchor(
"$controller_name/view_tax_codes/$tax_code_row->tax_code",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller_name) . ".update_tax_codes")
]
@@ -74,9 +74,9 @@ function get_tax_categories_data_row($tax_categories_row): array
'tax_group_sequence' => $tax_categories_row->tax_group_sequence,
'edit' => anchor(
"$controller_name/view/$tax_categories_row->tax_category_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller_name) . ".update")
]
@@ -111,9 +111,9 @@ function get_tax_jurisdictions_data_row($tax_jurisdiction_row): array
'reporting_authority' => $tax_jurisdiction_row->reporting_authority,
'edit' => anchor(
"$controller_name/view/$tax_jurisdiction_row->jurisdiction_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller_name) . ".update")
]
@@ -156,9 +156,9 @@ function get_tax_rates_data_row($tax_rates_row): array
'rounding_code_name' => Rounding_mode::get_rounding_code_name($tax_rates_row->tax_rounding_code),
'edit' => anchor(
"$controller_name/view/$tax_rates_row->tax_rate_id",
'<i class="bi bi-pencil-square"></i>',
'<span class="glyphicon glyphicon-edit"></span>',
[
'class' => 'modal-launch',
'class' => 'modal-dlg',
'data-btn-submit' => lang('Common.submit'),
'title' => lang(ucfirst($controller_name) . ".update")
]

View File

@@ -9,6 +9,7 @@ return [
"amount_due" => "Amount Due",
"amount_tendered" => "Amount Tendered",
"authorized_signature" => "Authorised Signature",
"bank_transfer" => "Bank Transfer",
"cancel_sale" => "Cancel",
"cash" => "Cash",
"cash_1" => "",
@@ -223,6 +224,7 @@ return [
"update" => "Update",
"upi" => "UPI",
"visa" => "",
"wallet" => "Wallet",
"wholesale" => "",
"work_order" => "Work Order",
"work_order_number" => "Work Order Number",

View File

@@ -1,232 +1,237 @@
<?php
return [
"customers_available_points" => "Points Available",
"rewards_package" => "Rewards",
"rewards_remaining_balance" => "Reward Points remaining value is ",
"account_number" => "Account #",
"add_payment" => "Add Payment",
"amount_due" => "Amount Due",
"amount_tendered" => "Amount Tendered",
"authorized_signature" => "Authorized Signature",
"cancel_sale" => "Cancel",
"cash" => "Cash",
"cash_1" => "",
"cash_2" => "",
"cash_3" => "",
"cash_4" => "",
"cash_adjustment" => "Cash Adjustment",
"cash_deposit" => "Cash Deposit",
"cash_filter" => "Cash",
"change_due" => "Change Due",
"change_price" => "Change Selling Price",
"check" => "Check",
"check_balance" => "Check remainder",
"check_filter" => "Check",
"close" => "",
"comment" => "Comment",
"comments" => "Comments",
"company_name" => "",
"complete" => "",
"complete_sale" => "Complete",
"confirm_cancel_sale" => "Are you sure you want to clear this sale? All items will be cleared.",
"confirm_delete" => "Are you sure you want to delete the selected Sale(s)?",
"confirm_restore" => "Are you sure you want to restore the selected Sale(s)?",
"credit" => "Credit Card",
"credit_deposit" => "Credit Deposit",
"credit_filter" => "Credit Card",
"current_table" => "",
"customer" => "Customer",
"customer_address" => "Address",
"customer_discount" => "Discount",
"customer_email" => "Email",
"customer_location" => "Location",
"customer_mailchimp_status" => "MailChimp Status",
"customer_optional" => "(Required for Due Payments)",
"customer_required" => "(Required)",
"customer_total" => "Total",
"customer_total_spent" => "",
"daily_sales" => "",
"date" => "Sale Date",
"date_range" => "Date Range",
"date_required" => "A correct date must be entered.",
"date_type" => "Date is a required field.",
"debit" => "Debit Card",
"debit_filter" => "",
"delete" => "Allow Delete",
"delete_confirmation" => "Are you sure you want to delete this sale? This action cannot be undone.",
"delete_entire_sale" => "Delete Entire Sale",
"delete_successful" => "Sale delete successful.",
"delete_unsuccessful" => "Sale delete failed.",
"description_abbrv" => "Desc.",
"discard" => "Discard",
"discard_quote" => "",
"discount" => "Disc",
"discount_included" => "% Discount",
"discount_short" => "%",
"due" => "Due",
"due_filter" => "Due",
"edit" => "Edit",
"edit_item" => "Edit Item",
"edit_sale" => "Edit Sale",
"email_receipt" => "Email Receipt",
"employee" => "Employee",
"entry" => "Entry",
"error_editing_item" => "Error editing item",
"negative_price_invalid" => "Price cannot be negative.",
"negative_quantity_invalid" => "Quantity cannot be negative.",
"negative_discount_invalid" => "Discount cannot be negative.",
"discount_percent_exceeds_100" => "Percentage discount cannot exceed 100%.",
"discount_exceeds_item_total" => "Discount cannot exceed the item total.",
"negative_total_invalid" => "Sale total cannot be negative. Check item discounts and quantities.",
"find_or_scan_item" => "Find or Scan Item",
"find_or_scan_item_or_receipt" => "Find or Scan Item or Receipt",
"giftcard" => "Gift Card",
"giftcard_balance" => "Gift Card Balance",
"giftcard_filter" => "",
"giftcard_number" => "Gift Card Number",
"group_by_category" => "Group by Category",
"group_by_type" => "Group by Type",
"hsn" => "HSN",
"id" => "Sale ID",
"include_prices" => "Include Prices?",
"invoice" => "Invoice",
"invoice_confirm" => "This invoice will be sent to",
"invoice_enable" => "Invoice Number",
"invoice_filter" => "Invoices",
"invoice_no_email" => "This customer does not have a valid email address.",
"invoice_number" => "Invoice #",
"invoice_number_duplicate" => "Invoice Number {0} must be unique.",
"invoice_sent" => "Invoice sent to",
"invoice_total" => "Invoice Total",
"invoice_type_custom_invoice" => "Custom Invoice (custom_invoice.php)",
"invoice_type_custom_tax_invoice" => "Custom Tax Invoice (custom_tax_invoice.php)",
"invoice_type_invoice" => "Invoice (invoice.php)",
"invoice_type_tax_invoice" => "Tax Invoice (tax_invoice.php)",
"invoice_unsent" => "Invoice failed to be sent to",
"invoice_update" => "Recount",
"item_insufficient_of_stock" => "Item has insufficient stock.",
"item_name" => "Item Name",
"item_number" => "Item #",
"item_out_of_stock" => "Item is out of stock.",
"key_browser" => "Helpful Shortcuts",
"key_cancel" => "Cancels Current Quote/Invoice/Sale",
"key_customer_search" => "Customer Search",
"key_finish_quote" => "Finish Quote/Invoice without payment",
"key_finish_sale" => "Add Payment and Complete Invoice/Sale",
"key_full" => "Open in Full Screen Mode",
"key_function" => "Function",
"key_help" => "Shortcuts",
"key_help_modal" => "Open Shortcuts Window",
"key_in" => "Zoom in",
"key_item_search" => "Item Search",
"key_out" => "Zoom Out",
"key_payment" => "Add Payment",
"key_print" => "Print Current Page",
"key_restore" => "Restore Original Display/Zoom",
"key_search" => "Search Reports Tables",
"key_suspend" => "Suspend Current Sale",
"key_suspended" => "Show Suspended Sales",
"key_system" => "System Shortcuts",
"key_tendered" => "Edit Amount Tendered",
"key_title" => "Sales Keyboard Shortcuts",
"mc" => "",
"mode" => "Register Mode",
"must_enter_numeric" => "Amount Tendered must be a number.",
"must_enter_numeric_giftcard" => "Gift Card Number must be a number.",
"new_customer" => "New Customer",
"new_item" => "New Item",
"no_description" => "No description",
"no_filter" => "All",
"no_items_in_cart" => "There are no Items in the cart.",
"no_sales_to_display" => "No Sales to display.",
"none_selected" => "You have not selected any Sale(s) to delete.",
"nontaxed_ind" => " ",
"not_authorized" => "This action is not authorized.",
"one_or_multiple" => "Sale(s)",
"payment" => "Payment Type",
"payment_amount" => "Amount",
"payment_not_cover_total" => "Payment Amount must be greater than or equal to Total.",
"payment_type" => "Type",
"payments" => "",
"payments_total" => "Payments Total",
"price" => "Price",
"print_after_sale" => "Print after Sale",
"quantity" => "Quantity",
"quantity_less_than_reorder_level" => "Warning: Desired Quantity is below Reorder Level for that Item.",
"quantity_less_than_zero" => "Warning: Desired Quantity is insufficient. You can still process the sale, but audit your inventory.",
"quantity_of_items" => "Quantity of {0} Items",
"quote" => "Quote",
"quote_number" => "Quote Number",
"quote_number_duplicate" => "Quote Number must be unique.",
"quote_sent" => "Quote sent to",
"quote_unsent" => "Quote failed to be sent to",
"receipt" => "Sales Receipt",
"receipt_no_email" => "This customer does not have a valid email address.",
"receipt_number" => "Sale #",
"receipt_sent" => "Receipt sent to",
"receipt_unsent" => "Receipt failed to be sent to",
"refund" => "Refund Type",
"register" => "Sales Register",
"remove_customer" => "Remove Customer",
"remove_discount" => "",
"return" => "Return",
"rewards" => "Reward Points",
"rewards_balance" => "Reward Points Balance",
"sale" => "Sale",
"sale_by_invoice" => "Sale by Invoice",
"sale_for_customer" => "Customer:",
"sale_time" => "Time",
"sales_tax" => "Sales Tax",
"sales_total" => "",
"select_customer" => "Select Customer",
"selected_customer" => "Selected Customer",
"send_invoice" => "Send Invoice",
"send_quote" => "Send Quote",
"send_receipt" => "Send Receipt",
"send_work_order" => "Send Work Order",
"serial" => "Serial",
"service_charge" => "",
"show_due" => "",
"show_invoice" => "Show Invoice",
"show_receipt" => "Show Receipt",
"start_typing_customer_name" => "Start typing customer details...",
"start_typing_item_name" => "Start typing Item Name or scan Barcode...",
"stock" => "Stock",
"stock_location" => "Stock Location",
"sub_total" => "Subtotal",
"successfully_deleted" => "You have successfully deleted",
"successfully_restored" => "You have successfully restored",
"successfully_suspended_sale" => "Sale suspend successful.",
"successfully_updated" => "Sale update successful.",
"suspend_sale" => "Suspend",
"suspended_doc_id" => "Document",
"suspended_sale_id" => "ID",
"suspended_sales" => "Suspended",
"table" => "Table",
"takings" => "Daily Sales",
"tax" => "Tax",
"tax_id" => "Tax Id",
"tax_invoice" => "Tax Invoice",
"tax_percent" => "Tax %",
"taxed_ind" => "T",
"total" => "Total",
"total_tax_exclusive" => "Tax excluded",
"transaction_failed" => "Sales Transaction failed.",
"unable_to_add_item" => "Item add to Sale failed",
"unsuccessfully_deleted" => "Sale(s) delete failed.",
"unsuccessfully_restored" => "Sale(s) restore failed.",
"unsuccessfully_suspended_sale" => "Sale suspend failed.",
"unsuccessfully_updated" => "Sale update failed.",
"unsuspend" => "Unsuspend",
"unsuspend_and_delete" => "Action",
"update" => "Update",
"upi" => "UPI",
"visa" => "",
"wholesale" => "",
"work_order" => "Work Order",
"work_order_number" => "Work Order Number",
"work_order_number_duplicate" => "Work Order Number must be unique.",
"work_order_sent" => "Work Order sent to",
"work_order_unsent" => "Work Order failed to be sent to",
'customers_available_points' => 'Points Available',
'rewards_package' => 'Rewards',
'rewards_remaining_balance' => 'Reward Points remaining value is ',
'account_number' => 'Account #',
'add_payment' => 'Add Payment',
'amount_due' => 'Amount Due',
'amount_tendered' => 'Amount Tendered',
'authorized_signature' => 'Authorized Signature',
'bank_transfer' => 'Bank Transfer',
'cancel_sale' => 'Cancel',
'cash' => 'Cash',
'cash_1' => '',
'cash_2' => '',
'cash_3' => '',
'cash_4' => '',
'cash_adjustment' => 'Cash Adjustment',
'cash_deposit' => 'Cash Deposit',
'cash_filter' => 'Cash',
'change_due' => 'Change Due',
'change_price' => 'Change Selling Price',
'check' => 'Check',
'check_balance' => 'Check remainder',
'check_filter' => 'Check',
'close' => '',
'comment' => 'Comment',
'comments' => 'Comments',
'company_name' => '',
'complete' => '',
'complete_sale' => 'Complete',
'confirm_cancel_sale' => 'Are you sure you want to clear this sale? All items will be cleared.',
'confirm_delete' => 'Are you sure you want to delete the selected Sale(s)?',
'confirm_restore' => 'Are you sure you want to restore the selected Sale(s)?',
'credit' => 'Credit Card',
'credit_deposit' => 'Credit Deposit',
'credit_filter' => 'Credit Card',
'current_table' => '',
'customer' => 'Customer',
'customer_address' => 'Address',
'customer_discount' => 'Discount',
'customer_email' => 'Email',
'customer_location' => 'Location',
'customer_mailchimp_status' => 'MailChimp Status',
'customer_optional' => '(Required for Due Payments)',
'customer_required' => '(Required)',
'customer_total' => 'Total',
'customer_total_spent' => '',
'daily_sales' => '',
'date' => 'Sale Date',
'date_range' => 'Date Range',
'date_required' => 'A correct date must be entered.',
'date_type' => 'Date is a required field.',
'debit' => 'Debit Card',
'debit_filter' => '',
'delete' => 'Allow Delete',
'delete_confirmation' => 'Are you sure you want to delete this sale? This action cannot be undone.',
'delete_entire_sale' => 'Delete Entire Sale',
'delete_successful' => 'Sale delete successful.',
'delete_unsuccessful' => 'Sale delete failed.',
'description_abbrv' => 'Desc.',
'discard' => 'Discard',
'discard_quote' => '',
'discount' => 'Disc',
'discount_included' => '% Discount',
'discount_short' => '%',
'due' => 'Due',
'due_filter' => 'Due',
'edit' => 'Edit',
'edit_item' => 'Edit Item',
'edit_sale' => 'Edit Sale',
'email_receipt' => 'Email Receipt',
'employee' => 'Employee',
'entry' => 'Entry',
'error_editing_item' => 'Error editing item',
'negative_price_invalid' => 'Price cannot be negative.',
'negative_quantity_invalid' => 'Quantity cannot be negative.',
'negative_discount_invalid' => 'Discount cannot be negative.',
'discount_percent_exceeds_100' => 'Percentage discount cannot exceed 100%.',
'discount_exceeds_item_total' => 'Discount cannot exceed the item total.',
'negative_total_invalid' => 'Sale total cannot be negative. Check item discounts and quantities.',
'find_or_scan_item' => 'Find or Scan Item',
'find_or_scan_item_or_receipt' => 'Find or Scan Item or Receipt',
'giftcard' => 'Gift Card',
'giftcard_balance' => 'Gift Card Balance',
'giftcard_filter' => '',
'giftcard_number' => 'Gift Card Number',
'group_by_category' => 'Group by Category',
'group_by_type' => 'Group by Type',
'hsn' => 'HSN',
'id' => 'Sale ID',
'include_prices' => 'Include Prices?',
'invoice' => 'Invoice',
'invoice_confirm' => 'This invoice will be sent to',
'invoice_enable' => 'Invoice Number',
'invoice_filter' => 'Invoices',
'invoice_no_email' => 'This customer does not have a valid email address.',
'invoice_number' => 'Invoice #',
'invoice_number_duplicate' => 'Invoice Number {0} must be unique.',
'invoice_sent' => 'Invoice sent to',
'invoice_total' => 'Invoice Total',
'invoice_type_custom_invoice' => 'Custom Invoice (custom_invoice.php)',
'invoice_type_custom_tax_invoice' => 'Custom Tax Invoice (custom_tax_invoice.php)',
'invoice_type_invoice' => 'Invoice (invoice.php)',
'invoice_type_tax_invoice' => 'Tax Invoice (tax_invoice.php)',
'invoice_unsent' => 'Invoice failed to be sent to',
'invoice_update' => 'Recount',
'item_insufficient_of_stock' => 'Item has insufficient stock.',
'item_name' => 'Item Name',
'item_number' => 'Item #',
'item_out_of_stock' => 'Item is out of stock.',
'key_browser' => 'Helpful Shortcuts',
'key_cancel' => 'Cancels Current Quote/Invoice/Sale',
'key_customer_search' => 'Customer Search',
'key_finish_quote' => 'Finish Quote/Invoice without payment',
'key_finish_sale' => 'Add Payment and Complete Invoice/Sale',
'key_full' => 'Open in Full Screen Mode',
'key_function' => 'Function',
'key_help' => 'Shortcuts',
'key_help_modal' => 'Open Shortcuts Window',
'key_in' => 'Zoom in',
'key_item_search' => 'Item Search',
'key_out' => 'Zoom Out',
'key_payment' => 'Add Payment',
'key_print' => 'Print Current Page',
'key_restore' => 'Restore Original Display/Zoom',
'key_search' => 'Search Reports Tables',
'key_suspend' => 'Suspend Current Sale',
'key_suspended' => 'Show Suspended Sales',
'key_system' => 'System Shortcuts',
'key_tendered' => 'Edit Amount Tendered',
'key_title' => 'Sales Keyboard Shortcuts',
'mc' => '',
'mode' => 'Register Mode',
'must_enter_numeric' => 'Amount Tendered must be a number.',
'must_enter_numeric_giftcard' => 'Gift Card Number must be a number.',
'new_customer' => 'New Customer',
'new_item' => 'New Item',
'no_description' => 'No description',
'no_filter' => 'All',
'no_items_in_cart' => 'There are no Items in the cart.',
'no_sales_to_display' => 'No Sales to display.',
'none_selected' => 'You have not selected any Sale(s) to delete.',
'nontaxed_ind' => ' ',
'not_authorized' => 'This action is not authorized.',
'one_or_multiple' => 'Sale(s)',
'payment' => 'Payment Type',
'payment_amount' => 'Amount',
'payment_not_cover_total' => 'Payment Amount must be greater than or equal to Total.',
'payment_type' => 'Type',
'payments' => '',
'payments_total' => 'Payments Total',
'price' => 'Price',
'print_after_sale' => 'Print after Sale',
'quantity' => 'Quantity',
'quantity_less_than_reorder_level' => 'Warning: Desired Quantity is below Reorder Level for that Item.',
'quantity_less_than_zero' => 'Warning: Desired Quantity is insufficient. You can still process the sale, but audit your inventory.',
'quantity_of_items' => 'Quantity of {0} Items',
'quote' => 'Quote',
'quote_number' => 'Quote Number',
'quote_number_duplicate' => 'Quote Number must be unique.',
'quote_sent' => 'Quote sent to',
'quote_unsent' => 'Quote failed to be sent to',
'receipt' => 'Sales Receipt',
'receipt_no_email' => 'This customer does not have a valid email address.',
'receipt_number' => 'Sale #',
'receipt_sent' => 'Receipt sent to',
'receipt_unsent' => 'Receipt failed to be sent to',
'refund' => 'Refund Type',
'register' => 'Sales Register',
'remove_customer' => 'Remove Customer',
'remove_discount' => '',
'return' => 'Return',
'rewards' => 'Reward Points',
'rewards_balance' => 'Reward Points Balance',
'sale' => 'Sale',
'sale_by_invoice' => 'Sale by Invoice',
'sale_for_customer' => 'Customer:',
'sale_time' => 'Time',
'sales_tax' => 'Sales Tax',
'sales_total' => '',
'select_customer' => 'Select Customer',
'selected_customer' => 'Selected Customer',
'send_invoice' => 'Send Invoice',
'send_quote' => 'Send Quote',
'send_receipt' => 'Send Receipt',
'send_work_order' => 'Send Work Order',
'serial' => 'Serial',
'service_charge' => '',
'show_due' => '',
'show_invoice' => 'Show Invoice',
'show_receipt' => 'Show Receipt',
'start_typing_customer_name' => 'Start typing customer details...',
'start_typing_item_name' => 'Start typing Item Name or scan Barcode...',
'stock' => 'Stock',
'stock_location' => 'Stock Location',
'sub_total' => 'Subtotal',
'successfully_deleted' => 'You have successfully deleted',
'successfully_restored' => 'You have successfully restored',
'successfully_suspended_sale' => 'Sale suspend successful.',
'successfully_updated' => 'Sale update successful.',
'suspend_sale' => 'Suspend',
'suspended_doc_id' => 'Document',
'suspended_sale_id' => 'ID',
'suspended_sales' => 'Suspended',
'table' => 'Table',
'takings' => 'Daily Sales',
'tax' => 'Tax',
'tax_id' => 'Tax Id',
'tax_invoice' => 'Tax Invoice',
'tax_percent' => 'Tax %',
'taxed_ind' => 'T',
'total' => 'Total',
'total_tax_exclusive' => 'Tax excluded',
'transaction_failed' => 'Sales Transaction failed.',
'unable_to_add_item' => 'Item add to Sale failed',
'unsuccessfully_deleted' => 'Sale(s) delete failed.',
'unsuccessfully_restored' => 'Sale(s) restore failed.',
'unsuccessfully_suspended_sale' => 'Sale suspend failed.',
'unsuccessfully_updated' => 'Sale update failed.',
'unsuspend' => 'Unsuspend',
'unsuspend_and_delete' => 'Action',
'update' => 'Update',
'upi' => 'UPI',
'visa' => '',
'wallet' => 'Wallet',
'wholesale' => '',
'work_order' => 'Work Order',
'work_order_number' => 'Work Order Number',
'work_order_number_duplicate' => 'Work Order Number must be unique.',
'work_order_sent' => 'Work Order sent to',
'work_order_unsent' => 'Work Order failed to be sent to',
'download_ubl' => 'Download UBL Invoice',
'ubl_generation_failed' => 'UBL invoice generation failed',
'sale_not_found' => 'Sale not found',
];

View File

@@ -9,6 +9,7 @@ return [
"amount_due" => "Monto Adeudado",
"amount_tendered" => "Cantidad Recibida",
"authorized_signature" => "Firma Autorizada",
"bank_transfer" => "Transferencia Bancaria",
"cancel_sale" => "Cancelar Venta",
"cash" => "Efectivo",
"cash_1" => "1",
@@ -222,6 +223,7 @@ return [
"update" => "Editar",
"upi" => "PIN UPI",
"visa" => "Tarjeta Visa",
"wallet" => "Monedero",
"wholesale" => "Precio al por mayor",
"work_order" => "Orden trabajo",
"work_order_number" => "Numero Orden Trabajo",

View File

@@ -9,6 +9,7 @@ return [
"amount_due" => "Monto de adeudo",
"amount_tendered" => "Cantidad Recibida",
"authorized_signature" => "Firma Autorizada",
"bank_transfer" => "Transferencia Bancaria",
"cancel_sale" => "Cancelar",
"cash" => "Efectivo",
"cash_1" => "",
@@ -222,6 +223,7 @@ return [
"update" => "Actualizar",
"upi" => "UPI",
"visa" => "",
"wallet" => "Monedero",
"wholesale" => "",
"work_order" => "Orden de trabajo",
"work_order_number" => "Número de orden de trabajo",

View File

@@ -9,6 +9,7 @@ return [
"amount_due" => "Montant à Payer",
"amount_tendered" => "Montant Présenté",
"authorized_signature" => "Signature autorisée",
"bank_transfer" => "Virement Bancaire",
"cancel_sale" => "Annuler la Vente",
"cash" => "Espèce",
"cash_1" => "",
@@ -222,6 +223,7 @@ return [
"update" => "Éditer",
"upi" => "UPI",
"visa" => "",
"wallet" => "Portefeuille",
"wholesale" => "",
"work_order" => "Commande de travail",
"work_order_number" => "Numéro de commande",

View File

@@ -118,4 +118,38 @@ class Email_lib
return '<img id="image" src="data:' . $mimeType . ';base64,' . $logo_data . '" alt="company_logo">';
}
/**
* Send email with multiple attachments
*
* @param string $to
* @param string $subject
* @param string $message
* @param array $attachments
* @return bool
*/
public function sendMultipleAttachments(string $to, string $subject, string $message, array $attachments): bool
{
$email = $this->email;
$email->setFrom($this->config['email'], $this->config['company']);
$email->setTo($to);
$email->setSubject($subject);
$email->setMessage($message);
foreach ($attachments as $attachment) {
if (!empty($attachment) && file_exists($attachment)) {
$email->attach($attachment);
}
}
$result = $email->send();
if (!$result) {
log_message('error', $email->printDebugger());
}
return $result;
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Libraries\InvoiceAttachment;
interface InvoiceAttachment
{
/**
* Generate the attachment content and write to a temp file.
*
* @param array $saleData The sale data from _load_sale_data()
* @param string $type The document type (invoice, tax_invoice, quote, work_order, receipt)
* @return string|null Absolute path to generated file, or null on failure
*/
public function generate(array $saleData, string $type): ?string;
/**
* Check if this attachment type is applicable for the document type.
* E.g., UBL only works for invoice/tax_invoice
*
* @param string $type The document type
* @param array $saleData The sale data (to check invoice_number existence)
* @return bool
*/
public function isApplicableForType(string $type, array $saleData): bool;
/**
* Get the file extension for this attachment.
*
* @return string E.g., 'pdf', 'xml'
*/
public function getFileExtension(): string;
/**
* Get the config values that enable this attachment.
* Returns array of config values that should generate this attachment.
*
* @return array E.g., ['pdf_only', 'both'] for PDF
*/
public function getEnabledConfigValues(): array;
}

View File

@@ -0,0 +1,75 @@
<?php
namespace App\Libraries\InvoiceAttachment;
class InvoiceAttachmentGenerator
{
/** @var InvoiceAttachment[] */
private array $attachments = [];
/**
* Register an attachment generator.
*/
public function register(InvoiceAttachment $attachment): self
{
$this->attachments[] = $attachment;
return $this;
}
/**
* Create generator with attachments based on config.
* Factory method that instantiates the right attachments.
*
* @param string $invoiceFormat Config value: 'pdf_only', 'ubl_only', or 'both'
* @return self
*/
public static function createFromConfig(string $invoiceFormat): self
{
$generator = new self();
if (in_array($invoiceFormat, ['pdf_only', 'both'], true)) {
$generator->register(new PdfAttachment());
}
if (in_array($invoiceFormat, ['ubl_only', 'both'], true)) {
$generator->register(new UblAttachment());
}
return $generator;
}
/**
* Generate all applicable attachments for a sale.
*
* @param array $saleData The sale data
* @param string $type The document type
* @return string[] Array of file paths to generated attachments
*/
public function generateAttachments(array $saleData, string $type): array
{
$files = [];
foreach ($this->attachments as $attachment) {
if ($attachment->isApplicableForType($type, $saleData)) {
$filepath = $attachment->generate($saleData, $type);
if ($filepath !== null) {
$files[] = $filepath;
}
}
}
return $files;
}
/**
* Clean up temporary attachment files.
*
* @param string[] $files
*/
public static function cleanup(array $files): void
{
foreach ($files as $file) {
@unlink($file);
}
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Libraries\InvoiceAttachment;
use CodeIgniter\Config\Services;
class PdfAttachment implements InvoiceAttachment
{
/**
* @inheritDoc
*/
public function generate(array $saleData, string $type): ?string
{
$view = Services::renderer();
$html = $view->setData($saleData)->render("sales/{$type}_email");
helper(['dompdf', 'file']);
$tempPath = tempnam(sys_get_temp_dir(), 'ospos_pdf_');
if ($tempPath === false) {
log_message('error', 'PDF attachment: failed to create temp file');
return null;
}
$filename = $tempPath . '.pdf';
rename($tempPath, $filename);
$pdfContent = create_pdf($html);
if (file_put_contents($filename, $pdfContent) === false) {
log_message('error', 'PDF attachment: failed to write content');
@unlink($filename);
return null;
}
return $filename;
}
/**
* @inheritDoc
*/
public function isApplicableForType(string $type, array $saleData): bool
{
return true;
}
/**
* @inheritDoc
*/
public function getFileExtension(): string
{
return 'pdf';
}
/**
* @inheritDoc
*/
public function getEnabledConfigValues(): array
{
return ['pdf_only', 'both'];
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Libraries\InvoiceAttachment;
use App\Libraries\UBLGenerator;
class UblAttachment implements InvoiceAttachment
{
public function __construct()
{
require_once ROOTPATH . 'vendor/autoload.php';
}
/**
* @inheritDoc
*/
public function generate(array $saleData, string $type): ?string
{
try {
$generator = new UBLGenerator();
$xml = $generator->generateUblInvoice($saleData);
$tempPath = tempnam(sys_get_temp_dir(), 'ospos_ubl_');
if ($tempPath === false) {
log_message('error', 'UBL attachment: failed to create temp file');
return null;
}
$filename = $tempPath . '.xml';
rename($tempPath, $filename);
if (file_put_contents($filename, $xml) === false) {
log_message('error', 'UBL attachment: failed to write content');
@unlink($filename);
return null;
}
return $filename;
} catch (\Exception $e) {
log_message('error', 'UBL attachment generation failed: ' . $e->getMessage());
return null;
}
}
/**
* @inheritDoc
*/
public function isApplicableForType(string $type, array $saleData): bool
{
return in_array($type, ['invoice', 'tax_invoice'], true)
&& !empty($saleData['invoice_number']);
}
/**
* @inheritDoc
*/
public function getFileExtension(): string
{
return 'xml';
}
/**
* @inheritDoc
*/
public function getEnabledConfigValues(): array
{
return ['ubl_only', 'both'];
}
}

View File

@@ -108,6 +108,11 @@ class Sale_lib
'custom_tax_invoice'
];
private const ALLOWED_RECEIPT_TEMPLATES = [
'receipt_default',
'receipt_short'
];
public function get_invoice_type_options(): array
{
$invoice_types = [];
@@ -161,6 +166,11 @@ class Sale_lib
return in_array($invoice_type, self::ALLOWED_INVOICE_TYPES, true);
}
public static function isValidReceiptTemplate(string $receipt_template): bool
{
return in_array($receipt_template, self::ALLOWED_RECEIPT_TEMPLATES, true);
}
/**
* @return array
*/

View File

@@ -0,0 +1,369 @@
<?php
namespace App\Libraries;
use DateTime;
use NumNum\UBL\AccountingParty;
use NumNum\UBL\Address;
use NumNum\UBL\AllowanceCharge;
use NumNum\UBL\Contact;
use NumNum\UBL\Country;
use NumNum\UBL\Generator;
use NumNum\UBL\Invoice;
use NumNum\UBL\InvoiceLine;
use NumNum\UBL\Item;
use NumNum\UBL\LegalMonetaryTotal;
use NumNum\UBL\Party;
use NumNum\UBL\PartyTaxScheme;
use NumNum\UBL\Price;
use NumNum\UBL\TaxCategory;
use NumNum\UBL\TaxScheme;
use NumNum\UBL\TaxSubTotal;
use NumNum\UBL\TaxTotal;
use NumNum\UBL\UnitCode;
helper(['country']);
class UBLGenerator
{
/**
* Generate UBL invoice XML from sale data
*
* @param array $saleData Sale data from _load_sale_data()
*
* @return string UBL XML string
*/
public function generateUblInvoice(array $saleData): string
{
$taxScheme = (new TaxScheme())->setId('VAT');
$isTaxIncluded = ! empty($saleData['tax_included']);
$supplierParty = $this->buildSupplierParty($saleData, $taxScheme);
$customerParty = $this->buildCustomerParty($saleData['customer_object'] ?? null, $taxScheme);
$invoiceLines = $this->buildInvoiceLines($saleData, $taxScheme, $isTaxIncluded);
$taxTotal = $this->buildTaxTotal($saleData['taxes'] ?? [], $taxScheme);
$monetaryTotal = $this->buildMonetaryTotal($saleData);
$invoice = (new Invoice())
->setUBLVersionId('2.1')
->setCustomizationId('urn:cen.eu:en16931:2017')
->setProfileId('urn:fdc:peppol.eu:2017:poacc:billing:01:1.0')
->setId($saleData['invoice_number'] ?? '')
->setIssueDate(new DateTime($saleData['transaction_date'] ?? 'now'))
->setInvoiceTypeCode(380)
->setAccountingSupplierParty($supplierParty)
->setAccountingCustomerParty($customerParty)
->setInvoiceLines($invoiceLines)
->setTaxTotal($taxTotal)
->setLegalMonetaryTotal($monetaryTotal);
// Set currency if available
if (! empty($saleData['currency_code'])) {
Generator::$currencyID = $saleData['currency_code'];
}
$generator = new Generator();
return $generator->invoice($invoice);
}
/**
* Build supplier (seller) party
*/
protected function buildSupplierParty(array $saleData, TaxScheme $taxScheme): AccountingParty
{
$config = $saleData['config'] ?? [];
$addressParts = $this->parseAddress($config['address'] ?? '');
$countryCode = getCountryCode($config['country'] ?? '');
$country = (new Country())->setIdentificationCode($countryCode);
$address = (new Address())
->setStreetName($addressParts['street'] ?? '')
->setBuildingNumber($addressParts['number'] ?? '')
->setCityName($addressParts['city'] ?? '')
->setPostalZone($addressParts['zip'] ?? '')
->setCountrySubentity($config['state'] ?? '')
->setCountry($country);
$party = (new Party())
->setName($config['company'] ?? '')
->setPostalAddress($address);
$partyTaxScheme = null;
if (! empty($config['account_number'])) {
$partyTaxScheme = (new PartyTaxScheme())
->setCompanyId($config['account_number'])
->setTaxScheme($taxScheme);
$party->setPartyTaxScheme($partyTaxScheme);
} elseif (! empty($config['tax_id'])) {
// Use tax_id if account_number is not set
$partyTaxScheme = (new PartyTaxScheme())
->setCompanyId($config['tax_id'])
->setTaxScheme($taxScheme);
$party->setPartyTaxScheme($partyTaxScheme);
}
return (new AccountingParty())->setParty($party);
}
/**
* Build customer (buyer) party
*/
protected function buildCustomerParty(?object $customerInfo, TaxScheme $taxScheme): AccountingParty
{
if ($customerInfo === null) {
return (new AccountingParty())->setParty(new Party());
}
$countryCode = getCountryCode($customerInfo->country ?? '');
$country = (new Country())->setIdentificationCode($countryCode);
$address = (new Address())
->setStreetName($customerInfo->address_1 ?? '')
->setAddressLine([$customerInfo->address_2 ?? ''])
->setCityName($customerInfo->city ?? '')
->setPostalZone($customerInfo->zip ?? '')
->setCountrySubentity($customerInfo->state ?? '')
->setCountry($country);
$partyName = ! empty($customerInfo->company_name)
? $customerInfo->company_name
: trim(($customerInfo->first_name ?? '') . ' ' . ($customerInfo->last_name ?? ''));
$party = (new Party())
->setName($partyName)
->setPostalAddress($address);
if (! empty($customerInfo->email)) {
$contact = (new Contact())
->setElectronicMail($customerInfo->email)
->setTelephone($customerInfo->phone_number ?? '');
$party->setContact($contact);
}
$accountingParty = (new AccountingParty())->setParty($party);
if (! empty($customerInfo->account_number)) {
$accountingParty->setSupplierAssignedAccountId($customerInfo->account_number);
}
if (! empty($customerInfo->tax_id)) {
$partyTaxScheme = (new PartyTaxScheme())
->setCompanyId($customerInfo->tax_id)
->setTaxScheme($taxScheme);
$party->setPartyTaxScheme($partyTaxScheme);
}
return $accountingParty;
}
/**
* Build invoice lines
*/
protected function buildInvoiceLines(array $saleData, TaxScheme $taxScheme, bool $isTaxIncluded): array
{
$lines = [];
$itemTaxes = $saleData['item_taxes'] ?? [];
$cart = $saleData['cart'] ?? [];
foreach ($cart as $item) {
$itemId = $item['item_id'] ?? 0;
$quantity = (float) ($item['quantity'] ?? 0);
$unitPrice = (float) ($item['price'] ?? 0);
$discount = (float) ($item['discount'] ?? 0);
$discountType = (int) ($item['discount_type'] ?? 0);
// Calculate discount amount per unit
if ($discountType === PERCENT && $discount > 0) {
// Percentage discount
$discountAmountPerUnit = round($unitPrice * $discount / 100, 4);
} else {
// Fixed discount (discount is total for the line, divide by quantity)
$discountAmountPerUnit = $quantity > 0 ? round($discount / $quantity, 4) : 0;
}
// Net price per unit (after discount)
$netPricePerUnit = round($unitPrice - $discountAmountPerUnit, 4);
if ($netPricePerUnit < 0) {
$netPricePerUnit = 0;
}
// Get tax rate for this item
$taxRate = 0.0;
$taxCategory = (new TaxCategory())
->setId('S')
->setPercent(0)
->setTaxScheme($taxScheme);
if (isset($itemTaxes[$itemId]) && ! empty($itemTaxes[$itemId])) {
// Use the first (primary) tax for this item
$itemTax = $itemTaxes[$itemId][0];
$taxRate = (float) ($itemTax['percent'] ?? 0);
if (abs($taxRate) < 0.001) {
$taxCategory->setId('Z'); // Zero rated
} elseif ($taxRate < 0) {
$taxCategory->setId('E'); // Exempt
} else {
$taxCategory->setId('S'); // Standard
}
$taxCategory->setPercent(round($taxRate, 2));
}
// Calculate line extension amount (net line total)
$lineExtensionAmount = round($netPricePerUnit * $quantity, 2);
// Build Price - PriceAmount MUST be the net price excluding VAT per Peppol EN16931 (BR-27)
// "The price of an item, exclusive of VAT, after subtracting discount"
$price = (new Price())
->setBaseQuantity(1.0)
->setUnitCode(UnitCode::UNIT);
if ($isTaxIncluded && $taxRate > 0) {
// Tax-inclusive: cart price includes VAT, so extract the net price
// net_price = gross_price / (1 + tax_rate/100)
$taxExclusivePricePerUnit = round($netPricePerUnit / (1 + $taxRate / 100), 4);
$price->setPriceAmount($taxExclusivePricePerUnit);
// Recalculate line extension amount with tax-exclusive price
$lineExtensionAmount = round($taxExclusivePricePerUnit * $quantity, 2);
} else {
// Tax-exclusive: cart price is already the net price
$price->setPriceAmount(round($netPricePerUnit, 4));
}
// Add AllowanceCharge if there's a discount (gross-to-net price reduction)
if ($discountAmountPerUnit > 0) {
$allowanceCharge = (new AllowanceCharge())
->setChargeIndicator(false) // false = allowance/discount
->setAllowanceChargeReason('Discount')
->setAmount(round($discountAmountPerUnit, 4))
->setBaseAmount(round((float) ($item['price'] ?? 0), 4));
$price->setAllowanceCharge($allowanceCharge);
}
// Build Item
$itemObj = (new Item())
->setName($item['name'] ?? '')
->setDescription($item['description'] ?? '')
->setClassifiedTaxCategory($taxCategory);
// Add SellersItemIdentification if item_number exists (BR-25)
if (! empty($item['item_number'])) {
$itemObj->setSellersItemIdentification((string) $item['item_number']);
}
// Build InvoiceLine
$line = (new InvoiceLine())
->setId(isset($item['line']) ? (string) $item['line'] : '1')
->setInvoicedQuantity($quantity)
->setLineExtensionAmount($lineExtensionAmount)
->setItem($itemObj)
->setPrice($price);
$lines[] = $line;
}
return $lines;
}
/**
* Build tax total from sales_taxes table data
*/
protected function buildTaxTotal(array $taxes, TaxScheme $taxScheme): TaxTotal
{
$totalTax = '0';
$taxSubTotals = [];
foreach ($taxes as $tax) {
if (isset($tax['tax_rate'])) {
$taxRate = (string) $tax['tax_rate'];
$taxAmount = (string) ($tax['sale_tax_amount'] ?? '0');
// Use sale_tax_basis directly from DB instead of reverse-computing
$taxableAmount = (string) ($tax['sale_tax_basis'] ?? '0');
// Determine category ID based on tax rate
$categoryId = 'S'; // Standard
$floatRate = (float) $taxRate;
if (abs($floatRate) < 0.001) {
$categoryId = 'Z'; // Zero rated
} elseif ($floatRate < 0) {
$categoryId = 'E'; // Exempt
}
$taxCategory = (new TaxCategory())
->setId($categoryId)
->setPercent(round($floatRate, 2))
->setTaxScheme($taxScheme);
$taxSubTotal = (new TaxSubTotal())
->setTaxableAmount(round((float) $taxableAmount, 2))
->setTaxAmount(round((float) $taxAmount, 2))
->setTaxCategory($taxCategory);
$taxSubTotals[] = $taxSubTotal;
$totalTax = bcadd($totalTax, $taxAmount);
}
}
$taxTotal = new TaxTotal();
$taxTotal->setTaxAmount(round((float) $totalTax, 2));
foreach ($taxSubTotals as $subTotal) {
$taxTotal->addTaxSubTotal($subTotal);
}
return $taxTotal;
}
/**
* Build monetary total
*/
protected function buildMonetaryTotal(array $saleData): LegalMonetaryTotal
{
// In OSPOS, after get_totals(): subtotal is ALWAYS tax-exclusive (net)
// total is ALWAYS tax-inclusive (gross)
$subtotal = (float) ($saleData['subtotal'] ?? 0);
$total = (float) ($saleData['total'] ?? 0);
$amountDue = (float) ($saleData['amount_due'] ?? 0);
return (new LegalMonetaryTotal())
->setLineExtensionAmount(round($subtotal, 2))
->setTaxExclusiveAmount(round($subtotal, 2))
->setTaxInclusiveAmount(round($total, 2))
->setPayableAmount(round($amountDue, 2));
}
/**
* Parse address string into components
*/
protected function parseAddress(string $address): array
{
$parts = array_filter(array_map('trim', explode("\n", $address)));
$result = [
'street' => '',
'number' => '',
'city' => '',
'zip' => '',
];
if (! empty($parts)) {
$result['street'] = $parts[0];
if (isset($parts[1])) {
// Match 4-5 digit postal codes (e.g., 1234, 12345) followed by city name
if (preg_match('/(\d{4,5})\s*(.+)/', $parts[1], $matches)) {
$result['zip'] = $matches[1];
$result['city'] = $matches[2];
} else {
$result['city'] = $parts[1];
}
}
}
return $result;
}
}

View File

@@ -601,6 +601,10 @@ class Attribute extends Model
*/
public function saveAttributeLink(int $itemId, int $definitionId, int $attributeId): bool
{
if ($attributeId <= 0) {
return false;
}
$normalizedItemId = empty($itemId) ? null : $itemId;
$normalizedAttributeId = empty($attributeId) ? null : $attributeId;

View File

@@ -294,7 +294,9 @@ class Receiving extends Model
lang('Sales.check') => lang('Sales.check'),
lang('Sales.debit') => lang('Sales.debit'),
lang('Sales.credit') => lang('Sales.credit'),
lang('Sales.due') => lang('Sales.due')
lang('Sales.due') => lang('Sales.due'),
lang('Sales.bank_transfer') => lang('Sales.bank_transfer'),
lang('Sales.wallet') => lang('Sales.wallet')
];
}

View File

@@ -33,14 +33,16 @@ class Summary_sales_taxes extends Summary_report
* @param object $builder
* @return void
*/
protected function _where(array $inputs, object &$builder): void // TODO: hungarian notation
protected function _where(array $inputs, object &$builder): void
{
$builder->where('sales.sale_status', COMPLETED);
if (empty($this->config['date_or_time_format'])) { // TODO: Duplicated code
$builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
if (empty($this->config['date_or_time_format'])) {
$builder->where('DATE(sales.sale_time) >=', $inputs['start_date']);
$builder->where('DATE(sales.sale_time) <=', $inputs['end_date']);
} else {
$builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
$builder->where('sales.sale_time >=', $inputs['start_date']);
$builder->where('sales.sale_time <=', $inputs['end_date']);
}
}
@@ -53,9 +55,11 @@ class Summary_sales_taxes extends Summary_report
$builder = $this->db->table('sales_taxes');
if (empty($this->config['date_or_time_format'])) {
$builder->where('DATE(sale_time) BETWEEN ' . $inputs['start_date'] . ' AND ' . $inputs['end_date']);
$builder->where('DATE(sale_time) >=', $inputs['start_date']);
$builder->where('DATE(sale_time) <=', $inputs['end_date']);
} else {
$builder->where('sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
$builder->where('sale_time >=', $inputs['start_date']);
$builder->where('sale_time <=', $inputs['end_date']);
}
$builder->select('reporting_authority, jurisdiction_name, tax_category, tax_rate, SUM(sale_tax_amount) AS tax');

View File

@@ -2,10 +2,10 @@
namespace App\Models;
use App\Libraries\Sale_lib;
use CodeIgniter\Database\BaseBuilder;
use CodeIgniter\Database\ResultInterface;
use CodeIgniter\Model;
use App\Libraries\Sale_lib;
use Config\OSPOS;
use ReflectionException;
@@ -14,11 +14,11 @@ use ReflectionException;
*/
class Sale extends Model
{
protected $table = 'sales';
protected $primaryKey = 'sale_id';
protected $table = 'sales';
protected $primaryKey = 'sale_id';
protected $useAutoIncrement = true;
protected $useSoftDeletes = false;
protected $allowedFields = [
protected $useSoftDeletes = false;
protected $allowedFields = [
'sale_time',
'customer_id',
'employee_id',
@@ -28,7 +28,7 @@ class Sale extends Model
'invoice_number',
'dinner_table_id',
'work_order_number',
'sale_type'
'sale_type',
];
public function __construct()
@@ -45,16 +45,16 @@ class Sale extends Model
$config = config(OSPOS::class)->settings;
$this->create_temp_table(['sale_id' => $sale_id]);
$decimals = totals_decimals();
$sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
$decimals = totals_decimals();
$sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
$cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
$sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
. " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
$sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
. " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, {$decimals}) "
. 'ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END';
$sale_total = $config['tax_included']
? "ROUND(SUM($sale_price), $decimals) + $cash_adjustment"
: "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
? "ROUND(SUM({$sale_price}), {$decimals}) + {$cash_adjustment}"
: "ROUND(SUM({$sale_price}), {$decimals}) + {$sales_tax} + {$cash_adjustment}";
$sql = 'sales.sale_id AS sale_id,
MAX(DATE(sales.sale_time)) AS sale_date,
@@ -73,9 +73,9 @@ class Sale extends Model
MAX(IFnull(payments.sale_cash_adjustment, 0)) AS cash_adjustment,
MAX(IFnull(payments.sale_cash_refund, 0)) AS cash_refund,
' . "
$sale_total AS amount_due,
{$sale_total} AS amount_due,
MAX(IFnull(payments.sale_payment_amount, 0)) AS amount_tendered,
(MAX(payments.sale_payment_amount)) - ($sale_total) AS change_due,
(MAX(payments.sale_payment_amount)) - ({$sale_total}) AS change_due,
" . '
MAX(payments.payment_type) AS payment_type';
@@ -89,7 +89,7 @@ class Sale extends Model
$builder->join(
'sales_items_taxes_temp AS sales_items_taxes',
'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line',
'LEFT OUTER'
'LEFT OUTER',
);
$builder->where('sales.sale_id', $sale_id);
@@ -114,15 +114,25 @@ class Sale extends Model
public function search(?string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'sales.sale_time', ?string $order = 'desc', ?bool $count_only = false)
{
// Set default values
if ($rows == null) $rows = 0;
if ($limit_from == null) $limit_from = 0;
if ($sort == null) $sort = 'sales.sale_time';
if ($order == null) $order = 'desc';
if ($count_only == null) $count_only = false;
if ($rows === null) {
$rows = 0;
}
if ($limit_from === null) {
$limit_from = 0;
}
if ($sort === null) {
$sort = 'sales.sale_time';
}
if ($order === null) {
$order = 'desc';
}
if ($count_only === null) {
$count_only = false;
}
$config = config(OSPOS::class)->settings;
$config = config(OSPOS::class)->settings;
$db_prefix = $this->db->getPrefix();
$decimals = totals_decimals();
$decimals = totals_decimals();
// Only non-suspended records
$where = 'sales.sale_status = 0 AND ';
@@ -133,18 +143,18 @@ class Sale extends Model
$this->create_temp_table_sales_payments_data($where);
$sale_price = 'CASE WHEN `sales_items`.`discount_type` = ' . PERCENT
. " THEN `sales_items`.`quantity_purchased` * `sales_items`.`item_unit_price` - ROUND(`sales_items`.`quantity_purchased` * `sales_items`.`item_unit_price` * `sales_items`.`discount` / 100, $decimals) "
. " THEN `sales_items`.`quantity_purchased` * `sales_items`.`item_unit_price` - ROUND(`sales_items`.`quantity_purchased` * `sales_items`.`item_unit_price` * `sales_items`.`discount` / 100, {$decimals}) "
. 'ELSE `sales_items`.`quantity_purchased` * (`sales_items`.`item_unit_price` - `sales_items`.`discount`) END';
$sale_cost = 'SUM(`sales_items`.`item_cost_price` * `sales_items`.`quantity_purchased`)';
$tax = 'IFNULL(SUM(`sales_items_taxes`.`tax`), 0)';
$sales_tax = 'IFNULL(SUM(`sales_items_taxes`.`sales_tax`), 0)';
$internal_tax = 'IFNULL(SUM(`sales_items_taxes`.`internal_tax`), 0)';
$tax = 'IFNULL(SUM(`sales_items_taxes`.`tax`), 0)';
$sales_tax = 'IFNULL(SUM(`sales_items_taxes`.`sales_tax`), 0)';
$internal_tax = 'IFNULL(SUM(`sales_items_taxes`.`internal_tax`), 0)';
$cash_adjustment = 'IFNULL(SUM(`payments`.`sale_cash_adjustment`), 0)';
$sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax";
$sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
$sale_subtotal = "ROUND(SUM({$sale_price}), {$decimals}) - {$internal_tax}";
$sale_total = "ROUND(SUM({$sale_price}), {$decimals}) + {$sales_tax} + {$cash_adjustment}";
$this->create_temp_table_sales_items_taxes_data($where);
@@ -171,7 +181,7 @@ class Sale extends Model
$sale_total . ' AS amount_due',
'MAX(`payments`.`sale_payment_amount`) AS amount_tendered',
'(MAX(`payments`.`sale_payment_amount`)) - (' . $sale_total . ') AS change_due',
'MAX(`payments`.`payment_type`) AS payment_type'
'MAX(`payments`.`payment_type`) AS payment_type',
], false);
}
@@ -182,7 +192,7 @@ class Sale extends Model
$builder->join(
'sales_items_taxes_temp AS sales_items_taxes',
'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line',
'LEFT OUTER'
'LEFT OUTER',
);
$builder->where($where);
@@ -227,7 +237,7 @@ class Sale extends Model
$builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
}
if (!empty($search)) { // TODO: duplicated code. We should think about refactoring out a method.
if (! empty($search)) { // TODO: duplicated code. We should think about refactoring out a method.
if ($filters['is_valid_receipt']) {
$pieces = explode(' ', $search);
$builder->where('sales.sale_id', $pieces[1]);
@@ -242,13 +252,13 @@ class Sale extends Model
}
// TODO: This needs to be converted to a switch statement
if ($filters['sale_type'] == 'sales') { // TODO: we need to think about refactoring this block to a switch statement.
if ($filters['sale_type'] === 'sales') { // TODO: we need to think about refactoring this block to a switch statement.
$builder->where('sales.sale_status = ' . COMPLETED . ' AND payment_amount > 0');
} elseif ($filters['sale_type'] == 'quotes') {
} elseif ($filters['sale_type'] === 'quotes') {
$builder->where('sales.sale_status = ' . SUSPENDED . ' AND sales.quote_number IS NOT NULL');
} elseif ($filters['sale_type'] == 'returns') {
} elseif ($filters['sale_type'] === 'returns') {
$builder->where('sales.sale_status = ' . COMPLETED . ' AND payment_amount < 0');
} elseif ($filters['sale_type'] == 'all') {
} elseif ($filters['sale_type'] === 'all') {
$builder->where('sales.sale_status = ' . COMPLETED);
}
@@ -277,17 +287,25 @@ class Sale extends Model
$builder->like('payment_type', lang('Sales.debit'));
}
if ($filters['only_bank_transfer']) {
$builder->like('payment_type', lang('Sales.bank_transfer'));
}
if ($filters['only_wallet']) {
$builder->like('payment_type', lang('Sales.wallet'));
}
$builder->groupBy('payment_type');
$payments = $builder->get()->getResultArray();
// Consider Gift Card as only one type of payment and do not show "Gift Card: 1, Gift Card: 2, etc." in the total
$gift_card_count = 0;
$gift_card_count = 0;
$gift_card_amount = 0;
foreach ($payments as $key => $payment) {
if (strstr($payment['payment_type'], lang('Sales.giftcard'))) {
$gift_card_count += $payment['count'];
$gift_card_count += $payment['count'];
$gift_card_amount += $payment['payment_amount'];
// Remove the "Gift Card: 1", "Gift Card: 2", etc. payment string
@@ -319,7 +337,7 @@ class Sale extends Model
{
$suggestions = [];
if (!$this->is_valid_receipt($search)) {
if (! $this->is_valid_receipt($search)) {
$builder = $this->db->table('sales');
$builder->distinct()->select('first_name, last_name');
$builder->join('people', 'people.person_id = sales.customer_id');
@@ -361,21 +379,11 @@ class Sale extends Model
return $builder->get();
}
/**
* @param string $year
* @param int $start_from
* @return int
*/
public function get_invoice_number_for_year(string $year = '', int $start_from = 0): int
{
return $this->get_number_for_year('invoice_number', $year, $start_from);
}
/**
* @param string $year
* @param int $start_from
* @return int
*/
public function get_quote_number_for_year(string $year = '', int $start_from = 0): int
{
return $this->get_number_for_year('quote_number', $year, $start_from);
@@ -386,31 +394,32 @@ class Sale extends Model
*/
private function get_number_for_year(string $field, string $year = '', int $start_from = 0): int
{
$year = $year == '' ? date('Y') : $year;
$year = $year === '' ? date('Y') : $year;
$builder = $this->db->table('sales');
$builder->select('COUNT( 1 ) AS number_year');
$builder->where('DATE_FORMAT(sale_time, "%Y" ) = ', $year);
$builder->where("$field IS NOT NULL");
$builder->where("{$field} IS NOT NULL");
$result = $builder->get()->getRowArray();
return ($start_from + $result['number_year']);
return $start_from + $result['number_year'];
}
/**
* Checks if valid receipt
*/
public function is_valid_receipt(string|null &$receipt_sale_id): bool // TODO: like the others, maybe this should be an array rather than a delimited string... either that or the parameter name needs to be changed. $receipt_sale_id implies that it's an int.
public function is_valid_receipt(?string &$receipt_sale_id): bool // TODO: like the others, maybe this should be an array rather than a delimited string... either that or the parameter name needs to be changed. $receipt_sale_id implies that it's an int.
{
$config = config(OSPOS::class)->settings;
if (!empty($receipt_sale_id)) {
if (! empty($receipt_sale_id)) {
// POS #
$pieces = explode(' ', $receipt_sale_id);
if (count($pieces) == 2 && preg_match('/(POS)/i', $pieces[0])) {
if (count($pieces) === 2 && preg_match('/(POS)/i', $pieces[0])) {
return $this->exists($pieces[1]);
} elseif ($config['invoice_enable']) {
}
if ($config['invoice_enable']) {
$sale_info = $this->get_sale_by_invoice_number($receipt_sale_id);
if ($sale_info->getNumRows() > 0) {
@@ -432,11 +441,14 @@ class Sale extends Model
$builder = $this->db->table('sales');
$builder->where('sale_id', $sale_id);
return ($builder->get()->getNumRows() == 1); // TODO: ===
return $builder->get()->getNumRows() === 1; // TODO: ===
}
/**
* Update sale
*
* @param mixed|null $sale_id
* @param mixed|null $sale_data
*/
public function update($sale_id = null, $sale_data = null): bool
{
@@ -447,7 +459,7 @@ class Sale extends Model
$success = $builder->update($update_data);
// Touch payment only if update sale is successful and there is a payments object otherwise the result would be to delete all the payments associated to the sale
if ($success && !empty($sale_data['payments'])) {
if ($success && ! empty($sale_data['payments'])) {
// Run these queries as a transaction, we want to make sure we do all or nothing
$this->db->transStart();
@@ -455,14 +467,14 @@ class Sale extends Model
// Add new payments
foreach ($sale_data['payments'] as $payment) {
$payment_id = $payment['payment_id'];
$payment_type = $payment['payment_type'];
$payment_amount = $payment['payment_amount'];
$cash_refund = $payment['cash_refund'];
$payment_id = $payment['payment_id'];
$payment_type = $payment['payment_type'];
$payment_amount = $payment['payment_amount'];
$cash_refund = $payment['cash_refund'];
$cash_adjustment = $payment['cash_adjustment'];
$employee_id = $payment['employee_id'];
$employee_id = $payment['employee_id'];
if ($payment_id == NEW_ENTRY && $payment_amount != 0) {
if ($payment_id === NEW_ENTRY && $payment_amount !== 0) {
// Add a new payment transaction
$sales_payments_data = [
'sale_id' => $sale_id,
@@ -470,17 +482,17 @@ class Sale extends Model
'payment_amount' => $payment_amount,
'cash_refund' => $cash_refund,
'cash_adjustment' => $cash_adjustment,
'employee_id' => $employee_id
'employee_id' => $employee_id,
];
$success = $builder->insert($sales_payments_data);
} elseif ($payment_id != NEW_ENTRY) {
if ($payment_amount != 0) {
} elseif ($payment_id !== NEW_ENTRY) {
if ($payment_amount !== 0) {
// Update existing payment transactions (payment_type only)
$sales_payments_data = [
'payment_type' => $payment_type,
'payment_amount' => $payment_amount,
'cash_refund' => $cash_refund,
'cash_adjustment' => $cash_adjustment
'cash_adjustment' => $cash_adjustment,
];
$builder->where('payment_id', $payment_id);
@@ -502,6 +514,7 @@ class Sale extends Model
/**
* Save the sale information after the sales is complete but before the final document is printed
* The sales_taxes variable needs to be initialized to an empty array before calling
*
* @throws ReflectionException
*/
public function save_value(
@@ -517,22 +530,22 @@ class Sale extends Model
int $sale_type,
?array $payments,
?int $dinner_table_id,
?array &$sales_taxes
?array &$sales_taxes,
): int { // TODO: this method returns the sale_id but the override is expecting it to return a bool. The signature needs to be reworked. Generally when there are more than 3 maybe 4 parameters, there's a good chance that an object needs to be passed rather than so many params.
$config = config(OSPOS::class)->settings;
$config = config(OSPOS::class)->settings;
$attribute = model(Attribute::class);
$customer = model(Customer::class);
$giftcard = model(Giftcard::class);
$customer = model(Customer::class);
$giftcard = model(Giftcard::class);
$inventory = model('Inventory');
$item = model(Item::class);
$item = model(Item::class);
$item_quantity = model(Item_quantity::class);
if ($sale_id != NEW_ENTRY) {
if ($sale_id !== NEW_ENTRY) {
$this->clear_suspended_sale_detail($sale_id);
}
if (count($items) == 0) { // TODO: ===
if (count($items) === 0) { // TODO: ===
return -1; // TODO: Replace -1 with a constant
}
@@ -546,13 +559,13 @@ class Sale extends Model
'quote_number' => $quote_number,
'work_order_number' => $work_order_number,
'dinner_table_id' => $dinner_table_id,
'sale_type' => $sale_type
'sale_type' => $sale_type,
];
// Run these queries as a transaction, we want to make sure we do all or nothing
$this->db->transStart();
if ($sale_id == NEW_ENTRY) {
if ($sale_id === NEW_ENTRY) {
$builder = $this->db->table('sales');
$builder->insert($sales_data);
$sale_id = $this->db->insertID();
@@ -562,19 +575,19 @@ class Sale extends Model
$builder->update($sales_data);
}
$total_amount = 0;
$total_amount = 0;
$total_amount_used = 0;
foreach ($payments as $payment_id => $payment) {
if (!empty(strstr($payment['payment_type'], lang('Sales.giftcard')))) {
if (! empty(strstr($payment['payment_type'], lang('Sales.giftcard')))) {
// We have a gift card, and we have to deduct the used value from the total value of the card.
$splitpayment = explode(':', $payment['payment_type']); // TODO: this variable doesn't follow our naming conventions. Probably should be refactored to split_payment.
$splitpayment = explode(':', $payment['payment_type']); // TODO: this variable doesn't follow our naming conventions. Probably should be refactored to split_payment.
$cur_giftcard_value = $giftcard->get_giftcard_value($splitpayment[1]); // TODO: this should be refactored to $current_giftcard_value
$giftcard->update_giftcard_value($splitpayment[1], $cur_giftcard_value - $payment['payment_amount']);
} elseif (!empty(strstr($payment['payment_type'], lang('Sales.rewards')))) {
} elseif (! empty(strstr($payment['payment_type'], lang('Sales.rewards')))) {
$cur_rewards_value = $customer->get_info($customer_id)->points;
$customer->update_reward_points_value($customer_id, $cur_rewards_value - $payment['payment_amount']);
$total_amount_used = floatval($total_amount_used) + floatval($payment['payment_amount']);
$total_amount_used = (float) $total_amount_used + (float) ($payment['payment_amount']);
}
$sales_payments_data = [
@@ -583,13 +596,13 @@ class Sale extends Model
'payment_amount' => $payment['payment_amount'],
'cash_refund' => $payment['cash_refund'],
'cash_adjustment' => $payment['cash_adjustment'],
'employee_id' => $employee_id
'employee_id' => $employee_id,
];
$builder = $this->db->table('sales_payments');
$builder->insert($sales_payments_data);
$total_amount = floatval($total_amount) + floatval($payment['payment_amount']) - floatval($payment['cash_refund']);
$total_amount = (float) $total_amount + (float) ($payment['payment_amount']) - (float) ($payment['cash_refund']);
}
$this->save_customer_rewards($customer_id, $sale_id, $total_amount, $total_amount_used);
@@ -599,7 +612,7 @@ class Sale extends Model
foreach ($items as $line => $item_data) {
$cur_item_info = $item->get_info($item_data['item_id']);
if ($item_data['price'] == 0.00) {
if ($item_data['price'] === 0.00) {
$item_data['discount'] = 0.00;
}
@@ -615,13 +628,13 @@ class Sale extends Model
'item_cost_price' => $item_data['cost_price'],
'item_unit_price' => $item_data['price'],
'item_location' => $item_data['item_location'],
'print_option' => $item_data['print_option']
'print_option' => $item_data['print_option'],
];
$builder = $this->db->table('sales_items');
$builder->insert($sales_items_data);
if ($cur_item_info->stock_type == HAS_STOCK && $sale_status == COMPLETED) { // TODO: === ?
if ($cur_item_info->stock_type === HAS_STOCK && $sale_status === COMPLETED) { // TODO: === ?
// Update stock quantity if item type is a standard stock item and the sale is a standard sale
$item_quantity_data = $item_quantity->get_item_quantity($item_data['item_id'], $item_data['item_location']);
@@ -629,10 +642,10 @@ class Sale extends Model
[
'quantity' => $item_quantity_data->quantity - $item_data['quantity'],
'item_id' => $item_data['item_id'],
'location_id' => $item_data['item_location']
'location_id' => $item_data['item_location'],
],
$item_data['item_id'],
$item_data['item_location']
$item_data['item_location'],
);
// If an items was deleted but later returned it's restored with this rule
@@ -642,13 +655,13 @@ class Sale extends Model
// Inventory Count Details
$sale_remarks = 'POS ' . $sale_id; // TODO: Use string interpolation here.
$inv_data = [
$inv_data = [
'trans_date' => date('Y-m-d H:i:s'),
'trans_items' => $item_data['item_id'],
'trans_user' => $employee_id,
'trans_location' => $item_data['item_location'],
'trans_comment' => $sale_remarks,
'trans_inventory' => -$item_data['quantity']
'trans_inventory' => -$item_data['quantity'],
];
$inventory->insert($inv_data, false);
@@ -657,14 +670,14 @@ class Sale extends Model
$attribute->copy_attribute_links($item_data['item_id'], 'sale_id', $sale_id);
}
if ($customer_id == NEW_ENTRY || $customer->taxable) {
if ($customer_id === NEW_ENTRY || $customer->taxable) {
$this->save_sales_tax($sale_id, $sales_taxes[0]);
$this->save_sales_items_taxes($sale_id, $sales_taxes[1]);
}
if ($config['dinner_table_enable']) {
$dinner_table = model(Dinner_table::class);
if ($sale_status == COMPLETED) { // TODO: === ?
if ($sale_status === COMPLETED) { // TODO: === ?
$dinner_table->release($dinner_table_id);
} else {
$dinner_table->occupy($dinner_table_id);
@@ -713,7 +726,7 @@ class Sale extends Model
'item_tax_amount' => $tax_item['item_tax_amount'],
'sales_tax_code_id' => $tax_item['sales_tax_code_id'],
'tax_category_id' => $tax_item['tax_category_id'],
'jurisdiction_id' => $tax_item['jurisdiction_id']
'jurisdiction_id' => $tax_item['jurisdiction_id'],
];
$builder->insert($sales_items_taxes);
@@ -748,8 +761,36 @@ class Sale extends Model
return $builder->get()->getResultArray();
}
/**
* Return all item taxes for a sale (for UBL invoice generation)
* Returns array keyed by item_id, each containing array of tax info
*/
public function get_sale_item_taxes_by_sale(int $sale_id): array
{
$builder = $this->db->table('sales_items_taxes');
$builder->select('item_id, line, name, percent, tax_type, item_tax_amount');
$builder->where('sale_id', $sale_id);
$builder->orderBy('line', 'asc');
$results = $builder->get()->getResultArray();
// Group by item_id
$itemTaxes = [];
foreach ($results as $row) {
$itemId = $row['item_id'];
if (! isset($itemTaxes[$itemId])) {
$itemTaxes[$itemId] = [];
}
$itemTaxes[$itemId][] = $row;
}
return $itemTaxes;
}
/**
* Deletes list of sales
*
* @throws ReflectionException
*/
public function delete_list(array $sale_ids, int $employee_id, bool $update_inventory = true): bool
@@ -779,6 +820,10 @@ class Sale extends Model
* Delete sale. Hard deletes are not supported for sales transactions.
* When a sale is "deleted" it is simply changed to a status of canceled.
* However, if applicable the inventory still needs to be updated
*
* @param mixed|null $sale_id
* @param mixed|null $employee_id
*
* @throws ReflectionException
*/
public function delete($sale_id = null, bool $purge = false, bool $update_inventory = true, $employee_id = null): bool
@@ -788,11 +833,11 @@ class Sale extends Model
$sale_status = $this->get_sale_status($sale_id);
if ($update_inventory && $sale_status == COMPLETED) {
if ($update_inventory && $sale_status === COMPLETED) {
// Defect, not all item deletions will be undone?
// Get array with all the items involved in the sale to update the inventory tracking
$inventory = model('Inventory');
$item = model(Item::class);
$inventory = model('Inventory');
$item = model(Item::class);
$item_quantity = model(Item_quantity::class);
$items = $this->get_sale_items($sale_id)->getResultArray();
@@ -800,7 +845,7 @@ class Sale extends Model
foreach ($items as $item_data) {
$cur_item_info = $item->get_info($item_data['item_id']);
if ($cur_item_info->stock_type == HAS_STOCK) {
if ($cur_item_info->stock_type === HAS_STOCK) {
// Create query to update inventory tracking
$inv_data = [
'trans_date' => date('Y-m-d H:i:s'),
@@ -808,7 +853,7 @@ class Sale extends Model
'trans_user' => $employee_id,
'trans_comment' => 'Deleting sale ' . $sale_id,
'trans_location' => $item_data['item_location'],
'trans_inventory' => $item_data['quantity_purchased']
'trans_inventory' => $item_data['quantity_purchased'],
];
// Update inventory
$inventory->insert($inv_data, false);
@@ -844,7 +889,7 @@ class Sale extends Model
public function get_sale_items_ordered(int $sale_id): ResultInterface
{
$config = config(OSPOS::class)->settings;
$item = model(Item::class);
$item = model(Item::class);
$builder = $this->db->table('sales_items AS sales_items');
$builder->select('
@@ -868,18 +913,18 @@ class Sale extends Model
$builder->where('sales_items.sale_id', $sale_id);
// Entry sequence (this will render kits in the expected sequence)
if ($config['line_sequence'] == '0') { // TODO: Replace these with constants and this should be converted to a switch.
if ($config['line_sequence'] === '0') { // TODO: Replace these with constants and this should be converted to a switch.
$builder->orderBy('line', 'asc');
}
// Group by Stock Type (nonstock first - type 1, stock next - type 0)
elseif ($config['line_sequence'] == '1') {
elseif ($config['line_sequence'] === '1') {
$builder->orderBy('stock_type', 'desc');
$builder->orderBy('sales_items.description', 'asc');
$builder->orderBy('items.name', 'asc');
$builder->orderBy('items.qty_per_pack', 'asc');
}
// Group by Item Category
elseif ($config['line_sequence'] == '2') {
elseif ($config['line_sequence'] === '2') {
$builder->orderBy('category', 'asc');
$builder->orderBy('sales_items.description', 'asc');
$builder->orderBy('items.name', 'asc');
@@ -919,8 +964,8 @@ class Sale extends Model
$payments[lang('Sales.rewards')] = lang('Sales.rewards');
}
$sale_lib = new Sale_lib();
if ($sale_lib->get_mode() == 'sale_work_order') {
$payments[lang('Sales.cash_deposit')] = lang('Sales.cash_deposit');
if ($sale_lib->get_mode() === 'sale_work_order') {
$payments[lang('Sales.cash_deposit')] = lang('Sales.cash_deposit');
$payments[lang('Sales.credit_deposit')] = lang('Sales.credit_deposit');
}
@@ -961,11 +1006,11 @@ class Sale extends Model
$builder = $this->db->table('sales');
$builder->where('quote_number', $quote_number);
if (!empty($sale_id)) {
if (! empty($sale_id)) {
$builder->where('sale_id !=', $sale_id);
}
return ($builder->get()->getNumRows() == 1); // TODO: ===
return $builder->get()->getNumRows() === 1; // TODO: ===
}
/**
@@ -976,11 +1021,11 @@ class Sale extends Model
$builder = $this->db->table('sales');
$builder->where('invoice_number', $invoice_number);
if (!empty($sale_id)) {
if (! empty($sale_id)) {
$builder->where('sale_id !=', $sale_id);
}
return ($builder->get()->getNumRows() == 1); // TODO: ===
return $builder->get()->getNumRows() === 1; // TODO: ===
}
/**
@@ -990,11 +1035,11 @@ class Sale extends Model
{
$builder = $this->db->table('sales');
$builder->where('invoice_number', $work_order_number);
if (!empty($sale_id)) {
if (! empty($sale_id)) {
$builder->where('sale_id !=', $sale_id);
}
return ($builder->get()->getNumRows() == 1); // TODO: ===
return $builder->get()->getNumRows() === 1; // TODO: ===
}
/**
@@ -1004,7 +1049,7 @@ class Sale extends Model
{
$giftcard = model(Giftcard::class);
if (!$giftcard->exists($giftcard->get_giftcard_id($giftcardNumber))) { // TODO: camelCase is used here for the variable name but we are using _ everywhere else. CI4 moved to camelCase... we should pick one and do that.
if (! $giftcard->exists($giftcard->get_giftcard_id($giftcardNumber))) { // TODO: camelCase is used here for the variable name but we are using _ everywhere else. CI4 moved to camelCase... we should pick one and do that.
return 0;
}
@@ -1035,22 +1080,22 @@ class Sale extends Model
$decimals = totals_decimals();
$sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
. " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
. " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, {$decimals}) "
. 'ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END';
$sale_cost = 'SUM(sales_items.item_cost_price * sales_items.quantity_purchased)';
$tax = 'IFNULL(SUM(sales_items_taxes.tax), 0)';
$sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
$internal_tax = 'IFNULL(SUM(sales_items_taxes.internal_tax), 0)';
$tax = 'IFNULL(SUM(sales_items_taxes.tax), 0)';
$sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
$internal_tax = 'IFNULL(SUM(sales_items_taxes.internal_tax), 0)';
$cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
if ($config['tax_included']) {
$sale_total = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
$sale_subtotal = "$sale_total - $internal_tax";
$sale_total = "ROUND(SUM({$sale_price}), {$decimals}) + {$cash_adjustment}";
$sale_subtotal = "{$sale_total} - {$internal_tax}";
} else {
$sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax + $cash_adjustment";
$sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
$sale_subtotal = "ROUND(SUM({$sale_price}), {$decimals}) - {$internal_tax} + {$cash_adjustment}";
$sale_total = "ROUND(SUM({$sale_price}), {$decimals}) + {$sales_tax} + {$cash_adjustment}";
}
// Create a temporary table to contain all the sum of taxes per sale item
@@ -1092,7 +1137,7 @@ class Sale extends Model
$this->db->query($sql);
$item = model(Item::class);
$sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_temp') .
$sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_temp') .
' (INDEX(sale_date), INDEX(sale_time), INDEX(sale_id))
(
SELECT
@@ -1114,7 +1159,7 @@ class Sale extends Model
MAX(sales.employee_id) AS employee_id,
MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name,
items.item_id AS item_id,
MAX(' . $item->get_item_name() . ') AS name,
MAX(' . $item->get_item_name() . ") AS name,
MAX(items.item_number) AS item_number,
MAX(items.category) AS category,
MAX(items.supplier_id) AS supplier_id,
@@ -1129,12 +1174,12 @@ class Sale extends Model
MAX(sales_items.description) AS description,
MAX(payments.payment_type) AS payment_type,
MAX(payments.sale_payment_amount) AS sale_payment_amount,
' . "
$sale_subtotal AS subtotal,
$tax AS tax,
$sale_total AS total,
$sale_cost AS cost,
($sale_subtotal - $sale_cost) AS profit
{$sale_subtotal} AS subtotal,
{$tax} AS tax,
{$sale_total} AS total,
{$sale_cost} AS cost,
({$sale_subtotal} - {$sale_cost}) AS profit
" . '
FROM ' . $this->db->prefixTable('sales_items') . ' AS sales_items
INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
@@ -1165,7 +1210,7 @@ class Sale extends Model
*/
public function get_all_suspended(?int $customer_id = null): array
{
if ($customer_id == NEW_ENTRY) {
if ($customer_id === NEW_ENTRY) {
$query = $this->db->query("SELECT sale_id, case when sale_type = '" . SALE_TYPE_QUOTE . "' THEN quote_number WHEN sale_type = '" . SALE_TYPE_WORK_ORDER . "' THEN work_order_number else sale_id end as doc_id, sale_id as suspended_sale_id, sale_status, sale_time, dinner_table_id, customer_id, employee_id, comment FROM "
. $this->db->prefixTable('sales') . ' where sale_status = ' . SUSPENDED);
} else {
@@ -1181,7 +1226,7 @@ class Sale extends Model
*/
public function get_dinner_table(int $sale_id) // TODO: this is returning null or the table_id. We can keep it this way but multiple return types can't be declared until PHP 8.x
{
if ($sale_id == NEW_ENTRY) {
if ($sale_id === NEW_ENTRY) {
return null;
}
@@ -1213,11 +1258,6 @@ class Sale extends Model
return $builder->get()->getRow()->sale_status;
}
/**
* @param int $sale_id
* @param int $sale_status
* @return void
*/
public function update_sale_status(int $sale_id, int $sale_status): void
{
$builder = $this->db->table('sales');
@@ -1236,7 +1276,7 @@ class Sale extends Model
$row = $builder->get()->getRow();
if ($row != null) {
if ($row !== null) {
return $row->quote_number;
}
@@ -1253,7 +1293,7 @@ class Sale extends Model
$row = $builder->get()->getRow();
if ($row != null) { // TODO: === ?
if ($row !== null) { // TODO: === ?
return $row->work_order_number;
}
@@ -1270,7 +1310,7 @@ class Sale extends Model
$row = $builder->get()->getRow();
if ($row != null) { // TODO: === ?
if ($row !== null) { // TODO: === ?
return $row->comment;
}
@@ -1300,7 +1340,7 @@ class Sale extends Model
$config = config(OSPOS::class)->settings;
if ($config['dinner_table_enable']) {
$dinner_table = model(Dinner_table::class);
$dinner_table = model(Dinner_table::class);
$dinner_table_id = $this->get_dinner_table($sale_id);
$dinner_table->release($dinner_table_id);
}
@@ -1322,7 +1362,7 @@ class Sale extends Model
$config = config(OSPOS::class)->settings;
if ($config['dinner_table_enable']) {
$dinner_table = model(Dinner_table::class);
$dinner_table = model(Dinner_table::class);
$dinner_table_id = $this->get_dinner_table($sale_id);
$dinner_table->release($dinner_table_id);
}
@@ -1357,30 +1397,24 @@ class Sale extends Model
return $builder->get();
}
/**
* @param int $customer_id
* @param int $sale_id
* @param float $total_amount
* @param float $total_amount_used
*/
private function save_customer_rewards(int $customer_id, int $sale_id, float $total_amount, float $total_amount_used): void
{
$config = config(OSPOS::class)->settings;
if (!empty($customer_id) && $config['customer_reward_enable']) {
$customer = model(Customer::class);
if (! empty($customer_id) && $config['customer_reward_enable']) {
$customer = model(Customer::class);
$customer_rewards = model(Customer_rewards::class);
$rewards = model(Rewards::class);
$rewards = model(Rewards::class);
$package_id = $customer->get_info($customer_id)->package_id;
if (!empty($package_id)) {
$points_percent = $customer_rewards->get_points_percent($package_id);
$points = $customer->get_info($customer_id)->points;
$points = ($points == null ? 0 : $points);
$points_percent = ($points_percent == null ? 0 : $points_percent);
if (! empty($package_id)) {
$points_percent = $customer_rewards->get_points_percent($package_id);
$points = $customer->get_info($customer_id)->points;
$points = ($points === null ? 0 : $points);
$points_percent = ($points_percent === null ? 0 : $points_percent);
$total_amount_earned = ($total_amount * $points_percent / 100);
$points = $points + $total_amount_earned;
$points += $total_amount_earned;
$customer->update_reward_points_value($customer_id, $points);
@@ -1394,7 +1428,6 @@ class Sale extends Model
/**
* Creates a temporary table to store the sales_payments data
*
* @param string $where
* @return array
*/
private function create_temp_table_sales_payments_data(string $where): void
@@ -1404,7 +1437,7 @@ class Sale extends Model
'payments.sale_id',
'SUM(CASE WHEN `payments`.`cash_adjustment` = 0 THEN `payments`.`payment_amount` ELSE 0 END) AS sale_payment_amount',
'SUM(CASE WHEN `payments`.`cash_adjustment` = 1 THEN `payments`.`payment_amount` ELSE 0 END) AS sale_cash_adjustment',
'GROUP_CONCAT(CONCAT(`payments`.`payment_type`, " ", (`payments`.`payment_amount` - `payments`.`cash_refund`)) SEPARATOR ", ") AS payment_type'
'GROUP_CONCAT(CONCAT(`payments`.`payment_type`, " ", (`payments`.`payment_amount` - `payments`.`cash_refund`)) SEPARATOR ", ") AS payment_type',
]);
$builder->join('sales', 'sales.sale_id = payments.sale_id', 'inner');
$builder->where($where);
@@ -1421,12 +1454,10 @@ class Sale extends Model
/**
* Temporary table to store the sales_items_taxes data
*
* @param string $where
* @return \CodeIgniter\Database\BaseBuilder
* @return BaseBuilder
*/
private function create_temp_table_sales_items_taxes_data(string $where): void
{
$builder = $this->db->table('sales_items_taxes AS sales_items_taxes');
$builder->select([
'sales_items_taxes.sale_id AS sale_id',
@@ -1434,7 +1465,7 @@ class Sale extends Model
'sales_items_taxes.line AS line',
'SUM(sales_items_taxes.item_tax_amount) AS tax',
'SUM(CASE WHEN sales_items_taxes.tax_type = 0 THEN sales_items_taxes.item_tax_amount ELSE 0 END) AS internal_tax',
'SUM(CASE WHEN sales_items_taxes.tax_type = 1 THEN sales_items_taxes.item_tax_amount ELSE 0 END) AS sales_tax'
'SUM(CASE WHEN sales_items_taxes.tax_type = 1 THEN sales_items_taxes.item_tax_amount ELSE 0 END) AS sales_tax',
]);
$builder->join('sales', 'sales.sale_id = sales_items_taxes.sale_id', 'inner');
$builder->join('sales_items', 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.line = sales_items_taxes.line', 'inner');
@@ -1447,15 +1478,9 @@ class Sale extends Model
. ' (INDEX(sale_id), INDEX(item_id)) ENGINE=MEMORY AS (' . $sub_query . ')');
}
/**
* @param string $search
* @param array $filters
* @param BaseBuilder $builder
* @return void
*/
private function add_filters_to_query(?string $search, array $filters, BaseBuilder $builder): void
{
if (!empty($search)) { // TODO: this is duplicated code. We should think about refactoring out a method
if (! empty($search)) { // TODO: this is duplicated code. We should think about refactoring out a method
if ($filters['is_valid_receipt']) {
$pieces = explode(' ', $search);
$builder->where('sales.sale_id', $pieces[1]);
@@ -1473,16 +1498,15 @@ class Sale extends Model
}
}
if ($filters['location_id'] != 'all') {
if ($filters['location_id'] !== 'all') {
$builder->where('sales_items.item_location', $filters['location_id']);
}
if ($filters['selected_customer'] != false) {
if ($filters['selected_customer'] !== false) {
$sale_lib = new Sale_lib();
$builder->where('sales.customer_id', $sale_lib->get_customer());
}
if ($filters['only_invoices']) {
$builder->where('sales.invoice_number IS NOT NULL');
}
@@ -1509,5 +1533,13 @@ class Sale extends Model
if ($filters['only_check']) {
$builder->like('payments.payment_type', lang('Sales.check'));
}
if ($filters['only_bank_transfer']) {
$builder->like('payments.payment_type', lang('Sales.bank_transfer'));
}
if ($filters['only_wallet']) {
$builder->like('payments.payment_type', lang('Sales.wallet'));
}
}
}

View File

@@ -10,75 +10,93 @@
*/
?>
<?= form_open("attributes/saveDefinition/$definition_id", ['id' => 'attribute_form']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open("attributes/saveDefinition/$definition_id", ['id' => 'attribute_form', 'class' => 'form-horizontal']) ?>
<fieldset id="attribute_basic_info">
<label for="definition_name" class="form-label"><?= lang('Attributes.definition_name'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="definition_name-icon"><i class="bi bi-star"></i></span>
<input type="text" class="form-control" name="definition_name" id="definition_name" aria-describedby="definition_name-icon" value="<?= esc($definition_info->definition_name); ?>">
</div>
<label for="definition_type" class="form-label"><?= lang('Attributes.definition_type'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="definition_type-icon"><i class="bi bi-list"></i></span>
<select class="form-select" name="definition_type" id="definition_type" aria-describedby="definition_type-icon">
<?php foreach (DEFINITION_TYPES as $key => $label): ?>
<option value="<?= $key ?>" <?= ($key === array_search($definition_info->definition_type, DEFINITION_TYPES)) ? 'selected' : '' ?>>
<?= $label ?>
</option>
<?php endforeach; ?>
</select>
</div>
<label for="definition_group" class="form-label"><?= lang('Attributes.definition_group'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="definition_group-icon"><i class="bi bi-collection"></i></span>
<select class="form-select" name="definition_group" id="definition_group" aria-describedby="definition_group-icon" <?= empty($definition_group) ? 'disabled' : '' ?>>
<?php foreach ($definition_group as $key => $label): ?>
<option value="<?= $key ?>" <?= ($key == $definition_info->definition_fk) ? 'selected' : '' ?>>
<?= $label ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="toggle-hide d-none">
<label for="definition_flags" class="form-label"><?= lang('Attributes.definition_flags'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="definition_flags-icon"><i class="bi bi-eyeglasses"></i></span>
<select class="form-select" name="definition_flags[]" id="definition_flags" aria-describedby="definition_flags-icon" multiple>
<?php foreach ($definition_flags as $key => $label): ?>
<option value="<?= $key ?>" <?= in_array($key, array_keys($selected_definition_flags)) ? 'selected' : '' ?>>
<?= $label ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Attributes.definition_name'), 'definition_name', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'definition_name',
'id' => 'definition_name',
'class' => 'form-control input-sm',
'value' => esc($definition_info->definition_name)
]) ?>
</div>
</div>
</div>
<div class="toggle-hide d-none">
<label for="definition_unit" class="form-label"><?= lang('Attributes.definition_unit'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="definition_unit-icon"><i class="bi bi-flask"></i></span>
<input type="text" class="form-control" name="definition_unit" id="definition_unit" aria-describedby="definition_unit-icon" value="<?= esc($definition_info->definition_unit); ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Attributes.definition_type'), 'definition_type', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown('definition_type', DEFINITION_TYPES, array_search($definition_info->definition_type, DEFINITION_TYPES), 'id="definition_type" class="form-control"') ?>
</div>
</div>
</div>
<div class="toggle-hide d-none">
<label for="definition_value" class="form-label"><?= lang('Attributes.definition_values'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="definition_value-icon"><i class="bi bi-list"></i></span>
<input type="text" class="form-control" name="definition_value" id="definition_value" aria-describedby="definition_value-icon">
<button type="button" class="btn btn-outline-secondary" id="add_attribute_value"><i class="bi bi-plus-circle"></i></button>
<div class="form-group form-group-sm">
<?= form_label(lang('Attributes.definition_group'), 'definition_group', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown(
'definition_group',
$definition_group,
$definition_info->definition_fk,
'id="definition_group" class="form-control" ' . (empty($definition_group) ? 'disabled="disabled"' : '')
) ?>
</div>
</div>
</div>
<div class="toggle-hide d-none">
<ul class="list-group" id="definition_list_group"></ul>
</div>
<div class="form-group form-group-sm hidden">
<?= form_label(lang('Attributes.definition_flags'), 'definition_flags', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<?= form_multiselect('definition_flags[]', $definition_flags, array_keys($selected_definition_flags), [
'id' => 'definition_flags',
'class' => 'selectpicker show-menu-arrow',
'data-none-selected-text' => lang('Common.none_selected_text'),
'data-selected-text-format' => 'count > 1',
'data-style' => 'btn-default btn-sm',
'data-width' => 'fit'
]) ?>
</div>
</div>
</div>
<div class="form-group form-group-sm hidden">
<?= form_label(lang('Attributes.definition_unit'), 'definition_units', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<?= form_input([
'name' => 'definition_unit',
'value' => esc($definition_info->definition_unit),
'class' => 'form-control input-sm',
'id' => 'definition_unit'
]) ?>
</div>
</div>
</div>
<div class="form-group form-group-sm hidden">
<?= form_label(lang('Attributes.definition_values'), 'definition_value', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<?= form_input(['name' => 'definition_value', 'class' => 'form-control input-sm', 'id' => 'definition_value']) ?>
<span id="add_attribute_value" class="input-group-addon input-sm btn btn-default">
<span class="glyphicon glyphicon-plus-sign"></span>
</span>
</div>
</div>
</div>
<div class="form-group form-group-sm hidden">
<?= form_label('&nbsp;', 'definition_list_group', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<ul id="definition_list_group" class="list-group"></ul>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">
@@ -107,8 +125,8 @@
if (definition_id == -1) {
$('#definition_name').prop("disabled", true);
$('#definition_type').prop("disabled", true);
$('#definition_group').parents('.toggle-hide').toggleClass("d-none", true);
$('#definition_flags').parents('.toggle-hide').toggleClass("d-none", true);
$('#definition_group').parents('.form-group').toggleClass("hidden", true);
$('#definition_flags').parents('.form-group').toggleClass('hidden', true);
}
}
disable_category_dropdown();
@@ -119,23 +137,21 @@
var is_no_group = $('#definition_type').val() !== '0';
var is_category_dropdown = definition_id == -1;
$('#definition_value, #definition_list_group').parents('.toggle-hide').toggleClass('d-none', is_dropdown);
$('#definition_unit').parents('.toggle-hide').toggleClass('d-none', is_decimal);
$('#definition_value, #definition_list_group').parents('.form-group').toggleClass('hidden', is_dropdown);
$('#definition_unit').parents('.form-group').toggleClass('hidden', is_decimal);
// Appropriately show definition flags if not category_dropdown
if (definition_id != -1) {
$('#definition_flags').parents('.toggle-hide').toggleClass('d-none', !is_no_group);
$('#definition_flags').parents('.form-group').toggleClass('hidden', !is_no_group);
}
};
$('#definition_type').change(show_hide_fields);
show_hide_fields();
new TomSelect('#definition_flags', {
plugins: ['checkbox_options', 'remove_button'],
placeholder: '<?= lang('Common.none_selected_text') ?>',
hidePlaceholder: true,
closeAfterSelect: false,
$('.selectpicker').each(function() {
var $selectpicker = $(this);
$.fn.selectpicker.call($selectpicker, $selectpicker.data());
});
var remove_attribute_value = function() {
@@ -176,7 +192,7 @@
}
}
$('#definition_list_group').append('<li class="list-group-item list-group-item-action d-flex justify-content-between">' + DOMPurify.sanitize(value) + '<a href="javascript:void(0);"><span class="text-danger"><i class="bi bi-trash"></i></span></a></li>')
$('#definition_list_group').append('<li class="list-group-item">' + DOMPurify.sanitize(value) + '<a href="javascript:void(0);"><span class="glyphicon glyphicon-trash pull-right"></span></a></li>')
.find(':last-child a').click(remove_attribute_value);
$('#definition_value').val('');
};

View File

@@ -7,98 +7,96 @@
*/
?>
<label for="definition_name" class="form-label"><?= lang('Attributes.definition_name'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-star"></i></span>
<select class="form-select" name="definition_name" id="definition_name">
<option value="-1" selected></option>
<?php foreach ($definition_names as $key => $value): ?>
<option value="<?= $key ?>"><?= $value ?></option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Attributes.definition_name'), 'definition_name_label', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown([
'name' => 'definition_name',
'options' => $definition_names,
'selected' => -1,
'class' => 'form-control',
'id' => 'definition_name'
]) ?>
</div>
</div>
<?php foreach ($definition_values as $definition_id => $definition_value) { ?>
<span class="attribute_added">
<?php
$attribute_value = $definition_value['attribute_value'];
<div class="form-group form-group-sm">
<?= form_label(esc($definition_value['definition_name']), esc($definition_value['definition_name']), ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<?php
echo form_hidden("attribute_ids[$definition_id]", strval($definition_value['attribute_id']));
$attribute_value = $definition_value['attribute_value'];
switch ($definition_value['definition_type']) {
switch ($definition_value['definition_type']) {
case DATE:
$value = (empty($attribute_value) || empty($attribute_value->attribute_date)) ? NOW : strtotime($attribute_value->attribute_date);
echo form_input([
'name' => "attribute_links[$definition_id]",
'value' => to_date($value),
'class' => 'form-control input-sm datetime',
'data-definition-id' => $definition_id,
'readonly' => 'true'
]);
break;
case DROPDOWN:
$selected_value = $definition_value['selected_value'];
echo form_dropdown([
'name' => "attribute_links[$definition_id]",
'options' => $definition_value['values'],
'selected' => $selected_value,
'class' => 'form-control',
'data-definition-id' => $definition_id
]);
break;
case TEXT:
$value = (empty($attribute_value) || empty($attribute_value->attribute_value)) ? $definition_value['selected_value'] : $attribute_value->attribute_value;
echo form_input([
'name' => "attribute_links[$definition_id]",
'value' => esc($value),
'class' => 'form-control valid_chars',
'data-definition-id' => $definition_id
]);
break;
case DECIMAL:
$value = (empty($attribute_value) || empty($attribute_value->attribute_decimal)) ? $definition_value['selected_value'] : $attribute_value->attribute_decimal;
echo form_input([
'name' => "attribute_links[$definition_id]",
'value' => to_decimals((float)$value),
'class' => 'form-control valid_chars',
'data-definition-id' => $definition_id
]);
break;
case CHECKBOX:
$value = (empty($attribute_value) || empty($attribute_value->attribute_value)) ? $definition_value['selected_value'] : $attribute_value->attribute_value;
case DATE:
$value = (empty($attribute_value) || empty($attribute_value->attribute_date)) ? NOW : strtotime($attribute_value->attribute_date);
?>
<label for="attribute_links[<?= $definition_id ?>]" class="form-label"><?= esc($definition_value['definition_name']) ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="attribute_links[<?= $definition_id ?>]-icon"><i class="bi bi-calendar2"></i></span>
<input type="hidden" name="attribute_ids[<?= $definition_id ?>]" value="<?= strval($definition_value['attribute_id']) ?>">
<input type="text" class="form-select datetime" name="attribute_links[<?= $definition_id ?>]" id="attribute_links[<?= $definition_id ?>]" aria-describedby="attribute_links[<?= $definition_id ?>]-icon" value="<?= to_date($value) ?>" data-definition-id="<?= $definition_id ?>" readonly>
<button type="button" class="btn btn-outline-danger remove_attribute_btn"><i class="bi bi-trash"></i></button>
// Sends 0 if the box is unchecked instead of not sending anything.
echo form_input([
'type' => 'hidden',
'name' => "attribute_links[$definition_id]",
'id' => "attribute_links[$definition_id]",
'value' => 0,
'data-definition-id' => $definition_id
]);
echo form_checkbox([
'name' => "attribute_links[$definition_id]",
'id' => "attribute_links[$definition_id]",
'value' => 1,
'checked' => $value == 1,
'class' => 'checkbox-inline',
'data-definition-id' => $definition_id
]);
break;
}
?>
<span class="input-group-addon input-sm btn btn-default remove_attribute_btn">
<span class="glyphicon glyphicon-trash"></span>
</span>
</div>
<?php
break;
case DROPDOWN:
$selected_value = $definition_value['selected_value'];
?>
<label for="attribute_links[<?= $definition_id ?>]" class="form-label"><?= esc($definition_value['definition_name']) ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="attribute_links[<?= $definition_id ?>]-icon"><i class="bi bi-menu-down"></i></span>
<input type="hidden" name="attribute_ids[<?= $definition_id ?>]" value="<?= strval($definition_value['attribute_id']) ?>">
<select class="form-select" name="attribute_links[<?= $definition_id ?>]" id="attribute_links[<?= $definition_id ?>]" data-definition-id="<?= $definition_id ?>">
<?php foreach ($definition_value['values'] as $key => $val): ?>
<option value="<?= $key ?>" <?= $selected_value == $key ? 'selected' : '' ?>><?= $val ?></option>
<?php endforeach; ?>
</select>
<button type="button" class="btn btn-outline-danger remove_attribute_btn"><i class="bi bi-trash"></i></button>
</div>
<?php
break;
case TEXT:
$value = (empty($attribute_value) || empty($attribute_value->attribute_value)) ? $definition_value['selected_value'] : $attribute_value->attribute_value;
?>
<label for="attribute_links[<?= $definition_id ?>]" class="form-label"><?= esc($definition_value['definition_name']) ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="attribute_links[<?= $definition_id ?>]-icon"><i class="bi bi-type"></i></span>
<input type="hidden" name="attribute_ids[<?= $definition_id ?>]" value="<?= strval($definition_value['attribute_id']) ?>">
<input type="text" name="attribute_links[<?= $definition_id ?>]" id="attribute_links[<?= $definition_id ?>]" value="<?= esc($value) ?>" class="form-control valid_chars" data-definition-id="<?= $definition_id ?>">
<button type="button" class="btn btn-outline-danger remove_attribute_btn"><i class="bi bi-trash"></i></button>
</div>
<?php
break;
case DECIMAL:
$value = (empty($attribute_value) || empty($attribute_value->attribute_decimal)) ? $definition_value['selected_value'] : $attribute_value->attribute_decimal;
?>
<label for="attribute_links[<?= $definition_id ?>]" class="form-label"><?= esc($definition_value['definition_name']) ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="attribute_links[<?= $definition_id ?>]-icon"><i class="bi bi-dot"></i></span>
<input type="hidden" name="attribute_ids[<?= $definition_id ?>]" value="<?= strval($definition_value['attribute_id']) ?>">
<input type="text" name="attribute_links[<?= $definition_id ?>]" id="attribute_links[<?= $definition_id ?>]" value="<?= to_decimals((float)$value) ?>" class="form-control valid_chars" data-definition-id="<?= $definition_id ?>">
<button type="button" class="btn btn-outline-danger remove_attribute_btn"><i class="bi bi-trash"></i></button>
</div>
<?php
break;
case CHECKBOX:
$value = (empty($attribute_value) || empty($attribute_value->attribute_value)) ? $definition_value['selected_value'] : $attribute_value->attribute_value;
?>
<div class="d-flex justify-content-between">
<div class="form-check form-check-inline mb-3">
<input type="hidden" name="attribute_ids[<?= $definition_id ?>]" value="<?= strval($definition_value['attribute_id']) ?>">
<input type="hidden" name="attribute_links_h1[<?= $definition_id ?>]" id="attribute_links_h1<?= $definition_id ?>" value="0" data-definition-id="<?= $definition_id ?>">
<input type="checkbox" class="form-check-input" name="attribute_links[<?= $definition_id ?>]" id="attribute_links[<?= $definition_id ?>]" value="1" <?= $value == 1 ? 'checked' : '' ?> data-definition-id="<?= $definition_id ?>">
<label class="form-check-label" for="attribute_links[<?= $definition_id ?>]"><?= esc($definition_value['definition_name']) ?></label>
</div>
<button type="button" class="btn btn-outline-danger remove_attribute_btn"><i class="bi bi-trash"></i></button>
</div>
<?php
break;
}
?>
</span>
</div>
</div>
<?php } ?>
@@ -108,7 +106,7 @@
var enable_delete = function() {
$('.remove_attribute_btn').click(function() {
$(this).parents('.attribute_added').remove();
$(this).parents('.form-group').remove();
});
};
@@ -136,13 +134,13 @@
$("[name*='attribute_links'").each(function() {
var definition_id = $(this).data('definition-id');
var element = $(this);
// For checkboxes, use the visible checkbox, not the hidden input
if (element.attr('type') === 'hidden' && element.siblings('input[type="checkbox"]').length > 0) {
// Skip hidden inputs that have a corresponding checkbox
return;
}
// For checkboxes, get the checked state
if (element.attr('type') === 'checkbox') {
result[definition_id] = element.prop('checked') ? '1' : '0';

View File

@@ -8,11 +8,6 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = 'Attributes';
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
$(document).ready(function() {
<?= view('partial/bootstrap_tables_locale') ?>
@@ -26,16 +21,16 @@ echo view('configs/config_header', $title_info);
});
</script>
<div class="d-flex gap-2 justify-content-end d-print-none">
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= esc("$controller_name/view") ?>" title="<?= lang(ucfirst($controller_name) . ".new") ?>">
<i class="bi bi-star me-2"></i><?= lang(ucfirst($controller_name) . ".new") ?>
<div id="title_bar" class="btn-toolbar print_hide">
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= esc("$controller_name/view") ?>" title="<?= lang(ucfirst($controller_name) . ".new") ?>">
<span class="glyphicon glyphicon-star">&nbsp;</span><?= lang(ucfirst($controller_name) . ".new") ?>
</button>
</div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary d-print-none" id="delete">
<i class="bi bi-trash"></i><span class="d-none d-sm-inline ms-2"><?= lang('Common.delete') ?></span>
<div class="pull-left form-inline" role="toolbar">
<button id="delete" class="btn btn-default btn-sm print_hide">
<span class="glyphicon glyphicon-trash">&nbsp;</span><?= lang('Common.delete') ?>
</button>
</div>
</div>

View File

@@ -23,7 +23,7 @@
<div class="col-xs-6">
<div class="input-group">
<span class="input-group-addon input-sm">
<i class="bi bi-calendar2-check"></i>
<span class="glyphicon glyphicon-calendar"></span>
</span>
<?= form_input([
'name' => 'open_date',
@@ -87,7 +87,7 @@
<div class="col-xs-6">
<div class="input-group">
<span class="input-group-addon input-sm">
<i class="bi bi-calendar2-x"></i>
<span class="glyphicon glyphicon-calendar"></span>
</span>
<?= form_input([
'name' => 'close_date',

View File

@@ -12,11 +12,6 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = 'Cashups';
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
$(document).ready(function() {
// Load the preset datarange picker
@@ -51,36 +46,29 @@ echo view('configs/config_header', $title_info);
<?= view('partial/print_receipt', ['print_after_sale' => false, 'selected_printer' => 'takings_printer']) ?>
<div id="title_bar" class="d-flex gap-2 justify-content-end d-print-none">
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . ".new") ?>">
<i class="bi bi-journal-check me-2"></i><?= lang(esc(ucfirst($controller_name)) . '.new') // TODO: String Interpolation ?>
<div id="title_bar" class="print_hide btn-toolbar">
<button onclick="printdoc()" class="btn btn-info btn-sm pull-right">
<span class="glyphicon glyphicon-print">&nbsp;</span><?= lang('Common.print') ?>
</button>
<button type="button" class="btn btn-primary" onclick="window.print()" title="<?= lang('Common.print') ?>">
<i class="bi bi-printer me-2"></i><?= lang('Common.print') ?>
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . ".new") ?>">
<span class="glyphicon glyphicon-tags">&nbsp;</span><?= lang(esc(ucfirst($controller_name)) . '.new') // TODO: String Interpolation ?>
</button>
</div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" id="delete" class="btn btn-secondary d-print-none">
<i class="bi bi-trash"></i><span class="d-none d-sm-inline ms-2"><?= lang('Common.delete') ?></span>
<div class="pull-left form-inline" role="toolbar">
<button id="delete" class="btn btn-default btn-sm print_hide">
<span class="glyphicon glyphicon-trash">&nbsp;</span><?= lang('Common.delete') ?>
</button>
<div class="input-group w-auto">
<span class="input-group-text" id="daterangepicker-icon"><i class="bi bi-calendar2-range"></i></span>
<input type="text" class="form-select" name="daterangepicker" id="daterangepicker" aria-describedby="daterangepicker-icon">
</div>
<div class="input-group w-auto">
<span class="input-group-text" id="filters-icon"><i class="bi bi-funnel"></i></span>
<select class="form-select" name="filters[]" id="filters" aria-describedby="filters-icon" multiple>
<?php foreach ($filters as $key => $label): ?>
<option value="<?= $key ?>" <?= in_array($key, $selected_filters ?? []) ? 'selected' : '' ?>>
<?= esc($label) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?= form_input(['name' => 'daterangepicker', 'class' => 'form-control input-sm', 'id' => 'daterangepicker']) ?>
<?= form_multiselect('filters[]', $filters, $selected_filters ?? [], [
'id' => 'filters',
'data-none-selected-text' => lang('Common.none_selected_text'),
'class' => 'selectpicker show-menu-arrow',
'data-selected-text-format' => 'count > 1',
'data-style' => 'btn-default btn-sm',
'data-width' => 'fit'
]) ?>
</div>
</div>
@@ -89,15 +77,3 @@ echo view('configs/config_header', $title_info);
</div>
<?= view('partial/footer') ?>
<script type="text/javascript">
new TomSelect('#filters', {
plugins: ['checkbox_options', 'remove_button'],
placeholder: '<?= lang('Common.none_selected_text') ?>',
hidePlaceholder: true,
closeAfterSelect: false,
onChange: function() {
$('#table').bootstrapTable('refresh');
}
});
</script>

View File

@@ -1,124 +0,0 @@
<?php
/**
*
*/
$beta = '<sup><span class="badge bg-secondary">BETA</span></sup>';
?>
<?= form_open('config/saveAppearance/', ['id' => 'appearance_config_form']) ?>
<?php
$title_info['config_title'] = 'Appearance';
echo view('configs/config_header', $title_info);
?>
<ul id="error_message_box" class="appearance_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-lg-6">
<label for="theme-change" class="form-label"><?= lang('Config.theme'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-binoculars"></i></span>
<select class="form-select" name="theme" id="theme-change">
<?php foreach ($themes as $value => $display): ?>
<option value="<?= $value ?>" <?= $config['theme'] == $value ? 'selected' : '' ?>><?= $display ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="login_form" class="form-label"><?= lang('Config.login_form'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-view-stacked"></i></span>
<select class="form-select" name="login_form" id="login_form">
<option value="floating_labels" <?= $config['login_form'] == 'floating_labels' ? 'selected' : '' ?>><?= lang('Config.floating_labels') ?></option>
<option value="input_groups" <?= $config['login_form'] == 'input_groups' ? 'selected' : '' ?>><?= lang('Config.input_groups') ?></option>
</select>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="color_mode" class="form-label">Color Mode <?= $beta; ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="color-mode-icon"><i class="bi bi-palette"></i></span>
<select class="form-select" id="color_mode" name="color_mode" aria-describedby="color-mode-icon">
<option value="light" <?= $config['color_mode'] == 'light' ? 'selected' : '' ?>>Light</option>
<option value="dark" <?= $config['color_mode'] == 'dark' ? 'selected' : '' ?>>Dark</option>
</select>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="notify_position" class="form-label"><?= lang('Config.notify_alignment'); ?></label>
<div class="row" id="notify_position">
<div class="col-6 mb-3">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-arrow-down-up"></i></span>
<select class="form-select" name="notify_vertical_position">
<option value="top" <?= $config['notify_vertical_position'] == 'top' ? 'selected' : '' ?>><?= lang('Config.top') ?></option>
<option value="bottom" <?= $config['notify_vertical_position'] == 'bottom' ? 'selected' : '' ?>><?= lang('Config.bottom') ?></option>
</select>
</div>
</div>
<div class="col-6 mb-3">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-arrow-left-right"></i></span>
<select class="form-select" name="notify_horizontal_position">
<option value="left" <?= $config['notify_horizontal_position'] == 'left' ? 'selected' : '' ?>><?= lang('Config.left') ?></option>
<option value="center" <?= $config['notify_horizontal_position'] == 'center' ? 'selected' : '' ?>><?= lang('Config.center') ?></option>
<option value="right" <?= $config['notify_horizontal_position'] == 'right' ? 'selected' : '' ?>><?= lang('Config.right') ?></option>
</select>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="config_menu_position" class="form-label">Configuration Menu Position</label>
<div class="input-group mb-3">
<span class="input-group-text" id="config-menu-position-icon"><i class="bi bi-distribute-horizontal"></i></span>
<select class="form-select" id="config_menu_position" name="config_menu_position" aria-describedby="config-menu-position-icon">
<option value="start" <?= $config['config_menu_position'] == 'start' ? 'selected' : '' ?>>Start</option>
<option value="end" <?= $config['config_menu_position'] == 'end' ? 'selected' : '' ?>>End</option>
</select>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="responsive_design" name="responsive_design" value="responsive_design" <?= $config['responsive_design'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="responsive_design">Responsive Design <?= $beta; ?></label>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_appearance"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="application/javascript">
// Validation and submit handling
$(document).ready(function() {
$('#appearance_config_form').validate($.extend(form_support.handler, {
submitHandler: function(form) {
$(form).ajaxSubmit({
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message + '&nbsp;<em>Click to refresh.</em>',
url: 'javascript:window.location.reload();',
target: '_self'
}, {
type: response.success ? 'success' : 'danger'
})
},
dataType: 'json'
});
},
errorLabelContainer: '.appearance_error_message_box'
}));
});
</script>

View File

@@ -6,194 +6,256 @@
*/
?>
<?= form_open('config/saveBarcode/', ['id' => 'barcode_config_form']) ?>
<?= form_open('config/saveBarcode/', ['id' => 'barcode_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.barcode_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="barcode_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="barcode_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-lg-6">
<label for="barcode_type" class="form-label"><?= lang('Config.barcode_type'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-braces"></i></span>
<select class="form-select" name="barcode_type" id="barcode_type">
<?php foreach ($support_barcode as $key => $value): ?>
<option value="<?= $key ?>" <?= $config['barcode_type'] == $key ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_type'), 'barcode_type', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'barcode_type',
$support_barcode,
$config['barcode_type'],
'class="form-control input-sm"'
) ?>
</div>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="barcode_width" class="form-label"><?= lang('Config.barcode_width'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrows"></i></span>
<input type="number" class="form-control" step="5" max="350" min="60" name="barcode_width" id="barcode_width" value="<?= $config['barcode_width'] ?>" required>
<span class="input-group-text">px</span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_width'), 'barcode_width', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<?= form_input([
'step' => '5',
'max' => '350',
'min' => '60',
'type' => 'number',
'name' => 'barcode_width',
'id' => 'barcode_width',
'class' => 'form-control input-sm required',
'value' => $config['barcode_width']
]) ?>
</div>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="barcode_height" class="form-label"><?= lang('Config.barcode_height'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrows-vertical"></i></span>
<input type="number" class="form-control" min="10" max="120" name="barcode_height" id="barcode_height" value="<?= $config['barcode_height'] ?>" required>
<span class="input-group-text">px</span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_height'), 'barcode_height', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<?= form_input([
'type' => 'number',
'min' => 10,
'max' => 120,
'name' => 'barcode_height',
'id' => 'barcode_height',
'class' => 'form-control input-sm required',
'value' => $config['barcode_height']
]) ?>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_font'), 'barcode_font', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-sm-2">
<?= form_dropdown(
'barcode_font',
$barcode_fonts,
$config['barcode_font'],
'class="form-control input-sm" required'
) ?>
</div>
<div class="col-sm-2">
<?= form_input([
'type' => 'number',
'min' => '1',
'max' => '30',
'name' => 'barcode_font_size',
'id' => 'barcode_font_size',
'class' => 'form-control input-sm required',
'value' => $config['barcode_font_size']
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.allow_duplicate_barcodes'), 'allow_duplicate_barcodes', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'allow_duplicate_barcodes',
'id' => 'allow_duplicate_barcodes',
'value' => 'allow_duplicate_barcodes',
'checked' => $config['allow_duplicate_barcodes'] == 1
]) ?>
&nbsp;
<label class="control-label">
<span class="glyphicon glyphicon-warning-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.barcode_tooltip') ?>"></span>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_content'), 'barcode_content', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'barcode_content',
'value' => 'id',
'checked' => $config['barcode_content'] == 'id'
]) ?>
<?= lang('Config.barcode_id') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'barcode_content',
'value' => 'number',
'checked' => $config['barcode_content'] == 'number'
]) ?>
<?= lang('Config.barcode_number') ?>
</label>
&nbsp;
&nbsp;
<label class="checkbox-inline">
<?= form_checkbox([
'name' => 'barcode_generate_if_empty',
'value' => 'barcode_generate_if_empty',
'checked' => $config['barcode_generate_if_empty'] == 1
]) ?>
<?= lang('Config.barcode_generate_if_empty') ?>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_formats'), 'barcode_formats', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<?php
$barcode_formats = json_decode(config('OSPOS')->settings['barcode_formats']);
echo form_dropdown([
'name' => 'barcode_formats[]',
'id' => 'barcode_formats',
'options' => !empty($barcode_formats) ? array_combine($barcode_formats, $barcode_formats) : [],
'multiple' => 'multiple',
'data-role' => 'tagsinput'
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_layout'), 'barcode_layout', ['class' => 'control-label col-xs-2']) ?>
<div class="col-sm-10">
<div class="form-group form-group-sm row">
<label class="control-label col-sm-1"><?= lang('Config.barcode_first_row') . ' ' ?></label>
<div class="col-sm-2">
<?= form_dropdown(
'barcode_first_row',
[
'not_show' => lang('Config.none'),
'name' => lang('Items.name'),
'category' => lang('Items.category'),
'cost_price' => lang('Items.cost_price'),
'unit_price' => lang('Items.unit_price'),
'company_name' => lang('Suppliers.company_name')
],
$config['barcode_first_row'],
['class' => 'form-control input-sm']
); ?>
</div>
<label class="control-label col-sm-1"><?= lang('Config.barcode_second_row') . ' ' ?></label>
<div class="col-sm-2">
<?= form_dropdown(
'barcode_second_row',
[
'not_show' => lang('Config.none'),
'name' => lang('Items.name'),
'category' => lang('Items.category'),
'cost_price' => lang('Items.cost_price'),
'unit_price' => lang('Items.unit_price'),
'item_code' => lang('Items.item_number'),
'company_name' => lang('Suppliers.company_name')
],
$config['barcode_second_row'],
['class' => 'form-control input-sm']
) ?>
</div>
<label class="control-label col-sm-1"><?= lang('Config.barcode_third_row') . ' ' ?></label>
<div class="col-sm-2">
<?= form_dropdown(
'barcode_third_row',
[
'not_show' => lang('Config.none'),
'name' => lang('Items.name'),
'category' => lang('Items.category'),
'cost_price' => lang('Items.cost_price'),
'unit_price' => lang('Items.unit_price'),
'item_code' => lang('Items.item_number'),
'company_name' => lang('Suppliers.company_name')
],
$config['barcode_third_row'],
['class' => 'form-control input-sm']
) ?>
</div>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_number_in_row'), 'barcode_num_in_row', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<?= form_input([
'type' => 'number',
'name' => 'barcode_num_in_row',
'id' => 'barcode_num_in_row',
'class' => 'form-control input-sm required',
'value' => $config['barcode_num_in_row']
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_page_width'), 'barcode_page_width', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-sm-2">
<div class="input-group">
<?= form_input([
'type' => 'number',
'min' => '0',
'max' => '100',
'name' => 'barcode_page_width',
'id' => 'barcode_page_width',
'class' => 'form-control input-sm required',
'value' => $config['barcode_page_width']
]) ?>
<span class="input-group-addon input-sm">%</span>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.barcode_page_cellspacing'), 'barcode_page_cellspacing', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-sm-2">
<div class="input-group">
<?= form_input([
'type' => 'number',
'name' => 'barcode_page_cellspacing',
'id' => 'barcode_page_cellspacing',
'class' => 'form-control input-sm required',
'value' => $config['barcode_page_cellspacing']
]) ?>
<span class="input-group-addon input-sm">px</span>
</div>
</div>
</div>
<?= form_submit([
'name' => 'submit_barcode',
'id' => 'submit_barcode',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<div class="row">
<div class="col-6 col-lg-3">
<label for="barcode_font" class="form-label"><?= lang('Config.barcode_font'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-fonts"></i></span>
<select class="form-select" id="barcode_font" name="barcode_font" required>
<?php foreach ($barcode_fonts as $key => $value): ?>
<option value="<?= $key ?>" <?= $config['barcode_font'] == $key ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="barcode_font_size" class="form-label">Font Size<sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrows-angle-expand"></i></span>
<input type="number" class="form-control" min="1" max="30" name="barcode_font_size" id="barcode_font_size" value="<?= $config['barcode_font_size'] ?>" required>
<span class="input-group-text">px</span>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="allow_duplicate_barcodes" name="allow_duplicate_barcodes" value="allow_duplicate_barcodes" <?= $config['allow_duplicate_barcodes'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="allow_duplicate_barcodes"><?= lang('Config.allow_duplicate_barcodes'); ?></label>
<div class="form-text"><i class="bi bi-info-square pe-1"></i><?= lang('Config.barcode_tooltip') ?></div>
</div>
<label for="barcode_content" class="form-label"><?= lang('Config.barcode_content'); ?></label>
<div class="row mb-3">
<div class="col-12">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="barcode_content" id="barcode_content_id" value="id" <?= $config['barcode_content'] == 'id' ? 'checked' : '' ?>>
<label class="form-check-label" for="barcode_content_id"><?= lang('Config.barcode_id') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="barcode_content" id="barcode_content_number" value="number" <?= $config['barcode_content'] == 'number' ? 'checked' : '' ?>>
<label class="form-check-label" for="barcode_content_number"><?= lang('Config.barcode_number') ?></label>
</div>
<div class="form-check form-check-inline form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="barcode_generate_if_empty" name="barcode_generate_if_empty" value="barcode_generate_if_empty" <?= $config['barcode_generate_if_empty'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="barcode_generate_if_empty"><?= lang('Config.barcode_generate_if_empty'); ?></label>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="barcode_formats" class="form-label"><?= lang('Config.barcode_formats'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-code-square"></i></span>
<!-- <?php
$barcode_formats = json_decode(config('OSPOS')->settings['barcode_formats']);
$options = !empty($barcode_formats) ? array_combine($barcode_formats, $barcode_formats) : [];
?>
<select class="form-select" id="barcode_formats" name="barcode_formats[]" data-role="tagsinput" multiple>
<?php foreach ($options as $value): ?>
<option value="<?= $value ?>" <?= in_array($value, $barcode_formats) ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select> -->
<input type="text" class="form-control" disabled>
</div>
</div>
</div>
<div class="row">
<label for="barcode_layout" class="form-label"><?= lang('Config.barcode_layout'); ?></label>
<div class="col-6 col-lg-3">
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-1-square"></i></span>
<select name="barcode_first_row" class="form-select">
<option value="not_show" <?= $config['barcode_first_row'] == 'not_show' ? 'selected' : '' ?>><?= lang('Config.none') ?></option>
<option value="name" <?= $config['barcode_first_row'] == 'name' ? 'selected' : '' ?>><?= lang('Items.name') ?></option>
<option value="category" <?= $config['barcode_first_row'] == 'category' ? 'selected' : '' ?>><?= lang('Items.category') ?></option>
<option value="cost_price" <?= $config['barcode_first_row'] == 'cost_price' ? 'selected' : '' ?>><?= lang('Items.cost_price') ?></option>
<option value="unit_price" <?= $config['barcode_first_row'] == 'unit_price' ? 'selected' : '' ?>><?= lang('Items.unit_price') ?></option>
<option value="company_name" <?= $config['barcode_first_row'] == 'company_name' ? 'selected' : '' ?>><?= lang('Suppliers.company_name') ?></option>
</select>
</div>
</div>
<div class="col-6 col-lg-3">
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-2-square"></i></span>
<select name="barcode_second_row" class="form-select">
<option value="not_show" <?= $config['barcode_second_row'] == 'not_show' ? 'selected' : '' ?>><?= lang('Config.none') ?></option>
<option value="name" <?= $config['barcode_second_row'] == 'name' ? 'selected' : '' ?>><?= lang('Items.name') ?></option>
<option value="category" <?= $config['barcode_second_row'] == 'category' ? 'selected' : '' ?>><?= lang('Items.category') ?></option>
<option value="cost_price" <?= $config['barcode_second_row'] == 'cost_price' ? 'selected' : '' ?>><?= lang('Items.cost_price') ?></option>
<option value="unit_price" <?= $config['barcode_second_row'] == 'unit_price' ? 'selected' : '' ?>><?= lang('Items.unit_price') ?></option>
<option value="item_code" <?= $config['barcode_second_row'] == 'item_code' ? 'selected' : '' ?>><?= lang('Items.item_number') ?></option>
<option value="company_name" <?= $config['barcode_second_row'] == 'company_name' ? 'selected' : '' ?>><?= lang('Suppliers.company_name') ?></option>
</select>
</div>
</div>
<div class="col-6 col-lg-3">
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-3-square"></i></span>
<select name="barcode_third_row" class="form-select">
<option value="not_show" <?= $config['barcode_third_row'] == 'not_show' ? 'selected' : '' ?>><?= lang('Config.none') ?></option>
<option value="name" <?= $config['barcode_third_row'] == 'name' ? 'selected' : '' ?>><?= lang('Items.name') ?></option>
<option value="category" <?= $config['barcode_third_row'] == 'category' ? 'selected' : '' ?>><?= lang('Items.category') ?></option>
<option value="cost_price" <?= $config['barcode_third_row'] == 'cost_price' ? 'selected' : '' ?>><?= lang('Items.cost_price') ?></option>
<option value="unit_price" <?= $config['barcode_third_row'] == 'unit_price' ? 'selected' : '' ?>><?= lang('Items.unit_price') ?></option>
<option value="item_code" <?= $config['barcode_third_row'] == 'item_code' ? 'selected' : '' ?>><?= lang('Items.item_number') ?></option>
<option value="company_name" <?= $config['barcode_third_row'] == 'company_name' ? 'selected' : '' ?>><?= lang('Suppliers.company_name') ?></option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-6 col-lg-3">
<label for="barcode_num_in_row" class="form-label"><?= lang('Config.barcode_number_in_row'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-123"></i></span>
<input type="number" name="barcode_num_in_row" id="barcode_num_in_row" class="form-control" value="<?= $config['barcode_num_in_row'] ?>" required>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="barcode_page_width" class="form-label"><?= lang('Config.barcode_page_width'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrows"></i></span>
<input type="number" min="0" max="100" name="barcode_page_width" id="barcode_page_width" class="form-control" value="<?= $config['barcode_page_width'] ?>" required>
<span class="input-group-text"><i class="bi bi-percent"></i></span>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="barcode_page_cellspacing" class="form-label"><?= lang('Config.barcode_page_cellspacing'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-distribute-horizontal"></i></span>
<input type="number" name="barcode_page_cellspacing" id="barcode_page_cellspacing" class="form-control" value="<?= $config['barcode_page_cellspacing'] ?>" required>
<span class="input-group-text">px</span>
</div>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_barcode"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -201,7 +263,7 @@
$(document).ready(function() {
$('#barcode_config_form').validate($.extend(form_support.handler, {
errorLabelContainer: ".barcode_error_message_box",
errorLabelContainer: "#barcode_error_message_box",
rules: {
barcode_width: {

View File

@@ -1,5 +0,0 @@
<div class="d-flex">
<h4 class="flex-grow-1 fw-bold"><?= $config_title; ?></h4>
<h5 class="link-secondary d-print-none" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Learn more in our docs"><i class="bi bi-journal-arrow-up"></i></h5>
</div>
<hr class="mt-0 d-print-none">

View File

@@ -4,85 +4,138 @@
*/
?>
<?= form_open('config/saveEmail/', ['id' => 'email_config_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('config/saveEmail/', ['id' => 'email_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.email_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="email_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="email_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-lg-6">
<label for="protocol" class="form-label"><?= lang('Config.email_protocol'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-mailbox"></i></span>
<?= form_dropdown('protocol', array('mail' => 'Mail', 'sendmail' => 'Sendmail', 'smtp' => 'SMTP'), $config['protocol'], array('class' => 'form-select', 'id' => 'protocol')); ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_protocol'), 'protocol', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'protocol',
[
'mail' => 'Mail',
'sendmail' => 'Sendmail',
'smtp' => 'SMTP'
],
$config['protocol'],
'class="form-control input-sm" id="protocol"'
) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="mailpath" class="form-label"><?= lang('Config.email_mailpath'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-braces"></i></span>
<input type="text" name="mailpath" class="form-control" id="mailpath" value="<?= $config['mailpath']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_mailpath'), 'mailpath', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'mailpath',
'id' => 'mailpath',
'class' => 'form-control input-sm',
'value' => $config['mailpath']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="smtp_host" class="form-label"><?= lang('Config.email_smtp_host'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-database"></i></span>
<input type="text" name="smtp_host" class="form-control" id="smtp_host" value="<?= $config['smtp_host']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_smtp_host'), 'smtp_host', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'smtp_host',
'id' => 'smtp_host',
'class' => 'form-control input-sm',
'value' => $config['smtp_host']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="smtp_port" class="form-label"><?= lang('Config.email_smtp_port'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-door-open"></i></span>
<input type="number" name="smtp_port" class="form-control" id="smtp_port" value="<?= $config['smtp_port']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_smtp_port'), 'smtp_port', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'type' => 'number',
'name' => 'smtp_port',
'id' => 'smtp_port',
'class' => 'form-control input-sm',
'value' => $config['smtp_port']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="smtp_crypto" class="form-label"><?= lang('Config.email_smtp_crypto'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-shield-lock"></i></span>
<?= form_dropdown('smtp_crypto', array('' => 'None', 'tls' => 'TLS', 'ssl' => 'SSL'), $config['smtp_crypto'], array('class' => 'form-select', 'id' => 'smtp_crypto')); ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_smtp_crypto'), 'smtp_crypto', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'smtp_crypto',
[
'' => 'None',
'tls' => 'TLS',
'ssl' => 'SSL'
],
$config['smtp_crypto'],
'class="form-control input-sm" id="smtp_crypto"'
) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="smtp_timeout" class="form-label"><?= lang('Config.email_smtp_timeout'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-stopwatch"></i></span>
<input type="number" name="smtp_timeout" class="form-control" id="smtp_timeout" value="<?= $config['smtp_timeout']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_smtp_timeout'), 'smtp_timeout', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'type' => 'number',
'name' => 'smtp_timeout',
'id' => 'smtp_timeout',
'class' => 'form-control input-sm',
'value' => $config['smtp_timeout']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="smtp_user" class="form-label"><?= lang('Config.email_smtp_user'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-person"></i></span>
<input type="text" name="smtp_user" class="form-control" id="smtp_user" value="<?= $config['smtp_user']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_smtp_user'), 'smtp_user', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-user"></span>
</span>
<?= form_input([
'name' => 'smtp_user',
'id' => 'smtp_user',
'class' => 'form-control input-sm',
'value' => $config['smtp_user']
]) ?>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="smtp_pass" class="form-label"><?= lang('Config.email_smtp_pass'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<input type="password" name="smtp_pass" class="form-control" id="smtp_pass" value="<?= $config['smtp_pass']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_smtp_pass'), 'smtp_pass', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-asterisk"></span>
</span>
<?= form_password([
'name' => 'smtp_pass',
'id' => 'smtp_pass',
'class' => 'form-control input-sm',
'value' => $config['smtp_pass']
]) ?>
</div>
</div>
</div>
</div>
<?= form_submit([
'name' => 'submit_email',
'id' => 'submit_email',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_email"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -111,7 +164,6 @@
},
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'
@@ -123,7 +175,7 @@
});
},
errorLabelContainer: '.email_error_message_box'
errorLabelContainer: '#email_error_message_box'
}));
});
</script>

View File

@@ -9,209 +9,459 @@
*/
?>
<?= form_open('config/saveGeneral/', ['id' => 'general_config_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('config/saveGeneral/', ['id' => 'general_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.general_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="general_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="general_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-sm-6 col-xxl-3">
<label for="default_sales_discount" class="form-label"><?= lang('Config.default_sales_discount') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-cart-dash"></i></span>
<input class="form-control" type="number" min="0" max="100" name="default_sales_discount" id="default_sales_discount" value="<?= $config['default_sales_discount'] ?>" required>
<input type="radio" class="btn-check" name="default_sales_discount_type" id="dsd_type_1" value="1" <?= $config['default_sales_discount_type'] == 1 ? 'checked' : '' ?>>
<label class="btn btn-outline-primary fw-semibold" for="dsd_type_1"><?= $config['currency_symbol'] ?></label>
<input type="radio" class="btn-check" name="default_sales_discount_type" id="dsd_type_0" value="0" <?= $config['default_sales_discount_type'] == 0 ? 'checked' : '' ?>>
<label class="btn btn-outline-primary fw-semibold" for="dsd_type_0">%</label>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.theme'), 'theme', ['class' => 'control-label col-xs-2']) ?>
<div class="col-sm-10">
<div class="form-group form-group-sm row">
<div class="col-sm-3">
<?= form_dropdown(
'theme',
$themes,
$config['theme'],
'class="form-control input-sm" id="theme-change"'
) ?>
</div>
<div class="col-sm-7">
<a href="<?= 'https://bootswatch.com/3/' . ('bootstrap' == ($config['theme']) ? 'default' : esc($config['theme'])) ?>" target="_blank" rel=”noopener”>
<span><?= lang('Config.theme_preview') . ' ' . ucfirst(esc($config['theme'])) . ' ' ?></span>
<span class="glyphicon glyphicon-new-window"></span>
</a>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-xxl-3">
<label for="default_receivings_discount" class="form-label"><?= lang('Config.default_receivings_discount') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-bag-dash"></i></span>
<input class="form-control" type="number" min="0" max="100" name="default_receivings_discount" id="default_receivings_discount" value="<?= $config['default_receivings_discount'] ?>" required>
<input type="radio" class="btn-check" name="default_receivings_discount_type" id="drd_type_1" value="1" <?= $config['default_receivings_discount_type'] == 1 ? 'checked' : '' ?>>
<label class="btn btn-outline-primary fw-semibold" for="drd_type_1"><?= $config['currency_symbol'] ?></label>
<input type="radio" class="btn-check" name="default_receivings_discount_type" id="drd_type_0" value="0" <?= $config['default_receivings_discount_type'] == 0 ? 'checked' : '' ?>>
<label class="btn btn-outline-primary fw-semibold" for="drd_type_0">%</label>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.login_form'), 'login_form', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'login_form',
[
'floating_labels' => lang('Config.floating_labels'),
'input_groups' => lang('Config.input_groups')
],
$config['login_form'],
'class="form-control input-sm"'
) ?>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-sm-6 col-xxl-3">
<label for="lines_per_page" class="form-label"><?= lang('Config.lines_per_page'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-list"></i></span>
<input type="number" min="10" max="1000" name="lines_per_page" class="form-control" id="lines_per_page" value="<?= $config['lines_per_page']; ?>" required>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.default_sales_discount'), 'default_sales_discount', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<div class="input-group">
<?= form_input([
'name' => 'default_sales_discount',
'id' => 'default_sales_discount',
'class' => 'form-control input-sm required',
'type' => 'number',
'min' => 0,
'max' => 100,
'value' => $config['default_sales_discount']
]) ?>
<span class="input-group-btn">
<?= form_checkbox([
'id' => 'default_sales_discount_type',
'name' => 'default_sales_discount_type',
'value' => 1,
'data-toggle' => 'toggle',
'data-size' => 'normal',
'data-onstyle' => 'success',
'data-on' => '<b>' . $config['currency_symbol'] . '</b>',
'data-off' => '<b>%</b>',
'checked' => $config['default_sales_discount_type'] == 1
]) ?>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="enforce_privacy" name="enforce_privacy" <?= $config['enforce_privacy'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="enforce_privacy"><?= lang('Config.enforce_privacy'); ?></label>
<div class="form-text"><i class="bi bi-info-square pe-1"></i><?= lang('Config.enforce_privacy_tooltip') ?></div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="receiving_calculate_average_price" name="receiving_calculate_average_price" <?= $config['receiving_calculate_average_price'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="receiving_calculate_average_price"><?= lang('Config.receiving_calculate_average_price'); ?></label>
</div>
<div class="row">
<label class="form-label"><?= lang('Config.image_restrictions'); ?></label>
<div class="col-12 col-sm-6 col-xl-3">
<div class="input-group mb-3" data-bs-toggle="tooltip" title="<?= lang('Config.image_max_width_tooltip'); ?>">
<span class="input-group-text"><i class="bi bi-arrows"></i></span>
<input type="number" min="128" max="3840" name="image_max_width" id="image_max_width" class="form-control" value="<?= $config['image_max_width']; ?>" required>
<span class="input-group-text">px</span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.default_receivings_discount'), 'default_receivings_discount', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<div class="input-group">
<?= form_input([
'name' => 'default_receivings_discount',
'id' => 'default_receivings_discount',
'class' => 'form-control input-sm required',
'type' => 'number',
'min' => 0,
'max' => 100,
'value' => $config['default_receivings_discount']
]) ?>
<span class="input-group-btn">
<?= form_checkbox([
'id' => 'default_receivings_discount_type',
'name' => 'default_receivings_discount_type',
'value' => 1,
'data-toggle' => 'toggle',
'data-size' => 'normal',
'data-onstyle' => 'success',
'data-on' => '<b>' . $config['currency_symbol'] . '</b>',
'data-off' => '<b>%</b>',
'checked' => $config['default_receivings_discount_type'] == 1
]) ?>
</span>
</div>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-xl-3">
<div class="input-group mb-3" data-bs-toggle="tooltip" title="<?= lang('Config.image_max_height_tooltip'); ?>">
<span class="input-group-text"><i class="bi bi-arrows-vertical"></i></span>
<input type="number" min="128" max="3840" name="image_max_height" id="image_max_height" class="form-control" value="<?= $config['image_max_height']; ?>" required>
<span class="input-group-text">px</span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.enforce_privacy'), 'enforce_privacy', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'enforce_privacy',
'id' => 'enforce_privacy',
'value' => 'enforce_privacy',
'checked' => $config['enforce_privacy'] == 1
]) ?>
&nbsp;
<label class="control-label">
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.enforce_privacy_tooltip') ?>"></span>
</label>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-xl-3">
<div class="input-group mb-3" data-bs-toggle="tooltip" title="<?= lang('Config.image_max_size_tooltip'); ?>">
<span class="input-group-text"><i class="bi bi-hdd"></i></span>
<input type="number" min="128" max="2048" name="image_max_size" id="image_max_size" class="form-control" value="<?= $config['image_max_size']; ?>" required>
<span class="input-group-text">kb</span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receiving_calculate_average_price'), 'receiving_calculate_average_price', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'receiving_calculate_average_price',
'id' => 'receiving_calculate_average_price',
'value' => 'receiving_calculate_average_price',
'checked' => $config['receiving_calculate_average_price'] == 1
]) ?>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-xl-3">
<div class="input-group mb-3" data-bs-toggle="tooltip" title="<?= lang('Config.image_allowed_file_types'); ?>">
<span class="input-group-text"><i class="bi bi-images"></i></span>
<select name="image_allowed_types[]" id="image_allowed_types" class="form-select" multiple placeholder="<?= lang('Config.image_allowed_file_types'); ?>" required>
<?php foreach($image_allowed_types as $type): ?>
<option value="<?= $type; ?>" <?= in_array($type, $selected_image_allowed_types) ? 'selected' : ''; ?>>
<?= $type; ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.lines_per_page'), 'lines_per_page', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'lines_per_page',
'id' => 'lines_per_page',
'class' => 'form-control input-sm required',
'type' => 'number',
'min' => 10,
'max' => 1000,
'value' => $config['lines_per_page']
]) ?>
</div>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" name="gcaptcha_enable" id="gcaptcha_enable" value="gcaptcha_enable" <?= $config['gcaptcha_enable'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="gcaptcha_enable"><?= lang('Config.gcaptcha_enable') ?></label>
<a class="d-inline-block" href="https://google.com/recaptcha/admin" target="_blank" rel="noopener"><i class="bi bi-link-45deg link-secondary"></i></a>
<div class="form-text"><i class="bi bi-info-square pe-1"></i><?= lang('Config.gcaptcha_tooltip') ?></div>
</div>
<div class="row mb-3">
<div class="col-12 col-lg-6">
<label for="gcaptcha_site_key" class="form-label"><?= lang('Config.gcaptcha_site_key') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-key"></i></span>
<input type="text" class="form-control" name="gcaptcha_site_key" id="gcaptcha_site_key" required>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.notify_alignment'), 'notify_horizontal_position', ['class' => 'control-label col-xs-2']) ?>
<div class="col-sm-10">
<div class="form-group form-group-sm row">
<div class="col-sm-2">
<?= form_dropdown(
'notify_vertical_position',
[
'top' => lang('Config.top'),
'bottom' => lang('Config.bottom')
],
$config['notify_vertical_position'],
'class="form-control input-sm"'
) ?>
</div>
<div class="col-sm-2">
<?= form_dropdown(
'notify_horizontal_position',
[
'left' => lang('Config.left'),
'center' => lang('Config.center'),
'right' => lang('Config.right')
],
$config['notify_horizontal_position'],
'class="form-control input-sm"'
) ?>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="gcaptcha_secret_key" class="form-label"><?= lang('Config.gcaptcha_secret_key') ?></label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-stars"></i></span>
<input type="text" class="form-control" name="gcaptcha_secret_key" id="gcaptcha_secret_key" required>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.image_restrictions'), 'image_restrictions', ['class' => 'control-label col-xs-2']) ?>
<div class="col-sm-10">
<div class="form-group form-group-sm row">
<div class="col-sm-2">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-resize-horizontal"></span>
</span>
<?= form_input([
'name' => 'image_max_width',
'id' => 'image_max_width',
'class' => 'form-control input-sm required',
'type' => 'number',
'min' => 128,
'max' => 3840,
'value' => $config['image_max_width'],
'data-toggle' => 'tooltip',
'data-placement' => 'top',
'title' => lang('Config.image_max_width_tooltip')
]) ?>
</div>
</div>
<div class="col-sm-2">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-resize-vertical"></span>
</span>
<?= form_input([
'name' => 'image_max_height',
'id' => 'image_max_height',
'class' => 'form-control input-sm required',
'type' => 'number',
'min' => 128,
'max' => 3840,
'value' => $config['image_max_height'],
'data-toggle' => 'tooltip',
'data-placement' => 'top',
'title' => lang('Config.image_max_height_tooltip')
]) ?>
</div>
</div>
<div class="col-sm-2">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-hdd"></span>
</span>
<?= form_input([
'name' => 'image_max_size',
'id' => 'image_max_size',
'class' => 'form-control input-sm required',
'type' => 'number',
'min' => 128,
'max' => 2048,
'value' => $config['image_max_size'],
'data-toggle' => 'tooltip',
'data-placement' => 'top',
'title' => lang('Config.image_max_size_tooltip')
]) ?>
</div>
</div>
<div class="col-sm-4">
<div class="input-group">
<span class="input-group-addon input-sm"><?= lang('Config.image_allowed_file_types') ?></span>
<?= form_multiselect([
'name' => 'image_allowed_types[]',
'options' => $image_allowed_types,
'selected' => $selected_image_allowed_types,
'id' => 'image_allowed_types',
'class' => 'selectpicker show-menu-arrow',
'data-none-selected-text' => lang('Common.none_selected_text'),
'data-selected-text-format' => 'count > 1',
'data-style' => 'btn-default btn-sm',
'data-width' => '100%'
]) ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" id="suggestions_layout">
<label for="suggestions_layout" class="form-label"><?= lang('Config.suggestions_layout'); ?></label>
<div class="col-12 col-sm-6 col-xl-4 col-xxl-3 mb-3">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-layout-three-columns"></i>&nbsp;1.</span>
<select class="form-select" name="suggestions_first_column">
<option value="name" <?= $config['suggestions_first_column'] == 'name' ? 'selected' : '' ?>><?= lang('Items.name') ?></option>
<option value="item_number" <?= $config['suggestions_first_column'] == 'item_number' ? 'selected' : '' ?>><?= lang('Items.number_information') ?></option>
<option value="unit_price" <?= $config['suggestions_first_column'] == 'unit_price' ? 'selected' : '' ?>><?= lang('Items.unit_price') ?></option>
<option value="cost_price" <?= $config['suggestions_first_column'] == 'cost_price' ? 'selected' : '' ?>><?= lang('Items.cost_price') ?></option>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.gcaptcha_enable'), 'gcaptcha_enable', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'gcaptcha_enable',
'id' => 'gcaptcha_enable',
'value' => 'gcaptcha_enable',
'checked' => $config['gcaptcha_enable'] == 1
]) ?>
<label class="control-label">
<a href="https://www.google.com/recaptcha/admin" target="_blank">
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.gcaptcha_tooltip') ?>"></span>
</a>
</label>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-xl-4 col-xxl-3 mb-3">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-layout-three-columns"></i>&nbsp;2.</span>
<select class="form-select" name="suggestions_second_column">
<option value="" <?= $config['suggestions_second_column'] == null ? 'selected' : '' ?>><?= lang('Config.none') ?></option>
<option value="name" <?= $config['suggestions_second_column'] == 'name' ? 'selected' : '' ?>><?= lang('Items.name') ?></option>
<option value="item_number" <?= $config['suggestions_second_column'] == 'item_number' ? 'selected' : '' ?>><?= lang('Items.number_information') ?></option>
<option value="unit_price" <?= $config['suggestions_second_column'] == 'unit_price' ? 'selected' : '' ?>><?= lang('Items.unit_price') ?></option>
<option value="cost_price" <?= $config['suggestions_second_column'] == 'cost_price' ? 'selected' : '' ?>><?= lang('Items.cost_price') ?></option>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.gcaptcha_site_key'), 'config_gcaptcha_site_key', ['class' => 'required control-label col-xs-2', 'id' => 'config_gcaptcha_site_key']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'gcaptcha_site_key',
'id' => 'gcaptcha_site_key',
'class' => 'form-control input-sm required',
'value' => $config['gcaptcha_site_key']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-xl-4 col-xxl-3 mb-3">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-layout-three-columns"></i>&nbsp;3.</span>
<select class="form-select" name="suggestions_third_column">
<option value="" <?= $config['suggestions_third_column'] == null ? 'selected' : '' ?>><?= lang('Config.none') ?></option>
<option value="name" <?= $config['suggestions_third_column'] == 'name' ? 'selected' : '' ?>><?= lang('Items.name') ?></option>
<option value="item_number" <?= $config['suggestions_third_column'] == 'item_number' ? 'selected' : '' ?>><?= lang('Items.number_information') ?></option>
<option value="unit_price" <?= $config['suggestions_third_column'] == 'unit_price' ? 'selected' : '' ?>><?= lang('Items.unit_price') ?></option>
<option value="cost_price" <?= $config['suggestions_third_column'] == 'cost_price' ? 'selected' : '' ?>><?= lang('Items.cost_price') ?></option>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.gcaptcha_secret_key'), 'config_gcaptcha_secret_key', ['class' => 'required control-label col-xs-2', 'id' => 'config_gcaptcha_secret_key']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'gcaptcha_secret_key',
'id' => 'gcaptcha_secret_key',
'class' => 'form-control input-sm required',
'value' => $config['gcaptcha_secret_key']
]) ?>
</div>
</div>
</div>
</div>
<label for="giftcard_number" class="form-label"><?= lang('Config.giftcard_number'); ?></label>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="giftcard_number" id="giftcard_series" value="series" <?= $config['giftcard_number'] == 'series' ? 'checked' : '' ?>>
<label class="form-check-label" for="giftcard_series"><?= lang('Config.giftcard_series') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="giftcard_number" id="giftcard_random" value="random" <?= $config['giftcard_number'] == 'random' ? 'checked' : '' ?>>
<label class="form-check-label" for="giftcard_random"><?= lang('Config.giftcard_random') ?></label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.suggestions_layout'), 'suggestions_layout', ['class' => 'control-label col-xs-2']) ?>
<div class="col-sm-10">
<div class="form-group form-group-sm row">
<div class="col-sm-3">
<div class="input-group">
<span class="input-group-addon input-sm"><?= lang('Config.suggestions_first_column') ?></span>
<?= form_dropdown(
'suggestions_first_column',
[
'name' => lang('Items.name'),
'item_number' => lang('Items.number_information'),
'unit_price' => lang('Items.unit_price'),
'cost_price' => lang('Items.cost_price')
],
$config['suggestions_first_column'],
'class="form-control input-sm"'
) ?>
</div>
</div>
<div class="col-sm-3">
<div class="input-group">
<span class="input-group-addon input-sm"><?= lang('Config.suggestions_second_column') ?></span>
<?= form_dropdown(
'suggestions_second_column',
[
'' => lang('Config.none'),
'name' => lang('Items.name'),
'item_number' => lang('Items.number_information'),
'unit_price' => lang('Items.unit_price'),
'cost_price' => lang('Items.cost_price')
],
$config['suggestions_second_column'],
'class="form-control input-sm"'
) ?>
</div>
</div>
<div class="col-sm-3">
<div class="input-group">
<span class="input-group-addon input-sm"><?= lang('Config.suggestions_third_column') ?></span>
<?= form_dropdown(
'suggestions_third_column',
[
'' => lang('Config.none'),
'name' => lang('Items.name'),
'item_number' => lang('Items.number_information'),
'unit_price' => lang('Items.unit_price'),
'cost_price' => lang('Items.cost_price')
],
$config['suggestions_third_column'],
'class="form-control input-sm"'
) ?>
</div>
</div>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="derive_sale_quantity" name="derive_sale_quantity" value="derive_sale_quantity" <?= $config['derive_sale_quantity'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="derive_sale_quantity"><?= lang('Config.derive_sale_quantity'); ?></label>
<div class="form-text"><i class="bi bi-info-square pe-1"></i><?= lang('Config.derive_sale_quantity_tooltip') ?></div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.giftcard_number'), 'giftcard_number', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'giftcard_number',
'value' => 'series',
'checked' => $config['giftcard_number'] == 'series'
]) ?>
<?= lang('Config.giftcard_series') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'giftcard_number',
'value' => 'random',
'checked' => $config['giftcard_number'] == 'random'
]) ?>
<?= lang('Config.giftcard_random') ?>
</label>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="show_office_group" name="show_office_group" value="show_office_group" <?= $show_office_group > 0 ? 'checked' : '' ?>>
<label class="form-check-label" for="show_office_group"><?= lang('Config.show_office_group'); ?></label>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.derive_sale_quantity'), 'derive_sale_quantity', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'derive_sale_quantity',
'id' => 'derive_sale_quantity',
'value' => 'derive_sale_quantity',
'checked' => $config['derive_sale_quantity'] == 1
]) ?>
&nbsp;
<label class="control-label">
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.derive_sale_quantity_tooltip') ?>"></span>
</label>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="multi_pack_enabled" name="multi_pack_enabled" value="multi_pack_enabled" <?= $config['multi_pack_enabled'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="multi_pack_enabled"><?= lang('Config.multi_pack_enabled'); ?></label>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.show_office_group'), 'show_office_group', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'show_office_group',
'id' => 'show_office_group',
'value' => 'show_office_group',
'checked' => $show_office_group > 0
]) ?>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="include_hsn" name="include_hsn" value="include_hsn" <?= $config['include_hsn'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="include_hsn"><?= lang('Config.include_hsn'); ?></label>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.multi_pack_enabled'), 'multi_pack_enabled', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'multi_pack_enabled',
'id' => 'multi_pack_enabled',
'value' => 'multi_pack_enabled',
'checked' => $config['multi_pack_enabled'] == 1
]) ?>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="category_dropdown" name="category_dropdown" value="category_dropdown" <?= $config['category_dropdown'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="category_dropdown"><?= lang('Config.category_dropdown'); ?></label>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.include_hsn'), 'include_hsn', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'include_hsn',
'id' => 'include_hsn',
'value' => 'include_hsn',
'checked' => $config['include_hsn'] == 1
]) ?>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_general"><?= lang('Common.submit'); ?></button>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.category_dropdown'), 'category_dropdown', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'category_dropdown',
'id' => 'category_dropdown',
'value' => 'category_dropdown',
'checked' => $config['category_dropdown'] == 1
]) ?>
</div>
</div>
<?= form_submit([
'name' => 'submit_general',
'id' => 'submit_general',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -234,7 +484,7 @@
$('#general_config_form').validate($.extend(form_support.handler, {
errorLabelContainer: ".general_error_message_box",
errorLabelContainer: "#general_error_message_box",
rules: {
lines_per_page: {
@@ -278,7 +528,6 @@
},
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'

View File

@@ -6,110 +6,154 @@
*/
?>
<?= form_open('config/saveInfo/', ['id' => 'info_config_form', 'enctype' => 'multipart/form-data', 'class' => 'needs-validation']) ?> <!-- TODO-BS5 add is-invalid and invalid-feeback from BS5 to boxes -->
<?= form_open('config/saveInfo/', ['id' => 'info_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.info_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="info_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="info_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-lg-6">
<label for="info-company" class="form-label"><?= lang('Config.company'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-shop-window"></i></span>
<input type="text" class="form-control" name="company" id="info-company" value="<?= $config['company']; ?>" required> <!-- TODO-BS5 invalid-feedback makes input borders not rounded? -->
<div class="invalid-feedback"><?= lang('Config.company_required') ?></div>
</div>
</div>
</div>
<div class="row mb-3">
<label for="info-company_logo" class="form-label"><?= lang('Config.company_logo'); ?></label>
<div class="col-12 col-lg-6">
<div id="info-company_logo" class="w-100 fileinput <?= $logo_exists ? 'fileinput-exists' : 'fileinput-new'; ?>" data-provides="fileinput">
<div class="input-group mb-3" aria-describedby="company-logo-desc">
<span class="input-group-text"><i class="bi bi-image"></i></span>
<div class="fileinput-new form-control rounded-end mb-0" style="height: 200px; cursor: default;"></div>
<div class="fileinput-exists fileinput-preview img-thumbnail form-control rounded-end mb-0 bg-light mh-100" style="height: 200px; cursor: default; background-size: 40px 40px; background-position: 0 0, 20px 20px; background-image: linear-gradient(45deg, white 25%, transparent 25%, transparent 75%, white 75%, white), linear-gradient(45deg, white 25%, transparent 25%, transparent 75%, white 75%, white);">
<img class="mh-100 mw-100" data-src="holder.js/100%x100%" alt="<?= esc(lang('Config.company_logo')) ?>" src="<?= $logo_src ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.company'), 'company', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-6">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-home"></span>
</span>
<?= form_input([
'name' => 'company',
'id' => 'company',
'class' => 'form-control input-sm required',
'value' => $config['company']
]) ?>
</div>
</div>
<div type="button" class="btn btn-secondary btn-file me-2">
<span class="fileinput-new"><i class="bi bi-hand-index me-2"></i><?= lang('Config.company_select_image') ?></span>
<span class="fileinput-exists"><i class="bi bi-images me-2"></i><?= lang('Config.company_change_image') ?></span>
<input type="file" name="company_logo">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.company_logo'), 'company_logo', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-6">
<div class="fileinput <?= $logo_exists ? 'fileinput-exists' : 'fileinput-new' ?>" data-provides="fileinput">
<div class="fileinput-new thumbnail" style="width: 200px; height: 200px;"></div>
<div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 200px; max-height: 200px;">
<img data-src="holder.js/100%x100%" alt="<?= esc(lang('Config.company_logo')) ?>" src="<?= $logo_src ?>" style="max-height: 100%; max-width: 100%;">
</div>
<div>
<span class="btn btn-default btn-sm btn-file">
<span class="fileinput-new"><?= lang('Config.company_select_image') ?></span>
<span class="fileinput-exists"><?= lang('Config.company_change_image') ?></span>
<input type="file" name="company_logo">
</span>
<a href="#" class="btn btn-default btn-sm fileinput-exists" data-dismiss="fileinput"><?= lang('Config.company_remove_image') ?></a>
</div>
</div>
</div>
<a type="button" class="btn btn-outline-secondary fileinput-exists" data-dismiss="fileinput">
<i class="bi bi-eraser me-2"></i><?= lang('Config.company_remove_image') ?>
</a>
</div>
</div>
<div class="col-12 col-lg-6 form-text d-none d-lg-block" id="company-logo-desc">
<ul class="list-unstyled">
<li>&raquo; Supported file formats; gif, png, jpg</li> <!-- TODO-BS5 add to translations -->
<li>&raquo; Max upload size of 100kb</li> <!-- TODO-BS5 add to translations -->
<li>&raquo; Max dimensions of 200x200px</li> <!-- TODO-BS5 add to translations -->
</ul>
</div>
</div>
<label for="info-address" class="form-label"><?= lang('Config.address'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-house"></i></span>
<textarea class="form-control" name="address" id="info-address" rows="10" required><?= $config['address']; ?></textarea>
<div class="invalid-feedback"><?= lang('Config.address_required') ?></div>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="info-website" class="form-label"><?= lang('Config.website'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-globe"></i></span>
<input class="form-control" name="website" id="info-website" value="<?= $config['website']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.address'), 'address', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-6">
<?= form_textarea([
'name' => 'address',
'id' => 'address',
'class' => 'form-control input-sm required',
'value' => $config['address']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="info-email" class="form-label"><?= lang('Config.email'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-at"></i></span>
<input type="email" class="form-control" name="email" id="info-email" value="<?= $config['email']; ?>">
<div class="invalid-feedback"><?= lang('Common.email_invalid_format') ?></div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.website'), 'website', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-6">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-globe"></span>
</span>
<?= form_input([
'name' => 'website',
'id' => 'website',
'class' => 'form-control input-sm',
'value' => $config['website']
]) ?>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="info-phone" class="form-label"><?= lang('Config.phone'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-telephone"></i></span>
<input type="tel" class="form-control" name="phone" id="info-phone" value="<?= $config['phone']; ?>" required>
<div class="invalid-feedback"><?= lang('Config.phone_required') ?></div>
<div class="form-group form-group-sm">
<?= form_label(lang('Common.email'), 'email', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-6">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-envelope"></span>
</span>
<?= form_input([
'name' => 'email',
'id' => 'email',
'type' => 'email',
'class' => 'form-control input-sm',
'value' => $config['email']
]) ?>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="info-fax" class="form-label"><?= lang('Config.fax'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-printer"></i></span>
<input type="tel" class="form-control" name="fax" id="info-fax" value="<?= $config['fax']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.phone'), 'phone', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-6">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-phone-alt"></span>
</span>
<?= form_input([
'type' => 'tel',
'name' => 'phone',
'id' => 'phone',
'class' => 'form-control input-sm required',
'value' => $config['phone']
]) ?>
</div>
</div>
</div>
</div>
</div>
<label for="info-return_policy" class="form-label"><?= lang('Common.return_policy'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-box-arrow-in-down-left"></i></span>
<textarea class="form-control" name="return_policy" id="info-return_policy" rows="10" required><?= $config['return_policy']; ?></textarea>
<div class="invalid-feedback"><?= lang('Config.return_policy_required') ?></div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.fax'), 'fax', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-6">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-phone-alt"></span>
</span>
<?= form_input([
'type' => 'tel',
'name' => 'fax',
'id' => 'fax',
'class' => 'form-control input-sm',
'value' => $config['fax']
]) ?>
</div>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_info"><?= lang('Common.submit'); ?></button>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Common.return_policy'), 'return_policy', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-6">
<?= form_textarea([
'name' => 'return_policy',
'id' => 'return_policy',
'class' => 'form-control input-sm required',
'value' => $config['return_policy']
]) ?>
</div>
</div>
<?= form_submit([
'name' => 'submit_info',
'id' => 'submit_info',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -125,7 +169,7 @@
$('#info_config_form').validate($.extend(form_support.handler, {
errorLabelContainer: ".info_error_message_box",
errorLabelContainer: "#info_error_message_box",
rules: {
company: "required",

View File

@@ -5,55 +5,64 @@
*/
?>
<?= form_open('config/saveMailchimp/', ['id' => 'mailchimp_config_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('config/saveMailchimp/', ['id' => 'mailchimp_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.integrations_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<div id="integrations_header"><?= lang('Config.mailchimp_configuration') ?></div>
<ul id="mailchimp_error_message_box" class="error_message_box"></ul>
<legend class="fs-5"><?= lang('Config.mailchimp_configuration') ?></legend>
<ul id="error_message_box" class="mailchimp_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-lg-6">
<label for="mailchimp_api_key" class="form-label">
<?= lang('Config.mailchimp_api_key'); ?>
<!--<a href="https://eepurl.com/dyijVH" target="_blank" rel="noopener">
<i class="bi bi-info-circle-fill text-secondary" data-bs-toggle="tooltip" title="<?= lang('Config.mailchimp_tooltip'); ?>"></i>
</a>-->
</label>
<div class="input-group">
<span class="input-group-text" id="mailchimp-api-key-icon"><i class="bi bi-key"></i></span>
<input type="text" class="form-control" name="mailchimp_api_key" id="mailchimp_api_key" aria-describedby="mailchimp-api-key-icon" value="<?= $mailchimp['api_key']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.mailchimp_api_key'), 'mailchimp_api_key', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-cloud"></span>
</span>
<?= form_input([
'name' => 'mailchimp_api_key',
'id' => 'mailchimp_api_key',
'class' => 'form-control input-sm',
'value' => $mailchimp['api_key']
]) ?>
</div>
</div>
<div class="col-xs-1">
<label class="control-label">
<a href="https://eepurl.com/b9a05b" target="_blank">
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.mailchimp_tooltip') ?>"></span>
</a>
</label>
</div>
</div>
<div class="form-text mb-3">
<a class="link-secondary" href="https://eepurl.com/dyijVH" target="_blank" rel="noopener">
<i class="bi bi-info-square pe-1"></i><?= lang('Config.mailchimp_tooltip') ?>
</a>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="mailchimp_list_id" class="form-label"><?= lang('Config.mailchimp_lists'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="mailchimp-lists-icon"><i class="bi bi-list-stars"></i></span>
<select class="form-select" id="mailchimp_list_id" aria-describedby="mailchimp-lists-icon" <?= $mailchimp['api_key'] == null ? 'disabled' : '' ?>>
<option>Choose...</option>
<?php foreach($mailchimp['lists'] as $value => $display_text): ?>
<option value="<?= $value; ?>" <?= $value == $mailchimp['list_id'] ? 'selected' : ''; ?>>
<?= $display_text; ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.mailchimp_lists'), 'mailchimp_list_id', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-user"></span>
</span>
<?= form_dropdown(
'mailchimp_list_id',
$mailchimp['lists'],
$mailchimp['list_id'],
'id="mailchimp_list_id" class="form-control input-sm"'
) ?>
</div>
</div>
</div>
</div>
<?= form_submit([
'name' => 'submit_mailchimp',
'id' => 'submit_mailchimp',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="sumbit_mailchimp"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -65,7 +74,6 @@
},
function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'
@@ -94,7 +102,7 @@
});
},
errorLabelContainer: '.mailchimp_error_message_box'
errorLabelContainer: '#mailchimp_error_message_box'
}));
});
</script>

View File

@@ -6,135 +6,193 @@
*/
?>
<?= form_open('config/saveInvoice/', ['id' => 'invoice_config_form']) ?>
<?= form_open('config/saveInvoice/', ['id' => 'invoice_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.invoice_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="invoice_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="invoice_error_message_box alert alert-warning d-none"></ul>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="invoice_enable" name="invoice_enable" value="invoice_enable" <?= $config['invoice_enable'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="invoice_enable"><?= lang('Config.invoice_enable'); ?></label>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="invoice_type" class="form-label"><?= lang('Config.invoice_type'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-file-code"></i></span>
<select class="form-select" name="invoice_type">
<?php foreach ($invoice_type_options as $key => $value): ?>
<option value="<?= $key ?>" <?= $key == $config['invoice_type'] ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.invoice_enable'), 'invoice_enable', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'invoice_enable',
'value' => 'invoice_enable',
'id' => 'invoice_enable',
'checked' => $config['invoice_enable'] == 1
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="recv_invoice_format" class="form-label"><?= lang('Config.recv_invoice_format'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-braces"></i></span>
<input type="text" class="form-control" name="recv_invoice_format" id="recv_invoice_format" value="<?= $config['recv_invoice_format']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.invoice_type'), 'invoice_type', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-3">
<?= form_dropdown(
'invoice_type',
$invoice_type_options,
$config['invoice_type'],
'class="form-control input-sm"'
) ?>
</div>
</div>
</div>
</div>
<label for="invoice_default_comments" class="form-label"><?= lang('Config.invoice_default_comments'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-file-text"></i></span>
<textarea class="form-control" name="invoice_default_comments" id="invoice_default_comments" rows="10" required><?= $config['invoice_default_comments']; ?></textarea>
</div>
<label for="invoice_email_message" class="form-label"><?= lang('Config.invoice_email_message'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-envelope-paper"></i></span>
<textarea class="form-control" name="invoice_email_message" id="invoice_email_message" rows="10" required><?= $config['invoice_email_message']; ?></textarea>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="line_sequence" class="form-label"><?= lang('Config.line_sequence'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-list-ol"></i></span>
<select class="form-select" name="line_sequence">
<?php foreach ($line_sequence_options as $key => $value): ?>
<option value="<?= $key ?>" <?= $key == $config['line_sequence'] ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.recv_invoice_format'), 'recv_invoice_format', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'recv_invoice_format',
'id' => 'recv_invoice_format',
'class' => 'form-control input-sm',
'value' => $config['recv_invoice_format']
]) ?>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="sales_invoice_format" class="form-label"><?= lang('Config.sales_invoice_format'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-braces"></i></span>
<input type="text" class="form-control" name="sales_invoice_format" id="sales_invoice_format" value="<?= $config['sales_invoice_format']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.invoice_default_comments'), 'invoice_default_comments', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-5">
<?= form_textarea([
'name' => 'invoice_default_comments',
'id' => 'invoice_default_comments',
'class' => 'form-control input-sm',
'value' => $config['invoice_default_comments']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="last_used_invoice_number" class="form-label"><?= lang('Config.last_used_invoice_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-123"></i></span>
<input type="number" class="form-control" name="last_used_invoice_number" id="last_used_invoice_number" value="<?= $config['last_used_invoice_number']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.invoice_email_message'), 'invoice_email_message', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-5">
<?= form_textarea([
'name' => 'invoice_email_message',
'id' => 'invoice_email_message',
'class' => 'form-control input-sm',
'value' => $config['invoice_email_message']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="sales_quote_format" class="form-label"><?= lang('Config.sales_quote_format'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-braces"></i></span>
<input type="text" class="form-control" name="sales_quote_format" id="sales_quote_format" value="<?= $config['sales_quote_format']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.line_sequence'), 'line_sequence', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'line_sequence',
$line_sequence_options,
$config['line_sequence'],
'class="form-control input-sm"'
) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="last_used_quote_number" class="form-label"><?= lang('Config.last_used_quote_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-123"></i></span>
<input type="number" class="form-control" name="last_used_quote_number" id="last_used_quote_number" value="<?= $config['last_used_quote_number']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.sales_invoice_format'), 'sales_invoice_format', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'sales_invoice_format',
'id' => 'sales_invoice_format',
'class' => 'form-control input-sm',
'value' => $config['sales_invoice_format']
]) ?>
</div>
</div>
</div>
</div>
<label for="quote_default_comments" class="form-label"><?= lang('Config.quote_default_comments'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-file-text"></i></span>
<textarea class="form-control" name="quote_default_comments" id="quote_default_comments" rows="10" required><?= $config['quote_default_comments']; ?></textarea>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="work_order_enable" name="work_order_enable" value="work_order_enable" <?= $config['work_order_enable'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="work_order_enable"><?= lang('Config.work_order_enable'); ?></label>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="work_order_format" class="form-label"><?= lang('Config.work_order_format'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-braces"></i></span>
<input type="text" class="form-control" name="work_order_format" id="work_order_format" value="<?= $config['work_order_format']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.last_used_invoice_number'), 'last_used_invoice_number', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'type' => 'number',
'name' => 'last_used_invoice_number',
'id' => 'last_used_invoice_number',
'class' => 'form-control input-sm required',
'value' => $config['last_used_invoice_number']
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="last_used_work_order_number" class="form-label"><?= lang('Config.last_used_work_order_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-123"></i></span>
<input type="number" class="form-control" name="last_used_work_order_number" id="last_used_work_order_number" value="<?= $config['last_used_work_order_number']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.sales_quote_format'), 'sales_quote_format', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'sales_quote_format',
'id' => 'sales_quote_format',
'class' => 'form-control input-sm',
'value' => $config['sales_quote_format']
]) ?>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_invoice"><?= lang('Common.submit'); ?></button>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.last_used_quote_number'), 'last_used_quote_number', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'type' => 'number',
'name' => 'last_used_quote_number',
'id' => 'last_used_quote_number',
'class' => 'form-control input-sm required',
'value' => $config['last_used_quote_number']
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.quote_default_comments'), 'quote_default_comments', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-5">
<?= form_textarea([
'name' => 'quote_default_comments',
'id' => 'quote_default_comments',
'class' => 'form-control input-sm',
'value' => $config['quote_default_comments']
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.work_order_enable'), 'work_order_enable', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'work_order_enable',
'value' => 'work_order_enable',
'id' => 'work_order_enable',
'checked' => $config['work_order_enable'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.work_order_format'), 'work_order_format', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'work_order_format',
'id' => 'work_order_format',
'class' => 'form-control input-sm',
'value' => $config['work_order_format']
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.last_used_work_order_number'), 'last_used_work_order_number', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'type' => 'number',
'name' => 'last_used_work_order_number',
'id' => 'last_used_work_order_number',
'class' => 'form-control input-sm required',
'value' => $config['last_used_work_order_number']
]) ?>
</div>
</div>
<?= form_submit([
'name' => 'submit_invoice',
'id' => 'submit_invoice',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -167,7 +225,7 @@
$("#invoice_config_form").validate($.extend(form_support.handler, {
errorLabelContainer: ".invoice_error_message_box",
errorLabelContainer: "#invoice_error_message_box",
submitHandler: function(form) {
$(form).ajaxSubmit({
@@ -177,7 +235,6 @@
},
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'

View File

@@ -4,25 +4,29 @@
*/
?>
<?= form_open('', ['id' => 'license_config_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('', ['id' => 'license_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset>
<?php
$title_info['config_title'] = lang('Config.license_configuration');
echo view('configs/config_header', $title_info);
?>
<?php
$license_i = 0;
foreach ($licenses as $license) {
?>
<div class="mb-3 mx-3 mx-lg-0">
<label for="license_<?= $license_i; ?>" class="form-label"><?= $license['title']; ?></label>
<textarea name="license" rows="10" id="license_<?= $license_i; ?>" class="form-control font-monospace" style="font-size: .875rem;" readonly><?= $license['text']; ?></textarea>
</div>
<?php
$license_i++; // Increment counter
} ?>
<?php
$counter = 0;
foreach ($licenses as $license) {
?>
<div class="form-group form-group-sm">
<?= form_label($license['title'], 'license', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-6">
<?= form_textarea([
'name' => 'license',
'id' => 'license_' . $counter++, // TODO: String Interpolation
'class' => 'form-control font-monospace',
'rows' => '14',
'readonly' => '',
'value' => $license['text']
]) ?>
</div>
</div>
<?php } ?>
</fieldset>
</div>
<?= form_close() ?>

View File

@@ -5,245 +5,285 @@
* @var string $controller_name
* @var array $config
*/
$beta = '<sup><span class="badge bg-secondary">BETA</span></sup>';
?>
<?= form_open('config/saveLocale/', ['id' => 'locale_config_form']) ?>
<?= form_open('config/saveLocale/', ['id' => 'locale_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.locale_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="locale_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="locale_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-sm-6 col-xxl-3">
<label for="number_locale" class="form-label"><?= lang('Config.number_locale') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-globe-americas"></i></span>
<input type="text" class="form-control" name="number_locale" id="number_locale" value="<?= $config['number_locale'] ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.number_locale'), 'number_locale', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_input([
'name' => 'number_locale',
'id' => 'number_locale',
'class' => 'form-control input-sm',
'value' => $config['number_locale']
]) ?>
<?= form_hidden(['name' => 'save_number_locale', 'value' => $config['number_locale']]) ?>
</div>
<div class="col-xs-2">
<label class="control-label">
<a href="https://github.com/opensourcepos/opensourcepos/wiki/Localisation-support" target="_blank">
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.number_locale_tooltip') ?>"></span>
</a>
<span id="number_locale_example">
&nbsp;&nbsp;<?= to_currency(1234567890.12300) ?>
</span>
</label>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-xxl-3">
<label for="number_locale_example" class="form-label">Localization Example</label>
<div class="mb-3" id="number_locale_example">
<?= to_currency(1234567890.12300) ?>&nbsp;
<a href="https://github.com/opensourcepos/opensourcepos/wiki/Localisation-support" target="_blank" rel="noopener">
<i class="bi bi-link-45deg link-secondary" data-bs-toggle="tooltip" title="<?= lang('Config.number_locale_tooltip'); ?>"></i>
</a>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.thousands_separator'), 'thousands_separator', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_checkbox([
'name' => 'thousands_separator',
'id' => 'thousands_separator',
'value' => 'thousands_separator',
'checked' => $config['thousands_separator'] == 1
]) ?>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.currency_symbol'), 'currency_symbol', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_input([
'name' => 'currency_symbol',
'id' => 'currency_symbol',
'class' => 'form-control input-sm number_locale',
'value' => $config['currency_symbol']
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.currency_code'), 'currency_code', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_input([
'name' => 'currency_code',
'id' => 'currency_code',
'class' => 'form-control input-sm number_locale',
'value' => $currency_code
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.currency_decimals'), 'currency_decimals', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'currency_decimals',
[
'0' => '0',
'1' => '1',
'2' => '2'
],
$config['currency_decimals'],
['class' => 'form-control input-sm']
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.tax_decimals'), 'tax_decimals', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'tax_decimals',
[
'0' => '0',
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4'
],
$config['tax_decimals'],
['class' => 'form-control input-sm']
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.quantity_decimals'), 'quantity_decimals', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'quantity_decimals',
[
'0' => '0',
'1' => '1',
'2' => '2',
'3' => '3'
],
$config['quantity_decimals'],
['class' => 'form-control input-sm']
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.cash_decimals'), 'cash_decimals', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'cash_decimals',
[
'-1' => '-1',
'0' => '0',
'1' => '1',
'2' => '2'
],
$config['cash_decimals'],
['class' => 'form-control input-sm']
) ?>
</div>
<div class="col-xs-1">
<label class="control-label">
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.cash_decimals_tooltip') ?>"></span>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.cash_rounding'), 'cash_rounding_code', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'cash_rounding_code',
$rounding_options,
$config['cash_rounding_code'],
'class="form-control input-sm"'
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.payment_options_order'), 'payment_options_order', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<?= form_dropdown(
'payment_options_order',
[
'cashdebitcredit' => lang('Sales.cash') . ' / ' . lang('Sales.debit') . ' / ' . lang('Sales.credit'),
'debitcreditcash' => lang('Sales.debit') . ' / ' . lang('Sales.credit') . ' / ' . lang('Sales.cash'),
'debitcashcredit' => lang('Sales.debit') . ' / ' . lang('Sales.cash') . ' / ' . lang('Sales.credit'),
'creditdebitcash' => lang('Sales.credit') . ' / ' . lang('Sales.debit') . ' / ' . lang('Sales.cash'),
'creditcashdebit' => lang('Sales.credit') . ' / ' . lang('Sales.cash') . ' / ' . lang('Sales.debit')
],
$config['payment_options_order'],
'class="form-control input-sm"'
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.country_codes'), 'country_codes', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_input([
'name' => 'country_codes',
'class' => 'form-control input-sm',
'value' => $config['country_codes']
]) ?>
</div>
<div class="col-xs-1">
<label class="control-label">
<a href="https://wiki.openstreetmap.org/wiki/Nominatim/Country_Codes" target="_blank">
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.country_codes_tooltip'); ?>"></span>
</a>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.language'), 'language', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<?= form_dropdown(
'language',
get_languages(),
current_language_code(true) . ':' . current_language(true),
['class' => 'form-control input-sm']
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.timezone'), 'timezone', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<?= form_dropdown(
'timezone',
get_timezones(),
$config['timezone'] ? $config['timezone'] : date_default_timezone_get(),
['class' => 'form-control input-sm']
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.datetimeformat'), 'datetimeformat', ['class' => 'control-label col-xs-2']) ?>
<div class="col-sm-2">
<?= form_dropdown(
'dateformat',
get_dateformats(),
$config['dateformat'],
['class' => 'form-control input-sm']
) ?>
</div>
<div class="col-sm-2">
<?= form_dropdown(
'timeformat',
get_timeformats(),
$config['timeformat'],
['class' => 'form-control input-sm']
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.date_or_time_format'), 'date_or_time_format', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_checkbox([
'name' => 'date_or_time_format',
'id' => 'date_or_time_format',
'value' => 'date_or_time_format',
'checked' => $config['date_or_time_format'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.financial_year'), 'financial_year', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'financial_year',
[
'1' => lang('Config.financial_year_jan'),
'2' => lang('Config.financial_year_feb'),
'3' => lang('Config.financial_year_mar'),
'4' => lang('Config.financial_year_apr'),
'5' => lang('Config.financial_year_may'),
'6' => lang('Config.financial_year_jun'),
'7' => lang('Config.financial_year_jul'),
'8' => lang('Config.financial_year_aug'),
'9' => lang('Config.financial_year_sep'),
'10' => lang('Config.financial_year_oct'),
'11' => lang('Config.financial_year_nov'),
'12' => lang('Config.financial_year_dec')
],
$config['financial_year'],
['class' => 'form-control input-sm']
) ?>
</div>
</div>
<?= form_submit([
'name' => 'submit_locale',
'id' => 'submit_locale',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="thousands_separator" name="thousands_separator" value="thousands_separator" <?= $config['thousands_separator'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="thousands_separator"><?= lang('Config.thousands_separator'); ?></label>
</div>
<div class="row">
<div class="col-12 col-sm-6 col-xxl-3">
<label for="currency_symbol" class="form-label"><?= lang('Config.currency_symbol') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-currency-exchange"></i></span>
<input type="text" class="form-control" name="currency_symbol" id="currency_symbol" value="<?= $config['currency_symbol'] ?>">
</div>
</div>
<div class="col-12 col-sm-6 col-xxl-3">
<label for="currency_code" class="form-label"><?= lang('Config.currency_code') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-cash"></i></span>
<input type="text" class="form-control" name="currency_code" id="currency_code" value="<?= $currency_code ?>">
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-sm-6 col-xxl-3">
<label for="currency_decimals" class="form-label"><?= lang('Config.currency_decimals') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-coin"></i></span>
<select class="form-select" name="currency_decimals" id="currency_decimals">
<option value="0" <?= $config['currency_decimals'] == '0' ? 'selected' : '' ?>>0</option>
<option value="1" <?= $config['currency_decimals'] == '1' ? 'selected' : '' ?>>1</option>
<option value="2" <?= $config['currency_decimals'] == '2' ? 'selected' : '' ?>>2</option>
</select>
</div>
</div>
<div class="col-12 col-sm-6 col-xxl-3">
<label for="tax_decimals" class="form-label"><?= lang('Config.tax_decimals') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-archive"></i></span>
<select class="form-select" name="tax_decimals" id="tax_decimals">
<option value="0" <?= $config['tax_decimals'] == '0' ? 'selected' : '' ?>>0</option>
<option value="1" <?= $config['tax_decimals'] == '1' ? 'selected' : '' ?>>1</option>
<option value="2" <?= $config['tax_decimals'] == '2' ? 'selected' : '' ?>>2</option>
<option value="3" <?= $config['tax_decimals'] == '3' ? 'selected' : '' ?>>3</option>
<option value="4" <?= $config['tax_decimals'] == '4' ? 'selected' : '' ?>>4</option>
</select>
</div>
</div>
<div class="col-12 col-sm-6 col-xxl-3">
<label for="quantity_decimals" class="form-label"><?= lang('Config.quantity_decimals') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-123"></i></span>
<select class="form-select" name="quantity_decimals" id="quantity_decimals">
<option value="0" <?= $config['quantity_decimals'] == '0' ? 'selected' : '' ?>>0</option>
<option value="1" <?= $config['quantity_decimals'] == '1' ? 'selected' : '' ?>>1</option>
<option value="2" <?= $config['quantity_decimals'] == '2' ? 'selected' : '' ?>>2</option>
<option value="3" <?= $config['quantity_decimals'] == '3' ? 'selected' : '' ?>>3</option>
</select>
</div>
</div>
<div class="col-12 col-sm-6 col-xxl-3">
<label for="cash_decimals" class="form-label"><?= lang('Config.cash_decimals') ?>
<i class="bi bi-info-circle-fill text-secondary" data-bs-toggle="tooltip" title="<?= lang('Config.cash_decimals_tooltip'); ?>"></i>
</label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-cash-coin"></i></span>
<select class="form-select" name="cash_decimals" id="cash_decimals">
<option value="0" <?= $config['cash_decimals'] == '0' ? 'selected' : '' ?>>0</option>
<option value="1" <?= $config['cash_decimals'] == '1' ? 'selected' : '' ?>>1</option>
<option value="2" <?= $config['cash_decimals'] == '2' ? 'selected' : '' ?>>2</option>
</select>
</div>
</div>
<div class="col-12 col-sm-6 col-xxl-3">
<label for="cash_rounding_code" class="form-label"><?= lang('Config.cash_rounding') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrow-repeat"></i></span>
<select class="form-select" name="cash_rounding_code" id="cash_rounding_code">
<?php foreach ($rounding_options as $code => $label): ?>
<option value="<?= $code ?>" <?= $config['cash_rounding_code'] == $code ? 'selected' : '' ?>><?= $label ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="payment_options_order" class="form-label"><?= lang('Config.payment_options_order') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-credit-card"></i></span>
<select class="form-select" name="payment_options_order" id="payment_options_order">
<option value="cashdebitcredit" <?= $config['payment_options_order'] == 'cashdebitcredit' ? 'selected' : '' ?>><?= lang('Sales.cash') ?> / <?= lang('Sales.debit') ?> / <?= lang('Sales.credit') ?></option>
<option value="debitcreditcash" <?= $config['payment_options_order'] == 'debitcreditcash' ? 'selected' : '' ?>><?= lang('Sales.debit') ?> / <?= lang('Sales.credit') ?> / <?= lang('Sales.cash') ?></option>
<option value="debitcashcredit" <?= $config['payment_options_order'] == 'debitcashcredit' ? 'selected' : '' ?>><?= lang('Sales.debit') ?> / <?= lang('Sales.cash') ?> / <?= lang('Sales.credit') ?></option>
<option value="creditdebitcash" <?= $config['payment_options_order'] == 'creditdebitcash' ? 'selected' : '' ?>><?= lang('Sales.credit') ?> / <?= lang('Sales.debit') ?> / <?= lang('Sales.cash') ?></option>
<option value="creditcashdebit" <?= $config['payment_options_order'] == 'creditcashdebit' ? 'selected' : '' ?>><?= lang('Sales.credit') ?> / <?= lang('Sales.cash') ?> / <?= lang('Sales.debit') ?></option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="country_codes" class="form-label">
<?= lang('Config.country_codes') ?>
<a href="https://wiki.openstreetmap.org/wiki/Nominatim/Country_Codes" target="_blank" rel="noopener">
<i class="bi bi-link-45deg text-secondary" data-bs-toggle="tooltip" title="<?= lang('Config.country_codes_tooltip'); ?>"></i>
</a>
</label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-code"></i></span>
<input type="text" class="form-control" name="country_codes" id="country_codes" value="<?= $config['country_codes'] ?>">
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="language" class="form-label"><?= lang('Config.language') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-translate"></i></span>
<select class="form-select" name="language" id="language">
<?php foreach (get_languages() as $value => $label): ?>
<option value="<?= esc($value) ?>" <?= $value === current_language_code(true) . ':' . current_language(true) ? 'selected' : '' ?>><?= esc($label) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="rtl_language" name="rtl_language" value="rtl_language" <?= $config['rtl_language'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="rtl_language">RTL Language <?= $beta; ?></label>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="timezone" class="form-label"><?= lang('Config.timezone') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-clock"></i></span>
<?= form_dropdown(
'timezone',
get_timezones(),
$config['timezone'] ? $config['timezone'] : date_default_timezone_get(),
['class' => 'form-select']
) ?>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="datetimeformat" class="form-label"><?= lang('Config.datetimeformat') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-calendar2"></i></span>
<?= form_dropdown(
'dateformat',
get_dateformats(),
$config['dateformat'],
['class' => 'form-select']
) ?>
<?= form_dropdown(
'timeformat',
get_timeformats(),
$config['timeformat'],
['class' => 'form-select']
) ?>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="date_or_time_format" name="date_or_time_format" value="date_or_time_format" <?= $config['date_or_time_format'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="date_or_time_format"><?= lang('Config.date_or_time_format'); ?></label>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="financial_year" class="form-label"><?= lang('Config.financial_year') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-calendar2-month"></i></span>
<select class="form-select" name="financial_year" id="financial_year">
<option value="1" <?= ($config['financial_year'] == '1' ? 'selected' : ''); ?>><?= lang('Config.financial_year_jan'); ?></option>
<option value="2" <?= ($config['financial_year'] == '2' ? 'selected' : ''); ?>><?= lang('Config.financial_year_feb'); ?></option>
<option value="3" <?= ($config['financial_year'] == '3' ? 'selected' : ''); ?>><?= lang('Config.financial_year_mar'); ?></option>
<option value="4" <?= ($config['financial_year'] == '4' ? 'selected' : ''); ?>><?= lang('Config.financial_year_apr'); ?></option>
<option value="5" <?= ($config['financial_year'] == '5' ? 'selected' : ''); ?>><?= lang('Config.financial_year_may'); ?></option>
<option value="6" <?= ($config['financial_year'] == '6' ? 'selected' : ''); ?>><?= lang('Config.financial_year_jun'); ?></option>
<option value="7" <?= ($config['financial_year'] == '7' ? 'selected' : ''); ?>><?= lang('Config.financial_year_jul'); ?></option>
<option value="8" <?= ($config['financial_year'] == '8' ? 'selected' : ''); ?>><?= lang('Config.financial_year_aug'); ?></option>
<option value="9" <?= ($config['financial_year'] == '9' ? 'selected' : ''); ?>><?= lang('Config.financial_year_sep'); ?></option>
<option value="10" <?= ($config['financial_year'] == '10' ? 'selected' : ''); ?>><?= lang('Config.financial_year_oct'); ?></option>
<option value="11" <?= ($config['financial_year'] == '11' ? 'selected' : ''); ?>><?= lang('Config.financial_year_nov'); ?></option>
<option value="12" <?= ($config['financial_year'] == '12' ? 'selected' : ''); ?>><?= lang('Config.financial_year_dec'); ?></option>
</select>
</div>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_locale"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -314,7 +354,7 @@
}
},
errorLabelContainer: '.locale_error_message_box'
errorLabelContainer: '#locale_error_message_box'
}));
});
</script>

View File

@@ -1,66 +1,85 @@
<?php
$tabs = [
['id' => 'info', 'icon' => 'bi-shop', 'label' => lang('Config.info'), 'title' => lang('Config.info_configuration')],
['id' => 'general', 'icon' => 'bi-sliders', 'label' => lang('Config.general'), 'title' => lang('Config.general_configuration')],
['id' => 'appearance', 'icon' => 'bi-eye', 'label' => 'Appearance', 'title' => 'Appearance Configuration'],
['id' => 'locale', 'icon' => 'bi-translate', 'label' => lang('Config.locale'), 'title' => lang('Config.locale_configuration')],
['id' => 'tax', 'icon' => 'bi-piggy-bank', 'label' => lang('Config.tax'), 'title' => lang('Config.tax_configuration')],
['id' => 'barcode', 'icon' => 'bi-upc-scan', 'label' => lang('Config.barcode'), 'title' => lang('Config.barcode_configuration')],
['id' => 'stock', 'icon' => 'bi-truck', 'label' => lang('Config.location'), 'title' => lang('Config.location_configuration')],
['id' => 'receipt', 'icon' => 'bi-receipt', 'label' => lang('Config.receipt'), 'title' => lang('Config.receipt_configuration')],
['id' => 'invoice', 'icon' => 'bi-file-text', 'label' => lang('Config.invoice'), 'title' => lang('Config.invoice_configuration')],
['id' => 'shortcuts', 'icon' => 'bi-shift', 'label' => lang('Config.shortcuts'), 'title' => lang('Config.shortcuts_configuration')],
['id' => 'reward', 'icon' => 'bi-trophy', 'label' => lang('Config.reward'), 'title' => lang('Config.reward_configuration')],
['id' => 'table', 'icon' => 'bi-cup-straw', 'label' => lang('Config.table'), 'title' => lang('Config.table_configuration')],
['id' => 'email', 'icon' => 'bi-envelope', 'label' => lang('Config.email'), 'title' => lang('Config.email_configuration')],
['id' => 'message', 'icon' => 'bi-chat', 'label' => lang('Config.message'), 'title' => lang('Config.message_configuration')],
['id' => 'integrations', 'icon' => 'bi-gear-wide-connected', 'label' => lang('Config.integrations'), 'title' => lang('Config.integrations_configuration')],
['id' => 'system', 'icon' => 'bi-info-circle', 'label' => lang('Config.system_info'), 'title' => lang('Config.system_info'), 'view' => 'configs/system_info'],
['id' => 'license', 'icon' => 'bi-journal-check', 'label' => lang('Config.license'), 'title' => lang('Config.license_configuration')],
];
?>
<?= view('partial/header') ?>
<script type="text/javascript" src="resources/clipboard/clipboard.min.js"></script>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<div class="row">
<div class="col-lg-3 <?= $config['config_menu_position'] == 'start' ? '' : 'order-lg-2' ?>">
<div class="list-group d-none d-lg-block" role="tablist">
<?php foreach ($tabs as $i => $tab): ?>
<button type="button" class="list-group-item list-group-item-action text-truncate <?= $i === 0 ? 'active' : '' ?>" id="<?= $tab['id'] ?>-tab" data-bs-toggle="tab" data-bs-target="#<?= $tab['id'] ?>" role="tab" title="<?= $tab['title'] ?>">
<i class="bi <?= $tab['icon'] ?> me-2"></i><?= $tab['label'] ?>
</button>
<?php endforeach ?>
</div>
<ul class="nav nav-tabs" data-tabs="tabs">
<li class="active" role="presentation">
<a data-toggle="tab" href="#info_tab" title="<?= lang('Config.info_configuration') ?>"><?= lang('Config.info') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#general_tab" title="<?= lang('Config.general_configuration') ?>"><?= lang('Config.general') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#tax_tab" title="<?= lang('Config.tax_configuration') ?>"><?= lang('Config.tax') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#locale_tab" title="<?= lang('Config.locale_configuration') ?>"><?= lang('Config.locale') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#barcode_tab" title="<?= lang('Config.barcode_configuration') ?>"><?= lang('Config.barcode') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#stock_tab" title="<?= lang('Config.location_configuration') ?>"><?= lang('Config.location') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#receipt_tab" title="<?= lang('Config.receipt_configuration') ?>"><?= lang('Config.receipt') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#invoice_tab" title="<?= lang('Config.invoice_configuration') ?>"><?= lang('Config.invoice') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#shortcuts_tab" title="<?= lang('Config.shortcuts_configuration') ?>"><?= lang('Config.shortcuts') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#reward_tab" title="<?= lang('Config.reward_configuration') ?>"><?= lang('Config.reward') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#table_tab" title="<?= lang('Config.table_configuration') ?>"><?= lang('Config.table') ?></a>
</li>
<li role="presentation">
<a data-toggle="tab" href="#system_tab" title="<?= lang('Config.system_conf') ?>"><?= lang('Config.system_conf') ?></a>
</li>
</ul>
<div class="nav dropdown d-lg-none mb-3">
<button type="button" class="btn btn-primary w-100 dropdown-toggle text-truncate" id="configs-dropdown" data-bs-toggle="dropdown" aria-expanded="false">
<?= lang('Config.info') ?>
</button>
<ul class="dropdown-menu w-100" aria-labelledby="configs-dropdown">
<?php foreach ($tabs as $i => $tab): ?>
<li>
<a class="dropdown-item py-2 text-truncate <?= $i === 0 ? 'active' : '' ?>" data-bs-toggle="tab" data-bs-target="#<?= $tab['id'] ?>" role="tab" title="<?= $tab['title'] ?>">
<i class="bi <?= $tab['icon'] ?> me-2"></i><?= $tab['label'] ?>
</a>
</li>
<?php endforeach ?>
</ul>
</div>
<div class="tab-content">
<div class="tab-pane fade in active" id="info_tab">
<?= view('configs/info_config') ?>
</div>
<div class="col-lg-9 order-lg-1">
<div class="tab-content">
<?php foreach ($tabs as $i => $tab): ?>
<div class="tab-pane <?= $i === 0 ? 'active' : '' ?>" id="<?= $tab['id'] ?>" role="tabpanel" aria-labelledby="<?= $tab['id'] ?>-tab">
<?= view($tab['view'] ?? 'configs/' . $tab['id'] . '_config') ?>
</div>
<?php endforeach ?>
</div>
<div class="tab-pane" id="general_tab">
<?= view('configs/general_config') ?>
</div>
<div class="tab-pane" id="tax_tab">
<?= view('configs/tax_config') ?>
</div>
<div class="tab-pane" id="locale_tab">
<?= view('configs/locale_config') ?>
</div>
<div class="tab-pane" id="barcode_tab">
<?= view('configs/barcode_config') ?>
</div>
<div class="tab-pane" id="stock_tab">
<?= view('configs/stock_config') ?>
</div>
<div class="tab-pane" id="receipt_tab">
<?= view('configs/receipt_config') ?>
</div>
<div class="tab-pane" id="invoice_tab">
<?= view('configs/invoice_config') ?>
</div>
<div class="tab-pane" id="shortcuts_tab">
<?= view('configs/shortcuts_config') ?>
</div>
<div class="tab-pane" id="reward_tab">
<?= view('configs/reward_config') ?>
</div>
<div class="tab-pane" id="table_tab">
<?= view('configs/table_config') ?>
</div>
<div class="tab-pane" id="system_tab">
<?= view('configs/system_config') ?>
</div>
</div>
<script type="text/javascript" src="js/bs-tab_anchor_linking.js"></script>
<script type="text/javascript" src="js/bs-validation.js"></script>
<?= view('partial/footer') ?>

View File

@@ -4,51 +4,86 @@
*/
?>
<?= form_open('config/saveMessage/', ['id' => 'message_config_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('config/saveMessage/', ['id' => 'message_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.message_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="message_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="message_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-lg-6 mb-3">
<label for="msg_uid" class="form-label"><?= lang('Config.msg_uid'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group">
<span class="input-group-text" id="msg_uid-icon"><i class="bi bi-person"></i></span>
<input type="text" class="form-control" name="msg_uid" id="msg_uid" aria-describedby="msg_uid-icon" required value="<?= $config['msg_uid']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.msg_uid'), 'msg_uid', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-user"></span>
</span>
<?= form_input([
'name' => 'msg_uid',
'id' => 'msg_uid',
'class' => 'form-control input-sm required',
'value' => $config['msg_uid']
]) ?>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 mb-3">
<label for="msg_pwd" class="form-label"><?= lang('Config.msg_pwd'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group">
<span class="input-group-text" id="msg_pwd-icon"><i class="bi bi-lock"></i></span>
<input type="password" class="form-control" name="msg_pwd" id="msg_pwd" aria-describedby="msg_pwd-icon" required value="<?= $config['msg_pwd']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.msg_pwd'), 'msg_pwd', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-lock"></span>
</span>
<?= form_password([
'name' => 'msg_pwd',
'id' => 'msg_pwd',
'class' => 'form-control input-sm required',
'value' => $config['msg_pwd']
]) ?>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 mb-3">
<label for="msg_src" class="form-label"><?= lang('Config.msg_src'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group">
<span class="input-group-text" id="msg_src-icon"><i class="bi bi-megaphone"></i></span>
<input type="text" class="form-control" name="msg_src" id="msg_src" aria-describedby="msg_src-icon" required value="<?= $config['msg_src'] == null ? $config['company'] : $config['msg_src']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.msg_src'), 'msg_src', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-4">
<div class="input-group">
<span class="input-group-addon input-sm">
<span class="glyphicon glyphicon-bullhorn"></span>
</span>
<?= form_input([
'name' => 'msg_src',
'id' => 'msg_src',
'class' => 'form-control input-sm required',
'value' => $config['msg_src'] == null ? $config['company'] : $config['msg_src']
]) ?>
</div>
</div>
</div>
</div>
</div>
<label for="msg_msg" class="form-label"><?= lang('Config.msg_msg'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-chat-quote"></i></span>
<textarea class="form-control" name="msg_msg" id="msg_msg" rows="10" placeholder="<?= lang('Config.msg_msg_placeholder'); ?>"><?= esc($config['msg_msg']); ?></textarea>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.msg_msg'), 'msg_msg', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-4">
<?= form_textarea([
'name' => 'msg_msg',
'id' => 'msg_msg',
'class' => 'form-control input-sm',
'value' => $config['msg_msg'],
'placeholder' => lang('Config.msg_msg_placeholder')
]) ?>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_message"><?= lang('Common.submit'); ?></button>
</div>
<?= form_submit([
'name' => 'submit_message',
'id' => 'submit_message',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -56,7 +91,7 @@
$(document).ready(function() {
$('#message_config_form').validate($.extend(form_support.handler, {
errorLabelContainer: ".message_error_message_box",
errorLabelContainer: "#message_error_message_box",
rules: {
msg_uid: "required",

View File

@@ -4,199 +4,334 @@
*/
?>
<?= form_open('config/saveReceipt/', ['id' => 'receipt_config_form']) ?>
<?= form_open('config/saveReceipt/', ['id' => 'receipt_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.receipt_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="receipt_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="receipt_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-lg-6">
<label for="receipt_template" class="form-label"><?= lang('Config.receipt_template'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-file-code"></i></span>
<select class="form-select" name="receipt_template">
<option value="receipt_default" <?= $config['receipt_template'] == 'receipt_default' ? 'selected' : '' ?>><?= lang('Config.receipt_default') ?></option>
<option value="receipt_short" <?= $config['receipt_template'] == 'receipt_short' ? 'selected' : '' ?>><?= lang('Config.receipt_short') ?></option>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_template'), 'receipt_template', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'receipt_template',
[
'receipt_default' => lang('Config.receipt_default'),
'receipt_short' => lang('Config.receipt_short')
],
$config['receipt_template'],
'class="form-control input-sm"'
) ?>
</div>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="receipt_font_size" class="form-label"><?= lang('Config.receipt_font_size'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrows-angle-expand"></i></span>
<input type="number" class="form-control" name="receipt_font_size" id="receipt_font_size" value="<?= $config['receipt_font_size']; ?>">
<span class="input-group-text">px</span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_font_size'), 'receipt_font_size', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<div class="input-group">
<?= form_input([
'type' => 'number',
'min' => '0',
'max' => '20',
'name' => 'receipt_font_size',
'id' => 'receipt_font_size',
'class' => 'form-control input-sm required',
'value' => $config['receipt_font_size']
]) ?>
<span class="input-group-addon input-sm">px</span>
</div>
</div>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="print_delay_autoreturn" class="form-label"><?= lang('Config.print_delay_autoreturn'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-stopwatch"></i></span>
<input type="number" class="form-control" name="print_delay_autoreturn" id="print_delay_autoreturn" value="<?= $config['print_delay_autoreturn']; ?>">
<span class="input-group-text">s</span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_delay_autoreturn'), 'print_delay_autoreturn', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<div class="input-group">
<?= form_input([
'type' => 'number',
'min' => '0',
'max' => '30',
'name' => 'print_delay_autoreturn',
'id' => 'print_delay_autoreturn',
'class' => 'form-control input-sm required',
'value' => $config['print_delay_autoreturn']
]) ?>
<span class="input-group-addon input-sm">s</span>
</div>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.email_receipt_check_behaviour'), 'email_receipt_check_behaviour', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'email_receipt_check_behaviour',
'value' => 'always',
'checked' => $config['email_receipt_check_behaviour'] == 'always'
]) ?>
<?= lang('Config.email_receipt_check_behaviour_always') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'email_receipt_check_behaviour',
'value' => 'never',
'checked' => $config['email_receipt_check_behaviour'] == 'never'
]) ?>
<?= lang('Config.email_receipt_check_behaviour_never') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'email_receipt_check_behaviour',
'value' => 'last',
'checked' => $config['email_receipt_check_behaviour'] == 'last'
]) ?>
<?= lang('Config.email_receipt_check_behaviour_last') ?>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_receipt_check_behaviour'), 'print_receipt_check_behaviour', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'print_receipt_check_behaviour',
'value' => 'always',
'checked' => $config['print_receipt_check_behaviour'] == 'always'
]) ?>
<?= lang('Config.print_receipt_check_behaviour_always') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'print_receipt_check_behaviour',
'value' => 'never',
'checked' => $config['print_receipt_check_behaviour'] == 'never'
]) ?>
<?= lang('Config.print_receipt_check_behaviour_never') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'print_receipt_check_behaviour',
'value' => 'last',
'checked' => $config['print_receipt_check_behaviour'] == 'last'
]) ?>
<?= lang('Config.print_receipt_check_behaviour_last') ?>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_show_company_name'), 'receipt_show_company_name', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'receipt_show_company_name',
'value' => 'receipt_show_company_name',
'id' => 'receipt_show_company_name',
'checked' => $config['receipt_show_company_name'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_show_taxes'), 'receipt_show_taxes', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'receipt_show_taxes',
'value' => 'receipt_show_taxes',
'id' => 'receipt_show_taxes',
'checked' => $config['receipt_show_taxes'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_show_tax_ind'), 'receipt_show_tax_ind', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'receipt_show_tax_ind',
'value' => 'receipt_show_tax_ind',
'id' => 'receipt_show_tax_ind',
'checked' => $config['receipt_show_tax_ind'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_show_total_discount'), 'receipt_show_total_discount', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'receipt_show_total_discount',
'value' => 'receipt_show_total_discount',
'id' => 'receipt_show_total_discount',
'checked' => $config['receipt_show_total_discount'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_show_description'), 'receipt_show_description', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'receipt_show_description',
'value' => 'receipt_show_description',
'id' => 'receipt_show_description',
'checked' => $config['receipt_show_description'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_show_serialnumber'), 'receipt_show_serialnumber', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'receipt_show_serialnumber',
'value' => 'receipt_show_serialnumber',
'id' => 'receipt_show_serialnumber',
'checked' => $config['receipt_show_serialnumber'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_silently'), 'print_silently', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'print_silently',
'id' => 'print_silently',
'value' => 'print_silently',
'checked' => $config['print_silently'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_header'), 'print_header', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'print_header',
'id' => 'print_header',
'value' => 'print_header',
'checked' => $config['print_header'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_footer'), 'print_footer', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'print_footer',
'id' => 'print_footer',
'value' => 'print_footer',
'checked' => $config['print_footer'] == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.receipt_printer'), 'config_receipt_printer', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown('receipt_printer', [], ' ', 'id="receipt_printer" class="form-control"') ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.invoice_printer'), 'config_invoice_printer', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown('invoice_printer', [], ' ', 'id="invoice_printer" class="form-control"') ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.takings_printer'), 'config_takings_printer', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown('takings_printer', [], ' ', 'id="takings_printer" class="form-control"') ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_top_margin'), 'print_top_margin', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<div class="input-group">
<?= form_input([
'type' => 'number',
'min' => '0',
'max' => '20',
'name' => 'print_top_margin',
'id' => 'print_top_margin',
'class' => 'form-control input-sm required',
'value' => $config['print_top_margin']
]) ?>
<span class="input-group-addon input-sm">px</span>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_left_margin'), 'print_left_margin', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<div class="input-group">
<?= form_input([
'type' => 'number',
'min' => '0',
'max' => '20',
'name' => 'print_left_margin',
'id' => 'print_left_margin',
'class' => 'form-control input-sm required',
'value' => $config['print_left_margin']
]) ?>
<span class="input-group-addon input-sm">px</span>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_bottom_margin'), 'print_bottom_margin', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<div class="input-group">
<?= form_input([
'type' => 'number',
'min' => '0',
'max' => '20',
'name' => 'print_bottom_margin',
'id' => 'print_bottom_margin',
'class' => 'form-control input-sm required',
'value' => $config['print_bottom_margin']
]) ?>
<span class="input-group-addon input-sm">px</span>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.print_right_margin'), 'print_right_margin', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-2">
<div class="input-group">
<?= form_input([
'type' => 'number',
'min' => '0',
'max' => '20',
'name' => 'print_right_margin',
'id' => 'print_right_margin',
'class' => 'form-control input-sm required',
'value' => $config['print_right_margin']
]) ?>
<span class="input-group-addon input-sm">px</span>
</div>
</div>
</div>
<?= form_submit([
'name' => 'submit_receipt',
'id' => 'submit_receipt',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<label for="email_receipt_check_behaviour" class="form-label"><?= lang('Config.email_receipt_check_behaviour'); ?></label>
<div class="row mb-3">
<div class="col-12">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="email_receipt_check_behaviour" id="email_receipt_check_behaviour_always" value="always" <?= $config['email_receipt_check_behaviour'] == 'always' ? 'checked' : '' ?>>
<label class="form-check-label" for="email_receipt_check_behaviour_always"><?= lang('Config.email_receipt_check_behaviour_always') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="email_receipt_check_behaviour" id="email_receipt_check_behaviour_never" value="never" <?= $config['email_receipt_check_behaviour'] == 'never' ? 'checked' : '' ?>>
<label class="form-check-label" for="email_receipt_check_behaviour_never"><?= lang('Config.email_receipt_check_behaviour_never') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="email_receipt_check_behaviour" id="email_receipt_check_behaviour_last" value="last" <?= $config['email_receipt_check_behaviour'] == 'last' ? 'checked' : '' ?>>
<label class="form-check-label" for="email_receipt_check_behaviour_last"><?= lang('Config.email_receipt_check_behaviour_last') ?></label>
</div>
</div>
</div>
<label for="print_receipt_check_behaviour" class="form-label"><?= lang('Config.print_receipt_check_behaviour'); ?></label>
<div class="row mb-3">
<div class="col-12">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="print_receipt_check_behaviour" id="print_receipt_check_behaviour_always" value="always" <?= $config['print_receipt_check_behaviour'] == 'always' ? 'checked' : '' ?>>
<label class="form-check-label" for="print_receipt_check_behaviour_always"><?= lang('Config.print_receipt_check_behaviour_always') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="print_receipt_check_behaviour" id="print_receipt_check_behaviour_never" value="never" <?= $config['print_receipt_check_behaviour'] == 'never' ? 'checked' : '' ?>>
<label class="form-check-label" for="print_receipt_check_behaviour_never"><?= lang('Config.print_receipt_check_behaviour_never') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="print_receipt_check_behaviour" id="print_receipt_check_behaviour_last" value="last" <?= $config['print_receipt_check_behaviour'] == 'last' ? 'checked' : '' ?>>
<label class="form-check-label" for="print_receipt_check_behaviour_last"><?= lang('Config.print_receipt_check_behaviour_last') ?></label>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="receipt_show_company_name" name="receipt_show_company_name" value="receipt_show_company_name" <?= $config['receipt_show_company_name'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="receipt_show_company_name"><?= lang('Config.receipt_show_company_name'); ?></label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="receipt_show_taxes" name="receipt_show_taxes" value="receipt_show_taxes" <?= $config['receipt_show_taxes'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="receipt_show_taxes"><?= lang('Config.receipt_show_taxes'); ?></label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="receipt_show_tax_ind" name="receipt_show_tax_ind" value="receipt_show_tax_ind" <?= $config['receipt_show_tax_ind'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="receipt_show_tax_ind"><?= lang('Config.receipt_show_tax_ind'); ?></label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="receipt_show_total_discount" name="receipt_show_total_discount" value="receipt_show_total_discount" <?= $config['receipt_show_total_discount'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="receipt_show_total_discount"><?= lang('Config.receipt_show_total_discount'); ?></label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="receipt_show_description" name="receipt_show_description" value="receipt_show_description" <?= $config['receipt_show_description'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="receipt_show_description"><?= lang('Config.receipt_show_description'); ?></label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="receipt_show_serialnumber" name="receipt_show_serialnumber" value="receipt_show_serialnumber" <?= $config['receipt_show_serialnumber'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="receipt_show_serialnumber"><?= lang('Config.receipt_show_serialnumber'); ?></label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="print_silently" name="print_silently" value="print_silently" <?= $config['print_silently'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="print_silently"><?= lang('Config.print_silently'); ?></label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="print_header" name="print_header" value="print_header" <?= $config['print_header'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="print_header"><?= lang('Config.print_header'); ?></label>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="print_footer" name="print_footer" value="print_footer" <?= $config['print_footer'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="print_footer"><?= lang('Config.print_footer'); ?></label>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="receipt_printer" class="form-label"><?= lang('Config.receipt_printer'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-printer"></i></span>
<select class="form-select" name="receipt_printer" id="receipt_printer"></select>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="invoice_printer" class="form-label"><?= lang('Config.invoice_printer'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-printer"></i></span>
<select class="form-select" name="invoice_printer" id="invoice_printer"></select>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="takings_printer" class="form-label"><?= lang('Config.takings_printer'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-printer"></i></span>
<select class="form-select" name="takings_printer" id="takings_printer"></select>
</div>
</div>
</div>
<div class="row">
<div class="col-6 col-lg-3">
<label for="print_top_margin" class="form-label"><?= lang('Config.print_top_margin'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrow-bar-down"></i></span>
<input type="number" class="form-control" name="print_top_margin" id="print_top_margin" value="<?= $config['print_top_margin']; ?>">
<span class="input-group-text">px</span>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="print_left_margin" class="form-label"><?= lang('Config.print_left_margin'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrow-bar-right"></i></span>
<input type="number" class="form-control" name="print_left_margin" id="print_left_margin" value="<?= $config['print_left_margin']; ?>">
<span class="input-group-text">px</span>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="print_bottom_margin" class="form-label"><?= lang('Config.print_bottom_margin'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrow-bar-up"></i></span>
<input type="number" class="form-control" name="print_bottom_margin" id="print_bottom_margin" value="<?= $config['print_bottom_margin']; ?>">
<span class="input-group-text">px</span>
</div>
</div>
<div class="col-6 col-lg-3">
<label for="print_right_margin" class="form-label"><?= lang('Config.print_right_margin'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-arrow-bar-left"></i></span>
<input type="number" class="form-control" name="print_right_margin" id="print_right_margin" value="<?= $config['print_right_margin']; ?>">
<span class="input-group-text">px</span>
</div>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_receipt"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -235,7 +370,6 @@
},
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'
@@ -245,7 +379,7 @@
});
},
errorLabelContainer: ".receipt_error_message_box",
errorLabelContainer: "#receipt_error_message_box",
rules: {
print_top_margin: {

View File

@@ -5,28 +5,38 @@
*/
?>
<?= form_open('config/saveRewards/', ['id' => 'reward_config_form']) ?>
<?= form_open('config/saveRewards/', ['id' => 'reward_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.reward_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="reward_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="reward_error_message_box alert alert-warning d-none"></ul>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.customer_reward_enable'), 'customer_reward_enable', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'customer_reward_enable',
'value' => 'customer_reward_enable',
'id' => 'customer_reward_enable',
'checked' => $config['customer_reward_enable'] == 1
]) ?>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="customer_reward_enable" name="customer_reward_enable" value="customer_reward_enable" <?= $config['customer_reward_enable'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="customer_reward_enable"><?= lang('Config.customer_reward_enable'); ?></label>
<div id="customer_rewards">
<?= view('partial/customer_rewards', ['customer_rewards' => $customer_rewards]) ?>
</div>
<?= form_submit([
'name' => 'submit_reward',
'id' => 'submit_reward',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<div class="row" id="customer_rewards">
<?= view('partial/customer_rewards', ['customer_rewards' => $customer_rewards]) ?>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_reward"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -66,9 +76,9 @@
var new_block = block.insertAfter($(this).parent());
var new_block_id = 'customer_reward_' + ++id;
var new_block_id_next = 'reward_points_' + id;
$(new_block).find('label').html("<?= lang('Config.customer_reward') ?> " + ++table_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2'); // TODO-BS5 change classes from bs3 to bs5
$(new_block).find("input[id='" + previous_id + "']").attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val(''); // TODO-BS5 change classes from bs3 to bs5
$(new_block).find("input[id='" + previous_id_next + "']").attr('id', new_block_id_next).removeAttr('disabled').attr('name', new_block_id_next).attr('class', 'form-control input-sm').val(''); // TODO-BS5 change classes from bs3 to bs5
$(new_block).find('label').html("<?= lang('Config.customer_reward') ?> " + ++table_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
$(new_block).find("input[id='" + previous_id + "']").attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
$(new_block).find("input[id='" + previous_id_next + "']").attr('id', new_block_id_next).removeAttr('disabled').attr('name', new_block_id_next).attr('class', 'form-control input-sm').val('');
hide_show_remove();
};
@@ -109,7 +119,6 @@
},
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'
@@ -120,7 +129,7 @@
});
},
errorLabelContainer: ".reward_error_message_box",
errorLabelContainer: "#reward_error_message_box",
rules: {
<?php

View File

@@ -23,32 +23,41 @@ $shortcutLabels = [
];
?>
<?= form_open('config/saveShortcuts', ['id' => 'shortcuts_config_form']) ?>
<?= form_open('config/saveShortcuts', ['id' => 'shortcuts_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<div class="row">
<fieldset id="config_info">
<div class="col-md-8">
<div id="required_fields_message"><?= esc(lang('Common.fields_required_message')) ?></div>
<ul id="shortcuts_error_message_box" class="error_message_box"></ul>
<?php
$title_info['config_title'] = lang('Config.shortcuts_configuration');
echo view('configs/config_header', $title_info);
?>
<?php foreach ($shortcutLabels as $name => $label): ?>
<div class="form-group form-group-sm">
<?= form_label($label, 'key_' . $name, ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?php $keyboardShortcutSelectedValue = $keyboardShortcuts[$name]['value'] ?? ''; ?>
<?= form_dropdown(
'key_' . $name,
$keyboardShortcutOptions,
$keyboardShortcutSelectedValue,
'class="form-control input-sm"'
) ?>
</div>
</div>
<?php endforeach; ?>
<ul id="error_message_box" class="shortcuts_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<?php foreach ($shortcutLabels as $name => $label): ?>
<div class="col-12 col-lg-6">
<?= form_label($label, 'key_' . $name, ['class' => 'form-label']) ?>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-keyboard"></i></span>
<?php $keyboardShortcutSelectedValue = $keyboardShortcuts[$name]['value'] ?? ''; ?>
<?= form_dropdown('key_' . $name, $keyboardShortcutOptions, $keyboardShortcutSelectedValue, 'class="form-select"') ?>
<div class="col-xs-12 clearfix">
<?= form_submit([
'name' => 'submit_shortcuts',
'id' => 'submit_shortcuts',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</div>
</div>
</div>
<?php endforeach; ?>
</fieldset>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_shortcuts"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -74,6 +83,6 @@ $shortcutLabels = [
});
},
errorLabelContainer: '.shortcuts_error_message_box'
errorLabelContainer: '#shortcuts_error_message_box'
}));
</script>

View File

@@ -4,23 +4,26 @@
*/
?>
<?= form_open('config/saveLocations/', ['id' => 'location_config_form']) ?>
<?= form_open('config/saveLocations/', ['id' => 'location_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.location_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="stock_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="stock_error_message_box alert alert-warning d-none"></ul>
<div id="stock_locations">
<?= view('partial/stock_locations', ['stock_locations' => $stock_locations]) ?>
</div>
<div id="stock_locations">
<?= view('partial/stock_locations', ['stock_locations' => $stock_locations]) ?>
<?= form_submit([
'name' => 'submit_stock',
'id' => 'submit_stock',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_stock"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -40,8 +43,8 @@
var block = $(this).parent().clone(true);
var new_block = block.insertAfter($(this).parent());
var new_block_id = 'stock_location[]';
$(new_block).find('label').html("<?= lang('Config.stock_location') ?> " + ++location_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2'); // TODO-BS5 change classes from bs3 to bs5
$(new_block).find('input').attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val(''); // TODO-BS5 change classes from bs3 to bs5
$(new_block).find('label').html("<?= lang('Config.stock_location') ?> " + ++location_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
$(new_block).find('input').attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
hide_show_remove();
};
@@ -76,7 +79,6 @@
$(form).ajaxSubmit({
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'
@@ -87,7 +89,7 @@
});
},
errorLabelContainer: ".stock_error_message_box",
errorLabelContainer: "#stock_error_message_box",
rules: {
<?php

View File

@@ -0,0 +1,17 @@
<br>
<div class="container-fluid">
<ul class="nav nav-tabs" id="myTabs" data-toggle="tab">
<li class="active"><a href="#system_tabs" data-toggle="tab" title="<?= lang('Config.system_conf') ?>"><?= lang('Config.system_conf') ?></a></li>
<li><a href="#email_tabs" data-toggle="tab" title="<?= lang('Config.email_configuration') ?>"><?= lang('Config.email') ?></a></li>
<li><a href="#message_tabs" data-toggle="tab" title="<?= lang('Config.message_configuration') ?>"><?= lang('Config.message') ?></a></li>
<li><a href="#integrations_tabs" data-toggle="tab" title="<?= lang('Config.integrations_configuration') ?>"><?= lang('Config.integrations') ?></a></li>
<li><a href="#license_tabs" data-toggle="tab" title="<?= lang('Config.license_configuration') ?>"><?= lang('Config.license') ?></a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="system_tabs"><?= view('configs/system_info') ?></div>
<div class="tab-pane" id="email_tabs"><?= view('configs/email_config') ?></div>
<div class="tab-pane" id="message_tabs"><?= view('configs/message_config') ?></div>
<div class="tab-pane" id="integrations_tabs"><?= view('configs/integrations_config') ?></div>
<div class="tab-pane" id="license_tabs"><br><?= view('configs/license_config') ?></div>
</div>
</div>

View File

@@ -6,97 +6,48 @@
use Config\OSPOS;
$logs = WRITEPATH . 'logs/';
$uploads = FCPATH . 'uploads/';
$images = FCPATH . 'uploads/item_pics/';
$importCustomers = WRITEPATH . '/uploads/importCustomers.csv'; //TODO: This variable does not follow naming conventions for the project.
$bullet = '&raquo;' . '&nbsp;';
$divider = ' &middot;' . '&nbsp;';
$enabled = '<span class="text-success">&#10003; Enabled</span>';
$disabled = '<span class="text-danger">&#10007; Disabled</span>';
$writable = '<span class="text-success">&#10003; Writable</span>';
$notwritable = '<span class="text-danger">&#10007; Not Writable</span>';
$readable = '<span class="text-success">&#10003; Readable</span>';
$notreadable = '<span class="text-danger">&#10007; Not Readable</span>';
$permissions_check = '<span class="text-success">&#10003; Security Check Passed</span>';
$permissions_fail = '<span class="text-danger">&#10007; Vulnerable or Incorrect Permissions</span>';
?>
<?php
$title_info['config_title'] = lang('Config.system_info');
echo view('configs/config_header', $title_info);
?>
<style>
a:hover {
cursor: pointer;
}
<div class="mb-3"><?= lang('Config.server_notice'); ?></div>
hidden {
visibility: hidden;
}
</style>
<form id="copy-issue">
<script type="text/javascript" src="js/clipboard.min.js"></script>
<?php
if (!((substr(decoct(fileperms($logs)), -4) == 750)
&& (substr(decoct(fileperms($uploads)), -4) == 750)
&& (substr(decoct(fileperms($images)), -4) == 750)
&& ((substr(decoct(fileperms($importCustomers)), -4) == 640)
|| (substr(decoct(fileperms($importCustomers)), -4) == 660)))) {
echo '<div class="card border-danger-subtle mb-4">
<div class="card-header bg-danger-subtle border-danger-subtle fw-bold"><i class="bi bi-exclamation-circle"></i> ' . lang('Config.security_issue') . '</div>
<div class="card-body">
<p class="card-text">' . lang('Config.perm_risk') . '</p>
<ul class="list-unstyled mb-0">';
}
if (substr(decoct(fileperms($logs)), -4) != 750) {
echo '<li class="card-text">' . $bullet . '<code>writable/logs</code> ' . lang('Config.is_writable') . '</li>';
}
if (substr(decoct(fileperms($uploads)), -4) != 750) {
echo '<li class="card-text">' . $bullet . '<code>public/uploads</code> ' . lang('Config.is_writable') . '</li>';
}
if (substr(decoct(fileperms($images)), -4) != 750) {
echo '<li class="card-text">' . $bullet . '<code>public/uploads/item_pics</code> ' . lang('Config.is_writable') . '</li>';
}
if (!((substr(decoct(fileperms($importCustomers)), -4) == 640)
|| (substr(decoct(fileperms($importCustomers)), -4) == 660))) {
echo '<li class="card-text">' . $bullet . '<code>importCustomers.csv</code> ' . lang('Config.is_readable') . '</li>';
}
echo '</div></div>';
?>
<div class="row mb-3">
<label for="general-info" class="col-12 col-lg-2 form-label fw-bold">General Info</label>
<div class="col-12 col-lg-10" id="general-info">
<?= lang('Config.ospos_info') . ':&nbsp;' . esc(config('App')->application_version) . '&nbsp;-&nbsp;' . esc(substr(config(OSPOS::class)->commit_sha1, 0, 6)); ?><br>
<div>Language Code: <?= current_language_code(); ?></div><br>
<div id="time-error" class="row mb-3 d-none">
<div class="col-12 text-danger"><?= lang('Config.timezone_error'); ?></div>
<div class="col-6">
<label for="timezone"><?= lang('Config.user_timezone'); ?></label>
<div id="timezone"></div>
</div>
<div class="col-6">
<label for="ostimezone"><?= lang('Config.os_timezone'); ?></label>
<div id="ostimezone"><?= $config['timezone']; ?></div>
</div>
<div id="config_wrapper" class="col-sm-12">
<?= lang('Config.server_notice') ?>
<div class="container">
<div class="row">
<div class="col-sm-2" style="text-align: left;"><br>
<p style="min-height: 17.7em; font-weight: bold;">General Info</p>
<p style="min-height: 12.2em; font-weight: bold;">User Setup</p><br>
<p style="font-weight: bold;">Permissions</p>
</div>
<span>Extensions & Modules:</span><br>
<ul class="list-unstyled">
<li><?= $bullet . 'GD: ', extension_loaded('gd') ? $enabled : $disabled; ?></li>
<li><?= $bullet . 'BC Math: ', extension_loaded('bcmath') ? $enabled : $disabled; ?></li>
<li><?= $bullet . 'INTL: ', extension_loaded('intl') ? $enabled : $disabled; ?></li>
<li><?= $bullet . 'OpenSSL: ', extension_loaded('openssl') ? $enabled : $disabled; ?></li>
<li><?= $bullet . 'MBString: ', extension_loaded('mbstring') ? $enabled : $disabled; ?></li>
<li><?= $bullet . 'Curl: ', extension_loaded('curl') ? $enabled : $disabled; ?></li>
<li><?= $bullet . 'Xml: ', extension_loaded('xml') ? $enabled : $disabled; ?></li>
</ul>
</div>
</div>
<div class="row mb-3">
<label for="user-setup" class="col-12 col-lg-2 form-label fw-bold">User Setup</label>
<div class="col-12 col-lg-10" id="user-setup">
<ul class="list-unstyled">
<?php
<div class="col-sm-8" id="issuetemplate" style="text-align: left;"><br>
<?= lang('Config.ospos_info') . ':' ?>
<?= esc(config('App')->application_version) ?> - <?= esc(substr(config(OSPOS::class)->commit_sha1, 0, 6)) ?><br>
Language Code: <?= current_language_code() ?><br><br>
<div id="TimeError"></div>
Extensions & Modules:<br>
<?php
echo "&#187; GD: ", extension_loaded('gd') ? '<span style="color: green;">Enabled &#x2713</span>' : '<span style="color: red;">Disabled &#x2717</span>', '<br>';
echo "&#187; BC Math: ", extension_loaded('bcmath') ? '<span style="color: green;">Enabled &#x2713</span>' : '<span style="color: red;">Disabled &#x2717</span>', '<br>';
echo "&#187; INTL: ", extension_loaded('intl') ? '<span style="color: green;">Enabled &#x2713</span>' : '<span style="color: red;">Disabled &#x2717</span>', '<br>';
echo "&#187; OpenSSL: ", extension_loaded('openssl') ? '<span style="color: green;">Enabled &#x2713</span>' : '<span style="color: red;">Disabled &#x2717</span>', '<br>';
echo "&#187; MBString: ", extension_loaded('mbstring') ? '<span style="color: green;">Enabled &#x2713</span>' : '<span style="color: red;">Disabled &#x2717</span>', '<br>';
echo "&#187; Curl: ", extension_loaded('curl') ? '<span style="color: green;">Enabled &#x2713</span>' : '<span style="color: red;">Disabled &#x2717</span>', '<br>';
echo "&#187; Json: ", extension_loaded('json') ? '<span style="color: green;">Enabled &#x2713</span>' : '<span style="color: red;">Disabled &#x2717</span>', '<br>';
echo "&#187; Xml: ", extension_loaded('xml') ? '<span style="color: green;">Enabled &#x2713</span>' : '<span style="color: red;">Disabled &#x2717</span>', '<br><br>';
?>
User Configuration:<br>
.Browser:
<?php
/**
* @param string $userAgent
* @return string
@@ -104,169 +55,162 @@ echo view('configs/config_header', $title_info);
function getBrowserNameAndVersion(string $userAgent): string
{
$browser = match (true) {
strpos($userAgent, 'Opera') !== false || strpos($userAgent, 'OPR/') !== false => 'Opera',
strpos($userAgent, 'Edge') !== false => 'Edge',
strpos($userAgent, 'Chrome') !== false => 'Chrome',
strpos($userAgent, 'Safari') !== false => 'Safari',
strpos($userAgent, 'Opera') !== false || strpos($userAgent, 'OPR/') !== false => 'Opera',
strpos($userAgent, 'Edge') !== false => 'Edge',
strpos($userAgent, 'Chrome') !== false => 'Chrome',
strpos($userAgent, 'Safari') !== false => 'Safari',
strpos($userAgent, 'Firefox') !== false => 'Firefox',
strpos($userAgent, 'MSIE') !== false || strpos($userAgent, 'Trident/7') !== false => 'Internet Explorer',
default => 'Other',
strpos($userAgent, 'MSIE') !== false || strpos($userAgent, 'Trident/7') !== false => 'Internet Explorer',
default => 'Other',
};
$version = match ($browser) {
'Opera' => preg_match('/(Opera|OPR)\/([0-9.]+)/', $userAgent, $matches) ? $matches[2] : '',
'Edge' => preg_match('/Edge\/([0-9.]+)/', $userAgent, $matches) ? $matches[1] : '',
'Chrome' => preg_match('/Chrome\/([0-9.]+)/', $userAgent, $matches) ? $matches[1] : '',
'Safari' => preg_match('/Version\/([0-9.]+)/', $userAgent, $matches) ? $matches[1] : '',
'Firefox' => preg_match('/Firefox\/([0-9.]+)/', $userAgent, $matches) ? $matches[1] : '',
'Opera' => preg_match('/(Opera|OPR)\/([0-9.]+)/', $userAgent, $matches) ? $matches[2] : '',
'Edge' => preg_match('/Edge\/([0-9.]+)/', $userAgent, $matches) ? $matches[1] : '',
'Chrome' => preg_match('/Chrome\/([0-9.]+)/', $userAgent, $matches) ? $matches[1] : '',
'Safari' => preg_match('/Version\/([0-9.]+)/', $userAgent, $matches) ? $matches[1] : '',
'Firefox' => preg_match('/Firefox\/([0-9.]+)/', $userAgent, $matches) ? $matches[1] : '',
'Internet Explorer' => preg_match('/(MSIE|rv:)([0-9.]+)/', $userAgent, $matches) ? $matches[2] : '',
default => '',
default => '',
};
return $browser . ($version ? ' ' . $version : '');
}
?>
<li><?= $bullet . 'Browser: ' . esc(getBrowserNameAndVersion($_SERVER['HTTP_USER_AGENT'])); ?></li>
<li><?= $bullet . 'Server Software: ' . esc($_SERVER['SERVER_SOFTWARE']); ?></li>
<li><?= $bullet . 'PHP Version: ' . PHP_VERSION; ?></li>
<li><?= $bullet . 'DB Version: ' . esc($dbVersion); ?></li>
<li><?= $bullet . 'Server Port: ' . esc($_SERVER['SERVER_PORT']); ?></li>
<li><?= $bullet . 'OS: ' . php_uname('s') . ' ' . php_uname('r'); ?></li>
</ul>
echo esc(getBrowserNameAndVersion($_SERVER['HTTP_USER_AGENT']));
?><br>
Server Software: <?= esc($_SERVER['SERVER_SOFTWARE']) ?><br>
PHP Version: <?= PHP_VERSION ?><br>
DB Version: <?= esc($dbVersion) ?><br>
Server Port: <?= esc($_SERVER['SERVER_PORT']) ?><br>
OS: <?= php_uname('s') . ' ' . php_uname('r') ?><br><br>
<br><br>
File Permissions:<br>
&#187; [writable/logs:]
<?php $logs = WRITEPATH . 'logs/';
$uploads = FCPATH. 'uploads/';
$images = FCPATH. 'uploads/item_pics/';
$importCustomers = WRITEPATH . '/uploads/importCustomers.csv'; // TODO: This variable does not follow naming conventions for the project.
if (is_writable($logs)) {
echo ' - ' . substr(sprintf("%o", fileperms($logs)), -4) . ' | ' . '<span style="color: green;"> Writable &#x2713 </span>';
} else {
echo ' - ' . substr(sprintf("%o", fileperms($logs)), -4) . ' | ' . '<span style="color: red;"> Not Writable &#x2717 </span>';
}
clearstatcache();
if (is_writable($logs) && substr(decoct(fileperms($logs)), -4) != 750) {
echo ' | <span style="color: red;">Vulnerable or Incorrect Permissions &#x2717</span>';
} else {
echo ' | <span style="color: green;">Security Check Passed &#x2713</span>';
}
clearstatcache();
?>
<br>
&#187; [public/uploads:]
<?php
if (is_writable($uploads)) {
echo ' - ' . substr(sprintf("%o", fileperms($uploads)), -4) . ' | ' . '<span style="color: green;"> Writable &#x2713 </span>';
} else {
echo ' - ' . substr(sprintf("%o", fileperms($uploads)), -4) . ' | ' . '<span style="color: red;"> Not Writable &#x2717 </span>';
}
clearstatcache();
if (is_writable($uploads) && substr(decoct(fileperms($uploads)), -4) != 750) {
echo ' | <span style="color: red;">Vulnerable or Incorrect Permissions &#x2717</span>';
} else {
echo ' | <span style="color: green;">Security Check Passed &#x2713 </span>';
}
clearstatcache();
?>
<br>
&#187; [public/uploads/item_pics:]
<?php
if (is_writable($images)) {
echo ' - ' . substr(sprintf("%o", fileperms($images)), -4) . ' | ' . '<span style="color: green;"> Writable &#x2713 </span>';
} else {
echo ' - ' . substr(sprintf("%o", fileperms($images)), -4) . ' | ' . '<span style="color: red;"> Not Writable &#x2717 </span>';
}
clearstatcache();
if (substr(decoct(fileperms($images)), -4) != 750) {
echo ' | <span style="color: red;">Vulnerable or Incorrect Permissions &#x2717</span>';
} else {
echo ' | <span style="color: green;">Security Check Passed &#x2713 </span>';
}
clearstatcache();
?>
<br>
&#187; [importCustomers.csv:]
<?php
if (is_readable($importCustomers)) {
echo ' - ' . substr(sprintf("%o", fileperms($importCustomers)), -4) . ' | ' . '<span style="color: green;"> Readable &#x2713 </span>';
} else {
echo ' - ' . substr(sprintf("%o", fileperms($importCustomers)), -4) . ' | ' . '<span style="color: red;"> Not Readable &#x2717 </span>';
}
clearstatcache();
if (!((substr(decoct(fileperms($importCustomers)), -4) == 640) || (substr(decoct(fileperms($importCustomers)), -4) == 660))) {
echo ' | <span style="color: red;">Vulnerable or Incorrect Permissions &#x2717</span>';
} else {
echo ' | <span style="color: green;">Security Check Passed &#x2713 </span>';
}
clearstatcache();
?>
<br>
<?php
if (!((substr(decoct(fileperms($logs)), -4) == 750)
&& (substr(decoct(fileperms($uploads)), -4) == 750)
&& (substr(decoct(fileperms($images)), -4) == 750)
&& ((substr(decoct(fileperms($importCustomers)), -4) == 640)
|| (substr(decoct(fileperms($importCustomers)), -4) == 660)))) {
echo '<br><span style="color: red;"><strong>' . lang('Config.security_issue') . '</strong> <br>' . lang('Config.perm_risk') . '</span><br>';
} else {
echo '<br><span style="color: green;">' . lang('Config.no_risk') . '</strong> <br> </span>';
}
if (substr(decoct(fileperms($logs)), -4) != 750) {
echo '<br><span style="color: red;"> &#187; [writable/logs:] ' . lang('Config.is_writable') . '</span>';
}
if (substr(decoct(fileperms($uploads)), -4) != 750) {
echo '<br><span style="color: red;"> &#187; [writable/uploads:] ' . lang('Config.is_writable') . '</span>';
}
if (substr(decoct(fileperms($images)), -4) != 750) {
echo '<br><span style="color: red;"> &#187; [writable/uploads/item_pics:] ' . lang('Config.is_writable') . '</span>';
}
if (!((substr(decoct(fileperms($importCustomers)), -4) == 640)
|| (substr(decoct(fileperms($importCustomers)), -4) == 660))) {
echo '<br><span style="color: red;"> &#187; [importCustomers.csv:] ' . lang('Config.is_readable') . '</span>';
}
?>
</div>
</div>
</div>
<div class="row mb-3">
<label for="permissions" class="col-12 col-lg-2 form-label fw-bold">Permissions</label>
<div class="col-12 col-lg-10" id="permissions">
<ul class="list-unstyled">
<li>
<?= $bullet; ?><code>writable/logs</code>
<?php
if (is_writable($logs)) {
echo substr(sprintf("%o", fileperms($logs)), -4) . $divider . $writable;
} else {
echo substr(sprintf("%o", fileperms($logs)), -4) . $divider . $notwritable;
}
clearstatcache();
echo $divider;
if (is_writable($logs) && substr(decoct(fileperms($logs)), -4) != 750) {
echo $permissions_fail;
} else {
echo $permissions_check;
}
clearstatcache();
?>
</li>
<li>
<?= $bullet; ?><code>public/uploads</code>
<?php
if(is_writable($uploads)) {
echo substr(sprintf("%o",fileperms($uploads)),-4) . $divider . $writable;
} else {
echo substr(sprintf("%o",fileperms($uploads)),-4) . $divider . $notwritable;
}
clearstatcache();
echo $divider;
if(is_writable($uploads) && substr(decoct(fileperms($uploads)), -4) != 750 ) {
echo $permissions_fail;
} else {
echo $permissions_check;
}
clearstatcache();
?>
</li>
<li>
<?= $bullet; ?><code>public/uploads/item_pics</code>
<?php
if (is_writable($images)) {
echo substr(sprintf("%o", fileperms($images)), -4) . $divider . $writable;
} else {
echo substr(sprintf("%o", fileperms($images)), -4) . $divider . $notwritable;
}
clearstatcache();
echo $divider;
if (substr(decoct(fileperms($images)), -4) != 750) {
echo $permissions_fail;
} else {
echo $permissions_check;
}
clearstatcache();
?>
</li>
<li>
<?= $bullet; ?><code>importCustomers.csv</code>
<?php
if (is_readable($importCustomers)) {
echo substr(sprintf("%o", fileperms($importCustomers)), -4) . $divider . $readable;
} else {
echo substr(sprintf("%o", fileperms($importCustomers)), -4) . $divider . $notreadable;
}
clearstatcache();
echo $divider;
if (!((substr(decoct(fileperms($importCustomers)), -4) == 640) || (substr(decoct(fileperms($importCustomers)), -4) == 660))) {
echo $permissions_fail;
} else {
echo $permissions_check;
}
clearstatcache();
?>
</li>
</ul>
<?php
if (((substr(decoct(fileperms($logs)), -4) == 750) && (substr(decoct(fileperms($uploads)), -4) == 750) && (substr(decoct(fileperms($images)), -4) == 750) && ((substr(decoct(fileperms($importCustomers)), -4) == 640) || (substr(decoct(fileperms($importCustomers)), -4) == 660)))) {
echo '<span class="text-success">' . lang('Config.no_risk') . '</span>';
}
?>
</div>
</div>
</form>
<div class="d-flex justify-content-center gap-3">
<button type="button" class="copy btn btn-secondary" data-clipboard-target="#copy-issue"><i class="bi bi-clipboard-plus"></i> Copy Info</button> <!-- TODO-BS5 add to translations -->
<a class="btn btn-secondary" href="https://github.com/opensourcepos/opensourcepos/issues/new" target="_blank" rel="noopener"><i class="bi bi-flag"></i> <?= lang('Config.report_an_issue') ?></a>
</div>
<script type="text/javascript">
var clipboard = new ClipboardJS('.copy');
<div style="text-align: center;">
<a class="copy" data-clipboard-action="copy" data-clipboard-target="#issuetemplate">Copy Info</a> | <a href="https://github.com/opensourcepos/opensourcepos/issues/new" target="_blank"> <?= lang('Config.report_an_issue') ?></a>
<script type="text/javascript">
var clipboard = new ClipboardJS('.copy');
clipboard.on('success', function(e) {
document.getSelection().removeAllRanges();
$.notify({
icon: 'bi bi-clipboard-check-fill',
message: 'System info successfully copied.'
}, {
type: 'success'
clipboard.on('success', function(e) {
document.getSelection().removeAllRanges();
});
});
clipboard.on('error', function(e) {
$.notify({
icon: 'bi bi-clipboard-x-fill',
message: 'Something went wrong while copying.'
}, {
type: 'danger'
$(function() {
$('#timezone').clone().appendTo('#timezoneE');
});
});
document.getElementById("timezone").innerText = Intl.DateTimeFormat().resolvedOptions().timeZone;
$(function() {
$('#timezone').clone().appendTo('#timezoneE');
});
if ($('#timezone').html() !== $('#ostimezone').html()) {
$('#time-error').removeClass('d-none');
};
</script>
if ($('#timezone').html() !== $('#ostimezone').html()) {
document.getElementById("timezone").innerText = Intl.DateTimeFormat().resolvedOptions().timeZone;
document.getElementById("TimeError").innerHTML = '<span style="color: red;"><?= lang('Config.timezone_error') ?></span><br><br><?= lang('Config.user_timezone') ?><div id="timezoneE" style="font-weight:600;"></div><br><?= lang('Config.os_timezone') ?><div id="ostimezoneE" style="font-weight:600;"><?= esc($config['timezone']) ?></div><br>';
}
</script>
</div>

View File

@@ -5,28 +5,38 @@
*/
?>
<?= form_open('config/saveTables/', ['id' => 'table_config_form']) ?>
<?= form_open('config/saveTables/', ['id' => 'table_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.table_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="table_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="table_error_message_box alert alert-warning d-none"></ul>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.dinner_table_enable'), 'dinner_table_enable', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'dinner_table_enable',
'value' => 'dinner_table_enable',
'id' => 'dinner_table_enable',
'checked' => $config['dinner_table_enable'] == 1
]) ?>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="dinner_table_enable" name="dinner_table_enable" value="dinner_table_enable" <?= $config['dinner_table_enable'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="dinner_table_enable"><?= lang('Config.dinner_table_enable'); ?></label>
<div id="dinner_tables">
<?= view('partial/dinner_tables', ['dinner_tables' => $dinner_tables]) ?>
</div>
<?= form_submit([
'name' => 'submit_table',
'id' => 'submit_table',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<div class="row" id="dinner_tables">
<?= view('partial/dinner_tables', ['dinner_tables' => $dinner_tables]) ?>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_table"><?= lang('Common.submit'); ?></button>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -62,8 +72,8 @@
var block = $(this).parent().clone(true);
var new_block = block.insertAfter($(this).parent());
var new_block_id = 'dinner_table_' + ++id;
$(new_block).find('label').html("<?= lang('Config.dinner_table') ?> " + ++table_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2'); // TODO-BS5 change classes from bs3 to bs5
$(new_block).find('input').attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val(''); // TODO-BS5 change classes from bs3 to bs5
$(new_block).find('label').html("<?= lang('Config.dinner_table') ?> " + ++table_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
$(new_block).find('input').attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
hide_show_remove();
};
@@ -104,7 +114,6 @@
},
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'

View File

@@ -8,99 +8,144 @@
*/
?>
<?= form_open('config/saveTax/', ['id' => 'tax_config_form']) ?>
<?= form_open('config/saveTax/', ['id' => 'tax_config_form', 'class' => 'form-horizontal']) ?>
<div id="config_wrapper">
<fieldset id="config_info">
<?php
$title_info['config_title'] = lang('Config.tax_configuration');
echo view('configs/config_header', $title_info);
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="tax_error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="tax_error_message_box alert alert-warning d-none"></ul>
<div class="row">
<div class="col-12 col-lg-6">
<label for="tax_id" class="form-label"><?= lang('Config.tax_id'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-bank"></i></span>
<input type="text" name="tax_id" class="form-control" id="tax_id" value="<?= $config['tax_id']; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Config.tax_id'), 'tax_id', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'tax_id',
'id' => 'tax_id',
'class' => 'form-control input-sm',
'value' => $config['tax_id']
]) ?>
</div>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="tax_included" name="tax_included" <?= $config['tax_included'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="tax_included"><?= lang('Config.tax_included'); ?></label>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="default_tax_1_rate" class="form-label"><?= lang('Config.default_tax_rate_1') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-1-square"></i></span>
<input type="text" class="form-control w-25" id="default_tax_1_name" name="default_tax_1_name" value="<?= $config['default_tax_1_name'] !== false ? $config['default_tax_1_name'] : lang('Items.sales_tax_1') ?>">
<input type="number" step="any" min="0" max="100" class="form-control" id="default_tax_1_rate" name="default_tax_1_rate" value="<?= to_tax_decimals($config['default_tax_1_rate']) ?>">
<span class="input-group-text"><i class="bi bi-percent"></i></span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.tax_included'), 'tax_included', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_checkbox([
'name' => 'tax_included',
'id' => 'tax_included',
'value' => 'tax_included',
'checked' => $config['tax_included'] == 1
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="default_tax_2_rate" class="form-label"><?= lang('Config.default_tax_rate_2') ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-2-square"></i></span>
<input type="text" class="form-control w-25" id="default_tax_2_name" name="default_tax_2_name" value="<?= $config['default_tax_2_name'] !== false ? $config['default_tax_2_name'] : lang('Items.sales_tax_2') ?>">
<input type="number" step="any" min="0" max="100" class="form-control" id="default_tax_2_rate" name="default_tax_2_rate" value="<?= to_tax_decimals($config['default_tax_2_rate']) ?>">
<span class="input-group-text"><i class="bi bi-percent"></i></span>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.default_tax_rate_1'), 'default_tax_1_rate', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'default_tax_1_name',
'id' => 'default_tax_1_name',
'class' => 'form-control input-sm',
'value' => $config['default_tax_1_name'] !== false ? $config['default_tax_1_name'] : lang('Items.sales_tax_1')
]) ?>
</div>
<div class="col-xs-1 input-group">
<?= form_input([
'type' => 'number',
'step' => 'any',
'min' => '0',
'max' => '100',
'name' => 'default_tax_1_rate',
'id' => 'default_tax_1_rate',
'class' => 'form-control input-sm',
'value' => to_tax_decimals($config['default_tax_1_rate'])
]) ?>
<span class="input-group-addon input-sm">%</span>
</div>
</div>
</div>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" role="switch" id="use_destination_based_tax" name="use_destination_based_tax" value="use_destination_based_tax" <?= $config['use_destination_based_tax'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="use_destination_based_tax"><?= lang('Config.use_destination_based_tax'); ?></label>
</div>
<div class="row">
<div class="col-12 col-lg-6">
<label for="default_tax_code" class="form-label"><?= lang('Config.default_tax_code'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-code"></i></span>
<select class="form-select" name="default_tax_code" id="default_tax_code">
<?php foreach ($tax_code_options as $key => $value): ?>
<option value="<?= $key ?>" <?= $config['default_tax_code'] == $key ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.default_tax_rate_2'), 'default_tax_2_rate', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_input([
'name' => 'default_tax_2_name',
'id' => 'default_tax_2_name',
'class' => 'form-control input-sm',
'value' => $config['default_tax_2_name'] !== false ? $config['default_tax_2_name'] : lang('Items.sales_tax_2')
]) ?>
</div>
<div class="col-xs-1 input-group">
<?= form_input([
'type' => 'number',
'step' => 'any',
'min' => '0',
'max' => '100',
'name' => 'default_tax_2_rate',
'id' => 'default_tax_2_rate',
'class' => 'form-control input-sm',
'value' => to_tax_decimals($config['default_tax_2_rate'])
]) ?>
<span class="input-group-addon input-sm">%</span>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="default_tax_category" class="form-label"><?= lang('Config.default_tax_category'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-bookmark"></i></span>
<select class="form-select" name="default_tax_category" id="default_tax_category">
<?php foreach ($tax_category_options as $key => $value): ?>
<option value="<?= $key ?>" <?= $config['default_tax_category'] == $key ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.use_destination_based_tax'), 'use_destination_based_tax', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_checkbox([
'name' => 'use_destination_based_tax',
'id' => 'use_destination_based_tax',
'value' => 'use_destination_based_tax',
'checked' => $config['use_destination_based_tax'] == 1
]) ?>
</div>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="default_tax_jurisdiction" class="form-label"><?= lang('Config.default_tax_jurisdiction'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-globe"></i></span>
<select class="form-select" name="default_tax_jurisdiction" id="default_tax_jurisdiction">
<?php foreach ($tax_jurisdiction_options as $key => $value): ?>
<option value="<?= $key ?>" <?= $config['default_tax_jurisdiction'] == $key ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.default_tax_code'), 'default_tax_code', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'default_tax_code',
$tax_code_options,
$config['default_tax_code'],
'class="form-control input-sm"'
) ?>
</div>
</div>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" name="submit_tax"><?= lang('Common.submit'); ?></button>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.default_tax_category'), 'default_tax_category', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'default_tax_category',
$tax_category_options,
$config['default_tax_category'],
'class="form-control input-sm"'
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Config.default_tax_jurisdiction'), 'default_tax_jurisdiction', ['class' => 'control-label col-xs-2']) ?>
<div class="col-xs-2">
<?= form_dropdown(
'default_tax_jurisdiction',
$tax_jurisdiction_options,
$config['default_tax_jurisdiction'],
'class="form-control input-sm"'
) ?>
</div>
</div>
<?= form_submit([
'name' => 'submit_tax',
'id' => 'submit_tax',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
</fieldset>
</div>
<?= form_close() ?>
<script type="text/javascript">
@@ -131,7 +176,6 @@
},
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'

View File

@@ -11,239 +11,433 @@
*/
?>
<?= form_open("$controller_name/save/$person_info->person_id", ['id' => 'customer_form']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<?php if (!empty($stats) || (!empty($mailchimp_info) && !empty($mailchimp_activity))) { ?>
<ul class="nav nav-pills nav-justified mb-3" role="tablist">
<li class="nav-item" role="presentation">
<button type="button" class="nav-link active" data-bs-toggle="pill" data-bs-target="#customer_basic_info" role="tab"><?= lang('Customers.basic_information') ?></button>
<?= form_open("$controller_name/save/$person_info->person_id", ['id' => 'customer_form', 'class' => 'form-horizontal']) ?>
<ul class="nav nav-tabs nav-justified" data-tabs="tabs">
<li class="active" role="presentation">
<a data-toggle="tab" href="#customer_basic_info"><?= lang('Customers.basic_information') ?></a>
</li>
<?php if (!empty($stats)) { ?>
<li role="presentation">
<a data-toggle="tab" href="#customer_stats_info"><?= lang('Customers.stats_info') ?></a>
</li>
<?php if (!empty($stats)) { ?>
<li class="nav-item" role="presentation">
<button type="button" class="nav-link" data-bs-toggle="pill" data-bs-target="#customer_stats_info" role="tab"><?= lang('Customers.stats_info') ?></button>
</li>
<?php } ?>
<?php if (!empty($mailchimp_info) && !empty($mailchimp_activity)) { ?>
<li class="nav-item" role="presentation">
<button type="button" class="nav-link" data-bs-toggle="pill" data-bs-target="#customer_mailchimp_info" role="tab"><?= lang('Customers.mailchimp_info') ?></button>
</li>
<?php } ?>
</ul>
<?php } ?>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?php } ?>
<?php if (!empty($mailchimp_info) && !empty($mailchimp_activity)) { ?>
<li role="presentation">
<a data-toggle="tab" href="#customer_mailchimp_info"><?= lang('Customers.mailchimp_info') ?></a>
</li>
<?php } ?>
</ul>
<div class="tab-content">
<div class="tab-pane show active" id="customer_basic_info" role="tabpanel" tabindex="0">
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" name="consent" id="consent" value="1" required <?php $checked = ($person_info->consent == '' ? !$config['enforce_privacy'] : (bool)$person_info->consent); if ($checked) { echo 'checked';} ?>>
<label class="form-check-label" for="consent"><?= lang('Customers.consent') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
</div>
<?= view('people/form_basic_info') ?>
<label for="discount_type" class="form-label"><?= lang('Customers.discount_type') ?></label>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="discount_type" id="discount_type_percent" value="0" <?php if ($person_info->discount_type == PERCENT) echo 'checked'; ?>>
<label class="form-check-label" for="discount_type_percent"><?= lang('Customers.discount_percent') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="discount_type" id="discount_type_fixed" value="1" <?php if ($person_info->discount_type == FIXED) echo 'checked'; ?>>
<label class="form-check-label" for="discount_type_fixed"><?= lang('Customers.discount_fixed') ?></label>
</div>
</div>
<label for="discount" class="form-label"><?= lang('Customers.discount'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="discount-icon"><i class="bi bi-patch-minus"></i></span>
<input type="number" step="any" class="form-control" name="discount" id="discount" aria-describedby="discount-icon" value="<?= $person_info->discount_type === FIXED ? to_currency_no_money($person_info->discount) : to_decimals($person_info->discount)?>">
</div>
<label for="company_name" class="form-label"><?= lang('Customers.company_name'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="company_name-icon"><i class="bi bi-building"></i></span>
<input type="text" class="form-control" name="company_name" id="company_name" aria-describedby="company_name-icon" value="<?= $person_info->company_name ?>">
</div>
<label for="account_number" class="form-label"><?= lang('Customers.account_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="account_number-icon"><i class="bi bi-hash"></i></span>
<input type="text" class="form-control" name="account_number" id="account_number" aria-describedby="account_number-icon" value="<?= $person_info->account_number ?>">
</div>
<label for="tax_id" class="form-label"><?= lang('Customers.tax_id'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="tax_id-icon"><i class="bi bi-bank"></i></span>
<input type="text" class="form-control" name="tax_id" id="tax_id" aria-describedby="tax_id-icon" value="<?= $person_info->tax_id ?>">
</div>
<?php if ($config['customer_reward_enable']): ?>
<label for="rewards" class="form-label"><?= lang('Customers.rewards_package'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-trophy"></i></span>
<select class="form-select" name="package_id">
<?php foreach ($packages as $id => $label): ?>
<option value="<?= $id ?>" <?= $id == $selected_package ? 'selected' : '' ?>><?= $label ?></option>
<?php endforeach; ?>
</select>
<div class="tab-pane fade in active" id="customer_basic_info">
<fieldset>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.consent'), 'consent', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-1">
<?= form_checkbox('consent', 1, $person_info->consent == '' ? !$config['enforce_privacy'] : (bool)$person_info->consent) ?>
</div>
</div>
<label for="available_points" class="form-label"><?= lang('Customers.available_points'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="available_points-icon"><i class="bi bi-hand-thumbs-up"></i></span>
<input type="text" class="form-control" name="available_points" id="available_points" aria-describedby="available_points-icon" value="<?= $person_info->points ?>" disabled readonly>
<?= view('people/form_basic_info') ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.discount_type'), 'discount_type', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'discount_type',
'type' => 'radio',
'id' => 'discount_type',
'value' => 0,
'checked' => $person_info->discount_type == PERCENT
]) ?> <?= lang('Customers.discount_percent') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'discount_type',
'type' => 'radio',
'id' => 'discount_type',
'value' => 1,
'checked' => $person_info->discount_type == FIXED
]) ?> <?= lang('Customers.discount_fixed') ?>
</label>
</div>
</div>
<?php endif; ?>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" name="taxable" id="taxable" value="1" <?php if ($person_info->taxable == 1) echo 'checked'; ?>>
<label class="form-check-label" for="taxable"><?= lang('Customers.taxable') ?></label>
</div>
<?php if ($use_destination_based_tax): ?>
<label for="sales_tax_code_name" class="form-label"><?= lang('Customers.tax_code'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="sales_tax_code_name-icon"><i class="bi bi-bank"></i></span>
<input type="hidden" name="sales_tax_code_id" value="<?= $person_info->sales_tax_code_id ?>">
<input type="text" class="form-control" name="sales_tax_code_name" id="sales_tax_code_name" aria-describedby="sales_tax_code_name-icon" size="50" value="<?= $sales_tax_code_label ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.discount'), 'discount', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-3">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'discount',
'id' => 'discount',
'class' => 'form-control input-sm',
'onClick' => 'this.select();',
'value' => $person_info->discount_type === FIXED ? to_currency_no_money($person_info->discount) : to_decimals($person_info->discount)
]) ?>
</div>
</div>
</div>
<?php endif; ?>
<label for="datetime" class="form-label"><?= lang('Customers.date'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="datetime-icon"><i class="bi bi-calendar2"></i></span>
<input type="hidden" name="date" id="datetime" aria-describedby="datetime-icon" value="<?= to_datetime(strtotime($person_info->date)) ?>">
<input type="text" class="form-control" value="<?= to_datetime(strtotime($person_info->date)) ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.company_name'), 'customer_company_name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'company_name',
'id' => 'customer_company_name',
'class' => 'form-control input-sm',
'value' => $person_info->company_name
]) ?>
</div>
</div>
<label for="employee" class="form-label"><?= lang('Customers.employee'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="employee-icon"><i class="bi bi-person"></i></span>
<input type="hidden" name="employee_id" value="<?= $person_info->employee_id ?>">
<input type="text" class="form-control" name="employee" id="employee" aria-describedby="employee-icon" value="<?= $employee ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.account_number'), 'account_number', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'account_number',
'id' => 'account_number',
'class' => 'form-control input-sm',
'value' => $person_info->account_number
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.tax_id'), 'tax_id', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'tax_id',
'id' => 'tax_id',
'class' => 'form-control input-sm',
'value' => $person_info->tax_id
]) ?>
</div>
</div>
<?php if ($config['customer_reward_enable']): ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.rewards_package'), 'rewards', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown(
'package_id',
$packages,
$selected_package,
'class="form-control input-sm"'
) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.available_points'), 'available_points', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'available_points',
'id' => 'available_points',
'class' => 'form-control input-sm',
'value' => $person_info->points,
'disabled' => ''
]) ?>
</div>
</div>
<?php endif; ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.taxable'), 'taxable', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-1">
<?= form_checkbox('taxable', 1, $person_info->taxable == 1) ?>
</div>
</div>
<?php if ($use_destination_based_tax) { ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.tax_code'), 'sales_tax_code_name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'sales_tax_code_name',
'id' => 'sales_tax_code_name',
'class' => 'form-control input-sm',
'size' => '50',
'value' => $sales_tax_code_label
]) ?>
<?= form_hidden('sales_tax_code_id', $person_info->sales_tax_code_id) ?>
</div>
</div>
</div>
<?php } ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.date'), 'date', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-calendar"></span></span>
<?= form_input([
'name' => 'date',
'id' => 'datetime',
'class' => 'form-control input-sm',
'value' => to_datetime(strtotime($person_info->date)),
'readonly' => 'true'
]) ?>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.employee'), 'employee', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'employee',
'id' => 'employee',
'class' => 'form-control input-sm',
'value' => $employee,
'readonly' => 'true'
]) ?>
</div>
</div>
<?= form_hidden('employee_id', $person_info->employee_id) ?>
</fieldset>
</div>
<?php if (!empty($stats)) { ?>
<div class="tab-pane" id="customer_stats_info" role="tabpanel" tabindex="0">
<label for="total" class="form-label"><?= lang('Customers.total'); ?></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="total-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="text" class="form-control" name="total" id="total" aria-describedby="total-icon" value="<?= to_currency_no_money($stats->total) ?>" disabled readonly>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="total-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<br>
<div class="tab-pane" id="customer_stats_info">
<fieldset>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.total'), 'total', ['class' => 'control-label col-xs-5']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
<?= form_input([
'name' => 'total',
'id' => 'total',
'class' => 'form-control input-sm',
'value' => to_currency_no_money($stats->total),
'disabled' => ''
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
</div>
</div>
</div>
<label for="max" class="form-label"><?= lang('Customers.max'); ?></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="max-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="text" class="form-control" name="max" id="max" aria-describedby="max-icon" value="<?= to_currency_no_money($stats->max) ?>" disabled readonly>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="max-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.max'), 'max', ['class' => 'control-label col-xs-5']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
<?= form_input([
'name' => 'max',
'id' => 'max',
'class' => 'form-control input-sm',
'value' => to_currency_no_money($stats->max),
'disabled' => ''
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
</div>
</div>
</div>
<label for="min" class="form-label"><?= lang('Customers.min'); ?></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="min-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="text" class="form-control" name="min" id="min" aria-describedby="min-icon" value="<?= to_currency_no_money($stats->min) ?>" disabled readonly>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="min-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.min'), 'min', ['class' => 'control-label col-xs-5']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
<?= form_input([
'name' => 'min',
'id' => 'min',
'class' => 'form-control input-sm',
'value' => to_currency_no_money($stats->min),
'disabled' => ''
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
</div>
</div>
</div>
<label for="average" class="form-label"><?= lang('Customers.average'); ?></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="average-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="text" class="form-control" name="average" id="average" aria-describedby="average-icon" value="<?= to_currency_no_money($stats->average) ?>" disabled readonly>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="average-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.average'), 'average', ['class' => 'control-label col-xs-5']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
<?= form_input([
'name' => 'average',
'id' => 'average',
'class' => 'form-control input-sm',
'value' => to_currency_no_money($stats->average),
'disabled' => ''
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
</div>
</div>
</div>
<label for="quantity" class="form-label"><?= lang('Customers.quantity'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="quantity-icon"><i class="bi bi-123"></i></span>
<input type="text" class="form-control" name="quantity" id="quantity" aria-describedby="quantity-icon" value="<?= to_quantity_decimals($stats->quantity) ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.quantity'), 'quantity', ['class' => 'control-label col-xs-5']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<span class="input-group-addon input-sm"><b><?= '>' ?></b></span>
<?= form_input([
'name' => 'quantity',
'id' => 'quantity',
'class' => 'form-control input-sm',
'value' => to_quantity_decimals($stats->quantity),
'disabled' => ''
]) ?>
</div>
</div>
</div>
<label for="avg_discount" class="form-label"><?= lang('Customers.avg_discount'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="avg_discount-icon"><i class="bi bi-percent"></i></span>
<input type="text" class="form-control" name="avg_discount" id="avg_discount" aria-describedby="avg_discount-icon" value="<?= to_decimals($stats->avg_discount) ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.avg_discount'), 'avg_discount', ['class' => 'control-label col-xs-5']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'avg_discount',
'id' => 'avg_discount',
'class' => 'form-control input-sm',
'value' => to_decimals($stats->avg_discount),
'disabled' => ''
]) ?>
<span class="input-group-addon input-sm"><b>%</b></span>
</div>
</div>
</div>
</fieldset>
</div>
<?php } ?>
<?php if (!empty($mailchimp_info) && !empty($mailchimp_activity)) { ?>
<div class="tab-pane" id="customer_mailchimp_info" role="tabpanel" tabindex="0">
<label for="mailchimp_status" class="form-label"><?= lang('Customers.mailchimp_status'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-envelope-check"></i></span>
<select class="form-select" name="mailchimp_status" id="mailchimp_status">
<option value="subscribed" <?= $mailchimp_info['status'] === 'subscribed' ? 'selected' : '' ?>>Subscribed</option>
<option value="unsubscribed" <?= $mailchimp_info['status'] === 'unsubscribed' ? 'selected' : '' ?>>Unsubscribed</option>
<option value="cleaned" <?= $mailchimp_info['status'] === 'cleaned' ? 'selected' : '' ?>>Cleaned</option>
<option value="pending" <?= $mailchimp_info['status'] === 'pending' ? 'selected' : '' ?>>Pending</option>
</select>
</div>
<div class="tab-pane" id="customer_mailchimp_info">
<fieldset>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_status'), 'mailchimp_status', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_dropdown(
'mailchimp_status',
[
'subscribed' => 'subscribed',
'unsubscribed' => 'unsubscribed',
'cleaned' => 'cleaned',
'pending' => 'pending'
],
$mailchimp_info['status'],
['id' => 'mailchimp_status', 'class' => 'form-control input-sm']
) ?>
</div>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" name="mailchimp_vip" id="mailchimp_vip" value="1" <?= $mailchimp_info['vip'] == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="mailchimp_vip"><?= lang('Customers.mailchimp_vip') ?></label>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_vip'), 'mailchimp_vip', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-1">
<?= form_checkbox('mailchimp_vip', 1, $mailchimp_info['vip'] == 1) ?>
</div>
</div>
<label for="mailchimp_member_rating" class="form-label"><?= lang('Customers.mailchimp_member_rating'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="mailchimp_member_rating-icon"><i class="bi bi-hand-thumbs-up"></i></span>
<input type="text" class="form-control" name="mailchimp_member_rating" id="mailchimp_member_rating" aria-describedby="mailchimp_member_rating-icon" value="<?= $mailchimp_info['member_rating'] ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_member_rating'), 'mailchimp_member_rating', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'mailchimp_member_rating',
'class' => 'form-control input-sm',
'value' => $mailchimp_info['member_rating'],
'disabled' => ''
]) ?>
</div>
</div>
<label for="mailchimp_activity_total" class="form-label"><?= lang('Customers.mailchimp_activity_total'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="mailchimp_activity_total-icon"><i class="bi bi-envelope-arrow-up"></i></span>
<input type="text" class="form-control" name="mailchimp_activity_total" id="mailchimp_activity_total" aria-describedby="mailchimp_activity_total-icon" value="<?= $mailchimp_activity['total'] ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_activity_total'), 'mailchimp_activity_total', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'mailchimp_activity_total',
'class' => 'form-control input-sm',
'value' => $mailchimp_activity['total'],
'disabled' => ''
]) ?>
</div>
</div>
<label for="mailchimp_activity_lastopen" class="form-label"><?= lang('Customers.mailchimp_activity_lastopen'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="mailchimp_activity_lastopen-icon"><i class="bi bi-calendar2-check"></i></span>
<input type="text" class="form-control" name="mailchimp_activity_lastopen" id="mailchimp_activity_lastopen" aria-describedby="mailchimp_activity_lastopen-icon" value="<?= $mailchimp_activity['lastopen'] ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_activity_lastopen'), 'mailchimp_activity_lastopen', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'mailchimp_activity_lastopen',
'class' => 'form-control input-sm',
'value' => $mailchimp_activity['lastopen'],
'disabled' => ''
]) ?>
</div>
</div>
<label for="mailchimp_activity_open" class="form-label"><?= lang('Customers.mailchimp_activity_open'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="mailchimp_activity_open-icon"><i class="bi bi-envelope-open"></i></span>
<input type="text" class="form-control" name="mailchimp_activity_open" id="mailchimp_activity_open" aria-describedby="mailchimp_activity_open-icon" value="<?= $mailchimp_activity['open'] ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_activity_open'), 'mailchimp_activity_open', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'mailchimp_activity_open',
'class' => 'form-control input-sm',
'value' => $mailchimp_activity['open'],
'disabled' => ''
]) ?>
</div>
</div>
<label for="mailchimp_activity_click" class="form-label"><?= lang('Customers.mailchimp_activity_click'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="mailchimp_activity_click-icon"><i class="bi bi-hand-index"></i></span>
<input type="text" class="form-control" name="mailchimp_activity_click" id="mailchimp_activity_click" aria-describedby="mailchimp_activity_click-icon" value="<?= $mailchimp_activity['click'] ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_activity_click'), 'mailchimp_activity_click', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'mailchimp_activity_click',
'class' => 'form-control input-sm',
'value' => $mailchimp_activity['click'],
'disabled' => ''
]) ?>
</div>
</div>
<label for="mailchimp_activity_unopen" class="form-label"><?= lang('Customers.mailchimp_activity_unopen'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="mailchimp_activity_unopen-icon"><i class="bi bi-envelope-slash"></i></span>
<input type="text" class="form-control" name="mailchimp_activity_unopen" id="mailchimp_activity_unopen" aria-describedby="mailchimp_activity_unopen-icon" value="<?= $mailchimp_activity['unopen'] ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_activity_unopen'), 'mailchimp_activity_unopen', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'mailchimp_activity_unopen',
'class' => 'form-control input-sm',
'value' => $mailchimp_activity['unopen'],
'disabled' => ''
]) ?>
</div>
</div>
<label for="mailchimp_email_client" class="form-label"><?= lang('Customers.mailchimp_email_client'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="mailchimp_email_client-icon"><i class="bi bi-inbox"></i></span>
<input type="text" class="form-control" name="mailchimp_email_client" id="mailchimp_email_client" aria-describedby="mailchimp_email_client-icon" value="<?= $mailchimp_info['email_client'] ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Customers.mailchimp_email_client'), 'mailchimp_email_client', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'mailchimp_email_client',
'class' => 'form-control input-sm',
'value' => $mailchimp_info['email_client'],
'disabled' => ''
]) ?>
</div>
</div>
</fieldset>
</div>
<?php } ?>
</div>

View File

@@ -1,22 +1,27 @@
<?= form_open_multipart('customers/importCsvFile/', ['id' => 'csv_form']) ?>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open_multipart('customers/importCsvFile/', ['id' => 'csv_form', 'class' => 'form-horizontal']) ?>
<fieldset id="item_basic_info">
<a type="button" class="btn btn-secondary mb-3" href="<?= esc('customers/csv') ?>"><?= lang('Common.download_import_template') ?></a>
<div class="fileinput fileinput-new input-group mb-3" data-provides="fileinput">
<span class="input-group-text"><i class="bi bi-filetype-csv"></i></span>
<div class="form-control" data-trigger="fileinput">
<span class="fileinput-filename"></span>
<div class="form-group form-group-sm">
<div class="col-xs-12">
<a href="<?= esc('customers/csv') ?>"><?= lang('Common.download_import_template') ?></a>
</div>
</div>
<span class="input-group-text fileinput-exists" data-dismiss="fileinput" style="cursor: pointer;"><?= lang('Common.import_remove_file') ?></span>
<span class="input-group-text btn-file">
<span class="fileinput-new"><?= lang('Common.import_select_file') ?></span>
<span class="fileinput-exists"><?= lang('Common.import_change_file') ?></span>
<input type="file" id="file_path" name="file_path" accept=".csv">
</span>
</div>
<div class="form-group form-group-sm">
<div class="col-xs-12">
<div class="fileinput fileinput-new input-group" data-provides="fileinput">
<div class="form-control" data-trigger="fileinput"><i class="glyphicon glyphicon-file fileinput-exists"></i><span class="fileinput-filename"></span></div>
<span class="input-group-addon input-sm btn btn-default btn-file">
<span class="fileinput-new"><?= lang('Common.import_select_file') ?></span><span class="fileinput-exists"><?= lang('Common.import_change_file') ?></span><input type="file" id="file_path" name="file_path" accept=".csv">
</span>
<a href="#" class="input-group-addon input-sm btn btn-default fileinput-exists" data-dismiss="fileinput"><?= lang('Common.import_remove_file') ?></a>
</div>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">

View File

@@ -8,125 +8,152 @@
*/
?>
<?= form_open("$controller_name/save/$person_info->person_id", ['id' => 'employee_form']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<ul class="nav nav-pills nav-justified mb-3" role="tablist">
<li class="nav-item" role="presentation">
<button type="button" class="nav-link active" data-bs-toggle="pill" data-bs-target="#employee_basic_info" role="tab"><?= lang('Employees.basic_information') ?></button>
<?= form_open("$controller_name/save/$person_info->person_id", ['id' => 'employee_form', 'class' => 'form-horizontal']) ?>
<ul class="nav nav-tabs nav-justified" data-tabs="tabs">
<li class="active" role="presentation">
<a data-toggle="tab" href="#employee_basic_info"><?= lang('Employees.basic_information') ?></a>
</li>
<li class="nav-item" role="presentation">
<button type="button" class="nav-link" data-bs-toggle="pill" data-bs-target="#employee_login_info" role="tab"><?= lang('Employees.login_info') ?></button>
<li role="presentation">
<a data-toggle="tab" href="#employee_login_info"><?= lang('Employees.login_info') ?></a>
</li>
<li class="nav-item" role="presentation">
<button type="button" class="nav-link" data-bs-toggle="pill" data-bs-target="#employee_permission_info" role="tab"><?= lang('Employees.permission_info') ?></button>
<li role="presentation">
<a data-toggle="tab" href="#employee_permission_info"><?= lang('Employees.permission_info') ?></a>
</li>
</ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<div class="tab-content">
<div class="tab-pane show active" id="employee_basic_info" role="tabpanel" tabindex="0">
<?= view('people/form_basic_info') ?>
<div class="tab-pane fade in active" id="employee_basic_info">
<fieldset>
<?= view('people/form_basic_info') ?>
</fieldset>
</div>
<div class="tab-pane" id="employee_login_info" role="tabpanel" tabindex="0">
<label for="username" class="form-label"><?= lang('Employees.username'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="username-icon"><i class="bi bi-person"></i></span>
<input type="text" class="form-control" name="username" id="username" aria-describedby="username-icon" value="<?= $person_info->username; ?>" required>
</div>
<div class="tab-pane" id="employee_login_info">
<fieldset>
<div class="form-group form-group-sm">
<?= form_label(lang('Employees.username'), 'username', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-user"></span></span>
<?= form_input([
'name' => 'username',
'id' => 'username',
'class' => 'form-control input-sm',
'value' => $person_info->username
]) ?>
</div>
</div>
</div>
<?php $password_label_attributes = $person_info->person_id == "" ? ['class' => 'required'] : []; ?>
<label for="password" class="form-label"><?= lang('Employees.password'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="password-icon"><i class="bi bi-lock"></i></span>
<input type="password" class="form-control" name="password" id="password" aria-describedby="password-icon" required>
</div>
<?php $password_label_attributes = $person_info->person_id == "" ? ['class' => 'required'] : []; ?>
<label for="repeat_password" class="form-label"><?= lang('Employees.repeat_password'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="repeat_password-icon"><i class="bi bi-lock"></i></span>
<input type="password" class="form-control" name="repeat_password" id="repeat_password" aria-describedby="repeat_password-icon" required>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Employees.password'), 'password', array_merge($password_label_attributes, ['class' => 'control-label col-xs-3'])) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-lock"></span></span>
<?= form_password([
'name' => 'password',
'id' => 'password',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
</div>
<label for="language" class="form-label"><?= lang('Employees.language'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="language-icon"><i class="bi bi-globe"></i></span>
<?php
$languages = get_languages();
$languages[':'] = lang('Employees.system_language');
$language_code = current_language_code();
$language = current_language();
<div class="form-group form-group-sm">
<?= form_label(lang('Employees.repeat_password'), 'repeat_password', array_merge($password_label_attributes, ['class' => 'control-label col-xs-3'])) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-lock"></span></span>
<?= form_password([
'name' => 'repeat_password',
'id' => 'repeat_password',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
</div>
// If No language is set then it will display "System Language"
if ($language_code === current_language_code(true)) {
$language_code = '';
$language = '';
}
echo form_dropdown(
'language',
$languages,
"$language_code:$language",
['class' => 'form-select']
);
?>
</div>
</div>
<div class="tab-pane" id="employee_permission_info" role="tabpanel" tabindex="0">
<div class="mb-3"><?= lang('Employees.permission_desc') ?></div>
<ul class="list-unstyled" id="permission_list">
<?php foreach ($all_modules as $module): ?>
<li class="form-check">
<input class="form-check-input module" type="checkbox" value="<?= $module->module_id ?>" name="grant_<?= $module->module_id ?>" id="grant_<?= $module->module_id ?>" <?= $module->grant == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="grant_<?= $module->module_id ?>">
<select class="form-select form-select-sm d-inline-block w-auto me-1 module" name="menu_group_<?= $module->module_id ?>">
<option value="home" <?= $module->menu_group == 'home' ? 'selected' : '' ?>>
<?= lang('Module.home') ?>
</option>
<option value="office" <?= $module->menu_group == 'office' ? 'selected' : '' ?>>
<?= lang('Module.office') ?>
</option>
<option value="both" <?= $module->menu_group == 'both' ? 'selected' : '' ?>>
<?= lang('Module.both') ?>
</option>
</select>
<span><?= lang("Module.$module->module_id") ?>:</span>
<span class="fw-light fst-italic"><?= lang("Module.$module->module_id" . '_desc') ?></span>
</label>
<?php foreach ($all_subpermissions as $permission): ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Employees.language'), 'language', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<?php
$exploded_permission = explode('_', $permission->permission_id, 2);
$languages = get_languages();
$languages[':'] = lang('Employees.system_language');
$language_code = current_language_code();
$language = current_language();
if ($permission->module_id != $module->module_id) {
continue;
}
// If No language is set then it will display "System Language"
if ($language_code === current_language_code(true)) {
$language_code = '';
$language = '';
}
$lang_key = $module->module_id . '.' . $exploded_permission[1];
$lang_line = lang(ucfirst($lang_key));
// Fallback if language line doesn't exist
if ($lang_line === lang(ucfirst($lang_key))) {
$lang_line = ucwords(str_replace("_", " ", $exploded_permission[1]));
}
if (empty($lang_line)) {
continue;
}
echo form_dropdown(
'language',
$languages,
"$language_code:$language",
['class' => 'form-control input-sm']
);
?>
<ul class="list-unstyled">
<li class="form-check">
<input class="form-check-input module" type="checkbox" value="<?= $permission->permission_id ?>" name="grant_<?= $permission->permission_id ?>" id="grant_<?= $permission->permission_id ?>" <?= $permission->grant == 1 ? 'checked' : '' ?>>
<input type="hidden" name="menu_group_<?= $permission->permission_id ?>" value="--">
<label class="form-check-label" for="grant_<?= $permission->permission_id ?>"><?= esc($lang_line) ?></label>
</li>
</ul>
<?php endforeach; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
</fieldset>
</div>
<div class="tab-pane" id="employee_permission_info">
<fieldset>
<p><?= lang('Employees.permission_desc') ?></p>
<ul id="permission_list">
<?php foreach ($all_modules as $module) { ?>
<li>
<?= form_checkbox("grant_$module->module_id", $module->module_id, $module->grant == 1, 'class="module"') ?>
<?= form_dropdown(
"menu_group_$module->module_id",
[
'home' => lang('Module.home'),
'office' => lang('Module.office'),
'both' => lang('Module.both')
],
$module->menu_group,
'class="module"'
) ?>
<span class="medium"><?= lang("Module.$module->module_id") ?>:</span>
<span class="small"><?= lang("Module.$module->module_id" . '_desc') ?></span>
<?php
foreach ($all_subpermissions as $permission) {
$exploded_permission = explode('_', $permission->permission_id, 2);
if ($permission->module_id == $module->module_id) {
$lang_key = $module->module_id . '.' . $exploded_permission[1];
$lang_line = lang(ucfirst($lang_key));
$lang_line = (lang(ucfirst($lang_key)) == $lang_line) ? ucwords(str_replace("_", " ", $exploded_permission[1])) : $lang_line;
if (!empty($lang_line)) {
?>
<ul>
<li>
<?= form_checkbox("grant_$permission->permission_id", $permission->permission_id, $permission->grant == 1) ?>
<?= form_hidden("menu_group_$permission->permission_id", "--") ?>
<span class="medium"><?= esc($lang_line) ?></span>
</li>
</ul>
<?php
}
}
}
?>
</li>
<?php } ?>
</ul>
</fieldset>
</div>
</div>

View File

@@ -24,7 +24,7 @@
<?= form_label(lang('Expenses.date'), 'date', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-6">
<div class="input-group">
<span class="input-group-addon input-sm"><i class="bi bi-calendar2"></i></span>
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-calendar"></span></span>
<?= form_input([
'name' => 'date',
'class' => 'form-control input-sm datetime',
@@ -52,7 +52,7 @@
</div>
<div class="col-xs-2">
<a id="remove_supplier_button" class="btn btn-danger btn-sm" title="Remove Supplier">
<i class="bi bi-x-circle"></i>
<span class="glyphicon glyphicon-remove"></span>
</a>
</div>
</div>

View File

@@ -12,11 +12,6 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = 'Expenses';
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
$(document).ready(function() {
// Load the preset datarange picker
@@ -59,36 +54,29 @@ echo view('configs/config_header', $title_info);
<?= view('partial/print_receipt', ['print_after_sale' => false, 'selected_printer' => 'takings_printer']) ?>
<div id="title_bar" class="d-flex gap-2 justify-content-end d-print-none">
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . ".new") ?>">
<i class="bi bi-journal-check me-2"></i><?= lang(esc(ucfirst($controller_name)) . '.new') // TODO: String Interpolation ?>
<div id="title_bar" class="print_hide btn-toolbar">
<button onclick="printdoc()" class="btn btn-info btn-sm pull-right">
<span class="glyphicon glyphicon-print">&nbsp;</span><?= lang('Common.print') ?>
</button>
<button type="button" class="btn btn-primary" onclick="window.print()" title="<?= lang('Common.print') ?>">
<i class="bi bi-printer me-2"></i><?= lang('Common.print') ?>
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<span class="glyphicon glyphicon-tags">&nbsp;</span><?= lang(ucfirst($controller_name) . '.new') ?>
</button>
</div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" id="delete" class="btn btn-secondary d-print-none">
<i class="bi bi-trash"></i><span class="d-none d-sm-inline ms-2"><?= lang('Common.delete') ?></span>
<div class="pull-left form-inline" role="toolbar">
<button id="delete" class="btn btn-default btn-sm print_hide">
<span class="glyphicon glyphicon-trash">&nbsp;</span><?= lang('Common.delete') ?>
</button>
<div class="input-group w-auto">
<span class="input-group-text" id="daterangepicker-icon"><i class="bi bi-calendar2-range"></i></span>
<input type="text" class="form-select" name="daterangepicker" id="daterangepicker" aria-describedby="daterangepicker-icon">
</div>
<div class="input-group w-auto">
<span class="input-group-text" id="filters-icon"><i class="bi bi-funnel"></i></span>
<select class="form-select" name="filters[]" id="filters" aria-describedby="filters-icon" multiple>
<?php foreach (esc($filters) as $value => $label) { ?>
<option value="<?= $value ?>" <?= in_array($value, $selected_filters ?? []) ? 'selected' : '' ?>>
<?= $label ?>
</option>
<?php } ?>
</select>
</div>
<?= form_input(['name' => 'daterangepicker', 'class' => 'form-control input-sm', 'id' => 'daterangepicker']) ?>
<?= form_multiselect('filters[]', esc($filters), $selected_filters ?? [], [
'id' => 'filters',
'data-none-selected-text' => lang('Common.none_selected_text'),
'class' => 'selectpicker show-menu-arrow',
'data-selected-text-format' => 'count > 1',
'data-style' => 'btn-default btn-sm',
'data-width' => 'fit'
]) ?>
</div>
</div>
@@ -99,15 +87,3 @@ echo view('configs/config_header', $title_info);
<div id="payment_summary"></div>
<?= view('partial/footer') ?>
<script type="text/javascript">
new TomSelect('#filters', {
plugins: ['checkbox_options', 'remove_button'],
placeholder: '<?= lang('Common.none_selected_text') ?>',
hidePlaceholder: true,
closeAfterSelect: false,
onChange: function() {
$('#table').bootstrapTable('refresh');
}
});
</script>

View File

@@ -5,22 +5,37 @@
*/
?>
<?= form_open("expenses_categories/save/$category_info->expense_category_id", ['id' => 'expense_category_edit_form']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open("expenses_categories/save/$category_info->expense_category_id", ['id' => 'expense_category_edit_form', 'class' => 'form-horizontal']) ?>
<fieldset id="expenses_categories">
<label for="category_name" class="form-label"><?= lang('Expenses_categories.name'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="category_name-icon"><i class="bi bi-bookmark"></i></span>
<input type="text" class="form-control" name="category_name" id="category_name" aria-describedby="category_name-icon" value="<?= $category_info->category_name; ?>" required>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Expenses_categories.name'), 'category_name', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'category_name',
'id' => 'category_name',
'class' => 'form-control input-sm',
'value' => $category_info->category_name
]) ?>
</div>
</div>
<label for="category_description" class="form-label"><?= lang('Expenses_categories.description'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="category_description-icon"><i class="bi bi-card-text"></i></span>
<textarea class="form-control" name="category_description" id="category_description" rows="10" aria-describedby="category_description-icon"><?= $category_info->category_description ?></textarea>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Expenses_categories.description'), 'category_description', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_textarea([
'name' => 'category_description',
'id' => 'category_description',
'class' => 'form-control input-sm',
'value' => $category_info->category_description
]) ?>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">

View File

@@ -8,11 +8,6 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = 'Expenses Categories';
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
$(document).ready(function() {
<?= view('partial/bootstrap_tables_locale') ?>
@@ -32,16 +27,16 @@ echo view('configs/config_header', $title_info);
});
</script>
<div class="d-flex gap-2 justify-content-end">
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= esc("$controller_name/view") ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<i class="bi bi-bookmark-plus me-2"></i><?= lang(ucfirst($controller_name) . '.new') ?>
<div id="title_bar" class="btn-toolbar">
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= esc("$controller_name/view") ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<span class="glyphicon glyphicon-list">&nbsp;</span><?= lang(ucfirst($controller_name) . '.new') ?>
</button>
</div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary" id="delete">
<i class="bi bi-trash"></i><span class="d-none d-sm-inline ms-2"><?= lang('Common.delete') ?></span>
<div class="pull-left form-inline" role="toolbar">
<button id="delete" class="btn btn-default btn-sm print_hide">
<span class="glyphicon glyphicon-trash">&nbsp;</span><?= lang('Common.delete') ?>
</button>
</div>
</div>

View File

@@ -10,42 +10,65 @@
*/
?>
<?= form_open("giftcards/save/$giftcard_id", ['id' => 'giftcard_form']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open("giftcards/save/$giftcard_id", ['id' => 'giftcard_form', 'class' => 'form-horizontal']) ?>
<fieldset id="giftcard_basic_info">
<label for="person_name" class="form-label"><?= lang('Giftcards.person_id'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="person_name-icon"><i class="bi bi-person"></i></span>
<input type="hidden" name="person_id" value="<?= (string)$selected_person_id ?>">
<input type="text" class="form-control" name="person_name" id="person_name" aria-describedby="person_name-icon" value="<?= $selected_person_name ?>">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Giftcards.person_id'), 'person_name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'person_name',
'id' => 'person_name',
'class' => 'form-control input-sm',
'value' => $selected_person_name
]) ?>
<?= form_hidden('person_id', (string)$selected_person_id) ?>
</div>
</div>
<?php
$class = '';
$label = '';
if ($config['giftcard_number'] == 'series') {
$class = 'required';
$label = '<sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup>';
}
?>
<label for="giftcard_number" class="form-label"><?= lang('Giftcards.giftcard_number'); ?><?= $label ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="giftcard_number-icon"><i class="bi bi-gift"></i></span>
<input type="text" class="form-control" name="giftcard_number" id="giftcard_number" aria-describedby="giftcard_number-icon" value="<?= $giftcard_number ?>" <?= $class ?>>
</div>
<?php
$class = '';
if ($config['giftcard_number'] == 'series') {
$class = ' required';
}
?>
<div class="form-group form-group-sm">
<?= form_label(lang('Giftcards.giftcard_number'), 'giftcard_number', ['class' => "control-label col-xs-3$class"]) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'giftcard_number',
'id' => 'giftcard_number',
'class' => 'form-control input-sm',
'value' => $giftcard_number
]) ?>
</div>
</div>
<label for="giftcard_amount" class="form-label"><?= lang('Giftcards.card_value') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="giftcard_amount-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="number" class="form-control" name="giftcard_amount" id="giftcard_amount" aria-describedby="giftcard_amount-icon" value="<?= number_format((float)$giftcard_value, 2, '.', '') ?>" required>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="giftcard_amount-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Giftcards.card_value'), 'giftcard_amount', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<?= form_input([
'name' => 'giftcard_amount',
'id' => 'giftcard_amount',
'class' => 'form-control input-sm',
'value' => to_currency_no_money($giftcard_value)
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">

View File

@@ -8,11 +8,6 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = 'Gift Cards';
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
$(document).ready(function() {
<?= view('partial/bootstrap_tables_locale') ?>
@@ -25,16 +20,16 @@ echo view('configs/config_header', $title_info);
});
</script>
<div class="d-flex gap-2 justify-content-end">
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= esc("$controller_name/view") ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<i class="bi bi-gift me-2"></i><?= lang(ucfirst($controller_name) .'.new') ?>
<div id="title_bar" class="btn-toolbar">
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= esc("$controller_name/view") ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<span class="glyphicon glyphicon-heart">&nbsp;</span><?= lang(ucfirst($controller_name) . '.new') ?>
</button>
</div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary">
<i class="bi bi-trash"></i><span class="d-none d-sm-inline ms-2"><?= lang('Common.delete') ?></span>
<div class="pull-left btn-toolbar">
<button id="delete" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-trash">&nbsp;</span><?= lang('Common.delete') ?>
</button>
</div>
</div>

View File

@@ -0,0 +1,130 @@
<?php
/**
* @var object $person_info
*/
?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<?= form_open("home/save/$person_info->person_id", ['id' => 'employee_form', 'class' => 'form-horizontal']) ?>
<div class="tab-content">
<div class="tab-pane fade in active" id="employee_login_info">
<fieldset>
<div class="form-group form-group-sm">
<?= form_label(lang('Employees.username'), 'username', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-user"></span></span>
<?= form_input([
'name' => 'username',
'id' => 'username',
'class' => 'form-control input-sm',
'value' => $person_info->username,
'readonly' => 'true'
]) ?>
</div>
</div>
</div>
<?php $password_label_attributes = $person_info->person_id == "" ? ['class' => 'required'] : []; ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Employees.current_password'), 'current_password', array_merge($password_label_attributes, ['class' => 'control-label col-xs-3'])) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-lock"></span></span>
<?= form_password([
'name' => 'current_password',
'id' => 'current_password',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Employees.password'), 'password', array_merge($password_label_attributes, ['class' => 'control-label col-xs-3'])) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-lock"></span></span>
<?= form_password([
'name' => 'password',
'id' => 'password',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Employees.repeat_password'), 'repeat_password', array_merge($password_label_attributes, ['class' => 'control-label col-xs-3'])) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-lock"></span></span>
<?= form_password([
'name' => 'repeat_password',
'id' => 'repeat_password',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
</div>
</fieldset>
</div>
</div>
<?= form_close() ?>
<script type="text/javascript">
// Validation and submit handling
$(document).ready(function() {
$.validator.setDefaults({
ignore: []
});
$.validator.addMethod("notEqualTo", function(value, element, param) {
return this.optional(element) || value != $(param).val();
}, '<?= lang('Employees.password_not_must_match') ?>');
$('#employee_form').validate($.extend({
submitHandler: function(form) {
$(form).ajaxSubmit({
success: function(response) {
dialog_support.hide();
$.notify(response.message, {
type: response.success ? 'success' : 'danger'
});
},
dataType: 'json'
});
},
rules: {
current_password: {
required: true,
minlength: 8
},
password: {
required: true,
minlength: 8,
notEqualTo: "#current_password"
},
repeat_password: {
equalTo: "#password"
}
},
messages: {
password: {
required: "<?= lang('Employees.password_required') ?>",
minlength: "<?= lang('Employees.password_minlength') ?>"
},
repeat_password: {
equalTo: "<?= lang('Employees.password_must_match') ?>"
}
}
}, form_support.error));
});
</script>

View File

@@ -6,6 +6,19 @@
<?= view('partial/header') ?>
<?= view('home/modules') ?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<h3 class="text-center"><?= lang('Common.welcome_message') ?></h3>
<div id="home_module_list">
<?php foreach($allowed_modules as $module) { ?>
<div class="module_item" title="<?= lang("Module.$module->module_id" . '_desc') ?>">
<a href="<?= base_url($module->module_id) ?>"><img src="<?= base_url("images/menubar/$module->module_id.svg") ?>" style="border-width: 0; height: 64px; max-width: 64px;" alt="Menubar Image"></a>
<a href="<?= base_url($module->module_id) ?>"><?= lang("Module.$module->module_id") ?></a>
</div>
<?php } ?>
</div>
<?= view('partial/footer') ?>

View File

@@ -1,16 +0,0 @@
<h3 class="text-center pb-3 d-none d-lg-block"><?= lang('Common.welcome_message') ?></h3>
<section class="container-fluid d-flex flex-wrap justify-content-center gap-3 p-0 py-1 py-lg-0">
<?php foreach ($allowed_modules as $module) { ?>
<div class="border border-primary rounded shadow-sm bg-primary-subtle text-center d-block" title="<?= lang("Module.$module->module_id" . '_desc') ?>">
<a href="<?= base_url($module->module_id) ?>">
<img class="d-block mx-auto p-2" src="<?= base_url("images/menubar/$module->module_id.svg") ?>" alt="Menubar Image"> <!-- TODO-BS5 alt text translatable -->
</a>
<a href="<?= base_url($module->module_id) ?>">
<div class="tile-text rounded-bottom d-block bg-primary text-light fw-bold p-2">
<span><?= lang("Module.$module->module_id") ?></span>
</div>
</a>
</div>
<?php } ?>
</section>

View File

@@ -6,6 +6,19 @@
<?= view('partial/header') ?>
<?= view('home/modules') ?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<h3 class="text-center"><?= lang('Common.welcome_message') ?></h3>
<div id="office_module_list">
<?php foreach ($allowed_modules as $module) { ?>
<div class="module_item" title="<?= lang("Module.$module->module_id" . '_desc') ?>">
<a href="<?= base_url($module->module_id) ?>"><img src="<?= base_url("images/menubar/$module->module_id.svg") ?>" style="border-width: 0; height: 64px; max-width: 64px;" alt="Menubar Image"></a>
<a href="<?= base_url($module->module_id) ?>"><?= lang("Module.$module->module_id") ?></a>
</div>
<?php } ?>
</div>
<?= view('partial/footer') ?>

View File

@@ -1,137 +0,0 @@
<?php
$email = $user_info->email;
$size = 96;
$default = 'https://ui-avatars.com/api/?name=' . $user_info->first_name . '+' . $user_info->last_name . '&format=svg&size=' . $size;
$grav_url = 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($email))) . '?d=' . urlencode($default) . '&s=' . $size;
?>
<div class="modal fade" id="profile-modal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<ul class="nav nav-pills nav-justified w-100 me-1 gap-1">
<li class="nav-item">
<button type="button" id="modal-button-profile" onclick="modalSwitchProfile()" class="nav-link active">Profile</button>
</li>
<li class="nav-item" title="<?= lang('Employees.change_password'); ?>">
<button type="button" id="modal-button-password" onclick="modalSwitchPassword()" class="nav-link"><?= lang('Employees.change_password'); ?></button>
</li>
</ul>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body text-start">
<div id="modal-profile">
<div class="container">
<table>
<tbody>
<tr>
<td class="pe-2"><img class="img-thumbnail rounded-circle" src="<?= $default; ?>" style="height: 48px;"></td>
<td class="align-middle"><h5><?= $user_info->first_name . '&nbsp;' . $user_info->last_name; ?></h5></td>
</tr>
</tbody>
</table>
<br>
<table>
<tbody>
<tr>
<td class="pe-3">Username</td>
<td><?= $user_info->username; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.id'); ?></td>
<td><?= $user_info->person_id; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.email'); ?></td>
<td><?= $user_info->email; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.phone_number'); ?></td>
<td><?= $user_info->phone_number; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.gender'); ?></td>
<td><?= $user_info->gender; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.address_1'); ?></td>
<td><?= $user_info->address_1; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.address_2'); ?></td>
<td><?= $user_info->address_2; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.city'); ?></td>
<td><?= $user_info->city; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.state'); ?></td>
<td><?= $user_info->state; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.zip'); ?></td>
<td><?= $user_info->zip; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.country'); ?></td>
<td><?= $user_info->country; ?></td>
</tr>
<tr>
<td class="pe-3"><?= lang('Common.comments'); ?></td>
<td><?= $user_info->comments; ?></td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="modal-password" class="d-none was-validated" novalidate>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-person"></i></span>
<div class="form-floating">
<input name="username" id="input-username" type="text" class="form-control" placeholder="<?= lang('Login.username'); ?>" value="<?= $user_info->username; ?>" disabled>
<label for="input-username"><?= lang('Login.username'); ?></label>
</div>
</div>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<div class="form-floating is-invalid">
<input name="password-current" id="input-password-current" type="password" class="form-control" placeholder="Current Password" required>
<label for="input-password-current">Current Password</label>
</div>
<div class="invalid-feedback">Please fill in your current password.</div>
</div>
<div class="form-text">Must be 8-20 characters long</div>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<div class="form-floating is-invalid">
<input name="password-new" id="input-password-new" type="password" class="form-control" placeholder="New Password" required>
<label for="input-password-new">New Password</label>
</div>
<div class="invalid-feedback">Please fill in a new password.</div>
</div>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<div class="form-floating is-invalid">
<input name="password-repeat" id="input-password-repeat" type="password" class="form-control" placeholder="Repeat Password" required>
<label for="input-password-repeat">Repeat Password</label>
</div>
<div class="invalid-feedback">Please repeat the new password.</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<a type="button" id="modal-button-logout" class="btn btn-danger" href="home/logout">
<i class="bi bi-power me-2"></i><?= lang('Login.logout'); ?>
</a>
<button type="button" id="modal-button-save" class="btn btn-primary d-none">
<i class="bi bi-floppy me-2"></i>Save
</button>
</div>
</div>
</div>
</div>

View File

@@ -8,114 +8,200 @@
*/
?>
<?= form_open("item_kits/save/$item_kit_info->item_kit_id", ['id' => 'item_kit_form']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open("item_kits/save/$item_kit_info->item_kit_id", ['id' => 'item_kit_form', 'class' => 'form-horizontal']) ?>
<fieldset id="item_kit_basic_info">
<label for="item_kit_number" class="form-label"><?= lang('Item_kits.item_kit_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="item_kit_number-icon"><i class="bi bi-upc-scan"></i></span>
<input type="text" class="form-control" name="item_kit_number" id="item_kit_number" aria-describedby="item_kit_number-icon" value="<?= $item_kit_info->item_kit_number ?>">
</div>
<label for="name" class="form-label"><?= lang('Item_kits.name'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="name-icon"><i class="bi bi-tags"></i></span>
<input type="text" class="form-control" name="name" id="name" aria-describedby="name-icon" value="<?= $item_kit_info->name ?>" required>
</div>
<label for="item_name" class="form-label"><?= lang('Item_kits.find_kit_item'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="item_name-icon"><i class="bi bi-tag"></i></span>
<input type="hidden" name="kit_item_id" value="<?= (string)$selected_kit_item_id ?>">
<input type="text" class="form-control" name="item_name" id="item_name" aria-describedby="item_name-icon" value="<?= $selected_kit_item ?>">
</div>
<label for="kit_discount_type" class="form-label"><?= lang('Item_kits.discount_type') ?></label>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="kit_discount_type" id="kit_discount_type_percent" value="0" <?= $item_kit_info->kit_discount_type == PERCENT ? 'checked' : '' ?>>
<label class="form-check-label" for="kit_discount_type_percent"><?= lang('Item_kits.discount_percent') ?></label>
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.item_kit_number'), 'item_kit_number', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-barcode"></span></span>
<?= form_input([
'name' => 'item_kit_number',
'id' => 'item_kit_number',
'class' => 'form-control input-sm',
'value' => $item_kit_info->item_kit_number
]) ?>
</div>
</div>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="kit_discount_type" id="kit_discount_type_fixed" value="1" <?= $item_kit_info->kit_discount_type == FIXED ? 'checked' : '' ?>>
<label class="form-check-label" for="kit_discount_type_fixed"><?= lang('Item_kits.discount_fixed') ?></label>
</div>
</div>
<label for="kit_discount" class="form-label"><?= lang('Item_kits.discount'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="kit_discount-icon"><i class="bi bi-patch-minus"></i></span>
<input type="number" step="any" class="form-control" name="kit_discount" id="kit_discount" aria-describedby="kit_discount-icon" value="<?= $item_kit_info->kit_discount_type === FIXED ? to_currency_no_money($item_kit_info->kit_discount) : to_decimals($item_kit_info->kit_discount) ?>">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.name'), 'name', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'name',
'id' => 'name',
'class' => 'form-control input-sm',
'value' => $item_kit_info->name
]) ?>
</div>
</div>
<label for="price_option" class="form-label"><?= lang('Item_kits.price_option') ?> <?= !empty($basic_version) ? '<sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup>' : '' ?></label>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="price_option" id="price_option_kit_and_components" value="0" <?= $item_kit_info->price_option == PRICE_ALL ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="price_option_kit_and_components"><?= lang('Item_kits.kit_and_components') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="price_option" id="price_option_kit_only" value="1" <?= $item_kit_info->price_option == PRICE_KIT ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="price_option_kit_only"><?= lang('Item_kits.kit_only') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="price_option" id="price_option_kit_and_stock" value="2" <?= $item_kit_info->price_option == PRICE_KIT_ITEMS ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="price_option_kit_and_stock"><?= lang('Item_kits.kit_and_stock') ?></label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.find_kit_item'), 'item_name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'item_name',
'id' => 'item_name',
'class' => 'form-control input-sm',
'size' => '50',
'value' => $selected_kit_item
]) ?>
<?= form_hidden('kit_item_id', (string)$selected_kit_item_id) ?>
<label for="print_option" class="form-label"><?= lang('Item_kits.print_option') ?> <?= !empty($basic_version) ? '<sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup>' : '' ?></label>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="print_option" id="print_option_all" value="0" <?= $item_kit_info->print_option == PRINT_ALL ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="print_option_all"><?= lang('Item_kits.all') ?></label>
</div>
</div>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="print_option" id="print_option_priced_only" value="1" <?= $item_kit_info->print_option == PRINT_PRICED ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="print_option_priced_only"><?= lang('Item_kits.priced_only') ?></label>
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.discount_type'), 'kit_discount_type', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'kit_discount_type',
'type' => 'radio',
'value' => 0,
'checked' => $item_kit_info->kit_discount_type == PERCENT
]) ?> <?= lang('Item_kits.discount_percent') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'kit_discount_type',
'type' => 'radio',
'value' => 1,
'checked' => $item_kit_info->kit_discount_type == FIXED
]) ?> <?= lang('Item_kits.discount_fixed') ?>
</label>
</div>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="print_option" id="print_option_kit_only" value="2" <?= $item_kit_info->print_option == PRINT_KIT ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="print_option_kit_only"><?= lang('Item_kits.kit_only') ?></label>
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.discount'), 'kit_discount', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-3">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'kit_discount',
'size' => '5',
'maxlength' => '5',
'id' => 'kit_discount',
'class' => 'form-control input-sm',
'value' => $item_kit_info->kit_discount_type === FIXED ? to_currency_no_money($item_kit_info->kit_discount) : to_decimals($item_kit_info->kit_discount)
]) ?>
</div>
</div>
</div>
</div>
<label for="description" class="form-label"><?= lang('Item_kits.description'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-chat"></i></span>
<textarea class="form-control" name="description" id="description" rows="6"><?= $item_kit_info->description ?></textarea>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.price_option'), 'price_option', !empty($basic_version) ? ['class' => 'required control-label col-xs-3'] : ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'price_option',
'type' => 'radio',
'value' => 0,
'checked' => $item_kit_info->price_option == PRICE_ALL
]) ?> <?= lang('Item_kits.kit_and_components') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'price_option',
'type' => 'radio',
'value' => 1,
'checked' => $item_kit_info->price_option == PRICE_KIT
]) ?> <?= lang('Item_kits.kit_only') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'price_option',
'type' => 'radio',
'value' => 2,
'checked' => $item_kit_info->price_option == PRICE_KIT_ITEMS // TODO: === for all of these?
]) ?> <?= lang('Item_kits.kit_and_stock') ?>
</label>
</div>
</div>
<label for="item" class="form-label"><?= lang('Item_kits.add_item'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="item-icon"><i class="bi bi-tag"></i></span>
<input type="text" class="form-control" name="item" id="item" aria-describedby="item-icon">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.print_option'), 'print_option', !empty($basic_version) ? ['class' => 'required control-label col-xs-3'] : ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'print_option',
'type' => 'radio',
'value' => 0,
'checked' => $item_kit_info->print_option == PRINT_ALL
]) ?> <?= lang('Item_kits.all') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'print_option',
'type' => 'radio',
'value' => 1,
'checked' => $item_kit_info->print_option == PRINT_PRICED
]) ?> <?= lang('Item_kits.priced_only') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'print_option',
'type' => 'radio',
'value' => 2,
'checked' => $item_kit_info->print_option == PRINT_KIT
]) ?> <?= lang('Item_kits.kit_only') ?>
</label>
</div>
</div>
<div class="table-responsive">
<table class="table table-sm table-hover align-middle text-nowrap" id="item_kit_items">
<thead class="table-secondary">
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.description'), 'description', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_textarea([
'name' => 'description',
'id' => 'description',
'class' => 'form-control input-sm',
'value' => $item_kit_info->description
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Item_kits.add_item'), 'item', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'item',
'id' => 'item',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
<table id="item_kit_items" class="table table-striped table-hover">
<thead>
<tr>
<th scope="col"><?= lang('Common.delete') ?></th>
<th scope="col"><?= lang('Item_kits.sequence') ?></th>
<th scope="col"><?= lang('Item_kits.item') ?></th>
<th scope="col"><?= lang('Item_kits.quantity') ?></th>
<th style="width: 10%;"><?= lang('Common.delete') ?></th>
<th style="width: 10%;"><?= lang('Item_kits.sequence') ?></th>
<th style="width: 60%;"><?= lang('Item_kits.item') ?></th>
<th style="width: 20%;"><?= lang('Item_kits.quantity') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($item_kit_items as $item_kit_item): ?>
<?php foreach ($item_kit_items as $item_kit_item) { ?>
<tr>
<td class="text-center"><a class="text-danger" href="#" onclick="return delete_item_kit_row(this);"><i class="bi bi-trash"></i></a></td>
<td class="text-center"><input class="quantity form-control" id="item_seq_<?= $item_kit_item['item_id'] ?>" name="item_kit_seq[<?= $item_kit_item['item_id'] ?>]" value="<?= parse_decimals($item_kit_item['kit_sequence'], 0) ?>"></td>
<td><a href="#" onclick="return delete_item_kit_row(this);"><span class="glyphicon glyphicon-trash"></span></a></td>
<td><input class="quantity form-control input-sm" id="item_seq_<?= $item_kit_item['item_id'] ?>" name="item_kit_seq[<?= $item_kit_item['item_id'] ?>]" value="<?= parse_decimals($item_kit_item['kit_sequence'], 0) ?>"></td>
<td><?= esc($item_kit_item['name']) ?></td>
<td class="text-center"><input class="quantity form-control" id="item_qty_<?= $item_kit_item['item_id'] ?>" name="item_kit_qty[<?= $item_kit_item['item_id'] ?>]" value="<?= to_quantity_decimals($item_kit_item['quantity']) ?>"></td>
<td><input class="quantity form-control input-sm" id="item_qty_<?= $item_kit_item['item_id'] ?>" name="item_kit_qty[<?= $item_kit_item['item_id'] ?>]" value="<?= to_quantity_decimals($item_kit_item['quantity']) ?>"></td>
</tr>
<?php endforeach; ?>
<?php } ?>
</tbody>
</table>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">
@@ -132,10 +218,10 @@
$('#item_kit_item_' + ui.item.value).val(parseFloat($('#item_kit_item_' + ui.item.value).val()) + 1);
} else {
$('#item_kit_items').append('<tr>' +
'<td class="text-center"><a class="text-danger" href="#" onclick="return delete_item_kit_row(this);"><i class="bi bi-trash"></i></a></td>' +
'<td class="text-center"><input class="quantity form-control" id="item_seq_' + ui.item.value + '" name="item_kit_seq[' + ui.item.value + ']" value="0"></td>' +
'<td><a href="#" onclick="return delete_item_kit_row(this);"><span class="glyphicon glyphicon-trash"></span></a></td>' +
'<td><input class="quantity form-control input-sm" id="item_seq_' + ui.item.value + '" name="item_kit_seq[' + ui.item.value + ']" value="0"></td>' +
'<td>' + DOMPurify.sanitize(ui.item.label) + '</td>' +
'<td class="text-center"><input class="quantity form-control" id="item_qty_' + ui.item.value + '" name="item_kit_qty[' + ui.item.value + ']" value="1"></td>' +
'<td><input class="quantity form-control input-sm" id="item_qty_' + ui.item.value + '" name="item_kit_qty[' + ui.item.value + ']" value="1"></td>' +
'</tr>');
}
$('#item').val('');

View File

@@ -8,11 +8,6 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = 'Item Kits';
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
$(document).ready(function() {
<?= view('partial/bootstrap_tables_locale') ?>
@@ -33,19 +28,20 @@ echo view('configs/config_header', $title_info);
});
</script>
<div class="d-flex gap-2 justify-content-end">
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= esc("$controller_name/view") ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<i class="bi bi-tags me-2"></i><?= lang(ucfirst($controller_name) . '.new') ?>
<div id="title_bar" class="btn-toolbar">
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= esc("$controller_name/view") ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<span class="glyphicon glyphicon-tags">&nbsp;</span><?= lang(ucfirst($controller_name) . '.new') ?>
</button>
</div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary" id="delete">
<i class="bi bi-trash"></i><span class="d-none d-sm-inline ms-2"><?= lang('Common.delete') ?></span>
<div class="pull-left btn-toolbar">
<button id="delete" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-trash">&nbsp;</span><?= lang('Common.delete') ?>
</button>
<button type="button" class="btn btn-secondary" id="generate_barcodes" data-href="<?= esc("$controller_name/generateBarcodes") ?>" title="<?= lang('Items.generate_barcodes') ?>">
<i class="bi bi-upc-scan"></i><span class="d-none d-sm-inline ms-2"><?= lang('Items.generate_barcodes') ?></span>
<button id="generate_barcodes" class="btn btn-default btn-sm" data-href="<?= esc("$controller_name/generateBarcodes") ?>">
<span class="glyphicon glyphicon-barcode">&nbsp;</span><?= lang('Items.generate_barcodes') ?>
</button>
</div>
</div>

View File

@@ -25,226 +25,430 @@
*/
?>
<?= form_open("items/save/$item_info->item_id", ['id' => 'item_form', 'enctype' => 'multipart/form-data']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open("items/save/$item_info->item_id", ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<fieldset id="item_basic_info">
<label for="item_number" class="form-label"><?= lang('Items.item_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="item_number-icon"><i class="bi bi-upc-scan"></i></span>
<input type="text" class="form-control" name="item_number" id="item_number" aria-describedby="item_number-icon" value="<?= $item_info->item_number ?>">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.item_number'), 'item_number', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-barcode"></span></span>
<?= form_input([
'name' => 'item_number',
'id' => 'item_number',
'class' => 'form-control input-sm',
'value' => $item_info->item_number
]) ?>
</div>
</div>
</div>
<label for="name" class="form-label"><?= lang('Items.name'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="name-icon"><i class="bi bi-tag"></i></span>
<input type="text" class="form-control" name="name" id="name" aria-describedby="name-icon" value="<?= $item_info->name ?>">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.name'), 'name', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'name',
'id' => 'name',
'class' => 'form-control input-sm',
'value' => $item_info->name
]) ?>
</div>
</div>
<label for="category" class="form-label"><?= lang('Items.category'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="category-icon"><i class="bi bi-bookmark"></i></span>
<?php if ($config['category_dropdown']) { ?>
<select class="form-select" name="category" id="category" required>
<?php foreach ($categories as $key => $value) { ?>
<option value="<?= $key ?>" <?= $selected_category == $key ? 'selected' : '' ?>><?= $value ?></option>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.category'), 'category', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-tag"></span></span>
<?php
if ($config['category_dropdown']) {
echo form_dropdown('category', $categories, $selected_category, ['class' => 'form-control']);
} else {
echo form_input([
'name' => 'category',
'id' => 'category',
'class' => 'form-control input-sm',
'value' => $item_info->category
]);
}
?>
</div>
</div>
</div>
<div id="attributes">
<script type="text/javascript">
$('#attributes').load('<?= "items/attributes/$item_info->item_id" ?>');
</script>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.stock_type'), 'stock_type', !empty($basic_version) ? ['class' => 'required control-label col-xs-3'] : ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?= form_radio([
'name' => 'stock_type',
'type' => 'radio',
'id' => 'stock_type',
'value' => 0,
'checked' => $item_info->stock_type == HAS_STOCK
]) ?> <?= lang('Items.stock') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'stock_type',
'type' => 'radio',
'id' => 'stock_type',
'value' => 1,
'checked' => $item_info->stock_type == HAS_NO_STOCK
]) ?><?= lang('Items.nonstock') ?>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.type'), 'item_type', !empty($basic_version) ? ['class' => 'required control-label col-xs-3'] : ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<label class="radio-inline">
<?php
$radio_button = [
'name' => 'item_type',
'type' => 'radio',
'id' => 'item_type',
'value' => 0,
'checked' => $item_info->item_type == ITEM
];
if ($standard_item_locked) {
$radio_button['disabled'] = true;
}
echo form_radio($radio_button) ?> <?= lang('Items.standard') ?>
</label>
<label class="radio-inline">
<?php
$radio_button = [
'name' => 'item_type',
'type' => 'radio',
'id' => 'item_type',
'value' => 1,
'checked' => $item_info->item_type == ITEM_KIT
];
if ($item_kit_disabled) {
$radio_button['disabled'] = true;
}
echo form_radio($radio_button) ?> <?= lang('Items.kit') ?>
</label>
<?php if ($config['derive_sale_quantity'] == '1') { ?>
<label class="radio-inline">
<?= form_radio([
'name' => 'item_type',
'type' => 'radio',
'id' => 'item_type',
'value' => 2,
'checked' => $item_info->item_type == ITEM_AMOUNT_ENTRY
]) ?><?= lang('Items.amount_entry') ?>
</label>
<?php } ?>
<?php if ($allow_temp_item == 1) { ?>
<label class="radio-inline">
<?= form_radio([
'name' => 'item_type',
'type' => 'radio',
'id' => 'item_type',
'value' => 3,
'checked' => $item_info->item_type == ITEM_TEMP
]) ?> <?= lang('Items.temp') ?>
</label>
<?php } ?>
</select>
<?php } else { ?>
<input type="text" class="form-control" name="category" id="category" aria-describedby="category-icon" value="<?= $item_info->category ?>" required>
<?php } ?>
</div>
<div id="attributes">
<script type="text/javascript">
$('#attributes').load('<?= "items/attributes/$item_info->item_id" ?>');
</script>
</div>
<label for="stock_type" class="form-label"><?= lang('Items.stock_type') ?><?= !empty($basic_version) ? '<sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup>' : '' ?></label>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="stock_type" id="stock_type_stock" value="0" <?= $item_info->stock_type == HAS_STOCK ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="stock_type_stock"><?= lang('Items.stock') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="stock_type" id="stock_type_nonstock" value="1" <?= $item_info->stock_type == HAS_NO_STOCK ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="stock_type_nonstock"><?= lang('Items.nonstock') ?></label>
</div>
</div>
<label for="item_type" class="form-label"><?= lang('Items.type') ?><?= !empty($basic_version) ? '<sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup>' : '' ?></label>
<div class="mb-3">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="item_type" id="item_type_standard" value="0" <?= $item_info->item_type == ITEM ? 'checked' : '' ?> <?= $standard_item_locked ? 'disabled readonly' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="item_type_standard"><?= lang('Items.standard') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="item_type" id="item_type_kit" value="1" <?= $item_info->item_type == ITEM_KIT ? 'checked' : '' ?> <?= $item_kit_disabled ? 'disabled readonly' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="item_type_kit"><?= lang('Items.kit') ?></label>
</div>
<?php if ($config['derive_sale_quantity'] == '1') { ?>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="item_type" id="item_type_amount_entry" value="2" <?= $item_info->item_type == ITEM_AMOUNT_ENTRY ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="item_type_amount_entry"><?= lang('Items.amount_entry') ?></label>
</div>
<?php } ?>
<?php if ($allow_temp_item == 1) { ?>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="item_type" id="item_type_temp" value="3" <?= $item_info->item_type == ITEM_TEMP ? 'checked' : '' ?> <?= !empty($basic_version) ? 'required' : '' ?>>
<label class="form-check-label" for="item_type_temp"><?= lang('Items.temp') ?></label>
</div>
<?php } ?>
</div>
<label for="supplier_id" class="form-label"><?= lang('Items.supplier'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-truck"></i></span>
<select class="form-select" name="supplier_id" id="supplier_id">
<?php foreach ($suppliers as $key => $value) { ?>
<option value="<?= $key ?>" <?= $selected_supplier == $key ? 'selected' : '' ?>><?= $value ?></option>
<?php } ?>
</select>
</div>
<label for="cost_price" class="form-label"><?= lang('Items.cost_price') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="cost_price-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="number" step="any" class="form-control" name="cost_price" id="cost_price" aria-describedby="cost_price-icon" value="<?= to_currency_no_money($item_info->cost_price) ?>" required>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="cost_price-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<label for="unit_price" class="form-label"><?= lang('Items.unit_price') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="unit_price-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="number" step="any" class="form-control" name="unit_price" id="unit_price" aria-describedby="unit_price-icon" value="<?= to_currency_no_money($item_info->unit_price) ?>" required>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="unit_price-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<?php if (!$use_destination_based_tax): ?>
<label for="tax_name_1" class="form-label"><?= lang('Items.tax_1') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="tax_name_1-icon"><i class="bi bi-piggy-bank"></i></span>
<input type="text" class="form-control w-25" name="tax_names[]" id="tax_name_1" aria-describedby="tax_name_1-icon" value="<?= $item_tax_info[0]['name'] ?? $config['default_tax_1_name'] ?>">
<input type="number" step="any" min="0" max="100" class="form-control" name="tax_percents[]" id="tax_percent_name_1" aria-describedby="tax_percent_name_1-icon" value="<?= isset($item_tax_info[0]['percent']) ? to_tax_decimals($item_tax_info[0]['percent']) : to_tax_decimals($default_tax_1_rate) ?>">
<span class="input-group-text" id="tax_percent_name_1-icon"><i class="bi bi-percent"></i></span>
</div>
<label for="tax_name_2" class="form-label"><?= lang('Items.tax_2') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="tax_name_2-icon"><i class="bi bi-piggy-bank"></i></span>
<input type="text" class="form-control w-25" name="tax_names[]" id="tax_name_2" aria-describedby="tax_name_2-icon" value="<?= $item_tax_info[1]['name'] ?? $config['default_tax_2_name'] ?>">
<input type="number" step="any" min="0" max="100" class="form-control" name="tax_percents[]" id="tax_percent_name_2" aria-describedby="tax_percent_name_2-icon" value="<?= isset($item_tax_info[1]['percent']) ? to_tax_decimals($item_tax_info[1]['percent']) : to_tax_decimals($default_tax_2_rate) ?>">
<span class="input-group-text" id="tax_percent_name_2-icon"><i class="bi bi-percent"></i></span>
</div>
<?php endif; ?>
<?php if ($use_destination_based_tax): ?>
<label for="tax_category" class="form-label"><?= lang('Taxes.tax_category') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="tax_category-icon"><i class="bi bi-piggy-bank"></i></span>
<input type="hidden" name="tax_category_id" id="tax_category_id" value="<?= $tax_category_id ?>">
<input type="text" class="form-control" name="tax_category" id="tax_category" aria-describedby="tax_category-icon" value="<?= $tax_category ?>">
</div>
<?php endif; ?>
<?php if ($include_hsn): ?>
<label for="hsn_code" class="form-label"><?= lang('Items.hsn_code'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="hsn_code-icon"><i class="bi bi-123"></i></span>
<input type="text" class="form-control" name="hsn_code" id="hsn_code" aria-describedby="hsn_code-icon" value="<?= $hsn_code ?>">
</div>
<?php endif; ?>
<?php foreach ($stock_locations as $key => $location_detail): ?>
<label for="quantity_<?= $key ?>" class="form-label"><?= lang('Items.quantity') . ' ' . $location_detail['location_name'] ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="quantity_<?= $key ?>-icon"><i class="bi bi-boxes"></i></span>
<input type="text" class="form-control" name="quantity_<?= $key ?>" id="quantity_<?= $key ?>" aria-describedby="quantity_<?= $key ?>-icon" value="<?= isset($item_info->item_id) ? to_quantity_decimals($location_detail['quantity']) : to_quantity_decimals(0) ?>" required>
</div>
<?php endforeach; ?>
<label for="receiving_quantity" class="form-label"><?= lang('Items.receiving_quantity') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="receiving_quantity-icon"><i class="bi bi-truck"></i></span>
<input type="text" class="form-control" name="receiving_quantity" id="receiving_quantity" aria-describedby="receiving_quantity-icon" value="<?= isset($item_info->item_id) ? to_quantity_decimals($item_info->receiving_quantity) : to_quantity_decimals(0) ?>">
</div>
<label for="reorder_level" class="form-label"><?= lang('Items.reorder_level') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="reorder_level-icon"><i class="bi bi-list-ol"></i></span>
<input type="text" class="form-control" name="reorder_level" id="reorder_level" aria-describedby="reorder_level-icon" value="<?= isset($item_info->item_id) ? to_quantity_decimals($item_info->reorder_level) : to_quantity_decimals(0) ?>">
</div>
<label for="description" class="form-label"><?= lang('Items.description'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-chat"></i></span>
<textarea class="form-control" name="description" id="description" rows="6"><?= $item_info->description ?></textarea>
</div>
<label for="items_image" class="form-label"><?= lang('Items.image'); ?></label>
<div id="items_image" class="w-100 fileinput <?= $logo_exists ? 'fileinput-exists' : 'fileinput-new'; ?>" data-provides="fileinput">
<div class="input-group mb-3" aria-describedby="company-logo-desc">
<span class="input-group-text"><i class="bi bi-image"></i></span>
<div class="fileinput-new form-control rounded-end mb-0" style="height: 200px; cursor: default;"></div>
<div class="fileinput-exists fileinput-preview img-thumbnail form-control rounded-end mb-0 bg-light mh-100" style="height: 200px; cursor: default; background-size: 40px 40px; background-position: 0 0, 20px 20px; background-image: linear-gradient(45deg, white 25%, transparent 25%, transparent 75%, white 75%, white), linear-gradient(45deg, white 25%, transparent 25%, transparent 75%, white 75%, white);">
<img class="mh-100 mw-100" data-src="holder.js/100%x100%" alt="<?= esc(lang('Config.company_logo')) ?>" src="<?= $image_path ?>">
</div>
</div>
<div type="button" class="btn btn-secondary btn-file me-2">
<span class="fileinput-new"><i class="bi bi-hand-index me-2"></i><?= lang('Items.select_image') ?></span>
<span class="fileinput-exists"><i class="bi bi-images me-2"></i><?= lang('Items.change_image') ?></span>
<input type="file" name="items_image" accept="image/*">
</div>
<a type="button" class="btn btn-outline-secondary fileinput-exists" data-dismiss="fileinput">
<i class="bi bi-eraser me-2"></i><?= lang('Items.remove_image') ?>
</a>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" name="allow_alt_description" id="allow_alt_description" value="1" <?= $item_info->allow_alt_description == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="allow_alt_description"><?= lang('Items.allow_alt_description') ?></label>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" name="is_serialized" id="is_serialized" value="1" <?= $item_info->is_serialized == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="is_serialized"><?= lang('Items.is_serialized') ?></label>
</div>
<?php if ($config['multi_pack_enabled'] == '1'): ?>
<label for="qty_per_pack" class="form-label"><?= lang('Items.qty_per_pack') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="qty_per_pack-icon"><i class="bi bi-123"></i></span>
<input type="text" class="form-control" name="qty_per_pack" id="qty_per_pack" aria-describedby="qty_per_pack-icon" value="<?= isset($item_info->item_id) ? to_quantity_decimals($item_info->qty_per_pack) : to_quantity_decimals(0) ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Items.supplier'), 'supplier', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown('supplier_id', $suppliers, $selected_supplier, ['class' => 'form-control']) ?>
</div>
</div>
<label for="pack_name" class="form-label"><?= lang('Items.pack_name') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="pack_name-icon"><i class="bi bi-box2-heart"></i></span>
<input type="text" class="form-control" name="pack_name" id="pack_name" aria-describedby="pack_name-icon" value="<?= $item_info->pack_name ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Items.cost_price'), 'cost_price', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
<?= form_input([
'name' => 'cost_price',
'id' => 'cost_price',
'class' => 'form-control input-sm',
'onClick' => 'this.select();',
'value' => to_currency_no_money($item_info->cost_price)
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
</div>
</div>
</div>
<label for="low_sell_item_name" class="form-label"><?= lang('Items.low_sell_item') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="pack_name-icon"><i class="bi bi-thermometer-low"></i></span>
<input type="hidden" name="low_sell_item_id" value="<?= $selected_low_sell_item_id ?>">
<input type="text" class="form-control" name="low_sell_item_name" id="low_sell_item_name" aria-describedby="low_sell_item_name-icon" value="<?= $selected_low_sell_item ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Items.unit_price'), 'unit_price', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
<?= form_input([
'name' => 'unit_price',
'id' => 'unit_price',
'class' => 'form-control input-sm',
'onClick' => 'this.select();',
'value' => to_currency_no_money($item_info->unit_price)
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" name="is_deleted" id="is_deleted" value="1" <?= $item_info->deleted == 1 ? 'checked' : '' ?>>
<label class="form-check-label" for="is_deleted"><?= lang('Items.is_deleted') ?></label>
</div>
<?php if (!$use_destination_based_tax) { ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.tax_1'), 'tax_percent_1', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'tax_names[]',
'id' => 'tax_name_1',
'class' => 'form-control input-sm',
'value' => $item_tax_info[0]['name'] ?? $config['default_tax_1_name']
]) ?>
</div>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'tax_percents[]',
'id' => 'tax_percent_name_1',
'class' => 'form-control input-sm',
'value' => isset($item_tax_info[0]['percent']) ? to_tax_decimals($item_tax_info[0]['percent']) : to_tax_decimals($default_tax_1_rate)
]) ?>
<span class="input-group-addon input-sm"><b>%</b></span>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.tax_2'), 'tax_percent_2', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'tax_names[]',
'id' => 'tax_name_2',
'class' => 'form-control input-sm',
'value' => $item_tax_info[1]['name'] ?? $config['default_tax_2_name']
]) ?>
</div>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'tax_percents[]',
'class' => 'form-control input-sm',
'id' => 'tax_percent_name_2',
'value' => isset($item_tax_info[1]['percent']) ? to_tax_decimals($item_tax_info[1]['percent']) : to_tax_decimals($default_tax_2_rate)
]) ?>
<span class="input-group-addon input-sm"><b>%</b></span>
</div>
</div>
</div>
<?php } ?>
<?php if ($use_destination_based_tax): ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Taxes.tax_category'), 'tax_category', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'tax_category',
'id' => 'tax_category',
'class' => 'form-control input-sm',
'size' => '50',
'value' => $tax_category
]) ?>
<?= form_hidden('tax_category_id', $tax_category_id) ?>
</div>
</div>
</div>
<?php endif; ?>
<?php if ($include_hsn): ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.hsn_code'), 'category', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<?= form_input([
'name' => 'hsn_code',
'id' => 'hsn_code',
'class' => 'form-control input-sm',
'value' => $hsn_code
]) ?>
</div>
</div>
</div>
<?php endif; ?>
<?php foreach ($stock_locations as $key => $location_detail) { ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.quantity') . ' ' . $location_detail['location_name'], "quantity_$key", ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => "quantity_$key",
'id' => "quantity_$key",
'class' => 'required quantity form-control',
'onClick' => 'this.select();',
'value' => isset($item_info->item_id) ? to_quantity_decimals($location_detail['quantity']) : to_quantity_decimals(0)
]) ?>
</div>
</div>
<?php } ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.receiving_quantity'), 'receiving_quantity', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'receiving_quantity',
'id' => 'receiving_quantity',
'class' => 'required form-control input-sm',
'onClick' => 'this.select();',
'value' => isset($item_info->item_id) ? to_quantity_decimals($item_info->receiving_quantity) : to_quantity_decimals(0)
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.reorder_level'), 'reorder_level', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'reorder_level',
'id' => 'reorder_level',
'class' => 'form-control input-sm',
'onClick' => 'this.select();',
'value' => isset($item_info->item_id) ? to_quantity_decimals($item_info->reorder_level) : to_quantity_decimals(0)
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.description'), 'description', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_textarea([
'name' => 'description',
'id' => 'description',
'class' => 'form-control input-sm',
'value' => $item_info->description
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.image'), 'items_image', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="fileinput <?= $logo_exists ? 'fileinput-exists' : 'fileinput-new' ?>" data-provides="fileinput">
<div class="fileinput-new thumbnail" style="width: 100px; height: 100px;"></div>
<div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 100px; max-height: 100px;">
<img data-src="holder.js/100%x100%" alt="<?= lang('Items.image') ?>"
src="<?= $image_path ?>"
style="max-height: 100%; max-width: 100%;">
</div>
<div>
<span class="btn btn-default btn-sm btn-file">
<span class="fileinput-new"><?= lang('Items.select_image') ?></span>
<span class="fileinput-exists"><?= lang('Items.change_image') ?></span>
<input type="file" name="items_image" accept="image/*">
</span>
<a href="#" class="btn btn-default btn-sm fileinput-exists" data-dismiss="fileinput"><?= lang('Items.remove_image') ?></a>
</div>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.allow_alt_description'), 'allow_alt_description', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'allow_alt_description',
'id' => 'allow_alt_description',
'value' => 1,
'checked' => $item_info->allow_alt_description == 1
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.is_serialized'), 'is_serialized', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'is_serialized',
'id' => 'is_serialized',
'value' => 1,
'checked' => $item_info->is_serialized == 1
]) ?>
</div>
</div>
<?php if ($config['multi_pack_enabled'] == '1') { ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.qty_per_pack'), 'qty_per_pack', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'qty_per_pack',
'id' => 'qty_per_pack',
'class' => 'form-control input-sm',
'value' => isset($item_info->item_id) ? to_quantity_decimals($item_info->qty_per_pack) : to_quantity_decimals(0)
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.pack_name'), 'name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'pack_name',
'id' => 'pack_name',
'class' => 'form-control input-sm',
'value' => $item_info->pack_name
]) ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.low_sell_item'), 'low_sell_item_name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'low_sell_item_name',
'id' => 'low_sell_item_name',
'class' => 'form-control input-sm',
'value' => $selected_low_sell_item
]) ?>
<?= form_hidden('low_sell_item_id', $selected_low_sell_item_id) ?>
</div>
</div>
</div>
<?php } ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.is_deleted'), 'is_deleted', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-1">
<?= form_checkbox([
'name' => 'is_deleted',
'id' => 'is_deleted',
'value' => 1,
'checked' => $item_info->deleted == 1
]) ?>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">

View File

@@ -8,104 +8,165 @@
*/
?>
<?= form_open('items/bulkUpdate/', ['id' => 'item_form']) ?>
<div id="required_fields_message"><?= lang('Items.edit_fields_you_want_to_update') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<div class="mb-3"><?= lang('Items.edit_fields_you_want_to_update') ?></div>
<?= form_open('items/bulkUpdate/', ['id' => 'item_form', 'class' => 'form-horizontal']) ?>
<fieldset id="bulk_item_basic_info">
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.name'), 'name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'name',
'id' => 'name',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
<label for="name" class="form-label"><?= lang('Items.name') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="name-icon"><i class="bi bi-tag"></i></span>
<input type="text" class="form-control" name="name" id="name" aria-describedby="name-icon">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.category'), 'category', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-tag"></span></span>
<?= form_input([
'name' => 'category',
'id' => 'category',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
</div>
<label for="category" class="form-label"><?= lang('Items.category') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="category-icon"><i class="bi bi-bookmark"></i></span>
<input type="text" class="form-control" name="category" id="category" aria-describedby="category-icon">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.supplier'), 'supplier', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown('supplier_id', $suppliers, '', ['class' => 'form-control']) ?>
</div>
</div>
<label for="supplier" class="form-label"><?= lang('Items.supplier'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-truck"></i></span>
<select class="form-select" name="supplier_id" id="supplier">
<?php foreach ($suppliers as $value => $label): ?>
<option value="<?= $value ?>"><?= $label ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.cost_price'), 'cost_price', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
<?= form_input([
'name' => 'cost_price',
'id' => 'cost_price',
'class' => 'form-control input-sm'
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
</div>
</div>
</div>
<label for="cost_price" class="form-label"><?= lang('Items.cost_price') ?></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="cost_price-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="number" step="any" class="form-control" name="cost_price" id="cost_price" aria-describedby="cost_price-icon">
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="cost_price-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<div class="form-group form-group">
<?= form_label(lang('Items.unit_price'), 'unit_price', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
<?= form_input([
'name' => 'unit_price',
'id' => 'unit_price',
'class' => 'form-control input-sm'
]) ?>
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-addon input-sm"><b><?= esc($config['currency_symbol']) ?></b></span>
<?php endif; ?>
</div>
</div>
</div>
<label for="unit_price" class="form-label"><?= lang('Items.unit_price') ?></label>
<div class="input-group mb-3">
<?php if (!is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="unit_price-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
<input type="number" step="any" class="form-control" name="unit_price" id="unit_price" aria-describedby="unit_price-icon">
<?php if (is_right_side_currency_symbol()): ?>
<span class="input-group-text" id="unit_price-icon"><?= esc($config['currency_symbol']) ?></span>
<?php endif; ?>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.tax_1'), 'tax_percent_1', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'tax_names[]',
'id' => 'tax_name_1',
'class' => 'form-control input-sm',
'value' => $config['default_tax_1_name']
]) ?>
</div>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'tax_percents[]',
'id' => 'tax_percent_name_1',
'class' => 'form-control input-sm',
'value' => to_tax_decimals($config['default_tax_1_rate'])
]) ?>
<span class="input-group input-group-addon"><b>%</b></span>
</div>
</div>
</div>
<label for="tax_name_1" class="form-label"><?= lang('Items.tax_1') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="tax_name_1-icon"><i class="bi bi-piggy-bank"></i></span>
<input type="text" class="form-control w-25" name="tax_names[]" id="tax_name_1" aria-describedby="tax_name_1-icon" value="<?= $config['default_tax_1_name'] ?>">
<input type="number" step="any" min="0" max="100" class="form-control" name="tax_percents[]" id="tax_percent_name_1" aria-describedby="tax_percent_name_1-icon" value="<?= to_tax_decimals($config['default_tax_1_rate']) ?>">
<span class="input-group-text" id="tax_percent_name_1-icon"><i class="bi bi-percent"></i></span>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.tax_2'), 'tax_percent_2', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'tax_names[]',
'id' => 'tax_name_2',
'class' => 'form-control input-sm',
'value' => $config['default_tax_2_name']
]) ?>
</div>
<div class="col-xs-4">
<div class="input-group input-group-sm">
<?= form_input([
'name' => 'tax_percents[]',
'id' => 'tax_percent_name_2',
'class' => 'form-control input-sm',
'value' => to_tax_decimals($config['default_tax_2_rate'])
]) ?>
<span class="input-group input-group-addon"><b>%</b></span>
</div>
</div>
</div>
<label for="tax_name_2" class="form-label"><?= lang('Items.tax_2') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="tax_name_2-icon"><i class="bi bi-piggy-bank"></i></span>
<input type="text" class="form-control w-25" name="tax_names[]" id="tax_name_2" aria-describedby="tax_name_2-icon" value="<?= $config['default_tax_2_name'] ?>">
<input type="number" step="any" min="0" max="100" class="form-control" name="tax_percents[]" id="tax_percent_name_2" aria-describedby="tax_percent_name_2-icon" value="<?= to_tax_decimals($config['default_tax_2_rate']) ?>">
<span class="input-group-text" id="tax_percent_name_2-icon"><i class="bi bi-percent"></i></span>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.reorder_level'), 'reorder_level', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'reorder_level',
'id' => 'reorder_level',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
<label for="reorder_level" class="form-label"><?= lang('Items.reorder_level') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="reorder_level-icon"><i class="bi bi-list-ol"></i></span>
<input type="text" class="form-control" name="reorder_level" id="reorder_level" aria-describedby="reorder_level-icon">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.description'), 'description', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_textarea([
'name' => 'description',
'id' => 'description',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
<label for="description" class="form-label"><?= lang('Items.description'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-chat"></i></span>
<textarea class="form-control" name="description" id="description" rows="6"></textarea>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.allow_alt_description'), 'allow_alt_description', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown('allow_alt_description', $allow_alt_description_choices, '', ['class' => 'form-control']) ?>
</div>
</div>
<label for="allow_alt_description" class="form-label"><?= lang('Items.allow_alt_description'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-input-cursor-text"></i></span>
<select class="form-select" name="allow_alt_description" id="allow_alt_description">
<?php foreach ($allow_alt_description_choices as $value => $label): ?>
<option value="<?= $value ?>"><?= $label ?></option>
<?php endforeach; ?>
</select>
</div>
<label for="is_serialized" class="form-label"><?= lang('Items.is_serialized'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-123"></i></span>
<select class="form-select" name="is_serialized" id="is_serialized">
<?php foreach ($serialization_choices as $value => $label): ?>
<option value="<?= $value ?>"><?= $label ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.is_serialized'), 'is_serialized', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown('is_serialized', $serialization_choices, '', ['class' => 'form-control']) ?>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">

View File

@@ -9,74 +9,105 @@ use App\Models\Employee;
use App\Models\Inventory;
?>
<?= form_open('items', ['id' => 'item_form']) ?>
<?= form_open('items', ['id' => 'item_form', 'class' => 'form-horizontal']) ?>
<fieldset id="count_item_basic_info">
<label for="item_number" class="form-label"><?= lang('Items.item_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="item_number-icon"><i class="bi bi-upc-scan"></i></span>
<input type="text" class="form-control" name="item_number" id="item_number" aria-describedby="item_number-icon" value="<?= $item_info->item_number ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.item_number'), 'name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-barcode"></span></span>
<?= form_input([
'name' => 'item_number',
'id' => 'item_number',
'class' => 'form-control input-sm',
'disabled' => '',
'value' => $item_info->item_number
]) ?>
</div>
</div>
</div>
<label for="name" class="form-label"><?= lang('Items.name'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="name-icon"><i class="bi bi-tag"></i></span>
<input type="text" class="form-control" name="name" id="name" aria-describedby="name-icon" value="<?= $item_info->name ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.name'), 'name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'name',
'id' => 'name',
'class' => 'form-control input-sm',
'disabled' => '',
'value' => $item_info->name
]) ?>
</div>
</div>
<label for="category" class="form-label"><?= lang('Items.category'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="category-icon"><i class="bi bi-bookmark"></i></span>
<input type="text" class="form-control" name="category" id="category" aria-describedby="category-icon" value="<?= $item_info->category ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.category'), 'category', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-tag"></span></span>
<?= form_input([
'name' => 'category',
'id' => 'category',
'class' => 'form-control input-sm',
'disabled' => '',
'value' => $item_info->category
]) ?>
</div>
</div>
</div>
<label for="stock_location" class="form-label"><?= lang('Items.stock_location'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-boxes"></i></span>
<select class="form-select" name="stock_location" id="stock_location" onchange="display_stock(this.value)">
<?php foreach ($stock_locations as $value => $label): ?>
<option value="<?= $value ?>" <?= $value == current($stock_locations) ? 'selected' : '' ?>><?= $label ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.stock_location'), 'stock_location', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown('stock_location', $stock_locations, current($stock_locations), ['onchange' => 'display_stock(this.value);', 'class' => 'form-control']) ?>
</div>
</div>
<label for="quantity" class="form-label"><?= lang('Items.current_quantity'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="quantity-icon"><i class="bi bi-box"></i></span>
<input type="text" class="form-control" name="quantity" id="quantity" aria-describedby="quantity-icon" value="<?= to_quantity_decimals(current($item_quantities)) ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.current_quantity'), 'quantity', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'quantity',
'id' => 'quantity',
'class' => 'form-control input-sm',
'disabled' => '',
'value' => to_quantity_decimals(current($item_quantities))
]) ?>
</div>
</div>
</fieldset>
<?= form_close() ?>
<div class="table-responsive">
<table class="table table-sm table-hover align-middle text-nowrap" id="items_count_details">
<thead class="table-secondary">
<tr class="table-active">
<th colspan="4"><?= lang('Items.inventory_data_tracking') ?></th>
</tr>
<tr>
<th scope="col"><?= lang('Items.inventory_date') ?></th>
<th scope="col"><?= lang('Items.inventory_employee') ?></th>
<th scope="col" class="text-center" title="<?= lang('Items.inventory_in_out_quantity') ?>">#</th>
<th scope="col"><?= lang('Items.inventory_remarks') ?></th>
</tr>
</thead>
<tbody id="inventory_result">
<?php
// The tbody content of the table will be filled in by the javascript (see bottom of page)
$employee = model(Employee::class);
$inventory = model(Inventory::class);
<table id="items_count_details" class="table table-striped table-hover">
<thead>
<tr style="background-color: #999 !important;">
<th colspan="4"><?= lang('Items.inventory_data_tracking') ?></th>
</tr>
<tr>
<th style="width: 30%;"><?= lang('Items.inventory_date') ?></th>
<th style="width: 20%;"><?= lang('Items.inventory_employee') ?></th>
<th style="width: 20%;"><?= lang('Items.inventory_in_out_quantity') ?></th>
<th style="width: 30%;"><?= lang('Items.inventory_remarks') ?></th>
</tr>
</thead>
<tbody id="inventory_result">
<?php
// The tbody content of the table will be filled in by the javascript (see bottom of page)
$employee = model(Employee::class);
$inventory = model(Inventory::class);
$inventory_array = $inventory->get_inventory_data_for_item($item_info->item_id)->getResultArray();
$employee_name = [];
$inventory_array = $inventory->get_inventory_data_for_item($item_info->item_id)->getResultArray();
$employee_name = [];
foreach ($inventory_array as $row) {
$employee_data = $employee->get_info($row['trans_user']);
$employee_name[] = $employee_data->first_name . ' ' . $employee_data->last_name;
}
?>
</tbody>
</table>
</div>
foreach ($inventory_array as $row) {
$employee_data = $employee->get_info($row['trans_user']);
$employee_name[] = $employee_data->first_name . ' ' . $employee_data->last_name;
}
?>
</tbody>
</table>
<script type="text/javascript">
$(document).ready(function() {
@@ -114,7 +145,7 @@ use App\Models\Inventory;
td = document.createElement('td');
td.appendChild(document.createTextNode(parseFloat(data['trans_inventory']).toFixed(<?= quantity_decimals() ?>)));
td.setAttribute("class", "text-end");
td.setAttribute("style", "text-align: center");
tr.appendChild(td);
td = document.createElement('td');

View File

@@ -1,22 +1,27 @@
<?= form_open_multipart('items/importCsvFile/', ['id' => 'csv_form']) ?>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open_multipart('items/importCsvFile/', ['id' => 'csv_form', 'class' => 'form-horizontal']) ?>
<fieldset id="item_basic_info">
<a type="button" class="btn btn-secondary mb-3" href="<?= esc('items/generateCsvFile', 'attr') ?>"><?= lang('Common.download_import_template') ?></a>
<div class="fileinput fileinput-new input-group mb-3" data-provides="fileinput">
<span class="input-group-text"><i class="bi bi-filetype-csv"></i></span>
<div class="form-control" data-trigger="fileinput">
<span class="fileinput-filename"></span>
<div class="form-group form-group-sm">
<div class="col-xs-12">
<a href="<?= esc('items/generateCsvFile', 'attr') ?>"><?= lang('Common.download_import_template') ?></a>
</div>
</div>
<span class="input-group-text fileinput-exists" data-dismiss="fileinput" style="cursor: pointer;"><?= lang('Common.import_remove_file') ?></span>
<span class="input-group-text btn-file">
<span class="fileinput-new"><?= lang('Common.import_select_file') ?></span>
<span class="fileinput-exists"><?= lang('Common.import_change_file') ?></span>
<input type="file" id="file_path" name="file_path" accept=".csv">
</span>
</div>
<div class="form-group form-group-sm">
<div class="col-xs-12">
<div class="fileinput fileinput-new input-group" data-provides="fileinput">
<div class="form-control" data-trigger="fileinput"><i class="glyphicon glyphicon-file fileinput-exists"></i><span class="fileinput-filename"></span></div>
<span class="input-group-addon input-sm btn btn-default btn-file">
<span class="fileinput-new"><?= lang('Common.import_select_file') ?></span><span class="fileinput-exists"><?= lang('Common.import_change_file') ?></span><input type="file" id="file_path" name="file_path" accept=".csv">
</span>
<a href="#" class="input-group-addon input-sm btn btn-default fileinput-exists" data-dismiss="fileinput"><?= lang('Common.import_remove_file') ?></a>
</div>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">

View File

@@ -7,56 +7,100 @@
*/
?>
<?= form_open("items/saveInventory/$item_info->item_id", ['id' => 'item_form']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open("items/saveInventory/$item_info->item_id", ['id' => 'item_form', 'class' => 'form-horizontal']) ?>
<fieldset id="inv_item_basic_info">
<label for="item_number" class="form-label"><?= lang('Items.item_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="item_number-icon"><i class="bi bi-upc-scan"></i></span>
<input type="text" class="form-control" name="item_number" id="item_number" aria-describedby="item_number-icon" value="<?= $item_info->item_number ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.item_number'), 'name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-barcode"></span></span>
<?= form_input([
'name' => 'item_number',
'id' => 'item_number',
'class' => 'form-control input-sm',
'disabled' => '',
'value' => $item_info->item_number
]) ?>
</div>
</div>
</div>
<label for="name" class="form-label"><?= lang('Items.name'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="name-icon"><i class="bi bi-tag"></i></span>
<input type="text" class="form-control" name="name" id="name" aria-describedby="name-icon" value="<?= $item_info->name ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.name'), 'name', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'name',
'id' => 'name',
'class' => 'form-control input-sm',
'disabled' => '',
'value' => $item_info->name
]) ?>
</div>
</div>
<label for="category" class="form-label"><?= lang('Items.category'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="category-icon"><i class="bi bi-bookmark"></i></span>
<input type="text" class="form-control" name="category" id="category" aria-describedby="category-icon" value="<?= $item_info->category ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.category'), 'category', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-tag"></span></span>
<?= form_input([
'name' => 'category',
'id' => 'category',
'class' => 'form-control input-sm',
'disabled' => '',
'value' => $item_info->category
]) ?>
</div>
</div>
</div>
<label for="stock_location" class="form-label"><?= lang('Items.stock_location'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-boxes"></i></span>
<select class="form-select" name="stock_location" id="stock_location" onchange="fill_quantity(this.value)">
<?php foreach ($stock_locations as $value => $label): ?>
<option value="<?= $value ?>" <?= $value == current($stock_locations) ? 'selected' : '' ?>><?= $label ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.stock_location'), 'stock_location', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_dropdown('stock_location', $stock_locations, current($stock_locations), ['onchange' => 'fill_quantity(this.value)', 'class' => 'form-control']) ?>
</div>
</div>
<label for="quantity" class="form-label"><?= lang('Items.current_quantity'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="quantity-icon"><i class="bi bi-box"></i></span>
<input type="text" class="form-control" name="quantity" id="quantity" aria-describedby="quantity-icon" value="<?= to_quantity_decimals(current($item_quantities)) ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.current_quantity'), 'quantity', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'quantity',
'id' => 'quantity',
'class' => 'form-control input-sm',
'disabled' => '',
'value' => to_quantity_decimals(current($item_quantities))
]) ?>
</div>
</div>
<label for="newquantity" class="form-label"><?= lang('Items.add_minus'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="newquantity-icon"><i class="bi bi-plus-slash-minus"></i></span>
<input type="number" step="1" class="form-control" name="newquantity" id="newquantity" aria-describedby="newquantity-icon">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.add_minus'), 'quantity', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-4">
<?= form_input([
'name' => 'newquantity',
'id' => 'newquantity',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
<label for="trans_comment" class="form-label"><?= lang('Items.inventory_comments'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-chat"></i></span>
<textarea class="form-control" name="trans_comment" id="trans_comment" rows="6"></textarea>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Items.inventory_comments'), 'description', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_textarea([
'name' => 'trans_comment',
'id' => 'trans_comment',
'class' => 'form-control input-sm'
]) ?>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">

View File

@@ -16,11 +16,6 @@ use App\Models\Employee;
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = 'Items';
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
$(document).ready(function() {
$('#generate_barcodes').click(function() {
@@ -81,57 +76,51 @@ echo view('configs/config_header', $title_info);
<?= view('partial/table_filter_persistence', ['additional_params' => ['stock_location']]) ?>
<div class="d-flex gap-2 justify-content-end">
<button type="button" class="btn btn-primary modal-launch" data-btn-new="<?= lang('Common.new') ?>" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<i class="bi bi-tag me-2"></i><?= lang(ucfirst($controller_name) . '.new') ?>
<div id="title_bar" class="btn-toolbar print_hide">
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/csvImport" ?>" title="<?= lang('Items.import_items_csv') ?>">
<span class="glyphicon glyphicon-import">&nbsp;</span><?= lang('Common.import_csv') ?>
</button>
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/csvImport" ?>" title="<?= lang('Items.import_items_csv') ?>">
<i class="bi bi-file-earmark-arrow-down me-2"></i><?= lang('Common.import_csv') ?>
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-new="<?= lang('Common.new') ?>" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<span class="glyphicon glyphicon-tag">&nbsp;</span><?= lang(ucfirst($controller_name) . '.new') ?>
</button>
</div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary d-print-none" id="delete">
<i class="bi bi-trash"></i><span class="d-none d-md-inline ms-2"><?= lang('Common.delete') ?></span>
<div class="pull-left form-inline" role="toolbar">
<button id="delete" class="btn btn-default btn-sm print_hide">
<span class="glyphicon glyphicon-trash">&nbsp;</span><?= lang('Common.delete') ?>
</button>
<button type="button" class="btn btn-secondary modal-launch d-print-none" id="bulk_edit" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "items/bulkEdit" ?>" title="<?= lang('Items.edit_multiple_items') ?>">
<i class="bi bi-pencil-square"></i><span class="d-none d-md-inline ms-2"><?= lang('Items.bulk_edit') ?></span>
<button id="bulk_edit" class="btn btn-default btn-sm modal-dlg print_hide" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "items/bulkEdit" ?>" title="<?= lang('Items.edit_multiple_items') ?>">
<span class="glyphicon glyphicon-edit">&nbsp;</span><?= lang('Items.bulk_edit') ?>
</button>
<button type="button" class="btn btn-secondary d-print-none" id="generate_barcodes" data-href="<?= "$controller_name/generateBarcodes" ?>" title="<?= lang('Items.generate_barcodes') ?>">
<i class="bi bi-upc-scan"></i><span class="d-none d-md-inline ms-2"><?= lang('Items.generate_barcodes') ?></span>
<button id="generate_barcodes" class="btn btn-default btn-sm print_hide" data-href="<?= "$controller_name/generateBarcodes" ?>" title="<?= lang('Items.generate_barcodes') ?>">
<span class="glyphicon glyphicon-barcode">&nbsp;</span><?= lang('Items.generate_barcodes') ?>
</button>
<div class="input-group w-auto">
<span class="input-group-text" id="daterangepicker-icon"><i class="bi bi-calendar2-range"></i></span>
<input type="text" class="form-select" name="daterangepicker" id="daterangepicker" aria-describedby="daterangepicker-icon">
</div>
<div class="input-group w-auto">
<span class="input-group-text" id="filters-icon"><i class="bi bi-funnel"></i></span>
<select class="form-select" name="filters[]" id="filters" aria-describedby="filters-icon" multiple>
<?php foreach ($filters as $key => $label): ?>
<option value="<?= $key ?>" <?= in_array($key, $selected_filters ?? []) ? 'selected' : '' ?>>
<?= esc($label) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php if (count($stock_locations) > 1): ?>
<div class="input-group w-auto">
<span class="input-group-text" id="stock_location-icon"><i class="bi bi-boxes"></i></span>
<select class="form-select" name="stock_location" id="stock_location" aria-describedby="stock_location-icon" multiple>
<?php foreach ($stock_locations as $value => $label): ?>
<option value="<?= $value ?>" <?= $value == $stock_location ? 'selected' : '' ?>>
<?= $label ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
<?= form_input(['name' => 'daterangepicker', 'class' => 'form-control input-sm', 'id' => 'daterangepicker']) ?>
<?= form_multiselect('filters[]', $filters, $selected_filters ?? [], [
'id' => 'filters',
'class' => 'selectpicker show-menu-arrow',
'data-none-selected-text' => lang('Common.none_selected_text'),
'data-selected-text-format' => 'count > 1',
'data-style' => 'btn-default btn-sm',
'data-width' => 'fit'
]) ?>
<?php
if (count($stock_locations) > 1) {
echo form_dropdown(
'stock_location',
$stock_locations,
$stock_location,
[
'id' => 'stock_location',
'class' => 'selectpicker show-menu-arrow',
'data-style' => 'btn-default btn-sm',
'data-width' => 'fit'
]
);
}
?>
</div>
</div>
@@ -140,25 +129,3 @@ echo view('configs/config_header', $title_info);
</div>
<?= view('partial/footer') ?>
<script type="text/javascript">
new TomSelect('#filters', {
plugins: ['checkbox_options', 'remove_button'],
placeholder: '<?= lang('Common.none_selected_text') ?>',
hidePlaceholder: true,
closeAfterSelect: false,
onChange: function() {
$('#table').bootstrapTable('refresh');
}
});
new TomSelect('#stock_location', {
plugins: ['checkbox_options', 'remove_button'],
placeholder: '<?= lang('Common.none_selected_text') ?>',
hidePlaceholder: true,
closeAfterSelect: false,
onChange: function() {
$('#table').bootstrapTable('refresh');
}
});
</script>

View File

@@ -13,83 +13,31 @@
use Config\Services;
$request = Services::request();
// Manually setting some error messages for testing
// $validation->setError('test', 'The test error is testing.');
// $validation->setError('email', 'The email field is required.');
// $has_errors = $validation->hasError('email');
// $has_errors = $validation->hasError('test');
// Manually set database migration message to show
// $is_new_install = true;
// $is_latest = false;
// $latest_version = '1.0.0';
// Manually set language for page, doesn't work for dynamic elements
// \Config\Services::language()->setLocale('de-DE');
// Manually set login form appearence
// $config['login_form'] = 'input_groups';
// Manually set theme
// $config['theme'] = 'flatly';
$theme = (empty($config['theme']) ? 'bootstrap' : $config['theme']);
$themeColors = [
'bootstrap' => '#0d6efd',
'flatly' => '#2c3e50',
'darkly' => '#375a7f',
'cosmo' => '#2780e3',
'cerulean' => '#2fa4e7',
'journal' => '#eb6864',
'litera' => '#4582ec',
'lumen' => '#158cba',
'lux' => '#1a1a1a',
'materia' => '#2196f3',
'minty' => '#78c2ad',
'morph' => '#378dfc',
'pulse' => '#593196',
'quartz' => '#6d45bb',
'sandstone' => '#93c54b',
'simplex' => '#d9230f',
'sketchy' => '#333333',
'slate' => '#3a3f44',
'solar' => '#b58900',
'spacelab' => '#446e9b',
'superhero' => '#df6919',
'united' => '#e95420',
'vapor' => '#6f42c1',
'yeti' => '#008cba',
'zephyr' => '#3459e6',
];
$themeColor = $themeColors[$theme] ?? '#0d6efd';
?>
<!doctype html>
<html lang="<?= current_language_code() ?>" data-bs-theme="<?= esc($config['color_mode'] ?? 'light') ?>" <?= esc($config['rtl_language'] ?? 0) == 1 ? 'dir="rtl"' : '' ?>>
<html lang="<?= current_language_code() ?>">
<head>
<meta charset="utf-8">
<base href="<?= base_url() ?>">
<title><?= esc($config['company']) . '&nbsp;|&nbsp;' . esc(lang('Common.software_short')) . '&nbsp;|&nbsp;' . esc(lang('Login.login')) ?></title>
<?= ($config['responsive_design'] ?? 0) == 1 ? '<meta name="viewport" content="width=device-width, initial-scale=1">' : '' ?>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.ico">
<link rel="stylesheet" href="resources/bootswatch/<?= $theme ?>/bootstrap<?= esc($config['rtl_language'] ?? 0) == 1 ? '.rtl' : '' ?>.min.css">
<link rel="stylesheet" href="resources/bootstrap-icons/bootstrap-icons.min.css">
<?php
$theme = (empty($config['theme'])
|| 'paper' == $config['theme']
|| 'readable' == $config['theme']
? 'flatly'
: $config['theme']);
?>
<link rel="stylesheet" href="resources/bootswatch5/<?= "$theme" ?>/bootstrap.min.css">
<link rel="stylesheet" href="css/login.css">
<meta name="theme-color" content="<?= $themeColor ?>">
<meta name="theme-color" content="#2c3e50">
</head>
<body class="bg-secondary-subtle d-flex flex-column">
<!-- BS5 WIP message -->
<div data-notify="container" class="col-11 col-sm-9 col-md-7 col-lg-6 col-xl-5 col-xxl-4 alert alert-warning position-absolute top-0 mt-3 start-50 translate-middle-x" role="alert">
<span data-notify="icon" class="me-2" role="img"><i class="bi bi-exclamation-diamond-fill"></i></span>
<span data-notify="message">WIP conversion to Bootstrap 5</span>
</div>
<main class="d-flex justify-content-around align-items-center flex-grow-1">
<div class="container-login container-fluid d-flex flex-column flex-md-row bg-body shadow rounded m-3 p-4 p-md-0">
<div class="box-logo d-flex flex-column justify-content-center align-items-center border-end border-secondary-subtle px-4 pb-3 p-md-4">
@@ -105,87 +53,94 @@ $themeColor = $themeColors[$theme] ?? '#0d6efd';
</div>
<section class="box-login d-flex flex-column justify-content-center align-items-center p-md-4">
<?= form_open('login', ['id' => 'login-form']) ?>
<h3 id="form-heading" class="text-center m-0">
<?php if (!$is_latest || $is_new_install): ?>
<?= lang('Login.migration_required') ?>
<?php else: ?>
<?= lang('Login.welcome', [lang('Common.software_short')]) ?>
<?php endif; ?>
</h3>
<div id="migration-warning" class="alert alert-info mt-3<?= $is_new_install ? '' : ' d-none' ?>">
<?= lang('Login.migration_auth_message', [$latest_version]) ?>
</div>
<?php if ($has_errors): ?>
<?php foreach ($validation->getErrors() as $error): ?>
<div class="alert alert-danger mt-3">
<?= $error ?>
</div>
<?php endforeach; ?>
<h3 id="form-heading" class="text-center m-0">
<?php if (!$is_latest || $is_new_install): ?>
<?= lang('Login.migration_required') ?>
<?php else: ?>
<?= lang('Login.welcome', [lang('Common.software_short')]) ?>
<?php endif; ?>
<div id="migration-success" class="alert alert-success d-none mt-3">
<strong><?= lang('Login.migration_complete') ?></strong>
<?= lang('Login.migration_complete_login') ?>
</div>
<div id="migration-progress" class="d-none w-100">
<div class="text-center fw-bold mb-3 mt-3"><?= lang('Login.migration_initializing') ?></div>
<div class="progress" role="progressbar">
<div class="progress-bar progress-bar-striped progress-bar-animated" style="width: 100%"></div>
</h3>
<div id="migration-warning" class="alert alert-warning mt-3<?= $is_new_install ? '' : ' d-none' ?>">
<strong><?= lang('Login.migration_auth_message', [$latest_version]) ?></strong>
</div>
<?php if ($has_errors): ?>
<?php foreach ($validation->getErrors() as $error): ?>
<div class="alert alert-danger mt-3">
<?= $error ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
<div id="migration-success" class="alert alert-success d-none mt-3">
<strong><?= lang('Login.migration_complete') ?></strong> <?= lang('Login.migration_complete_login') ?>
</div>
<div id="migration-progress" class="d-none mt-4">
<h3 class="text-center mb-4"><?= lang('Login.migration_initializing') ?></h3>
<div class="progress mb-3" style="height: 30px;">
<div class="progress-bar progress-bar-striped progress-bar-animated bg-primary"
role="progressbar"
style="width: 100%">
</div>
<p class="text-center text-muted mt-3" id="migration-status">
<?= lang('Login.migration_running') ?>
</p>
</div>
<div id="migration-error" class="alert alert-danger d-none mt-3" role="alert">
<strong>Error:</strong> <span id="migration-error-message"></span>
</div>
<div id="login-fields" class="w-100<?= $is_new_install ? ' d-none' : '' ?>">
<?php if (empty($config['login_form']) || 'floating_labels' == ($config['login_form'])): ?>
<div class="form-floating mt-3">
<input class="form-control" id="input-username" name="username" type="text" placeholder="<?= lang('Login.username') ?>" <?php if (ENVIRONMENT == "testing") echo 'value="admin"'; ?>>
<label for="input-username"><?= lang('Login.username') ?></label>
</div>
<div class="form-floating mb-3">
<input class="form-control" id="input-password" name="password" type="password" placeholder="<?= lang('Login.password') ?>" <?php if (ENVIRONMENT == "testing") echo 'value="pointofsale"'; ?>>
<label for="input-password"><?= lang('Login.password') ?></label>
</div>
<?php elseif ('input_groups' == ($config['login_form'])): ?>
<div class="input-group mt-3">
<span class="input-group-text" id="input-username">
<i class="bi bi-person" title="<?= lang('Common.icon') . '&nbsp;' . lang('Login.username') ?>"></i>
</span>
<input class="form-control" name="username" type="text" placeholder="<?= lang('Login.username'); ?>" aria-label="<?= lang('Login.username') ?>" aria-describedby="input-username" <?php if (ENVIRONMENT == "testing") echo 'value="admin"'; ?>>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="input-password">
<i class="bi bi-lock" title="<?= lang('Common.icon') . '&nbsp;' . lang('Login.password') ?>"></i>
</span>
<input class="form-control" name="password" type="password" placeholder="<?= lang('Login.password') ?>" aria-label="<?= lang('Login.password') ?>" aria-describedby="input-password" <?php if (ENVIRONMENT == "testing") echo 'value="pointofsale"'; ?>>
</div>
<p class="text-center text-muted" id="migration-status">
<?= lang('Login.migration_running') ?>
</p>
</div>
<div id="migration-error" class="alert alert-danger d-none mt-3" role="alert">
<strong>Error:</strong> <span id="migration-error-message"></span>
</div>
<div id="login-fields" class="w-100<?= $is_new_install ? ' d-none' : '' ?>">
<?php if (empty($config['login_form']) || 'floating_labels' == ($config['login_form'])): ?>
<div class="form-floating mt-3">
<input class="form-control" id="input-username" name="username" type="text" placeholder="<?= lang('Login.username') ?>" <?php if (ENVIRONMENT == "testing") echo 'value="admin"'; ?>>
<label for="input-username"><?= lang('Login.username') ?></label>
</div>
<div class="form-floating mb-3">
<input class="form-control" id="input-password" name="password" type="password" placeholder="<?= lang('Login.password') ?>" <?php if (ENVIRONMENT == "testing") echo 'value="pointofsale"'; ?>>
<label for="input-password"><?= lang('Login.password') ?></label>
</div>
<?php elseif ('input_groups' == ($config['login_form'])): ?>
<div class="input-group mt-3">
<span class="input-group-text" id="input-username">
<svg class="bi bi-person-fill" fill="currentColor" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<title><?= lang('Common.icon') . '&nbsp;' . lang('Login.username') ?></title>
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6" />
</svg>
</span>
<input class="form-control" name="username" type="text" placeholder="<?= lang('Login.username'); ?>" aria-label="<?= lang('Login.username') ?>" aria-describedby="input-username" <?php if (ENVIRONMENT == "testing") echo 'value="admin"'; ?>>
</div>
<div class="input-group mb-3">
<span class="input-group-text" id="input-password">
<svg class="bi bi-key-fill" fill="currentColor" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<title><?= lang('Common.icon') . '&nbsp;' . lang('Login.password') ?></title>
<path d="M3.5 11.5a3.5 3.5 0 1 1 3.163-5H14L15.5 8 14 9.5l-1-1-1 1-1-1-1 1-1-1-1 1H6.663a3.5 3.5 0 0 1-3.163 2M2.5 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2" />
</svg>
</span>
<input class="form-control" name="password" type="password" placeholder="<?= lang('Login.password') ?>" aria-label="<?= lang('Login.password') ?>" aria-describedby="input-password" <?php if (ENVIRONMENT == "testing") echo 'value="pointofsale"'; ?>>
</div>
<?php endif; ?>
<?php if ($gcaptcha_enabled): ?>
<script src="https://www.google.com/recaptcha/api.js"></script>
<div class="g-recaptcha mb-3" style="text-align: center;" data-sitekey="<?= esc($config['gcaptcha_site_key']) ?>"></div>
<?php endif; ?>
</div>
<div class="d-grid">
<button id="submit-button" class="btn btn-lg btn-primary" name="login-button" type="submit">
<?php if ($is_new_install): ?>
<?= lang('Module.migrate') ?>
<?php else: ?>
<?= lang('Login.go') ?>
<?php endif; ?>
<?php if ($gcaptcha_enabled): ?>
<script src="https://www.google.com/recaptcha/api.js"></script>
<div class="g-recaptcha mb-3" style="text-align: center;" data-sitekey="<?= esc($config['gcaptcha_site_key'] ?? '') ?>"></div>
<?php endif; ?>
</div>
<div class="d-grid">
<button type="submit" id="submit-button" class="btn btn-lg btn-primary" name="login-button">
<?php if ($is_new_install): ?>
<?= lang('Module.migrate') ?>
<?php else: ?>
<?= lang('Login.go') ?>
<?php endif; ?>
</button>
</div>
</button>
</div>
<?= form_close() ?>
</section>
</div>
@@ -302,9 +257,9 @@ $themeColor = $themeColors[$theme] ?? '#0d6efd';
$form.on('submit', function(e) {
if (APP_STATE.isNewInstall) {
e.preventDefault();
showMigrationProgress();
$.ajax({
url: APP_STATE.migrateUrl,
type: 'POST',

View File

@@ -6,34 +6,44 @@
*/
?>
<?= form_open("messages/send_form/$person_info->person_id", ['id' => 'send_sms_form']) ?>
<div id="required_fields_message"><?= lang('Common.fields_required_message') ?></div>
<ul id="error_message_box" class="error_message_box"></ul>
<ul id="error_message_box" class="alert alert-warning d-none"></ul>
<?= form_open("messages/send_form/$person_info->person_id", ['id' => 'send_sms_form', 'class' => 'form-horizontal']) ?>
<fieldset>
<label for="first_name" class="form-label"><?= lang('Messages.first_name'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="first_name-icon"><i class="bi bi-person-square"></i></span>
<input type="text" class="form-control" name="first_name" id="first_name" aria-describedby="first_name-icon" value="<?= $person_info->first_name; ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Messages.first_name'), 'first_name_label', ['for' => 'first_name', 'class' => 'control-label col-xs-2']) ?>
<div class="col-xs-10">
<?= form_input(['class' => 'form-control input-sm', 'type' => 'text', 'name' => 'first_name', 'value' => $person_info->first_name, 'readonly' => 'true']) ?>
</div>
</div>
<label for="last_name" class="form-label"><?= lang('Messages.last_name'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="last_name-icon"><i class="bi bi-person-square"></i></span>
<input type="text" class="form-control" name="last_name" id="last_name" aria-describedby="last_name-icon" value="<?= $person_info->last_name; ?>" disabled readonly>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Messages.last_name'), 'last_name_label', ['for' => 'last_name', 'class' => 'control-label col-xs-2']) ?>
<div class="col-xs-10">
<?= form_input(['class' => 'form-control input-sm', 'type' => 'text', 'name' => 'last_name', 'value' => $person_info->last_name, 'readonly' => 'true']) ?>
</div>
</div>
<label for="phone" class="form-label"><?= lang('Messages.phone'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="phone-icon"><i class="bi bi-telephone"></i></span>
<input type="text" class="form-control" name="phone" id="phone" aria-describedby="phone-icon" value="<?= $person_info->phone_number; ?>">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Messages.phone'), 'phone_label', ['for' => 'phone', 'class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-10">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-phone-alt"></span></span>
<?= form_input(['class' => 'form-control input-sm required', 'type' => 'text', 'name' => 'phone', 'value' => $person_info->phone_number]) ?>
</div>
</div>
</div>
<label for="message" class="form-label"><?= lang('Messages.message'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="message-icon"><i class="bi bi-chat-dots"></i></span>
<textarea class="form-control" name="message" id="message" rows="10" aria-describedby="message-icon"><?= $config['msg_msg'] ?></textarea>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Messages.message'), 'message_label', ['for' => 'message', 'class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-10">
<?= form_textarea(['class' => 'form-control input-sm required', 'name' => 'message', 'id' => 'message', 'value' => $config['msg_msg']]) ?>
</div>
</div>
</fieldset>
<?= form_close() ?>
<script type="text/javascript">

View File

@@ -1,34 +1,39 @@
<?= view('partial/header') ?>
<?= form_open("messages/send/", ['id' => 'send_sms_form', 'enctype' => 'multipart/form-data', 'method' => 'post']) ?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<?php
$title_info['config_title'] = lang('Messages.sms_send');
echo view('configs/config_header', $title_info);
?>
<div class="jumbotron" style="max-width: 60%; margin: auto;">
<?= form_open("messages/send/", ['id' => 'send_sms_form', 'enctype' => 'multipart/form-data', 'method' => 'post', 'class' => 'form-horizontal']) ?>
<fieldset>
<div class="col mb-3">
<label for="message-recipients" class="form-label"><?= lang('Messages.phone'); ?></label>
<div class="input-group">
<span class="input-group-text" id="message-icon"><i class="bi bi-phone"></i></span>
<input type="text" name="phone" class="form-control" id="message-recipients" aria-describedby="message-icon" required placeholder="<?= lang('Messages.phone_placeholder'); ?>">
</div>
<span class="form-text"><?= lang('Messages.multiple_phones'); ?></span>
</div>
<legend style="text-align: center;"><?= lang('Messages.sms_send') ?></legend>
<div class="form-group form-group-sm">
<label for="phone" class="col-xs-3 control-label"><?= lang('Messages.phone') ?></label>
<div class="col-xs-9">
<input class="form-control input-sm" type="text" name="phone" placeholder="<?= lang('Messages.phone_placeholder') ?>">
<span class="help-block" style="text-align: center;"><?= lang('Messages.multiple_phones') ?></span>
</div>
</div>
<div class="col mb-3">
<label for="text-message" class="form-label"><?= lang('Messages.message'); ?></label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-chat-quote"></i></span>
<textarea class="form-control" name="message" id="text-message" rows="10" placeholder="<?= lang('Messages.message_placeholder'); ?>"></textarea>
</div>
</div>
<div class="form-group form-group-sm">
<label for="message" class="col-xs-3 control-label"><?= lang('Messages.message') ?></label>
<div class="col-xs-9">
<textarea class="form-control input-sm" rows="3" id="message" name="message" placeholder="<?= lang('Messages.message_placeholder') ?>"></textarea>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary" id="submit_form" name="submit_form">Send</button>
</div>
<?= form_submit([
'name' => 'submit_form',
'id' => 'submit_form',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
]) ?>
<?= form_close() ?>
</fieldset>
<?= form_close() ?>
</div>
<?= view('partial/footer') ?>
@@ -40,7 +45,6 @@
$(form).ajaxSubmit({
success: function(response) {
$.notify({
icon: 'bi bi-bell-fill',
message: response.message
}, {
type: response.success ? 'success' : 'danger'

View File

@@ -4,10 +4,6 @@
*/
?>
<span class="d-flex justify-content-start add_customer_reward">
<button type="button" class="btn btn-outline-success mb-3"><i class="bi bi-plus-lg"></i>&nbsp;Add reward</button> <!-- TODO-BS5 translate -->
</span>
<?php
$i = 0;
@@ -18,14 +14,33 @@ foreach ($customer_rewards as $reward_key => $reward_category) {
++$i;
?>
<div class="col-12 col-lg-6 <?= $reward_category['deleted'] ? 'd-none' : '' ?>">
<label for="customer_reward_<?= $i ?>" class="form-label"><?= lang('Config.customer_reward') . " $i"; ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><?= $customer_reward_id ?>.</span>
<input type="text" class="form-control customer_reward valid_chars w-25" name="customer_reward_<?= $customer_reward_id ?>" id="customer_reward_<?= $customer_reward_id ?>" value="<?= $customer_reward_name ?>" required <?= $reward_category['deleted'] ? 'disabled' : '' ?>>
<input type="number" min="0" class="form-control customer_reward valid_chars" name="reward_points_<?= $customer_reward_id ?>" id="reward_points_<?= $customer_reward_id ?>" value="<?= $customer_points_percent ?>" required <?= $reward_category['deleted'] ? 'disabled' : '' ?>>
<button type="button" class="btn btn-outline-danger remove_customer_reward"><i class="bi bi-x-lg"></i></button>
<div class="form-group form-group-sm" style="<?= $reward_category['deleted'] ? 'display: none;' : 'display: block;' ?>">
<?= form_label(lang('Config.customer_reward') . " $i", "customer_reward_$i", ['class' => 'required control-label col-xs-2']) ?>
<div class="col-xs-2">
<?php $form_data = [
'name' => 'customer_reward_' . $customer_reward_id,
'id' => 'customer_reward_' . $customer_reward_id,
'class' => 'customer_reward valid_chars form-control input-sm required',
'value' => $customer_reward_name
];
$reward_category['deleted'] && $form_data['disabled'] = 'disabled';
echo form_input($form_data);
?>
</div>
<div class="col-xs-2">
<?php $form_data = [
'name' => 'reward_points_' . $customer_reward_id,
'id' => 'reward_points_' . $customer_reward_id,
'class' => 'customer_reward valid_chars form-control input-sm required',
'value' => $customer_points_percent
];
$reward_category['deleted'] && $form_data['disabled'] = 'disabled';
echo form_input($form_data);
?>
</div>
<span class="add_customer_reward glyphicon glyphicon-plus" style="padding-top: 0.5em;"></span>
<span>&nbsp;&nbsp;</span>
<span class="remove_customer_reward glyphicon glyphicon-minus" style="padding-top: 0.5em;"></span>
</div>
<?php } ?>

View File

@@ -5,209 +5,206 @@
?>
<?php if (empty($config['date_or_time_format'])) { ?>
$('#daterangepicker').css("width", "180");
var start_date = "<?= date('Y-m-d') ?>";
var end_date = "<?= date('Y-m-d') ?>";
$('#daterangepicker').daterangepicker({
"ranges": {
"<?= lang('Datepicker.today') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.today_last_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y") - 1) - 1) ?>"
],
"<?= lang('Datepicker.yesterday') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") - 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.last_7') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") - 6, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.last_30') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") - 29, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.this_month') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m") + 1, 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.same_month_to_same_day_last_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y") - 1) - 1) ?>"
],
"<?= lang('Datepicker.same_month_last_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m") + 1, 1, date("Y") - 1) - 1) ?>"
],
"<?= lang('Datepicker.last_month') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m") - 1, 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.this_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, 1, 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y") + 1) - 1) ?>"
],
"<?= lang('Datepicker.last_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, 1, 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, 1, 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.this_financial_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y") + 1) - 1) ?>"
],
"<?= lang('Datepicker.last_financial_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.all_time') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, 1, 1, 2010)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
],
},
"locale": {
"format": '<?= dateformat_momentjs($config['dateformat']) ?>',
"separator": " - ",
"applyLabel": "<?= lang('Datepicker.apply') ?>",
"cancelLabel": "<?= lang('Datepicker.cancel') ?>",
"fromLabel": "<?= lang('Datepicker.from') ?>",
"toLabel": "<?= lang('Datepicker.to') ?>",
"customRangeLabel": "<?= lang('Datepicker.custom') ?>",
"daysOfWeek": [
"<?= lang('Calendar.su') ?>",
"<?= lang('Calendar.mo') ?>",
"<?= lang('Calendar.tu') ?>",
"<?= lang('Calendar.we') ?>",
"<?= lang('Calendar.th') ?>",
"<?= lang('Calendar.fr') ?>",
"<?= lang('Calendar.sa') ?>"
],
"monthNames": [
"<?= lang('Calendar.january') ?>",
"<?= lang('Calendar.february') ?>",
"<?= lang('Calendar.march') ?>",
"<?= lang('Calendar.april') ?>",
"<?= lang('Calendar.may') ?>",
"<?= lang('Calendar.june') ?>",
"<?= lang('Calendar.july') ?>",
"<?= lang('Calendar.august') ?>",
"<?= lang('Calendar.september') ?>",
"<?= lang('Calendar.october') ?>",
"<?= lang('Calendar.november') ?>",
"<?= lang('Calendar.december') ?>"
],
"firstDay": <?= lang('Datepicker.weekstart') ?>
},
"alwaysShowCalendars": true,
"startDate": "<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>",
"endDate": "<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>",
"minDate": "<?= date($config['dateformat'], mktime(0, 0, 0, 01, 01, 2010)) ?>",
"maxDate": "<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>",
"buttonClasses": "btn",
"applyButtonClasses": "btn-primary",
"cancelClass": "btn-secondary"
"ranges": {
"<?= lang('Datepicker.today') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.today_last_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y") - 1) - 1) ?>"
],
"<?= lang('Datepicker.yesterday') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") - 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.last_7') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") - 6, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.last_30') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") - 29, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.this_month') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m") + 1, 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.same_month_to_same_day_last_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y") - 1) - 1) ?>"
],
"<?= lang('Datepicker.same_month_last_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m") + 1, 1, date("Y") - 1) - 1) ?>"
],
"<?= lang('Datepicker.last_month') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m") - 1, 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.this_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, 1, 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y") + 1) - 1) ?>"
],
"<?= lang('Datepicker.last_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, 1, 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, 1, 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.this_financial_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y"))) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), 1, date("Y") + 1) - 1) ?>"
],
"<?= lang('Datepicker.last_financial_year') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y")) - 1) ?>"
],
"<?= lang('Datepicker.all_time') ?>": [
"<?= date($config['dateformat'], mktime(0, 0, 0, 1, 1, 2010)) ?>",
"<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
],
},
function(start, end, label) {
start_date = start.format('YYYY-MM-DD');
end_date = end.format('YYYY-MM-DD');
"locale": {
"format": '<?= dateformat_momentjs($config['dateformat']) ?>',
"separator": " - ",
"applyLabel": "<?= lang('Datepicker.apply') ?>",
"cancelLabel": "<?= lang('Datepicker.cancel') ?>",
"fromLabel": "<?= lang('Datepicker.from') ?>",
"toLabel": "<?= lang('Datepicker.to') ?>",
"customRangeLabel": "<?= lang('Datepicker.custom') ?>",
"daysOfWeek": [
"<?= lang('Calendar.su') ?>",
"<?= lang('Calendar.mo') ?>",
"<?= lang('Calendar.tu') ?>",
"<?= lang('Calendar.we') ?>",
"<?= lang('Calendar.th') ?>",
"<?= lang('Calendar.fr') ?>",
"<?= lang('Calendar.sa') ?>"
],
"monthNames": [
"<?= lang('Calendar.january') ?>",
"<?= lang('Calendar.february') ?>",
"<?= lang('Calendar.march') ?>",
"<?= lang('Calendar.april') ?>",
"<?= lang('Calendar.may') ?>",
"<?= lang('Calendar.june') ?>",
"<?= lang('Calendar.july') ?>",
"<?= lang('Calendar.august') ?>",
"<?= lang('Calendar.september') ?>",
"<?= lang('Calendar.october') ?>",
"<?= lang('Calendar.november') ?>",
"<?= lang('Calendar.december') ?>"
],
"firstDay": <?= lang('Datepicker.weekstart') ?>
},
"alwaysShowCalendars": true,
"startDate": "<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>",
"endDate": "<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>",
"minDate": "<?= date($config['dateformat'], mktime(0, 0, 0, 01, 01, 2010)) ?>",
"maxDate": "<?= date($config['dateformat'], mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")) - 1) ?>"
}, function(start, end, label) {
start_date = start.format('YYYY-MM-DD');
end_date = end.format('YYYY-MM-DD');
});
<?php } else { ?>
$('#daterangepicker').css("width", "305");
var start_date = "<?= date('Y-m-d H:i:s', mktime(0, 0, 0, date("m"), date("d"), date("Y"))) ?>";
var end_date = "<?= date('Y-m-d H:i:s', mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>";
$('#daterangepicker').daterangepicker({
"ranges": {
"<?= lang('Datepicker.today') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['dateformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"<?= lang('Datepicker.today_last_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y") - 1)) ?>"
],
"<?= lang('Datepicker.yesterday') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d") - 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d") - 1, date("Y"))) ?>"
],
"<?= lang('Datepicker.last_7') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d") - 6, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"<?= lang('Datepicker.last_30') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d") - 29, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"<?= lang('Datepicker.this_month') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"<?= lang('Datepicker.same_month_to_same_day_last_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y") - 1)) ?>"
],
"<?= lang('Datepicker.same_month_last_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m") + 1, 0, date("Y") - 1)) ?>"
],
"<?= lang('Datepicker.last_month') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m") - 1, 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), 0, date("Y"))) ?>"
],
"<?= lang('Datepicker.this_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, 1, 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m") + 1, 0, date("Y"))) ?>"
],
"<?= lang('Datepicker.last_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, 1, 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, 12, 31, date("Y") - 1)) ?>"
],
"<?= lang('Datepicker.this_financial_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m") + 1, 0, date("Y"))) ?>"
],
"<?= lang('Datepicker.last_financial_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, $config['financial_year'], 0, date("Y"))) ?>"
],
"<?= lang('Datepicker.all_time') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, 1, 1, 2010)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"ranges": {
"<?= lang('Datepicker.today') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['dateformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"<?= lang('Datepicker.today_last_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y") - 1)) ?>"
],
"<?= lang('Datepicker.yesterday') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d") - 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d") - 1, date("Y"))) ?>"
],
"<?= lang('Datepicker.last_7') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d") - 6, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"<?= lang('Datepicker.last_30') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d") - 29, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"<?= lang('Datepicker.this_month') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
"<?= lang('Datepicker.same_month_to_same_day_last_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y") - 1)) ?>"
],
"<?= lang('Datepicker.same_month_last_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m") + 1, 0, date("Y") - 1)) ?>"
],
"<?= lang('Datepicker.last_month') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m") - 1, 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), 0, date("Y"))) ?>"
],
"<?= lang('Datepicker.this_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, 1, 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m") + 1, 0, date("Y"))) ?>"
],
"<?= lang('Datepicker.last_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, 1, 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, 12, 31, date("Y") - 1)) ?>"
],
"<?= lang('Datepicker.this_financial_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y"))) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m") + 1, 0, date("Y"))) ?>"
],
"<?= lang('Datepicker.last_financial_year') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, $config['financial_year'], 1, date("Y") - 1)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, $config['financial_year'], 0, date("Y"))) ?>"
],
"<?= lang('Datepicker.all_time') ?>": [
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, 1, 1, 2010)) ?>",
"<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
],
},
"locale": {
"format": '<?= dateformat_momentjs($config['dateformat'] . ' ' . $config['timeformat']) ?>',
"separator": " - ",
"applyLabel": "<?= lang('Datepicker.apply') ?>",
"cancelLabel": "<?= lang('Datepicker.cancel') ?>",
"fromLabel": "<?= lang('Datepicker.from') ?>",
"toLabel": "<?= lang('Datepicker.to') ?>",
"customRangeLabel": "<?= lang('Datepicker.custom') ?>",
"daysOfWeek": [
"<?= lang('Calendar.su') ?>",
"<?= lang('Calendar.mo') ?>",
"<?= lang('Calendar.tu') ?>",
"<?= lang('Calendar.we') ?>",
"<?= lang('Calendar.th') ?>",
"<?= lang('Calendar.fr') ?>",
"<?= lang('Calendar.sa') ?>"
],
"monthNames": [
"<?= lang('Calendar.january') ?>",
"<?= lang('Calendar.february') ?>",
"<?= lang('Calendar.march') ?>",
"<?= lang('Calendar.april') ?>",
"<?= lang('Calendar.may') ?>",
"<?= lang('Calendar.june') ?>",
"<?= lang('Calendar.july') ?>",
"<?= lang('Calendar.august') ?>",
"<?= lang('Calendar.september') ?>",
"<?= lang('Calendar.october') ?>",
"<?= lang('Calendar.november') ?>",
"<?= lang('Calendar.december') ?>"
],
"firstDay": <?= lang('Datepicker.weekstart') ?>
"format": '<?= dateformat_momentjs($config['dateformat'] . ' ' . $config['timeformat']) ?>',
"separator": " - ",
"applyLabel": "<?= lang('Datepicker.apply') ?>",
"cancelLabel": "<?= lang('Datepicker.cancel') ?>",
"fromLabel": "<?= lang('Datepicker.from') ?>",
"toLabel": "<?= lang('Datepicker.to') ?>",
"customRangeLabel": "<?= lang('Datepicker.custom') ?>",
"daysOfWeek": [
"<?= lang('Calendar.su') ?>",
"<?= lang('Calendar.mo') ?>",
"<?= lang('Calendar.tu') ?>",
"<?= lang('Calendar.we') ?>",
"<?= lang('Calendar.th') ?>",
"<?= lang('Calendar.fr') ?>",
"<?= lang('Calendar.sa') ?>"
],
"monthNames": [
"<?= lang('Calendar.january') ?>",
"<?= lang('Calendar.february') ?>",
"<?= lang('Calendar.march') ?>",
"<?= lang('Calendar.april') ?>",
"<?= lang('Calendar.may') ?>",
"<?= lang('Calendar.june') ?>",
"<?= lang('Calendar.july') ?>",
"<?= lang('Calendar.august') ?>",
"<?= lang('Calendar.september') ?>",
"<?= lang('Calendar.october') ?>",
"<?= lang('Calendar.november') ?>",
"<?= lang('Calendar.december') ?>"
],
"firstDay": <?= lang('Datepicker.weekstart') ?>
},
"timePicker": true,
"timePickerSeconds": true,
@@ -215,13 +212,9 @@
"startDate": "<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, date("m"), date("d"), date("Y"))) ?>",
"endDate": "<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>",
"minDate": "<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(0, 0, 0, 01, 01, 2010)) ?>",
"maxDate": "<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>",
"buttonClasses": "btn",
"applyButtonClasses": "btn-primary",
"cancelClass": "btn-secondary"
},
function(start, end, label) {
start_date = start.format('YYYY-MM-DD HH:mm:ss');
end_date = end.format('YYYY-MM-DD HH:mm:ss');
"maxDate": "<?= date($config['dateformat'] . ' ' . $config['timeformat'], mktime(23, 59, 59, date("m"), date("d"), date("Y"))) ?>"
}, function(start, end, label) {
start_date = start.format('YYYY-MM-DD HH:mm:ss');
end_date = end.format('YYYY-MM-DD HH:mm:ss');
});
<?php } ?>

View File

@@ -4,10 +4,6 @@
*/
?>
<span class="d-flex justify-content-start add_dinner_table">
<button type="button" class="btn btn-outline-success mb-3"><i class="bi bi-plus-lg"></i>&nbsp;Add table</button> <!-- TODO-BS5 translate -->
</span>
<?php
$i = 0;
@@ -17,13 +13,24 @@ foreach ($dinner_tables as $table_key => $table) {
++$i;
?>
<div class="col-12 col-lg-6 <?= $table['deleted'] ? 'd-none' : '' ?>">
<label for="dinner_table_<?= $dinner_table_id ?>" class="form-label"><?= lang('Config.dinner_table') . " $i"; ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><?= $dinner_table_id ?>.</span>
<input type="text" class="form-control dinner_table valid_chars" name="dinner_table_<?= $dinner_table_id ?>" id="dinner_table_<?= $dinner_table_id ?>" value="<?= $dinner_table_name ?>" required <?= $table['deleted'] && $form_data['disabled'] = 'disabled' ?>>
<button type="button" class="btn btn-outline-danger remove_dinner_table"><i class="bi bi-x-lg"></i></button>
<div class="form-group form-group-sm" style="<?= $table['deleted'] ? 'display: none;' : 'display: block;' ?>">
<?= form_label(lang('Config.dinner_table') . " $i", "dinner_table_$i", ['class' => 'required control-label col-xs-2']) ?>
<div class="col-xs-2">
<?php $form_data = [
'name' => "dinner_table_$dinner_table_id",
'id' => "dinner_table_$dinner_table_id",
'class' => 'dinner_table valid_chars form-control input-sm required',
'value' => $dinner_table_name
];
$table['deleted'] && $form_data['disabled'] = 'disabled';
echo form_input($form_data);
?>
</div>
<span class="add_dinner_table glyphicon glyphicon-plus" style="padding-top: 0.5em;"></span>
<span>&nbsp;&nbsp;</span>
<span class="remove_dinner_table glyphicon glyphicon-minus" style="padding-top: 0.5em;"></span>
</div>
<?php } ?>

View File

@@ -4,27 +4,20 @@ use Config\OSPOS;
?>
</main>
<footer class="flex-shrink-0 text-body-secondary small fw-semibold bg-secondary-subtle py-3 d-print-none">
<div class="container-lg d-flex flex-wrap justify-content-center align-items-center">
<div>
<span><?= lang('Common.copyrights', [date('Y')]) ?></span>
</div>
<div>
<span class="d-none d-xl-block">&nbsp;·&nbsp;<a href="https://opensourcepos.org" class="text-body-secondary" target="_blank" rel="noopener"><?= lang('Common.website') ?></a>&nbsp;·&nbsp;</span>
<span class="d-xl-none">&nbsp;·&nbsp;<?= lang('Common.website') ?>&nbsp;·&nbsp;</span>
</div>
<div>
<span><?= esc(config('App')->application_version) ?>&nbsp;-</span>
<span class="d-none d-xl-inline"><a href="https://github.com/opensourcepos/opensourcepos/commit/<?= esc(config(OSPOS::class)->commit_sha1) ?>" class="text-body-secondary" target="_blank" rel="noopener"><?= esc(substr(config(OSPOS::class)->commit_sha1, 0, 6)); ?></a></span>
<span class="d-xl-none"><?= esc(substr(config(OSPOS::class)->commit_sha1, 0, 6)); ?></span>
</div>
</div>
</footer>
<script type="text/javascript" src="js/bs-tooltips.js"></script>
<script type="text/javascript" src="js/bs-modal_switch_content.js"></script>
</body>
<div id="footer">
<div class="jumbotron push-spaces">
<strong>
<?= lang('Common.copyrights', [date('Y')]) ?> ·
<a href="https://opensourcepos.org" target="_blank"><?= lang('Common.website') ?></a> ·
<?= esc(config('App')->application_version) ?> -
<a target="_blank" href="https://github.com/opensourcepos/opensourcepos/commit/<?= esc(config(OSPOS::class)->commit_sha1) ?>">
<?= esc(substr(config(OSPOS::class)->commit_sha1, 0, 6)); ?>
</a>
</strong>.
</div>
</div>
</body>
</html>

View File

@@ -9,56 +9,19 @@
use Config\Services;
$request = Services::request();
// Services::language()->setLocale('de-DE');
$theme = (empty($config['theme']) ? 'bootstrap' : $config['theme']);
$themeColors = [
'bootstrap' => '#0d6efd',
'flatly' => '#2c3e50',
'darkly' => '#375a7f',
'cosmo' => '#2780e3',
'cerulean' => '#2fa4e7',
'journal' => '#eb6864',
'litera' => '#4582ec',
'lumen' => '#158cba',
'lux' => '#1a1a1a',
'materia' => '#2196f3',
'minty' => '#78c2ad',
'morph' => '#378dfc',
'pulse' => '#593196',
'quartz' => '#6d45bb',
'sandstone' => '#93c54b',
'simplex' => '#d9230f',
'sketchy' => '#333333',
'slate' => '#3a3f44',
'solar' => '#b58900',
'spacelab' => '#446e9b',
'superhero' => '#df6919',
'united' => '#e95420',
'vapor' => '#6f42c1',
'yeti' => '#008cba',
'zephyr' => '#3459e6',
];
$themeColor = $themeColors[$theme] ?? '#0d6efd';
?>
<!doctype html>
<html lang="<?= current_language_code() ?>" data-bs-theme="<?= $config['color_mode'] ?>" <?= $config['rtl_language'] == 1 ? 'dir="rtl"' : '' ?>>
<html lang="<?= current_language_code() ?>">
<head>
<meta charset="utf-8">
<base href="<?= base_url() ?>">
<title><?= esc($config['company']) . ' | ' . lang('Common.powered_by') . ' OSPOS ' . esc(config('App')->application_version) ?></title>
<?= $config['responsive_design'] == 1 ? '<meta name="viewport" content="width=device-width, initial-scale=1">' : '' ?>
<meta name="robots" content="noindex, nofollow">
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.ico">
<link rel="stylesheet" href="resources/bootswatch/<?= $theme ?>/bootstrap<?= esc($config['rtl_language']) == 1 ? '.rtl' : '' ?>.min.css">
<link rel="stylesheet" href="resources/bootstrap-icons/bootstrap-icons.min.css">
<meta name="theme-color" content="<?= $themeColor ?>">
<?php $theme = (empty($config['theme']) ? 'flatly' : esc($config['theme'])); ?>
<link rel="stylesheet" href="resources/bootswatch/<?= "$theme" ?>/bootstrap.min.css">
<?php if (ENVIRONMENT == 'development' || get_cookie('debug') == 'true' || $request->getGet('debug') == 'true') : ?>
<!-- inject:debug:css -->
@@ -66,8 +29,13 @@ $themeColor = $themeColors[$theme] ?? '#0d6efd';
<!-- inject:debug:js -->
<!-- endinject -->
<?php else : ?>
<!-- inject:prod:css -->
<!--inject:prod:css -->
<!-- endinject -->
<!-- Tweaks to the UI for a particular theme should drop here -->
<?php if ($config['theme'] != 'flatly' && file_exists($_SERVER['DOCUMENT_ROOT'] . '/public/css/' . esc($config['theme']) . '.css')) { ?>
<link rel="stylesheet" href="<?= 'css/' . esc($config['theme']) . '.css' ?>">
<?php } ?>
<!-- inject:prod:js -->
<!-- endinject -->
<?php endif; ?>
@@ -75,51 +43,60 @@ $themeColor = $themeColors[$theme] ?? '#0d6efd';
<?= view('partial/header_js') ?>
<?= view('partial/lang_lines') ?>
<style>
html {
overflow: auto;
}
</style>
</head>
<body class="d-flex flex-column">
<header class="flex-shrink-0 small bg-secondary-subtle py-1 d-print-none">
<div class="container-lg container-navbar d-flex flex-wrap-reverse justify-content-between align-items-center">
<div class="flex-grow-1 d-none d-md-block ps-md-3 ps-lg-0">
<span id="liveclock"><?= date($config['dateformat'] . ' ' . $config['timeformat']) ?></span>
</div>
<div class="fw-bold ps-3 ps-md-0">
<?= esc($config['company']) ?>
</div>
<div class="flex-grow-1 text-end pe-3 pe-lg-0">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="removeAnimationBg()" data-bs-toggle="modal" data-bs-target="#profile-modal" title="<?= lang('Employees.change_password'); ?>">
<?= $user_info->first_name . '&nbsp;' . $user_info->last_name; ?>
</button>
<?= view('home/profile'); ?>
<body>
<div class="wrapper">
<div class="topbar">
<div class="container">
<div class="navbar-left">
<div id="liveclock"><?= date($config['dateformat'] . ' ' . $config['timeformat']) ?></div>
</div>
<div class="navbar-right" style="margin: 0;">
<?= anchor("home/changePassword/$user_info->person_id", "$user_info->first_name $user_info->last_name", ['class' => 'modal-dlg', 'data-btn-submit' => lang('Common.submit'), 'title' => lang('Employees.change_password')]) ?>
<span>&nbsp;|&nbsp;</span>
<?= anchor('home/logout', lang('Login.logout')) ?>
</div>
<div class="navbar-center" style="text-align: center;">
<strong><?= esc($config['company']) ?></strong>
</div>
</div>
</div>
</header>
<nav class="navbar navbar-dark navbar-expand-lg bg-primary py-0 d-print-none">
<div class="container-lg container-navbar">
<a class="navbar-brand py-2 pe-1 ps-3 ps-lg-0 fs-4" href="<?= site_url() ?>"><i class="bi bi-house-fill"></i></a>
<button type="button" class="navbar-toggler my-2 mx-3" data-bs-toggle="collapse" data-bs-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar navbar-default" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<div class="collapse navbar-collapse" id="navbar">
<ul class="navbar-nav ms-0 ms-lg-auto">
<?php foreach($allowed_modules as $module): ?>
<li class="d-none d-lg-block nav-item ms-1 <?= $module->module_id == $request->getUri()->getSegment(1) ? 'active bg-light bg-opacity-25' : '' ?>" data-bs-toggle="tooltip" data-bs-placement="bottom" title="<?= lang("Module.$module->module_id") ?>">
<a class="nav-link p-2" href="<?= base_url($module->module_id) ?>">
<img src="<?= base_url("images/menubar/$module->module_id.svg") ?>" alt="<?= lang('Common.icon') . '&nbsp;' . lang("Module.$module->module_id") ?>">
</a>
</li>
<li class="d-lg-none nav-item py-1 <?= $module->module_id == $request->getUri()->getSegment(1) ? 'active bg-light bg-opacity-25' : '' ?>">
<a class="nav-link p-0" href="<?= base_url($module->module_id) ?>">
<img class="ps-3 pe-1 my-1" src="<?= base_url("images/menubar/$module->module_id.svg") ?>" alt="<?= lang('Common.icon') . '&nbsp;' . lang("Module.$module->module_id") ?>">
<span class="align-middle text-light"><?= lang("Module.$module->module_id") ?></span>
</a>
</li>
<?php endforeach; ?>
</ul>
<a class="navbar-brand hidden-sm" href="<?= site_url() ?>">OSPOS</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<?php foreach ($allowed_modules as $module): ?>
<li class="<?= $module->module_id == $request->getUri()->getSegment(1) ? 'active' : '' ?>">
<a href="<?= base_url($module->module_id) ?>" title="<?= lang("Module.$module->module_id") ?>" class="menu-icon">
<img src="<?= base_url("images/menubar/$module->module_id.svg") ?>" style="border: none;" alt="Module Icon"><br>
<?= lang('Module.' . $module->module_id) ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
</nav>
<main class="container-lg flex-grow-1 py-3">
<div class="container">
<div class="row">

View File

@@ -4,10 +4,6 @@
*/
?>
<span class="d-flex justify-content-start add_stock_location">
<button type="button" class="btn btn-outline-success mb-3"><i class="bi bi-plus-lg"></i>&nbsp;Add location</button> <!-- TODO-BS5 translate -->
</span>
<?php
$i = 0;
@@ -17,13 +13,22 @@ foreach ($stock_locations as $location => $location_data) {
++$i;
?>
<div class="col-12 col-lg-6 <?= $location_data['deleted'] ? 'd-none' : '' ?>">
<label for="stock_location_<?= $i ?>" class="form-label"><?= lang('Config.stock_location') . " $i"; ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><?= $location_id ?>.</span>
<input type="text" class="form-control stock_location valid_chars" name="stock_location<?= $location_id ?>" id="stock_location<?= $location_id ?>" value="<?= $location_name ?>" required <?= $location_data['deleted'] ? 'disabled' : '' ?>>
<button type="button" class="btn btn-outline-danger remove_stock_location"><i class="bi bi-x-lg"></i></button>
<div class="form-group form-group-sm" style="<?= $location_data['deleted'] ? 'display: none;' : 'display: block;' ?>">
<?= form_label(lang('Config.stock_location') . " $i", "stock_location_$i", ['class' => 'required control-label col-xs-2']) ?>
<div class="col-xs-2">
<?php $form_data = [
'name' => "stock_location[$location_id]",
'id' => "stock_location[$location_id]",
'class' => 'stock_location valid_chars form-control input-sm required',
'value' => $location_name
];
$location_data['deleted'] && $form_data['disabled'] = 'disabled';
echo form_input($form_data);
?>
</div>
<span class="add_stock_location glyphicon glyphicon-plus" style="padding-top: 0.5em;"></span>
<span>&nbsp;&nbsp;</span>
<span class="remove_stock_location glyphicon glyphicon-minus" style="padding-top: 0.5em;"></span>
</div>
</div>
<?php } ?>

View File

@@ -37,9 +37,9 @@ foreach ($tax_categories as $key => $category) {
echo form_input($form_data);
?>
</div>
<span class="add_tax_category bi bi-plus-circle" style="padding-top: 0.5em; display: inline-block; cursor: pointer;"></span>
<span class="add_tax_category glyphicon glyphicon-plus" style="padding-top: 0.5em;"></span>
<span>&nbsp;&nbsp;</span>
<span class="remove_tax_category bi bi-dash-circle" style="padding-top: 0.5em; display: inline-block; cursor: pointer;"></span>
<span class="remove_tax_category glyphicon glyphicon-minus" style="padding-top: 0.5em;"></span>
<?= form_hidden('tax_category_id[]', (string)$tax_category_id) ?>
</div>

View File

@@ -60,9 +60,9 @@ foreach ($tax_codes as $tax_code => $tax_code_data) {
?>
</div>
<span class="add_tax_code bi bi-plus-circle" style="padding-top: 0.5em; display: inline-block; cursor: pointer;"></span>
<span class="add_tax_code glyphicon glyphicon-plus" style="padding-top: 0.5em;"></span>
<span>&nbsp;&nbsp;</span>
<span class="remove_tax_code bi bi-dash-circle" style="padding-top: 0.5em; display: inline-block; cursor: pointer;"></span>
<span class="remove_tax_code glyphicon glyphicon-minus" style="padding-top: 0.5em;"></span>
<?= form_hidden('tax_code_id[]', (string)$tax_code_id) ?>
</div>

View File

@@ -80,9 +80,9 @@ foreach ($tax_jurisdictions as $tax_jurisdiction => $jurisdiction) {
echo form_input($form_data)
?>
</div>
<span class="add_tax_jurisdiction bi bi-plus-circle" style="padding-top: 0.5em; display: inline-block; cursor: pointer;"></span>
<span class="add_tax_jurisdiction glyphicon glyphicon-plus" style="padding-top: 0.5em;"></span>
<span>&nbsp;&nbsp;</span>
<span class="remove_tax_jurisdiction bi bi-dash-circle" style="padding-top: 0.5em; display: inline-block; cursor: pointer;"></span>
<span class="remove_tax_jurisdiction glyphicon glyphicon-minus" style="padding-top: 0.5em;"></span>
<?= form_hidden('jurisdiction_id[]', (string)$jurisdiction_id) ?>
</div>

View File

@@ -93,6 +93,6 @@ applySummaryVisibility();
var init_dialog = function () {
<?php if (isset($editable)): ?>
table_support.submit_handler('<?php echo site_url("reports/get_detailed_{$editable}_row") ?>');
dialog_support.init("a.modal-launch");
dialog_support.init("a.modal-dlg");
<?php endif; ?>
};

View File

@@ -5,87 +5,167 @@
*/
?>
<label for="first_name" class="form-label"><?= lang('Common.first_name'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="first_name-icon"><i class="bi bi-person-square"></i></span>
<input type="text" class="form-control" name="first_name" id="first_name" aria-describedby="first_name-icon" value="<?= $person_info->first_name; ?>" required>
<div class="form-group form-group-sm">
<?= form_label(lang('Common.first_name'), 'first_name', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'first_name',
'id' => 'first_name',
'class' => 'form-control input-sm',
'value' => $person_info->first_name
]) ?>
</div>
</div>
<label for="last_name" class="form-label"><?= lang('Common.last_name'); ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="last_name-icon"><i class="bi bi-person-square"></i></span>
<input type="text" class="form-control" name="last_name" id="last_name" aria-describedby="last_name-icon" value="<?= $person_info->last_name; ?>" required>
<div class="form-group form-group-sm">
<?= form_label(lang('Common.last_name'), 'last_name', ['class' => 'required control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'last_name',
'id' => 'last_name',
'class' => 'form-control input-sm',
'value' => $person_info->last_name
]) ?>
</div>
</div>
<label for="gender" class="form-label"><?= lang('Common.gender'); ?><?php if (!empty($basic_version)): ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup><?php endif ?></label>
<div class="row mb-3">
<div class="col-12">
<div class="form-group form-group-sm">
<?= form_label(lang('Common.gender'), 'gender', !empty($basic_version) ? ['class' => 'required control-label col-xs-3'] : ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-4">
<label class="radio-inline">
<?= form_radio([
'name' => 'gender',
'type' => 'radio',
'id' => 'gender',
'value' => 1,
'checked' => $person_info->gender === '1'
]) ?> <?= lang('Common.gender_male') ?>
</label>
<label class="radio-inline">
<?= form_radio([
'name' => 'gender',
'type' => 'radio',
'id' => 'gender',
'value' => 0,
'checked' => $person_info->gender === '0'
]) ?> <?= lang('Common.gender_female') ?>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Common.email'), 'email', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" id="gender_male" value="1" <?= $person_info->gender === '1' ? 'checked' : '' ?>>
<label class="form-check-label" for="gender_male"><i class="bi bi-gender-male me-1"></i><?= lang('Common.gender_male') ?></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" id="gender_female" value="0" <?= $person_info->gender === '0' ? 'checked' : '' ?>>
<label class="form-check-label" for="gender_female"><i class="bi bi-gender-female me-1"></i><?= lang('Common.gender_female') ?></label>
</div>
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-envelope"></span></span>
<?= form_input([
'name' => 'email',
'id' => 'email',
'class' => 'form-control input-sm',
'value' => $person_info->email
]) ?>
</div>
</div>
</div>
<label for="email" class="form-label"><?= lang('Common.email'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="email-icon"><i class="bi bi-envelope"></i></span>
<input type="email" class="form-control" name="email" id="email" aria-describedby="email-icon" value="<?= $person_info->email; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Common.phone_number'), 'phone_number', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-phone-alt"></span></span>
<?= form_input([
'name' => 'phone_number',
'id' => 'phone_number',
'class' => 'form-control input-sm',
'value' => $person_info->phone_number
]) ?>
</div>
</div>
</div>
<label for="phone_number" class="form-label"><?= lang('Common.phone_number'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="phone_number-icon"><i class="bi bi-telephone"></i></span>
<input type="tel" class="form-control" name="phone_number" id="phone_number" aria-describedby="phone_number-icon" value="<?= $person_info->phone_number; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Common.address_1'), 'address_1', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'address_1',
'id' => 'address_1',
'class' => 'form-control input-sm',
'value' => $person_info->address_1
]) ?>
</div>
</div>
<label for="address_1" class="form-label"><?= lang('Common.address_1'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="address_1-icon"><i class="bi bi-geo-alt"></i></span>
<input type="text" class="form-control" name="address_1" id="address_1" aria-describedby="address_1-icon" value="<?= $person_info->address_1; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Common.address_2'), 'address_2', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'address_2',
'id' => 'address_2',
'class' => 'form-control input-sm',
'value' => $person_info->address_2
]) ?>
</div>
</div>
<label for="address_2" class="form-label"><?= lang('Common.address_2'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="address_2-icon"><i class="bi bi-geo-alt"></i></span>
<input type="text" class="form-control" name="address_2" id="address_2" aria-describedby="address_2-icon" value="<?= $person_info->address_2; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Common.city'), 'city', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'city',
'id' => 'city',
'class' => 'form-control input-sm',
'value' => $person_info->city
]) ?>
</div>
</div>
<label for="city" class="form-label"><?= lang('Common.city'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="city-icon"><i class="bi bi-geo-alt"></i></span>
<input type="text" class="form-control" name="city" id="city" aria-describedby="city-icon" value="<?= $person_info->city; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Common.state'), 'state', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'state',
'id' => 'state',
'class' => 'form-control input-sm',
'value' => $person_info->state
]) ?>
</div>
</div>
<label for="state" class="form-label"><?= lang('Common.state'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="state-icon"><i class="bi bi-geo-alt"></i></span>
<input type="text" class="form-control" name="state" id="state" aria-describedby="state-icon" value="<?= $person_info->state; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Common.zip'), 'zip', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'zip',
'id' => 'postcode',
'class' => 'form-control input-sm',
'value' => $person_info->zip
]) ?>
</div>
</div>
<label for="postcode" class="form-label"><?= lang('Common.zip'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="zip-icon"><i class="bi bi-geo-alt"></i></span>
<input type="text" class="form-control" name="zip" id="postcode" aria-describedby="zip-icon" value="<?= $person_info->zip; ?>">
<div class="form-group form-group-sm">
<?= form_label(lang('Common.country'), 'country', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_input([
'name' => 'country',
'id' => 'country',
'class' => 'form-control input-sm',
'value' => $person_info->country
]) ?>
</div>
</div>
<label for="country" class="form-label"><?= lang('Common.country'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="country-icon"><i class="bi bi-globe-americas"></i></span>
<input type="text" class="form-control" name="country" id="country" aria-describedby="country-icon" value="<?= $person_info->country; ?>">
</div>
<label for="comments" class="form-label"><?= lang('Common.comments'); ?></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-chat"></i></span>
<textarea class="form-control" name="comments" id="comments" rows="6"><?= $person_info->comments; ?></textarea>
<div class="form-group form-group-sm">
<?= form_label(lang('Common.comments'), 'comments', ['class' => 'control-label col-xs-3']) ?>
<div class="col-xs-8">
<?= form_textarea([
'name' => 'comments',
'id' => 'comments',
'class' => 'form-control input-sm',
'value' => $person_info->comments
]) ?>
</div>
</div>
<script type="text/javascript">

View File

@@ -8,11 +8,6 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = 'People';
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
$(document).ready(function() {
<?= view('partial/bootstrap_tables_locale') ?>
@@ -37,24 +32,24 @@ echo view('configs/config_header', $title_info);
});
</script>
<div class="d-flex gap-2 justify-content-end">
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<i class="bi bi-person-add me-2"></i><?= lang(ucfirst($controller_name) . '.new') ?>
</button>
<?php if ($controller_name == 'customers') { ?>
<button type="button" class="btn btn-primary modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/csvImport" ?>" title="<?= lang(ucfirst($controller_name) . '.import_items_csv') ?>">
<i class="bi bi-file-earmark-arrow-down me-2"></i><?= lang('Common.import_csv') ?>
</button>
<div id="title_bar" class="btn-toolbar">
<?php if ($controller_name === 'customers') { ?>
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/csvImport" ?>" title="<?= lang(ucfirst($controller_name) . '.import_items_csv') ?>">
<span class="glyphicon glyphicon-import">&nbsp;</span><?= lang('Common.import_csv') ?>
</button>
<?php } ?>
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
<span class="glyphicon glyphicon-user">&nbsp;</span><?= lang(ucfirst($controller_name) . '.new') ?>
</button>
</div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary" id="delete">
<i class="bi bi-trash"></i><span class="d-none d-sm-inline ms-2"><?= lang('Common.delete') ?></span>
<div class="pull-left btn-toolbar">
<button id="delete" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-trash">&nbsp;</span><?= lang('Common.delete') ?>
</button>
<button type="button" class="btn btn-secondary" id="email">
<i class="bi bi-envelope"></i><span class="d-none d-sm-inline ms-2"><?= lang('Common.email') ?></span>
<button id="email" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-envelope">&nbsp;</span><?= lang('Common.email') ?>
</button>
</div>
</div>

View File

@@ -28,9 +28,9 @@ echo view('partial/print_receipt', ['print_after_sale', $print_after_sale, 'sele
<div class="print_hide" id="control_buttons" style="text-align: right;">
<a href="javascript:printdoc();">
<div class="btn btn-info btn-sm" id="show_print_button"><?= '<i class="bi bi-printer me-2"></i>' . lang('Common.print') ?></div>
<div class="btn btn-info btn-sm" id="show_print_button"><?= '<span class="glyphicon glyphicon-print">&nbsp;</span>' . lang('Common.print') ?></div>
</a>
<?= anchor("receivings", '<i class="bi bi-box me-2"></i>' . lang('Receivings.register'), ['class' => 'btn btn-info btn-sm', 'id' => 'show_sales_button']) ?>
<?= anchor("receivings", '<span class="glyphicon glyphicon-save">&nbsp;</span>' . lang('Receivings.register'), ['class' => 'btn btn-info btn-sm', 'id' => 'show_sales_button']) ?>
</div>
<div id="receipt_wrapper">

View File

@@ -46,7 +46,7 @@ if (isset($success)) {
<label class="control-label"><?= lang(ucfirst($controller_name) . '.mode') ?></label>
</li>
<li class="pull-left">
<?= form_dropdown('mode', $modes, $mode, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
<?= form_dropdown('mode', $modes, $mode, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
</li>
<?php if ($show_stock_locations) { ?>
@@ -54,7 +54,7 @@ if (isset($success)) {
<label class="control-label"><?= lang(ucfirst($controller_name) . '.stock_source') ?></label>
</li>
<li class="pull-left">
<?= form_dropdown('stock_source', $stock_locations, $stock_source, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
<?= form_dropdown('stock_source', $stock_locations, $stock_source, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
</li>
<?php if ($mode == 'requisition') { ?>
@@ -62,7 +62,7 @@ if (isset($success)) {
<label class="control-label"><?= lang(ucfirst($controller_name) . '.stock_destination') ?></label>
</li>
<li class="pull-left">
<?= form_dropdown('stock_destination', $stock_locations, $stock_destination, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
<?= form_dropdown('stock_destination', $stock_locations, $stock_destination, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
</li>
<?php
}
@@ -92,8 +92,8 @@ if (isset($success)) {
</li>
<li class="pull-right">
<button id="new_item_button" class="btn btn-info btn-sm pull-right modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-btn-new="<?= lang('Common.new') ?>" data-href="<?= "items/view" ?>" title="<?= lang('Sales.new_item') ?>">
<i class="bi bi-tag me-2"></i><?= lang('Sales.new_item') ?>
<button id="new_item_button" class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-btn-new="<?= lang('Common.new') ?>" data-href="<?= "items/view" ?>" title="<?= lang('Sales.new_item') ?>">
<span class="glyphicon glyphicon-tag">&nbsp;</span><?= lang('Sales.new_item') ?>
</button>
</li>
</ul>
@@ -133,7 +133,7 @@ if (isset($success)) {
<?= form_open("$controller_name/editItem/$line", ['class' => 'form-horizontal', 'id' => "cart_$line"]) ?>
<tr>
<td><?= anchor("$controller_name/deleteItem/$line", '<i class="bi bi-trash"></i>') ?></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;">
<?= esc($item['name'] . ' ' . implode(' ', [$item['attribute_values'], $item['attribute_dtvalues']])) ?><br>
@@ -178,7 +178,7 @@ if (isset($success)) {
'id' => 'discount_toggle',
'name' => 'discount_toggle',
'value' => 1,
'data-toggle' => 'toggle',
'data-toggle' => "toggle",
'data-size' => 'small',
'data-onstyle' => 'success',
'data-on' => '<b>' . $config['currency_symbol'] . '</b>',
@@ -198,7 +198,7 @@ if (isset($success)) {
</td>
<td>
<a href="javascript:$('#<?= esc("cart_$line", 'js') ?>').submit();" title=<?= lang(ucfirst($controller_name) . '.update') ?>>
<i class="bi bi-arrow-repeat"></i>
<span class="glyphicon glyphicon-refresh"></span>
</a>
</td>
</tr>
@@ -272,7 +272,7 @@ if (isset($success)) {
<?= anchor(
"$controller_name/removeSupplier",
'<i class="bi bi-x-circle me-2"></i>' . lang('Common.remove') . ' ' . lang('Suppliers.supplier'),
'<span class="glyphicon glyphicon-remove">&nbsp;</span>' . lang('Common.remove') . ' ' . lang('Suppliers.supplier'),
[
'class' => 'btn btn-danger btn-sm',
'id' => 'remove_supplier_button',
@@ -295,8 +295,8 @@ if (isset($success)) {
'value' => lang(ucfirst($controller_name) . '.start_typing_supplier_name')
]) ?>
<button id="new_supplier_button" class="btn btn-info btn-sm modal-launch" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "suppliers/view" ?>" title="<?= lang(ucfirst($controller_name) . '.new_supplier') ?>">
<i class="bi bi-building-add me-2"></i><?= lang(ucfirst($controller_name) . '.new_supplier') ?>
<button id="new_supplier_button" class="btn btn-info btn-sm modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "suppliers/view" ?>" title="<?= lang(ucfirst($controller_name) . '.new_supplier') ?>">
<span class="glyphicon glyphicon-user">&nbsp;</span><?= lang(ucfirst($controller_name) . '.new_supplier') ?>
</button>
</div>
@@ -334,10 +334,10 @@ if (isset($success)) {
]) ?>
<div class="btn btn-sm btn-danger pull-left" id="cancel_receiving_button">
<i class="bi bi-x-circle me-2"></i><?= lang(ucfirst($controller_name) . '.cancel_receiving') ?>
<span class="glyphicon glyphicon-remove">&nbsp;</span><?= lang(ucfirst($controller_name) . '.cancel_receiving') ?>
</div>
<div class="btn btn-sm btn-success pull-right" id="finish_receiving_button">
<i class="bi bi-check-circle me-2"></i><?= lang(ucfirst($controller_name) . '.complete_receiving') ?>
<span class="glyphicon glyphicon-ok">&nbsp;</span><?= lang(ucfirst($controller_name) . '.complete_receiving') ?>
</div>
</div>
@@ -393,7 +393,7 @@ if (isset($success)) {
[],
[
'id' => 'payment_types',
'class' => 'selectpicker',
'class' => 'selectpicker show-menu-arrow',
'data-style' => 'btn-default btn-sm',
'data-width' => 'auto'
]
@@ -415,10 +415,10 @@ if (isset($success)) {
</div>
<div class="btn btn-sm btn-danger pull-left" id="cancel_receiving_button">
<i class="bi bi-x-circle me-2"></i><?= lang(ucfirst($controller_name) . '.cancel_receiving') ?>
<span class="glyphicon glyphicon-remove">&nbsp;</span><?= lang(ucfirst($controller_name) . '.cancel_receiving') ?>
</div>
<div class="btn btn-sm btn-success pull-right" id="finish_receiving_button">
<i class="bi bi-check-circle me-2"></i><?= lang(ucfirst($controller_name) . '.complete_receiving') ?>
<span class="glyphicon glyphicon-ok">&nbsp;</span><?= lang(ucfirst($controller_name) . '.complete_receiving') ?>
</div>
</div>
@@ -489,7 +489,7 @@ if (isset($success)) {
}
});
dialog_support.init("a.modal-launch, button.modal-launch");
dialog_support.init("a.modal-dlg, button.modal-dlg");
$('#supplier').blur(function() {
$(this).attr('value', "<?= lang(ucfirst($controller_name) . '.start_typing_supplier_name') ?>");

View File

@@ -7,10 +7,12 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = lang('Reports.report_input');
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<div id="page_title"><?= lang('Reports.report_input') ?></div>
<?php
if (isset($error)) {
@@ -18,76 +20,69 @@ if (isset($error)) {
}
?>
<?= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div class="row">
<div class="col-12 col-lg-6">
<label for="daterangepicker" class="form-label"><?= lang('Reports.date_range') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="daterangepicker-icon"><i class="bi bi-calendar2-range"></i></span>
<input type="text" class="form-select" name="daterangepicker" id="daterangepicker" aria-describedby="daterangepicker-icon">
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.date_range'), 'report_date_range_label', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-3">
<?= form_input(['name' => 'daterangepicker', 'class' => 'form-control input-sm', 'id' => 'daterangepicker']) ?>
</div>
</div>
<div class="col-12 col-lg-6">
<?php if (!empty($mode)) { ?>
<?php if ($mode == 'sale') { ?>
<label for="reports_sale_type_label" class="form-label"><?= lang('Reports.sale_type') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3" id="report_sale_type">
<span class="input-group-text"><i class="bi bi-receipt"></i></span>
<select class="form-select" name="sale_type" id="input_type" required>
<?php foreach ($sale_type_options as $value => $label) { ?>
<option value="<?= $value ?>" <?= $value === 'complete' ? 'selected' : '' ?>><?= $label ?></option>
<?php } ?>
</select>
</div>
<?php } elseif ($mode == 'receiving') { ?>
<label for="reports_receiving_type_label" class="form-label"><?= lang('Reports.receiving_type') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3" id="report_receiving_type">
<span class="input-group-text"><i class="bi bi-truck"></i></span>
<select class="form-select" name="receiving_type" id="input_type" required>
<option value="all" <?= 'all' === 'all' ? 'selected' : '' ?>><?= lang('Reports.all') ?></option>
<option value="receiving"><?= lang('Reports.receivings') ?></option>
<option value="returns"><?= lang('Reports.returns') ?></option>
<option value="requisitions"><?= lang('Reports.requisitions') ?></option>
</select>
</div>
<?php } ?>
<?php if (!empty($mode)) { ?>
<div class="form-group form-group-sm">
<?php if ($mode == 'sale') { ?>
<?= form_label(lang('Reports.sale_type'), 'reports_sale_type_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_sale_type" class="col-xs-3">
<?= form_dropdown('sale_type', $sale_type_options, 'complete', ['id' => 'input_type', 'class' => 'form-control']) ?>
</div>
<?php } elseif ($mode == 'receiving') { ?>
<?= form_label(lang('Reports.receiving_type'), 'reports_receiving_type_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_receiving_type" class="col-xs-3">
<?= form_dropdown(
'receiving_type',
[
'all' => lang('Reports.all'),
'receiving' => lang('Reports.receivings'),
'returns' => lang('Reports.returns'),
'requisitions' => lang('Reports.requisitions')
],
'all',
['id' => 'input_type', 'class' => 'form-control']
) ?>
</div>
<?php } ?>
</div>
<?php } ?>
<?php if (isset($discount_type_options)) { ?>
<div class="col-12 col-lg-6">
<label for="reports_discount_type_label" class="form-label"><?= lang('Reports.discount_type') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3" id="report_discount_type">
<span class="input-group-text"><i class="bi bi-plus-slash-minus"></i></span>
<select class="form-select" name="discount_type" id="discount_type_id" required>
<?php foreach ($discount_type_options as $value => $label) { ?>
<option value="<?= $value ?>" <?= $value == $config['default_sales_discount_type'] ? 'selected' : '' ?>><?= $label ?></option>
<?php } ?>
</select>
</div>
<?php if (isset($discount_type_options)) { ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.discount_type'), 'reports_discount_type_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_discount_type" class="col-xs-3">
<?= form_dropdown('discount_type', $discount_type_options, $config['default_sales_discount_type'], ['id' => 'discount_type_id', 'class' => 'form-control']) ?>
</div>
<?php } ?>
</div>
<?php } ?>
<?php if (!empty($stock_locations) && count($stock_locations) > 2) { ?>
<div class="col-12 col-lg-6">
<label for="reports_stock_location_label" class="form-label"><?= lang('Reports.stock_location') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3" id="report_stock_location">
<span class="input-group-text"><i class="bi bi-boxes"></i></span>
<select class="form-select" name="stock_location" id="location_id" required>
<?php foreach ($stock_locations as $value => $label) { ?>
<option value="<?= $value ?>" <?= $value === 'all' ? 'selected' : '' ?>><?= $label ?></option>
<?php } ?>
</select>
</div>
<?php if (!empty($stock_locations) && count($stock_locations) > 2) { ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.stock_location'), 'reports_stock_location_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_stock_location" class="col-xs-3">
<?= form_dropdown('stock_location', $stock_locations, 'all', ['id' => 'location_id', 'class' => 'form-control']) ?>
</div>
<?php } ?>
</div>
</div>
<?php } ?>
<div class="d-flex justify-content-end">
<button type="button" class="btn btn-primary" name="generate_report" id="generate_report"><?= lang('Common.submit'); ?></button>
</div>
<?php
echo form_button(
[
'name' => 'generate_report',
'id' => 'generate_report',
'content' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm'
]
);
?>
<?= form_close() ?>

View File

@@ -9,18 +9,24 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = esc($title);
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<h5><?= esc($subtitle) ?></h5>
<div id="page_title"><?= esc($title) ?></div>
<div id="page_subtitle"><?= esc($subtitle) ?></div>
<div class="ct-chart ct-golden-section" id="chart1"></div>
<button type="button" class="btn btn-secondary d-print-none" id="toggleCostProfitButton">
<i class="bi bi-toggles"></i><span class="d-none d-sm-inline ms-2"><?= lang('Reports.toggle_cost_and_profit') ?></span>
</button>
<div id="toolbar">
<div class="pull-left form-inline" role="toolbar">
<!-- Toggle Button -->
<button id="toggleCostProfitButton" class="btn btn-default btn-sm print_hide">
<?php echo lang('Reports.toggle_cost_and_profit'); ?>
</button>
</div>
</div>
<?= view($chart_type) ?>

View File

@@ -7,10 +7,11 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = lang('Reports.report_input');
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<div id="page_title"><?= lang('Reports.report_input') ?></div>
<?php
if (isset($error)) {
@@ -18,38 +19,30 @@ if (isset($error)) {
}
?>
<?= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div class="row">
<div class="col-12 col-lg-6">
<label for="reports_stock_location_label" class="form-label"><?= lang('Reports.stock_location') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3" id="report_stock_location">
<span class="input-group-text"><i class="bi bi-boxes"></i></span>
<select class="form-select" name="stock_location" id="location_id" required>
<?php foreach ($stock_locations as $value => $label) { ?>
<option value="<?= $value ?>" <?= $value === 'all' ? 'selected' : '' ?>><?= $label ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="reports_item_count_label" class="form-label"><?= lang('Reports.item_count') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3" id="report_item_count">
<span class="input-group-text"><i class="bi bi-funnel"></i></span>
<select class="form-select" name="item_count" id="item_count" required>
<?php foreach ($item_count as $value => $label) { ?>
<option value="<?= $value ?>" <?= $value === 'all' ? 'selected' : '' ?>><?= $label ?></option>
<?php } ?>
</select>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.stock_location'), 'reports_stock_location_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_stock_location" class="col-xs-3">
<?= form_dropdown('stock_location', $stock_locations, 'all', 'id="location_id" class="form-control"') ?>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="button" class="btn btn-primary" name="generate_report" id="generate_report"><?= lang('Common.submit'); ?></button>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.item_count'), 'reports_item_count_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_item_count" class="col-xs-3">
<?= form_dropdown('item_count', $item_count, 'all', 'id="item_count" class="form-control"') ?>
</div>
</div>
<?php
echo form_button([
'name' => 'generate_report',
'id' => 'generate_report',
'content' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm'
]) ?>
<?= form_close() ?>
<?= view('partial/footer') ?>

View File

@@ -17,84 +17,88 @@ $detailed_reports = [
<?= view('partial/header') ?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<?php
$title_info['config_title'] = 'Reports';
echo view('configs/config_header', $title_info);
if (isset($error)) {
echo '<div class="alert alert-dismissible alert-danger">' . esc($error) . '</div>';
}
?>
<?php if (isset($error)) { ?>
<div class="alert alert-danger alert-dismissible" role="alert">
<?= esc($error) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php } ?>
<div class="row">
<div class="col-12 col-md-6 col-lg-4 mb-3">
<div class="card bg-primary">
<div class="card-header text-light text-truncate">
<i class="bi bi-bar-chart me-2"></i><?= lang('Reports.graphical_reports'); ?>
<div class="col-md-4">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title"><span class="glyphicon glyphicon-stats">&nbsp;</span><?= lang('Reports.graphical_reports') ?></h3>
</div>
<div class="list-group list-group-flush">
<div class="list-group">
<?php foreach ($permission_ids as $permission_id) {
if (can_show_report($permission_id, ['inventory', 'receiving'])) {
$link = get_report_link($permission_id, 'graphical_summary'); ?>
<a class="list-group-item list-group-item-action text-truncate" href="<?= $link['path'] ?>"><?= esc($link['label']) ?></a>
<?php }} ?>
$link = get_report_link($permission_id, 'graphical_summary');
?>
<a class="list-group-item" href="<?= $link['path'] ?>"><?= esc($link['label']) ?></a>
<?php
}
}
?>
</div>
</div>
</div>
<div class="col-12 col-md-6 col-lg-4 mb-3">
<div class="card bg-primary">
<div class="card-header text-light text-truncate">
<i class="bi bi-card-list me-2"></i><?= lang('Reports.summary_reports'); ?>
<div class="col-md-4">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title"><span class="glyphicon glyphicon-list">&nbsp;</span><?= lang('Reports.summary_reports') ?></h3>
</div>
<div class="list-group list-group-flush">
<div class="list-group">
<?php foreach ($permission_ids as $permission_id) {
if (can_show_report($permission_id, ['inventory', 'receiving'])) {
$link = get_report_link($permission_id, 'summary'); ?>
<a class="list-group-item list-group-item-action text-truncate" href="<?= $link['path'] ?>"><?= esc($link['label']) ?></a>
<?php }} ?>
$link = get_report_link($permission_id, 'summary');
?>
<a class="list-group-item" href="<?= $link['path'] ?>"><?= esc($link['label']) ?></a>
<?php
}
}
?>
</div>
</div>
</div>
<div class="col-12 col-lg-4">
<div class="row">
<div class="col-12 col-md-6 col-lg-12 mb-3">
<div class="card bg-primary">
<div class="card-header text-light text-truncate">
<i class="bi bi-card-checklist me-2"></i><?= lang('Reports.detailed_reports') ?>
</div>
<div class="list-group list-group-flush">
<?php foreach ($detailed_reports as $report_name => $prefix) {
if (in_array($report_name, $permission_ids, true)) {
$link = get_report_link($report_name, $prefix); ?>
<a class="list-group-item list-group-item-action text-truncate" href="<?= $link['path'] ?>"><?= esc($link['label']) ?></a>
<?php }} ?>
</div>
<div class="col-md-4">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title"><span class="glyphicon glyphicon-list-alt">&nbsp;</span><?= lang('Reports.detailed_reports') ?></h3>
</div>
<div class="list-group">
<?php foreach ($detailed_reports as $report_name => $prefix) {
if (in_array($report_name, $permission_ids, true)) {
$link = get_report_link($report_name, $prefix);
?>
<a class="list-group-item" href="<?= $link['path'] ?>"><?= esc($link['label']) ?></a>
<?php
}
}
?>
</div>
</div>
<?php if (in_array('reports_inventory', $permission_ids, true)) { ?>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title"><span class="glyphicon glyphicon-book">&nbsp;</span><?= lang('Reports.inventory_reports') ?></h3>
</div>
<div class="list-group">
<?php
$inventory_low_report = get_report_link('reports_inventory_low');
$inventory_summary_report = get_report_link('reports_inventory_summary');
?>
<a class="list-group-item" href="<?= $inventory_low_report['path'] ?>"><?= esc($inventory_low_report['label']) ?></a>
<a class="list-group-item" href="<?= $inventory_summary_report['path'] ?>"><?= esc($inventory_summary_report['label']) ?></a>
</div>
</div>
<?php if (in_array('reports_inventory', $permission_ids, true)) { ?>
<div class="col-12 col-md-6 col-lg-12 mb-3">
<div class="card bg-primary">
<div class="card-header text-light text-truncate">
<i class="bi bi-box me-2"></i><?= lang('Reports.inventory_reports') ?>
</div>
<div class="list-group list-group-flush">
<?php
$inventory_low_report = get_report_link('reports_inventory_low');
$inventory_summary_report = get_report_link('reports_inventory_summary');
?>
<a class="list-group-item list-group-item-action text-truncate" href="<?= $inventory_low_report['path'] ?>"><?= esc($inventory_low_report['label']) ?></a>
<a class="list-group-item list-group-item-action text-truncate" href="<?= $inventory_summary_report['path'] ?>"><?= esc($inventory_summary_report['label']) ?></a>
</div>
</div>
</div>
<?php } ?>
</div>
<?php } ?>
</div>
</div>

View File

@@ -9,10 +9,11 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = lang('Reports.report_input');
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<div id="page_title"><?= lang('Reports.report_input') ?></div>
<?php
if (isset($error)) {
@@ -20,68 +21,49 @@ if (isset($error)) {
}
?>
<?= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div class="row">
<div class="col-12 col-lg-6">
<label for="daterangepicker" class="form-label"><?= lang('Reports.date_range') ?></label>
<div class="input-group mb-3">
<span class="input-group-text" id="daterangepicker-icon"><i class="bi bi-calendar2-range"></i></span>
<input type="text" class="form-select" name="daterangepicker" id="daterangepicker" aria-describedby="daterangepicker-icon">
</div>
</div>
<div class="col-12 col-lg-6">
<label for="specific_input_data" class="form-label"><?= $specific_input_name ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text"><i class="bi bi-person"></i></span>
<select class="form-select" name="specific_input_data" id="specific_input_data" required>
<?php foreach ($specific_input_data as $key => $value): ?>
<option value="<?= $key ?>"><?= $value ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="input_type" class="form-label"><?= lang('Reports.sale_type') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3 report_sale_type">
<span class="input-group-text"><i class="bi bi-receipt"></i></span>
<select class="form-select" name="sale_type" id="input_type" required>
<?php foreach ($sale_type_options as $key => $value): ?>
<option value="<?= $key ?>" <?= $key === 'complete' ? 'selected' : '' ?>><?= $value ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col-12 col-lg-6">
<label for="input_payment_type" class="form-label"><?= lang('Reports.payment_type') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3 report_sale_type">
<span class="input-group-text"><i class="bi bi-receipt"></i></span>
<select class="form-select" name="payment_type" id="input_payment_type" required>
<?php foreach ($payment_type as $key => $value): ?>
<option value="<?= $key ?>"><?= $value ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.date_range'), 'report_date_range_label', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-3">
<?= form_input(['name' => 'daterangepicker', 'class' => 'form-control input-sm', 'id' => 'daterangepicker']) ?>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="button" class="btn btn-primary" name="generate_report" id="generate_report"><?= lang('Common.submit'); ?></button>
<div class="form-group form-group-sm" id="report_specific_input_data">
<?= form_label($specific_input_name, 'specific_input_name_label', ['class' => 'required control-label col-xs-2']) ?>
<div class="col-xs-3">
<?= form_dropdown('specific_input_data', $specific_input_data, '', 'id="specific_input_data" class="form-control selectpicker" data-live-search="true"') ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.sale_type'), 'reports_sale_type_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_sale_type" class="col-xs-3">
<?= form_dropdown('sale_type', $sale_type_options, 'complete', 'id="input_type" class="form-control"') ?>
</div>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.payment_type'), 'reports_payment_type_label', ['class' => 'required control-label col-xs-2']) ?>
<div class="col-xs-3">
<?= form_dropdown('payment_type', $payment_type, '', 'id="input_payment_type" class="form-control"') ?>
</div>
</div>
<?php
echo form_button([
'name' => 'generate_report',
'id' => 'generate_report',
'content' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm'
]); ?>
<?= form_close() ?>
<?= view('partial/footer') ?>
<script type="text/javascript">
new TomSelect('#specific_input_data',{
plugins: ['dropdown_input'],
placeholder: 'Type to search...',
});
$(document).ready(function() {
<?= view('partial/daterangepicker') ?>

View File

@@ -9,10 +9,11 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = lang('Reports.report_input');
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<div id="page_title"><?= lang('Reports.report_input') ?></div>
<?php
if (isset($error)) {
@@ -20,65 +21,58 @@ if (isset($error)) {
}
?>
<?= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data']) ?>
<?= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
<div class="row">
<div class="col-12 col-lg-6">
<label for="daterangepicker" class="form-label"><?= lang('Reports.date_range') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3">
<span class="input-group-text" id="daterangepicker-icon"><i class="bi bi-calendar2-range"></i></span>
<input type="text" class="form-select" name="daterangepicker" id="daterangepicker" aria-describedby="daterangepicker-icon" required>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.date_range'), 'report_date_range_label', ['class' => 'control-label col-xs-2 required']) ?>
<div class="col-xs-3">
<?= form_input(['name' => 'daterangepicker', 'class' => 'form-control input-sm', 'id' => 'daterangepicker']) ?>
</div>
</div>
<?php if (isset($discount_type_options)) { ?>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.discount_type'), 'reports_discount_type_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_discount_type" class="col-xs-3">
<?= form_dropdown('discount_type', $discount_type_options, $config['default_sales_discount_type'], ['id' => 'discount_type_id', 'class' => 'form-control']) ?>
</div>
</div>
<?php } ?>
<div class="form-group form-group-sm" id="report_specific_input_data">
<?= form_label($specific_input_name, 'specific_input_name_label', ['class' => 'required control-label col-xs-2']) ?>
<div class="col-xs-3 discount_percent">
<?= form_dropdown('specific_input_data', $specific_input_data, '', 'id="specific_input_data" class="form-control"') ?>
</div>
<?php if (isset($discount_type_options)) { ?>
<div class="col-12 col-lg-6">
<label for="reports_discount_type_label" class="form-label"><?= lang('Reports.discount_type') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3" id="report_discount_type">
<span class="input-group-text"><i class="bi bi-patch-minus"></i></span>
<select class="form-select" name="discount_type" id="discount_type_id" required>
<?php foreach ($discount_type_options as $value => $label) { ?>
<option value="<?= $value ?>" <?= $value == $config['default_sales_discount_type'] ? 'selected' : '' ?>><?= $label ?></option>
<?php } ?>
</select>
</div>
<div class="col-xs-3 discount_fixed">
<?= form_input([
'name' => 'discount_fixed',
'id' => 'discount_fixed',
'class' => 'form-control input-sm required',
'type' => 'number',
'min' => 0,
'value' => $config['default_sales_discount']
]) ?>
</div>
<?php } ?>
</div>
<div class="col-12 col-lg-6">
<label for="specific_input_name_label" class="form-label"><?= $specific_input_name ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3 discount_percent">
<span class="input-group-text"><i class="bi bi-dot"></i></span>
<select class="form-select w-25" name="specific_input_data" id="specific_input_data" required>
<?php foreach ($specific_input_data as $value => $label) { ?>
<option value="<?= $value ?>"><?= $label ?></option>
<?php } ?>
</select>
</div>
<?php if (isset($discount_type_options)) { ?>
<div class="input-group mb-3 discount_fixed">
<span class="input-group-text"><i class="bi bi-cash"></i></span>
<input type="number" min="0" name="discount_fixed" id="discount_fixed" class="form-control" value="<?= $config['default_sales_discount'] ?>" required>
</div>
<?php } ?>
</div>
<div class="col-12 col-lg-6">
<label for="reports_sale_type_label" class="form-label"><?= lang('Reports.sale_type') ?><sup><span class="badge text-primary"><i class="bi bi-asterisk"></i></span></sup></label>
<div class="input-group mb-3" id="report_sale_type">
<span class="input-group-text"><i class="bi bi-receipt"></i></span>
<select class="form-select" name="sale_type" id="input_type" required>
<?php foreach ($sale_type_options as $value => $label) { ?>
<option value="<?= $value ?>" <?= $value === 'complete' ? 'selected' : '' ?>><?= $label ?></option>
<?php } ?>
</select>
</div>
<div class="form-group form-group-sm">
<?= form_label(lang('Reports.sale_type'), 'reports_sale_type_label', ['class' => 'required control-label col-xs-2']) ?>
<div id="report_sale_type" class="col-xs-3">
<?= form_dropdown('sale_type', $sale_type_options, 'complete', 'id="input_type" class="form-control"') ?>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="button" class="btn btn-primary" name="generate_report" id="generate_report"><?= lang('Common.submit'); ?></button>
</div>
<?php
echo form_button([
'name' => 'generate_report',
'id' => 'generate_report',
'content' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm'
]) ?>
<?= form_close() ?>
@@ -94,7 +88,7 @@ if (isset($error)) {
$("#generate_report").click(function() {
var specific_input_data = $('#specific_input_data').val();
if ($('#discount_fixed').length && !$("#discount_percent").is(":visible")) {
if (!$(".discount_percent").is(":visible")) {
specific_input_data = $('#discount_fixed').val();
}

View File

@@ -11,17 +11,18 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = esc($title);
echo view('configs/config_header', $title_info);
?>
<script type="text/javascript">
dialog_support.init("a.modal-dlg");
</script>
<h5><?= esc($subtitle) ?></h5>
<div id="page_title"><?= esc($title) ?></div>
<div id="page_subtitle"><?= esc($subtitle) ?></div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary d-print-none" id="toggleCostProfitButton">
<i class="bi bi-toggles"></i><span class="d-none d-sm-inline ms-2"><?= lang('Reports.toggle_cost_and_profit') ?></span>
<div class="pull-left form-inline" role="toolbar">
<button id="toggleCostProfitButton" class="btn btn-default btn-sm print_hide">
<?php echo lang('Reports.toggle_cost_and_profit'); ?>
</button>
</div>
</div>
@@ -53,7 +54,6 @@ echo view('configs/config_header', $title_info);
.addClass("table-striped")
.addClass("table-bordered")
.bootstrapTable({
toolbar: '#toolbar',
columns: applyColumnVisibility(<?= transform_headers(esc($headers), true, false) ?>),
stickyHeader: true,
stickyHeaderOffsetLeft: $('#table').offset().left + 'px',
@@ -66,13 +66,10 @@ echo view('configs/config_header', $title_info);
pagination: true,
showColumns: true,
data: <?= json_encode($data) ?>,
iconSize: 'sm',
paginationVAlign: 'bottom',
escape: true,
search: true,
loadingTemplate: function (loadingMessage) {
return '<div class="w-100 h-100 bg-body text-center pt-2"><div class="spinner-grow spinner-grow-sm"></div><span class="ps-1" role="status">' + loadingMessage + '</span></div>'
},
loadingFontSize: '1em'
search: true
});
});
</script>

View File

@@ -12,17 +12,15 @@
<?= view('partial/header') ?>
<?php
$title_info['config_title'] = esc($title);
echo view('configs/config_header', $title_info);
?>
<div id="page_title"><?= esc($title) ?></div>
<h5><?= esc($subtitle) ?></h5>
<div id="page_subtitle"><?= esc($subtitle) ?></div>
<div id="toolbar">
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary d-print-none" id="toggleCostProfitButton">
<i class="bi bi-toggles"></i><span class="d-none d-sm-inline ms-2"><?= lang('Reports.toggle_cost_and_profit') ?></span>
<div class="pull-left form-inline" role="toolbar">
<!-- Toggle Button -->
<button id="toggleCostProfitButton" class="btn btn-default btn-sm print_hide">
<?php echo lang('Reports.toggle_cost_and_profit'); ?>
</button>
</div>
</div>
@@ -50,7 +48,7 @@ echo view('configs/config_header', $title_info);
var init_dialog = function () {
<?php if (isset($editable)) { ?>
table_support.submit_handler('<?= esc(site_url("reports/get_detailed_$editable" . '_row')) ?>');
dialog_support.init("a.modal-launch");
dialog_support.init("a.modal-dlg");
<?php } ?>
};
@@ -58,7 +56,6 @@ echo view('configs/config_header', $title_info);
.addClass("table-striped")
.addClass("table-bordered")
.bootstrapTable({
toolbar: '#toolbar',
columns: applyColumnVisibility(<?= transform_headers(esc($headers['summary']), true) ?>),
stickyHeader: true,
stickyHeaderOffsetLeft: $('#table').offset().left + 'px',
@@ -72,17 +69,14 @@ echo view('configs/config_header', $title_info);
exportDataType: 'all',
exportTypes: ['json', 'xml', 'csv', 'txt', 'sql', 'excel', 'pdf'],
data: <?= json_encode($summary_data) ?>,
loadingTemplate: function (loadingMessage) {
return '<div class="w-100 h-100 bg-body text-center pt-2"><div class="spinner-grow spinner-grow-sm"></div><span class="ps-1" role="status">' + loadingMessage + '</span></div>'
},
loadingFontSize: '1em',
iconSize: 'sm',
paginationVAlign: 'bottom',
detailView: true,
escape: true,
search: true,
onPageChange: init_dialog,
onPostBody: function () {
dialog_support.init("a.modal-launch");
dialog_support.init("a.modal-dlg");
},
onExpandRow: function (index, row, $detail) {
$detail.html('<table></table>').find("table").bootstrapTable({

Some files were not shown because too many files have changed in this diff Show More