mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-25 00:44:03 -04:00
Compare commits
1 Commits
master
...
refactor-4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62236aec30 |
@@ -91,7 +91,7 @@ class Expenses extends Secure_Controller
|
||||
*/
|
||||
public function getView(int $expense_id = NEW_ENTRY): string
|
||||
{
|
||||
$data = []; // TODO: Duplicated code
|
||||
$data = [];
|
||||
|
||||
$data['expenses_info'] = $this->expense->get_info($expense_id);
|
||||
$expense_id = $data['expenses_info']->expense_id;
|
||||
|
||||
@@ -11,6 +11,7 @@ use App\Models\Item_kit;
|
||||
use App\Models\Receiving;
|
||||
use App\Models\Stock_location;
|
||||
use App\Models\Supplier;
|
||||
use App\Traits\Controller\Shared;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\OSPOS;
|
||||
use Config\Services;
|
||||
@@ -18,6 +19,7 @@ use ReflectionException;
|
||||
|
||||
class Receivings extends Secure_Controller
|
||||
{
|
||||
use Shared;
|
||||
private Receiving_lib $receiving_lib;
|
||||
private Token_lib $token_lib;
|
||||
private Barcode_lib $barcode_lib;
|
||||
@@ -208,7 +210,7 @@ class Receivings extends Secure_Controller
|
||||
$quantity = parse_quantity($this->request->getPost('quantity'));
|
||||
$raw_receiving_quantity = parse_quantity($this->request->getPost('receiving_quantity'));
|
||||
|
||||
$description = $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS); // TODO: Duplicated code
|
||||
$description = $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$serialnumber = $this->request->getPost('serialnumber', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? '';
|
||||
$discount_type = $this->request->getPost('discount_type', FILTER_SANITIZE_NUMBER_INT);
|
||||
$discount = $discount_type
|
||||
@@ -425,19 +427,10 @@ class Receivings extends Secure_Controller
|
||||
$employee_info = $this->employee->get_info($receiving_info['employee_id']);
|
||||
$data['employee'] = $employee_info->first_name . ' ' . $employee_info->last_name;
|
||||
|
||||
$supplier_id = $this->receiving_lib->get_supplier(); // TODO: Duplicated code
|
||||
$supplier_id = $this->receiving_lib->get_supplier();
|
||||
if ($supplier_id != -1) {
|
||||
$supplier_info = $this->supplier->get_info($supplier_id);
|
||||
$data['supplier'] = $supplier_info->company_name;
|
||||
$data['first_name'] = $supplier_info->first_name;
|
||||
$data['last_name'] = $supplier_info->last_name;
|
||||
$data['supplier_email'] = $supplier_info->email;
|
||||
$data['supplier_address'] = $supplier_info->address_1;
|
||||
if (!empty($supplier_info->zip) or !empty($supplier_info->city)) {
|
||||
$data['supplier_location'] = $supplier_info->zip . ' ' . $supplier_info->city;
|
||||
} else {
|
||||
$data['supplier_location'] = '';
|
||||
}
|
||||
$this->buildSupplierInfo($supplier_info, $data);
|
||||
}
|
||||
|
||||
$data['print_after_sale'] = false;
|
||||
@@ -474,18 +467,9 @@ class Receivings extends Secure_Controller
|
||||
|
||||
$supplier_id = $this->receiving_lib->get_supplier();
|
||||
|
||||
if ($supplier_id != -1) { // TODO: Duplicated Code... replace -1 with a constant
|
||||
if ($supplier_id != -1) {
|
||||
$supplier_info = $this->supplier->get_info($supplier_id);
|
||||
$data['supplier'] = $supplier_info->company_name;
|
||||
$data['first_name'] = $supplier_info->first_name;
|
||||
$data['last_name'] = $supplier_info->last_name;
|
||||
$data['supplier_email'] = $supplier_info->email;
|
||||
$data['supplier_address'] = $supplier_info->address_1;
|
||||
if (!empty($supplier_info->zip) or !empty($supplier_info->city)) {
|
||||
$data['supplier_location'] = $supplier_info->zip . ' ' . $supplier_info->city;
|
||||
} else {
|
||||
$data['supplier_location'] = '';
|
||||
}
|
||||
$this->buildSupplierInfo($supplier_info, $data);
|
||||
}
|
||||
|
||||
$data['print_after_sale'] = $this->receiving_lib->is_print_after_sale();
|
||||
|
||||
@@ -128,8 +128,8 @@ class Reports extends Secure_Controller
|
||||
* @param string $location_id
|
||||
* @return string
|
||||
*/
|
||||
public function summary_sales(string $start_date, string $end_date, string $sale_type, string $location_id = 'all'): string // TODO: Perhaps these need to be passed as an array? Too many parameters in the signature.
|
||||
{ // TODO: Duplicated code
|
||||
public function summary_sales(string $start_date, string $end_date, string $sale_type, string $location_id = 'all'): string
|
||||
{
|
||||
$this->clearCache();
|
||||
|
||||
$inputs = [
|
||||
@@ -176,7 +176,7 @@ class Reports extends Secure_Controller
|
||||
* @return string
|
||||
*/
|
||||
public function summary_categories(string $start_date, string $end_date, string $sale_type, string $location_id = 'all'): string
|
||||
{ // TODO: Duplicated code
|
||||
{
|
||||
$this->clearCache();
|
||||
|
||||
$inputs = [
|
||||
@@ -493,7 +493,7 @@ class Reports extends Secure_Controller
|
||||
* @return string
|
||||
*/
|
||||
public function summary_sales_taxes(string $start_date, string $end_date, string $sale_type, string $location_id = 'all'): string
|
||||
{ // TODO: Duplicated code
|
||||
{
|
||||
$this->clearCache();
|
||||
|
||||
$inputs = [
|
||||
|
||||
@@ -20,6 +20,7 @@ use App\Models\Stock_location;
|
||||
use App\Models\Tokens\Token_invoice_count;
|
||||
use App\Models\Tokens\Token_customer;
|
||||
use App\Models\Tokens\Token_invoice_sequence;
|
||||
use App\Traits\Controller\Shared;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
use Config\OSPOS;
|
||||
@@ -28,6 +29,7 @@ use stdClass;
|
||||
|
||||
class Sales extends Secure_Controller
|
||||
{
|
||||
use Shared;
|
||||
protected $helpers = ['file'];
|
||||
private Barcode_lib $barcode_lib;
|
||||
private Email_lib $email_lib;
|
||||
@@ -731,7 +733,7 @@ class Sales extends Secure_Controller
|
||||
$data["customer_comments"] = $customer_info->comments;
|
||||
$data['tax_id'] = $customer_info->tax_id;
|
||||
}
|
||||
$tax_details = $this->tax_lib->get_taxes($data['cart']); // TODO: Duplicated code
|
||||
$tax_details = $this->tax_lib->get_taxes($data['cart']);
|
||||
$data['taxes'] = $tax_details[0];
|
||||
$data['discount'] = $this->sale_lib->get_discount();
|
||||
$data['payments'] = $this->sale_lib->get_payments();
|
||||
@@ -743,7 +745,7 @@ class Sales extends Secure_Controller
|
||||
$data['payments_total'] = $totals['payment_total'];
|
||||
$data['payments_cover_total'] = $totals['payments_cover_total'];
|
||||
$data['cash_rounding'] = $this->session->get('cash_rounding');
|
||||
$data['cash_mode'] = $this->session->get('cash_mode'); // TODO: Duplicated code
|
||||
$data['cash_mode'] = $this->session->get('cash_mode');
|
||||
$data['prediscount_subtotal'] = $totals['prediscount_subtotal'];
|
||||
$data['cash_total'] = $totals['cash_total'];
|
||||
$data['non_cash_total'] = $totals['total'];
|
||||
@@ -1098,7 +1100,7 @@ class Sales extends Secure_Controller
|
||||
$data['subtotal'] = $totals['subtotal'];
|
||||
$data['payments_total'] = $totals['payment_total'];
|
||||
$data['payments_cover_total'] = $totals['payments_cover_total'];
|
||||
$data['cash_mode'] = $this->session->get('cash_mode'); // TODO: Duplicated code.
|
||||
$data['cash_mode'] = $this->session->get('cash_mode');.
|
||||
$data['prediscount_subtotal'] = $totals['prediscount_subtotal'];
|
||||
$data['cash_total'] = $totals['cash_total'];
|
||||
$data['non_cash_total'] = $totals['total'];
|
||||
@@ -1126,35 +1128,15 @@ class Sales extends Secure_Controller
|
||||
$data['quote_number'] = $sale_info['quote_number'];
|
||||
$data['sale_status'] = $sale_info['sale_status'];
|
||||
|
||||
$data['company_info'] = implode("\n", [$this->config['address'], $this->config['phone']]); // TODO: Duplicated code.
|
||||
|
||||
if ($this->config['account_number']) {
|
||||
$data['company_info'] .= "\n" . lang('Sales.account_number') . ": " . $this->config['account_number'];
|
||||
}
|
||||
if ($this->config['tax_id'] != '') {
|
||||
$data['company_info'] .= "\n" . lang('Sales.tax_id') . ": " . $this->config['tax_id'];
|
||||
}
|
||||
$data['company_info'] = $this->buildCompanyInfo();
|
||||
|
||||
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
|
||||
$data['print_after_sale'] = false;
|
||||
$data['price_work_orders'] = false;
|
||||
|
||||
if ($this->sale_lib->get_mode() == 'sale_invoice') { // TODO: Duplicated code.
|
||||
$data['mode_label'] = lang('Sales.invoice');
|
||||
$data['customer_required'] = lang('Sales.customer_required');
|
||||
} elseif ($this->sale_lib->get_mode() == 'sale_quote') {
|
||||
$data['mode_label'] = lang('Sales.quote');
|
||||
$data['customer_required'] = lang('Sales.customer_required');
|
||||
} elseif ($this->sale_lib->get_mode() == 'sale_work_order') {
|
||||
$data['mode_label'] = lang('Sales.work_order');
|
||||
$data['customer_required'] = lang('Sales.customer_required');
|
||||
} elseif ($this->sale_lib->get_mode() == 'return') {
|
||||
$data['mode_label'] = lang('Sales.return');
|
||||
$data['customer_required'] = lang('Sales.customer_optional');
|
||||
} else {
|
||||
$data['mode_label'] = lang('Sales.receipt');
|
||||
$data['customer_required'] = lang('Sales.customer_optional');
|
||||
}
|
||||
$modeData = $this->getSaleModeLabel($this->sale_lib->get_mode());
|
||||
$data['mode_label'] = $modeData['mode_label'];
|
||||
$data['customer_required'] = $modeData['customer_required'];
|
||||
|
||||
$invoice_type = $this->config['invoice_type'];
|
||||
if (!Sale_lib::isValidInvoiceType($invoice_type)) {
|
||||
@@ -1192,7 +1174,7 @@ class Sales extends Secure_Controller
|
||||
$data['stock_locations'] = $this->stock_location->get_allowed_locations('sales');
|
||||
$data['stock_location'] = $this->sale_lib->get_sale_location();
|
||||
$data['tax_exclusive_subtotal'] = $this->sale_lib->get_subtotal(true, true);
|
||||
$tax_details = $this->tax_lib->get_taxes($data['cart']); // TODO: Duplicated code.
|
||||
$tax_details = $this->tax_lib->get_taxes($data['cart']);.
|
||||
$data['taxes'] = $tax_details[0];
|
||||
$data['discount'] = $this->sale_lib->get_discount();
|
||||
$data['payments'] = $this->sale_lib->get_payments();
|
||||
@@ -1210,7 +1192,7 @@ class Sales extends Secure_Controller
|
||||
// cash_mode indicates whether this sale is going to be processed using cash_rounding
|
||||
$cash_mode = $this->session->get('cash_mode');
|
||||
$data['cash_mode'] = $cash_mode;
|
||||
$data['prediscount_subtotal'] = $totals['prediscount_subtotal']; // TODO: Duplicated code.
|
||||
$data['prediscount_subtotal'] = $totals['prediscount_subtotal'];.
|
||||
$data['cash_total'] = $totals['cash_total'];
|
||||
$data['non_cash_total'] = $totals['total'];
|
||||
$data['cash_amount_due'] = $totals['cash_amount_due'];
|
||||
@@ -1257,23 +1239,9 @@ class Sales extends Secure_Controller
|
||||
$data['quote_number'] = $this->sale_lib->get_quote_number();
|
||||
$data['work_order_number'] = $this->sale_lib->get_work_order_number();
|
||||
|
||||
// TODO: the if/else set below should be converted to a switch
|
||||
if ($this->sale_lib->get_mode() == 'sale_invoice') { // TODO: Duplicated code.
|
||||
$data['mode_label'] = lang('Sales.invoice');
|
||||
$data['customer_required'] = lang('Sales.customer_required');
|
||||
} elseif ($this->sale_lib->get_mode() == 'sale_quote') {
|
||||
$data['mode_label'] = lang('Sales.quote');
|
||||
$data['customer_required'] = lang('Sales.customer_required');
|
||||
} elseif ($this->sale_lib->get_mode() == 'sale_work_order') {
|
||||
$data['mode_label'] = lang('Sales.work_order');
|
||||
$data['customer_required'] = lang('Sales.customer_required');
|
||||
} elseif ($this->sale_lib->get_mode() == 'return') {
|
||||
$data['mode_label'] = lang('Sales.return');
|
||||
$data['customer_required'] = lang('Sales.customer_optional');
|
||||
} else {
|
||||
$data['mode_label'] = lang('Sales.receipt');
|
||||
$data['customer_required'] = lang('Sales.customer_optional');
|
||||
}
|
||||
$modeData = $this->getSaleModeLabel($this->sale_lib->get_mode());
|
||||
$data['mode_label'] = $modeData['mode_label'];
|
||||
$data['customer_required'] = $modeData['customer_required'];
|
||||
|
||||
return view("sales/register", $data);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@ use App\Models\Tax;
|
||||
use App\Models\Tax_category;
|
||||
use App\Models\Tax_code;
|
||||
use App\Models\Tax_jurisdiction;
|
||||
use App\Traits\Controller\Shared;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\OSPOS;
|
||||
use Config\Services;
|
||||
|
||||
class Taxes extends Secure_Controller
|
||||
{
|
||||
use Shared;
|
||||
private array $config;
|
||||
private Tax_lib $tax_lib;
|
||||
private Tax $tax;
|
||||
@@ -140,44 +142,26 @@ class Taxes extends Secure_Controller
|
||||
{
|
||||
$tax_code_info = $this->tax->get_info($tax_code);
|
||||
|
||||
$default_tax_category_id = 1; // Tax category id is always the default tax category // TODO: Replace 1 with constant
|
||||
$default_tax_category = $this->tax->get_tax_category($default_tax_category_id); // TODO: this variable is never used in the code.
|
||||
$default_tax_category_id = 1; // Tax category id is always the default tax category // TODO: This variable is not used anywhere in the code
|
||||
$default_tax_category = $this->tax->get_tax_category($default_tax_category_id); // TODO: This variable is not used anywhere in the code
|
||||
|
||||
$tax_rate_info = $this->tax->get_rate_info($tax_code, $default_tax_category_id);
|
||||
|
||||
$data['rounding_options'] = Rounding_mode::get_rounding_options();
|
||||
$data['html_rounding_options'] = $this->get_html_rounding_options();
|
||||
|
||||
if ($this->config['tax_included']) {
|
||||
$data['default_tax_type'] = Tax_lib::TAX_TYPE_INCLUDED;
|
||||
} else {
|
||||
$data['default_tax_type'] = Tax_lib::TAX_TYPE_EXCLUDED;
|
||||
}
|
||||
|
||||
$data['rounding_options'] = Rounding_mode::get_rounding_options();
|
||||
$data['html_rounding_options'] = $this->get_html_rounding_options();
|
||||
|
||||
if ($tax_code == NEW_ENTRY) { // TODO: Duplicated code
|
||||
$data['tax_code'] = '';
|
||||
$data['tax_code_name'] = '';
|
||||
$data['tax_code_type'] = '0';
|
||||
$data['city'] = '';
|
||||
$data['state'] = '';
|
||||
$data['tax_rate'] = '0.0000';
|
||||
$data['rate_tax_code'] = '';
|
||||
$data['rate_tax_category_id'] = 1;
|
||||
$data['tax_category'] = '';
|
||||
$data['add_tax_category'] = '';
|
||||
$data['rounding_code'] = '0';
|
||||
if ($tax_code == NEW_ENTRY) {
|
||||
$taxData = $this->initDefaultTaxCodeData();
|
||||
$data = array_merge($data, $taxData);
|
||||
} else {
|
||||
$data['tax_code'] = $tax_code;
|
||||
$data['tax_code_name'] = $tax_code_info->tax_code_name;
|
||||
$data['tax_code_type'] = $tax_code_info->tax_code_type;
|
||||
$data['city'] = $tax_code_info->city;
|
||||
$data['state'] = $tax_code_info->state;
|
||||
$data['rate_tax_code'] = $tax_code_info->rate_tax_code;
|
||||
$data['rate_tax_category_id'] = $tax_code_info->rate_tax_category_id;
|
||||
$data['tax_category'] = $tax_code_info->tax_category;
|
||||
$data['add_tax_category'] = '';
|
||||
$data['tax_rate'] = $tax_rate_info->tax_rate;
|
||||
$data['rounding_code'] = $tax_rate_info->rounding_code;
|
||||
$taxData = $this->buildTaxCodeData($tax_code_info, $tax_rate_info);
|
||||
$data = array_merge($data, $taxData);
|
||||
}
|
||||
|
||||
$tax_rates = [];
|
||||
@@ -300,7 +284,7 @@ class Taxes extends Secure_Controller
|
||||
*/
|
||||
public function getView_tax_jurisdictions(int $tax_code = NEW_ENTRY): string // TODO: This appears to be called no where in the code.
|
||||
{
|
||||
$tax_code_info = $this->tax->get_info($tax_code); // TODO: Duplicated code
|
||||
$tax_code_info = $this->tax->get_info($tax_code);
|
||||
|
||||
$default_tax_category_id = 1; // Tax category id is always the default tax category
|
||||
$default_tax_category = $this->tax->get_tax_category($default_tax_category_id); // TODO: This variable is not used anywhere in the code
|
||||
|
||||
@@ -4,16 +4,15 @@ namespace App\Database\Migrations;
|
||||
|
||||
use App\Libraries\Tax_lib;
|
||||
use App\Models\Appconfig;
|
||||
use App\Traits\Database\SalesTaxMigration;
|
||||
use CodeIgniter\Database\Migration;
|
||||
use CodeIgniter\Database\ResultInterface;
|
||||
|
||||
/**
|
||||
* @property tax_lib tax_lib
|
||||
* @property appconfig appconfig
|
||||
*/
|
||||
class Migration_Sales_Tax_Data extends Migration
|
||||
{
|
||||
public const ROUND_UP = 5; // TODO: These need to be moved to constants.php
|
||||
use SalesTaxMigration;
|
||||
|
||||
public const ROUND_UP = 5;
|
||||
public const ROUND_DOWN = 6;
|
||||
public const HALF_FIVE = 7;
|
||||
public const YES = '1';
|
||||
@@ -327,79 +326,18 @@ class Migration_Sales_Tax_Data extends Migration
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public function clean(string $string): string // TODO: $string is not a good name for this variable
|
||||
public function clean(string $string): string
|
||||
{
|
||||
$string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
|
||||
|
||||
return preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
|
||||
return $this->cleanIdentifier($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $sales_taxes
|
||||
* @return void
|
||||
*/
|
||||
public function apply_invoice_taxing(array &$sales_taxes): void
|
||||
{
|
||||
if (!empty($sales_taxes)) { // TODO: Duplicated code
|
||||
$sort = [];
|
||||
|
||||
foreach ($sales_taxes as $key => $value) {
|
||||
$sort['print_sequence'][$key] = $value['print_sequence'];
|
||||
}
|
||||
|
||||
array_multisort($sort['print_sequence'], SORT_ASC, $sales_taxes);
|
||||
}
|
||||
|
||||
$decimals = totals_decimals();
|
||||
|
||||
foreach ($sales_taxes as $row_number => $sales_tax) {
|
||||
$sales_taxes[$row_number]['sale_tax_amount'] = $this->get_sales_tax_for_amount($sales_tax['sale_tax_basis'], $sales_tax['tax_rate'], $sales_tax['rounding_code'], $decimals);
|
||||
}
|
||||
$this->applyInvoiceTaxing($sales_taxes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $sales_taxes
|
||||
* @return void
|
||||
*/
|
||||
public function round_sales_taxes(array &$sales_taxes): void
|
||||
{
|
||||
if (!empty($sales_taxes)) {
|
||||
$sort = [];
|
||||
foreach ($sales_taxes as $k => $v) {
|
||||
$sort['print_sequence'][$k] = $v['print_sequence'];
|
||||
}
|
||||
array_multisort($sort['print_sequence'], SORT_ASC, $sales_taxes);
|
||||
}
|
||||
|
||||
$decimals = totals_decimals();
|
||||
|
||||
foreach ($sales_taxes as $row_number => $sales_tax) {
|
||||
$sale_tax_amount = (float)$sales_tax['sale_tax_amount'];
|
||||
$rounding_code = $sales_tax['rounding_code'];
|
||||
$rounded_sale_tax_amount = $sale_tax_amount;
|
||||
|
||||
if (
|
||||
$rounding_code == PHP_ROUND_HALF_UP
|
||||
|| $rounding_code == PHP_ROUND_HALF_DOWN
|
||||
|| $rounding_code == PHP_ROUND_HALF_EVEN
|
||||
|| $rounding_code == PHP_ROUND_HALF_ODD
|
||||
) {
|
||||
$rounded_sale_tax_amount = round($sale_tax_amount, $decimals, $rounding_code);
|
||||
} elseif ($rounding_code == Migration_Sales_Tax_Data::ROUND_UP) {
|
||||
$fig = (int) str_pad('1', $decimals, '0');
|
||||
$rounded_sale_tax_amount = (ceil($sale_tax_amount * $fig) / $fig);
|
||||
} elseif ($rounding_code == Migration_Sales_Tax_Data::ROUND_DOWN) {
|
||||
$fig = (int) str_pad('1', $decimals, '0');
|
||||
$rounded_sale_tax_amount = (floor($sale_tax_amount * $fig) / $fig);
|
||||
} elseif ($rounding_code == Migration_Sales_Tax_Data::HALF_FIVE) {
|
||||
$rounded_sale_tax_amount = round($sale_tax_amount / 5) * 5;
|
||||
}
|
||||
|
||||
$sales_taxes[$row_number]['sale_tax_amount'] = $rounded_sale_tax_amount;
|
||||
}
|
||||
$this->roundSalesTaxes($sales_taxes, self::ROUND_UP, self::ROUND_DOWN, self::HALF_FIVE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,22 @@
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use App\Traits\Database\SalesTaxMigration;
|
||||
use CodeIgniter\Database\Migration;
|
||||
use App\Libraries\Tax_lib;
|
||||
use App\Models\Appconfig;
|
||||
use CodeIgniter\Database\ResultInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @property appconfig appconfig
|
||||
* @property tax_lib tax_lib
|
||||
*/
|
||||
class Migration_TaxAmount extends Migration
|
||||
{
|
||||
use SalesTaxMigration;
|
||||
|
||||
public const ROUND_UP = 5;
|
||||
public const ROUND_DOWN = 6;
|
||||
public const HALF_FIVE = 7;
|
||||
public const YES = '1';
|
||||
public const VAT_TAX = '0';
|
||||
public const SALES_TAX = '1'; // TODO: It appears that this constant is never used
|
||||
public const SALES_TAX = '1';
|
||||
private Appconfig $appconfig;
|
||||
|
||||
public function __construct()
|
||||
@@ -305,79 +302,18 @@ class Migration_TaxAmount extends Migration
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public function clean(string $string): string // TODO: This can probably go into the migration helper as it's used it more than one migration. Also, $string needs to be refactored to a different name.
|
||||
public function clean(string $string): string
|
||||
{
|
||||
$string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
|
||||
|
||||
return preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
|
||||
return $this->cleanIdentifier($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $sales_taxes
|
||||
* @return void
|
||||
*/
|
||||
public function apply_invoice_taxing(array &$sales_taxes): void
|
||||
{
|
||||
if (!empty($sales_taxes)) { // TODO: Duplicated code
|
||||
$sort = [];
|
||||
foreach ($sales_taxes as $k => $v) {
|
||||
$sort['print_sequence'][$k] = $v['print_sequence'];
|
||||
}
|
||||
array_multisort($sort['print_sequence'], SORT_ASC, $sales_taxes);
|
||||
}
|
||||
|
||||
$decimals = totals_decimals();
|
||||
|
||||
foreach ($sales_taxes as $row_number => $sales_tax) {
|
||||
$sales_taxes[$row_number]['sale_tax_amount'] = $this->get_sales_tax_for_amount($sales_tax['sale_tax_basis'], $sales_tax['tax_rate'], $sales_tax['rounding_code'], $decimals);
|
||||
}
|
||||
$this->applyInvoiceTaxing($sales_taxes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $sales_taxes
|
||||
* @return void
|
||||
*/
|
||||
public function round_sales_taxes(array &$sales_taxes): void
|
||||
{
|
||||
if (!empty($sales_taxes)) {
|
||||
$sort = [];
|
||||
|
||||
foreach ($sales_taxes as $k => $v) {
|
||||
$sort['print_sequence'][$k] = $v['print_sequence'];
|
||||
}
|
||||
|
||||
array_multisort($sort['print_sequence'], SORT_ASC, $sales_taxes);
|
||||
}
|
||||
|
||||
$decimals = totals_decimals();
|
||||
|
||||
foreach ($sales_taxes as $row_number => $sales_tax) {
|
||||
$sale_tax_amount = (float)$sales_tax['sale_tax_amount'];
|
||||
$rounding_code = $sales_tax['rounding_code'];
|
||||
$rounded_sale_tax_amount = $sale_tax_amount;
|
||||
|
||||
if (
|
||||
$rounding_code == PHP_ROUND_HALF_UP // TODO: This block of if/elseif statements can be converted to a switch.
|
||||
|| $rounding_code == PHP_ROUND_HALF_DOWN
|
||||
|| $rounding_code == PHP_ROUND_HALF_EVEN
|
||||
|| $rounding_code == PHP_ROUND_HALF_ODD
|
||||
) {
|
||||
$rounded_sale_tax_amount = round($sale_tax_amount, $decimals, $rounding_code);
|
||||
} elseif ($rounding_code == Migration_TaxAmount::ROUND_UP) {
|
||||
$fig = (int) str_pad('1', $decimals, '0');
|
||||
$rounded_sale_tax_amount = (ceil($sale_tax_amount * $fig) / $fig);
|
||||
} elseif ($rounding_code == Migration_TaxAmount::ROUND_DOWN) {
|
||||
$fig = (int) str_pad('1', $decimals, '0');
|
||||
$rounded_sale_tax_amount = (floor($sale_tax_amount * $fig) / $fig);
|
||||
} elseif ($rounding_code == Migration_TaxAmount::HALF_FIVE) {
|
||||
$rounded_sale_tax_amount = round($sale_tax_amount / 5) * 5;
|
||||
}
|
||||
|
||||
$sales_taxes[$row_number]['sale_tax_amount'] = $rounded_sale_tax_amount;
|
||||
}
|
||||
$this->roundSalesTaxes($sales_taxes, self::ROUND_UP, self::ROUND_DOWN, self::HALF_FIVE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ class Attribute extends Model
|
||||
}
|
||||
} elseif ($from_type === DROPDOWN) {
|
||||
if (in_array($to_type, [TEXT, CHECKBOX], true)) {
|
||||
if ($to_type === CHECKBOX) { // TODO: Duplicated code.
|
||||
if ($to_type === CHECKBOX) {
|
||||
$checkbox_attribute_values = $this->checkbox_attribute_values($definition_id);
|
||||
|
||||
$this->db->transStart();
|
||||
|
||||
@@ -423,7 +423,7 @@ class Customer extends Person
|
||||
$builder->orLike('phone_number', $search);
|
||||
$builder->orLike('account_number', $search);
|
||||
$builder->orLike('company_name', $search);
|
||||
$builder->orLike('CONCAT(first_name, " ", last_name)', $search); // TODO: Duplicated code.
|
||||
$builder->orLike('CONCAT(first_name, " ", last_name)', $search);
|
||||
$builder->groupEnd();
|
||||
$builder->where('deleted', 0);
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ class Module extends Model
|
||||
public function get_allowed_office_modules(int $person_id): ResultInterface
|
||||
{
|
||||
$menus = ['office', 'both'];
|
||||
$builder = $this->db->table('modules'); // TODO: Duplicated code
|
||||
$builder = $this->db->table('modules');
|
||||
$builder->join('permissions', 'permissions.permission_id = modules.module_id');
|
||||
$builder->join('grants', 'permissions.permission_id = grants.permission_id');
|
||||
$builder->where('person_id', $person_id);
|
||||
|
||||
@@ -3,32 +3,21 @@
|
||||
namespace App\Models\Reports;
|
||||
|
||||
use App\Models\Sale;
|
||||
use App\Traits\Models\Reports\SaleTypeFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @property sale sale
|
||||
*
|
||||
*/
|
||||
class Detailed_sales extends Report
|
||||
{
|
||||
/**
|
||||
* @param array $inputs
|
||||
* @return void
|
||||
*/
|
||||
use SaleTypeFilter;
|
||||
|
||||
public function create(array $inputs): void
|
||||
{
|
||||
// Create our temp tables to work with the data in our report
|
||||
$sale = model(Sale::class);
|
||||
$sale->create_temp_table($inputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getDataColumns(): array
|
||||
{
|
||||
return [ // TODO: Duplicated code
|
||||
return [
|
||||
'summary' => [
|
||||
['id' => lang('Reports.sale_id')],
|
||||
['type_code' => lang('Reports.code_type')],
|
||||
@@ -119,47 +108,11 @@ class Detailed_sales extends Report
|
||||
MAX(payment_type) AS payment_type,
|
||||
MAX(comment) AS comment');
|
||||
|
||||
if ($inputs['location_id'] != 'all') { // TODO: Duplicated code
|
||||
if ($inputs['location_id'] != 'all') {
|
||||
$builder->where('item_location', $inputs['location_id']);
|
||||
}
|
||||
|
||||
switch ($inputs['sale_type']) {
|
||||
case 'complete':
|
||||
$builder->where('sale_status', COMPLETED);
|
||||
$builder->groupStart();
|
||||
$builder->where('sale_type', SALE_TYPE_POS);
|
||||
$builder->orWhere('sale_type', SALE_TYPE_INVOICE);
|
||||
$builder->orWhere('sale_type', SALE_TYPE_RETURN);
|
||||
$builder->groupEnd();
|
||||
break;
|
||||
|
||||
case 'sales':
|
||||
$builder->where('sale_status', COMPLETED);
|
||||
$builder->groupStart();
|
||||
$builder->where('sale_type', SALE_TYPE_POS);
|
||||
$builder->orWhere('sale_type', SALE_TYPE_INVOICE);
|
||||
$builder->groupEnd();
|
||||
break;
|
||||
|
||||
case 'quotes':
|
||||
$builder->where('sale_status', SUSPENDED);
|
||||
$builder->where('sale_type', SALE_TYPE_QUOTE);
|
||||
break;
|
||||
|
||||
case 'work_orders':
|
||||
$builder->where('sale_status', SUSPENDED);
|
||||
$builder->where('sale_type', SALE_TYPE_WORK_ORDER);
|
||||
break;
|
||||
|
||||
case 'canceled':
|
||||
$builder->where('sale_status', CANCELED);
|
||||
break;
|
||||
|
||||
case 'returns':
|
||||
$builder->where('sale_status', COMPLETED);
|
||||
$builder->where('sale_type', SALE_TYPE_RETURN);
|
||||
break;
|
||||
}
|
||||
$this->applySaleTypeFilter($builder, $inputs['sale_type'], false);
|
||||
|
||||
$builder->groupBy('sale_id');
|
||||
$builder->orderBy('MAX(sale_time)');
|
||||
@@ -209,56 +162,16 @@ class Detailed_sales extends Report
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inputs
|
||||
* @return array
|
||||
*/
|
||||
public function getSummaryData(array $inputs): array
|
||||
{
|
||||
$builder = $this->db->table('sales_items_temp');
|
||||
$builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
|
||||
|
||||
if ($inputs['location_id'] != 'all') { // TODO: Duplicated code
|
||||
if ($inputs['location_id'] != 'all') {
|
||||
$builder->where('item_location', $inputs['location_id']);
|
||||
}
|
||||
|
||||
switch ($inputs['sale_type']) {
|
||||
case 'complete':
|
||||
$builder->where('sale_status', COMPLETED);
|
||||
$builder->groupStart();
|
||||
$builder->where('sale_type', SALE_TYPE_POS);
|
||||
$builder->orWhere('sale_type', SALE_TYPE_INVOICE);
|
||||
$builder->orWhere('sale_type', SALE_TYPE_RETURN);
|
||||
$builder->groupEnd();
|
||||
break;
|
||||
|
||||
case 'sales':
|
||||
$builder->where('sale_status', COMPLETED);
|
||||
$builder->groupStart();
|
||||
$builder->where('sale_type', SALE_TYPE_POS);
|
||||
$builder->orWhere('sale_type', SALE_TYPE_INVOICE);
|
||||
$builder->groupEnd();
|
||||
break;
|
||||
|
||||
case 'quotes':
|
||||
$builder->where('sale_status', SUSPENDED);
|
||||
$builder->where('sale_type', SALE_TYPE_QUOTE);
|
||||
break;
|
||||
|
||||
case 'work_orders':
|
||||
$builder->where('sale_status', SUSPENDED);
|
||||
$builder->where('sale_type', SALE_TYPE_WORK_ORDER);
|
||||
break;
|
||||
|
||||
case 'canceled':
|
||||
$builder->where('sale_status', CANCELED);
|
||||
break;
|
||||
|
||||
case 'returns':
|
||||
$builder->where('sale_status', COMPLETED);
|
||||
$builder->where('sale_type', SALE_TYPE_RETURN);
|
||||
break;
|
||||
}
|
||||
$this->applySaleTypeFilter($builder, $inputs['sale_type'], false);
|
||||
|
||||
return $builder->get()->getRowArray();
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ class Specific_customer extends Report
|
||||
MAX(payment_type) AS payment_type,
|
||||
MAX(comment) AS comment');
|
||||
|
||||
$builder->where('customer_id', $inputs['customer_id']); // TODO: Duplicated code
|
||||
$builder->where('customer_id', $inputs['customer_id']);
|
||||
|
||||
if ($inputs['payment_type'] == 'invoices') {
|
||||
$builder->where('sale_type', SALE_TYPE_INVOICE);
|
||||
@@ -139,7 +139,7 @@ class Specific_customer extends Report
|
||||
break;
|
||||
}
|
||||
|
||||
$builder->groupBy('sale_id'); // TODO: Duplicated code
|
||||
$builder->groupBy('sale_id');
|
||||
$builder->orderBy('MAX(sale_time)');
|
||||
|
||||
$data = [];
|
||||
|
||||
@@ -27,7 +27,7 @@ class Specific_discount extends Report
|
||||
* @return array
|
||||
*/
|
||||
public function getDataColumns(): array
|
||||
{ // TODO: Duplicated code
|
||||
{
|
||||
return [
|
||||
'summary' => [
|
||||
['id' => lang('Reports.sale_id')],
|
||||
@@ -95,7 +95,7 @@ class Specific_discount extends Report
|
||||
MAX(payment_type) AS payment_type,
|
||||
MAX(comment) AS comment');
|
||||
|
||||
$builder->where('discount >=', $inputs['discount']); // TODO: Duplicated code
|
||||
$builder->where('discount >=', $inputs['discount']);
|
||||
$builder->where('discount_type', $inputs['discount_type']);
|
||||
|
||||
switch ($inputs['sale_type']) {
|
||||
@@ -136,7 +136,7 @@ class Specific_discount extends Report
|
||||
break;
|
||||
}
|
||||
|
||||
$builder->groupBy('sale_id'); // TODO: Duplicated code
|
||||
$builder->groupBy('sale_id');
|
||||
$builder->orderBy('MAX(sale_time)');
|
||||
|
||||
$data = [];
|
||||
@@ -168,7 +168,7 @@ class Specific_discount extends Report
|
||||
$builder = $this->db->table('sales_items_temp');
|
||||
$builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
|
||||
|
||||
$builder->where('discount >=', $inputs['discount']); // TODO: Duplicated code
|
||||
$builder->where('discount >=', $inputs['discount']);
|
||||
$builder->where('discount_type', $inputs['discount_type']);
|
||||
|
||||
// TODO: this needs to be converted to a switch statement
|
||||
|
||||
@@ -93,7 +93,7 @@ class Specific_employee extends Report
|
||||
MAX(payment_type) AS payment_type,
|
||||
MAX(comment) AS comment');
|
||||
|
||||
$builder->where('employee_id', $inputs['employee_id']); // TODO: Duplicated code
|
||||
$builder->where('employee_id', $inputs['employee_id']);
|
||||
|
||||
switch ($inputs['sale_type']) {
|
||||
case 'complete':
|
||||
@@ -164,7 +164,7 @@ class Specific_employee extends Report
|
||||
{
|
||||
$builder = $this->db->table('sales_items_temp');
|
||||
$builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
|
||||
$builder->where('employee_id', $inputs['employee_id']); // TODO: Duplicated code
|
||||
$builder->where('employee_id', $inputs['employee_id']);
|
||||
|
||||
// TODO: this needs to be converted to a switch statement
|
||||
if ($inputs['sale_type'] == 'complete') {
|
||||
|
||||
@@ -77,7 +77,7 @@ class Specific_supplier extends Report
|
||||
MAX(discount_type) AS discount_type,
|
||||
MAX(discount) AS discount');
|
||||
|
||||
$builder->where('supplier_id', $inputs['supplier_id']); // TODO: Duplicated code
|
||||
$builder->where('supplier_id', $inputs['supplier_id']);
|
||||
|
||||
switch ($inputs['sale_type']) {
|
||||
case 'complete':
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace App\Models\Reports;
|
||||
|
||||
use App\Traits\Models\Reports\ReportDateFilter;
|
||||
use Config\OSPOS;
|
||||
|
||||
class Summary_expenses_categories extends Summary_report
|
||||
{
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
protected function _get_data_columns(): array // TODO: Hungarian notation
|
||||
use ReportDateFilter;
|
||||
|
||||
protected function _get_data_columns(): array
|
||||
{
|
||||
return [
|
||||
['category_name' => lang('Reports.expenses_category')],
|
||||
@@ -19,10 +19,6 @@ class Summary_expenses_categories extends Summary_report
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inputs
|
||||
* @return array
|
||||
*/
|
||||
public function getData(array $inputs): array
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
@@ -31,8 +27,7 @@ class Summary_expenses_categories extends Summary_report
|
||||
$builder->select('expense_categories.category_name AS category_name, COUNT(expenses.expense_id) AS count, SUM(expenses.amount) AS total_amount, SUM(expenses.tax_amount) AS total_tax_amount');
|
||||
$builder->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT');
|
||||
|
||||
// TODO: convert this to ternary notation
|
||||
if (empty($config['date_or_time_format'])) { // TODO: Duplicated code
|
||||
if (empty($config['date_or_time_format'])) {
|
||||
$builder->where('DATE(expenses.date) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
|
||||
} else {
|
||||
$builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
|
||||
@@ -46,10 +41,6 @@ class Summary_expenses_categories extends Summary_report
|
||||
return $builder->get()->getResultArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inputs
|
||||
* @return array
|
||||
*/
|
||||
public function getSummaryData(array $inputs): array
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
@@ -57,7 +48,52 @@ class Summary_expenses_categories extends Summary_report
|
||||
$builder = $this->db->table('expenses AS expenses');
|
||||
$builder->select('SUM(expenses.amount) AS expenses_total_amount, SUM(expenses.tax_amount) AS expenses_total_tax_amount');
|
||||
|
||||
if (empty($config['date_or_time_format'])) { // TODO: Duplicated code
|
||||
if (empty($config['date_or_time_format'])) {
|
||||
$builder->where('DATE(expenses.date) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
|
||||
} else {
|
||||
$builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
|
||||
}
|
||||
|
||||
$builder->where('expenses.deleted', 0);
|
||||
|
||||
return $builder->get()->getRowArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inputs
|
||||
* @return array
|
||||
*/
|
||||
public function getData(array $inputs): array
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
$builder = $this->db->table('expenses AS expenses');
|
||||
$builder->select('expense_categories.category_name AS category_name, COUNT(expenses.expense_id) AS count, SUM(expenses.amount) AS total_amount, SUM(expenses.tax_amount) AS total_tax_amount');
|
||||
$builder->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT');
|
||||
|
||||
if (empty($config['date_or_time_format'])) {
|
||||
$builder->where('DATE(expenses.date) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
|
||||
} else {
|
||||
$builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
|
||||
}
|
||||
|
||||
$builder->where('expenses.deleted', 0);
|
||||
|
||||
$builder->groupBy('expense_categories.category_name');
|
||||
$builder->orderBy('expense_categories.category_name');
|
||||
|
||||
return $builder->get()->getResultArray();
|
||||
}
|
||||
|
||||
public function getSummaryData(array $inputs): array
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
$builder = $this->db->table('expenses AS expenses');
|
||||
$builder->select('SUM(expenses.amount) AS expenses_total_amount, SUM(expenses.tax_amount) AS expenses_total_tax_amount');
|
||||
|
||||
if (empty($config['date_or_time_format'])) {
|
||||
$builder->where('DATE(expenses.date) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
|
||||
} else {
|
||||
$builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace App\Models\Reports;
|
||||
|
||||
use App\Traits\Models\Reports\ReportDateFilter;
|
||||
use Config\OSPOS;
|
||||
|
||||
class Summary_payments extends Summary_report
|
||||
{
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
protected function _get_data_columns(): array // TODO: Hungarian notation
|
||||
use ReportDateFilter;
|
||||
|
||||
protected function _get_data_columns(): array
|
||||
{
|
||||
return [
|
||||
['trans_group' => lang('Reports.trans_group')],
|
||||
@@ -22,13 +22,9 @@ class Summary_payments extends Summary_report
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inputs
|
||||
* @return array
|
||||
*/
|
||||
public function getData(array $inputs): array
|
||||
{
|
||||
$cash_payment = lang('Sales.cash'); // TODO: This is never used. Should it be?
|
||||
$cash_payment = lang('Sales.cash');
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
$separator[] = [
|
||||
@@ -41,14 +37,7 @@ class Summary_payments extends Summary_report
|
||||
'trans_due' => ''
|
||||
];
|
||||
|
||||
$where = ''; // TODO: Duplicated code
|
||||
|
||||
// TODO: this needs to be converted to ternary notation
|
||||
if (empty($config['date_or_time_format'])) {
|
||||
$where .= 'DATE(sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
|
||||
} else {
|
||||
$where .= 'sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
|
||||
}
|
||||
$where = $this->buildDateWhereClause($inputs);
|
||||
|
||||
$this->create_summary_payments_temp_tables($where);
|
||||
|
||||
|
||||
@@ -2,25 +2,20 @@
|
||||
|
||||
namespace App\Models\Reports;
|
||||
|
||||
use Config\OSPOS;
|
||||
use App\Traits\Models\Reports\ReportDateFilter;
|
||||
use App\Traits\Models\Reports\SaleTypeFilter;
|
||||
use CodeIgniter\Database\BaseBuilder;
|
||||
use Config\OSPOS;
|
||||
|
||||
abstract class Summary_report extends Report
|
||||
{
|
||||
/**
|
||||
* Private interface implementing the core basic functionality for all reports
|
||||
*/
|
||||
private function __common_select(array $inputs, &$builder): void // TODO: Hungarian notation
|
||||
use ReportDateFilter;
|
||||
use SaleTypeFilter;
|
||||
|
||||
private function __common_select(array $inputs, &$builder): void
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
// TODO: convert to using QueryBuilder. Use App/Models/Reports/Summary_taxes.php getData() as a reference template
|
||||
$where = ''; // TODO: Duplicated code
|
||||
|
||||
if (empty($config['date_or_time_format'])) {
|
||||
$where .= 'DATE(sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
|
||||
} else {
|
||||
$where .= 'sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
|
||||
}
|
||||
$where = $this->buildDateWhereClause($inputs);
|
||||
|
||||
$decimals = totals_decimals();
|
||||
|
||||
@@ -110,48 +105,16 @@ abstract class Summary_report extends Report
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
// TODO: Probably going to need to rework these since you can't reference $builder without it's instantiation.
|
||||
if (empty($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']));
|
||||
} else {
|
||||
$builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
|
||||
}
|
||||
$this->applyDateFilter($builder, $inputs);
|
||||
|
||||
if ($inputs['location_id'] != 'all') {
|
||||
$builder->where('sales_items.item_location', $inputs['location_id']);
|
||||
}
|
||||
|
||||
if ($inputs['sale_type'] == 'complete') {
|
||||
$builder->where('sales.sale_status', COMPLETED);
|
||||
$builder->groupStart();
|
||||
$builder->where('sales.sale_type', SALE_TYPE_POS);
|
||||
$builder->orWhere('sales.sale_type', SALE_TYPE_INVOICE);
|
||||
$builder->orWhere('sales.sale_type', SALE_TYPE_RETURN);
|
||||
$builder->groupEnd();
|
||||
} elseif ($inputs['sale_type'] == 'sales') {
|
||||
$builder->where('sales.sale_status', COMPLETED);
|
||||
$builder->groupStart();
|
||||
$builder->where('sales.sale_type', SALE_TYPE_POS);
|
||||
$builder->orWhere('sales.sale_type', SALE_TYPE_INVOICE);
|
||||
$builder->groupEnd();
|
||||
} elseif ($inputs['sale_type'] == 'quotes') {
|
||||
$builder->where('sales.sale_status', SUSPENDED);
|
||||
$builder->where('sales.sale_type', SALE_TYPE_QUOTE);
|
||||
} elseif ($inputs['sale_type'] == 'work_orders') {
|
||||
$builder->where('sales.sale_status', SUSPENDED);
|
||||
$builder->where('sales.sale_type', SALE_TYPE_WORK_ORDER);
|
||||
} elseif ($inputs['sale_type'] == 'canceled') {
|
||||
$builder->where('sales.sale_status', CANCELED);
|
||||
} elseif ($inputs['sale_type'] == 'returns') {
|
||||
$builder->where('sales.sale_status', COMPLETED);
|
||||
$builder->where('sales.sale_type', SALE_TYPE_RETURN);
|
||||
}
|
||||
$this->applySaleTypeFilter($builder, $inputs['sale_type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected class interface implemented by derived classes where required
|
||||
*/
|
||||
abstract protected function _get_data_columns(): array; // TODO: hungarian notation
|
||||
abstract protected function _get_data_columns(): array;
|
||||
|
||||
/**
|
||||
* @param array $inputs
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
namespace App\Models\Reports;
|
||||
|
||||
use App\Traits\Models\Reports\ReportDateFilter;
|
||||
use Config\OSPOS;
|
||||
|
||||
class Summary_sales_taxes extends Summary_report
|
||||
{
|
||||
use ReportDateFilter;
|
||||
|
||||
private array $config;
|
||||
|
||||
public function __construct()
|
||||
@@ -14,10 +17,7 @@ class Summary_sales_taxes extends Summary_report
|
||||
$this->config = config(OSPOS::class)->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
protected function _get_data_columns(): array // TODO: hungarian notation
|
||||
protected function _get_data_columns(): array
|
||||
{
|
||||
return [
|
||||
['reporting_authority' => lang('Reports.authority')],
|
||||
@@ -28,35 +28,16 @@ class Summary_sales_taxes extends Summary_report
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inputs
|
||||
* @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']));
|
||||
} else {
|
||||
$builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
|
||||
}
|
||||
$this->applyDateFilter($builder, $inputs, 'sales', 'sale_time');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inputs
|
||||
* @return array
|
||||
*/
|
||||
public function getData(array $inputs): array
|
||||
{
|
||||
$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']);
|
||||
} else {
|
||||
$builder->where('sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
|
||||
}
|
||||
$this->applyDateFilter($builder, $inputs, 'sales_taxes', 'sale_time');
|
||||
|
||||
$builder->select('reporting_authority, jurisdiction_name, tax_category, tax_rate, SUM(sale_tax_amount) AS tax');
|
||||
$builder->join('sales', 'sales_taxes.sale_id = sales.sale_id', 'left');
|
||||
|
||||
130
app/Traits/Controller/Shared.php
Normal file
130
app/Traits/Controller/Shared.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits\Controller;
|
||||
|
||||
use Config\OSPOS;
|
||||
|
||||
/**
|
||||
* Shared trait for common controller functionality
|
||||
*/
|
||||
trait Shared
|
||||
{
|
||||
/**
|
||||
* Build supplier info array for views
|
||||
*
|
||||
* @param object $supplier_info Supplier info object
|
||||
* @param array $data Data array to populate
|
||||
* @return void
|
||||
*/
|
||||
protected function buildSupplierInfo(object $supplier_info, array &$data): void
|
||||
{
|
||||
$data['supplier'] = $supplier_info->company_name;
|
||||
$data['first_name'] = $supplier_info->first_name;
|
||||
$data['last_name'] = $supplier_info->last_name;
|
||||
$data['supplier_email'] = $supplier_info->email;
|
||||
$data['supplier_address'] = $supplier_info->address_1;
|
||||
if (!empty($supplier_info->zip) || !empty($supplier_info->city)) {
|
||||
$data['supplier_location'] = $supplier_info->zip . ' ' . $supplier_info->city;
|
||||
} else {
|
||||
$data['supplier_location'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mode label and customer required text based on sale mode
|
||||
*
|
||||
* @param string $mode The sale mode
|
||||
* @return array{mode_label: string, customer_required: string}
|
||||
*/
|
||||
protected function getSaleModeLabel(string $mode): array
|
||||
{
|
||||
return match ($mode) {
|
||||
'sale_invoice' => [
|
||||
'mode_label' => lang('Sales.invoice'),
|
||||
'customer_required' => lang('Sales.customer_required')
|
||||
],
|
||||
'sale_quote' => [
|
||||
'mode_label' => lang('Sales.quote'),
|
||||
'customer_required' => lang('Sales.customer_required')
|
||||
],
|
||||
'sale_work_order' => [
|
||||
'mode_label' => lang('Sales.work_order'),
|
||||
'customer_required' => lang('Sales.customer_required')
|
||||
],
|
||||
'return' => [
|
||||
'mode_label' => lang('Sales.return'),
|
||||
'customer_required' => lang('Sales.customer_optional')
|
||||
],
|
||||
default => [
|
||||
'mode_label' => lang('Sales.receipt'),
|
||||
'customer_required' => lang('Sales.customer_optional')
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build company info string from config
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildCompanyInfo(): string
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
$company_info = implode("\n", [$config['address'], $config['phone']]);
|
||||
|
||||
if (!empty($config['account_number'])) {
|
||||
$company_info .= "\n" . lang('Sales.account_number') . ": " . $config['account_number'];
|
||||
}
|
||||
if (!empty($config['tax_id'])) {
|
||||
$company_info .= "\n" . lang('Sales.tax_id') . ": " . $config['tax_id'];
|
||||
}
|
||||
|
||||
return $company_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize default tax code data for new entry
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initDefaultTaxCodeData(): array
|
||||
{
|
||||
return [
|
||||
'tax_code' => '',
|
||||
'tax_code_name' => '',
|
||||
'tax_code_type' => '0',
|
||||
'city' => '',
|
||||
'state' => '',
|
||||
'tax_rate' => '0.0000',
|
||||
'rate_tax_code' => '',
|
||||
'rate_tax_category_id' => 1,
|
||||
'tax_category' => '',
|
||||
'add_tax_category' => '',
|
||||
'rounding_code' => '0'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate tax code data from existing tax code info
|
||||
*
|
||||
* @param object $tax_code_info Tax code info object
|
||||
* @param object $tax_rate_info Tax rate info object
|
||||
* @return array
|
||||
*/
|
||||
protected function buildTaxCodeData(object $tax_code_info, object $tax_rate_info): array
|
||||
{
|
||||
return [
|
||||
'tax_code' => $tax_code_info->tax_code,
|
||||
'tax_code_name' => $tax_code_info->tax_code_name,
|
||||
'tax_code_type' => $tax_code_info->tax_code_type,
|
||||
'city' => $tax_code_info->city,
|
||||
'state' => $tax_code_info->state,
|
||||
'rate_tax_code' => $tax_code_info->rate_tax_code,
|
||||
'rate_tax_category_id' => $tax_code_info->rate_tax_category_id,
|
||||
'tax_category' => $tax_code_info->tax_category,
|
||||
'add_tax_category' => '',
|
||||
'tax_rate' => $tax_rate_info->tax_rate,
|
||||
'rounding_code' => $tax_rate_info->rounding_code
|
||||
];
|
||||
}
|
||||
}
|
||||
72
app/Traits/Database/SalesTaxMigration.php
Normal file
72
app/Traits/Database/SalesTaxMigration.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits\Database;
|
||||
|
||||
trait SalesTaxMigration
|
||||
{
|
||||
protected function cleanIdentifier(string $string): string
|
||||
{
|
||||
$string = str_replace(' ', '-', $string);
|
||||
return preg_replace('/[^A-Za-z0-9\-]/', '', $string);
|
||||
}
|
||||
|
||||
protected function applyInvoiceTaxing(array &$salesTaxes): void
|
||||
{
|
||||
if (!empty($salesTaxes)) {
|
||||
$sort = [];
|
||||
foreach ($salesTaxes as $k => $v) {
|
||||
$sort['print_sequence'][$k] = $v['print_sequence'];
|
||||
}
|
||||
array_multisort($sort['print_sequence'], SORT_ASC, $salesTaxes);
|
||||
}
|
||||
|
||||
$decimals = totals_decimals();
|
||||
|
||||
foreach ($salesTaxes as $rowNumber => $salesTax) {
|
||||
$salesTaxes[$rowNumber]['sale_tax_amount'] = $this->getSalesTaxForAmount(
|
||||
$salesTax['sale_tax_basis'],
|
||||
$salesTax['tax_rate'],
|
||||
$salesTax['rounding_code'],
|
||||
$decimals
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function roundSalesTaxes(array &$salesTaxes, int $halfUp = 1, int $roundUp = 5, int $roundDown = 6, int $halfFive = 7): void
|
||||
{
|
||||
if (!empty($salesTaxes)) {
|
||||
$sort = [];
|
||||
foreach ($salesTaxes as $k => $v) {
|
||||
$sort['print_sequence'][$k] = $v['print_sequence'];
|
||||
}
|
||||
array_multisort($sort['print_sequence'], SORT_ASC, $salesTaxes);
|
||||
}
|
||||
|
||||
$decimals = totals_decimals();
|
||||
|
||||
foreach ($salesTaxes as $rowNumber => $salesTax) {
|
||||
$saleTaxAmount = (float)$salesTax['sale_tax_amount'];
|
||||
$roundingCode = $salesTax['rounding_code'];
|
||||
$roundedSaleTaxAmount = $saleTaxAmount;
|
||||
|
||||
if (
|
||||
$roundingCode == PHP_ROUND_HALF_UP
|
||||
|| $roundingCode == PHP_ROUND_HALF_DOWN
|
||||
|| $roundingCode == PHP_ROUND_HALF_EVEN
|
||||
|| $roundingCode == PHP_ROUND_HALF_ODD
|
||||
) {
|
||||
$roundedSaleTaxAmount = round($saleTaxAmount, $decimals, $roundingCode);
|
||||
} elseif ($roundingCode == $roundUp) {
|
||||
$fig = (int) str_pad('1', $decimals, '0');
|
||||
$roundedSaleTaxAmount = (ceil($saleTaxAmount * $fig) / $fig);
|
||||
} elseif ($roundingCode == $roundDown) {
|
||||
$fig = (int) str_pad('1', $decimals, '0');
|
||||
$roundedSaleTaxAmount = (floor($saleTaxAmount * $fig) / $fig);
|
||||
} elseif ($roundingCode == $halfFive) {
|
||||
$roundedSaleTaxAmount = round($saleTaxAmount / 5) * 5;
|
||||
}
|
||||
|
||||
$salesTaxes[$rowNumber]['sale_tax_amount'] = $roundedSaleTaxAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
app/Traits/Models/Reports/ReportDateFilter.php
Normal file
30
app/Traits/Models/Reports/ReportDateFilter.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits\Models\Reports;
|
||||
|
||||
use CodeIgniter\Database\BaseBuilder;
|
||||
use Config\OSPOS;
|
||||
|
||||
trait ReportDateFilter
|
||||
{
|
||||
protected function buildDateWhereClause(array $inputs, string $dateColumn = 'sale_time'): string
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
if (empty($config['date_or_time_format'])) {
|
||||
return "DATE({$dateColumn}) BETWEEN " . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
|
||||
}
|
||||
return "{$dateColumn} BETWEEN " . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
|
||||
}
|
||||
|
||||
protected function applyDateFilter(BaseBuilder $builder, array $inputs, string $tablePrefix = 'sales', string $column = 'sale_time'): void
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
if (empty($config['date_or_time_format'])) {
|
||||
$builder->where("DATE({$tablePrefix}.{$column}) BETWEEN " . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
|
||||
} else {
|
||||
$builder->where("{$tablePrefix}.{$column} BETWEEN " . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
|
||||
}
|
||||
}
|
||||
}
|
||||
39
app/Traits/Models/Reports/SaleTypeFilter.php
Normal file
39
app/Traits/Models/Reports/SaleTypeFilter.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Traits\Models\Reports;
|
||||
|
||||
use CodeIgniter\Database\BaseBuilder;
|
||||
|
||||
trait SaleTypeFilter
|
||||
{
|
||||
protected function applySaleTypeFilter(BaseBuilder $builder, string $saleType, bool $usePrefix = true): void
|
||||
{
|
||||
$prefix = $usePrefix ? 'sales.' : '';
|
||||
|
||||
if ($saleType === 'complete') {
|
||||
$builder->where("{$prefix}sale_status", COMPLETED);
|
||||
$builder->groupStart();
|
||||
$builder->where("{$prefix}sale_type", SALE_TYPE_POS);
|
||||
$builder->orWhere("{$prefix}sale_type", SALE_TYPE_INVOICE);
|
||||
$builder->orWhere("{$prefix}sale_type", SALE_TYPE_RETURN);
|
||||
$builder->groupEnd();
|
||||
} elseif ($saleType === 'sales') {
|
||||
$builder->where("{$prefix}sale_status", COMPLETED);
|
||||
$builder->groupStart();
|
||||
$builder->where("{$prefix}sale_type", SALE_TYPE_POS);
|
||||
$builder->orWhere("{$prefix}sale_type", SALE_TYPE_INVOICE);
|
||||
$builder->groupEnd();
|
||||
} elseif ($saleType === 'quotes') {
|
||||
$builder->where("{$prefix}sale_status", SUSPENDED);
|
||||
$builder->where("{$prefix}sale_type", SALE_TYPE_QUOTE);
|
||||
} elseif ($saleType === 'work_orders') {
|
||||
$builder->where("{$prefix}sale_status", SUSPENDED);
|
||||
$builder->where("{$prefix}sale_type", SALE_TYPE_WORK_ORDER);
|
||||
} elseif ($saleType === 'canceled') {
|
||||
$builder->where("{$prefix}sale_status", CANCELED);
|
||||
} elseif ($saleType === 'returns') {
|
||||
$builder->where("{$prefix}sale_status", COMPLETED);
|
||||
$builder->where("{$prefix}sale_type", SALE_TYPE_RETURN);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user