From f54ce7e1df1d1026a4c082fb5ca395cd08af77e3 Mon Sep 17 00:00:00 2001 From: pappastech Date: Tue, 25 Feb 2014 17:34:25 -0500 Subject: [PATCH] Initial commit --- README.txt | 13 + UPGRADE.txt | 4 + WHATS_NEW.txt | 12 + application/.htaccess | 1 + application/cache/.htaccess | 1 + application/cache/index.html | 10 + application/config/autoload.php | 116 + application/config/config.php | 375 +++ application/config/constants.php | 41 + application/config/database.php.tmpl | 69 + application/config/doctypes.php | 15 + application/config/foreign_chars.php | 64 + application/config/hooks.php | 21 + application/config/index.html | 10 + application/config/migration.php | 41 + application/config/mimes.php | 106 + application/config/profiler.php | 17 + application/config/routes.php | 63 + application/config/smileys.php | 66 + application/config/user_agents.php | 178 ++ application/controllers/barcode.php | 14 + application/controllers/config.php | 52 + application/controllers/customers.php | 201 ++ application/controllers/employees.php | 132 ++ application/controllers/giftcards.php | 117 + application/controllers/home.php | 21 + application/controllers/index.html | 10 + .../interfaces/idata_controller.php | 17 + .../interfaces/iperson_controller.php | 11 + application/controllers/item_kits.php | 138 ++ application/controllers/items.php | 551 +++++ application/controllers/languagecheck.php | 192 ++ application/controllers/login.php | 43 + application/controllers/no_access.php | 15 + application/controllers/person_controller.php | 54 + application/controllers/receivings.php | 197 ++ application/controllers/reports.php | 827 +++++++ application/controllers/sales.php | 431 ++++ application/controllers/secure_area.php | 29 + application/controllers/suppliers.php | 131 ++ application/core/index.html | 10 + application/errors/error_404.php | 62 + application/errors/error_db.php | 62 + application/errors/error_general.php | 62 + application/errors/error_php.php | 10 + application/errors/index.html | 10 + application/helpers/currency_helper.php | 28 + application/helpers/index.html | 10 + application/helpers/report_helper.php | 87 + application/helpers/sale_helper.php | 0 application/helpers/table_helper.php | 350 +++ application/hooks/index.html | 10 + application/hooks/load_config.php | 32 + application/index.html | 10 + .../language/Azerbaijan/common_lang.php | 41 + .../language/Azerbaijan/config_lang.php | 35 + .../language/Azerbaijan/customers_lang.php | 16 + .../language/Azerbaijan/employees_lang.php | 27 + .../language/Azerbaijan/error_lang.php | 4 + .../language/Azerbaijan/giftcards_lang.php | 70 + application/language/Azerbaijan/index.html | 10 + .../language/Azerbaijan/item_kits_lang.php | 20 + .../language/Azerbaijan/items_lang.php | 80 + .../language/Azerbaijan/login_lang.php | 8 + .../language/Azerbaijan/module_lang.php | 34 + .../language/Azerbaijan/receivings_lang.php | 26 + .../language/Azerbaijan/reports_lang.php | 87 + .../language/Azerbaijan/sales_lang.php | 79 + .../language/Azerbaijan/suppliers_lang.php | 17 + .../language/BahasaIndonesia/common_lang.php | 41 + .../language/BahasaIndonesia/config_lang.php | 24 + .../BahasaIndonesia/customers_lang.php | 16 + .../BahasaIndonesia/employees_lang.php | 27 + .../language/BahasaIndonesia/error_lang.php | 4 + .../BahasaIndonesia/giftcards_lang.php | 71 + .../language/BahasaIndonesia/index.html | 10 + .../BahasaIndonesia/item_kits_lang.php | 20 + .../language/BahasaIndonesia/items_lang.php | 78 + .../language/BahasaIndonesia/login_lang.php | 8 + .../language/BahasaIndonesia/module_lang.php | 33 + .../BahasaIndonesia/receivings_lang.php | 26 + .../language/BahasaIndonesia/reports_lang.php | 85 + .../language/BahasaIndonesia/sales_lang.php | 78 + .../BahasaIndonesia/suppliers_lang.php | 17 + application/language/Russian/common_lang.php | 41 + application/language/Russian/config_lang.php | 35 + .../language/Russian/customers_lang.php | 16 + .../language/Russian/employees_lang.php | 27 + application/language/Russian/error_lang.php | 4 + .../language/Russian/giftcards_lang.php | 70 + application/language/Russian/index.html | 10 + .../language/Russian/item_kits_lang.php | 20 + application/language/Russian/items_lang.php | 80 + application/language/Russian/login_lang.php | 8 + application/language/Russian/module_lang.php | 34 + .../language/Russian/receivings_lang.php | 26 + application/language/Russian/reports_lang.php | 87 + application/language/Russian/sales_lang.php | 79 + .../language/Russian/suppliers_lang.php | 17 + application/language/Spanish/common_lang.php | 40 + application/language/Spanish/config_lang.php | 24 + .../language/Spanish/customers_lang.php | 16 + .../language/Spanish/employees_lang.php | 27 + application/language/Spanish/error_lang.php | 4 + .../language/Spanish/giftcards_lang.php | 69 + application/language/Spanish/index.html | 10 + .../language/Spanish/item_kits_lang.php | 20 + application/language/Spanish/items_lang.php | 77 + application/language/Spanish/login_lang.php | 8 + application/language/Spanish/module_lang.php | 33 + .../language/Spanish/receivings_lang.php | 26 + application/language/Spanish/reports_lang.php | 85 + application/language/Spanish/sales_lang.php | 78 + .../language/Spanish/suppliers_lang.php | 17 + application/language/english/common_lang.php | 41 + application/language/english/config_lang.php | 35 + .../language/english/customers_lang.php | 16 + .../language/english/employees_lang.php | 27 + application/language/english/error_lang.php | 4 + .../language/english/giftcards_lang.php | 70 + application/language/english/index.html | 10 + .../language/english/item_kits_lang.php | 20 + application/language/english/items_lang.php | 80 + application/language/english/login_lang.php | 8 + application/language/english/module_lang.php | 34 + .../language/english/receivings_lang.php | 26 + application/language/english/reports_lang.php | 87 + application/language/english/sales_lang.php | 79 + .../language/english/suppliers_lang.php | 17 + application/libraries/MY_Language.php | 26 + application/libraries/Receiving_lib.php | 251 ++ application/libraries/Sale_lib.php | 498 ++++ application/libraries/index.html | 10 + application/libraries/ofc-library/JSON.php | 806 +++++++ application/libraries/ofc-library/README.txt | 16 + .../libraries/ofc-library/dot_base.php | 231 ++ .../libraries/ofc-library/json_format.php | 86 + .../libraries/ofc-library/ofc_area_base.php | 40 + .../libraries/ofc-library/ofc_area_hollow.php | 10 + .../libraries/ofc-library/ofc_area_line.php | 10 + .../libraries/ofc-library/ofc_arrow.php | 27 + application/libraries/ofc-library/ofc_bar.php | 34 + .../libraries/ofc-library/ofc_bar_3d.php | 22 + .../libraries/ofc-library/ofc_bar_base.php | 97 + .../libraries/ofc-library/ofc_bar_filled.php | 39 + .../libraries/ofc-library/ofc_bar_glass.php | 131 ++ .../libraries/ofc-library/ofc_bar_sketch.php | 29 + .../libraries/ofc-library/ofc_bar_stack.php | 55 + .../libraries/ofc-library/ofc_candle.php | 41 + .../libraries/ofc-library/ofc_hbar.php | 64 + .../libraries/ofc-library/ofc_line.php | 157 ++ .../libraries/ofc-library/ofc_line_base.php | 92 + .../libraries/ofc-library/ofc_line_dot.php | 33 + .../libraries/ofc-library/ofc_line_hollow.php | 9 + .../libraries/ofc-library/ofc_line_style.php | 11 + .../libraries/ofc-library/ofc_menu.php | 56 + application/libraries/ofc-library/ofc_pie.php | 257 ++ .../libraries/ofc-library/ofc_radar_axis.php | 47 + .../ofc-library/ofc_radar_axis_labels.php | 15 + .../ofc-library/ofc_radar_spoke_labels.php | 15 + .../libraries/ofc-library/ofc_scatter.php | 47 + .../ofc-library/ofc_scatter_line.php | 49 + .../libraries/ofc-library/ofc_shape.php | 25 + .../libraries/ofc-library/ofc_sugar.php | 43 + .../libraries/ofc-library/ofc_tags.php | 133 ++ .../libraries/ofc-library/ofc_title.php | 39 + .../libraries/ofc-library/ofc_tooltip.php | 67 + .../libraries/ofc-library/ofc_x_axis.php | 140 ++ .../ofc-library/ofc_x_axis_label.php | 45 + .../ofc-library/ofc_x_axis_labels.php | 69 + .../libraries/ofc-library/ofc_x_legend.php | 15 + .../libraries/ofc-library/ofc_y_axis.php | 17 + .../libraries/ofc-library/ofc_y_axis_base.php | 116 + .../ofc-library/ofc_y_axis_label.php | 38 + .../ofc-library/ofc_y_axis_labels.php | 57 + .../ofc-library/ofc_y_axis_right.php | 6 + .../libraries/ofc-library/ofc_y_legend.php | 15 + .../ofc-library/open-flash-chart-object.php | 109 + .../ofc-library/open-flash-chart.php | 178 ++ application/logs/index.html | 10 + application/models/appconfig.php | 81 + application/models/customer.php | 245 ++ application/models/employee.php | 325 +++ application/models/giftcard.php | 255 ++ application/models/index.html | 10 + application/models/inventory.php | 18 + application/models/item.php | 579 +++++ application/models/item_kit.php | 171 ++ application/models/item_kit_items.php | 43 + application/models/item_taxes.php | 51 + application/models/module.php | 50 + application/models/person.php | 137 ++ application/models/receiving.php | 118 + .../models/reports/detailed_receivings.php | 67 + application/models/reports/detailed_sales.php | 68 + application/models/reports/inventory_low.php | 31 + .../models/reports/inventory_summary.php | 31 + application/models/reports/report.php | 28 + .../models/reports/specific_customer.php | 66 + .../models/reports/specific_employee.php | 68 + .../models/reports/summary_categories.php | 53 + .../models/reports/summary_customers.php | 54 + .../models/reports/summary_discounts.php | 49 + .../models/reports/summary_employees.php | 55 + application/models/reports/summary_items.php | 52 + .../models/reports/summary_payments.php | 50 + application/models/reports/summary_sales.php | 51 + .../models/reports/summary_suppliers.php | 55 + application/models/reports/summary_taxes.php | 66 + application/models/sale.php | 216 ++ application/models/sale_suspended.php | 160 ++ application/models/supplier.php | 260 ++ application/third_party/index.html | 10 + application/views/barcode.php | 332 +++ application/views/barcode_sheet.php | 28 + application/views/config.php | 439 ++++ application/views/customers/excel_import.php | 63 + application/views/customers/form.php | 73 + application/views/employees/form.php | 158 ++ application/views/giftcards/form.php | 108 + application/views/giftcards/manage.php | 86 + application/views/home.php | 19 + application/views/index.html | 10 + application/views/item_kits/form.php | 138 ++ application/views/item_kits/manage.php | 99 + application/views/items/count_details.php | 114 + application/views/items/excel_import.php | 63 + application/views/items/form.php | 491 ++++ application/views/items/form_bulk.php | 244 ++ application/views/items/inventory.php | 157 ++ application/views/items/manage.php | 183 ++ application/views/login.php | 52 + application/views/no_access.php | 3 + application/views/partial/footer.php | 6 + application/views/partial/footer_excel.php | 3 + application/views/partial/header.php | 70 + application/views/partial/header_excel.php | 54 + application/views/people/form_basic_info.php | 114 + application/views/people/manage.php | 91 + application/views/receivings/receipt.php | 104 + application/views/receivings/receiving.php | 294 +++ application/views/reports/date_input.php | 72 + .../views/reports/date_input_excel_export.php | 83 + application/views/reports/excel_export.php | 39 + application/views/reports/graphical.php | 27 + application/views/reports/graphs/bar.php | 46 + application/views/reports/graphs/hbar.php | 61 + application/views/reports/graphs/line.php | 49 + application/views/reports/graphs/pie.php | 25 + application/views/reports/listing.php | 63 + application/views/reports/specific_input.php | 90 + application/views/reports/tabular.php | 70 + application/views/reports/tabular_details.php | 102 + application/views/sales/delete.php | 18 + application/views/sales/edit.php | 109 + application/views/sales/receipt.php | 120 + application/views/sales/receipt_email.php | 95 + application/views/sales/register.php | 493 ++++ application/views/sales/suspended.php | 46 + application/views/suppliers/form.php | 78 + application/views/suppliers/manage.php | 85 + css/autocomplete.css | 54 + css/datepicker.css | 153 ++ css/editsale.css | 11 + css/general.css | 154 ++ css/login.css | 84 + css/menubar.css | 93 + css/ospos.css | 149 ++ css/ospos_print.css | 41 + css/popupbox.css | 99 + css/receipt.css | 60 + css/register.css | 165 ++ css/reports.css | 26 + css/tables.css | 126 + css/thickbox.css | 165 ++ database/database.sql | 696 ++++++ images/Thumbs.db | Bin 0 -> 5632 bytes images/big_action_button.jpg | Bin 0 -> 22091 bytes images/calendar.png | Bin 0 -> 1091 bytes images/checkbox_arrow.gif | Bin 0 -> 63 bytes images/loading_animation.gif | Bin 0 -> 5886 bytes images/menubar/config.png | Bin 0 -> 5127 bytes images/menubar/customers.png | Bin 0 -> 3745 bytes images/menubar/employees.png | Bin 0 -> 5989 bytes images/menubar/giftcards.png | Bin 0 -> 1485 bytes images/menubar/home.png | Bin 0 -> 5755 bytes images/menubar/item_kits.png | Bin 0 -> 3303 bytes images/menubar/items.png | Bin 0 -> 4702 bytes images/menubar/menubar_bg.gif | Bin 0 -> 419 bytes images/menubar/receivings.png | Bin 0 -> 59454 bytes images/menubar/reports.png | Bin 0 -> 5167 bytes images/menubar/sales.png | Bin 0 -> 4792 bytes images/menubar/suppliers.png | Bin 0 -> 5085 bytes images/menubar/thumb_clock.png | Bin 0 -> 19783 bytes images/menubar/thumb_colorscheme.png | Bin 0 -> 29555 bytes images/minus.png | Bin 0 -> 450 bytes images/plus.png | Bin 0 -> 466 bytes images/psds/big_action_button.psd | Bin 0 -> 40677 bytes images/psds/small_action_button.psd | Bin 0 -> 38389 bytes images/small_action_button.jpg | Bin 0 -> 20633 bytes images/spinner_small.gif | Bin 0 -> 1877 bytes images/tables/asc.gif | Bin 0 -> 54 bytes images/tables/bg.gif | Bin 0 -> 64 bytes images/tables/desc.gif | Bin 0 -> 54 bytes import_customers.csv | 2 + import_items.csv | 2 + index.php | 205 ++ js/common.js | 82 + js/date.js | 502 ++++ js/datepicker.js | 1216 ++++++++++ js/jquery-1.2.6.min.js | 32 + js/jquery.ajax_queue.js | 116 + js/jquery.autocomplete.js | 760 ++++++ js/jquery.bgiframe.min.js | 10 + js/jquery.color.js | 123 + js/jquery.form.js | 660 ++++++ js/jquery.jkey-1.1.js | 254 ++ js/jquery.metadata.js | 122 + js/jquery.tablesorter.min.js | 1 + js/jquery.validate.min.js | 3 + js/manage_tables.js | 333 +++ js/swfobject.js | 5 + js/thickbox.js | 334 +++ license/codeigniter_license.txt | 51 + license/codeigniter_version.txt | 1 + license/license.txt | 19 + open-flash-chart.swf | Bin 0 -> 276186 bytes system/.htaccess | 1 + system/core/Benchmark.php | 118 + system/core/CodeIgniter.php | 401 ++++ system/core/Common.php | 564 +++++ system/core/Config.php | 379 +++ system/core/Controller.php | 64 + system/core/Exceptions.php | 193 ++ system/core/Hooks.php | 248 ++ system/core/Input.php | 723 ++++++ system/core/Lang.php | 160 ++ system/core/Loader.php | 1248 ++++++++++ system/core/Model.php | 57 + system/core/Output.php | 574 +++++ system/core/Router.php | 522 ++++ system/core/Security.php | 866 +++++++ system/core/URI.php | 654 ++++++ system/core/Utf8.php | 165 ++ system/core/index.html | 10 + system/database/DB.php | 162 ++ system/database/DB_active_rec.php | 2041 ++++++++++++++++ system/database/DB_cache.php | 195 ++ system/database/DB_driver.php | 1390 +++++++++++ system/database/DB_forge.php | 382 +++ system/database/DB_result.php | 410 ++++ system/database/DB_utility.php | 414 ++++ .../database/drivers/cubrid/cubrid_driver.php | 792 +++++++ .../database/drivers/cubrid/cubrid_forge.php | 288 +++ .../database/drivers/cubrid/cubrid_result.php | 202 ++ .../drivers/cubrid/cubrid_utility.php | 108 + system/database/drivers/cubrid/index.html | 10 + system/database/drivers/index.html | 10 + system/database/drivers/mssql/index.html | 10 + .../database/drivers/mssql/mssql_driver.php | 667 ++++++ system/database/drivers/mssql/mssql_forge.php | 248 ++ .../database/drivers/mssql/mssql_result.php | 169 ++ .../database/drivers/mssql/mssql_utility.php | 88 + system/database/drivers/mysql/index.html | 10 + .../database/drivers/mysql/mysql_driver.php | 779 ++++++ system/database/drivers/mysql/mysql_forge.php | 273 +++ .../database/drivers/mysql/mysql_result.php | 174 ++ .../database/drivers/mysql/mysql_utility.php | 210 ++ system/database/drivers/mysqli/index.html | 10 + .../database/drivers/mysqli/mysqli_driver.php | 776 ++++++ .../database/drivers/mysqli/mysqli_forge.php | 258 ++ .../database/drivers/mysqli/mysqli_result.php | 174 ++ .../drivers/mysqli/mysqli_utility.php | 87 + system/database/drivers/oci8/index.html | 10 + system/database/drivers/oci8/oci8_driver.php | 808 +++++++ system/database/drivers/oci8/oci8_forge.php | 248 ++ system/database/drivers/oci8/oci8_result.php | 219 ++ system/database/drivers/oci8/oci8_utility.php | 87 + system/database/drivers/odbc/index.html | 10 + system/database/drivers/odbc/odbc_driver.php | 637 +++++ system/database/drivers/odbc/odbc_forge.php | 266 +++ system/database/drivers/odbc/odbc_result.php | 228 ++ system/database/drivers/odbc/odbc_utility.php | 103 + system/database/drivers/pdo/index.html | 10 + system/database/drivers/pdo/pdo_driver.php | 803 +++++++ system/database/drivers/pdo/pdo_forge.php | 266 +++ system/database/drivers/pdo/pdo_result.php | 171 ++ system/database/drivers/pdo/pdo_utility.php | 103 + system/database/drivers/postgre/index.html | 10 + .../drivers/postgre/postgre_driver.php | 703 ++++++ .../drivers/postgre/postgre_forge.php | 299 +++ .../drivers/postgre/postgre_result.php | 169 ++ .../drivers/postgre/postgre_utility.php | 88 + system/database/drivers/sqlite/index.html | 10 + .../database/drivers/sqlite/sqlite_driver.php | 658 ++++++ .../database/drivers/sqlite/sqlite_forge.php | 265 +++ .../database/drivers/sqlite/sqlite_result.php | 179 ++ .../drivers/sqlite/sqlite_utility.php | 96 + system/database/drivers/sqlsrv/index.html | 10 + .../database/drivers/sqlsrv/sqlsrv_driver.php | 599 +++++ .../database/drivers/sqlsrv/sqlsrv_forge.php | 248 ++ .../database/drivers/sqlsrv/sqlsrv_result.php | 169 ++ .../drivers/sqlsrv/sqlsrv_utility.php | 88 + system/database/index.html | 10 + system/fonts/index.html | 10 + system/fonts/texb.ttf | Bin 0 -> 143830 bytes system/helpers/array_helper.php | 119 + system/helpers/captcha_helper.php | 246 ++ system/helpers/cookie_helper.php | 103 + system/helpers/date_helper.php | 611 +++++ system/helpers/directory_helper.php | 80 + system/helpers/download_helper.php | 107 + system/helpers/email_helper.php | 62 + system/helpers/file_helper.php | 479 ++++ system/helpers/form_helper.php | 1054 +++++++++ system/helpers/html_helper.php | 436 ++++ system/helpers/index.html | 10 + system/helpers/inflector_helper.php | 203 ++ system/helpers/language_helper.php | 58 + system/helpers/number_helper.php | 76 + system/helpers/path_helper.php | 72 + system/helpers/security_helper.php | 128 + system/helpers/smiley_helper.php | 281 +++ system/helpers/string_helper.php | 307 +++ system/helpers/text_helper.php | 535 +++++ system/helpers/typography_helper.php | 93 + system/helpers/url_helper.php | 598 +++++ system/helpers/xml_helper.php | 71 + system/index.html | 10 + system/language/english/calendar_lang.php | 51 + system/language/english/date_lang.php | 61 + system/language/english/db_lang.php | 29 + system/language/english/email_lang.php | 24 + .../language/english/form_validation_lang.php | 29 + system/language/english/ftp_lang.php | 18 + system/language/english/imglib_lang.php | 24 + system/language/english/index.html | 10 + system/language/english/migration_lang.php | 13 + system/language/english/number_lang.php | 10 + system/language/english/profiler_lang.php | 25 + system/language/english/unit_test_lang.php | 25 + system/language/english/upload_lang.php | 22 + system/language/index.html | 10 + system/libraries/Cache/Cache.php | 216 ++ system/libraries/Cache/drivers/Cache_apc.php | 151 ++ .../libraries/Cache/drivers/Cache_dummy.php | 129 + system/libraries/Cache/drivers/Cache_file.php | 196 ++ .../Cache/drivers/Cache_memcached.php | 218 ++ system/libraries/Calendar.php | 475 ++++ system/libraries/Cart.php | 552 +++++ system/libraries/Driver.php | 229 ++ system/libraries/Email.php | 2092 +++++++++++++++++ system/libraries/Encrypt.php | 547 +++++ system/libraries/Form_validation.php | 1381 +++++++++++ system/libraries/Ftp.php | 660 ++++++ system/libraries/Image_lib.php | 1537 ++++++++++++ system/libraries/Javascript.php | 871 +++++++ system/libraries/Log.php | 114 + system/libraries/Migration.php | 338 +++ system/libraries/Pagination.php | 340 +++ system/libraries/Parser.php | 212 ++ system/libraries/Profiler.php | 558 +++++ system/libraries/Session.php | 777 ++++++ system/libraries/Sha1.php | 251 ++ system/libraries/Table.php | 531 +++++ system/libraries/Trackback.php | 548 +++++ system/libraries/Typography.php | 410 ++++ system/libraries/Unit_test.php | 383 +++ system/libraries/Upload.php | 1075 +++++++++ system/libraries/User_agent.php | 549 +++++ system/libraries/Xmlrpc.php | 1423 +++++++++++ system/libraries/Xmlrpcs.php | 612 +++++ system/libraries/Zip.php | 423 ++++ system/libraries/index.html | 10 + system/libraries/javascript/Jquery.php | 1071 +++++++++ 475 files changed, 77998 insertions(+) create mode 100644 README.txt create mode 100644 UPGRADE.txt create mode 100644 WHATS_NEW.txt create mode 100644 application/.htaccess create mode 100644 application/cache/.htaccess create mode 100644 application/cache/index.html create mode 100644 application/config/autoload.php create mode 100644 application/config/config.php create mode 100644 application/config/constants.php create mode 100644 application/config/database.php.tmpl create mode 100644 application/config/doctypes.php create mode 100644 application/config/foreign_chars.php create mode 100644 application/config/hooks.php create mode 100644 application/config/index.html create mode 100644 application/config/migration.php create mode 100644 application/config/mimes.php create mode 100644 application/config/profiler.php create mode 100644 application/config/routes.php create mode 100644 application/config/smileys.php create mode 100644 application/config/user_agents.php create mode 100644 application/controllers/barcode.php create mode 100644 application/controllers/config.php create mode 100644 application/controllers/customers.php create mode 100644 application/controllers/employees.php create mode 100644 application/controllers/giftcards.php create mode 100644 application/controllers/home.php create mode 100644 application/controllers/index.html create mode 100644 application/controllers/interfaces/idata_controller.php create mode 100644 application/controllers/interfaces/iperson_controller.php create mode 100644 application/controllers/item_kits.php create mode 100644 application/controllers/items.php create mode 100644 application/controllers/languagecheck.php create mode 100644 application/controllers/login.php create mode 100644 application/controllers/no_access.php create mode 100644 application/controllers/person_controller.php create mode 100644 application/controllers/receivings.php create mode 100644 application/controllers/reports.php create mode 100644 application/controllers/sales.php create mode 100644 application/controllers/secure_area.php create mode 100644 application/controllers/suppliers.php create mode 100644 application/core/index.html create mode 100644 application/errors/error_404.php create mode 100644 application/errors/error_db.php create mode 100644 application/errors/error_general.php create mode 100644 application/errors/error_php.php create mode 100644 application/errors/index.html create mode 100644 application/helpers/currency_helper.php create mode 100644 application/helpers/index.html create mode 100644 application/helpers/report_helper.php create mode 100644 application/helpers/sale_helper.php create mode 100644 application/helpers/table_helper.php create mode 100644 application/hooks/index.html create mode 100644 application/hooks/load_config.php create mode 100644 application/index.html create mode 100644 application/language/Azerbaijan/common_lang.php create mode 100644 application/language/Azerbaijan/config_lang.php create mode 100644 application/language/Azerbaijan/customers_lang.php create mode 100644 application/language/Azerbaijan/employees_lang.php create mode 100644 application/language/Azerbaijan/error_lang.php create mode 100644 application/language/Azerbaijan/giftcards_lang.php create mode 100644 application/language/Azerbaijan/index.html create mode 100644 application/language/Azerbaijan/item_kits_lang.php create mode 100644 application/language/Azerbaijan/items_lang.php create mode 100644 application/language/Azerbaijan/login_lang.php create mode 100644 application/language/Azerbaijan/module_lang.php create mode 100644 application/language/Azerbaijan/receivings_lang.php create mode 100644 application/language/Azerbaijan/reports_lang.php create mode 100644 application/language/Azerbaijan/sales_lang.php create mode 100644 application/language/Azerbaijan/suppliers_lang.php create mode 100644 application/language/BahasaIndonesia/common_lang.php create mode 100644 application/language/BahasaIndonesia/config_lang.php create mode 100644 application/language/BahasaIndonesia/customers_lang.php create mode 100644 application/language/BahasaIndonesia/employees_lang.php create mode 100644 application/language/BahasaIndonesia/error_lang.php create mode 100644 application/language/BahasaIndonesia/giftcards_lang.php create mode 100644 application/language/BahasaIndonesia/index.html create mode 100644 application/language/BahasaIndonesia/item_kits_lang.php create mode 100644 application/language/BahasaIndonesia/items_lang.php create mode 100644 application/language/BahasaIndonesia/login_lang.php create mode 100644 application/language/BahasaIndonesia/module_lang.php create mode 100644 application/language/BahasaIndonesia/receivings_lang.php create mode 100644 application/language/BahasaIndonesia/reports_lang.php create mode 100644 application/language/BahasaIndonesia/sales_lang.php create mode 100644 application/language/BahasaIndonesia/suppliers_lang.php create mode 100644 application/language/Russian/common_lang.php create mode 100644 application/language/Russian/config_lang.php create mode 100644 application/language/Russian/customers_lang.php create mode 100644 application/language/Russian/employees_lang.php create mode 100644 application/language/Russian/error_lang.php create mode 100644 application/language/Russian/giftcards_lang.php create mode 100644 application/language/Russian/index.html create mode 100644 application/language/Russian/item_kits_lang.php create mode 100644 application/language/Russian/items_lang.php create mode 100644 application/language/Russian/login_lang.php create mode 100644 application/language/Russian/module_lang.php create mode 100644 application/language/Russian/receivings_lang.php create mode 100644 application/language/Russian/reports_lang.php create mode 100644 application/language/Russian/sales_lang.php create mode 100644 application/language/Russian/suppliers_lang.php create mode 100644 application/language/Spanish/common_lang.php create mode 100644 application/language/Spanish/config_lang.php create mode 100644 application/language/Spanish/customers_lang.php create mode 100644 application/language/Spanish/employees_lang.php create mode 100644 application/language/Spanish/error_lang.php create mode 100644 application/language/Spanish/giftcards_lang.php create mode 100644 application/language/Spanish/index.html create mode 100644 application/language/Spanish/item_kits_lang.php create mode 100644 application/language/Spanish/items_lang.php create mode 100644 application/language/Spanish/login_lang.php create mode 100644 application/language/Spanish/module_lang.php create mode 100644 application/language/Spanish/receivings_lang.php create mode 100644 application/language/Spanish/reports_lang.php create mode 100644 application/language/Spanish/sales_lang.php create mode 100644 application/language/Spanish/suppliers_lang.php create mode 100644 application/language/english/common_lang.php create mode 100644 application/language/english/config_lang.php create mode 100644 application/language/english/customers_lang.php create mode 100644 application/language/english/employees_lang.php create mode 100644 application/language/english/error_lang.php create mode 100644 application/language/english/giftcards_lang.php create mode 100644 application/language/english/index.html create mode 100644 application/language/english/item_kits_lang.php create mode 100644 application/language/english/items_lang.php create mode 100644 application/language/english/login_lang.php create mode 100644 application/language/english/module_lang.php create mode 100644 application/language/english/receivings_lang.php create mode 100644 application/language/english/reports_lang.php create mode 100644 application/language/english/sales_lang.php create mode 100644 application/language/english/suppliers_lang.php create mode 100644 application/libraries/MY_Language.php create mode 100644 application/libraries/Receiving_lib.php create mode 100644 application/libraries/Sale_lib.php create mode 100644 application/libraries/index.html create mode 100644 application/libraries/ofc-library/JSON.php create mode 100644 application/libraries/ofc-library/README.txt create mode 100644 application/libraries/ofc-library/dot_base.php create mode 100644 application/libraries/ofc-library/json_format.php create mode 100644 application/libraries/ofc-library/ofc_area_base.php create mode 100644 application/libraries/ofc-library/ofc_area_hollow.php create mode 100644 application/libraries/ofc-library/ofc_area_line.php create mode 100644 application/libraries/ofc-library/ofc_arrow.php create mode 100644 application/libraries/ofc-library/ofc_bar.php create mode 100644 application/libraries/ofc-library/ofc_bar_3d.php create mode 100644 application/libraries/ofc-library/ofc_bar_base.php create mode 100644 application/libraries/ofc-library/ofc_bar_filled.php create mode 100644 application/libraries/ofc-library/ofc_bar_glass.php create mode 100644 application/libraries/ofc-library/ofc_bar_sketch.php create mode 100644 application/libraries/ofc-library/ofc_bar_stack.php create mode 100644 application/libraries/ofc-library/ofc_candle.php create mode 100644 application/libraries/ofc-library/ofc_hbar.php create mode 100644 application/libraries/ofc-library/ofc_line.php create mode 100644 application/libraries/ofc-library/ofc_line_base.php create mode 100644 application/libraries/ofc-library/ofc_line_dot.php create mode 100644 application/libraries/ofc-library/ofc_line_hollow.php create mode 100644 application/libraries/ofc-library/ofc_line_style.php create mode 100644 application/libraries/ofc-library/ofc_menu.php create mode 100644 application/libraries/ofc-library/ofc_pie.php create mode 100644 application/libraries/ofc-library/ofc_radar_axis.php create mode 100644 application/libraries/ofc-library/ofc_radar_axis_labels.php create mode 100644 application/libraries/ofc-library/ofc_radar_spoke_labels.php create mode 100644 application/libraries/ofc-library/ofc_scatter.php create mode 100644 application/libraries/ofc-library/ofc_scatter_line.php create mode 100644 application/libraries/ofc-library/ofc_shape.php create mode 100644 application/libraries/ofc-library/ofc_sugar.php create mode 100644 application/libraries/ofc-library/ofc_tags.php create mode 100644 application/libraries/ofc-library/ofc_title.php create mode 100644 application/libraries/ofc-library/ofc_tooltip.php create mode 100644 application/libraries/ofc-library/ofc_x_axis.php create mode 100644 application/libraries/ofc-library/ofc_x_axis_label.php create mode 100644 application/libraries/ofc-library/ofc_x_axis_labels.php create mode 100644 application/libraries/ofc-library/ofc_x_legend.php create mode 100644 application/libraries/ofc-library/ofc_y_axis.php create mode 100644 application/libraries/ofc-library/ofc_y_axis_base.php create mode 100644 application/libraries/ofc-library/ofc_y_axis_label.php create mode 100644 application/libraries/ofc-library/ofc_y_axis_labels.php create mode 100644 application/libraries/ofc-library/ofc_y_axis_right.php create mode 100644 application/libraries/ofc-library/ofc_y_legend.php create mode 100644 application/libraries/ofc-library/open-flash-chart-object.php create mode 100644 application/libraries/ofc-library/open-flash-chart.php create mode 100644 application/logs/index.html create mode 100644 application/models/appconfig.php create mode 100644 application/models/customer.php create mode 100644 application/models/employee.php create mode 100644 application/models/giftcard.php create mode 100644 application/models/index.html create mode 100644 application/models/inventory.php create mode 100644 application/models/item.php create mode 100644 application/models/item_kit.php create mode 100644 application/models/item_kit_items.php create mode 100644 application/models/item_taxes.php create mode 100644 application/models/module.php create mode 100644 application/models/person.php create mode 100644 application/models/receiving.php create mode 100644 application/models/reports/detailed_receivings.php create mode 100644 application/models/reports/detailed_sales.php create mode 100644 application/models/reports/inventory_low.php create mode 100644 application/models/reports/inventory_summary.php create mode 100644 application/models/reports/report.php create mode 100644 application/models/reports/specific_customer.php create mode 100644 application/models/reports/specific_employee.php create mode 100644 application/models/reports/summary_categories.php create mode 100644 application/models/reports/summary_customers.php create mode 100644 application/models/reports/summary_discounts.php create mode 100644 application/models/reports/summary_employees.php create mode 100644 application/models/reports/summary_items.php create mode 100644 application/models/reports/summary_payments.php create mode 100644 application/models/reports/summary_sales.php create mode 100644 application/models/reports/summary_suppliers.php create mode 100644 application/models/reports/summary_taxes.php create mode 100644 application/models/sale.php create mode 100644 application/models/sale_suspended.php create mode 100644 application/models/supplier.php create mode 100644 application/third_party/index.html create mode 100644 application/views/barcode.php create mode 100644 application/views/barcode_sheet.php create mode 100644 application/views/config.php create mode 100644 application/views/customers/excel_import.php create mode 100644 application/views/customers/form.php create mode 100644 application/views/employees/form.php create mode 100644 application/views/giftcards/form.php create mode 100644 application/views/giftcards/manage.php create mode 100644 application/views/home.php create mode 100644 application/views/index.html create mode 100644 application/views/item_kits/form.php create mode 100644 application/views/item_kits/manage.php create mode 100644 application/views/items/count_details.php create mode 100644 application/views/items/excel_import.php create mode 100644 application/views/items/form.php create mode 100644 application/views/items/form_bulk.php create mode 100644 application/views/items/inventory.php create mode 100644 application/views/items/manage.php create mode 100644 application/views/login.php create mode 100644 application/views/no_access.php create mode 100644 application/views/partial/footer.php create mode 100644 application/views/partial/footer_excel.php create mode 100644 application/views/partial/header.php create mode 100644 application/views/partial/header_excel.php create mode 100644 application/views/people/form_basic_info.php create mode 100644 application/views/people/manage.php create mode 100644 application/views/receivings/receipt.php create mode 100644 application/views/receivings/receiving.php create mode 100644 application/views/reports/date_input.php create mode 100644 application/views/reports/date_input_excel_export.php create mode 100644 application/views/reports/excel_export.php create mode 100644 application/views/reports/graphical.php create mode 100644 application/views/reports/graphs/bar.php create mode 100644 application/views/reports/graphs/hbar.php create mode 100644 application/views/reports/graphs/line.php create mode 100644 application/views/reports/graphs/pie.php create mode 100644 application/views/reports/listing.php create mode 100644 application/views/reports/specific_input.php create mode 100644 application/views/reports/tabular.php create mode 100644 application/views/reports/tabular_details.php create mode 100644 application/views/sales/delete.php create mode 100644 application/views/sales/edit.php create mode 100644 application/views/sales/receipt.php create mode 100644 application/views/sales/receipt_email.php create mode 100644 application/views/sales/register.php create mode 100644 application/views/sales/suspended.php create mode 100644 application/views/suppliers/form.php create mode 100644 application/views/suppliers/manage.php create mode 100644 css/autocomplete.css create mode 100644 css/datepicker.css create mode 100644 css/editsale.css create mode 100644 css/general.css create mode 100644 css/login.css create mode 100644 css/menubar.css create mode 100644 css/ospos.css create mode 100644 css/ospos_print.css create mode 100644 css/popupbox.css create mode 100644 css/receipt.css create mode 100644 css/register.css create mode 100644 css/reports.css create mode 100644 css/tables.css create mode 100644 css/thickbox.css create mode 100644 database/database.sql create mode 100644 images/Thumbs.db create mode 100644 images/big_action_button.jpg create mode 100644 images/calendar.png create mode 100644 images/checkbox_arrow.gif create mode 100644 images/loading_animation.gif create mode 100644 images/menubar/config.png create mode 100644 images/menubar/customers.png create mode 100644 images/menubar/employees.png create mode 100644 images/menubar/giftcards.png create mode 100644 images/menubar/home.png create mode 100644 images/menubar/item_kits.png create mode 100644 images/menubar/items.png create mode 100644 images/menubar/menubar_bg.gif create mode 100644 images/menubar/receivings.png create mode 100644 images/menubar/reports.png create mode 100644 images/menubar/sales.png create mode 100644 images/menubar/suppliers.png create mode 100644 images/menubar/thumb_clock.png create mode 100644 images/menubar/thumb_colorscheme.png create mode 100644 images/minus.png create mode 100644 images/plus.png create mode 100644 images/psds/big_action_button.psd create mode 100644 images/psds/small_action_button.psd create mode 100644 images/small_action_button.jpg create mode 100644 images/spinner_small.gif create mode 100644 images/tables/asc.gif create mode 100644 images/tables/bg.gif create mode 100644 images/tables/desc.gif create mode 100644 import_customers.csv create mode 100644 import_items.csv create mode 100644 index.php create mode 100644 js/common.js create mode 100644 js/date.js create mode 100644 js/datepicker.js create mode 100644 js/jquery-1.2.6.min.js create mode 100644 js/jquery.ajax_queue.js create mode 100644 js/jquery.autocomplete.js create mode 100644 js/jquery.bgiframe.min.js create mode 100644 js/jquery.color.js create mode 100644 js/jquery.form.js create mode 100644 js/jquery.jkey-1.1.js create mode 100644 js/jquery.metadata.js create mode 100644 js/jquery.tablesorter.min.js create mode 100644 js/jquery.validate.min.js create mode 100644 js/manage_tables.js create mode 100644 js/swfobject.js create mode 100644 js/thickbox.js create mode 100644 license/codeigniter_license.txt create mode 100644 license/codeigniter_version.txt create mode 100644 license/license.txt create mode 100644 open-flash-chart.swf create mode 100644 system/.htaccess create mode 100644 system/core/Benchmark.php create mode 100644 system/core/CodeIgniter.php create mode 100644 system/core/Common.php create mode 100644 system/core/Config.php create mode 100644 system/core/Controller.php create mode 100644 system/core/Exceptions.php create mode 100644 system/core/Hooks.php create mode 100644 system/core/Input.php create mode 100644 system/core/Lang.php create mode 100644 system/core/Loader.php create mode 100644 system/core/Model.php create mode 100644 system/core/Output.php create mode 100644 system/core/Router.php create mode 100644 system/core/Security.php create mode 100644 system/core/URI.php create mode 100644 system/core/Utf8.php create mode 100644 system/core/index.html create mode 100644 system/database/DB.php create mode 100644 system/database/DB_active_rec.php create mode 100644 system/database/DB_cache.php create mode 100644 system/database/DB_driver.php create mode 100644 system/database/DB_forge.php create mode 100644 system/database/DB_result.php create mode 100644 system/database/DB_utility.php create mode 100644 system/database/drivers/cubrid/cubrid_driver.php create mode 100644 system/database/drivers/cubrid/cubrid_forge.php create mode 100644 system/database/drivers/cubrid/cubrid_result.php create mode 100644 system/database/drivers/cubrid/cubrid_utility.php create mode 100644 system/database/drivers/cubrid/index.html create mode 100644 system/database/drivers/index.html create mode 100644 system/database/drivers/mssql/index.html create mode 100644 system/database/drivers/mssql/mssql_driver.php create mode 100644 system/database/drivers/mssql/mssql_forge.php create mode 100644 system/database/drivers/mssql/mssql_result.php create mode 100644 system/database/drivers/mssql/mssql_utility.php create mode 100644 system/database/drivers/mysql/index.html create mode 100644 system/database/drivers/mysql/mysql_driver.php create mode 100644 system/database/drivers/mysql/mysql_forge.php create mode 100644 system/database/drivers/mysql/mysql_result.php create mode 100644 system/database/drivers/mysql/mysql_utility.php create mode 100644 system/database/drivers/mysqli/index.html create mode 100644 system/database/drivers/mysqli/mysqli_driver.php create mode 100644 system/database/drivers/mysqli/mysqli_forge.php create mode 100644 system/database/drivers/mysqli/mysqli_result.php create mode 100644 system/database/drivers/mysqli/mysqli_utility.php create mode 100644 system/database/drivers/oci8/index.html create mode 100644 system/database/drivers/oci8/oci8_driver.php create mode 100644 system/database/drivers/oci8/oci8_forge.php create mode 100644 system/database/drivers/oci8/oci8_result.php create mode 100644 system/database/drivers/oci8/oci8_utility.php create mode 100644 system/database/drivers/odbc/index.html create mode 100644 system/database/drivers/odbc/odbc_driver.php create mode 100644 system/database/drivers/odbc/odbc_forge.php create mode 100644 system/database/drivers/odbc/odbc_result.php create mode 100644 system/database/drivers/odbc/odbc_utility.php create mode 100644 system/database/drivers/pdo/index.html create mode 100644 system/database/drivers/pdo/pdo_driver.php create mode 100644 system/database/drivers/pdo/pdo_forge.php create mode 100644 system/database/drivers/pdo/pdo_result.php create mode 100644 system/database/drivers/pdo/pdo_utility.php create mode 100644 system/database/drivers/postgre/index.html create mode 100644 system/database/drivers/postgre/postgre_driver.php create mode 100644 system/database/drivers/postgre/postgre_forge.php create mode 100644 system/database/drivers/postgre/postgre_result.php create mode 100644 system/database/drivers/postgre/postgre_utility.php create mode 100644 system/database/drivers/sqlite/index.html create mode 100644 system/database/drivers/sqlite/sqlite_driver.php create mode 100644 system/database/drivers/sqlite/sqlite_forge.php create mode 100644 system/database/drivers/sqlite/sqlite_result.php create mode 100644 system/database/drivers/sqlite/sqlite_utility.php create mode 100644 system/database/drivers/sqlsrv/index.html create mode 100644 system/database/drivers/sqlsrv/sqlsrv_driver.php create mode 100644 system/database/drivers/sqlsrv/sqlsrv_forge.php create mode 100644 system/database/drivers/sqlsrv/sqlsrv_result.php create mode 100644 system/database/drivers/sqlsrv/sqlsrv_utility.php create mode 100644 system/database/index.html create mode 100644 system/fonts/index.html create mode 100644 system/fonts/texb.ttf create mode 100644 system/helpers/array_helper.php create mode 100644 system/helpers/captcha_helper.php create mode 100644 system/helpers/cookie_helper.php create mode 100644 system/helpers/date_helper.php create mode 100644 system/helpers/directory_helper.php create mode 100644 system/helpers/download_helper.php create mode 100644 system/helpers/email_helper.php create mode 100644 system/helpers/file_helper.php create mode 100644 system/helpers/form_helper.php create mode 100644 system/helpers/html_helper.php create mode 100644 system/helpers/index.html create mode 100644 system/helpers/inflector_helper.php create mode 100644 system/helpers/language_helper.php create mode 100644 system/helpers/number_helper.php create mode 100644 system/helpers/path_helper.php create mode 100644 system/helpers/security_helper.php create mode 100644 system/helpers/smiley_helper.php create mode 100644 system/helpers/string_helper.php create mode 100644 system/helpers/text_helper.php create mode 100644 system/helpers/typography_helper.php create mode 100644 system/helpers/url_helper.php create mode 100644 system/helpers/xml_helper.php create mode 100644 system/index.html create mode 100644 system/language/english/calendar_lang.php create mode 100644 system/language/english/date_lang.php create mode 100644 system/language/english/db_lang.php create mode 100644 system/language/english/email_lang.php create mode 100644 system/language/english/form_validation_lang.php create mode 100644 system/language/english/ftp_lang.php create mode 100644 system/language/english/imglib_lang.php create mode 100644 system/language/english/index.html create mode 100644 system/language/english/migration_lang.php create mode 100644 system/language/english/number_lang.php create mode 100644 system/language/english/profiler_lang.php create mode 100644 system/language/english/unit_test_lang.php create mode 100644 system/language/english/upload_lang.php create mode 100644 system/language/index.html create mode 100644 system/libraries/Cache/Cache.php create mode 100644 system/libraries/Cache/drivers/Cache_apc.php create mode 100644 system/libraries/Cache/drivers/Cache_dummy.php create mode 100644 system/libraries/Cache/drivers/Cache_file.php create mode 100644 system/libraries/Cache/drivers/Cache_memcached.php create mode 100644 system/libraries/Calendar.php create mode 100644 system/libraries/Cart.php create mode 100644 system/libraries/Driver.php create mode 100644 system/libraries/Email.php create mode 100644 system/libraries/Encrypt.php create mode 100644 system/libraries/Form_validation.php create mode 100644 system/libraries/Ftp.php create mode 100644 system/libraries/Image_lib.php create mode 100644 system/libraries/Javascript.php create mode 100644 system/libraries/Log.php create mode 100644 system/libraries/Migration.php create mode 100644 system/libraries/Pagination.php create mode 100644 system/libraries/Parser.php create mode 100644 system/libraries/Profiler.php create mode 100644 system/libraries/Session.php create mode 100644 system/libraries/Sha1.php create mode 100644 system/libraries/Table.php create mode 100644 system/libraries/Trackback.php create mode 100644 system/libraries/Typography.php create mode 100644 system/libraries/Unit_test.php create mode 100644 system/libraries/Upload.php create mode 100644 system/libraries/User_agent.php create mode 100644 system/libraries/Xmlrpc.php create mode 100644 system/libraries/Xmlrpcs.php create mode 100644 system/libraries/Zip.php create mode 100644 system/libraries/index.html create mode 100644 system/libraries/javascript/Jquery.php diff --git a/README.txt b/README.txt new file mode 100644 index 000000000..493ffb052 --- /dev/null +++ b/README.txt @@ -0,0 +1,13 @@ +How to Install +------------------------- +1. Create/locate a new mysql database to install open source point of sale into +2. Execute the file database/database.sql to create the tables needed +3. unzip and upload Open Source Point of Sale files to web server +4. Copy application/config/database.php.tmpl to application/config/database.php +5. Modify application/config/database.php to connect to your database +6. Modify application/config/config.php encryption key with your own +7. Go to your point of sale install via the browser +8. LOGIN using +username: admin +password:pointofsale +9. Enjoy \ No newline at end of file diff --git a/UPGRADE.txt b/UPGRADE.txt new file mode 100644 index 000000000..af518e482 --- /dev/null +++ b/UPGRADE.txt @@ -0,0 +1,4 @@ +How to Upgrade +------------------------- +1. Replace all code from your point of sale installation with the code downloaded +2. Run the necessary database upgrades from the database folder \ No newline at end of file diff --git a/WHATS_NEW.txt b/WHATS_NEW.txt new file mode 100644 index 000000000..f1acccdc5 --- /dev/null +++ b/WHATS_NEW.txt @@ -0,0 +1,12 @@ +* Ver. 2.1.0 ++ Various upgrades, too numerous to list here. ++ Removed dependancy on ofc upload library due to vulnerability found. +------------------------------------------------------------------------------- +* Ver. 2.0.2 ++ Fixed multiple giftcards issue per Bug #4 reported on Sourceforge where a + second giftcard added would have its balance set to $0 even if the sale did + not require the total of the second giftcard to pay the remaining amount due. ++ Small code cleanup +------------------------------------------------------------------------------- +* Upgrade to CodeIgniter 2.1.0 +* Various small improvements \ No newline at end of file diff --git a/application/.htaccess b/application/.htaccess new file mode 100644 index 000000000..14249c50b --- /dev/null +++ b/application/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/application/cache/.htaccess b/application/cache/.htaccess new file mode 100644 index 000000000..3418e55a6 --- /dev/null +++ b/application/cache/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/application/cache/index.html b/application/cache/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/cache/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/config/autoload.php b/application/config/autoload.php new file mode 100644 index 000000000..cb62d45fa --- /dev/null +++ b/application/config/autoload.php @@ -0,0 +1,116 @@ + '', + 'xhtml1-strict' => '', + 'xhtml1-trans' => '', + 'xhtml1-frame' => '', + 'html5' => '', + 'html4-strict' => '', + 'html4-trans' => '', + 'html4-frame' => '' + ); + +/* End of file doctypes.php */ +/* Location: ./application/config/doctypes.php */ \ No newline at end of file diff --git a/application/config/foreign_chars.php b/application/config/foreign_chars.php new file mode 100644 index 000000000..14b0d7373 --- /dev/null +++ b/application/config/foreign_chars.php @@ -0,0 +1,64 @@ + 'ae', + '/ö|Å“/' => 'oe', + '/ü/' => 'ue', + '/Ä/' => 'Ae', + '/Ü/' => 'Ue', + '/Ö/' => 'Oe', + '/À|Ã|Â|Ã|Ä|Ã…|Ǻ|Ä€|Ä‚|Ä„|Ç/' => 'A', + '/à|á|â|ã|Ã¥|Ç»|Ä|ă|Ä…|ÇŽ|ª/' => 'a', + '/Ç|Ć|Ĉ|ÄŠ|ÄŒ/' => 'C', + '/ç|ć|ĉ|Ä‹|Ä/' => 'c', + '/Ã|ÄŽ|Ä/' => 'D', + '/ð|Ä|Ä‘/' => 'd', + '/È|É|Ê|Ë|Ä’|Ä”|Ä–|Ę|Äš/' => 'E', + '/è|é|ê|ë|Ä“|Ä•|Ä—|Ä™|Ä›/' => 'e', + '/Äœ|Äž|Ä |Ä¢/' => 'G', + '/Ä|ÄŸ|Ä¡|Ä£/' => 'g', + '/Ĥ|Ħ/' => 'H', + '/Ä¥|ħ/' => 'h', + '/ÃŒ|Ã|ÃŽ|Ã|Ĩ|Ī|Ĭ|Ç|Ä®|İ/' => 'I', + '/ì|í|î|ï|Ä©|Ä«|Ä­|Ç|į|ı/' => 'i', + '/Ä´/' => 'J', + '/ĵ/' => 'j', + '/Ķ/' => 'K', + '/Ä·/' => 'k', + '/Ĺ|Ä»|Ľ|Ä¿|Å/' => 'L', + '/ĺ|ļ|ľ|Å€|Å‚/' => 'l', + '/Ñ|Ń|Å…|Ň/' => 'N', + '/ñ|Å„|ņ|ň|ʼn/' => 'n', + '/Ã’|Ó|Ô|Õ|ÅŒ|ÅŽ|Ç‘|Å|Æ |Ø|Ǿ/' => 'O', + '/ò|ó|ô|õ|Å|Å|Ç’|Å‘|Æ¡|ø|Ç¿|º/' => 'o', + '/Å”|Å–|Ř/' => 'R', + '/Å•|Å—|Å™/' => 'r', + '/Åš|Åœ|Åž|Å /' => 'S', + '/Å›|Å|ÅŸ|Å¡|Å¿/' => 's', + '/Å¢|Ť|Ŧ/' => 'T', + '/Å£|Å¥|ŧ/' => 't', + '/Ù|Ú|Û|Ũ|Ū|Ŭ|Å®|Ű|Ų|Ư|Ç“|Ç•|Ç—|Ç™|Ç›/' => 'U', + '/ù|ú|û|Å©|Å«|Å­|ů|ű|ų|ư|Ç”|Ç–|ǘ|Çš|Çœ/' => 'u', + '/Ã|Ÿ|Ŷ/' => 'Y', + '/ý|ÿ|Å·/' => 'y', + '/Å´/' => 'W', + '/ŵ/' => 'w', + '/Ź|Å»|Ž/' => 'Z', + '/ź|ż|ž/' => 'z', + '/Æ|Ǽ/' => 'AE', + '/ß/'=> 'ss', + '/IJ/' => 'IJ', + '/ij/' => 'ij', + '/Å’/' => 'OE', + '/Æ’/' => 'f' +); + +/* End of file foreign_chars.php */ +/* Location: ./application/config/foreign_chars.php */ \ No newline at end of file diff --git a/application/config/hooks.php b/application/config/hooks.php new file mode 100644 index 000000000..38a5e97fc --- /dev/null +++ b/application/config/hooks.php @@ -0,0 +1,21 @@ + '', + 'function' => 'load_config', + 'filename' => 'load_config.php', + 'filepath' => 'hooks' + ); + + +/* End of file hooks.php */ +/* Location: ./application/config/hooks.php */ \ No newline at end of file diff --git a/application/config/index.html b/application/config/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/config/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/config/migration.php b/application/config/migration.php new file mode 100644 index 000000000..df42a3cae --- /dev/null +++ b/application/config/migration.php @@ -0,0 +1,41 @@ +migration->latest() this is the version that schema will +| be upgraded / downgraded to. +| +*/ +$config['migration_version'] = 0; + + +/* +|-------------------------------------------------------------------------- +| Migrations Path +|-------------------------------------------------------------------------- +| +| Path to your migrations folder. +| Typically, it will be within your application path. +| Also, writing permission is required within the migrations path. +| +*/ +$config['migration_path'] = APPPATH . 'migrations/'; + + +/* End of file migration.php */ +/* Location: ./application/config/migration.php */ \ No newline at end of file diff --git a/application/config/mimes.php b/application/config/mimes.php new file mode 100644 index 000000000..f00e5b6ed --- /dev/null +++ b/application/config/mimes.php @@ -0,0 +1,106 @@ + 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/x-csv', 'text/x-csv', 'text/csv', 'application/csv', 'application/excel', 'application/vnd.msexcel'), + 'bin' => 'application/macbinary', + 'dms' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'exe' => array('application/octet-stream', 'application/x-msdownload'), + 'class' => 'application/octet-stream', + 'psd' => 'application/x-photoshop', + 'so' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => array('application/pdf', 'application/x-download'), + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'), + 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'), + 'wbxml' => 'application/wbxml', + 'wmlc' => 'application/wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'gz' => 'application/x-gzip', + 'php' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'js' => 'application/x-javascript', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => array('application/x-tar', 'application/x-gzip-compressed'), + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'), + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'), + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'rv' => 'video/vnd.rn-realvideo', + 'wav' => array('audio/x-wav', 'audio/wave', 'audio/wav'), + 'bmp' => array('image/bmp', 'image/x-windows-bmp'), + 'gif' => 'image/gif', + 'jpeg' => array('image/jpeg', 'image/pjpeg'), + 'jpg' => array('image/jpeg', 'image/pjpeg'), + 'jpe' => array('image/jpeg', 'image/pjpeg'), + 'png' => array('image/png', 'image/x-png'), + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'log' => array('text/plain', 'text/x-log'), + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'word' => array('application/msword', 'application/octet-stream'), + 'xl' => 'application/excel', + 'eml' => 'message/rfc822', + 'json' => array('application/json', 'text/json') + ); + + +/* End of file mimes.php */ +/* Location: ./application/config/mimes.php */ diff --git a/application/config/profiler.php b/application/config/profiler.php new file mode 100644 index 000000000..f8a5b1a1e --- /dev/null +++ b/application/config/profiler.php @@ -0,0 +1,17 @@ + array('grin.gif', '19', '19', 'grin'), + ':lol:' => array('lol.gif', '19', '19', 'LOL'), + ':cheese:' => array('cheese.gif', '19', '19', 'cheese'), + ':)' => array('smile.gif', '19', '19', 'smile'), + ';-)' => array('wink.gif', '19', '19', 'wink'), + ';)' => array('wink.gif', '19', '19', 'wink'), + ':smirk:' => array('smirk.gif', '19', '19', 'smirk'), + ':roll:' => array('rolleyes.gif', '19', '19', 'rolleyes'), + ':-S' => array('confused.gif', '19', '19', 'confused'), + ':wow:' => array('surprise.gif', '19', '19', 'surprised'), + ':bug:' => array('bigsurprise.gif', '19', '19', 'big surprise'), + ':-P' => array('tongue_laugh.gif', '19', '19', 'tongue laugh'), + '%-P' => array('tongue_rolleye.gif', '19', '19', 'tongue rolleye'), + ';-P' => array('tongue_wink.gif', '19', '19', 'tongue wink'), + ':P' => array('raspberry.gif', '19', '19', 'raspberry'), + ':blank:' => array('blank.gif', '19', '19', 'blank stare'), + ':long:' => array('longface.gif', '19', '19', 'long face'), + ':ohh:' => array('ohh.gif', '19', '19', 'ohh'), + ':grrr:' => array('grrr.gif', '19', '19', 'grrr'), + ':gulp:' => array('gulp.gif', '19', '19', 'gulp'), + '8-/' => array('ohoh.gif', '19', '19', 'oh oh'), + ':down:' => array('downer.gif', '19', '19', 'downer'), + ':red:' => array('embarrassed.gif', '19', '19', 'red face'), + ':sick:' => array('sick.gif', '19', '19', 'sick'), + ':shut:' => array('shuteye.gif', '19', '19', 'shut eye'), + ':-/' => array('hmm.gif', '19', '19', 'hmmm'), + '>:(' => array('mad.gif', '19', '19', 'mad'), + ':mad:' => array('mad.gif', '19', '19', 'mad'), + '>:-(' => array('angry.gif', '19', '19', 'angry'), + ':angry:' => array('angry.gif', '19', '19', 'angry'), + ':zip:' => array('zip.gif', '19', '19', 'zipper'), + ':kiss:' => array('kiss.gif', '19', '19', 'kiss'), + ':ahhh:' => array('shock.gif', '19', '19', 'shock'), + ':coolsmile:' => array('shade_smile.gif', '19', '19', 'cool smile'), + ':coolsmirk:' => array('shade_smirk.gif', '19', '19', 'cool smirk'), + ':coolgrin:' => array('shade_grin.gif', '19', '19', 'cool grin'), + ':coolhmm:' => array('shade_hmm.gif', '19', '19', 'cool hmm'), + ':coolmad:' => array('shade_mad.gif', '19', '19', 'cool mad'), + ':coolcheese:' => array('shade_cheese.gif', '19', '19', 'cool cheese'), + ':vampire:' => array('vampire.gif', '19', '19', 'vampire'), + ':snake:' => array('snake.gif', '19', '19', 'snake'), + ':exclaim:' => array('exclaim.gif', '19', '19', 'excaim'), + ':question:' => array('question.gif', '19', '19', 'question') // no comma after last item + + ); + +/* End of file smileys.php */ +/* Location: ./application/config/smileys.php */ \ No newline at end of file diff --git a/application/config/user_agents.php b/application/config/user_agents.php new file mode 100644 index 000000000..e2d3c3af0 --- /dev/null +++ b/application/config/user_agents.php @@ -0,0 +1,178 @@ + 'Windows Longhorn', + 'windows nt 5.2' => 'Windows 2003', + 'windows nt 5.0' => 'Windows 2000', + 'windows nt 5.1' => 'Windows XP', + 'windows nt 4.0' => 'Windows NT 4.0', + 'winnt4.0' => 'Windows NT 4.0', + 'winnt 4.0' => 'Windows NT', + 'winnt' => 'Windows NT', + 'windows 98' => 'Windows 98', + 'win98' => 'Windows 98', + 'windows 95' => 'Windows 95', + 'win95' => 'Windows 95', + 'windows' => 'Unknown Windows OS', + 'os x' => 'Mac OS X', + 'ppc mac' => 'Power PC Mac', + 'freebsd' => 'FreeBSD', + 'ppc' => 'Macintosh', + 'linux' => 'Linux', + 'debian' => 'Debian', + 'sunos' => 'Sun Solaris', + 'beos' => 'BeOS', + 'apachebench' => 'ApacheBench', + 'aix' => 'AIX', + 'irix' => 'Irix', + 'osf' => 'DEC OSF', + 'hp-ux' => 'HP-UX', + 'netbsd' => 'NetBSD', + 'bsdi' => 'BSDi', + 'openbsd' => 'OpenBSD', + 'gnu' => 'GNU/Linux', + 'unix' => 'Unknown Unix OS' + ); + + +// The order of this array should NOT be changed. Many browsers return +// multiple browser types so we want to identify the sub-type first. +$browsers = array( + 'Flock' => 'Flock', + 'Chrome' => 'Chrome', + 'Opera' => 'Opera', + 'MSIE' => 'Internet Explorer', + 'Internet Explorer' => 'Internet Explorer', + 'Shiira' => 'Shiira', + 'Firefox' => 'Firefox', + 'Chimera' => 'Chimera', + 'Phoenix' => 'Phoenix', + 'Firebird' => 'Firebird', + 'Camino' => 'Camino', + 'Netscape' => 'Netscape', + 'OmniWeb' => 'OmniWeb', + 'Safari' => 'Safari', + 'Mozilla' => 'Mozilla', + 'Konqueror' => 'Konqueror', + 'icab' => 'iCab', + 'Lynx' => 'Lynx', + 'Links' => 'Links', + 'hotjava' => 'HotJava', + 'amaya' => 'Amaya', + 'IBrowse' => 'IBrowse' + ); + +$mobiles = array( + // legacy array, old values commented out + 'mobileexplorer' => 'Mobile Explorer', +// 'openwave' => 'Open Wave', +// 'opera mini' => 'Opera Mini', +// 'operamini' => 'Opera Mini', +// 'elaine' => 'Palm', + 'palmsource' => 'Palm', +// 'digital paths' => 'Palm', +// 'avantgo' => 'Avantgo', +// 'xiino' => 'Xiino', + 'palmscape' => 'Palmscape', +// 'nokia' => 'Nokia', +// 'ericsson' => 'Ericsson', +// 'blackberry' => 'BlackBerry', +// 'motorola' => 'Motorola' + + // Phones and Manufacturers + 'motorola' => "Motorola", + 'nokia' => "Nokia", + 'palm' => "Palm", + 'iphone' => "Apple iPhone", + 'ipad' => "iPad", + 'ipod' => "Apple iPod Touch", + 'sony' => "Sony Ericsson", + 'ericsson' => "Sony Ericsson", + 'blackberry' => "BlackBerry", + 'cocoon' => "O2 Cocoon", + 'blazer' => "Treo", + 'lg' => "LG", + 'amoi' => "Amoi", + 'xda' => "XDA", + 'mda' => "MDA", + 'vario' => "Vario", + 'htc' => "HTC", + 'samsung' => "Samsung", + 'sharp' => "Sharp", + 'sie-' => "Siemens", + 'alcatel' => "Alcatel", + 'benq' => "BenQ", + 'ipaq' => "HP iPaq", + 'mot-' => "Motorola", + 'playstation portable' => "PlayStation Portable", + 'hiptop' => "Danger Hiptop", + 'nec-' => "NEC", + 'panasonic' => "Panasonic", + 'philips' => "Philips", + 'sagem' => "Sagem", + 'sanyo' => "Sanyo", + 'spv' => "SPV", + 'zte' => "ZTE", + 'sendo' => "Sendo", + + // Operating Systems + 'symbian' => "Symbian", + 'SymbianOS' => "SymbianOS", + 'elaine' => "Palm", + 'palm' => "Palm", + 'series60' => "Symbian S60", + 'windows ce' => "Windows CE", + + // Browsers + 'obigo' => "Obigo", + 'netfront' => "Netfront Browser", + 'openwave' => "Openwave Browser", + 'mobilexplorer' => "Mobile Explorer", + 'operamini' => "Opera Mini", + 'opera mini' => "Opera Mini", + + // Other + 'digital paths' => "Digital Paths", + 'avantgo' => "AvantGo", + 'xiino' => "Xiino", + 'novarra' => "Novarra Transcoder", + 'vodafone' => "Vodafone", + 'docomo' => "NTT DoCoMo", + 'o2' => "O2", + + // Fallback + 'mobile' => "Generic Mobile", + 'wireless' => "Generic Mobile", + 'j2me' => "Generic Mobile", + 'midp' => "Generic Mobile", + 'cldc' => "Generic Mobile", + 'up.link' => "Generic Mobile", + 'up.browser' => "Generic Mobile", + 'smartphone' => "Generic Mobile", + 'cellphone' => "Generic Mobile" + ); + +// There are hundreds of bots but these are the most common. +$robots = array( + 'googlebot' => 'Googlebot', + 'msnbot' => 'MSNBot', + 'slurp' => 'Inktomi Slurp', + 'yahoo' => 'Yahoo', + 'askjeeves' => 'AskJeeves', + 'fastcrawler' => 'FastCrawler', + 'infoseek' => 'InfoSeek Robot 1.0', + 'lycos' => 'Lycos' + ); + +/* End of file user_agents.php */ +/* Location: ./application/config/user_agents.php */ \ No newline at end of file diff --git a/application/controllers/barcode.php b/application/controllers/barcode.php new file mode 100644 index 000000000..0d3d3b7b8 --- /dev/null +++ b/application/controllers/barcode.php @@ -0,0 +1,14 @@ +load->view('barcode'); + } +} +?> \ No newline at end of file diff --git a/application/controllers/config.php b/application/controllers/config.php new file mode 100644 index 000000000..028c4bff5 --- /dev/null +++ b/application/controllers/config.php @@ -0,0 +1,52 @@ +load->view("config"); + } + + function save() + { + $batch_save_data=array( + 'company'=>$this->input->post('company'), + 'address'=>$this->input->post('address'), + 'phone'=>$this->input->post('phone'), + 'email'=>$this->input->post('email'), + 'fax'=>$this->input->post('fax'), + 'website'=>$this->input->post('website'), + 'default_tax_1_rate'=>$this->input->post('default_tax_1_rate'), + 'default_tax_1_name'=>$this->input->post('default_tax_1_name'), + 'default_tax_2_rate'=>$this->input->post('default_tax_2_rate'), + 'default_tax_2_name'=>$this->input->post('default_tax_2_name'), + 'currency_symbol'=>$this->input->post('currency_symbol'), + 'currency_side'=>$this->input->post('currency_side'),/**GARRISON ADDED 4/20/2013**/ + 'return_policy'=>$this->input->post('return_policy'), + 'language'=>$this->input->post('language'), + 'timezone'=>$this->input->post('timezone'), + 'print_after_sale'=>$this->input->post('print_after_sale'), + 'custom1_name'=>$this->input->post('custom1_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom2_name'=>$this->input->post('custom2_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom3_name'=>$this->input->post('custom3_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom4_name'=>$this->input->post('custom4_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom5_name'=>$this->input->post('custom5_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom6_name'=>$this->input->post('custom6_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom7_name'=>$this->input->post('custom7_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom8_name'=>$this->input->post('custom8_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom9_name'=>$this->input->post('custom9_name'),/**GARRISON ADDED 4/20/2013**/ + 'custom10_name'=>$this->input->post('custom10_name')/**GARRISON ADDED 4/20/2013**/ + ); + + if( $this->Appconfig->batch_save( $batch_save_data ) ) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('config_saved_successfully'))); + } + } +} +?> \ No newline at end of file diff --git a/application/controllers/customers.php b/application/controllers/customers.php new file mode 100644 index 000000000..9d5de6687 --- /dev/null +++ b/application/controllers/customers.php @@ -0,0 +1,201 @@ +Customer->count_all(); + $config['per_page'] = '20'; + $config['uri_segment'] = 3; + $this->pagination->initialize($config); + + $data['controller_name']=strtolower(get_class()); + $data['form_width']=$this->get_form_width(); + $data['manage_table']=get_people_manage_table( $this->Customer->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this ); + $this->load->view('people/manage',$data); + } + + /* + Returns customer table data rows. This will be called with AJAX. + */ + function search() + { + $search=$this->input->post('search'); + $data_rows=get_people_manage_table_data_rows($this->Customer->search($search),$this); + echo $data_rows; + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest() + { + $suggestions = $this->Customer->get_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + /* + Loads the customer edit form + */ + function view($customer_id=-1) + { + $data['person_info']=$this->Customer->get_info($customer_id); + $this->load->view("customers/form",$data); + } + + /* + Inserts/updates a customer + */ + function save($customer_id=-1) + { + $person_data = array( + 'first_name'=>$this->input->post('first_name'), + 'last_name'=>$this->input->post('last_name'), + 'email'=>$this->input->post('email'), + 'phone_number'=>$this->input->post('phone_number'), + 'address_1'=>$this->input->post('address_1'), + 'address_2'=>$this->input->post('address_2'), + 'city'=>$this->input->post('city'), + 'state'=>$this->input->post('state'), + 'zip'=>$this->input->post('zip'), + 'country'=>$this->input->post('country'), + 'comments'=>$this->input->post('comments') + ); + $customer_data=array( + 'account_number'=>$this->input->post('account_number')=='' ? null:$this->input->post('account_number'), + 'taxable'=>$this->input->post('taxable')=='' ? 0:1, + ); + if($this->Customer->save($person_data,$customer_data,$customer_id)) + { + //New customer + if($customer_id==-1) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('customers_successful_adding').' '. + $person_data['first_name'].' '.$person_data['last_name'],'person_id'=>$customer_data['person_id'])); + } + else //previous customer + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('customers_successful_updating').' '. + $person_data['first_name'].' '.$person_data['last_name'],'person_id'=>$customer_id)); + } + } + else//failure + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('customers_error_adding_updating').' '. + $person_data['first_name'].' '.$person_data['last_name'],'person_id'=>-1)); + } + } + + /* + This deletes customers from the customers table + */ + function delete() + { + $customers_to_delete=$this->input->post('ids'); + + if($this->Customer->delete_list($customers_to_delete)) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('customers_successful_deleted').' '. + count($customers_to_delete).' '.$this->lang->line('customers_one_or_multiple'))); + } + else + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('customers_cannot_be_deleted'))); + } + } + + function excel() + { + $data = file_get_contents("import_customers.csv"); + $name = 'import_customers.csv'; + force_download($name, $data); + } + + function excel_import() + { + $this->load->view("customers/excel_import", null); + } + + function do_excel_import() + { + $msg = 'do_excel_import'; + $failCodes = array(); + if ($_FILES['file_path']['error']!=UPLOAD_ERR_OK) + { + $msg = $this->lang->line('items_excel_import_failed'); + echo json_encode( array('success'=>false,'message'=>$msg) ); + return; + } + else + { + if (($handle = fopen($_FILES['file_path']['tmp_name'], "r")) !== FALSE) + { + //Skip first row + fgetcsv($handle); + + $i=1; + while (($data = fgetcsv($handle)) !== FALSE) + { + $person_data = array( + 'first_name'=>$data[0], + 'last_name'=>$data[1], + 'email'=>$data[2], + 'phone_number'=>$data[3], + 'address_1'=>$data[4], + 'address_2'=>$data[5], + 'city'=>$data[6], + 'state'=>$data[7], + 'zip'=>$data[8], + 'country'=>$data[9], + 'comments'=>$data[10] + ); + + $customer_data=array( + 'account_number'=>$data[11]=='' ? null:$data[11], + 'taxable'=>$data[12]=='' ? 0:1, + ); + + if(!$this->Customer->save($person_data,$customer_data)) + { + $failCodes[] = $i; + } + + $i++; + } + } + else + { + echo json_encode( array('success'=>false,'message'=>'Your upload file has no data or not in supported format.') ); + return; + } + } + + $success = true; + if(count($failCodes) > 1) + { + $msg = "Most customers imported. But some were not, here is list of their CODE (" .count($failCodes) ."): ".implode(", ", $failCodes); + $success = false; + } + else + { + $msg = "Import Customers successful"; + } + + echo json_encode( array('success'=>$success,'message'=>$msg) ); + } + + /* + get the width for the add/edit form + */ + function get_form_width() + { + return 350; + } +} +?> \ No newline at end of file diff --git a/application/controllers/employees.php b/application/controllers/employees.php new file mode 100644 index 000000000..e719cb0cd --- /dev/null +++ b/application/controllers/employees.php @@ -0,0 +1,132 @@ +Employee->count_all(); + $config['per_page'] = '20'; + $config['uri_segment'] = 3; + $this->pagination->initialize($config); + + $data['controller_name']=strtolower(get_class()); + $data['form_width']=$this->get_form_width(); + $data['manage_table']=get_people_manage_table( $this->Employee->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this ); + $this->load->view('people/manage',$data); + } + + /* + Returns employee table data rows. This will be called with AJAX. + */ + function search() + { + $search=$this->input->post('search'); + $data_rows=get_people_manage_table_data_rows($this->Employee->search($search),$this); + echo $data_rows; + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest() + { + $suggestions = $this->Employee->get_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + /* + Loads the employee edit form + */ + function view($employee_id=-1) + { + $data['person_info']=$this->Employee->get_info($employee_id); + $data['all_modules']=$this->Module->get_all_modules(); + $this->load->view("employees/form",$data); + } + + /* + Inserts/updates an employee + */ + function save($employee_id=-1) + { + $person_data = array( + 'first_name'=>$this->input->post('first_name'), + 'last_name'=>$this->input->post('last_name'), + 'email'=>$this->input->post('email'), + 'phone_number'=>$this->input->post('phone_number'), + 'address_1'=>$this->input->post('address_1'), + 'address_2'=>$this->input->post('address_2'), + 'city'=>$this->input->post('city'), + 'state'=>$this->input->post('state'), + 'zip'=>$this->input->post('zip'), + 'country'=>$this->input->post('country'), + 'comments'=>$this->input->post('comments') + ); + $permission_data = $this->input->post("permissions")!=false ? $this->input->post("permissions"):array(); + + //Password has been changed OR first time password set + if($this->input->post('password')!='') + { + $employee_data=array( + 'username'=>$this->input->post('username'), + 'password'=>md5($this->input->post('password')) + ); + } + else //Password not changed + { + $employee_data=array('username'=>$this->input->post('username')); + } + + if($this->Employee->save($person_data,$employee_data,$permission_data,$employee_id)) + { + //New employee + if($employee_id==-1) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('employees_successful_adding').' '. + $person_data['first_name'].' '.$person_data['last_name'],'person_id'=>$employee_data['person_id'])); + } + else //previous employee + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('employees_successful_updating').' '. + $person_data['first_name'].' '.$person_data['last_name'],'person_id'=>$employee_id)); + } + } + else//failure + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('employees_error_adding_updating').' '. + $person_data['first_name'].' '.$person_data['last_name'],'person_id'=>-1)); + } + } + + /* + This deletes employees from the employees table + */ + function delete() + { + $employees_to_delete=$this->input->post('ids'); + + if($this->Employee->delete_list($employees_to_delete)) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('employees_successful_deleted').' '. + count($employees_to_delete).' '.$this->lang->line('employees_one_or_multiple'))); + } + else + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('employees_cannot_be_deleted'))); + } + } + /* + get the width for the add/edit form + */ + function get_form_width() + { + return 650; + } +} +?> \ No newline at end of file diff --git a/application/controllers/giftcards.php b/application/controllers/giftcards.php new file mode 100644 index 000000000..a5989cf02 --- /dev/null +++ b/application/controllers/giftcards.php @@ -0,0 +1,117 @@ +Giftcard->count_all(); + $config['per_page'] = '20'; + $config['uri_segment'] = 3; + $this->pagination->initialize($config); + + $data['controller_name']=strtolower(get_class()); + $data['form_width']=$this->get_form_width(); + $data['manage_table']=get_giftcards_manage_table( $this->Giftcard->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this ); + $this->load->view('giftcards/manage',$data); + } + + function search() + { + $search=$this->input->post('search'); + $data_rows=get_giftcards_manage_table_data_rows($this->Giftcard->search($search),$this); + echo $data_rows; + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest() + { + $suggestions = $this->Giftcard->get_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } +/** GARRISON ADDED 5/3/2013 **/ + /* + Gives search suggestions for person_id based on what is being searched for + */ + function suggest_person() + { + $suggestions = $this->Giftcard->get_person_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } +/** END GARRISON ADDED **/ + function get_row() + { + $giftcard_id = $this->input->post('row_id'); + $data_row=get_giftcard_data_row($this->Giftcard->get_info($giftcard_id),$this); + echo $data_row; + } + + function view($giftcard_id=-1) + { + $data['giftcard_info']=$this->Giftcard->get_info($giftcard_id); + + $this->load->view("giftcards/form",$data); + } + + function save($giftcard_id=-1) + { + $giftcard_data = array( + 'giftcard_number'=>$this->input->post('giftcard_number'), + 'value'=>$this->input->post('value'), + 'person_id'=>$this->input->post('person_id')/**GARRISON ADDED 4/22/2013**/ + ); + + if( $this->Giftcard->save( $giftcard_data, $giftcard_id ) ) + { + //New giftcard + if($giftcard_id==-1) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('giftcards_successful_adding').' '. + $giftcard_data['giftcard_number'],'giftcard_id'=>$giftcard_data['giftcard_id'])); + $giftcard_id = $giftcard_data['giftcard_id']; + } + else //previous giftcard + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('giftcards_successful_updating').' '. + $giftcard_data['giftcard_number'],'giftcard_id'=>$giftcard_id)); + } + } + else//failure + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('giftcards_error_adding_updating').' '. + $giftcard_data['giftcard_number'],'giftcard_id'=>-1)); + } + } + + function delete() + { + $giftcards_to_delete=$this->input->post('ids'); + + if($this->Giftcard->delete_list($giftcards_to_delete)) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('giftcards_successful_deleted').' '. + count($giftcards_to_delete).' '.$this->lang->line('giftcards_one_or_multiple'))); + } + else + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('giftcards_cannot_be_deleted'))); + } + } + + /* + get the width for the add/edit form + */ + function get_form_width() + { + return 360; + } +} +?> \ No newline at end of file diff --git a/application/controllers/home.php b/application/controllers/home.php new file mode 100644 index 000000000..8e5d307fe --- /dev/null +++ b/application/controllers/home.php @@ -0,0 +1,21 @@ +load->view("home"); + } + + function logout() + { + $this->Employee->logout(); + } +} +?> \ No newline at end of file diff --git a/application/controllers/index.html b/application/controllers/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/controllers/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/controllers/interfaces/idata_controller.php b/application/controllers/interfaces/idata_controller.php new file mode 100644 index 000000000..e05d493d0 --- /dev/null +++ b/application/controllers/interfaces/idata_controller.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/application/controllers/interfaces/iperson_controller.php b/application/controllers/interfaces/iperson_controller.php new file mode 100644 index 000000000..92cdb1810 --- /dev/null +++ b/application/controllers/interfaces/iperson_controller.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/application/controllers/item_kits.php b/application/controllers/item_kits.php new file mode 100644 index 000000000..5d4986e99 --- /dev/null +++ b/application/controllers/item_kits.php @@ -0,0 +1,138 @@ +Item_kit->count_all(); + $config['per_page'] = '20'; + $config['uri_segment'] = 3; + $this->pagination->initialize($config); + + $data['controller_name']=strtolower(get_class()); + $data['form_width']=$this->get_form_width(); + $data['manage_table']=get_item_kits_manage_table( $this->Item_kit->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this ); + $this->load->view('item_kits/manage',$data); + } + + function search() + { + $search=$this->input->post('search'); + $data_rows=get_item_kits_manage_table_data_rows($this->Item_kit->search($search),$this); + echo $data_rows; + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest() + { + $suggestions = $this->Item_kit->get_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + function get_row() + { + $item_kit_id = $this->input->post('row_id'); + $data_row=get_item_kit_data_row($this->Item_kit->get_info($item_kit_id),$this); + echo $data_row; + } + + function view($item_kit_id=-1) + { + $data['item_kit_info']=$this->Item_kit->get_info($item_kit_id); + $this->load->view("item_kits/form",$data); + } + + function save($item_kit_id=-1) + { + $item_kit_data = array( + 'name'=>$this->input->post('name'), + 'description'=>$this->input->post('description') + ); + + if($this->Item_kit->save($item_kit_data,$item_kit_id)) + { + //New item kit + if($item_kit_id==-1) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('item_kits_successful_adding').' '. + $item_kit_data['name'],'item_kit_id'=>$item_kit_data['item_kit_id'])); + $item_kit_id = $item_kit_data['item_kit_id']; + } + else //previous item + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('item_kits_successful_updating').' '. + $item_kit_data['name'],'item_kit_id'=>$item_kit_id)); + } + + if ($this->input->post('item_kit_item')) + { + $item_kit_items = array(); + foreach($this->input->post('item_kit_item') as $item_id => $quantity) + { + $item_kit_items[] = array( + 'item_id' => $item_id, + 'quantity' => $quantity + ); + } + + $this->Item_kit_items->save($item_kit_items, $item_kit_id); + } + } + else//failure + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('item_kits_error_adding_updating').' '. + $item_kit_data['name'],'item_kit_id'=>-1)); + } + + } + + function delete() + { + $item_kits_to_delete=$this->input->post('ids'); + + if($this->Item_kit->delete_list($item_kits_to_delete)) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('item_kits_successful_deleted').' '. + count($item_kits_to_delete).' '.$this->lang->line('item_kits_one_or_multiple'))); + } + else + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('item_kits_cannot_be_deleted'))); + } + } + + function generate_barcodes($item_kit_ids) + { + $result = array(); + + $item_kit_ids = explode(':', $item_kit_ids); + foreach ($item_kit_ids as $item_kid_id) + { + $item_kit_info = $this->Item_kit->get_info($item_kid_id); + + $result[] = array('name' =>$item_kit_info->name, 'id'=> 'KIT '.$item_kid_id); + } + + $data['items'] = $result; + $this->load->view("barcode_sheet", $data); + } + + + /* + get the width for the add/edit form + */ + function get_form_width() + { + return 360; + } +} +?> \ No newline at end of file diff --git a/application/controllers/items.php b/application/controllers/items.php new file mode 100644 index 000000000..281c25a11 --- /dev/null +++ b/application/controllers/items.php @@ -0,0 +1,551 @@ +Item->count_all(); + $config['per_page'] = '20'; + $config['uri_segment'] = 3; + $this->pagination->initialize($config); + + $data['controller_name']=strtolower(get_class()); + $data['form_width']=$this->get_form_width(); + $data['manage_table']=get_items_manage_table( $this->Item->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this ); + $this->load->view('items/manage',$data); + } + + function refresh() + { + $low_inventory=$this->input->post('low_inventory'); + $is_serialized=$this->input->post('is_serialized'); + $no_description=$this->input->post('no_description'); + $search_custom=$this->input->post('search_custom');//GARRISON ADDED 4/13/2013 + + $data['search_section_state']=$this->input->post('search_section_state'); + $data['low_inventory']=$this->input->post('low_inventory'); + $data['is_serialized']=$this->input->post('is_serialized'); + $data['no_description']=$this->input->post('no_description'); + $data['search_custom']=$this->input->post('search_custom');//GARRISON ADDED 4/13/2013 + $data['controller_name']=strtolower(get_class()); + $data['form_width']=$this->get_form_width(); + $data['manage_table']=get_items_manage_table($this->Item->get_all_filtered($low_inventory,$is_serialized,$no_description,$search_custom),$this);//GARRISON MODIFIED 4/13/2013 + $this->load->view('items/manage',$data); + } + + function find_item_info() + { + $item_number=$this->input->post('scan_item_number'); + echo json_encode($this->Item->find_item_info($item_number)); + } + + function search() + { + $search=$this->input->post('search'); + $data_rows=get_items_manage_table_data_rows($this->Item->search($search),$this); + echo $data_rows; + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest() + { + $suggestions = $this->Item->get_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + function item_search() + { + $suggestions = $this->Item->get_item_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_category() + { + $suggestions = $this->Item->get_category_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + +/**GARRISON ADDED 5/18/2013**/ + /* + Gives search suggestions based on what is being searched for + */ + function suggest_location() + { + $suggestions = $this->Item->get_location_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom1() + { + $suggestions = $this->Item->get_custom1_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom2() + { + $suggestions = $this->Item->get_custom2_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom3() + { + $suggestions = $this->Item->get_custom3_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom4() + { + $suggestions = $this->Item->get_custom4_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom5() + { + $suggestions = $this->Item->get_custom5_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom6() + { + $suggestions = $this->Item->get_custom6_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom7() + { + $suggestions = $this->Item->get_custom7_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom8() + { + $suggestions = $this->Item->get_custom8_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom9() + { + $suggestions = $this->Item->get_custom9_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest_custom10() + { + $suggestions = $this->Item->get_custom10_suggestions($this->input->post('q')); + echo implode("\n",$suggestions); + } +/**END GARRISON ADDED**/ + + function get_row() + { + $item_id = $this->input->post('row_id'); + $data_row=get_item_data_row($this->Item->get_info($item_id),$this); + echo $data_row; + } + + function view($item_id=-1) + { + $data['item_info']=$this->Item->get_info($item_id); + $data['item_tax_info']=$this->Item_taxes->get_info($item_id); + $suppliers = array('' => $this->lang->line('items_none')); + foreach($this->Supplier->get_all()->result_array() as $row) + { + $suppliers[$row['person_id']] = $row['company_name'] .' ('.$row['first_name'] .' '. $row['last_name'].')'; + } + + $data['suppliers']=$suppliers; + $data['selected_supplier'] = $this->Item->get_info($item_id)->supplier_id; + $data['default_tax_1_rate']=($item_id==-1) ? $this->Appconfig->get('default_tax_1_rate') : ''; + $data['default_tax_2_rate']=($item_id==-1) ? $this->Appconfig->get('default_tax_2_rate') : ''; + $this->load->view("items/form",$data); + } + + //Ramel Inventory Tracking + function inventory($item_id=-1) + { + $data['item_info']=$this->Item->get_info($item_id); + $this->load->view("items/inventory",$data); + } + + function count_details($item_id=-1) + { + $data['item_info']=$this->Item->get_info($item_id); + $this->load->view("items/count_details",$data); + } //------------------------------------------- Ramel + + function generate_barcodes($item_ids) + { + $result = array(); + + $item_ids = explode(':', $item_ids); + foreach ($item_ids as $item_id) + { + $item_info = $this->Item->get_info($item_id); + + $result[] = array('name' =>$item_info->name, 'id'=> $item_id); + } + + $data['items'] = $result; + $this->load->view("barcode_sheet", $data); + } + + function bulk_edit() + { + $data = array(); + $suppliers = array('' => $this->lang->line('items_none')); + foreach($this->Supplier->get_all()->result_array() as $row) + { + $suppliers[$row['person_id']] = $row['first_name'] .' '. $row['last_name']; + } + $data['suppliers'] = $suppliers; + $data['allow_alt_desciption_choices'] = array( + ''=>$this->lang->line('items_do_nothing'), + 1 =>$this->lang->line('items_change_all_to_allow_alt_desc'), + 0 =>$this->lang->line('items_change_all_to_not_allow_allow_desc')); + + $data['serialization_choices'] = array( + ''=>$this->lang->line('items_do_nothing'), + 1 =>$this->lang->line('items_change_all_to_serialized'), + 0 =>$this->lang->line('items_change_all_to_unserialized')); + $this->load->view("items/form_bulk", $data); + } + + function save($item_id=-1) + { + $item_data = array( + 'name'=>$this->input->post('name'), + 'description'=>$this->input->post('description'), + 'category'=>$this->input->post('category'), + 'supplier_id'=>$this->input->post('supplier_id')=='' ? null:$this->input->post('supplier_id'), + 'item_number'=>$this->input->post('item_number')=='' ? null:$this->input->post('item_number'), + 'cost_price'=>$this->input->post('cost_price'), + 'unit_price'=>$this->input->post('unit_price'), + 'quantity'=>$this->input->post('quantity'), + 'reorder_level'=>$this->input->post('reorder_level'), + 'location'=>$this->input->post('location'), + 'allow_alt_description'=>$this->input->post('allow_alt_description'), + 'is_serialized'=>$this->input->post('is_serialized'), + 'custom1'=>$this->input->post('custom1'), /**GARRISON ADDED 4/21/2013**/ + 'custom2'=>$this->input->post('custom2'),/**GARRISON ADDED 4/21/2013**/ + 'custom3'=>$this->input->post('custom3'),/**GARRISON ADDED 4/21/2013**/ + 'custom4'=>$this->input->post('custom4'),/**GARRISON ADDED 4/21/2013**/ + 'custom5'=>$this->input->post('custom5'),/**GARRISON ADDED 4/21/2013**/ + 'custom6'=>$this->input->post('custom6'),/**GARRISON ADDED 4/21/2013**/ + 'custom7'=>$this->input->post('custom7'),/**GARRISON ADDED 4/21/2013**/ + 'custom8'=>$this->input->post('custom8'),/**GARRISON ADDED 4/21/2013**/ + 'custom9'=>$this->input->post('custom9'),/**GARRISON ADDED 4/21/2013**/ + 'custom10'=>$this->input->post('custom10')/**GARRISON ADDED 4/21/2013**/ + ); + + $employee_id=$this->Employee->get_logged_in_employee_info()->person_id; + $cur_item_info = $this->Item->get_info($item_id); + + + if($this->Item->save($item_data,$item_id)) + { + //New item + if($item_id==-1) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_adding').' '. + $item_data['name'],'item_id'=>$item_data['item_id'])); + $item_id = $item_data['item_id']; + } + else //previous item + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_updating').' '. + $item_data['name'],'item_id'=>$item_id)); + } + + $inv_data = array + ( + 'trans_date'=>date('Y-m-d H:i:s'), + 'trans_items'=>$item_id, + 'trans_user'=>$employee_id, + 'trans_comment'=>$this->lang->line('items_manually_editing_of_quantity'), + 'trans_inventory'=>$cur_item_info ? $this->input->post('quantity') - $cur_item_info->quantity : $this->input->post('quantity') + ); + $this->Inventory->insert($inv_data); + $items_taxes_data = array(); + $tax_names = $this->input->post('tax_names'); + $tax_percents = $this->input->post('tax_percents'); + for($k=0;$k$tax_names[$k], 'percent'=>$tax_percents[$k] ); + } + } + $this->Item_taxes->save($items_taxes_data, $item_id); + } + else//failure + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('items_error_adding_updating').' '. + $item_data['name'],'item_id'=>-1)); + } + + } + + //Ramel Inventory Tracking + function save_inventory($item_id=-1) + { + $employee_id=$this->Employee->get_logged_in_employee_info()->person_id; + $cur_item_info = $this->Item->get_info($item_id); + $inv_data = array + ( + 'trans_date'=>date('Y-m-d H:i:s'), + 'trans_items'=>$item_id, + 'trans_user'=>$employee_id, + 'trans_comment'=>$this->input->post('trans_comment'), + 'trans_inventory'=>$this->input->post('newquantity') + ); + $this->Inventory->insert($inv_data); + + //Update stock quantity + $item_data = array( + 'quantity'=>$cur_item_info->quantity + $this->input->post('newquantity') + ); + if($this->Item->save($item_data,$item_id)) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_updating').' '. + $cur_item_info->name,'item_id'=>$item_id)); + } + else//failure + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('items_error_adding_updating').' '. + $cur_item_info->name,'item_id'=>-1)); + } + + }//---------------------------------------------------------------------Ramel + + function bulk_update() + { + $items_to_update=$this->input->post('item_ids'); + $item_data = array(); + + foreach($_POST as $key=>$value) + { + //This field is nullable, so treat it differently + if ($key == 'supplier_id') + { + $item_data["$key"]=$value == '' ? null : $value; + } + elseif($value!='' and !(in_array($key, array('item_ids', 'tax_names', 'tax_percents')))) + { + $item_data["$key"]=$value; + } + } + + //Item data could be empty if tax information is being updated + if(empty($item_data) || $this->Item->update_multiple($item_data,$items_to_update)) + { + $items_taxes_data = array(); + $tax_names = $this->input->post('tax_names'); + $tax_percents = $this->input->post('tax_percents'); + for($k=0;$k$tax_names[$k], 'percent'=>$tax_percents[$k] ); + } + } + $this->Item_taxes->save_multiple($items_taxes_data, $items_to_update); + + echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_bulk_edit'))); + } + else + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('items_error_updating_multiple'))); + } + } + + function delete() + { + $items_to_delete=$this->input->post('ids'); + + if($this->Item->delete_list($items_to_delete)) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('items_successful_deleted').' '. + count($items_to_delete).' '.$this->lang->line('items_one_or_multiple'))); + } + else + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('items_cannot_be_deleted'))); + } + } + + function excel() + { + $data = file_get_contents("import_items.csv"); + $name = 'import_items.csv'; + force_download($name, $data); + } + + function excel_import() + { + $this->load->view("items/excel_import", null); + } + + function do_excel_import() + { + $msg = 'do_excel_import'; + $failCodes = array(); + if ($_FILES['file_path']['error']!=UPLOAD_ERR_OK) + { + $msg = $this->lang->line('items_excel_import_failed'); + echo json_encode( array('success'=>false,'message'=>$msg) ); + return; + } + else + { + if (($handle = fopen($_FILES['file_path']['tmp_name'], "r")) !== FALSE) + { + //Skip first row + fgetcsv($handle); + + $i=1; + while (($data = fgetcsv($handle)) !== FALSE) + { + $item_data = array( + 'name' => $data[1], + 'description' => $data[13], + 'location' => $data[12], + 'category' => $data[2], + 'cost_price' => $data[4], + 'unit_price' => $data[5], + 'quantity' => $data[10], + 'reorder_level' => $data[11], + 'supplier_id' => $this->Supplier->exists($data[3]) ? $data[3] : null, + 'allow_alt_description' => $data[14] != '' ? '1' : '0', + 'is_serialized' => $data[15] != '' ? '1' : '0', + 'custom1' => $data[16], /** GARRISON ADDED 5/6/2013 **/ + 'custom2' => $data[17], /** GARRISON ADDED 5/6/2013 **/ + 'custom3' => $data[18], /** GARRISON ADDED 5/6/2013 **/ + 'custom4' => $data[19], /** GARRISON ADDED 5/6/2013 **/ + 'custom5' => $data[20], /** GARRISON ADDED 5/6/2013 **/ + 'custom6' => $data[21], /** GARRISON ADDED 5/6/2013 **/ + 'custom7' => $data[22], /** GARRISON ADDED 5/6/2013 **/ + 'custom8' => $data[23], /** GARRISON ADDED 5/6/2013 **/ + 'custom9' => $data[24], /** GARRISON ADDED 5/6/2013 **/ + 'custom10' => $data[25] /** GARRISON ADDED 5/6/2013 **/ + ); + $item_number = $data[0]; + + if ($item_number != "") + { + $item_data['item_number'] = $item_number; + } + + if($this->Item->save($item_data)) + { + $items_taxes_data = null; + //tax 1 + if( is_numeric($data[7]) && $data[6]!='' ) + { + $items_taxes_data[] = array('name'=>$data[6], 'percent'=>$data[7] ); + } + + //tax 2 + if( is_numeric($data[9]) && $data[8]!='' ) + { + $items_taxes_data[] = array('name'=>$data[8], 'percent'=>$data[9] ); + } + + // save tax values + if(count($items_taxes_data) > 0) + { + $this->Item_taxes->save($items_taxes_data, $item_data['item_id']); + } + + $employee_id=$this->Employee->get_logged_in_employee_info()->person_id; + $emp_info=$this->Employee->get_info($employee_id); + $comment ='Qty CSV Imported'; + $excel_data = array + ( + 'trans_items'=>$item_data['item_id'], + 'trans_user'=>$employee_id, + 'trans_comment'=>$comment, + 'trans_inventory'=>$data[10] + ); + $this->db->insert('inventory',$excel_data); + //------------------------------------------------Ramel + } + else//insert or update item failure + { + $failCodes[] = $i; + } + } + + $i++; + } + else + { + echo json_encode( array('success'=>false,'message'=>'Your upload file has no data or not in supported format.') ); + return; + } + } + + $success = true; + if(count($failCodes) > 1) + { + $msg = "Most items imported. But some were not, here is list of their CODE (" .count($failCodes) ."): ".implode(", ", $failCodes); + $success = false; + } + else + { + $msg = "Import items successful"; + } + + echo json_encode( array('success'=>$success,'message'=>$msg) ); + } + + /* + get the width for the add/edit form + */ + function get_form_width() + { + return 360; + } +} +?> \ No newline at end of file diff --git a/application/controllers/languagecheck.php b/application/controllers/languagecheck.php new file mode 100644 index 000000000..61b9a4709 --- /dev/null +++ b/application/controllers/languagecheck.php @@ -0,0 +1,192 @@ +load->helper('directory'); + + // for simplicity, we don't use views + $this->output('h1', 'Open Source Point of Sale - Language file checking and validation'); + + // determine the language file path + if ( ! is_dir($this->lang_path) ) + { + $this->lang_path = APPPATH . $this->lang_path; + + if ( ! is_dir($this->lang_path) ) + { + $this->output('h2', 'Defined language path "'.$this->lang_path.'" not found!', TRUE); + exit; + } + } + + // fetch the languages directory map + $languages = directory_map( $this->lang_path, TRUE ); + + // is our reference language present? + if ( ! in_array($this->reference, $languages ) ) + { + $this->output('h2', 'Reference language "'.$this->reference.'" not found!', TRUE); + exit; + } + + // load the list of language files for the reference language + $references = directory_map( $this->lang_path . '/' . $this->reference, TRUE ); + + // now process the list + foreach( $references as $reference ) + { + // skip non-language files in the language directory + if ( strpos($reference, '_lang'.EXT) === FALSE ) + { + continue; + } + + // process it + $this->output('h2', 'Processing '.$this->reference . ' » ' .$reference); + + // load the language file + include $this->lang_path . '/' . $this->reference . '/' . $reference; + + // did the file contain any language strings? + if ( empty($lang) ) + { + // language file was empty or not properly defined + $this->output('h3', 'Language file doesn\'t contain any language strings. Skipping file!', TRUE); + continue; + } + + // store the loaded language strings + $lang_ref = $lang; + unset($lang); + + // now loop through the available languages + foreach ( $languages as $language ) + { + // skip the reference language + if ( $language == $this->reference ) + { + continue; + } + + // language file to check + $file = $this->lang_path . '/' . $language . '/' . $reference; + + // check if the language file exists for this language + if ( ! file_exists( $file ) ) + { + // file not found + $this->output('h3', 'Language file doesn\'t exist for the language '.$language.'!', TRUE); + } + else + { + // load the file to compare + include $file; + + // did the file contain any language strings? + if ( empty($lang) ) + { + // language file was empty or not properly defined + $this->output('h3', 'Language file for the language '.$language.' doesn\'t contain any language strings!', TRUE); + } + else + { + // start comparing + $this->output('h3', 'Comparing with the '.$language.' version:'); + + // assume all goes well + $failures = 0; + + // start comparing language keys + foreach( $lang_ref as $key => $value ) + { + if ( ! isset($lang[$key]) ) + { + // report the missing key + $this->output('', 'Missing language string "'.$key.'"', TRUE); + + // increment the failure counter + $failures++; + } + } + + if ( ! $failures ) + { + $this->output('', 'The two language files have matching strings.'); + } + } + + // make sure the lang array is deleted before the next check + if ( isset($lang) ) + { + unset($lang); + } + } + } + + } + + $this->output('h2', 'Language file checking and validation completed'); + } + + // ----------------------------------------------------------------- + + private function output($type = '', $line = '', $highlight = FALSE) + { + switch ($type) + { + case 'h1': + $html = "

{line}

\n
\n"; + break; + + case 'h2': + $html = "

{line}

\n"; + break; + + case 'h3': + $html = "

   {line}

\n"; + break; + + default: + $html = "    » {line}
"; + break; + } + + if ( $highlight ) + { + $line = '' . $line . ''; + } + + echo str_replace('{line}', $line, $html); + } + // ----------------------------------------------------------------- + +} + +/* End of file languagecheck.php */ +/* Location: ./application/controllers/languagecheck.php */ diff --git a/application/controllers/login.php b/application/controllers/login.php new file mode 100644 index 000000000..809e0c432 --- /dev/null +++ b/application/controllers/login.php @@ -0,0 +1,43 @@ +Employee->is_logged_in()) + { + redirect('home'); + } + else + { + $this->form_validation->set_rules('username', 'lang:login_undername', 'callback_login_check'); + $this->form_validation->set_error_delimiters('
', '
'); + + if($this->form_validation->run() == FALSE) + { + $this->load->view('login'); + } + else + { + redirect('home'); + } + } + } + + function login_check($username) + { + $password = $this->input->post("password"); + + if(!$this->Employee->login($username,$password)) + { + $this->form_validation->set_message('login_check', $this->lang->line('login_invalid_username_and_password')); + return false; + } + return true; + } +} +?> \ No newline at end of file diff --git a/application/controllers/no_access.php b/application/controllers/no_access.php new file mode 100644 index 000000000..cba136e5c --- /dev/null +++ b/application/controllers/no_access.php @@ -0,0 +1,15 @@ +Module->get_module_name($module_id); + $this->load->view('no_access',$data); + } +} +?> \ No newline at end of file diff --git a/application/controllers/person_controller.php b/application/controllers/person_controller.php new file mode 100644 index 000000000..b039fa62b --- /dev/null +++ b/application/controllers/person_controller.php @@ -0,0 +1,54 @@ +input->post('ids'); + + if($people_to_email!=false) + { + $mailto_url='mailto:'; + foreach($this->Person->get_multiple_info($people_to_email)->result() as $person) + { + $mailto_url.=$person->email.','; + } + //remove last comma + $mailto_url=substr($mailto_url,0,strlen($mailto_url)-1); + + echo $mailto_url; + exit; + } + echo '#'; + } +/** GARRISON ADDED 4/25/2013 IN PROGRESS **/ + /* + Gives search suggestions based on what is being searched for + */ + function suggest() + { + $suggestions = $this->Person->get_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + /* + Gets one row for a person manage table. This is called using AJAX to update one row. + */ + function get_row() + { + $person_id = $this->input->post('row_id'); + $data_row=get_person_data_row($this->Person->get_info($person_id),$this); + echo $data_row; + } + +} +?> \ No newline at end of file diff --git a/application/controllers/receivings.php b/application/controllers/receivings.php new file mode 100644 index 000000000..122490603 --- /dev/null +++ b/application/controllers/receivings.php @@ -0,0 +1,197 @@ +load->library('receiving_lib'); + } + + function index() + { + $this->_reload(); + } + + function item_search() + { + $suggestions = $this->Item->get_item_search_suggestions($this->input->post('q'),$this->input->post('limit')); + $suggestions = array_merge($suggestions, $this->Item_kit->get_item_kit_search_suggestions($this->input->post('q'),$this->input->post('limit'))); + echo implode("\n",$suggestions); + } + + function supplier_search() + { + $suggestions = $this->Supplier->get_suppliers_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + function select_supplier() + { + $supplier_id = $this->input->post("supplier"); + $this->receiving_lib->set_supplier($supplier_id); + $this->_reload(); + } + + function change_mode() + { + $mode = $this->input->post("mode"); + $this->receiving_lib->set_mode($mode); + $this->_reload(); + } + + function add() + { + $data=array(); + $mode = $this->receiving_lib->get_mode(); + $item_id_or_number_or_item_kit_or_receipt = $this->input->post("item"); + $quantity = $mode=="receive" ? 1:-1; + + if($this->receiving_lib->is_valid_receipt($item_id_or_number_or_item_kit_or_receipt) && $mode=='return') + { + $this->receiving_lib->return_entire_receiving($item_id_or_number_or_item_kit_or_receipt); + } + elseif($this->receiving_lib->is_valid_item_kit($item_id_or_number_or_item_kit_or_receipt)) + { + $this->receiving_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt); + } + elseif(!$this->receiving_lib->add_item($item_id_or_number_or_item_kit_or_receipt,$quantity)) + { + $data['error']=$this->lang->line('recvs_unable_to_add_item'); + } + $this->_reload($data); + } + + function edit_item($item_id) + { + $data= array(); + + $this->form_validation->set_rules('price', 'lang:items_price', 'required|numeric'); + $this->form_validation->set_rules('quantity', 'lang:items_quantity', 'required|integer'); + $this->form_validation->set_rules('discount', 'lang:items_discount', 'required|integer'); + + $description = $this->input->post("description"); + $serialnumber = $this->input->post("serialnumber"); + $price = $this->input->post("price"); + $quantity = $this->input->post("quantity"); + $discount = $this->input->post("discount"); + + if ($this->form_validation->run() != FALSE) + { + $this->receiving_lib->edit_item($item_id,$description,$serialnumber,$quantity,$discount,$price); + } + else + { + $data['error']=$this->lang->line('recvs_error_editing_item'); + } + + $this->_reload($data); + } + + function delete_item($item_number) + { + $this->receiving_lib->delete_item($item_number); + $this->_reload(); + } + + function delete_supplier() + { + $this->receiving_lib->delete_supplier(); + $this->_reload(); + } + + function complete() + { + $data['cart']=$this->receiving_lib->get_cart(); + $data['total']=$this->receiving_lib->get_total(); + $data['receipt_title']=$this->lang->line('recvs_receipt'); + $data['transaction_time']= date('m/d/Y h:i:s a'); + $supplier_id=$this->receiving_lib->get_supplier(); + $employee_id=$this->Employee->get_logged_in_employee_info()->person_id; + $comment = $this->input->post('comment'); + $emp_info=$this->Employee->get_info($employee_id); + $payment_type = $this->input->post('payment_type'); + $data['payment_type']=$this->input->post('payment_type'); + + if ($this->input->post('amount_tendered')) + { + $data['amount_tendered'] = $this->input->post('amount_tendered'); + $data['amount_change'] = to_currency($data['amount_tendered'] - round($data['total'], 2)); + } + $data['employee']=$emp_info->first_name.' '.$emp_info->last_name; + + if($supplier_id!=-1) + { + $suppl_info=$this->Supplier->get_info($supplier_id); + $data['supplier']=$suppl_info->first_name.' '.$suppl_info->last_name; + } + + //SAVE receiving to database + $data['receiving_id']='RECV '.$this->Receiving->save($data['cart'], $supplier_id,$employee_id,$comment,$payment_type); + + if ($data['receiving_id'] == 'RECV -1') + { + $data['error_message'] = $this->lang->line('receivings_transaction_failed'); + } + + $this->load->view("receivings/receipt",$data); + $this->receiving_lib->clear_all(); + } + + function receipt($receiving_id) + { + $receiving_info = $this->Receiving->get_info($receiving_id)->row_array(); + $this->receiving_lib->copy_entire_receiving($receiving_id); + $data['cart']=$this->receiving_lib->get_cart(); + $data['total']=$this->receiving_lib->get_total(); + $data['receipt_title']=$this->lang->line('recvs_receipt'); + $data['transaction_time']= date('m/d/Y h:i:s a', strtotime($receiving_info['receiving_time'])); + $supplier_id=$this->receiving_lib->get_supplier(); + $emp_info=$this->Employee->get_info($receiving_info['employee_id']); + $data['payment_type']=$receiving_info['payment_type']; + + $data['employee']=$emp_info->first_name.' '.$emp_info->last_name; + + if($supplier_id!=-1) + { + $supplier_info=$this->Supplier->get_info($supplier_id); + $data['supplier']=$supplier_info->first_name.' '.$supplier_info->last_name; + } + $data['receiving_id']='RECV '.$receiving_id; + $this->load->view("receivings/receipt",$data); + $this->receiving_lib->clear_all(); + + } + + function _reload($data=array()) + { + $person_info = $this->Employee->get_logged_in_employee_info(); + $data['cart']=$this->receiving_lib->get_cart(); + $data['modes']=array('receive'=>$this->lang->line('recvs_receiving'),'return'=>$this->lang->line('recvs_return')); + $data['mode']=$this->receiving_lib->get_mode(); + $data['total']=$this->receiving_lib->get_total(); + $data['items_module_allowed'] = $this->Employee->has_permission('items', $person_info->person_id); + $data['payment_options']=array( + $this->lang->line('sales_cash') => $this->lang->line('sales_cash'), + $this->lang->line('sales_check') => $this->lang->line('sales_check'), + $this->lang->line('sales_debit') => $this->lang->line('sales_debit'), + $this->lang->line('sales_credit') => $this->lang->line('sales_credit') + ); + + $supplier_id=$this->receiving_lib->get_supplier(); + if($supplier_id!=-1) + { + $info=$this->Supplier->get_info($supplier_id); + $data['supplier']=$info->first_name.' '.$info->last_name; + } + $this->load->view("receivings/receiving",$data); + } + + function cancel_receiving() + { + $this->receiving_lib->clear_all(); + $this->_reload(); + } + +} +?> \ No newline at end of file diff --git a/application/controllers/reports.php b/application/controllers/reports.php new file mode 100644 index 000000000..ed759f047 --- /dev/null +++ b/application/controllers/reports.php @@ -0,0 +1,827 @@ +load->helper('report'); + } + + //Initial report listing screen + function index() + { + $this->load->view("reports/listing",array()); + } + + function _get_common_report_data() + { + $data = array(); + $data['report_date_range_simple'] = get_simple_date_ranges(); + $data['months'] = get_months(); + $data['days'] = get_days(); + $data['years'] = get_years(); + $data['selected_month']=date('n'); + $data['selected_day']=date('d'); + $data['selected_year']=date('Y'); + + return $data; + } + + //Input for reports that require only a date range and an export to excel. (see routes.php to see that all summary reports route here) + function date_input_excel_export() + { + $data = $this->_get_common_report_data(); + $this->load->view("reports/date_input_excel_export",$data); + } + + //Summary sales report + function summary_sales($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_sales'); + $model = $this->Summary_sales; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array($row['sale_date'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit'])); + } + + $data = array( + "title" => $this->lang->line('reports_sales_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + //Summary categories report + function summary_categories($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_categories'); + $model = $this->Summary_categories; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array($row['category'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit'])); + } + + $data = array( + "title" => $this->lang->line('reports_categories_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + //Summary customers report + function summary_customers($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_customers'); + $model = $this->Summary_customers; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array($row['customer'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit'])); + } + + $data = array( + "title" => $this->lang->line('reports_customers_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + //Summary suppliers report + function summary_suppliers($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_suppliers'); + $model = $this->Summary_suppliers; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array($row['supplier'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit'])); + } + + $data = array( + "title" => $this->lang->line('reports_suppliers_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + //Summary items report + function summary_items($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_items'); + $model = $this->Summary_items; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array(character_limiter($row['name'], 16), $row['quantity_purchased'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit'])); + } + + $data = array( + "title" => $this->lang->line('reports_items_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + //Summary employees report + function summary_employees($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_employees'); + $model = $this->Summary_employees; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array($row['employee'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit'])); + } + + $data = array( + "title" => $this->lang->line('reports_employees_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + //Summary taxes report + function summary_taxes($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_taxes'); + $model = $this->Summary_taxes; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array($row['percent'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax'])); + } + + $data = array( + "title" => $this->lang->line('reports_taxes_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + //Summary discounts report + function summary_discounts($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_discounts'); + $model = $this->Summary_discounts; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array($row['discount_percent'],$row['count']); + } + + $data = array( + "title" => $this->lang->line('reports_discounts_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + function summary_payments($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Summary_payments'); + $model = $this->Summary_payments; + $tabular_data = array(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + foreach($report_data as $row) + { + $tabular_data[] = array($row['payment_type'],to_currency($row['payment_amount'])); + } + + $data = array( + "title" => $this->lang->line('reports_payments_summary_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + //Input for reports that require only a date range. (see routes.php to see that all graphical summary reports route here) + function date_input() + { + $data = $this->_get_common_report_data(); + $this->load->view("reports/date_input",$data); + } + + //Graphical summary sales report + function graphical_summary_sales($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_sales'); + $model = $this->Summary_sales; + + $data = array( + "title" => $this->lang->line('reports_sales_summary_report'), + "data_file" => site_url("reports/graphical_summary_sales_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_sales_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_sales'); + $model = $this->Summary_sales; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[date('m/d/Y', strtotime($row['sale_date']))]= $row['total']; + } + + $data = array( + "title" => $this->lang->line('reports_sales_summary_report'), + "yaxis_label"=>$this->lang->line('reports_revenue'), + "xaxis_label"=>$this->lang->line('reports_date'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/line",$data); + + } + + //Graphical summary items report + function graphical_summary_items($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_items'); + $model = $this->Summary_items; + + $data = array( + "title" => $this->lang->line('reports_items_summary_report'), + "data_file" => site_url("reports/graphical_summary_items_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_items_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_items'); + $model = $this->Summary_items; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[$row['name']] = $row['total']; + } + + $data = array( + "title" => $this->lang->line('reports_items_summary_report'), + "xaxis_label"=>$this->lang->line('reports_revenue'), + "yaxis_label"=>$this->lang->line('reports_items'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/hbar",$data); + } + + //Graphical summary customers report + function graphical_summary_categories($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_categories'); + $model = $this->Summary_categories; + + $data = array( + "title" => $this->lang->line('reports_categories_summary_report'), + "data_file" => site_url("reports/graphical_summary_categories_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_categories_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_categories'); + $model = $this->Summary_categories; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[$row['category']] = $row['total']; + } + + $data = array( + "title" => $this->lang->line('reports_categories_summary_report'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/pie",$data); + } + + function graphical_summary_suppliers($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_suppliers'); + $model = $this->Summary_suppliers; + + $data = array( + "title" => $this->lang->line('reports_suppliers_summary_report'), + "data_file" => site_url("reports/graphical_summary_suppliers_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_suppliers_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_suppliers'); + $model = $this->Summary_suppliers; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[$row['supplier']] = $row['total']; + } + + $data = array( + "title" => $this->lang->line('reports_suppliers_summary_report'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/pie",$data); + } + + function graphical_summary_employees($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_employees'); + $model = $this->Summary_employees; + + $data = array( + "title" => $this->lang->line('reports_employees_summary_report'), + "data_file" => site_url("reports/graphical_summary_employees_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_employees_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_employees'); + $model = $this->Summary_employees; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[$row['employee']] = $row['total']; + } + + $data = array( + "title" => $this->lang->line('reports_employees_summary_report'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/pie",$data); + } + + function graphical_summary_taxes($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_taxes'); + $model = $this->Summary_taxes; + + $data = array( + "title" => $this->lang->line('reports_taxes_summary_report'), + "data_file" => site_url("reports/graphical_summary_taxes_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_taxes_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_taxes'); + $model = $this->Summary_taxes; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[$row['percent']] = $row['total']; + } + + $data = array( + "title" => $this->lang->line('reports_taxes_summary_report'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/pie",$data); + } + + //Graphical summary customers report + function graphical_summary_customers($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_customers'); + $model = $this->Summary_customers; + + $data = array( + "title" => $this->lang->line('reports_customers_summary_report'), + "data_file" => site_url("reports/graphical_summary_customers_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_customers_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_customers'); + $model = $this->Summary_customers; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[$row['customer']] = $row['total']; + } + + $data = array( + "title" => $this->lang->line('reports_customers_summary_report'), + "xaxis_label"=>$this->lang->line('reports_revenue'), + "yaxis_label"=>$this->lang->line('reports_customers'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/hbar",$data); + } + + //Graphical summary discounts report + function graphical_summary_discounts($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_discounts'); + $model = $this->Summary_discounts; + + $data = array( + "title" => $this->lang->line('reports_discounts_summary_report'), + "data_file" => site_url("reports/graphical_summary_discounts_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_discounts_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_discounts'); + $model = $this->Summary_discounts; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[$row['discount_percent']] = $row['count']; + } + + $data = array( + "title" => $this->lang->line('reports_discounts_summary_report'), + "yaxis_label"=>$this->lang->line('reports_count'), + "xaxis_label"=>$this->lang->line('reports_discount_percent'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/bar",$data); + } + + function graphical_summary_payments($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_payments'); + $model = $this->Summary_payments; + + $data = array( + "title" => $this->lang->line('reports_payments_summary_report'), + "data_file" => site_url("reports/graphical_summary_payments_graph/$start_date/$end_date/$sale_type"), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)) + ); + + $this->load->view("reports/graphical",$data); + } + + //The actual graph data + function graphical_summary_payments_graph($start_date, $end_date, $sale_type) + { + $this->load->model('reports/Summary_payments'); + $model = $this->Summary_payments; + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $graph_data = array(); + foreach($report_data as $row) + { + $graph_data[$row['payment_type']] = $row['payment_amount']; + } + + $data = array( + "title" => $this->lang->line('reports_payments_summary_report'), + "yaxis_label"=>$this->lang->line('reports_revenue'), + "xaxis_label"=>$this->lang->line('reports_payment_type'), + "data" => $graph_data + ); + + $this->load->view("reports/graphs/pie",$data); + } + function specific_customer_input() + { + $data = $this->_get_common_report_data(); + $data['specific_input_name'] = $this->lang->line('reports_customer'); + + $customers = array(); + foreach($this->Customer->get_all()->result() as $customer) + { + $customers[$customer->person_id] = $customer->first_name .' '.$customer->last_name; + } + $data['specific_input_data'] = $customers; + $this->load->view("reports/specific_input",$data); + } + + function specific_customer($start_date, $end_date, $customer_id, $sale_type, $export_excel=0) + { + $this->load->model('reports/Specific_customer'); + $model = $this->Specific_customer; + + $headers = $model->getDataColumns(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'customer_id' =>$customer_id, 'sale_type' => $sale_type)); + + $summary_data = array(); + $details_data = array(); + + foreach($report_data['summary'] as $key=>$row) + { + $summary_data[] = array(anchor('sales/edit/'.$row['sale_id'], 'POS '.$row['sale_id'], array('target' => '_blank')), $row['sale_date'], $row['items_purchased'], $row['employee_name'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit']), $row['payment_type'], $row['comment']); + + foreach($report_data['details'][$key] as $drow) + { + $details_data[$key][] = array($drow['name'], $drow['category'], $drow['serialnumber'], $drow['description'], $drow['quantity_purchased'], to_currency($drow['subtotal']), to_currency($drow['total']), to_currency($drow['tax']),to_currency($drow['profit']), $drow['discount_percent'].'%'); + } + } + + $customer_info = $this->Customer->get_info($customer_id); + $data = array( + "title" => $customer_info->first_name .' '. $customer_info->last_name.' '.$this->lang->line('reports_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "summary_data" => $summary_data, + "details_data" => $details_data, + "overall_summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date,'customer_id' =>$customer_id, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular_details",$data); + } + + function specific_employee_input() + { + $data = $this->_get_common_report_data(); + $data['specific_input_name'] = $this->lang->line('reports_employee'); + + $employees = array(); + foreach($this->Employee->get_all()->result() as $employee) + { + $employees[$employee->person_id] = $employee->first_name .' '.$employee->last_name; + } + $data['specific_input_data'] = $employees; + $this->load->view("reports/specific_input",$data); + } + + function specific_employee($start_date, $end_date, $employee_id, $sale_type, $export_excel=0) + { + $this->load->model('reports/Specific_employee'); + $model = $this->Specific_employee; + + $headers = $model->getDataColumns(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'employee_id' =>$employee_id, 'sale_type' => $sale_type)); + + $summary_data = array(); + $details_data = array(); + + foreach($report_data['summary'] as $key=>$row) + { + $summary_data[] = array(anchor('sales/edit/'.$row['sale_id'], 'POS '.$row['sale_id'], array('target' => '_blank')), $row['sale_date'], $row['items_purchased'], $row['customer_name'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit']), $row['payment_type'], $row['comment']); + + foreach($report_data['details'][$key] as $drow) + { + $details_data[$key][] = array($drow['name'], $drow['category'], $drow['serialnumber'], $drow['description'], $drow['quantity_purchased'], to_currency($drow['subtotal']), to_currency($drow['total']), to_currency($drow['tax']),to_currency($drow['profit']), $drow['discount_percent'].'%'); + } + } + + $employee_info = $this->Employee->get_info($employee_id); + $data = array( + "title" => $employee_info->first_name .' '. $employee_info->last_name.' '.$this->lang->line('reports_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "summary_data" => $summary_data, + "details_data" => $details_data, + "overall_summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date,'employee_id' =>$employee_id, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular_details",$data); + } + + function detailed_sales($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Detailed_sales'); + $model = $this->Detailed_sales; + + $headers = $model->getDataColumns(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $summary_data = array(); + $details_data = array(); + + foreach($report_data['summary'] as $key=>$row) + { + $summary_data[] = array(anchor('sales/edit/'.$row['sale_id'], 'POS '.$row['sale_id'], array('target' => '_blank')), $row['sale_date'], $row['items_purchased'], $row['employee_name'], $row['customer_name'], to_currency($row['subtotal']), to_currency($row['total']), to_currency($row['tax']),to_currency($row['profit']), $row['payment_type'], $row['comment']); + + foreach($report_data['details'][$key] as $drow) + { + $details_data[$key][] = array($drow['name'], $drow['category'], $drow['serialnumber'], $drow['description'], $drow['quantity_purchased'], to_currency($drow['subtotal']), to_currency($drow['total']), to_currency($drow['tax']),to_currency($drow['profit']), $drow['discount_percent'].'%'); + } + } + + $data = array( + "title" =>$this->lang->line('reports_detailed_sales_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "summary_data" => $summary_data, + "details_data" => $details_data, + "overall_summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular_details",$data); + } + + function detailed_receivings($start_date, $end_date, $sale_type, $export_excel=0) + { + $this->load->model('reports/Detailed_receivings'); + $model = $this->Detailed_receivings; + + $headers = $model->getDataColumns(); + $report_data = $model->getData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)); + + $summary_data = array(); + $details_data = array(); + + foreach($report_data['summary'] as $key=>$row) + { + $summary_data[] = array(anchor('receivings/receipt/'.$row['receiving_id'], 'RECV '.$row['receiving_id'], array('target' => '_blank')), $row['receiving_date'], $row['items_purchased'], $row['employee_name'], $row['supplier_name'], to_currency($row['total']), $row['payment_type'], $row['comment']); + + foreach($report_data['details'][$key] as $drow) + { + $details_data[$key][] = array($drow['name'], $drow['category'], $drow['quantity_purchased'], to_currency($drow['total']), $drow['discount_percent'].'%'); + } + } + + $data = array( + "title" =>$this->lang->line('reports_detailed_receivings_report'), + "subtitle" => date('m/d/Y', strtotime($start_date)) .'-'.date('m/d/Y', strtotime($end_date)), + "headers" => $model->getDataColumns(), + "summary_data" => $summary_data, + "details_data" => $details_data, + "overall_summary_data" => $model->getSummaryData(array('start_date'=>$start_date, 'end_date'=>$end_date, 'sale_type' => $sale_type)), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular_details",$data); + } + + function excel_export() + { + $this->load->view("reports/excel_export",array()); + } + + function inventory_low($export_excel=0) + { + $this->load->model('reports/Inventory_low'); + $model = $this->Inventory_low; + $tabular_data = array(); + $report_data = $model->getData(array()); + foreach($report_data as $row) + { + $tabular_data[] = array($row['name'], $row['item_number'], $row['description'], $row['quantity'], $row['reorder_level']); + } + + $data = array( + "title" => $this->lang->line('reports_low_inventory_report'), + "subtitle" => '', + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array()), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + + function inventory_summary($export_excel=0) + { + $this->load->model('reports/Inventory_summary'); + $model = $this->Inventory_summary; + $tabular_data = array(); + $report_data = $model->getData(array()); + foreach($report_data as $row) + { + $tabular_data[] = array($row['name'], $row['item_number'], $row['description'], $row['quantity'], $row['reorder_level']); + } + + $data = array( + "title" => $this->lang->line('reports_inventory_summary_report'), + "subtitle" => '', + "headers" => $model->getDataColumns(), + "data" => $tabular_data, + "summary_data" => $model->getSummaryData(array()), + "export_excel" => $export_excel + ); + + $this->load->view("reports/tabular",$data); + } + +} +?> \ No newline at end of file diff --git a/application/controllers/sales.php b/application/controllers/sales.php new file mode 100644 index 000000000..3e6ddd7f5 --- /dev/null +++ b/application/controllers/sales.php @@ -0,0 +1,431 @@ +load->library('sale_lib'); + } + + function index() + { + $this->_reload(); + } + + function item_search() + { + $suggestions = $this->Item->get_item_search_suggestions($this->input->post('q'),$this->input->post('limit')); + $suggestions = array_merge($suggestions, $this->Item_kit->get_item_kit_search_suggestions($this->input->post('q'),$this->input->post('limit'))); + echo implode("\n",$suggestions); + } + + function customer_search() + { + $suggestions = $this->Customer->get_customer_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + function select_customer() + { + $customer_id = $this->input->post("customer"); + $this->sale_lib->set_customer($customer_id); + $this->_reload(); + } + + function change_mode() + { + $mode = $this->input->post("mode"); + $this->sale_lib->set_mode($mode); + $this->_reload(); + } + + function set_comment() + { + $this->sale_lib->set_comment($this->input->post('comment')); + } + + function set_email_receipt() + { + $this->sale_lib->set_email_receipt($this->input->post('email_receipt')); + } + + //Alain Multiple Payments + function add_payment() + { + $data = array(); + $this->form_validation->set_rules( 'amount_tendered', 'lang:sales_amount_tendered', 'numeric' ); + + if ( $this->form_validation->run() == FALSE ) + { + if ( $this->input->post( 'payment_type' ) == $this->lang->line( 'sales_gift_card' ) ) + $data['error']=$this->lang->line('sales_must_enter_numeric_giftcard'); + else + $data['error']=$this->lang->line('sales_must_enter_numeric'); + + $this->_reload( $data ); + return; + } + + $payment_type = $this->input->post( 'payment_type' ); + if ( $payment_type == $this->lang->line( 'sales_giftcard' ) ) + { + $payments = $this->sale_lib->get_payments(); + $payment_type = $this->input->post( 'payment_type' ) . ':' . $payment_amount = $this->input->post( 'amount_tendered' ); + $current_payments_with_giftcard = isset( $payments[$payment_type] ) ? $payments[$payment_type]['payment_amount'] : 0; + $cur_giftcard_value = $this->Giftcard->get_giftcard_value( $this->input->post( 'amount_tendered' ) ) - $current_payments_with_giftcard; + + if ( $cur_giftcard_value <= 0 ) + { + $data['error'] = 'Giftcard balance is ' . to_currency( $this->Giftcard->get_giftcard_value( $this->input->post( 'amount_tendered' ) ) ) . ' !'; + $this->_reload( $data ); + return; + } + + $new_giftcard_value = $this->Giftcard->get_giftcard_value( $this->input->post( 'amount_tendered' ) ) - $this->sale_lib->get_amount_due( ); + $new_giftcard_value = ( $new_giftcard_value >= 0 ) ? $new_giftcard_value : 0; + $data['warning'] = 'Giftcard ' . $this->input->post( 'amount_tendered' ) . ' balance is ' . to_currency( $new_giftcard_value ) . ' !'; + $payment_amount = min( $this->sale_lib->get_amount_due( ), $this->Giftcard->get_giftcard_value( $this->input->post( 'amount_tendered' ) ) ); + } + else + { + $payment_amount = $this->input->post( 'amount_tendered' ); + } + + if( !$this->sale_lib->add_payment( $payment_type, $payment_amount ) ) + { + $data['error']='Unable to Add Payment! Please try again!'; + } + + $this->_reload($data); + } + + //Alain Multiple Payments + function delete_payment( $payment_id ) + { + $this->sale_lib->delete_payment( $payment_id ); + $this->_reload(); + } + + function add() + { + $data=array(); + $mode = $this->sale_lib->get_mode(); + $item_id_or_number_or_item_kit_or_receipt = $this->input->post("item"); + $quantity = $mode=="sale" ? 1:-1; + + if($this->sale_lib->is_valid_receipt($item_id_or_number_or_item_kit_or_receipt) && $mode=='return') + { + $this->sale_lib->return_entire_sale($item_id_or_number_or_item_kit_or_receipt); + } + elseif($this->sale_lib->is_valid_item_kit($item_id_or_number_or_item_kit_or_receipt)) + { + $this->sale_lib->add_item_kit($item_id_or_number_or_item_kit_or_receipt); + } + elseif(!$this->sale_lib->add_item($item_id_or_number_or_item_kit_or_receipt,$quantity)) + { + $data['error']=$this->lang->line('sales_unable_to_add_item'); + } + + if($this->sale_lib->out_of_stock($item_id_or_number_or_item_kit_or_receipt)) + { + $data['warning'] = $this->lang->line('sales_quantity_less_than_zero'); + } + $this->_reload($data); + } + + function edit_item($line) + { + $data= array(); + + $this->form_validation->set_rules('price', 'lang:items_price', 'required|numeric'); + $this->form_validation->set_rules('quantity', 'lang:items_quantity', 'required|numeric'); + + $description = $this->input->post("description"); + $serialnumber = $this->input->post("serialnumber"); + $price = $this->input->post("price"); + $quantity = $this->input->post("quantity"); + $discount = $this->input->post("discount"); + + + if ($this->form_validation->run() != FALSE) + { + $this->sale_lib->edit_item($line,$description,$serialnumber,$quantity,$discount,$price); + } + else + { + $data['error']=$this->lang->line('sales_error_editing_item'); + } + + if($this->sale_lib->out_of_stock($this->sale_lib->get_item_id($line))) + { + $data['warning'] = $this->lang->line('sales_quantity_less_than_zero'); + } + + + $this->_reload($data); + } + + function delete_item($item_number) + { + $this->sale_lib->delete_item($item_number); + $this->_reload(); + } + + function remove_customer() + { + $this->sale_lib->remove_customer(); + $this->_reload(); + } + + function complete() + { + $data['cart']=$this->sale_lib->get_cart(); + $data['subtotal']=$this->sale_lib->get_subtotal(); + $data['taxes']=$this->sale_lib->get_taxes(); + $data['total']=$this->sale_lib->get_total(); + $data['receipt_title']=$this->lang->line('sales_receipt'); + $data['transaction_time']= date('m/d/Y h:i:s a'); + $customer_id=$this->sale_lib->get_customer(); + $employee_id=$this->Employee->get_logged_in_employee_info()->person_id; + $comment = $this->sale_lib->get_comment(); + $emp_info=$this->Employee->get_info($employee_id); + $data['payments']=$this->sale_lib->get_payments(); + $data['amount_change']=to_currency($this->sale_lib->get_amount_due() * -1); + $data['employee']=$emp_info->first_name.' '.$emp_info->last_name; + + if($customer_id!=-1) + { + $cust_info=$this->Customer->get_info($customer_id); + $data['customer']=$cust_info->first_name.' '.$cust_info->last_name; + } + + //SAVE sale to database + $data['sale_id']='POS '.$this->Sale->save($data['cart'], $customer_id,$employee_id,$comment,$data['payments']); + if ($data['sale_id'] == 'POS -1') + { + $data['error_message'] = $this->lang->line('sales_transaction_failed'); + } + else + { + if ($this->sale_lib->get_email_receipt() && !empty($cust_info->email)) + { + $this->load->library('email'); + $config['mailtype'] = 'html'; + $this->email->initialize($config); + $this->email->from($this->config->item('email'), $this->config->item('company')); + $this->email->to($cust_info->email); + + $this->email->subject($this->lang->line('sales_receipt')); + $this->email->message($this->load->view("sales/receipt_email",$data, true)); + $this->email->send(); + } + } + $this->load->view("sales/receipt",$data); + $this->sale_lib->clear_all(); + } + + function receipt($sale_id) + { + $sale_info = $this->Sale->get_info($sale_id)->row_array(); + $this->sale_lib->copy_entire_sale($sale_id); + $data['cart']=$this->sale_lib->get_cart(); + $data['payments']=$this->sale_lib->get_payments(); + $data['subtotal']=$this->sale_lib->get_subtotal(); + $data['taxes']=$this->sale_lib->get_taxes(); + $data['total']=$this->sale_lib->get_total(); + $data['receipt_title']=$this->lang->line('sales_receipt'); + $data['transaction_time']= date('m/d/Y h:i:s a', strtotime($sale_info['sale_time'])); + $customer_id=$this->sale_lib->get_customer(); + $emp_info=$this->Employee->get_info($sale_info['employee_id']); + $data['payment_type']=$sale_info['payment_type']; + $data['amount_change']=to_currency($this->sale_lib->get_amount_due() * -1); + $data['employee']=$emp_info->first_name.' '.$emp_info->last_name; + + if($customer_id!=-1) + { + $cust_info=$this->Customer->get_info($customer_id); + $data['customer']=$cust_info->first_name.' '.$cust_info->last_name; + } + $data['sale_id']='POS '.$sale_id; + $this->load->view("sales/receipt",$data); + $this->sale_lib->clear_all(); + + } + + function edit($sale_id) + { + $data = array(); + + $data['customers'] = array('' => 'No Customer'); + foreach ($this->Customer->get_all()->result() as $customer) + { + $data['customers'][$customer->person_id] = $customer->first_name . ' '. $customer->last_name; + } + + $data['employees'] = array(); + foreach ($this->Employee->get_all()->result() as $employee) + { + $data['employees'][$employee->person_id] = $employee->first_name . ' '. $employee->last_name; + } + + $data['sale_info'] = $this->Sale->get_info($sale_id)->row_array(); + + + $this->load->view('sales/edit', $data); + } + + function delete($sale_id) + { + $data = array(); + + if ($this->Sale->delete($sale_id)) + { + $data['success'] = true; + } + else + { + $data['success'] = false; + } + + $this->load->view('sales/delete', $data); + + } + + function save($sale_id) + { + $sale_data = array( + 'sale_time' => date('Y-m-d', strtotime($this->input->post('date'))), + 'customer_id' => $this->input->post('customer_id') ? $this->input->post('customer_id') : null, + 'employee_id' => $this->input->post('employee_id'), + 'comment' => $this->input->post('comment') + ); + + if ($this->Sale->update($sale_data, $sale_id)) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('sales_successfully_updated'))); + } + else + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('sales_unsuccessfully_updated'))); + } + } + + function _payments_cover_total() + { + $total_payments = 0; + + foreach($this->sale_lib->get_payments() as $payment) + { + $total_payments += $payment['payment_amount']; + } + + /* Changed the conditional to account for floating point rounding */ + if ( ( $this->sale_lib->get_mode() == 'sale' ) && ( ( to_currency_no_money( $this->sale_lib->get_total() ) - $total_payments ) > 1e-6 ) ) + { + return false; + } + + return true; + } + + function _reload($data=array()) + { + $person_info = $this->Employee->get_logged_in_employee_info(); + $data['cart']=$this->sale_lib->get_cart(); + $data['modes']=array('sale'=>$this->lang->line('sales_sale'),'return'=>$this->lang->line('sales_return')); + $data['mode']=$this->sale_lib->get_mode(); + $data['subtotal']=$this->sale_lib->get_subtotal(); + $data['taxes']=$this->sale_lib->get_taxes(); + $data['total']=$this->sale_lib->get_total(); + $data['items_module_allowed'] = $this->Employee->has_permission('items', $person_info->person_id); + $data['comment'] = $this->sale_lib->get_comment(); + $data['email_receipt'] = $this->sale_lib->get_email_receipt(); + $data['payments_total']=$this->sale_lib->get_payments_total(); + $data['amount_due']=$this->sale_lib->get_amount_due(); + $data['payments']=$this->sale_lib->get_payments(); + $data['payment_options']=array( + $this->lang->line('sales_cash') => $this->lang->line('sales_cash'), + $this->lang->line('sales_check') => $this->lang->line('sales_check'), + $this->lang->line('sales_giftcard') => $this->lang->line('sales_giftcard'), + $this->lang->line('sales_debit') => $this->lang->line('sales_debit'), + $this->lang->line('sales_credit') => $this->lang->line('sales_credit') + ); + + $customer_id=$this->sale_lib->get_customer(); + if($customer_id!=-1) + { + $info=$this->Customer->get_info($customer_id); + $data['customer']=$info->first_name.' '.$info->last_name; + $data['customer_email']=$info->email; + } + $data['payments_cover_total'] = $this->_payments_cover_total(); + $this->load->view("sales/register",$data); + } + + function cancel_sale() + { + $this->sale_lib->clear_all(); + $this->_reload(); + + } + + function suspend() + { + $data['cart']=$this->sale_lib->get_cart(); + $data['subtotal']=$this->sale_lib->get_subtotal(); + $data['taxes']=$this->sale_lib->get_taxes(); + $data['total']=$this->sale_lib->get_total(); + $data['receipt_title']=$this->lang->line('sales_receipt'); + $data['transaction_time']= date('m/d/Y h:i:s a'); + $customer_id=$this->sale_lib->get_customer(); + $employee_id=$this->Employee->get_logged_in_employee_info()->person_id; + $comment = $this->input->post('comment'); + $emp_info=$this->Employee->get_info($employee_id); + $payment_type = $this->input->post('payment_type'); + $data['payment_type']=$this->input->post('payment_type'); + //Alain Multiple payments + $data['payments']=$this->sale_lib->get_payments(); + $data['amount_change']=to_currency($this->sale_lib->get_amount_due() * -1); + $data['employee']=$emp_info->first_name.' '.$emp_info->last_name; + + if($customer_id!=-1) + { + $cust_info=$this->Customer->get_info($customer_id); + $data['customer']=$cust_info->first_name.' '.$cust_info->last_name; + } + + $total_payments = 0; + + foreach($data['payments'] as $payment) + { + $total_payments += $payment['payment_amount']; + } + + //SAVE sale to database + $data['sale_id']='POS '.$this->Sale_suspended->save($data['cart'], $customer_id,$employee_id,$comment,$data['payments']); + if ($data['sale_id'] == 'POS -1') + { + $data['error_message'] = $this->lang->line('sales_transaction_failed'); + } + $this->sale_lib->clear_all(); + $this->_reload(array('success' => $this->lang->line('sales_successfully_suspended_sale'))); + } + + function suspended() + { + $data = array(); + $data['suspended_sales'] = $this->Sale_suspended->get_all()->result_array(); + $this->load->view('sales/suspended', $data); + } + + function unsuspend() + { + $sale_id = $this->input->post('suspended_sale_id'); + $this->sale_lib->clear_all(); + $this->sale_lib->copy_entire_suspended_sale($sale_id); + $this->Sale_suspended->delete($sale_id); + $this->_reload(); + } +} +?> \ No newline at end of file diff --git a/application/controllers/secure_area.php b/application/controllers/secure_area.php new file mode 100644 index 000000000..c6daac17c --- /dev/null +++ b/application/controllers/secure_area.php @@ -0,0 +1,29 @@ +load->model('Employee'); + if(!$this->Employee->is_logged_in()) + { + redirect('login'); + } + + if(!$this->Employee->has_permission($module_id,$this->Employee->get_logged_in_employee_info()->person_id)) + { + redirect('no_access/'.$module_id); + } + + //load up global data + $logged_in_employee_info=$this->Employee->get_logged_in_employee_info(); + $data['allowed_modules']=$this->Module->get_allowed_modules($logged_in_employee_info->person_id); + $data['user_info']=$logged_in_employee_info; + $this->load->vars($data); + } +} +?> \ No newline at end of file diff --git a/application/controllers/suppliers.php b/application/controllers/suppliers.php new file mode 100644 index 000000000..d23e27bac --- /dev/null +++ b/application/controllers/suppliers.php @@ -0,0 +1,131 @@ +Supplier->count_all(); + $config['per_page'] = '20'; + $config['uri_segment'] = 3; + $this->pagination->initialize($config); + + $data['controller_name']=strtolower(get_class()); + $data['form_width']=$this->get_form_width(); + $data['manage_table']=get_supplier_manage_table( $this->Supplier->get_all( $config['per_page'], $this->uri->segment( $config['uri_segment'] ) ), $this ); + $this->load->view('suppliers/manage',$data); + } + + /* + Returns supplier table data rows. This will be called with AJAX. + */ + function search() + { + $search=$this->input->post('search'); + $data_rows=get_supplier_manage_table_data_rows($this->Supplier->search($search),$this); + echo $data_rows; + } + + /* + Gives search suggestions based on what is being searched for + */ + function suggest() + { + $suggestions = $this->Supplier->get_search_suggestions($this->input->post('q'),$this->input->post('limit')); + echo implode("\n",$suggestions); + } + + /* + Loads the supplier edit form + */ + function view($supplier_id=-1) + { + $data['person_info']=$this->Supplier->get_info($supplier_id); + $this->load->view("suppliers/form",$data); + } + + /* + Inserts/updates a supplier + */ + function save($supplier_id=-1) + { + $person_data = array( + 'first_name'=>$this->input->post('first_name'), + 'last_name'=>$this->input->post('last_name'), + 'email'=>$this->input->post('email'), + 'phone_number'=>$this->input->post('phone_number'), + 'address_1'=>$this->input->post('address_1'), + 'address_2'=>$this->input->post('address_2'), + 'city'=>$this->input->post('city'), + 'state'=>$this->input->post('state'), + 'zip'=>$this->input->post('zip'), + 'country'=>$this->input->post('country'), + 'comments'=>$this->input->post('comments') + ); + $supplier_data=array( + 'company_name'=>$this->input->post('company_name'), + 'account_number'=>$this->input->post('account_number')=='' ? null:$this->input->post('account_number'), + ); + if($this->Supplier->save($person_data,$supplier_data,$supplier_id)) + { + //New supplier + if($supplier_id==-1) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('suppliers_successful_adding').' '. + $supplier_data['company_name'],'person_id'=>$supplier_data['person_id'])); + } + else //previous supplier + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('suppliers_successful_updating').' '. + $supplier_data['company_name'],'person_id'=>$supplier_id)); + } + } + else//failure + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('suppliers_error_adding_updating').' '. + $supplier_data['company_name'],'person_id'=>-1)); + } + } + + /* + This deletes suppliers from the suppliers table + */ + function delete() + { + $suppliers_to_delete=$this->input->post('ids'); + + if($this->Supplier->delete_list($suppliers_to_delete)) + { + echo json_encode(array('success'=>true,'message'=>$this->lang->line('suppliers_successful_deleted').' '. + count($suppliers_to_delete).' '.$this->lang->line('suppliers_one_or_multiple'))); + } + else + { + echo json_encode(array('success'=>false,'message'=>$this->lang->line('suppliers_cannot_be_deleted'))); + } + } + + /* + Gets one row for a supplier manage table. This is called using AJAX to update one row. + */ + function get_row() + { + $person_id = $this->input->post('row_id'); + $data_row=get_supplier_data_row($this->Supplier->get_info($person_id),$this); + echo $data_row; + } + + /* + get the width for the add/edit form + */ + function get_form_width() + { + return 360; + } +} +?> \ No newline at end of file diff --git a/application/core/index.html b/application/core/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/core/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/errors/error_404.php b/application/errors/error_404.php new file mode 100644 index 000000000..792726a67 --- /dev/null +++ b/application/errors/error_404.php @@ -0,0 +1,62 @@ + + + +404 Page Not Found + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/errors/error_db.php b/application/errors/error_db.php new file mode 100644 index 000000000..b396cda9f --- /dev/null +++ b/application/errors/error_db.php @@ -0,0 +1,62 @@ + + + +Database Error + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/errors/error_general.php b/application/errors/error_general.php new file mode 100644 index 000000000..fd63ce2c5 --- /dev/null +++ b/application/errors/error_general.php @@ -0,0 +1,62 @@ + + + +Error + + + +
+

+ +
+ + \ No newline at end of file diff --git a/application/errors/error_php.php b/application/errors/error_php.php new file mode 100644 index 000000000..f085c2037 --- /dev/null +++ b/application/errors/error_php.php @@ -0,0 +1,10 @@ +
+ +

A PHP Error was encountered

+ +

Severity:

+

Message:

+

Filename:

+

Line Number:

+ +
\ No newline at end of file diff --git a/application/errors/index.html b/application/errors/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/errors/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/helpers/currency_helper.php b/application/helpers/currency_helper.php new file mode 100644 index 000000000..744c854ef --- /dev/null +++ b/application/helpers/currency_helper.php @@ -0,0 +1,28 @@ +config->item('currency_symbol') ? $CI->config->item('currency_symbol') : '$'; + if($number >= 0) + { + if($CI->config->item('currency_side') !== 'currency_side') + return $currency_symbol.number_format($number, 2, '.', ''); + else + return number_format($number, 2, '.', '').$currency_symbol; + } + else + { + if($CI->config->item('currency_side') !== 'currency_side') + return '-'.$currency_symbol.number_format(abs($number), 2, '.', ''); + else + return '-'.number_format(abs($number), 2, '.', '').$currency_symbol; + } +} +/** END MODIFIED **/ + +function to_currency_no_money($number) +{ + return number_format($number, 2, '.', ''); +} +?> \ No newline at end of file diff --git a/application/helpers/index.html b/application/helpers/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/helpers/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/helpers/report_helper.php b/application/helpers/report_helper.php new file mode 100644 index 000000000..2b380e316 --- /dev/null +++ b/application/helpers/report_helper.php @@ -0,0 +1,87 @@ +load->language('reports'); + $today = date('Y-m-d'); + $yesterday = date('Y-m-d', mktime(0,0,0,date("m"),date("d")-1,date("Y"))); + $six_days_ago = date('Y-m-d', mktime(0,0,0,date("m"),date("d")-6,date("Y"))); + $start_of_this_month = date('Y-m-d', mktime(0,0,0,date("m"),1,date("Y"))); + $end_of_this_month = date('Y-m-d',strtotime('-1 second',strtotime('+1 month',strtotime(date('m').'/01/'.date('Y').' 00:00:00')))); + $start_of_last_month = date('Y-m-d', mktime(0,0,0,date("m")-1,1,date("Y"))); + $end_of_last_month = date('Y-m-d',strtotime('-1 second',strtotime('+1 month',strtotime((date('m') - 1).'/01/'.date('Y').' 00:00:00')))); + $start_of_this_year = date('Y-m-d', mktime(0,0,0,1,1,date("Y"))); + $end_of_this_year = date('Y-m-d', mktime(0,0,0,12,31,date("Y"))); + $start_of_last_year = date('Y-m-d', mktime(0,0,0,1,1,date("Y")-1)); + $end_of_last_year = date('Y-m-d', mktime(0,0,0,12,31,date("Y")-1)); + $start_of_time = date('Y-m-d', 0); + + return array( + $today. '/' . $today => $CI->lang->line('reports_today'), + $yesterday. '/' . $yesterday => $CI->lang->line('reports_yesterday'), + $six_days_ago. '/' . $today => $CI->lang->line('reports_last_7'), + $start_of_this_month . '/' . $end_of_this_month => $CI->lang->line('reports_this_month'), + $start_of_last_month . '/' . $end_of_last_month => $CI->lang->line('reports_last_month'), + $start_of_this_year . '/' . $end_of_this_year => $CI->lang->line('reports_this_year'), + $start_of_last_year . '/' . $end_of_last_year => $CI->lang->line('reports_last_year'), + $start_of_time . '/' . $today => $CI->lang->line('reports_all_time'), + ); +} + +function get_months() +{ + $months = array(); + for($k=1;$k<=12;$k++) + { + $cur_month = mktime(0, 0, 0, $k, 1, 2000); + $months[date("m", $cur_month)] = date("M",$cur_month); + } + + return $months; +} + +function get_days() +{ + $days = array(); + + for($k=1;$k<=31;$k++) + { + $cur_day = mktime(0, 0, 0, 1, $k, 2000); + $days[date('d',$cur_day)] = date('j',$cur_day); + } + + return $days; +} + +function get_years() +{ + $years = array(); + for($k=0;$k<10;$k++) + { + $years[date("Y")-$k] = date("Y")-$k; + } + + return $years; +} + +function get_random_colors($how_many) +{ + $colors = array(); + + for($k=0;$k<$how_many;$k++) + { + $colors[] = '#'.random_color(); + } + + return $colors; +} + +function random_color() +{ + mt_srand((double)microtime()*1000000); + $c = ''; + while(strlen($c)<6){ + $c .= sprintf("%02X", mt_rand(0, 255)); + } + return $c; +} \ No newline at end of file diff --git a/application/helpers/sale_helper.php b/application/helpers/sale_helper.php new file mode 100644 index 000000000..e69de29bb diff --git a/application/helpers/table_helper.php b/application/helpers/table_helper.php new file mode 100644 index 000000000..9f5927a11 --- /dev/null +++ b/application/helpers/table_helper.php @@ -0,0 +1,350 @@ +'; + + $headers = array('', + $CI->lang->line('common_last_name'), + $CI->lang->line('common_first_name'), + $CI->lang->line('common_email'), + $CI->lang->line('common_phone_number'), + ' '); + + $table.=''; + foreach($headers as $header) + { + $table.="$header"; + } + $table.=''; + $table.=get_people_manage_table_data_rows($people,$controller); + $table.=''; + return $table; +} + +/* +Gets the html data rows for the people. +*/ +function get_people_manage_table_data_rows($people,$controller) +{ + $CI =& get_instance(); + $table_data_rows=''; + + foreach($people->result() as $person) + { + $table_data_rows.=get_person_data_row($person,$controller); + } + + if($people->num_rows()==0) + { + $table_data_rows.="
".$CI->lang->line('common_no_persons_to_display')."
"; + } + + return $table_data_rows; +} + +function get_person_data_row($person,$controller) +{ + $CI =& get_instance(); + $controller_name=strtolower(get_class($CI)); + $width = $controller->get_form_width(); + + $table_data_row=''; + $table_data_row.=""; + $table_data_row.=''.character_limiter($person->last_name,13).''; + $table_data_row.=''.character_limiter($person->first_name,13).''; + $table_data_row.=''.mailto($person->email,character_limiter($person->email,22)).''; + $table_data_row.=''.character_limiter($person->phone_number,13).''; + $table_data_row.=''.anchor($controller_name."/view/$person->person_id/width:$width", $CI->lang->line('common_edit'),array('class'=>'thickbox','title'=>$CI->lang->line($controller_name.'_update'))).''; + $table_data_row.=''; + + return $table_data_row; +} + +/* +Gets the html table to manage suppliers. +*/ +function get_supplier_manage_table($suppliers,$controller) +{ + $CI =& get_instance(); + $table=''; + + $headers = array('', + $CI->lang->line('suppliers_company_name'), + $CI->lang->line('common_last_name'), + $CI->lang->line('common_first_name'), + $CI->lang->line('common_email'), + $CI->lang->line('common_phone_number'), + ' '); + + $table.=''; + foreach($headers as $header) + { + $table.=""; + } + $table.=''; + $table.=get_supplier_manage_table_data_rows($suppliers,$controller); + $table.='
$header
'; + return $table; +} + +/* +Gets the html data rows for the supplier. +*/ +function get_supplier_manage_table_data_rows($suppliers,$controller) +{ + $CI =& get_instance(); + $table_data_rows=''; + + foreach($suppliers->result() as $supplier) + { + $table_data_rows.=get_supplier_data_row($supplier,$controller); + } + + if($suppliers->num_rows()==0) + { + $table_data_rows.="
".$CI->lang->line('common_no_persons_to_display')."
"; + } + + return $table_data_rows; +} + +function get_supplier_data_row($supplier,$controller) +{ + $CI =& get_instance(); + $controller_name=strtolower(get_class($CI)); + $width = $controller->get_form_width(); + + $table_data_row=''; + $table_data_row.=""; + $table_data_row.=''.character_limiter($supplier->company_name,13).''; + $table_data_row.=''.character_limiter($supplier->last_name,13).''; + $table_data_row.=''.character_limiter($supplier->first_name,13).''; + $table_data_row.=''.mailto($supplier->email,character_limiter($supplier->email,22)).''; + $table_data_row.=''.character_limiter($supplier->phone_number,13).''; + $table_data_row.=''.anchor($controller_name."/view/$supplier->person_id/width:$width", $CI->lang->line('common_edit'),array('class'=>'thickbox','title'=>$CI->lang->line($controller_name.'_update'))).''; + $table_data_row.=''; + + return $table_data_row; +} + +/* +Gets the html table to manage items. +*/ +function get_items_manage_table($items,$controller) +{ + $CI =& get_instance(); + $table=''; + + $headers = array('', + $CI->lang->line('items_item_number'), + $CI->lang->line('items_name'), + $CI->lang->line('items_category'), + $CI->lang->line('items_cost_price'), + $CI->lang->line('items_unit_price'), + $CI->lang->line('items_tax_percents'), + $CI->lang->line('items_quantity'), + ' ', + $CI->lang->line('items_inventory') + ); + + $table.=''; + foreach($headers as $header) + { + $table.=""; + } + $table.=''; + $table.=get_items_manage_table_data_rows($items,$controller); + $table.='
$header
'; + return $table; +} + +/* +Gets the html data rows for the items. +*/ +function get_items_manage_table_data_rows($items,$controller) +{ + $CI =& get_instance(); + $table_data_rows=''; + + foreach($items->result() as $item) + { + $table_data_rows.=get_item_data_row($item,$controller); + } + + if($items->num_rows()==0) + { + $table_data_rows.="
".$CI->lang->line('items_no_items_to_display')."
"; + } + + return $table_data_rows; +} + +function get_item_data_row($item,$controller) +{ + $CI =& get_instance(); + $item_tax_info=$CI->Item_taxes->get_info($item->item_id); + $tax_percents = ''; + foreach($item_tax_info as $tax_info) + { + $tax_percents.=$tax_info['percent']. '%, '; + } + $tax_percents=substr($tax_percents, 0, -2); + $controller_name=strtolower(get_class($CI)); + $width = $controller->get_form_width(); + + $table_data_row=''; + $table_data_row.=""; + $table_data_row.=''.$item->item_number.''; + $table_data_row.=''.$item->name.''; + $table_data_row.=''.$item->category.''; + $table_data_row.=''.to_currency($item->cost_price).''; + $table_data_row.=''.to_currency($item->unit_price).''; + $table_data_row.=''.$tax_percents.''; + $table_data_row.=''.$item->quantity.''; + $table_data_row.=''.anchor($controller_name."/view/$item->item_id/width:$width", $CI->lang->line('common_edit'),array('class'=>'thickbox','title'=>$CI->lang->line($controller_name.'_update'))).''; + + //Ramel Inventory Tracking + $table_data_row.=''.anchor($controller_name."/inventory/$item->item_id/width:$width", $CI->lang->line('common_inv'),array('class'=>'thickbox','title'=>$CI->lang->line($controller_name.'_count')))./*'';//inventory count + $table_data_row.=''*/'    '.anchor($controller_name."/count_details/$item->item_id/width:$width", $CI->lang->line('common_det'),array('class'=>'thickbox','title'=>$CI->lang->line($controller_name.'_details_count'))).'';//inventory details + + $table_data_row.=''; + return $table_data_row; +} + +/* +Gets the html table to manage giftcards. +*/ +function get_giftcards_manage_table( $giftcards, $controller ) +{ + $CI =& get_instance(); + + $table=''; + + $headers = array('', + $CI->lang->line('common_last_name'), + $CI->lang->line('common_first_name'), + $CI->lang->line('giftcards_giftcard_number'), + $CI->lang->line('giftcards_card_value'), + ' ', + ); + + $table.=''; + foreach($headers as $header) + { + $table.=""; + } + $table.=''; + $table.=get_giftcards_manage_table_data_rows( $giftcards, $controller ); + $table.='
$header
'; + return $table; +} + +/* +Gets the html data rows for the giftcard. +*/ +function get_giftcards_manage_table_data_rows( $giftcards, $controller ) +{ + $CI =& get_instance(); + $table_data_rows=''; + + foreach($giftcards->result() as $giftcard) + { + $table_data_rows.=get_giftcard_data_row( $giftcard, $controller ); + } + + if($giftcards->num_rows()==0) + { + $table_data_rows.="
".$CI->lang->line('giftcards_no_giftcards_to_display')."
"; + } + + return $table_data_rows; +} + +/** GARRISON MODIFIED 4/25/2013 **/ +function get_giftcard_data_row($giftcard,$controller) +{ + $CI =& get_instance(); + $controller_name=strtolower(get_class($CI)); + $width = $controller->get_form_width(); + + $table_data_row=''; + $table_data_row.=""; + $table_data_row.=''.$giftcard->last_name.''; + $table_data_row.=''.$giftcard->first_name.''; + $table_data_row.=''.$giftcard->giftcard_number.''; + $table_data_row.=''.to_currency($giftcard->value).''; + $table_data_row.=''.anchor($controller_name."/view/$giftcard->giftcard_id/width:$width", $CI->lang->line('common_edit'),array('class'=>'thickbox','title'=>$CI->lang->line($controller_name.'_update'))).''; + + $table_data_row.=''; + return $table_data_row; +} +/** END GARRISON MODIFIED **/ + +/* +Gets the html table to manage item kits. +*/ +function get_item_kits_manage_table( $item_kits, $controller ) +{ + $CI =& get_instance(); + + $table=''; + + $headers = array('', + $CI->lang->line('item_kits_name'), + $CI->lang->line('item_kits_description'), + ' ', + ); + + $table.=''; + foreach($headers as $header) + { + $table.=""; + } + $table.=''; + $table.=get_item_kits_manage_table_data_rows( $item_kits, $controller ); + $table.='
$header
'; + return $table; +} + +/* +Gets the html data rows for the item kits. +*/ +function get_item_kits_manage_table_data_rows( $item_kits, $controller ) +{ + $CI =& get_instance(); + $table_data_rows=''; + + foreach($item_kits->result() as $item_kit) + { + $table_data_rows.=get_item_kit_data_row( $item_kit, $controller ); + } + + if($item_kits->num_rows()==0) + { + $table_data_rows.="
".$CI->lang->line('item_kits_no_item_kits_to_display')."
"; + } + + return $table_data_rows; +} + +function get_item_kit_data_row($item_kit,$controller) +{ + $CI =& get_instance(); + $controller_name=strtolower(get_class($CI)); + $width = $controller->get_form_width(); + + $table_data_row=''; + $table_data_row.=""; + $table_data_row.=''.$item_kit->name.''; + $table_data_row.=''.character_limiter($item_kit->description, 25).''; + $table_data_row.=''.anchor($controller_name."/view/$item_kit->item_kit_id/width:$width", $CI->lang->line('common_edit'),array('class'=>'thickbox','title'=>$CI->lang->line($controller_name.'_update'))).''; + + $table_data_row.=''; + return $table_data_row; +} + +?> \ No newline at end of file diff --git a/application/hooks/index.html b/application/hooks/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/hooks/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/hooks/load_config.php b/application/hooks/load_config.php new file mode 100644 index 000000000..7f24ea02c --- /dev/null +++ b/application/hooks/load_config.php @@ -0,0 +1,32 @@ +Appconfig->get_all()->result() as $app_config ) + { + $CI->config->set_item( $app_config->key, $app_config->value ); + } + + if ( $CI->config->item( 'language' ) ) + { + $CI->config->set_item( 'language', $CI->config->item( 'language' ) ); + $loaded = $CI->lang->is_loaded; + $CI->lang->is_loaded = array(); + + foreach($loaded as $file) + { + $CI->lang->load( str_replace( '_lang.php', '', $file ) ); + } + } + + if ( $CI->config->item( 'timezone' ) ) + { + date_default_timezone_set( $CI->config->item( 'timezone' ) ); + } + else + { + date_default_timezone_set( 'America/New_York' ); + } +} +?> \ No newline at end of file diff --git a/application/index.html b/application/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/language/Azerbaijan/common_lang.php b/application/language/Azerbaijan/common_lang.php new file mode 100644 index 000000000..3ddf42837 --- /dev/null +++ b/application/language/Azerbaijan/common_lang.php @@ -0,0 +1,41 @@ + \ No newline at end of file diff --git a/application/language/Azerbaijan/config_lang.php b/application/language/Azerbaijan/config_lang.php new file mode 100644 index 000000000..6c7686880 --- /dev/null +++ b/application/language/Azerbaijan/config_lang.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/application/language/Azerbaijan/customers_lang.php b/application/language/Azerbaijan/customers_lang.php new file mode 100644 index 000000000..d6978d458 --- /dev/null +++ b/application/language/Azerbaijan/customers_lang.php @@ -0,0 +1,16 @@ + diff --git a/application/language/Azerbaijan/employees_lang.php b/application/language/Azerbaijan/employees_lang.php new file mode 100644 index 000000000..a30c32b99 --- /dev/null +++ b/application/language/Azerbaijan/employees_lang.php @@ -0,0 +1,27 @@ + diff --git a/application/language/Azerbaijan/error_lang.php b/application/language/Azerbaijan/error_lang.php new file mode 100644 index 000000000..cfcd2f0c9 --- /dev/null +++ b/application/language/Azerbaijan/error_lang.php @@ -0,0 +1,4 @@ + diff --git a/application/language/Azerbaijan/giftcards_lang.php b/application/language/Azerbaijan/giftcards_lang.php new file mode 100644 index 000000000..edd7fc95b --- /dev/null +++ b/application/language/Azerbaijan/giftcards_lang.php @@ -0,0 +1,70 @@ + diff --git a/application/language/Azerbaijan/index.html b/application/language/Azerbaijan/index.html new file mode 100644 index 000000000..7f684dff4 --- /dev/null +++ b/application/language/Azerbaijan/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/language/Azerbaijan/item_kits_lang.php b/application/language/Azerbaijan/item_kits_lang.php new file mode 100644 index 000000000..601fae62d --- /dev/null +++ b/application/language/Azerbaijan/item_kits_lang.php @@ -0,0 +1,20 @@ + diff --git a/application/language/Azerbaijan/items_lang.php b/application/language/Azerbaijan/items_lang.php new file mode 100644 index 000000000..c0ed72e0a --- /dev/null +++ b/application/language/Azerbaijan/items_lang.php @@ -0,0 +1,80 @@ + diff --git a/application/language/Azerbaijan/login_lang.php b/application/language/Azerbaijan/login_lang.php new file mode 100644 index 000000000..a5aa1bb26 --- /dev/null +++ b/application/language/Azerbaijan/login_lang.php @@ -0,0 +1,8 @@ + diff --git a/application/language/Azerbaijan/module_lang.php b/application/language/Azerbaijan/module_lang.php new file mode 100644 index 000000000..9e95a2d81 --- /dev/null +++ b/application/language/Azerbaijan/module_lang.php @@ -0,0 +1,34 @@ + diff --git a/application/language/Azerbaijan/receivings_lang.php b/application/language/Azerbaijan/receivings_lang.php new file mode 100644 index 000000000..9f73af7b6 --- /dev/null +++ b/application/language/Azerbaijan/receivings_lang.php @@ -0,0 +1,26 @@ + diff --git a/application/language/Azerbaijan/reports_lang.php b/application/language/Azerbaijan/reports_lang.php new file mode 100644 index 000000000..12e1f3598 --- /dev/null +++ b/application/language/Azerbaijan/reports_lang.php @@ -0,0 +1,87 @@ + diff --git a/application/language/Azerbaijan/sales_lang.php b/application/language/Azerbaijan/sales_lang.php new file mode 100644 index 000000000..836446372 --- /dev/null +++ b/application/language/Azerbaijan/sales_lang.php @@ -0,0 +1,79 @@ + \ No newline at end of file diff --git a/application/language/Azerbaijan/suppliers_lang.php b/application/language/Azerbaijan/suppliers_lang.php new file mode 100644 index 000000000..fdcb86fbb --- /dev/null +++ b/application/language/Azerbaijan/suppliers_lang.php @@ -0,0 +1,17 @@ + diff --git a/application/language/BahasaIndonesia/common_lang.php b/application/language/BahasaIndonesia/common_lang.php new file mode 100644 index 000000000..53e4e9c6d --- /dev/null +++ b/application/language/BahasaIndonesia/common_lang.php @@ -0,0 +1,41 @@ + diff --git a/application/language/BahasaIndonesia/config_lang.php b/application/language/BahasaIndonesia/config_lang.php new file mode 100644 index 000000000..b28d95ff8 --- /dev/null +++ b/application/language/BahasaIndonesia/config_lang.php @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/application/language/BahasaIndonesia/customers_lang.php b/application/language/BahasaIndonesia/customers_lang.php new file mode 100644 index 000000000..4ce03c357 --- /dev/null +++ b/application/language/BahasaIndonesia/customers_lang.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/application/language/BahasaIndonesia/employees_lang.php b/application/language/BahasaIndonesia/employees_lang.php new file mode 100644 index 000000000..5f2fc811e --- /dev/null +++ b/application/language/BahasaIndonesia/employees_lang.php @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/application/language/BahasaIndonesia/error_lang.php b/application/language/BahasaIndonesia/error_lang.php new file mode 100644 index 000000000..5fb55ba97 --- /dev/null +++ b/application/language/BahasaIndonesia/error_lang.php @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/application/language/BahasaIndonesia/giftcards_lang.php b/application/language/BahasaIndonesia/giftcards_lang.php new file mode 100644 index 000000000..c6ba2ebe1 --- /dev/null +++ b/application/language/BahasaIndonesia/giftcards_lang.php @@ -0,0 +1,71 @@ + \ No newline at end of file diff --git a/application/language/BahasaIndonesia/index.html b/application/language/BahasaIndonesia/index.html new file mode 100644 index 000000000..04879110a --- /dev/null +++ b/application/language/BahasaIndonesia/index.html @@ -0,0 +1,10 @@ + + + 403 Dilarang + + + +

Akses direktori dilarang.

+ + + \ No newline at end of file diff --git a/application/language/BahasaIndonesia/item_kits_lang.php b/application/language/BahasaIndonesia/item_kits_lang.php new file mode 100644 index 000000000..ebd06926b --- /dev/null +++ b/application/language/BahasaIndonesia/item_kits_lang.php @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/application/language/BahasaIndonesia/items_lang.php b/application/language/BahasaIndonesia/items_lang.php new file mode 100644 index 000000000..2cc620e96 --- /dev/null +++ b/application/language/BahasaIndonesia/items_lang.php @@ -0,0 +1,78 @@ + diff --git a/application/language/BahasaIndonesia/login_lang.php b/application/language/BahasaIndonesia/login_lang.php new file mode 100644 index 000000000..7b0150f00 --- /dev/null +++ b/application/language/BahasaIndonesia/login_lang.php @@ -0,0 +1,8 @@ + diff --git a/application/language/BahasaIndonesia/module_lang.php b/application/language/BahasaIndonesia/module_lang.php new file mode 100644 index 000000000..b45605a1f --- /dev/null +++ b/application/language/BahasaIndonesia/module_lang.php @@ -0,0 +1,33 @@ + diff --git a/application/language/BahasaIndonesia/receivings_lang.php b/application/language/BahasaIndonesia/receivings_lang.php new file mode 100644 index 000000000..54c908e04 --- /dev/null +++ b/application/language/BahasaIndonesia/receivings_lang.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/application/language/BahasaIndonesia/reports_lang.php b/application/language/BahasaIndonesia/reports_lang.php new file mode 100644 index 000000000..a32b1bd22 --- /dev/null +++ b/application/language/BahasaIndonesia/reports_lang.php @@ -0,0 +1,85 @@ + diff --git a/application/language/BahasaIndonesia/sales_lang.php b/application/language/BahasaIndonesia/sales_lang.php new file mode 100644 index 000000000..089c3ef23 --- /dev/null +++ b/application/language/BahasaIndonesia/sales_lang.php @@ -0,0 +1,78 @@ + diff --git a/application/language/BahasaIndonesia/suppliers_lang.php b/application/language/BahasaIndonesia/suppliers_lang.php new file mode 100644 index 000000000..54e373e94 --- /dev/null +++ b/application/language/BahasaIndonesia/suppliers_lang.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/application/language/Russian/common_lang.php b/application/language/Russian/common_lang.php new file mode 100644 index 000000000..c501ddf2e --- /dev/null +++ b/application/language/Russian/common_lang.php @@ -0,0 +1,41 @@ + \ No newline at end of file diff --git a/application/language/Russian/config_lang.php b/application/language/Russian/config_lang.php new file mode 100644 index 000000000..05f6082ee --- /dev/null +++ b/application/language/Russian/config_lang.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/application/language/Russian/customers_lang.php b/application/language/Russian/customers_lang.php new file mode 100644 index 000000000..685e72bc1 --- /dev/null +++ b/application/language/Russian/customers_lang.php @@ -0,0 +1,16 @@ + diff --git a/application/language/Russian/employees_lang.php b/application/language/Russian/employees_lang.php new file mode 100644 index 000000000..4de2d6300 --- /dev/null +++ b/application/language/Russian/employees_lang.php @@ -0,0 +1,27 @@ + diff --git a/application/language/Russian/error_lang.php b/application/language/Russian/error_lang.php new file mode 100644 index 000000000..3efc57ae5 --- /dev/null +++ b/application/language/Russian/error_lang.php @@ -0,0 +1,4 @@ + diff --git a/application/language/Russian/giftcards_lang.php b/application/language/Russian/giftcards_lang.php new file mode 100644 index 000000000..8885c5fac --- /dev/null +++ b/application/language/Russian/giftcards_lang.php @@ -0,0 +1,70 @@ + diff --git a/application/language/Russian/index.html b/application/language/Russian/index.html new file mode 100644 index 000000000..7f684dff4 --- /dev/null +++ b/application/language/Russian/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/language/Russian/item_kits_lang.php b/application/language/Russian/item_kits_lang.php new file mode 100644 index 000000000..f7bb918d3 --- /dev/null +++ b/application/language/Russian/item_kits_lang.php @@ -0,0 +1,20 @@ + diff --git a/application/language/Russian/items_lang.php b/application/language/Russian/items_lang.php new file mode 100644 index 000000000..8972dd6fe --- /dev/null +++ b/application/language/Russian/items_lang.php @@ -0,0 +1,80 @@ + diff --git a/application/language/Russian/login_lang.php b/application/language/Russian/login_lang.php new file mode 100644 index 000000000..b0bdae042 --- /dev/null +++ b/application/language/Russian/login_lang.php @@ -0,0 +1,8 @@ + diff --git a/application/language/Russian/module_lang.php b/application/language/Russian/module_lang.php new file mode 100644 index 000000000..c618f6e73 --- /dev/null +++ b/application/language/Russian/module_lang.php @@ -0,0 +1,34 @@ + diff --git a/application/language/Russian/receivings_lang.php b/application/language/Russian/receivings_lang.php new file mode 100644 index 000000000..4753d1ce9 --- /dev/null +++ b/application/language/Russian/receivings_lang.php @@ -0,0 +1,26 @@ + diff --git a/application/language/Russian/reports_lang.php b/application/language/Russian/reports_lang.php new file mode 100644 index 000000000..e47cac200 --- /dev/null +++ b/application/language/Russian/reports_lang.php @@ -0,0 +1,87 @@ + diff --git a/application/language/Russian/sales_lang.php b/application/language/Russian/sales_lang.php new file mode 100644 index 000000000..ff9426671 --- /dev/null +++ b/application/language/Russian/sales_lang.php @@ -0,0 +1,79 @@ + \ No newline at end of file diff --git a/application/language/Russian/suppliers_lang.php b/application/language/Russian/suppliers_lang.php new file mode 100644 index 000000000..2a5fb704d --- /dev/null +++ b/application/language/Russian/suppliers_lang.php @@ -0,0 +1,17 @@ + diff --git a/application/language/Spanish/common_lang.php b/application/language/Spanish/common_lang.php new file mode 100644 index 000000000..474db8325 --- /dev/null +++ b/application/language/Spanish/common_lang.php @@ -0,0 +1,40 @@ + diff --git a/application/language/Spanish/config_lang.php b/application/language/Spanish/config_lang.php new file mode 100644 index 000000000..a39aa873e --- /dev/null +++ b/application/language/Spanish/config_lang.php @@ -0,0 +1,24 @@ + diff --git a/application/language/Spanish/customers_lang.php b/application/language/Spanish/customers_lang.php new file mode 100644 index 000000000..d36370d53 --- /dev/null +++ b/application/language/Spanish/customers_lang.php @@ -0,0 +1,16 @@ + diff --git a/application/language/Spanish/employees_lang.php b/application/language/Spanish/employees_lang.php new file mode 100644 index 000000000..52be3d99c --- /dev/null +++ b/application/language/Spanish/employees_lang.php @@ -0,0 +1,27 @@ + diff --git a/application/language/Spanish/error_lang.php b/application/language/Spanish/error_lang.php new file mode 100644 index 000000000..aef9e8c43 --- /dev/null +++ b/application/language/Spanish/error_lang.php @@ -0,0 +1,4 @@ + diff --git a/application/language/Spanish/giftcards_lang.php b/application/language/Spanish/giftcards_lang.php new file mode 100644 index 000000000..4a358491c --- /dev/null +++ b/application/language/Spanish/giftcards_lang.php @@ -0,0 +1,69 @@ + diff --git a/application/language/Spanish/index.html b/application/language/Spanish/index.html new file mode 100644 index 000000000..d9dd8677a --- /dev/null +++ b/application/language/Spanish/index.html @@ -0,0 +1,10 @@ + + + 403 Prohibido + + + +

El acceso a los directorios está prohibido.

+ + + diff --git a/application/language/Spanish/item_kits_lang.php b/application/language/Spanish/item_kits_lang.php new file mode 100644 index 000000000..2ffd7b807 --- /dev/null +++ b/application/language/Spanish/item_kits_lang.php @@ -0,0 +1,20 @@ + diff --git a/application/language/Spanish/items_lang.php b/application/language/Spanish/items_lang.php new file mode 100644 index 000000000..cc4f39bed --- /dev/null +++ b/application/language/Spanish/items_lang.php @@ -0,0 +1,77 @@ + diff --git a/application/language/Spanish/login_lang.php b/application/language/Spanish/login_lang.php new file mode 100644 index 000000000..8c60ff3a4 --- /dev/null +++ b/application/language/Spanish/login_lang.php @@ -0,0 +1,8 @@ + diff --git a/application/language/Spanish/module_lang.php b/application/language/Spanish/module_lang.php new file mode 100644 index 000000000..d00dc9862 --- /dev/null +++ b/application/language/Spanish/module_lang.php @@ -0,0 +1,33 @@ + diff --git a/application/language/Spanish/receivings_lang.php b/application/language/Spanish/receivings_lang.php new file mode 100644 index 000000000..bd1bb0ccb --- /dev/null +++ b/application/language/Spanish/receivings_lang.php @@ -0,0 +1,26 @@ + diff --git a/application/language/Spanish/reports_lang.php b/application/language/Spanish/reports_lang.php new file mode 100644 index 000000000..94d67239c --- /dev/null +++ b/application/language/Spanish/reports_lang.php @@ -0,0 +1,85 @@ + diff --git a/application/language/Spanish/sales_lang.php b/application/language/Spanish/sales_lang.php new file mode 100644 index 000000000..d1612d701 --- /dev/null +++ b/application/language/Spanish/sales_lang.php @@ -0,0 +1,78 @@ + diff --git a/application/language/Spanish/suppliers_lang.php b/application/language/Spanish/suppliers_lang.php new file mode 100644 index 000000000..f3b6a9c5b --- /dev/null +++ b/application/language/Spanish/suppliers_lang.php @@ -0,0 +1,17 @@ + diff --git a/application/language/english/common_lang.php b/application/language/english/common_lang.php new file mode 100644 index 000000000..3ddf42837 --- /dev/null +++ b/application/language/english/common_lang.php @@ -0,0 +1,41 @@ + \ No newline at end of file diff --git a/application/language/english/config_lang.php b/application/language/english/config_lang.php new file mode 100644 index 000000000..6c7686880 --- /dev/null +++ b/application/language/english/config_lang.php @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/application/language/english/customers_lang.php b/application/language/english/customers_lang.php new file mode 100644 index 000000000..d6978d458 --- /dev/null +++ b/application/language/english/customers_lang.php @@ -0,0 +1,16 @@ + diff --git a/application/language/english/employees_lang.php b/application/language/english/employees_lang.php new file mode 100644 index 000000000..a30c32b99 --- /dev/null +++ b/application/language/english/employees_lang.php @@ -0,0 +1,27 @@ + diff --git a/application/language/english/error_lang.php b/application/language/english/error_lang.php new file mode 100644 index 000000000..cfcd2f0c9 --- /dev/null +++ b/application/language/english/error_lang.php @@ -0,0 +1,4 @@ + diff --git a/application/language/english/giftcards_lang.php b/application/language/english/giftcards_lang.php new file mode 100644 index 000000000..cfd96a74e --- /dev/null +++ b/application/language/english/giftcards_lang.php @@ -0,0 +1,70 @@ + diff --git a/application/language/english/index.html b/application/language/english/index.html new file mode 100644 index 000000000..7f684dff4 --- /dev/null +++ b/application/language/english/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + diff --git a/application/language/english/item_kits_lang.php b/application/language/english/item_kits_lang.php new file mode 100644 index 000000000..601fae62d --- /dev/null +++ b/application/language/english/item_kits_lang.php @@ -0,0 +1,20 @@ + diff --git a/application/language/english/items_lang.php b/application/language/english/items_lang.php new file mode 100644 index 000000000..7535f42bb --- /dev/null +++ b/application/language/english/items_lang.php @@ -0,0 +1,80 @@ + diff --git a/application/language/english/login_lang.php b/application/language/english/login_lang.php new file mode 100644 index 000000000..a5aa1bb26 --- /dev/null +++ b/application/language/english/login_lang.php @@ -0,0 +1,8 @@ + diff --git a/application/language/english/module_lang.php b/application/language/english/module_lang.php new file mode 100644 index 000000000..9e95a2d81 --- /dev/null +++ b/application/language/english/module_lang.php @@ -0,0 +1,34 @@ + diff --git a/application/language/english/receivings_lang.php b/application/language/english/receivings_lang.php new file mode 100644 index 000000000..9f73af7b6 --- /dev/null +++ b/application/language/english/receivings_lang.php @@ -0,0 +1,26 @@ + diff --git a/application/language/english/reports_lang.php b/application/language/english/reports_lang.php new file mode 100644 index 000000000..12e1f3598 --- /dev/null +++ b/application/language/english/reports_lang.php @@ -0,0 +1,87 @@ + diff --git a/application/language/english/sales_lang.php b/application/language/english/sales_lang.php new file mode 100644 index 000000000..836446372 --- /dev/null +++ b/application/language/english/sales_lang.php @@ -0,0 +1,79 @@ + \ No newline at end of file diff --git a/application/language/english/suppliers_lang.php b/application/language/english/suppliers_lang.php new file mode 100644 index 000000000..fdcb86fbb --- /dev/null +++ b/application/language/english/suppliers_lang.php @@ -0,0 +1,17 @@ + diff --git a/application/libraries/MY_Language.php b/application/libraries/MY_Language.php new file mode 100644 index 000000000..a9b69505b --- /dev/null +++ b/application/libraries/MY_Language.php @@ -0,0 +1,26 @@ +config->set_item( 'language', $idiom ); + $loaded = $this->is_loaded; + $this->is_loaded = array(); + + foreach($loaded as $file) + { + $this->load( str_replace( '_lang.php', '', $file ) ); + } + } + } +} + +?> diff --git a/application/libraries/Receiving_lib.php b/application/libraries/Receiving_lib.php new file mode 100644 index 000000000..52716ee4a --- /dev/null +++ b/application/libraries/Receiving_lib.php @@ -0,0 +1,251 @@ +CI =& get_instance(); + } + + function get_cart() + { + if(!$this->CI->session->userdata('cartRecv')) + $this->set_cart(array()); + + return $this->CI->session->userdata('cartRecv'); + } + + function set_cart($cart_data) + { + $this->CI->session->set_userdata('cartRecv',$cart_data); + } + + function get_supplier() + { + if(!$this->CI->session->userdata('supplier')) + $this->set_supplier(-1); + + return $this->CI->session->userdata('supplier'); + } + + function set_supplier($supplier_id) + { + $this->CI->session->set_userdata('supplier',$supplier_id); + } + + function get_mode() + { + if(!$this->CI->session->userdata('recv_mode')) + $this->set_mode('receive'); + + return $this->CI->session->userdata('recv_mode'); + } + + function set_mode($mode) + { + $this->CI->session->set_userdata('recv_mode',$mode); + } + + function add_item($item_id,$quantity=1,$discount=0,$price=null,$description=null,$serialnumber=null) + { + //make sure item exists in database. + if(!$this->CI->Item->exists($item_id)) + { + //try to get item id given an item_number + $item_id = $this->CI->Item->get_item_id($item_id); + + if(!$item_id) + return false; + } + + //Get items in the receiving so far. + $items = $this->get_cart(); + + //We need to loop through all items in the cart. + //If the item is already there, get it's key($updatekey). + //We also need to get the next key that we are going to use in case we need to add the + //item to the list. Since items can be deleted, we can't use a count. we use the highest key + 1. + + $maxkey=0; //Highest key so far + $itemalreadyinsale=FALSE; //We did not find the item yet. + $insertkey=0; //Key to use for new entry. + $updatekey=0; //Key to use to update(quantity) + + foreach ($items as $item) + { + //We primed the loop so maxkey is 0 the first time. + //Also, we have stored the key in the element itself so we can compare. + //There is an array function to get the associated key for an element, but I like it better + //like that! + + if($maxkey <= $item['line']) + { + $maxkey = $item['line']; + } + + if($item['item_id']==$item_id) + { + $itemalreadyinsale=TRUE; + $updatekey=$item['line']; + } + } + + $insertkey=$maxkey+1; + + //array records are identified by $insertkey and item_id is just another field. + $item = array(($insertkey)=> + array( + 'item_id'=>$item_id, + 'line'=>$insertkey, + 'name'=>$this->CI->Item->get_info($item_id)->name, + 'description'=>$description!=null ? $description: $this->CI->Item->get_info($item_id)->description, + 'serialnumber'=>$serialnumber!=null ? $serialnumber: '', + 'allow_alt_description'=>$this->CI->Item->get_info($item_id)->allow_alt_description, + 'is_serialized'=>$this->CI->Item->get_info($item_id)->is_serialized, + 'quantity'=>$quantity, + 'discount'=>$discount, + 'price'=>$price!=null ? $price: $this->CI->Item->get_info($item_id)->cost_price + ) + ); + + //Item already exists + if($itemalreadyinsale) + { + $items[$updatekey]['quantity']+=$quantity; + } + else + { + //add to existing array + $items+=$item; + } + + $this->set_cart($items); + return true; + + } + + function edit_item($line,$description,$serialnumber,$quantity,$discount,$price) + { + $items = $this->get_cart(); + if(isset($items[$line])) + { + $items[$line]['description'] = $description; + $items[$line]['serialnumber'] = $serialnumber; + $items[$line]['quantity'] = $quantity; + $items[$line]['discount'] = $discount; + $items[$line]['price'] = $price; + $this->set_cart($items); + } + + return false; + } + + function is_valid_receipt($receipt_receiving_id) + { + //RECV # + $pieces = explode(' ',$receipt_receiving_id); + + if(count($pieces)==2) + { + return $this->CI->Receiving->exists($pieces[1]); + } + + return false; + } + + function is_valid_item_kit($item_kit_id) + { + //KIT # + $pieces = explode(' ',$item_kit_id); + + if(count($pieces)==2) + { + return $this->CI->Item_kit->exists($pieces[1]); + } + + return false; + } + + function return_entire_receiving($receipt_receiving_id) + { + //POS # + $pieces = explode(' ',$receipt_receiving_id); + $receiving_id = $pieces[1]; + + $this->empty_cart(); + $this->delete_supplier(); + + foreach($this->CI->Receiving->get_receiving_items($receiving_id)->result() as $row) + { + $this->add_item($row->item_id,-$row->quantity_purchased,$row->discount_percent,$row->item_unit_price,$row->description,$row->serialnumber); + } + $this->set_supplier($this->CI->Receiving->get_supplier($receiving_id)->person_id); + } + + function add_item_kit($external_item_kit_id) + { + //KIT # + $pieces = explode(' ',$external_item_kit_id); + $item_kit_id = $pieces[1]; + + foreach ($this->CI->Item_kit_items->get_info($item_kit_id) as $item_kit_item) + { + $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity']); + } + } + + function copy_entire_receiving($receiving_id) + { + $this->empty_cart(); + $this->delete_supplier(); + + foreach($this->CI->Receiving->get_receiving_items($receiving_id)->result() as $row) + { + $this->add_item($row->item_id,$row->quantity_purchased,$row->discount_percent,$row->item_unit_price,$row->description,$row->serialnumber); + } + $this->set_supplier($this->CI->Receiving->get_supplier($receiving_id)->person_id); + + } + + function delete_item($line) + { + $items=$this->get_cart(); + unset($items[$line]); + $this->set_cart($items); + } + + function empty_cart() + { + $this->CI->session->unset_userdata('cartRecv'); + } + + function delete_supplier() + { + $this->CI->session->unset_userdata('supplier'); + } + + function clear_mode() + { + $this->CI->session->unset_userdata('receiving_mode'); + } + + function clear_all() + { + $this->clear_mode(); + $this->empty_cart(); + $this->delete_supplier(); + } + + function get_total() + { + $total = 0; + foreach($this->get_cart() as $item) + { + $total+=($item['price']*$item['quantity']-$item['price']*$item['quantity']*$item['discount']/100); + } + + return $total; + } +} +?> \ No newline at end of file diff --git a/application/libraries/Sale_lib.php b/application/libraries/Sale_lib.php new file mode 100644 index 000000000..f7c75eb44 --- /dev/null +++ b/application/libraries/Sale_lib.php @@ -0,0 +1,498 @@ +CI =& get_instance(); + } + + function get_cart() + { + if(!$this->CI->session->userdata('cart')) + $this->set_cart(array()); + + return $this->CI->session->userdata('cart'); + } + + function set_cart($cart_data) + { + $this->CI->session->set_userdata('cart',$cart_data); + } + + //Alain Multiple Payments + function get_payments() + { + if( !$this->CI->session->userdata( 'payments' ) ) + $this->set_payments( array( ) ); + + return $this->CI->session->userdata('payments'); + } + + //Alain Multiple Payments + function set_payments($payments_data) + { + $this->CI->session->set_userdata('payments',$payments_data); + } + + function get_comment() + { + return $this->CI->session->userdata('comment'); + } + + function set_comment($comment) + { + $this->CI->session->set_userdata('comment', $comment); + } + + function clear_comment() + { + $this->CI->session->unset_userdata('comment'); + } + + function get_email_receipt() + { + return $this->CI->session->userdata('email_receipt'); + } + + function set_email_receipt($email_receipt) + { + $this->CI->session->set_userdata('email_receipt', $email_receipt); + } + + function clear_email_receipt() + { + $this->CI->session->unset_userdata('email_receipt'); + } + + function add_payment( $payment_id, $payment_amount ) + { + $payments = $this->get_payments(); + $payment = array( $payment_id=> + array( + 'payment_type' => $payment_id, + 'payment_amount' => $payment_amount + ) + ); + + //payment_method already exists, add to payment_amount + if( isset( $payments[$payment_id] ) ) + { + $payments[$payment_id]['payment_amount'] += $payment_amount; + } + else + { + //add to existing array + $payments += $payment; + } + + $this->set_payments( $payments ); + return true; + + } + + //Alain Multiple Payments + function edit_payment($payment_id,$payment_amount) + { + $payments = $this->get_payments(); + if(isset($payments[$payment_id])) + { + $payments[$payment_id]['payment_type'] = $payment_id; + $payments[$payment_id]['payment_amount'] = $payment_amount; + $this->set_payments($payment_id); + } + + return false; + } + + //Alain Multiple Payments + function delete_payment( $payment_id ) + { + $payments = $this->get_payments(); + unset( $payments[urldecode( $payment_id )] ); + $this->set_payments( $payments ); + } + + //Alain Multiple Payments + function empty_payments() + { + $this->CI->session->unset_userdata('payments'); + } + + //Alain Multiple Payments + function get_payments_total() + { + $subtotal = 0; + foreach($this->get_payments() as $payments) + { + $subtotal+=$payments['payment_amount']; + } + return to_currency_no_money($subtotal); + } + + //Alain Multiple Payments + function get_amount_due() + { + $amount_due=0; + $payment_total = $this->get_payments_total(); + $sales_total=$this->get_total(); + $amount_due=to_currency_no_money($sales_total - $payment_total); + return $amount_due; + } + + function get_customer() + { + if(!$this->CI->session->userdata('customer')) + $this->set_customer(-1); + + return $this->CI->session->userdata('customer'); + } + + function set_customer($customer_id) + { + $this->CI->session->set_userdata('customer',$customer_id); + } + + function get_mode() + { + if(!$this->CI->session->userdata('sale_mode')) + $this->set_mode('sale'); + + return $this->CI->session->userdata('sale_mode'); + } + + function set_mode($mode) + { + $this->CI->session->set_userdata('sale_mode',$mode); + } + + function add_item($item_id,$quantity=1,$discount=0,$price=null,$description=null,$serialnumber=null) + { + //make sure item exists + if(!$this->CI->Item->exists($item_id)) + { + //try to get item id given an item_number + $item_id = $this->CI->Item->get_item_id($item_id); + + if(!$item_id) + return false; + } + + + //Alain Serialization and Description + + //Get all items in the cart so far... + $items = $this->get_cart(); + + //We need to loop through all items in the cart. + //If the item is already there, get it's key($updatekey). + //We also need to get the next key that we are going to use in case we need to add the + //item to the cart. Since items can be deleted, we can't use a count. we use the highest key + 1. + + $maxkey=0; //Highest key so far + $itemalreadyinsale=FALSE; //We did not find the item yet. + $insertkey=0; //Key to use for new entry. + $updatekey=0; //Key to use to update(quantity) + + foreach ($items as $item) + { + //We primed the loop so maxkey is 0 the first time. + //Also, we have stored the key in the element itself so we can compare. + + if($maxkey <= $item['line']) + { + $maxkey = $item['line']; + } + + if($item['item_id']==$item_id) + { + $itemalreadyinsale=TRUE; + $updatekey=$item['line']; + } + } + + $insertkey=$maxkey+1; + + //array/cart records are identified by $insertkey and item_id is just another field. + $item = array(($insertkey)=> + array( + 'item_id'=>$item_id, + 'line'=>$insertkey, + 'name'=>$this->CI->Item->get_info($item_id)->name, + 'item_number'=>$this->CI->Item->get_info($item_id)->item_number, + 'description'=>$description!=null ? $description: $this->CI->Item->get_info($item_id)->description, + 'serialnumber'=>$serialnumber!=null ? $serialnumber: '', + 'allow_alt_description'=>$this->CI->Item->get_info($item_id)->allow_alt_description, + 'is_serialized'=>$this->CI->Item->get_info($item_id)->is_serialized, + 'quantity'=>$quantity, + 'discount'=>$discount, + 'price'=>$price!=null ? $price: $this->CI->Item->get_info($item_id)->unit_price + ) + ); + + //Item already exists and is not serialized, add to quantity + if($itemalreadyinsale && ($this->CI->Item->get_info($item_id)->is_serialized ==0) ) + { + $items[$updatekey]['quantity']+=$quantity; + } + else + { + //add to existing array + $items+=$item; + } + + $this->set_cart($items); + return true; + + } + + function out_of_stock($item_id) + { + //make sure item exists + if(!$this->CI->Item->exists($item_id)) + { + //try to get item id given an item_number + $item_id = $this->CI->Item->get_item_id($item_id); + + if(!$item_id) + return false; + } + + $item = $this->CI->Item->get_info($item_id); + $quanity_added = $this->get_quantity_already_added($item_id); + + if ($item->quantity - $quanity_added < 0) + { + return true; + } + + return false; + } + + function get_quantity_already_added($item_id) + { + $items = $this->get_cart(); + $quanity_already_added = 0; + foreach ($items as $item) + { + if($item['item_id']==$item_id) + { + $quanity_already_added+=$item['quantity']; + } + } + + return $quanity_already_added; + } + + function get_item_id($line_to_get) + { + $items = $this->get_cart(); + + foreach ($items as $line=>$item) + { + if($line==$line_to_get) + { + return $item['item_id']; + } + } + + return -1; + } + + function edit_item($line,$description,$serialnumber,$quantity,$discount,$price) + { + $items = $this->get_cart(); + if(isset($items[$line])) + { + $items[$line]['description'] = $description; + $items[$line]['serialnumber'] = $serialnumber; + $items[$line]['quantity'] = $quantity; + $items[$line]['discount'] = $discount; + $items[$line]['price'] = $price; + $this->set_cart($items); + } + + return false; + } + + function is_valid_receipt($receipt_sale_id) + { + //POS # + $pieces = explode(' ',$receipt_sale_id); + + if(count($pieces)==2) + { + return $this->CI->Sale->exists($pieces[1]); + } + + return false; + } + + function is_valid_item_kit($item_kit_id) + { + //KIT # + $pieces = explode(' ',$item_kit_id); + + if(count($pieces)==2) + { + return $this->CI->Item_kit->exists($pieces[1]); + } + + return false; + } + + function return_entire_sale($receipt_sale_id) + { + //POS # + $pieces = explode(' ',$receipt_sale_id); + $sale_id = $pieces[1]; + + $this->empty_cart(); + $this->remove_customer(); + + foreach($this->CI->Sale->get_sale_items($sale_id)->result() as $row) + { + $this->add_item($row->item_id,-$row->quantity_purchased,$row->discount_percent,$row->item_unit_price,$row->description,$row->serialnumber); + } + $this->set_customer($this->CI->Sale->get_customer($sale_id)->person_id); + } + + function add_item_kit($external_item_kit_id) + { + //KIT # + $pieces = explode(' ',$external_item_kit_id); + $item_kit_id = $pieces[1]; + + foreach ($this->CI->Item_kit_items->get_info($item_kit_id) as $item_kit_item) + { + $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity']); + } + } + + function copy_entire_sale($sale_id) + { + $this->empty_cart(); + $this->remove_customer(); + + foreach($this->CI->Sale->get_sale_items($sale_id)->result() as $row) + { + $this->add_item($row->item_id,$row->quantity_purchased,$row->discount_percent,$row->item_unit_price,$row->description,$row->serialnumber); + } + foreach($this->CI->Sale->get_sale_payments($sale_id)->result() as $row) + { + $this->add_payment($row->payment_type,$row->payment_amount); + } + $this->set_customer($this->CI->Sale->get_customer($sale_id)->person_id); + + } + + function copy_entire_suspended_sale($sale_id) + { + $this->empty_cart(); + $this->remove_customer(); + + foreach($this->CI->Sale_suspended->get_sale_items($sale_id)->result() as $row) + { + $this->add_item($row->item_id,$row->quantity_purchased,$row->discount_percent,$row->item_unit_price,$row->description,$row->serialnumber); + } + foreach($this->CI->Sale_suspended->get_sale_payments($sale_id)->result() as $row) + { + $this->add_payment($row->payment_type,$row->payment_amount); + } + $this->set_customer($this->CI->Sale_suspended->get_customer($sale_id)->person_id); + $this->set_comment($this->CI->Sale_suspended->get_comment($sale_id)); + } + + function delete_item($line) + { + $items=$this->get_cart(); + unset($items[$line]); + $this->set_cart($items); + } + + function empty_cart() + { + $this->CI->session->unset_userdata('cart'); + } + + function remove_customer() + { + $this->CI->session->unset_userdata('customer'); + } + + function clear_mode() + { + $this->CI->session->unset_userdata('sale_mode'); + } + + function clear_all() + { + $this->clear_mode(); + $this->empty_cart(); + $this->clear_comment(); + $this->clear_email_receipt(); + $this->empty_payments(); + $this->remove_customer(); + } + + function get_taxes() + { + $customer_id = $this->get_customer(); + $customer = $this->CI->Customer->get_info($customer_id); + + //Do not charge sales tax if we have a customer that is not taxable + if (!$customer->taxable and $customer_id!=-1) + { + return array(); + } + + $taxes = array(); + foreach($this->get_cart() as $line=>$item) + { + $tax_info = $this->CI->Item_taxes->get_info($item['item_id']); + + foreach($tax_info as $tax) + { + $name = $tax['percent'].'% ' . $tax['name']; + $tax_amount=($item['price']*$item['quantity']-$item['price']*$item['quantity']*$item['discount']/100)*(($tax['percent'])/100); + + + if (!isset($taxes[$name])) + { + $taxes[$name] = 0; + } + $taxes[$name] += $tax_amount; + } + } + + return $taxes; + } + + function get_subtotal() + { + $subtotal = 0; + foreach($this->get_cart() as $item) + { + $subtotal+=($item['price']*$item['quantity']-$item['price']*$item['quantity']*$item['discount']/100); + } + return to_currency_no_money($subtotal); + } + + function get_total() + { + $total = 0; + foreach($this->get_cart() as $item) + { + $total += ( $item['price'] * $item['quantity'] - $item['price'] * $item['quantity'] * $item['discount'] / 100); + } + + foreach($this->get_taxes() as $tax) + { + $total+=$tax; + } + + return to_currency_no_money($total); + } +} +?> \ No newline at end of file diff --git a/application/libraries/index.html b/application/libraries/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/libraries/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/libraries/ofc-library/JSON.php b/application/libraries/ofc-library/JSON.php new file mode 100644 index 000000000..0cddbddb4 --- /dev/null +++ b/application/libraries/ofc-library/JSON.php @@ -0,0 +1,806 @@ + + * @author Matt Knapp + * @author Brett Stimmerman + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_SLICE', 1); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_STR', 2); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_ARR', 3); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_OBJ', 4); + +/** + * Marker constant for Services_JSON::decode(), used to flag stack state + */ +define('SERVICES_JSON_IN_CMT', 5); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_LOOSE_TYPE', 16); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_SUPPRESS_ERRORS', 32); + +/** + * Converts to and from JSON format. + * + * Brief example of use: + * + * + * // create a new instance of Services_JSON + * $json = new Services_JSON(); + * + * // convert a complexe value to JSON notation, and send it to the browser + * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); + * $output = $json->encode($value); + * + * print($output); + * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] + * + * // accept incoming POST data, assumed to be in JSON notation + * $input = file_get_contents('php://input', 1000000); + * $value = $json->decode($input); + * + */ +class Services_JSON +{ + /** + * constructs a new JSON instance + * + * @param int $use object behavior flags; combine with boolean-OR + * + * possible values: + * - SERVICES_JSON_LOOSE_TYPE: loose typing. + * "{...}" syntax creates associative arrays + * instead of objects in decode(). + * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. + * Values which can't be encoded (e.g. resources) + * appear as NULL instead of throwing errors. + * By default, a deeply-nested resource will + * bubble up with an error, so all return values + * from encode() should be checked with isError() + */ + function Services_JSON($use = 0) + { + $this->use = $use; + } + + /** + * convert a string from one UTF-16 char to one UTF-8 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf16 UTF-16 character + * @return string UTF-8 character + * @access private + */ + function utf162utf8($utf16) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); + } + + $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); + + switch(true) { + case ((0x7F & $bytes) == $bytes): + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x7F & $bytes); + + case (0x07FF & $bytes) == $bytes: + // return a 2-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xC0 | (($bytes >> 6) & 0x1F)) + . chr(0x80 | ($bytes & 0x3F)); + + case (0xFFFF & $bytes) == $bytes: + // return a 3-byte UTF-8 character + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0xE0 | (($bytes >> 12) & 0x0F)) + . chr(0x80 | (($bytes >> 6) & 0x3F)) + . chr(0x80 | ($bytes & 0x3F)); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + function utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if(function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + function encode($var) + { + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + $properties = array_map(array($this, 'name_value'), + array_keys($var), + array_values($var)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + // treat it like a regular array + $elements = array_map(array($this, 'encode'), $var); + + foreach($elements as $element) { + if(Services_JSON::isError($element)) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = get_object_vars($var); + + $properties = array_map(array($this, 'name_value'), + array_keys($vars), + array_values($vars)); + + foreach($properties as $property) { + if(Services_JSON::isError($property)) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + function name_value($name, $value) + { + $encoded_value = $this->encode($value); + + if(Services_JSON::isError($encoded_value)) { + return $encoded_value; + } + + return $this->encode(strval($name)) . ':' . $encoded_value; + } + + /** + * reduce a string by removing leading and trailing comments and whitespace + * + * @param $str string string value to strip of comments and whitespace + * + * @return string string value stripped of comments and whitespace + * @access private + */ + function reduce_string($str) + { + $str = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $str); + + // eliminate extraneous space + return trim($str); + } + + /** + * decodes a JSON string into appropriate variable + * + * @param string $str JSON-formatted string + * + * @return mixed number, boolean, string, array, or object + * corresponding to given JSON input string. + * See argument 1 to Services_JSON() above for object-output behavior. + * Note that decode() always returns strings + * in ASCII or UTF-8 format! + * @access public + */ + function decode($str) + { + $str = $this->reduce_string($str); + + switch (strtolower($str)) { + case 'true': + return true; + + case 'false': + return false; + + case 'null': + return null; + + default: + $m = array(); + + if (is_numeric($str)) { + // Lookie-loo, it's a number + + // This would work on its own, but I'm trying to be + // good about returning integers where appropriate: + // return (float)$str; + + // Return float or int, as appropriate + return ((float)$str == (integer)$str) + ? (integer)$str + : (float)$str; + + } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { + // STRINGS RETURNED IN UTF-8 FORMAT + $delim = substr($str, 0, 1); + $chrs = substr($str, 1, -1); + $utf8 = ''; + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = substr($chrs, $c, 2); + $ord_chrs_c = ord($chrs{$c}); + + switch (true) { + case $substr_chrs_c_2 == '\b': + $utf8 .= chr(0x08); + ++$c; + break; + case $substr_chrs_c_2 == '\t': + $utf8 .= chr(0x09); + ++$c; + break; + case $substr_chrs_c_2 == '\n': + $utf8 .= chr(0x0A); + ++$c; + break; + case $substr_chrs_c_2 == '\f': + $utf8 .= chr(0x0C); + ++$c; + break; + case $substr_chrs_c_2 == '\r': + $utf8 .= chr(0x0D); + ++$c; + break; + + case $substr_chrs_c_2 == '\\"': + case $substr_chrs_c_2 == '\\\'': + case $substr_chrs_c_2 == '\\\\': + case $substr_chrs_c_2 == '\\/': + if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || + ($delim == "'" && $substr_chrs_c_2 != '\\"')) { + $utf8 .= $chrs{++$c}; + } + break; + + case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) + . chr(hexdec(substr($chrs, ($c + 4), 2))); + $utf8 .= $this->utf162utf8($utf16); + $c += 5; + break; + + case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): + $utf8 .= $chrs{$c}; + break; + + case ($ord_chrs_c & 0xE0) == 0xC0: + // characters U-00000080 - U-000007FF, mask 110XXXXX + //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 2); + ++$c; + break; + + case ($ord_chrs_c & 0xF0) == 0xE0: + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 3); + $c += 2; + break; + + case ($ord_chrs_c & 0xF8) == 0xF0: + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 4); + $c += 3; + break; + + case ($ord_chrs_c & 0xFC) == 0xF8: + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 5); + $c += 4; + break; + + case ($ord_chrs_c & 0xFE) == 0xFC: + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $utf8 .= substr($chrs, $c, 6); + $c += 5; + break; + + } + + } + + return $utf8; + + } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { + // array, or object notation + + if ($str{0} == '[') { + $stk = array(SERVICES_JSON_IN_ARR); + $arr = array(); + } else { + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = array(); + } else { + $stk = array(SERVICES_JSON_IN_OBJ); + $obj = new stdClass(); + } + } + + array_push($stk, array('what' => SERVICES_JSON_SLICE, + 'where' => 0, + 'delim' => false)); + + $chrs = substr($str, 1, -1); + $chrs = $this->reduce_string($chrs); + + if ($chrs == '') { + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } else { + return $obj; + + } + } + + //print("\nparsing {$chrs}\n"); + + $strlen_chrs = strlen($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = substr($chrs, $c, 2); + + if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { + // found a comma that is not inside a string, array, etc., + // OR we've reached the end of the character list + $slice = substr($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + // we are in an array, so just push an element onto the stack + array_push($arr, $this->decode($slice)); + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + // we are in an object, so figure + // out the property name and set an + // element in an associative array, + // for now + $parts = array(); + + if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode($parts[2]); + + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } + + } + + } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { + // found a quote, and we are not inside a string + array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); + //print("Found start of string at {$c}\n"); + + } elseif (($chrs{$c} == $top['delim']) && + ($top['what'] == SERVICES_JSON_IN_STR) && + ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { + // found a quote, we're in a string, and it's not escaped + // we know that it's not escaped becase there is _not_ an + // odd number of backslashes at the end of the string so far + array_pop($stk); + //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '[') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-bracket, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); + //print("Found start of array at {$c}\n"); + + } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { + // found a right-bracket, and we're in an array + array_pop($stk); + //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($chrs{$c} == '{') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a left-brace, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); + //print("Found start of object at {$c}\n"); + + } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { + // found a right-brace, and we're in an object + array_pop($stk); + //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } elseif (($substr_chrs_c_2 == '/*') && + in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { + // found a comment start, and we are in an array, object, or slice + array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); + $c++; + //print("Found start of comment at {$c}\n"); + + } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { + // found a comment end, and we're in one now + array_pop($stk); + $c++; + + for ($i = $top['where']; $i <= $c; ++$i) + $chrs = substr_replace($chrs, ' ', $i, 1); + + //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); + + } + + } + + if (reset($stk) == SERVICES_JSON_IN_ARR) { + return $arr; + + } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { + return $obj; + + } + + } + } + } + + /** + * @todo Ultimately, this should just call PEAR::isError() + */ + function isError($data, $code = null) + { + if (class_exists('pear')) { + return PEAR::isError($data, $code); + } elseif (is_object($data) && (get_class($data) == 'services_json_error' || + is_subclass_of($data, 'services_json_error'))) { + return true; + } + + return false; + } +} + +if (class_exists('PEAR_Error')) { + + class Services_JSON_Error extends PEAR_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + parent::PEAR_Error($message, $code, $mode, $options, $userinfo); + } + } + +} else { + + /** + * @todo Ultimately, this class shall be descended from PEAR_Error + */ + class Services_JSON_Error + { + function Services_JSON_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + + } + } + +} + +?> diff --git a/application/libraries/ofc-library/README.txt b/application/libraries/ofc-library/README.txt new file mode 100644 index 000000000..012fbfd52 --- /dev/null +++ b/application/libraries/ofc-library/README.txt @@ -0,0 +1,16 @@ +Open Flash Chart - PHP libraries. These help create data files for Open Flash Chart. +Copyright (C) 2007 + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA \ No newline at end of file diff --git a/application/libraries/ofc-library/dot_base.php b/application/libraries/ofc-library/dot_base.php new file mode 100644 index 000000000..5772efcd9 --- /dev/null +++ b/application/libraries/ofc-library/dot_base.php @@ -0,0 +1,231 @@ +type = $type; + if( isset( $value ) ) + $this->value( $value ); + } + + /** + * For line charts that only require a Y position + * for each point. + * @param $value as integer, the Y position + */ + function value( $value ) + { + $this->value = $value; + } + + /** + * For scatter charts that require an X and Y position for + * each point. + * + * @param $x as integer + * @param $y as integer + */ + function position( $x, $y ) + { + $this->x = $x; + $this->y = $y; + } + + /** + * @param $colour is a string, HEX colour, e.g. '#FF0000' red + */ + function colour($colour) + { + $this->colour = $colour; + return $this; + } + + /** + * The tooltip for this dot. + */ + function tooltip( $tip ) + { + $this->tip = $tip; + return $this; + } + + /** + * @param $size is an integer. Size of the dot. + */ + function size($size) + { + $tmp = 'dot-size'; + $this->$tmp = $size; + return $this; + } + + /** + * a private method + */ + function type( $type ) + { + $this->type = $type; + return $this; + } + + /** + * @param $size is an integer. The size of the hollow 'halo' around the dot that masks the line. + */ + function halo_size( $size ) + { + $tmp = 'halo-size'; + $this->$tmp = $size; + return $this; + } + + /** + * @param $do as string. One of three options (examples): + * - "http://example.com" - browse to this URL + * - "https://example.com" - browse to this URL + * - "trace:message" - print this message in the FlashDevelop debug pane + * - all other strings will be called as Javascript functions, so a string "hello_world" + * will call the JS function "hello_world(index)". It passes in the index of the + * point. + */ + function on_click( $do ) + { + $tmp = 'on-click'; + $this->$tmp = $do; + } +} + +/** + * Draw a hollow dot + */ +class hollow_dot extends dot_base +{ + function hollow_dot($value=null) + { + parent::dot_base( 'hollow-dot', $value ); + } +} + +/** + * Draw a star + */ +class star extends dot_base +{ + /** + * The constructor, takes an optional $value + */ + function star($value=null) + { + parent::dot_base( 'star', $value ); + } + + /** + * @param $angle is an integer. + */ + function rotation($angle) + { + $this->rotation = $angle; + return $this; + } + + /** + * @param $is_hollow is a boolean. + */ + function hollow($is_hollow) + { + $this->hollow = $is_hollow; + } +} + +/** + * Draw a 'bow tie' shape. + */ +class bow extends dot_base +{ + /** + * The constructor, takes an optional $value + */ + function bow($value=null) + { + parent::dot_base( 'bow', $value ); + } + + /** + * Rotate the anchor object. + * @param $angle is an integer. + */ + function rotation($angle) + { + $this->rotation = $angle; + return $this; + } +} + +/** + * An n sided shape. + */ +class anchor extends dot_base +{ + /** + * The constructor, takes an optional $value + */ + function anchor($value=null) + { + parent::dot_base( 'anchor', $value ); + } + + /** + * Rotate the anchor object. + * @param $angle is an integer. + */ + function rotation($angle) + { + $this->rotation = $angle; + return $this; + } + + /** + * @param $sides is an integer. Number of sides this shape has. + */ + function sides($sides) + { + $this->sides = $sides; + return $this; + } +} + +/** + * A simple dot + */ +class dot extends dot_base +{ + /** + * The constructor, takes an optional $value + */ + function dot($value=null) + { + parent::dot_base( 'dot', $value ); + } +} + +/** + * A simple dot + */ +class solid_dot extends dot_base +{ + /** + * The constructor, takes an optional $value + */ + function solid_dot($value=null) + { + parent::dot_base( 'solid-dot', $value ); + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/json_format.php b/application/libraries/ofc-library/json_format.php new file mode 100644 index 000000000..b8e3de5cb --- /dev/null +++ b/application/libraries/ofc-library/json_format.php @@ -0,0 +1,86 @@ + 0 && $json[$c-1] != '\\') + { + $in_string = !$in_string; + } + default: + $new_json .= $char; + break; + } + } + + return $new_json; +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_area_base.php b/application/libraries/ofc-library/ofc_area_base.php new file mode 100644 index 000000000..a6e811fd5 --- /dev/null +++ b/application/libraries/ofc-library/ofc_area_base.php @@ -0,0 +1,40 @@ +type = "area"; + } + + /** + * the fill colour + */ + function set_fill_colour( $colour ) + { + $this->fill = $colour; + } + + /** + * sugar: see set_fill_colour + */ + function fill_colour( $colour ) + { + $this->set_fill_colour( $colour ); + return $this; + } + + function set_fill_alpha( $alpha ) + { + $tmp = "fill-alpha"; + $this->$tmp = $alpha; + } + + function set_loop() + { + $this->loop = true; + } +} diff --git a/application/libraries/ofc-library/ofc_area_hollow.php b/application/libraries/ofc-library/ofc_area_hollow.php new file mode 100644 index 000000000..4293af0b6 --- /dev/null +++ b/application/libraries/ofc-library/ofc_area_hollow.php @@ -0,0 +1,10 @@ +type = "area_hollow"; + parent::area_base(); + } +} diff --git a/application/libraries/ofc-library/ofc_area_line.php b/application/libraries/ofc-library/ofc_area_line.php new file mode 100644 index 000000000..5731391a3 --- /dev/null +++ b/application/libraries/ofc-library/ofc_area_line.php @@ -0,0 +1,10 @@ +type = "area_line"; + parent::area_base(); + } +} diff --git a/application/libraries/ofc-library/ofc_arrow.php b/application/libraries/ofc-library/ofc_arrow.php new file mode 100644 index 000000000..3c2c6e9dc --- /dev/null +++ b/application/libraries/ofc-library/ofc_arrow.php @@ -0,0 +1,27 @@ +type = "arrow"; + $this->start = array("x"=>$x, "y"=>$y); + $this->end = array("x"=>$a, "y"=>$b); + $this->colour($colour); + $this->{"barb-length"} = $barb_length; + } + + function colour( $colour ) + { + $this->colour = $colour; + return $this; + } +} diff --git a/application/libraries/ofc-library/ofc_bar.php b/application/libraries/ofc-library/ofc_bar.php new file mode 100644 index 000000000..6ddda4274 --- /dev/null +++ b/application/libraries/ofc-library/ofc_bar.php @@ -0,0 +1,34 @@ +top = $top; + + if( isset( $bottom ) ) + $this->bottom = $bottom; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class bar extends bar_base +{ + function bar() + { + $this->type = "bar"; + parent::bar_base(); + } +} + diff --git a/application/libraries/ofc-library/ofc_bar_3d.php b/application/libraries/ofc-library/ofc_bar_3d.php new file mode 100644 index 000000000..47552184c --- /dev/null +++ b/application/libraries/ofc-library/ofc_bar_3d.php @@ -0,0 +1,22 @@ +top = $top; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + diff --git a/application/libraries/ofc-library/ofc_bar_base.php b/application/libraries/ofc-library/ofc_bar_base.php new file mode 100644 index 000000000..c1303b86b --- /dev/null +++ b/application/libraries/ofc-library/ofc_bar_base.php @@ -0,0 +1,97 @@ +text = $text; + $tmp = 'font-size'; + $this->$tmp = $size; + } + + /** + * syntatical sugar. + */ + function key( $text, $size ) + { + $this->set_key( $text, $size ); + } + + /** + * @param $v as an array, a mix of: + * - a bar_value class. You can use this to customise the paramters of each bar. + * - integer. This is the Y position of the top of the bar. + */ + function set_values( $v ) + { + $this->values = $v; + } + + /** + * see set_values + */ + function append_value( $v ) + { + $this->values[] = $v; + } + + /** + * @param $colour as string, a HEX colour, e.g. '#ff0000' red + */ + function set_colour( $colour ) + { + $this->colour = $colour; + } + + /** + *syntatical sugar + */ + function colour( $colour ) + { + $this->set_colour( $colour ); + } + + /** + * @param $alpha as real number (range 0 to 1), e.g. 0.5 is half transparent + */ + function set_alpha( $alpha ) + { + $this->alpha = $alpha; + } + + /** + * @param $tip as string, the tip to show. May contain various magic variables. + */ + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + /** + *@param $on_show as line_on_show object + */ + function set_on_show($on_show) + { + $this->{'on-show'} = $on_show; + } + + function set_on_click( $text ) + { + $tmp = 'on-click'; + $this->$tmp = $text; + } + + function attach_to_right_y_axis() + { + $this->axis = 'right'; + } +} + diff --git a/application/libraries/ofc-library/ofc_bar_filled.php b/application/libraries/ofc-library/ofc_bar_filled.php new file mode 100644 index 000000000..837c1fc45 --- /dev/null +++ b/application/libraries/ofc-library/ofc_bar_filled.php @@ -0,0 +1,39 @@ +$tmp = $outline_colour; + } +} + +class bar_filled extends bar_base +{ + function bar_filled( $colour=null, $outline_colour=null ) + { + $this->type = "bar_filled"; + parent::bar_base(); + + if( isset( $colour ) ) + $this->set_colour( $colour ); + + if( isset( $outline_colour ) ) + $this->set_outline_colour( $outline_colour ); + } + + function set_outline_colour( $outline_colour ) + { + $tmp = 'outline-colour'; + $this->$tmp = $outline_colour; + } +} + diff --git a/application/libraries/ofc-library/ofc_bar_glass.php b/application/libraries/ofc-library/ofc_bar_glass.php new file mode 100644 index 000000000..e83350151 --- /dev/null +++ b/application/libraries/ofc-library/ofc_bar_glass.php @@ -0,0 +1,131 @@ +type = $type; + $this->cascade = (float)$cascade; + $this->delay = (float)$delay; + } +} + +class bar_value +{ + /** + * @param $top as integer. The Y value of the top of the bar + * @param OPTIONAL $bottom as integer. The Y value of the bottom of the bar, defaults to Y min. + */ + function bar_value( $top, $bottom=null ) + { + $this->top = $top; + + if( isset( $bottom ) ) + $this->bottom = $bottom; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class bar extends bar_base +{ + function bar() + { + $this->type = "bar"; + parent::bar_base(); + } +} + +class bar_glass extends bar_base +{ + function bar_glass() + { + $this->type = "bar_glass"; + parent::bar_base(); + } +} + +class bar_cylinder extends bar_base +{ + function bar_cylinder() + { + $this->type = "bar_cylinder"; + parent::bar_base(); + } +} + +class bar_cylinder_outline extends bar_base +{ + function bar_cylinder_outline() + { + $this->type = "bar_cylinder_outline"; + parent::bar_base(); + } +} + +class bar_rounded_glass extends bar_base +{ + function bar_rounded_glass() + { + $this->type = "bar_round_glass"; + parent::bar_base(); + } +} + +class bar_round extends bar_base +{ + function bar_round() + { + $this->type = "bar_round"; + parent::bar_base(); + } +} + +class bar_dome extends bar_base +{ + function bar_dome() + { + $this->type = "bar_dome"; + parent::bar_base(); + } +} + +class bar_round3d extends bar_base +{ + function bar_round3d() + { + $this->type = "bar_round3d"; + parent::bar_base(); + } +} + +class bar_3d extends bar_base +{ + function bar_3d() + { + $this->type = "bar_3d"; + parent::bar_base(); + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_bar_sketch.php b/application/libraries/ofc-library/ofc_bar_sketch.php new file mode 100644 index 000000000..ce1bcccf8 --- /dev/null +++ b/application/libraries/ofc-library/ofc_bar_sketch.php @@ -0,0 +1,29 @@ +type = "bar_sketch"; + parent::bar_base(); + + $this->set_colour( $colour ); + $this->set_outline_colour( $outline_colour ); + $this->offset = $fun_factor; + } + + function set_outline_colour( $outline_colour ) + { + $tmp = 'outline-colour'; + $this->$tmp = $outline_colour; + } +} + diff --git a/application/libraries/ofc-library/ofc_bar_stack.php b/application/libraries/ofc-library/ofc_bar_stack.php new file mode 100644 index 000000000..3d9f8d9f0 --- /dev/null +++ b/application/libraries/ofc-library/ofc_bar_stack.php @@ -0,0 +1,55 @@ +type = "bar_stack"; + parent::bar_base(); + } + + function append_stack( $v ) + { + $this->append_value( $v ); + } + + // an array of HEX colours strings + // e.g. array( '#ff0000', '#00ff00' ); + function set_colours( $colours ) + { + $this->colours = $colours; + } + + // an array of bar_stack_value + function set_keys( $keys ) + { + $this->keys = $keys; + } +} + +class bar_stack_value +{ + function bar_stack_value( $val, $colour ) + { + $this->val = $val; + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class bar_stack_key +{ + function bar_stack_key( $colour, $text, $font_size ) + { + $this->colour = $colour; + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $font_size; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_candle.php b/application/libraries/ofc-library/ofc_candle.php new file mode 100644 index 000000000..21ad67f8d --- /dev/null +++ b/application/libraries/ofc-library/ofc_candle.php @@ -0,0 +1,41 @@ +high = $high; + $this->top = $open; + $this->bottom = $close; + $this->low = $low; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class candle extends bar_base +{ + function candle($colour, $negative_colour=null) + { + $this->type = "candle"; + parent::bar_base(); + + $this->set_colour( $colour ); + if(!is_null($negative_colour)) + $this->{'negative-colour'} = $negative_colour; + } +} + diff --git a/application/libraries/ofc-library/ofc_hbar.php b/application/libraries/ofc-library/ofc_hbar.php new file mode 100644 index 000000000..6f8c0e451 --- /dev/null +++ b/application/libraries/ofc-library/ofc_hbar.php @@ -0,0 +1,64 @@ +left = $left; + $this->right = $right; + } + else + $this->right = $left; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class hbar +{ + function hbar( $colour ) + { + $this->type = "hbar"; + $this->values = array(); + $this->set_colour( $colour ); + } + + function append_value( $v ) + { + $this->values[] = $v; + } + + function set_values( $v ) + { + foreach( $v as $val ) + $this->append_value( new hbar_value( $val ) ); + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_key( $text, $size ) + { + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $size; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + diff --git a/application/libraries/ofc-library/ofc_line.php b/application/libraries/ofc-library/ofc_line.php new file mode 100644 index 000000000..e635f2c02 --- /dev/null +++ b/application/libraries/ofc-library/ofc_line.php @@ -0,0 +1,157 @@ +type = $type; + $this->cascade = (float)$cascade; + $this->delay = (float)$delay; + } +} + +class line +{ + function line() + { + $this->type = "line"; + $this->values = array(); + } + + /** + * Set the default dot that all the real + * dots inherit their properties from. If you set the + * default dot to be red, all values in your chart that + * do not specify a colour will be red. Same for all the + * other attributes such as tooltip, on-click, size etc... + * + * @param $style as any class that inherits base_dot + */ + function set_default_dot_style( $style ) + { + $tmp = 'dot-style'; + $this->$tmp = $style; + } + + /** + * @param $v as array, can contain any combination of: + * - integer, Y position of the point + * - any class that inherits from dot_base + * - null + */ + function set_values( $v ) + { + $this->values = $v; + } + + /** + * Append a value to the line. + * + * @param mixed $v + */ + function append_value($v) + { + $this->values[] = $v; + } + + function set_width( $width ) + { + $this->width = $width; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + /** + * sytnatical sugar for set_colour + */ + function colour( $colour ) + { + $this->set_colour( $colour ); + return $this; + } + + function set_halo_size( $size ) + { + $tmp = 'halo-size'; + $this->$tmp = $size; + } + + function set_key( $text, $font_size ) + { + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $font_size; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + /** + * @param $text as string. A javascript function name as a string. The chart will + * try to call this function, it will pass the chart id as the only parameter into + * this function. E.g: + * + */ + function set_on_click( $text ) + { + $tmp = 'on-click'; + $this->$tmp = $text; + } + + function loop() + { + $this->loop = true; + } + + function line_style( $s ) + { + $tmp = "line-style"; + $this->$tmp = $s; + } + + /** + * Sets the text for the line. + * + * @param string $text + */ + function set_text($text) + { + $this->text = $text; + } + + function attach_to_right_y_axis() + { + $this->axis = 'right'; + } + + /** + *@param $on_show as line_on_show object + */ + function set_on_show($on_show) + { + $this->{'on-show'} = $on_show; + } + + function on_show($on_show) + { + $this->set_on_show($on_show); + return $this; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_line_base.php b/application/libraries/ofc-library/ofc_line_base.php new file mode 100644 index 000000000..fa45cbc89 --- /dev/null +++ b/application/libraries/ofc-library/ofc_line_base.php @@ -0,0 +1,92 @@ +type = "line"; + $this->text = "Page views"; + $tmp = 'font-size'; + $this->$tmp = 10; + + $this->values = array(); + } + + function set_values( $v ) + { + $this->values = $v; + } + + /** + * Append a value to the line. + * + * @param mixed $v + */ + function append_value($v) + { + $this->values[] = $v; + } + + function set_width( $width ) + { + $this->width = $width; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_dot_size( $size ) + { + $tmp = 'dot-size'; + $this->$tmp = $size; + } + + function set_halo_size( $size ) + { + $tmp = 'halo-size'; + $this->$tmp = $size; + } + + function set_key( $text, $font_size ) + { + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $font_size; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + function set_on_click( $text ) + { + $tmp = 'on-click'; + $this->$tmp = $text; + } + + function loop() + { + $this->loop = true; + } + + function line_style( $s ) + { + $tmp = "line-style"; + $this->$tmp = $s; + } + + /** + * Sets the text for the line. + * + * @param string $text + */ + function set_text($text) + { + $this->text = $text; + } + + +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_line_dot.php b/application/libraries/ofc-library/ofc_line_dot.php new file mode 100644 index 000000000..146691173 --- /dev/null +++ b/application/libraries/ofc-library/ofc_line_dot.php @@ -0,0 +1,33 @@ +value = $value; + $this->colour = $colour; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_size( $size ) + { + $this->size = $size; + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } +} + +class line_dot extends line_base +{ + function line_dot() + { + $this->type = "line_dot"; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_line_hollow.php b/application/libraries/ofc-library/ofc_line_hollow.php new file mode 100644 index 000000000..512bb07d9 --- /dev/null +++ b/application/libraries/ofc-library/ofc_line_hollow.php @@ -0,0 +1,9 @@ +type = "line_hollow"; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_line_style.php b/application/libraries/ofc-library/ofc_line_style.php new file mode 100644 index 000000000..4f538cf9d --- /dev/null +++ b/application/libraries/ofc-library/ofc_line_style.php @@ -0,0 +1,11 @@ +style = "dash"; + $this->on = $on; + $this->off = $off; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_menu.php b/application/libraries/ofc-library/ofc_menu.php new file mode 100644 index 000000000..0750a09c2 --- /dev/null +++ b/application/libraries/ofc-library/ofc_menu.php @@ -0,0 +1,56 @@ +type = "text"; + $this->text = $text; + $tmp = 'javascript-function'; + $this->$tmp = $javascript_function_name; + } +} + +class ofc_menu_item_camera +{ + /** + * @param $text as string. The menu item text. + * @param $javascript_function_name as string. The javascript function name, the + * js function takes one parameter, the chart ID. So for example, our js function + * could look like this: + * + * function save_image( chart_id ) + * { + * alert( chart_id ); + * } + * + * to make a menu item call this: ofc_menu_item_camera('Save chart', 'save_image'); + */ + function ofc_menu_item_camera($text, $javascript_function_name) + { + $this->type = "camera-icon"; + $this->text = $text; + $tmp = 'javascript-function'; + $this->$tmp = $javascript_function_name; + } +} + +class ofc_menu +{ + function ofc_menu($colour, $outline_colour) + { + $this->colour = $colour; + $this->outline_colour = $outline_colour; + } + + function values($values) + { + $this->values = $values; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_pie.php b/application/libraries/ofc-library/ofc_pie.php new file mode 100644 index 000000000..bf779c554 --- /dev/null +++ b/application/libraries/ofc-library/ofc_pie.php @@ -0,0 +1,257 @@ +value = $value; + $this->label = $label; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_label( $label, $label_colour, $font_size ) + { + $this->label = $label; + + $tmp = 'label-colour'; + $this->$tmp = $label_colour; + + $tmp = 'font-size'; + $this->$tmp = $font_size; + + } + + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + function on_click( $event ) + { + $tmp = 'on-click'; + $this->$tmp = $event; + } + + + /** + * An object that inherits from base_pie_animation + */ + function add_animation( $animation ) + { + if( !isset( $this->animate ) ) + $this->animate = array(); + + $this->animate[] = $animation; + + return $this; + } +} + +class base_pie_animation{} + +/** + * fade the pie slice from $alpha (pie set_alpha) to 100% opaque. + */ +class pie_fade extends base_pie_animation +{ + function pie_fade() + { + $this->type="fade"; + } +} + +/** + * Bounce the pie slice out a little + */ +class pie_bounce extends base_pie_animation +{ + /** + * @param $distance as integer, distance to bounce in pixels + */ + function pie_bounce( $distance ) + { + $this->type="bounce"; + $this->distance = $distance; + } +} + +/** + * Make a pie chart and fill it with pie slices + */ +class pie +{ + function pie() + { + $this->type = 'pie'; + } + + function set_colours( $colours ) + { + $this->colours = $colours; + } + + /** + * Sugar wrapped around set_colours + */ + function colours( $colours ) + { + $this->set_colours( $colours ); + return $this; + } + + /** + * @param $alpha as float (0-1) 0.75 = 3/4 visible + */ + function set_alpha( $alpha ) + { + $this->alpha = $alpha; + } + + /** + *sugar wrapped set_alpha + **/ + function alpha( $alpha ) + { + $this->set_alpha( $alpha ); + return $this; + } + + /** + * @param $v as array containing one of + * - null + * - real or integer number + * - a pie_value object + */ + function set_values( $v ) + { + $this->values = $v; + } + + /** + * sugar for set_values + */ + function values( $v ) + { + $this->set_values( $v ); + return $this; + } + + /** + * HACK to keep old code working. + */ + function set_animate( $bool ) + { + if( $bool ) + $this->add_animation( new pie_fade() ); + + } + + /** + * An object that inherits from base_pie_animation + */ + function add_animation( $animation ) + { + if( !isset( $this->animate ) ) + $this->animate = array(); + + $this->animate[] = $animation; + + return $this; + } + + /** + * @param $angle as real number + */ + function set_start_angle( $angle ) + { + $tmp = 'start-angle'; + $this->$tmp = $angle; + } + + /** + * sugar for set_start_angle + */ + function start_angle($angle) + { + $this->set_start_angle( $angle ); + return $this; + } + + /** + * @param $tip as string. The tooltip text. May contain magic varibles + */ + function set_tooltip( $tip ) + { + $this->tip = $tip; + } + + /** + * sugar for set_tooltip + */ + function tooltip( $tip ) + { + $this->set_tooltip( $tip ); + return $this; + } + + function set_gradient_fill() + { + $tmp = 'gradient-fill'; + $this->$tmp = true; + } + + function gradient_fill() + { + $this->set_gradient_fill(); + return $this; + } + + /** + * By default each label is the same colour as the slice, + * but you can ovveride that behaviour using this method. + * + * @param $label_colour as string HEX colour; + */ + function set_label_colour( $label_colour ) + { + $tmp = 'label-colour'; + $this->$tmp = $label_colour; + } + + function label_colour( $label_colour ) + { + $this->set_label_colour( $label_colour ); + return $this; + } + + /** + * Turn off the labels + */ + function set_no_labels() + { + $tmp = 'no-labels'; + $this->$tmp = true; + } + + function on_click( $event ) + { + $tmp = 'on-click'; + $this->$tmp = $event; + } + + /** + * Fix the radius of the pie chart. Take a look at the magic variable #radius# + * for helping figure out what radius to set it to. + * + * @param $radius as number + */ + function radius( $radius ) + { + $this->radius = $radius; + return $this; + } +} diff --git a/application/libraries/ofc-library/ofc_radar_axis.php b/application/libraries/ofc-library/ofc_radar_axis.php new file mode 100644 index 000000000..909c41af8 --- /dev/null +++ b/application/libraries/ofc-library/ofc_radar_axis.php @@ -0,0 +1,47 @@ +set_max( $max ); + } + + function set_max( $max ) + { + $this->max = $max; + } + + function set_steps( $steps ) + { + $this->steps = $steps; + } + + function set_stroke( $s ) + { + $this->stroke = $s; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_grid_colour( $colour ) + { + $tmp = 'grid-colour'; + $this->$tmp = $colour; + } + + function set_labels( $labels ) + { + $this->labels = $labels; + } + + function set_spoke_labels( $labels ) + { + $tmp = 'spoke-labels'; + $this->$tmp = $labels; + } +} + diff --git a/application/libraries/ofc-library/ofc_radar_axis_labels.php b/application/libraries/ofc-library/ofc_radar_axis_labels.php new file mode 100644 index 000000000..22d485e4e --- /dev/null +++ b/application/libraries/ofc-library/ofc_radar_axis_labels.php @@ -0,0 +1,15 @@ +labels = $labels; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_radar_spoke_labels.php b/application/libraries/ofc-library/ofc_radar_spoke_labels.php new file mode 100644 index 000000000..51ba25e9a --- /dev/null +++ b/application/libraries/ofc-library/ofc_radar_spoke_labels.php @@ -0,0 +1,15 @@ +labels = $labels; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_scatter.php b/application/libraries/ofc-library/ofc_scatter.php new file mode 100644 index 000000000..7159a3a64 --- /dev/null +++ b/application/libraries/ofc-library/ofc_scatter.php @@ -0,0 +1,47 @@ +x = $x; + $this->y = $y; + + if( $dot_size > 0 ) + { + $tmp = 'dot-size'; + $this->$tmp = $dot_size; + } + } +} + +class scatter +{ + function scatter( $colour ) + { + $this->type = "scatter"; + $this->set_colour( $colour ); + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_default_dot_style( $style ) + { + $tmp = 'dot-style'; + $this->$tmp = $style; + } + + /** + * @param $v as array, can contain any combination of: + * - integer, Y position of the point + * - any class that inherits from scatter_value + * - null + */ + function set_values( $values ) + { + $this->values = $values; + } +} diff --git a/application/libraries/ofc-library/ofc_scatter_line.php b/application/libraries/ofc-library/ofc_scatter_line.php new file mode 100644 index 000000000..d667d7e8c --- /dev/null +++ b/application/libraries/ofc-library/ofc_scatter_line.php @@ -0,0 +1,49 @@ +type = "scatter_line"; + $this->set_colour( $colour ); + $this->set_width( $width ); + } + + function set_default_dot_style( $style ) + { + $tmp = 'dot-style'; + $this->$tmp = $style; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_width( $width ) + { + $this->width = $width; + } + + function set_values( $values ) + { + $this->values = $values; + } + + function set_step_horizontal() + { + $this->stepgraph = 'horizontal'; + } + + function set_step_vertical() + { + $this->stepgraph = 'vertical'; + } + + function set_key( $text, $font_size ) + { + $this->text = $text; + $tmp = 'font-size'; + $this->$tmp = $font_size; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_shape.php b/application/libraries/ofc-library/ofc_shape.php new file mode 100644 index 000000000..0cfe39f9b --- /dev/null +++ b/application/libraries/ofc-library/ofc_shape.php @@ -0,0 +1,25 @@ +x = $x; + $this->y = $y; + } +} + +class shape +{ + function shape( $colour ) + { + $this->type = "shape"; + $this->colour = $colour; + $this->values = array(); + } + + function append_value( $p ) + { + $this->values[] = $p; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_sugar.php b/application/libraries/ofc-library/ofc_sugar.php new file mode 100644 index 000000000..a9e85555e --- /dev/null +++ b/application/libraries/ofc-library/ofc_sugar.php @@ -0,0 +1,43 @@ +colour($colour)->size($size); + } +} + +class s_box extends anchor +{ + /** + * I use this wrapper for default dot types, + * it just makes the code easier to read. + */ + function s_box($colour, $size) + { + parent::anchor(); + $this->colour($colour)->size($size)->rotation(45)->sides(4); + } +} + +class s_hollow_dot extends hollow_dot +{ + /** + * I use this wrapper for default dot types, + * it just makes the code easier to read. + */ + function s_hollow_dot($colour, $size) + { + parent::hollow_dot(); + $this->colour($colour)->size($size); + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_tags.php b/application/libraries/ofc-library/ofc_tags.php new file mode 100644 index 000000000..7e7e24454 --- /dev/null +++ b/application/libraries/ofc-library/ofc_tags.php @@ -0,0 +1,133 @@ +type = "tags"; + $this->values = array(); + } + + function colour( $colour ) + { + $this->colour = $colour; + return $this; + } + + /** + *@param $font as string. e.g. "Verdana" + *@param $size as integer. Size in px + */ + function font($font, $size) + { + $this->font = $font; + $this->{'font-size'} = $size; + return $this; + } + + /** + *@param $x as integer. Size of x padding in px + *@param $y as integer. Size of y padding in px + */ + function padding($x, $y) + { + $this->{"pad-x"} = $x; + $this->{"pad-y"} = $y; + return $this; + } + + function rotate($angle) + { + $this->rotate($angle); + return $this; + } + + function align_x_center() + { + $this->{"align-x"} = "center"; + return $this; + } + + function align_x_left() + { + $this->{"align-x"} = "left"; + return $this; + } + + function align_x_right() + { + $this->{"align-x"} = "right"; + return $this; + } + + function align_y_above() + { + $this->{"align-y"} = "above"; + return $this; + } + + function align_y_below() + { + $this->{"align-y"} = "below"; + return $this; + } + + function align_y_center() + { + $this->{"align-y"} = "center"; + return $this; + } + + /** + * This can contain some HTML, e.g: + * - "More info" + * - "ofc" + */ + function text($text) + { + $this->text = $text; + return $this; + } + + /** + * This works, but to get the mouse pointer to change + * to a little hand you need to use "stuff"-- see text() + */ + function on_click($on_click) + { + $this->{'on-click'} = $on_click; + return $this; + } + + /** + *@param $bold boolean. + *@param $underline boolean. + *@param $border boolean. + *@prarm $alpha real (0 to 1.0) + */ + function style($bold, $underline, $border, $alpha ) + { + $this->bold = $bold; + $this->border = $underline; + $this->underline = $border; + $this->alpha = $alpha; + return $this; + } + + /** + *@param $tag as ofc_tag + */ + function append_tag($tag) + { + $this->values[] = $tag; + } +} + +class ofc_tag extends ofc_tags +{ + function ofc_tag($x, $y) + { + $this->x = $x; + $this->y = $y; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_title.php b/application/libraries/ofc-library/ofc_title.php new file mode 100644 index 000000000..cda1de006 --- /dev/null +++ b/application/libraries/ofc-library/ofc_title.php @@ -0,0 +1,39 @@ +text = $text; + } + + /** + * A css string. Can optionally contain: + * - font-size + * - font-family + * - font-weight + * - color + * - background-color + * - text-align + * - margin + * - margin-left + * - margin-right + * - margin-top + * - margin-bottom + * - padding + * - padding-left + * - padding-right + * - padding-top + * - padding-bottom + * just like the css we use all the time :-) + */ + function set_style( $css ) + { + $this->style = $css; + //"{font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;}"; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_tooltip.php b/application/libraries/ofc-library/ofc_tooltip.php new file mode 100644 index 000000000..3104ee33b --- /dev/null +++ b/application/libraries/ofc-library/ofc_tooltip.php @@ -0,0 +1,67 @@ +shadow = $shadow; + } + + /** + * @param $stroke as integer, border width in pixels (e.g. 5 ) + */ + function set_stroke( $stroke ) + { + $this->stroke = $stroke; + } + + /** + * @param $colour as string, HEX colour e.g. '#0000ff' + */ + function set_colour( $colour ) + { + $this->colour = $colour; + } + + /** + * @param $bg as string, HEX colour e.g. '#0000ff' + */ + function set_background_colour( $bg ) + { + $this->background = $bg; + } + + /** + * @param $style as string. A css style. + */ + function set_title_style( $style ) + { + $this->title = $style; + } + + /** + * @param $style as string. A css style. + */ + function set_body_style( $style ) + { + $this->body = $style; + } + + function set_proximity() + { + $this->mouse = 1; + } + + function set_hover() + { + $this->mouse = 2; + } +} + diff --git a/application/libraries/ofc-library/ofc_x_axis.php b/application/libraries/ofc-library/ofc_x_axis.php new file mode 100644 index 000000000..da1c7672b --- /dev/null +++ b/application/libraries/ofc-library/ofc_x_axis.php @@ -0,0 +1,140 @@ +stroke = $stroke; + } + + function stroke( $stroke ) + { + $this->set_stroke( $stroke ); + return $this; + } + + /** + *@param $colour as string HEX colour + *@param $grid_colour as string HEX colour + */ + function set_colours( $colour, $grid_colour ) + { + $this->set_colour( $colour ); + $this->set_grid_colour( $grid_colour ); + } + + /** + *@param $colour as string HEX colour + */ + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function colour( $colour ) + { + $this->set_colour($colour); + return $this; + } + + function set_tick_height( $height ) + { + $tmp = 'tick-height'; + $this->$tmp = $height; + } + + function tick_height( $height ) + { + $this->set_tick_height($height); + return $this; + } + + function set_grid_colour( $colour ) + { + $tmp = 'grid-colour'; + $this->$tmp = $colour; + } + + function grid_colour( $colour ) + { + $this->set_grid_colour($colour); + return $this; + } + + /** + * @param $o is a boolean. If true, the X axis start half a step in + * This defaults to True + */ + function set_offset( $o ) + { + $this->offset = $o?true:false; + } + + function offset( $o ) + { + $this->set_offset($o); + return $this; + } + + /** + * @param $steps as integer. Which grid lines and ticks are visible. + */ + function set_steps( $steps ) + { + $this->steps = $steps; + } + + function steps( $steps ) + { + $this->set_steps($steps); + return $this; + } + + /** + * @param $val as an integer, the height in pixels of the 3D bar. Mostly + * used for the 3D bar chart. + */ + function set_3d( $val ) + { + $tmp = '3d'; + $this->$tmp = $val; + } + + /** + * @param $x_axis_labels as an x_axis_labels object + * Use this to customize the labels (colour, font, etc...) + */ + function set_labels( $x_axis_labels ) + { + //$this->labels = $v; + $this->labels = $x_axis_labels; + } + + /** + * Sugar syntax: helper function to make the examples simpler. + * @param $a is an array of labels + */ + function set_labels_from_array( $a ) + { + $x_axis_labels = new x_axis_labels(); + $x_axis_labels->set_labels( $a ); + $this->labels = $x_axis_labels; + + if( isset( $this->steps ) ) + $x_axis_labels->set_steps( $this->steps ); + } + + /** + * min and max. + */ + function set_range( $min, $max ) + { + $this->min = $min; + $this->max = $max; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_x_axis_label.php b/application/libraries/ofc-library/ofc_x_axis_label.php new file mode 100644 index 000000000..cf116f15f --- /dev/null +++ b/application/libraries/ofc-library/ofc_x_axis_label.php @@ -0,0 +1,45 @@ +set_text( $text ); + $this->set_colour( $colour ); + $this->set_size( $size ); + $this->set_rotate( $rotate ); + } + + function set_text( $text ) + { + $this->text = $text; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_size( $size ) + { + $this->size = $size; + } + + function set_rotate( $rotate ) + { + $this->rotate = $rotate; + } + + function set_vertical() + { + $this->rotate = "vertical"; + } + + function set_visible() + { + $this->visible = true; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_x_axis_labels.php b/application/libraries/ofc-library/ofc_x_axis_labels.php new file mode 100644 index 000000000..af4540f95 --- /dev/null +++ b/application/libraries/ofc-library/ofc_x_axis_labels.php @@ -0,0 +1,69 @@ +steps = $steps; + } + + /** + * @param $steps as integer which labels are visible + */ + function visible_steps( $steps ) + { + $this->{"visible-steps"} = $steps; + return $this; + } + + /** + * + * @param $labels as an array of [x_axis_label or string] + */ + function set_labels( $labels ) + { + $this->labels = $labels; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + /** + * font size in pixels + */ + function set_size( $size ) + { + $this->size = $size; + } + + /** + * rotate labels + */ + function set_vertical() + { + $this->rotate = 270; + } + + /** + * @param @angle as real. The angle of the text. + */ + function rotate( $angle ) + { + $this->rotate = $angle; + } + + /** + * @param $text as string. Replace and magic variables with actual x axis position. + */ + function text( $text ) + { + $this->text = $text; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_x_legend.php b/application/libraries/ofc-library/ofc_x_legend.php new file mode 100644 index 000000000..7a25af0c2 --- /dev/null +++ b/application/libraries/ofc-library/ofc_x_legend.php @@ -0,0 +1,15 @@ +text = $text; + } + + function set_style( $css ) + { + $this->style = $css; + //"{font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;}"; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_y_axis.php b/application/libraries/ofc-library/ofc_y_axis.php new file mode 100644 index 000000000..3846c9285 --- /dev/null +++ b/application/libraries/ofc-library/ofc_y_axis.php @@ -0,0 +1,17 @@ +$tmp = $colour; + } + +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_y_axis_base.php b/application/libraries/ofc-library/ofc_y_axis_base.php new file mode 100644 index 000000000..8093a09e5 --- /dev/null +++ b/application/libraries/ofc-library/ofc_y_axis_base.php @@ -0,0 +1,116 @@ +stroke = $s; + } + + /** + * @param $val as integer. The length of the ticks in pixels + */ + function set_tick_length( $val ) + { + $tmp = 'tick-length'; + $this->$tmp = $val; + } + + function set_colours( $colour, $grid_colour ) + { + $this->set_colour( $colour ); + $this->set_grid_colour( $grid_colour ); + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_grid_colour( $colour ) + { + $tmp = 'grid-colour'; + $this->$tmp = $colour; + } + + /** + * Set min and max values, also (optionally) set the steps value. + * You can reverse the chart by setting min larger than max, e.g. min = 10 + * and max = 0. + * + * @param $min as integer + * @param $max as integer + * @param $steps as integer. + */ + function set_range( $min, $max, $steps=1 ) + { + $this->min = $min; + $this->max = $max; + $this->set_steps( $steps ); + } + + /** + * Sugar for set_range + */ + function range( $min, $max, $steps=1 ) + { + $this->set_range( $min, $max, $steps ); + return $this; + } + + /** + * @param $off as Boolean. If true the Y axis is nudged up half a step. + */ + function set_offset( $off ) + { + $this->offset = $off?1:0; + } + + /** + * @param $y_axis_labels as an y_axis_labels object + * Use this to customize the labels (colour, font, etc...) + */ + function set_labels( $y_axis_labels ) + { + $this->labels = $y_axis_labels; + } + + /** + * Pass in some text for each label. This can contain magic variables "#val#" which + * will get replaced with the value for that Y axis label. Useful for: + * - "£#val#" + * - "#val#%" + * - "#val# million" + * + * @param $text as string. + */ + function set_label_text( $text ) + { + $tmp = new y_axis_labels(); + $tmp->set_text( $text ); + $this->labels = $tmp; + } + + /** + * @param $steps as integer. + * + * Only show every $steps label, e.g. every 10th + */ + function set_steps( $steps ) + { + $this->steps = $steps; + } + + /** + * Make the labels show vertical + */ + function set_vertical() + { + $this->rotate = "vertical"; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_y_axis_label.php b/application/libraries/ofc-library/ofc_y_axis_label.php new file mode 100644 index 000000000..f2616f537 --- /dev/null +++ b/application/libraries/ofc-library/ofc_y_axis_label.php @@ -0,0 +1,38 @@ +y = $y; + $this->set_text( $text ); + } + + function set_text( $text ) + { + $this->text = $text; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + function set_size( $size ) + { + $this->size = $size; + } + + function set_rotate( $rotate ) + { + $this->rotate = $rotate; + } + + function set_vertical() + { + $this->rotate = "vertical"; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_y_axis_labels.php b/application/libraries/ofc-library/ofc_y_axis_labels.php new file mode 100644 index 000000000..c0708ab21 --- /dev/null +++ b/application/libraries/ofc-library/ofc_y_axis_labels.php @@ -0,0 +1,57 @@ +steps = $steps; + } + + /** + * + * @param $labels as an array of [y_axis_label or string] + */ + function set_labels( $labels ) + { + $this->labels = $labels; + } + + function set_colour( $colour ) + { + $this->colour = $colour; + } + + /** + * font size in pixels + */ + function set_size( $size ) + { + $this->size = $size; + } + + /** + * rotate labels + */ + function set_vertical() + { + $this->rotate = 270; + } + + function rotate( $angle ) + { + $this->rotate = $angle; + } + + /** + * @param $text default text that all labels inherit + */ + function set_text( $text ) + { + $this->text = $text; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/ofc_y_axis_right.php b/application/libraries/ofc-library/ofc_y_axis_right.php new file mode 100644 index 000000000..71f7c2984 --- /dev/null +++ b/application/libraries/ofc-library/ofc_y_axis_right.php @@ -0,0 +1,6 @@ +text = $text; + } + + function set_style( $css ) + { + $this->style = $css; + //"{font-size: 20px; color:#0000ff; font-family: Verdana; text-align: center;}"; + } +} \ No newline at end of file diff --git a/application/libraries/ofc-library/open-flash-chart-object.php b/application/libraries/ofc-library/open-flash-chart-object.php new file mode 100644 index 000000000..6e1129f46 --- /dev/null +++ b/application/libraries/ofc-library/open-flash-chart-object.php @@ -0,0 +1,109 @@ +'; + + if( !isset( $open_flash_chart_seqno ) ) + { + $open_flash_chart_seqno = 1; + $out[] = ''; + } + else + { + $open_flash_chart_seqno++; + $obj_id .= '_'. $open_flash_chart_seqno; + $div_name .= '_'. $open_flash_chart_seqno; + } + + if( $use_swfobject ) + { + // Using library for auto-enabling Flash object on IE, disabled-Javascript proof + $out[] = '
'; + $out[] = ''; + $out[] = ''; + } + + return implode("\n",$out); +} +?> \ No newline at end of file diff --git a/application/libraries/ofc-library/open-flash-chart.php b/application/libraries/ofc-library/open-flash-chart.php new file mode 100644 index 000000000..b017097d0 --- /dev/null +++ b/application/libraries/ofc-library/open-flash-chart.php @@ -0,0 +1,178 @@ +title = new title( "Many data lines" ); + $this->elements = array(); + } + + function set_title( $t ) + { + $this->title = $t; + } + + function set_x_axis( $x ) + { + $this->x_axis = $x; + } + + function set_y_axis( $y ) + { + $this->y_axis = $y; + } + + function add_y_axis( $y ) + { + $this->y_axis = $y; + } + + function set_y_axis_right( $y ) + { + $this->y_axis_right = $y; + } + + function add_element( $e ) + { + $this->elements[] = $e; + } + + function set_x_legend( $x ) + { + $this->x_legend = $x; + } + + function set_y_legend( $y ) + { + $this->y_legend = $y; + } + + function set_bg_colour( $colour ) + { + $this->bg_colour = $colour; + } + + function set_radar_axis( $radar ) + { + $this->radar_axis = $radar; + } + + function set_tooltip( $tooltip ) + { + $this->tooltip = $tooltip; + } + + /** + * This is a bit funky :( + * + * @param $num_decimals as integer. Truncate the decimals to $num_decimals, e.g. set it + * to 5 and 3.333333333 will display as 3.33333. 2.0 will display as 2 (or 2.00000 - see below) + * @param $is_fixed_num_decimals_forced as boolean. If true it will pad the decimals. + * @param $is_decimal_separator_comma as boolean + * @param $is_thousand_separator_disabled as boolean + * + * This needs a bit of love and attention + */ + function set_number_format($num_decimals, $is_fixed_num_decimals_forced, $is_decimal_separator_comma, $is_thousand_separator_disabled ) + { + $this->num_decimals = $num_decimals; + $this->is_fixed_num_decimals_forced = $is_fixed_num_decimals_forced; + $this->is_decimal_separator_comma = $is_decimal_separator_comma; + $this->is_thousand_separator_disabled = $is_thousand_separator_disabled; + } + + /** + * This is experimental and will change as we make it work + * + * @param $m as ofc_menu + */ + function set_menu($m) + { + $this->menu = $m; + } + + function toString() + { + if (function_exists('json_encode')) + { + return json_encode($this); + } + else + { + $json = new Services_JSON(); + return $json->encode( $this ); + } + } + + function toPrettyString() + { + return json_format( $this->toString() ); + } +} + + + +// +// there is no PHP end tag so we don't mess the headers up! +// \ No newline at end of file diff --git a/application/logs/index.html b/application/logs/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/logs/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/models/appconfig.php b/application/models/appconfig.php new file mode 100644 index 000000000..6f0879148 --- /dev/null +++ b/application/models/appconfig.php @@ -0,0 +1,81 @@ +db->from('app_config'); + $this->db->where('app_config.key',$key); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + function get_all() + { + $this->db->from('app_config'); + $this->db->order_by("key", "asc"); + return $this->db->get(); + } + + function get($key) + { + $query = $this->db->get_where('app_config', array('key' => $key), 1); + + if($query->num_rows()==1) + { + return $query->row()->value; + } + + return ""; + + } + + function save($key,$value) + { + $config_data=array( + 'key'=>$key, + 'value'=>$value + ); + + if (!$this->exists($key)) + { + return $this->db->insert('app_config',$config_data); + } + + $this->db->where('key', $key); + return $this->db->update('app_config',$config_data); + } + + function batch_save($data) + { + $success=true; + + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + foreach($data as $key=>$value) + { + if(!$this->save($key,$value)) + { + $success=false; + break; + } + } + + $this->db->trans_complete(); + return $success; + + } + + function delete($key) + { + return $this->db->delete('app_config', array('key' => $key)); + } + + function delete_all() + { + return $this->db->empty_table('app_config'); + } +} + +?> \ No newline at end of file diff --git a/application/models/customer.php b/application/models/customer.php new file mode 100644 index 000000000..8b0e54913 --- /dev/null +++ b/application/models/customer.php @@ -0,0 +1,245 @@ +db->from('customers'); + $this->db->join('people', 'people.person_id = customers.person_id'); + $this->db->where('customers.person_id',$person_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + /* + Returns all the customers + */ + function get_all($limit=10000, $offset=0) + { + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->where('deleted',0); + $this->db->order_by("last_name", "asc"); + $this->db->limit($limit); + $this->db->offset($offset); + return $this->db->get(); + } + + function count_all() + { + $this->db->from('customers'); + $this->db->where('deleted',0); + return $this->db->count_all_results(); + } + + /* + Gets information about a particular customer + */ + function get_info($customer_id) + { + $this->db->from('customers'); + $this->db->join('people', 'people.person_id = customers.person_id'); + $this->db->where('customers.person_id',$customer_id); + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object, as $customer_id is NOT an customer + $person_obj=parent::get_info(-1); + + //Get all the fields from customer table + $fields = $this->db->list_fields('customers'); + + //append those fields to base parent object, we we have a complete empty object + foreach ($fields as $field) + { + $person_obj->$field=''; + } + + return $person_obj; + } + } + + /* + Gets information about multiple customers + */ + function get_multiple_info($customer_ids) + { + $this->db->from('customers'); + $this->db->join('people', 'people.person_id = customers.person_id'); + $this->db->where_in('customers.person_id',$customer_ids); + $this->db->order_by("last_name", "asc"); + return $this->db->get(); + } + + /* + Inserts or updates a customer + */ + function save(&$person_data, &$customer_data,$customer_id=false) + { + $success=false; + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + if(parent::save($person_data,$customer_id)) + { + if (!$customer_id or !$this->exists($customer_id)) + { + $customer_data['person_id'] = $person_data['person_id']; + $success = $this->db->insert('customers',$customer_data); + } + else + { + $this->db->where('person_id', $customer_id); + $success = $this->db->update('customers',$customer_data); + } + + } + + $this->db->trans_complete(); + return $success; + } + + /* + Deletes one customer + */ + function delete($customer_id) + { + $this->db->where('person_id', $customer_id); + return $this->db->update('customers', array('deleted' => 1)); + } + + /* + Deletes a list of customers + */ + function delete_list($customer_ids) + { + $this->db->where_in('person_id',$customer_ids); + return $this->db->update('customers', array('deleted' => 1)); + } + + /* + Get search suggestions to find customers + */ + function get_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->where("(first_name LIKE '%".$this->db->escape_like_str($search)."%' or + last_name LIKE '%".$this->db->escape_like_str($search)."%' or + CONCAT(`first_name`,' ',`last_name`) LIKE '%".$this->db->escape_like_str($search)."%') and deleted=0"); + $this->db->order_by("last_name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->first_name.' '.$row->last_name; + } + + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->where('deleted',0); + $this->db->like("email",$search); + $this->db->order_by("email", "asc"); + $by_email = $this->db->get(); + foreach($by_email->result() as $row) + { + $suggestions[]=$row->email; + } + + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->where('deleted',0); + $this->db->like("phone_number",$search); + $this->db->order_by("phone_number", "asc"); + $by_phone = $this->db->get(); + foreach($by_phone->result() as $row) + { + $suggestions[]=$row->phone_number; + } + + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->where('deleted',0); + $this->db->like("account_number",$search); + $this->db->order_by("account_number", "asc"); + $by_account_number = $this->db->get(); + foreach($by_account_number->result() as $row) + { + $suggestions[]=$row->account_number; + } + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + } + + /* + Get search suggestions to find customers + */ + function get_customer_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->where("(first_name LIKE '%".$this->db->escape_like_str($search)."%' or + last_name LIKE '%".$this->db->escape_like_str($search)."%' or + CONCAT(`first_name`,' ',`last_name`) LIKE '%".$this->db->escape_like_str($search)."%') and deleted=0"); + $this->db->order_by("last_name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->person_id.'|'.$row->first_name.' '.$row->last_name; + } + + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->where('deleted',0); + $this->db->like("account_number",$search); + $this->db->order_by("account_number", "asc"); + $by_account_number = $this->db->get(); + foreach($by_account_number->result() as $row) + { + $suggestions[]=$row->person_id.'|'.$row->account_number; + } + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + + } + /* + Preform a search on customers + */ + function search($search) + { + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->where("(first_name LIKE '%".$this->db->escape_like_str($search)."%' or + last_name LIKE '%".$this->db->escape_like_str($search)."%' or + email LIKE '%".$this->db->escape_like_str($search)."%' or + phone_number LIKE '%".$this->db->escape_like_str($search)."%' or + account_number LIKE '%".$this->db->escape_like_str($search)."%' or + CONCAT(`first_name`,' ',`last_name`) LIKE '%".$this->db->escape_like_str($search)."%') and deleted=0"); + $this->db->order_by("last_name", "asc"); + + return $this->db->get(); + } + +} +?> diff --git a/application/models/employee.php b/application/models/employee.php new file mode 100644 index 000000000..e0d0b3606 --- /dev/null +++ b/application/models/employee.php @@ -0,0 +1,325 @@ +db->from('employees'); + $this->db->join('people', 'people.person_id = employees.person_id'); + $this->db->where('employees.person_id',$person_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + /* + Returns all the employees + */ + function get_all($limit=10000, $offset=0) + { + $this->db->from('employees'); + $this->db->where('deleted',0); + $this->db->join('people','employees.person_id=people.person_id'); + $this->db->order_by("last_name", "asc"); + $this->db->limit($limit); + $this->db->offset($offset); + return $this->db->get(); + } + + function count_all() + { + $this->db->from('employees'); + $this->db->where('deleted',0); + return $this->db->count_all_results(); + } + + /* + Gets information about a particular employee + */ + function get_info($employee_id) + { + $this->db->from('employees'); + $this->db->join('people', 'people.person_id = employees.person_id'); + $this->db->where('employees.person_id',$employee_id); + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object, as $employee_id is NOT an employee + $person_obj=parent::get_info(-1); + + //Get all the fields from employee table + $fields = $this->db->list_fields('employees'); + + //append those fields to base parent object, we we have a complete empty object + foreach ($fields as $field) + { + $person_obj->$field=''; + } + + return $person_obj; + } + } + + /* + Gets information about multiple employees + */ + function get_multiple_info($employee_ids) + { + $this->db->from('employees'); + $this->db->join('people', 'people.person_id = employees.person_id'); + $this->db->where_in('employees.person_id',$employee_ids); + $this->db->order_by("last_name", "asc"); + return $this->db->get(); + } + + /* + Inserts or updates an employee + */ + function save(&$person_data, &$employee_data,&$permission_data,$employee_id=false) + { + $success=false; + + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + if(parent::save($person_data,$employee_id)) + { + if (!$employee_id or !$this->exists($employee_id)) + { + $employee_data['person_id'] = $employee_id = $person_data['person_id']; + $success = $this->db->insert('employees',$employee_data); + } + else + { + $this->db->where('person_id', $employee_id); + $success = $this->db->update('employees',$employee_data); + } + + //We have either inserted or updated a new employee, now lets set permissions. + if($success) + { + //First lets clear out any permissions the employee currently has. + $success=$this->db->delete('permissions', array('person_id' => $employee_id)); + + //Now insert the new permissions + if($success) + { + foreach($permission_data as $allowed_module) + { + $success = $this->db->insert('permissions', + array( + 'module_id'=>$allowed_module, + 'person_id'=>$employee_id)); + } + } + } + + } + + $this->db->trans_complete(); + return $success; + } + + /* + Deletes one employee + */ + function delete($employee_id) + { + $success=false; + + //Don't let employee delete their self + if($employee_id==$this->get_logged_in_employee_info()->person_id) + return false; + + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + //Delete permissions + if($this->db->delete('permissions', array('person_id' => $employee_id))) + { + $this->db->where('person_id', $employee_id); + $success = $this->db->update('employees', array('deleted' => 1)); + } + $this->db->trans_complete(); + return $success; + } + + /* + Deletes a list of employees + */ + function delete_list($employee_ids) + { + $success=false; + + //Don't let employee delete their self + if(in_array($this->get_logged_in_employee_info()->person_id,$employee_ids)) + return false; + + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + $this->db->where_in('person_id',$employee_ids); + //Delete permissions + if ($this->db->delete('permissions')) + { + //delete from employee table + $this->db->where_in('person_id',$employee_ids); + $success = $this->db->update('employees', array('deleted' => 1)); + } + $this->db->trans_complete(); + return $success; + } + + /* + Get search suggestions to find employees + */ + function get_search_suggestions($search,$limit=5) + { + $suggestions = array(); + + $this->db->from('employees'); + $this->db->join('people','employees.person_id=people.person_id'); + $this->db->where("(first_name LIKE '%".$this->db->escape_like_str($search)."%' or + last_name LIKE '%".$this->db->escape_like_str($search)."%' or + CONCAT(`first_name`,' ',`last_name`) LIKE '%".$this->db->escape_like_str($search)."%') and deleted=0"); + $this->db->order_by("last_name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->first_name.' '.$row->last_name; + } + + $this->db->from('employees'); + $this->db->join('people','employees.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->like("email",$search); + $this->db->order_by("email", "asc"); + $by_email = $this->db->get(); + foreach($by_email->result() as $row) + { + $suggestions[]=$row->email; + } + + $this->db->from('employees'); + $this->db->join('people','employees.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->like("username",$search); + $this->db->order_by("username", "asc"); + $by_username = $this->db->get(); + foreach($by_username->result() as $row) + { + $suggestions[]=$row->username; + } + + + $this->db->from('employees'); + $this->db->join('people','employees.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->like("phone_number",$search); + $this->db->order_by("phone_number", "asc"); + $by_phone = $this->db->get(); + foreach($by_phone->result() as $row) + { + $suggestions[]=$row->phone_number; + } + + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + + } + + /* + Preform a search on employees + */ + function search($search) + { + $this->db->from('employees'); + $this->db->join('people','employees.person_id=people.person_id'); + $this->db->where("(first_name LIKE '%".$this->db->escape_like_str($search)."%' or + last_name LIKE '%".$this->db->escape_like_str($search)."%' or + email LIKE '%".$this->db->escape_like_str($search)."%' or + phone_number LIKE '%".$this->db->escape_like_str($search)."%' or + username LIKE '%".$this->db->escape_like_str($search)."%' or + CONCAT(`first_name`,' ',`last_name`) LIKE '%".$this->db->escape_like_str($search)."%') and deleted=0"); + $this->db->order_by("last_name", "asc"); + + return $this->db->get(); + } + + /* + Attempts to login employee and set session. Returns boolean based on outcome. + */ + function login($username, $password) + { + $query = $this->db->get_where('employees', array('username' => $username,'password'=>md5($password), 'deleted'=>0), 1); + if ($query->num_rows() ==1) + { + $row=$query->row(); + $this->session->set_userdata('person_id', $row->person_id); + return true; + } + return false; + } + + /* + Logs out a user by destorying all session data and redirect to login + */ + function logout() + { + $this->session->sess_destroy(); + redirect('login'); + } + + /* + Determins if a employee is logged in + */ + function is_logged_in() + { + return $this->session->userdata('person_id')!=false; + } + + /* + Gets information about the currently logged in employee. + */ + function get_logged_in_employee_info() + { + if($this->is_logged_in()) + { + return $this->get_info($this->session->userdata('person_id')); + } + + return false; + } + + /* + Determins whether the employee specified employee has access the specific module. + */ + function has_permission($module_id,$person_id) + { + //if no module_id is null, allow access + if($module_id==null) + { + return true; + } + + $query = $this->db->get_where('permissions', array('person_id' => $person_id,'module_id'=>$module_id), 1); + return $query->num_rows() == 1; + + + return false; + } + +} +?> diff --git a/application/models/giftcard.php b/application/models/giftcard.php new file mode 100644 index 000000000..5c3f2d673 --- /dev/null +++ b/application/models/giftcard.php @@ -0,0 +1,255 @@ +db->from('giftcards'); + $this->db->where('giftcard_id',$giftcard_id); + $this->db->where('deleted',0); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + /* + Returns all the giftcards + */ + function get_all($limit=10000, $offset=0) + { + $this->db->from('giftcards'); + $this->db->join('people','people.person_id=giftcards.person_id');//GARRISON ADDED 4/25/2013 + $this->db->where('deleted',0); + $this->db->order_by("giftcard_number", "asc"); + $this->db->limit($limit); + $this->db->offset($offset); + return $this->db->get(); + } + + function count_all() + { + $this->db->from('giftcards'); + $this->db->where('deleted',0); + return $this->db->count_all_results(); + } + + /* + Gets information about a particular giftcard + */ + function get_info($giftcard_id) + { + $this->db->from('giftcards'); + $this->db->where('giftcard_id',$giftcard_id); + $this->db->where('deleted',0); + + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object, as $giftcard_id is NOT an giftcard + $giftcard_obj=new stdClass(); + + //Get all the fields from giftcards table + $fields = $this->db->list_fields('giftcards'); + + foreach ($fields as $field) + { + $giftcard_obj->$field=''; + } + + return $giftcard_obj; + } + } + + /* + Get an giftcard id given an giftcard number + */ + function get_giftcard_id($giftcard_number) + { + $this->db->from('giftcards'); + $this->db->where('giftcard_number',$giftcard_number); + $this->db->where('deleted',0); + + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row()->giftcard_id; + } + + return false; + } + + /* + Gets information about multiple giftcards + */ + function get_multiple_info($giftcard_ids) + { + $this->db->from('giftcards'); + $this->db->where_in('giftcard_id',$giftcard_ids); + $this->db->where('deleted',0); + $this->db->order_by("giftcard_number", "asc"); + return $this->db->get(); + } + + /* + Inserts or updates a giftcard + */ + function save(&$giftcard_data,$giftcard_id=false) + { + if (!$giftcard_id or !$this->exists($giftcard_id)) + { + if($this->db->insert('giftcards',$giftcard_data)) + { + $giftcard_data['giftcard_id']=$this->db->insert_id(); + return true; + } + return false; + } + + $this->db->where('giftcard_id', $giftcard_id); + return $this->db->update('giftcards',$giftcard_data); + } + + /* + Updates multiple giftcards at once + */ + function update_multiple($giftcard_data,$giftcard_ids) + { + $this->db->where_in('giftcard_id',$giftcard_ids); + return $this->db->update('giftcards',$giftcard_data); + } + + /* + Deletes one giftcard + */ + function delete($giftcard_id) + { + $this->db->where('giftcard_id', $giftcard_id); + return $this->db->update('giftcards', array('deleted' => 1)); + } + + /* + Deletes a list of giftcards + */ + function delete_list($giftcard_ids) + { + $this->db->where_in('giftcard_id',$giftcard_ids); + return $this->db->update('giftcards', array('deleted' => 1)); + } + + /* + Get search suggestions to find giftcards + */ + function get_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->from('giftcards'); + $this->db->like('giftcard_number', $search); + $this->db->where('deleted',0); + $this->db->order_by("giftcard_number", "asc"); + $by_number = $this->db->get(); + + foreach($by_number->result() as $row) + { + $suggestions[]=$row->giftcard_number; + } + +/** GARRISON MODIFIED 4/24/2013 **/ + $this->db->from('customers'); + $this->db->join('people','customers.person_id=people.person_id'); + $this->db->like("first_name",$this->db->escape_like_str($search)); + $this->db->or_like("last_name",$this->db->escape_like_str($search)); + $this->db->or_like("CONCAT(`first_name`,' ',`last_name`)",$this->db->escape_like_str($search)); + $this->db->where("deleted","0"); + $this->db->order_by("last_name", "asc"); + $by_name = $this->db->get(); + + foreach($by_name->result() as $row) + { + $suggestions[]=$row->first_name.' '.$row->last_name; + } +/** END GARRISON MODIFIED **/ + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + } + + /** GARRISON ADDED 5/3/2013 **/ + /* + Get search suggestions to find customers + */ + function get_person_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->select('person_id'); + $this->db->from('people'); + $this->db->like('person_id',$this->db->escape_like_str($search)); + $this->db->or_like('first_name',$this->db->escape_like_str($search)); + $this->db->or_like('last_name',$this->db->escape_like_str($search)); + $this->db->or_like("CONCAT(`first_name`,' ',`last_name`)",$this->db->escape_like_str($search)); + $this->db->or_like('email',$this->db->escape_like_str($search)); + $this->db->or_like('phone_number',$this->db->escape_like_str($search)); + $this->db->order_by('person_id', 'asc'); + $by_person_id = $this->db->get(); + + foreach($by_person_id->result() as $row) + { + $suggestions[]=$row->person_id; + } + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + } + +/** GARRISON MODIFIED 4/24/2013 **/ + /* + Preform a search on giftcards + */ + function search($search) + { + $this->db->from('giftcards'); + $this->db->join('people','giftcards.person_id=people.person_id'); + $this->db->like("first_name",$this->db->escape_like_str($search)); + $this->db->or_like("last_name",$this->db->escape_like_str($search)); + $this->db->or_like("CONCAT(`first_name`,' ',`last_name`)",$this->db->escape_like_str($search)); + $this->db->or_like("giftcard_number",$this->db->escape_like_str($search)); + $this->db->or_like("giftcards.person_id",$this->db->escape_like_str($search)); + $this->db->where('deleted',$this->db->escape('0')); + $this->db->order_by("giftcard_number", "asc"); + return $this->db->get(); + } + + public function get_giftcard_value( $giftcard_number ) + { + if ( !$this->exists( $this->get_giftcard_id($giftcard_number))) + return 0; + + $this->db->from('giftcards'); + $this->db->where('giftcard_number',$giftcard_number); + return $this->db->get()->row()->value; + } + + function update_giftcard_value( $giftcard_number, $value ) + { + $this->db->where('giftcard_number', $giftcard_number); + $this->db->update('giftcards', array('value' => $value)); + } +} +?> diff --git a/application/models/index.html b/application/models/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/models/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/models/inventory.php b/application/models/inventory.php new file mode 100644 index 000000000..2c18e0277 --- /dev/null +++ b/application/models/inventory.php @@ -0,0 +1,18 @@ +db->insert('inventory',$inventory_data); + } + + function get_inventory_data_for_item($item_id) + { + $this->db->from('inventory'); + $this->db->where('trans_items',$item_id); + $this->db->order_by("trans_date", "desc"); + return $this->db->get(); + } +} + +?> \ No newline at end of file diff --git a/application/models/item.php b/application/models/item.php new file mode 100644 index 000000000..d1a7aa51c --- /dev/null +++ b/application/models/item.php @@ -0,0 +1,579 @@ +db->from('items'); + $this->db->where('item_id',$item_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + /* + Returns all the items + */ + function get_all($limit=10000, $offset=0) + { + $this->db->from('items'); + $this->db->where('deleted',0); + $this->db->order_by("name", "asc"); + $this->db->limit($limit); + $this->db->offset($offset); + return $this->db->get(); + } + + function count_all() + { + $this->db->from('items'); + $this->db->where('deleted',0); + return $this->db->count_all_results(); + } + + function get_all_filtered($low_inventory=0,$is_serialized=0,$no_description,$search_custom)/**GARRISON MODIFIED 4/21/2013**/ + { + $this->db->from('items'); + if ($low_inventory !=0 ) + { + $this->db->where('quantity <=','reorder_level', false); + } + if ($is_serialized !=0 ) + { + $this->db->where('is_serialized',1); + } + if ($no_description!=0 ) + { + $this->db->where('description',''); + } +/**GARRISON SECTION ADDED 4/21/2013**/ +/** + if ($search_custom!=0 ) + { + $this->db->like('custom1',$search); + $this->db->or_like('custom2',$search); + $this->db->or_like('custom3',$search); + $this->db->or_like('custom4',$search); + $this->db->or_like('custom5',$search); + $this->db->or_like('custom6',$search); + $this->db->or_like('custom7',$search); + $this->db->or_like('custom8',$search); + $this->db->or_like('custom9',$search); + $this->db->or_like('custom10',$search); + } +**/ + $this->db->where('deleted',0); + $this->db->order_by("name", "asc"); + return $this->db->get(); + } + + /* + Gets information about a particular item + */ + function get_info($item_id) + { + $this->db->from('items'); + $this->db->where('item_id',$item_id); + + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object, as $item_id is NOT an item + $item_obj=new stdClass(); + + //Get all the fields from items table + $fields = $this->db->list_fields('items'); + + foreach ($fields as $field) + { + $item_obj->$field=''; + } + + return $item_obj; + } + } + + /* + Get an item id given an item number + */ + function get_item_id($item_number) + { + $this->db->from('items'); + $this->db->where('item_number',$item_number); + + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row()->item_id; + } + + return false; + } + + /* + Gets information about multiple items + */ + function get_multiple_info($item_ids) + { + $this->db->from('items'); + $this->db->where_in('item_id',$item_ids); + $this->db->order_by("item", "asc"); + return $this->db->get(); + } + + /* + Inserts or updates a item + */ + function save(&$item_data,$item_id=false) + { + if (!$item_id or !$this->exists($item_id)) + { + if($this->db->insert('items',$item_data)) + { + $item_data['item_id']=$this->db->insert_id(); + return true; + } + return false; + } + + $this->db->where('item_id', $item_id); + return $this->db->update('items',$item_data); + } + + /* + Updates multiple items at once + */ + function update_multiple($item_data,$item_ids) + { + $this->db->where_in('item_id',$item_ids); + return $this->db->update('items',$item_data); + } + + /* + Deletes one item + */ + function delete($item_id) + { + $this->db->where('item_id', $item_id); + return $this->db->update('items', array('deleted' => 1)); + } + + /* + Deletes a list of items + */ + function delete_list($item_ids) + { + $this->db->where_in('item_id',$item_ids); + return $this->db->update('items', array('deleted' => 1)); + } + + /* + Get search suggestions to find items + */ + function get_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->from('items'); + $this->db->like('name', $search); + $this->db->where('deleted',0); + $this->db->order_by("name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->name; + } + + $this->db->select('category'); + $this->db->from('items'); + $this->db->where('deleted',0); + $this->db->distinct(); + $this->db->like('category', $search); + $this->db->order_by("category", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->category; + } + + $this->db->from('items'); + $this->db->like('item_number', $search); + $this->db->where('deleted',0); + $this->db->order_by("item_number", "asc"); + $by_item_number = $this->db->get(); + foreach($by_item_number->result() as $row) + { + $suggestions[]=$row->item_number; + } +/** GARRISON ADDED 4/21/2013 **/ + //Search by description + $this->db->from('items'); + $this->db->like('description', $search); + $this->db->where('deleted',0); + $this->db->order_by("description", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->name; + } +/** END GARRISON ADDED **/ + +/** GARRISON ADDED 4/22/2013 **/ + //Search by custom fields + $this->db->from('items'); + $this->db->like('custom1', $search); + $this->db->or_like('custom2', $search); + $this->db->or_like('custom3', $search); + $this->db->or_like('custom4', $search); + $this->db->or_like('custom5', $search); + $this->db->or_like('custom6', $search); + $this->db->or_like('custom7', $search); + $this->db->or_like('custom8', $search); + $this->db->or_like('custom9', $search); + $this->db->or_like('custom10', $search); + $this->db->where('deleted',0); + $this->db->order_by("name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->name; + } +/** END GARRISON ADDED **/ + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + + } + + function get_item_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->from('items'); + $this->db->where('deleted',0); + $this->db->like('name', $search); + $this->db->order_by("name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->item_id.'|'.$row->name; + } + + $this->db->from('items'); + $this->db->where('deleted',0); + $this->db->like('item_number', $search); + $this->db->order_by("item_number", "asc"); + $by_item_number = $this->db->get(); + foreach($by_item_number->result() as $row) + { + $suggestions[]=$row->item_id.'|'.$row->item_number; + } +/** GARRISON ADDED 4/21/2013 **/ + //Search by description + $this->db->from('items'); + $this->db->where('deleted',0); + $this->db->like('description', $search); + $this->db->order_by("description", "asc"); + $by_description = $this->db->get(); + foreach($by_description->result() as $row) + { + $suggestions[]=$row->item_id.'|'.$row->name; + } +/** END GARRISON ADDED **/ + /** GARRISON ADDED 4/22/2013 **/ + //Search by custom fields + $this->db->from('items'); + $this->db->where('deleted',0); + $this->db->like('custom1', $search); + $this->db->or_like('custom2', $search); + $this->db->or_like('custom3', $search); + $this->db->or_like('custom4', $search); + $this->db->or_like('custom5', $search); + $this->db->or_like('custom6', $search); + $this->db->or_like('custom7', $search); + $this->db->or_like('custom8', $search); + $this->db->or_like('custom9', $search); + $this->db->or_like('custom10', $search); + $this->db->order_by("name", "asc"); + $by_description = $this->db->get(); + foreach($by_description->result() as $row) + { + $suggestions[]=$row->item_id.'|'.$row->name; + } + /** END GARRISON ADDED **/ + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + } + + function get_category_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('category'); + $this->db->from('items'); + $this->db->like('category', $search); + $this->db->where('deleted', 0); + $this->db->order_by("category", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->category; + } + + return $suggestions; + } + +/** GARRISON ADDED 5/18/2013 **/ + function get_location_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('location'); + $this->db->from('items'); + $this->db->like('location', $search); + $this->db->where('deleted', 0); + $this->db->order_by("location", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->location; + } + + return $suggestions; + } + + function get_custom1_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom1'); + $this->db->from('items'); + $this->db->like('custom1', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom1", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom1; + } + + return $suggestions; + } + + function get_custom2_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom2'); + $this->db->from('items'); + $this->db->like('custom2', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom2", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom2; + } + + return $suggestions; + } + + function get_custom3_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom3'); + $this->db->from('items'); + $this->db->like('custom3', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom3", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom3; + } + + return $suggestions; + } + + function get_custom4_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom4'); + $this->db->from('items'); + $this->db->like('custom4', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom4", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom4; + } + + return $suggestions; + } + + function get_custom5_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom5'); + $this->db->from('items'); + $this->db->like('custom5', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom5", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom5; + } + + return $suggestions; + } + + function get_custom6_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom6'); + $this->db->from('items'); + $this->db->like('custom6', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom6", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom6; + } + + return $suggestions; + } + + function get_custom7_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom7'); + $this->db->from('items'); + $this->db->like('custom7', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom7", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom7; + } + + return $suggestions; + } + + function get_custom8_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom8'); + $this->db->from('items'); + $this->db->like('custom8', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom8", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom8; + } + + return $suggestions; + } + + function get_custom9_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom9'); + $this->db->from('items'); + $this->db->like('custom9', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom9", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom9; + } + + return $suggestions; + } + + function get_custom10_suggestions($search) + { + $suggestions = array(); + $this->db->distinct(); + $this->db->select('custom10'); + $this->db->from('items'); + $this->db->like('custom10', $search); + $this->db->where('deleted', 0); + $this->db->order_by("custom10", "asc"); + $by_category = $this->db->get(); + foreach($by_category->result() as $row) + { + $suggestions[]=$row->custom10; + } + + return $suggestions; + } +/** END GARRISON ADDED **/ + /* + Preform a search on items + */ + function search($search) + { + $this->db->from('items'); + $this->db->where("( + name LIKE '%".$this->db->escape_like_str($search)."%' or + item_number LIKE '%".$this->db->escape_like_str($search)."%' or + description LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/21/2013**/ + custom1 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom2 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom3 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom4 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom5 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom6 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom7 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom8 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom9 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + custom10 LIKE '%".$this->db->escape_like_str($search)."%' or/**GARRISON ADDED 4/22/2013**/ + category LIKE '%".$this->db->escape_like_str($search)."%') and + deleted=0"); + $this->db->order_by("name", "asc"); + return $this->db->get(); + } + + function get_categories() + { + $this->db->select('category'); + $this->db->from('items'); + $this->db->where('deleted',0); + $this->db->distinct(); + $this->db->order_by("category", "asc"); + + return $this->db->get(); + } +} +?> diff --git a/application/models/item_kit.php b/application/models/item_kit.php new file mode 100644 index 000000000..84fcc7807 --- /dev/null +++ b/application/models/item_kit.php @@ -0,0 +1,171 @@ +db->from('item_kits'); + $this->db->where('item_kit_id',$item_kit_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + /* + Returns all the item kits + */ + function get_all($limit=10000, $offset=0) + { + $this->db->from('item_kits'); + $this->db->order_by("name", "asc"); + $this->db->limit($limit); + $this->db->offset($offset); + return $this->db->get(); + } + + function count_all() + { + $this->db->from('item_kits'); + return $this->db->count_all_results(); + } + + /* + Gets information about a particular item kit + */ + function get_info($item_kit_id) + { + $this->db->from('item_kits'); + $this->db->where('item_kit_id',$item_kit_id); + + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object, as $item_kit_id is NOT an item kit + $item_obj=new stdClass(); + + //Get all the fields from items table + $fields = $this->db->list_fields('item_kits'); + + foreach ($fields as $field) + { + $item_obj->$field=''; + } + + return $item_obj; + } + } + + /* + Gets information about multiple item kits + */ + function get_multiple_info($item_kit_ids) + { + $this->db->from('item_kits'); + $this->db->where_in('item_kit_id',$item_kit_ids); + $this->db->order_by("name", "asc"); + return $this->db->get(); + } + + /* + Inserts or updates an item kit + */ + function save(&$item_kit_data,$item_kit_id=false) + { + if (!$item_kit_id or !$this->exists($item_kit_id)) + { + if($this->db->insert('item_kits',$item_kit_data)) + { + $item_kit_data['item_kit_id']=$this->db->insert_id(); + return true; + } + return false; + } + + $this->db->where('item_kit_id', $item_kit_id); + return $this->db->update('item_kits',$item_kit_data); + } + + /* + Deletes one item kit + */ + function delete($item_kit_id) + { + return $this->db->delete('item_kits', array('item_kit_id' => $id)); + } + + /* + Deletes a list of item kits + */ + function delete_list($item_kit_ids) + { + $this->db->where_in('item_kit_id',$item_kit_ids); + return $this->db->delete('item_kits'); + } + + /* + Get search suggestions to find kits + */ + function get_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->from('item_kits'); + $this->db->like('name', $search); + $this->db->order_by("name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->name; + } + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + + } + + function get_item_kit_search_suggestions($search, $limit=25) + { + $suggestions = array(); + + $this->db->from('item_kits'); + $this->db->like('name', $search); + $this->db->order_by("name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]='KIT '.$row->item_kit_id.'|'.$row->name; + } + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + + } + + /* + Preform a search on items + */ + function search($search) + { + $this->db->from('item_kits'); + $this->db->where("name LIKE '%".$this->db->escape_like_str($search)."%' or + description LIKE '%".$this->db->escape_like_str($search)."%'"); + $this->db->order_by("name", "asc"); + return $this->db->get(); + } +} +?> \ No newline at end of file diff --git a/application/models/item_kit_items.php b/application/models/item_kit_items.php new file mode 100644 index 000000000..e69598b7e --- /dev/null +++ b/application/models/item_kit_items.php @@ -0,0 +1,43 @@ +db->from('item_kit_items'); + $this->db->where('item_kit_id',$item_kit_id); + //return an array of item kit items for an item + return $this->db->get()->result_array(); + } + + /* + Inserts or updates an item kit's items + */ + function save(&$item_kit_items_data, $item_kit_id) + { + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + $this->delete($item_kit_id); + + foreach ($item_kit_items_data as $row) + { + $row['item_kit_id'] = $item_kit_id; + $this->db->insert('item_kit_items',$row); + } + + $this->db->trans_complete(); + return true; + } + + /* + Deletes item kit items given an item kit + */ + function delete($item_kit_id) + { + return $this->db->delete('item_kit_items', array('item_kit_id' => $item_kit_id)); + } +} +?> diff --git a/application/models/item_taxes.php b/application/models/item_taxes.php new file mode 100644 index 000000000..18033baa7 --- /dev/null +++ b/application/models/item_taxes.php @@ -0,0 +1,51 @@ +db->from('items_taxes'); + $this->db->where('item_id',$item_id); + //return an array of taxes for an item + return $this->db->get()->result_array(); + } + + /* + Inserts or updates an item's taxes + */ + function save(&$items_taxes_data, $item_id) + { + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + $this->delete($item_id); + + foreach ($items_taxes_data as $row) + { + $row['item_id'] = $item_id; + $this->db->insert('items_taxes',$row); + } + + $this->db->trans_complete(); + return true; + } + + function save_multiple(&$items_taxes_data, $item_ids) + { + foreach($item_ids as $item_id) + { + $this->save($items_taxes_data, $item_id); + } + } + + /* + Deletes taxes given an item + */ + function delete($item_id) + { + return $this->db->delete('items_taxes', array('item_id' => $item_id)); + } +} +?> diff --git a/application/models/module.php b/application/models/module.php new file mode 100644 index 000000000..1e14c6d85 --- /dev/null +++ b/application/models/module.php @@ -0,0 +1,50 @@ +db->get_where('modules', array('module_id' => $module_id), 1); + + if ($query->num_rows() ==1) + { + $row = $query->row(); + return $this->lang->line($row->name_lang_key); + } + + return $this->lang->line('error_unknown'); + } + + function get_module_desc($module_id) + { + $query = $this->db->get_where('modules', array('module_id' => $module_id), 1); + if ($query->num_rows() ==1) + { + $row = $query->row(); + return $this->lang->line($row->desc_lang_key); + } + + return $this->lang->line('error_unknown'); + } + + function get_all_modules() + { + $this->db->from('modules'); + $this->db->order_by("sort", "asc"); + return $this->db->get(); + } + + function get_allowed_modules($person_id) + { + $this->db->from('modules'); + $this->db->join('permissions','permissions.module_id=modules.module_id'); + $this->db->where("permissions.person_id",$person_id); + $this->db->order_by("sort", "asc"); + return $this->db->get(); + } +} +?> diff --git a/application/models/person.php b/application/models/person.php new file mode 100644 index 000000000..ba87d8bc0 --- /dev/null +++ b/application/models/person.php @@ -0,0 +1,137 @@ +db->from('people'); + $this->db->where('people.person_id',$person_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + /*Gets all people*/ + function get_all($limit=10000, $offset=0) + { + $this->db->from('people'); + $this->db->order_by("last_name", "asc"); + $this->db->limit($limit); + $this->db->offset($offset); + return $this->db->get(); + } + + function count_all() + { + $this->db->from('people'); + $this->db->where('deleted',0); + return $this->db->count_all_results(); + } + + /* + Gets information about a person as an array. + */ + function get_info($person_id) + { + $query = $this->db->get_where('people', array('person_id' => $person_id), 1); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //create object with empty properties. + $fields = $this->db->list_fields('people'); + $person_obj = new stdClass; + + foreach ($fields as $field) + { + $person_obj->$field=''; + } + + return $person_obj; + } + } + + /* + Get people with specific ids + */ + function get_multiple_info($person_ids) + { + $this->db->from('people'); + $this->db->where_in('person_id',$person_ids); + $this->db->order_by("last_name", "asc"); + return $this->db->get(); + } + + /* + Inserts or updates a person + */ + function save(&$person_data,$person_id=false) + { + if (!$person_id or !$this->exists($person_id)) + { + if ($this->db->insert('people',$person_data)) + { + $person_data['person_id']=$this->db->insert_id(); + return true; + } + + return false; + } + + $this->db->where('person_id', $person_id); + return $this->db->update('people',$person_data); + } +/** GARRISON ADDED 4/25/2013 IN PROGRESS **/ + /* + Get search suggestions to find customers + */ + function get_search_suggestions($search,$limit=25) + { + $suggestions = array(); + +// $this->db->select("person_id"); +// $this->db->from('people'); +// $this->db->where('deleted',0); +// $this->db->where('person_id',$this->db->escape($search)); +// $this->db->like('first_name',$this->db->escape_like_str($search)); +// $this->db->or_like('last_name',$this->db->escape_like_str($search)); +// $this->db->or_like("CONCAT(`first_name`,' ',`last_name`)",$this->db->escape_like_str($search)); +// $this->db->or_like('email',$search); +// $this->db->or_like('phone_number',$search); +// $this->db->order_by('last_name', "asc"); + $by_person_id = $this->db->get(); + + foreach($by_person_id->result() as $row) + { + $suggestions[]=$row->person_id; + } + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + } + + /* + Deletes one Person (doesn't actually do anything) + */ + function delete($person_id) + { + return true;; + } + + /* + Deletes a list of people (doesn't actually do anything) + */ + function delete_list($person_ids) + { + return true; + } + +} +?> diff --git a/application/models/receiving.php b/application/models/receiving.php new file mode 100644 index 000000000..e47f46348 --- /dev/null +++ b/application/models/receiving.php @@ -0,0 +1,118 @@ +db->from('receivings'); + $this->db->where('receiving_id',$receiving_id); + return $this->db->get(); + } + + function exists($receiving_id) + { + $this->db->from('receivings'); + $this->db->where('receiving_id',$receiving_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + function save ($items,$supplier_id,$employee_id,$comment,$payment_type,$receiving_id=false) + { + if(count($items)==0) + return -1; + + $receivings_data = array( + 'supplier_id'=> $this->Supplier->exists($supplier_id) ? $supplier_id : null, + 'employee_id'=>$employee_id, + 'payment_type'=>$payment_type, + 'comment'=>$comment + ); + + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + $this->db->insert('receivings',$receivings_data); + $receiving_id = $this->db->insert_id(); + + + foreach($items as $line=>$item) + { + $cur_item_info = $this->Item->get_info($item['item_id']); + + $receivings_items_data = array + ( + 'receiving_id'=>$receiving_id, + 'item_id'=>$item['item_id'], + 'line'=>$item['line'], + 'description'=>$item['description'], + 'serialnumber'=>$item['serialnumber'], + 'quantity_purchased'=>$item['quantity'], + 'discount_percent'=>$item['discount'], + 'item_cost_price' => $cur_item_info->cost_price, + 'item_unit_price'=>$item['price'] + ); + + $this->db->insert('receivings_items',$receivings_items_data); + + //Update stock quantity + $item_data = array('quantity'=>$cur_item_info->quantity + $item['quantity']); + $this->Item->save($item_data,$item['item_id']); + + $qty_recv = $item['quantity']; + $recv_remarks ='RECV '.$receiving_id; + $inv_data = array + ( + 'trans_date'=>date('Y-m-d H:i:s'), + 'trans_items'=>$item['item_id'], + 'trans_user'=>$employee_id, + 'trans_comment'=>$recv_remarks, + 'trans_inventory'=>$qty_recv + ); + $this->Inventory->insert($inv_data); + + $supplier = $this->Supplier->get_info($supplier_id); + } + $this->db->trans_complete(); + + if ($this->db->trans_status() === FALSE) + { + return -1; + } + + return $receiving_id; + } + + function get_receiving_items($receiving_id) + { + $this->db->from('receivings_items'); + $this->db->where('receiving_id',$receiving_id); + return $this->db->get(); + } + + function get_supplier($receiving_id) + { + $this->db->from('receivings'); + $this->db->where('receiving_id',$receiving_id); + return $this->Supplier->get_info($this->db->get()->row()->supplier_id); + } + + //We create a temp table that allows us to do easy report/receiving queries + public function create_receivings_items_temp_table() + { + $this->db->query("CREATE TEMPORARY TABLE ".$this->db->dbprefix('receivings_items_temp')." + (SELECT date(receiving_time) as receiving_date, ".$this->db->dbprefix('receivings_items').".receiving_id, comment,payment_type, employee_id, + ".$this->db->dbprefix('items').".item_id, ".$this->db->dbprefix('receivings').".supplier_id, quantity_purchased, item_cost_price, item_unit_price, + discount_percent, (item_unit_price*quantity_purchased-item_unit_price*quantity_purchased*discount_percent/100) as subtotal, + ".$this->db->dbprefix('receivings_items').".line as line, serialnumber, ".$this->db->dbprefix('receivings_items').".description as description, + ROUND((item_unit_price*quantity_purchased-item_unit_price*quantity_purchased*discount_percent/100),2) as total, + (item_unit_price*quantity_purchased-item_unit_price*quantity_purchased*discount_percent/100) - (item_cost_price*quantity_purchased) as profit + FROM ".$this->db->dbprefix('receivings_items')." + INNER JOIN ".$this->db->dbprefix('receivings')." ON ".$this->db->dbprefix('receivings_items').'.receiving_id='.$this->db->dbprefix('receivings').'.receiving_id'." + INNER JOIN ".$this->db->dbprefix('items')." ON ".$this->db->dbprefix('receivings_items').'.item_id='.$this->db->dbprefix('items').'.item_id'." + GROUP BY receiving_id, item_id, line)"); + } + + +} +?> diff --git a/application/models/reports/detailed_receivings.php b/application/models/reports/detailed_receivings.php new file mode 100644 index 000000000..0af71d504 --- /dev/null +++ b/application/models/reports/detailed_receivings.php @@ -0,0 +1,67 @@ + array($this->lang->line('reports_receiving_id'), $this->lang->line('reports_date'), $this->lang->line('reports_items_received'), $this->lang->line('reports_received_by'), $this->lang->line('reports_supplied_by'), $this->lang->line('reports_total'), $this->lang->line('reports_payment_type'), $this->lang->line('reports_comments')), + 'details' => array($this->lang->line('reports_name'), $this->lang->line('reports_category'), $this->lang->line('reports_quantity_purchased'), $this->lang->line('reports_total'), $this->lang->line('reports_discount')) + ); + } + + public function getData(array $inputs) + { + $this->db->select('receiving_id, receiving_date, sum(quantity_purchased) as items_purchased, CONCAT(employee.first_name," ",employee.last_name) as employee_name, CONCAT(supplier.first_name," ",supplier.last_name) as supplier_name, sum(total) as total, sum(profit) as profit, payment_type, comment', false); + $this->db->from('receivings_items_temp'); + $this->db->join('people as employee', 'receivings_items_temp.employee_id = employee.person_id'); + $this->db->join('people as supplier', 'receivings_items_temp.supplier_id = supplier.person_id', 'left'); + $this->db->where('receiving_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('receiving_id'); + $this->db->order_by('receiving_date'); + + $data = array(); + $data['summary'] = $this->db->get()->result_array(); + $data['details'] = array(); + + foreach($data['summary'] as $key=>$value) + { + $this->db->select('name, category, quantity_purchased, serialnumber,total, discount_percent'); + $this->db->from('receivings_items_temp'); + $this->db->join('items', 'receivings_items_temp.item_id = items.item_id'); + $this->db->where('receiving_id = '.$value['receiving_id']); + $data['details'][$key] = $this->db->get()->result_array(); + } + + return $data; + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(total) as total'); + $this->db->from('receivings_items_temp'); + $this->db->where('receiving_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/detailed_sales.php b/application/models/reports/detailed_sales.php new file mode 100644 index 000000000..a1776c8fa --- /dev/null +++ b/application/models/reports/detailed_sales.php @@ -0,0 +1,68 @@ + array($this->lang->line('reports_sale_id'), $this->lang->line('reports_date'), $this->lang->line('reports_items_purchased'), $this->lang->line('reports_sold_by'), $this->lang->line('reports_sold_to'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit'), $this->lang->line('reports_payment_type'), $this->lang->line('reports_comments')), + 'details' => array($this->lang->line('reports_name'), $this->lang->line('reports_category'), $this->lang->line('reports_serial_number'), $this->lang->line('reports_description'), $this->lang->line('reports_quantity_purchased'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit'),$this->lang->line('reports_discount')) + ); + } + + public function getData(array $inputs) + { + $this->db->select('sale_id, sale_date, sum(quantity_purchased) as items_purchased, CONCAT(employee.first_name," ",employee.last_name) as employee_name, CONCAT(customer.first_name," ",customer.last_name) as customer_name, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit, payment_type, comment', false); + $this->db->from('sales_items_temp'); + $this->db->join('people as employee', 'sales_items_temp.employee_id = employee.person_id'); + $this->db->join('people as customer', 'sales_items_temp.customer_id = customer.person_id', 'left'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('sale_id'); + $this->db->order_by('sale_date'); + + $data = array(); + $data['summary'] = $this->db->get()->result_array(); + $data['details'] = array(); + + foreach($data['summary'] as $key=>$value) + { + $this->db->select('name, category, quantity_purchased, serialnumber, sales_items_temp.description, subtotal,total, tax, profit, discount_percent'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_id = '.$value['sale_id']); + $data['details'][$key] = $this->db->get()->result_array(); + } + + return $data; + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/inventory_low.php b/application/models/reports/inventory_low.php new file mode 100644 index 000000000..98652e6a7 --- /dev/null +++ b/application/models/reports/inventory_low.php @@ -0,0 +1,31 @@ +lang->line('reports_item_name'), $this->lang->line('reports_item_number'), $this->lang->line('reports_description'), $this->lang->line('reports_count'), $this->lang->line('reports_reorder_level')); + } + + public function getData(array $inputs) + { + $this->db->select('name, item_number, quantity, reorder_level, description'); + $this->db->from('items'); + $this->db->where('quantity <= reorder_level and deleted=0'); + $this->db->order_by('name'); + + return $this->db->get()->result_array(); + + } + + public function getSummaryData(array $inputs) + { + return array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/inventory_summary.php b/application/models/reports/inventory_summary.php new file mode 100644 index 000000000..a6130f891 --- /dev/null +++ b/application/models/reports/inventory_summary.php @@ -0,0 +1,31 @@ +lang->line('reports_item_name'), $this->lang->line('reports_item_number'), $this->lang->line('reports_description'), $this->lang->line('reports_count'), $this->lang->line('reports_reorder_level')); + } + + public function getData(array $inputs) + { + $this->db->select('name, item_number, quantity, reorder_level, description'); + $this->db->from('items'); + $this->db->where('deleted', 0); + $this->db->order_by('name'); + + return $this->db->get()->result_array(); + + } + + public function getSummaryData(array $inputs) + { + return array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/report.php b/application/models/reports/report.php new file mode 100644 index 000000000..0a7f6e31a --- /dev/null +++ b/application/models/reports/report.php @@ -0,0 +1,28 @@ +output->set_header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + $this->output->set_header("Cache-Control: no-store, no-cache, must-revalidate"); + $this->output->set_header("Cache-Control: post-check=0, pre-check=0", false); + $this->output->set_header("Pragma: no-cache"); + + //Create our temp tables to work with the data in our report + $this->Sale->create_sales_items_temp_table(); + $this->Receiving->create_receivings_items_temp_table(); + } + + //Returns the column names used for the report + public abstract function getDataColumns(); + + //Returns all the data to be populated into the report + public abstract function getData(array $inputs); + + //Returns key=>value pairing of summary data for the report + public abstract function getSummaryData(array $inputs); +} +?> \ No newline at end of file diff --git a/application/models/reports/specific_customer.php b/application/models/reports/specific_customer.php new file mode 100644 index 000000000..0b2f8c342 --- /dev/null +++ b/application/models/reports/specific_customer.php @@ -0,0 +1,66 @@ + array($this->lang->line('reports_sale_id'), $this->lang->line('reports_date'), $this->lang->line('reports_items_purchased'), $this->lang->line('reports_sold_by'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit'), $this->lang->line('reports_payment_type'), $this->lang->line('reports_comments')), + 'details' => array($this->lang->line('reports_name'), $this->lang->line('reports_category'),$this->lang->line('reports_serial_number'), $this->lang->line('reports_description'), $this->lang->line('reports_quantity_purchased'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit'),$this->lang->line('reports_discount')) + ); + } + + public function getData(array $inputs) + { + $this->db->select('sale_id, sale_date, sum(quantity_purchased) as items_purchased, CONCAT(first_name," ",last_name) as employee_name, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit, payment_type, comment', false); + $this->db->from('sales_items_temp'); + $this->db->join('people', 'sales_items_temp.employee_id = people.person_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'" and customer_id='.$inputs['customer_id']); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('sale_id'); + $this->db->order_by('sale_date'); + + $data = array(); + $data['summary'] = $this->db->get()->result_array(); + $data['details'] = array(); + + foreach($data['summary'] as $key=>$value) + { + $this->db->select('name, category, serialnumber, sales_items_temp.description, quantity_purchased, subtotal,total, tax, profit, discount_percent'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_id = '.$value['sale_id']); + $data['details'][$key] = $this->db->get()->result_array(); + } + + return $data; + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'" and customer_id='.$inputs['customer_id']); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/specific_employee.php b/application/models/reports/specific_employee.php new file mode 100644 index 000000000..39fff80f9 --- /dev/null +++ b/application/models/reports/specific_employee.php @@ -0,0 +1,68 @@ + array($this->lang->line('reports_sale_id'), $this->lang->line('reports_date'), $this->lang->line('reports_items_purchased'), $this->lang->line('reports_sold_to'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit'), $this->lang->line('reports_payment_type'), $this->lang->line('reports_comments')), + 'details' => array($this->lang->line('reports_name'), $this->lang->line('reports_category'), $this->lang->line('reports_serial_number'), $this->lang->line('reports_description'), $this->lang->line('reports_quantity_purchased'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit'),$this->lang->line('reports_discount')) + ); + } + + public function getData(array $inputs) + { + $this->db->select('sale_id, sale_date, sum(quantity_purchased) as items_purchased, CONCAT(first_name," ",last_name) as customer_name, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit, payment_type, comment', false); + $this->db->from('sales_items_temp'); + $this->db->join('people', 'sales_items_temp.customer_id = people.person_id', 'left'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'" and employee_id='.$inputs['employee_id']); + + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + + $this->db->group_by('sale_id'); + $this->db->order_by('sale_date'); + + $data = array(); + $data['summary'] = $this->db->get()->result_array(); + $data['details'] = array(); + + foreach($data['summary'] as $key=>$value) + { + $this->db->select('name, category, serialnumber, sales_items_temp.description, quantity_purchased, subtotal,total, tax, profit, discount_percent'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_id = '.$value['sale_id']); + $data['details'][$key] = $this->db->get()->result_array(); + } + + return $data; + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'" and employee_id='.$inputs['employee_id']); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_categories.php b/application/models/reports/summary_categories.php new file mode 100644 index 000000000..27c30ae46 --- /dev/null +++ b/application/models/reports/summary_categories.php @@ -0,0 +1,53 @@ +lang->line('reports_category'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit')); + } + + public function getData(array $inputs) + { + $this->db->select('category, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('category'); + $this->db->order_by('category'); + + return $this->db->get()->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_customers.php b/application/models/reports/summary_customers.php new file mode 100644 index 000000000..1f8fa6aea --- /dev/null +++ b/application/models/reports/summary_customers.php @@ -0,0 +1,54 @@ +lang->line('reports_customer'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit')); + } + + public function getData(array $inputs) + { + $this->db->select('CONCAT(first_name, " ",last_name) as customer, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax,sum(profit) as profit', false); + $this->db->from('sales_items_temp'); + $this->db->join('customers', 'customers.person_id = sales_items_temp.customer_id'); + $this->db->join('people', 'customers.person_id = people.person_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('customer_id'); + $this->db->order_by('last_name'); + + return $this->db->get()->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('customers', 'customers.person_id = sales_items_temp.customer_id'); + $this->db->join('people', 'customers.person_id = people.person_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_discounts.php b/application/models/reports/summary_discounts.php new file mode 100644 index 000000000..6b3949eb0 --- /dev/null +++ b/application/models/reports/summary_discounts.php @@ -0,0 +1,49 @@ +lang->line('reports_discount_percent'),$this->lang->line('reports_count')); + } + + public function getData(array $inputs) + { + $this->db->select('CONCAT(discount_percent, "%") as discount_percent, count(*) as count', false); + $this->db->from('sales_items_temp'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'" and discount_percent > 0'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('sales_items_temp.discount_percent'); + $this->db->order_by('discount_percent'); + return $this->db->get()->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax,sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_employees.php b/application/models/reports/summary_employees.php new file mode 100644 index 000000000..5308e8e95 --- /dev/null +++ b/application/models/reports/summary_employees.php @@ -0,0 +1,55 @@ +lang->line('reports_employee'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit')); + } + + public function getData(array $inputs) + { + $this->db->select('CONCAT(first_name, " ",last_name) as employee, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit', false); + $this->db->from('sales_items_temp'); + $this->db->join('employees', 'employees.person_id = sales_items_temp.employee_id'); + $this->db->join('people', 'employees.person_id = people.person_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('employee_id'); + $this->db->order_by('last_name'); + + return $this->db->get()->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('employees', 'employees.person_id = sales_items_temp.employee_id'); + $this->db->join('people', 'employees.person_id = people.person_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_items.php b/application/models/reports/summary_items.php new file mode 100644 index 000000000..8aefb5475 --- /dev/null +++ b/application/models/reports/summary_items.php @@ -0,0 +1,52 @@ +lang->line('reports_item'),$this->lang->line('reports_quantity_purchased'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'),$this->lang->line('reports_profit')); + } + + public function getData(array $inputs) + { + $this->db->select('name, sum(quantity_purchased) as quantity_purchased, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('items.item_id'); + $this->db->order_by('name'); + + return $this->db->get()->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_payments.php b/application/models/reports/summary_payments.php new file mode 100644 index 000000000..2c95ac69c --- /dev/null +++ b/application/models/reports/summary_payments.php @@ -0,0 +1,50 @@ +lang->line('reports_payment_type'), $this->lang->line('reports_total')); + } + + public function getData(array $inputs) + { + $this->db->select('sales_payments.payment_type, SUM(payment_amount) as payment_amount', false); + $this->db->from('sales_payments'); + $this->db->join('sales', 'sales.sale_id=sales_payments.sale_id'); + $this->db->where('date(sale_time) BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('payment_amount > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('payment_amount < 0'); + } + $this->db->group_by("payment_type"); + return $this->db->get()->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_sales.php b/application/models/reports/summary_sales.php new file mode 100644 index 000000000..e7914a9ee --- /dev/null +++ b/application/models/reports/summary_sales.php @@ -0,0 +1,51 @@ +lang->line('reports_date'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit')); + } + + public function getData(array $inputs) + { + $this->db->select('sale_date, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax,sum(profit) as profit'); + $this->db->from('sales_items_temp'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + + $this->db->group_by('sale_date'); + $this->db->having('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + $this->db->order_by('sale_date'); + return $this->db->get()->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax,sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + return $this->db->get()->row_array(); + } + +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_suppliers.php b/application/models/reports/summary_suppliers.php new file mode 100644 index 000000000..98566c343 --- /dev/null +++ b/application/models/reports/summary_suppliers.php @@ -0,0 +1,55 @@ +lang->line('reports_supplier'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax'), $this->lang->line('reports_profit')); + } + + public function getData(array $inputs) + { + $this->db->select('CONCAT(first_name, " ",last_name) as supplier, sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax,sum(profit) as profit', false); + $this->db->from('sales_items_temp'); + $this->db->join('suppliers', 'suppliers.person_id = sales_items_temp.supplier_id'); + $this->db->join('people', 'suppliers.person_id = people.person_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + $this->db->group_by('supplier_id'); + $this->db->order_by('last_name'); + + return $this->db->get()->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('suppliers', 'suppliers.person_id = sales_items_temp.supplier_id'); + $this->db->join('people', 'suppliers.person_id = people.person_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/reports/summary_taxes.php b/application/models/reports/summary_taxes.php new file mode 100644 index 000000000..824a72749 --- /dev/null +++ b/application/models/reports/summary_taxes.php @@ -0,0 +1,66 @@ +lang->line('reports_tax_percent'), $this->lang->line('reports_subtotal'), $this->lang->line('reports_total'), $this->lang->line('reports_tax')); + } + + public function getData(array $inputs) + { + + $quanitity_cond = ''; + if ($inputs['sale_type'] == 'sales') + { + $quanitity_cond = 'and quantity_purchased > 0'; + } + elseif ($inputs['sale_type'] == 'returns') + { + $quanitity_cond = 'and quantity_purchased < 0'; + } + + $query = $this->db->query("SELECT percent, SUM(subtotal) as subtotal, sum(total) as total, sum(tax) as tax + FROM (SELECT name, CONCAT( percent, '%' ) AS percent, ( + item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent /100 + ) AS subtotal, ROUND( ( + item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent /100 + ) * ( 1 + ( percent /100 ) ) , 2 ) AS total, ROUND( ( + item_unit_price * quantity_purchased - item_unit_price * quantity_purchased * discount_percent /100 + ) * ( percent /100 ) , 2 ) AS tax + FROM ".$this->db->dbprefix('sales_items_taxes')." + JOIN ".$this->db->dbprefix('sales_items')." ON " + .$this->db->dbprefix('sales_items').'.sale_id='.$this->db->dbprefix('sales_items_taxes').'.sale_id'." and " + .$this->db->dbprefix('sales_items').'.item_id='.$this->db->dbprefix('sales_items_taxes').'.item_id'." and " + .$this->db->dbprefix('sales_items').'.line='.$this->db->dbprefix('sales_items_taxes').'.line' + ." JOIN ".$this->db->dbprefix('sales')." ON ".$this->db->dbprefix('sales_items_taxes').".sale_id=".$this->db->dbprefix('sales').".sale_id + WHERE date(sale_time) BETWEEN '".$inputs['start_date']."' and '".$inputs['end_date']."' $quanitity_cond) as temp_taxes + GROUP BY percent"); + return $query->result_array(); + } + + public function getSummaryData(array $inputs) + { + $this->db->select('sum(subtotal) as subtotal, sum(total) as total, sum(tax) as tax, sum(profit) as profit'); + $this->db->from('sales_items_temp'); + $this->db->join('items', 'sales_items_temp.item_id = items.item_id'); + $this->db->where('sale_date BETWEEN "'. $inputs['start_date']. '" and "'. $inputs['end_date'].'"'); + + if ($inputs['sale_type'] == 'sales') + { + $this->db->where('quantity_purchased > 0'); + } + elseif ($inputs['sale_type'] == 'returns') + { + $this->db->where('quantity_purchased < 0'); + } + + return $this->db->get()->row_array(); + } +} +?> \ No newline at end of file diff --git a/application/models/sale.php b/application/models/sale.php new file mode 100644 index 000000000..6867fc803 --- /dev/null +++ b/application/models/sale.php @@ -0,0 +1,216 @@ +db->from('sales'); + $this->db->where('sale_id',$sale_id); + return $this->db->get(); + } + + function exists($sale_id) + { + $this->db->from('sales'); + $this->db->where('sale_id',$sale_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + function update($sale_data, $sale_id) + { + $this->db->where('sale_id', $sale_id); + $success = $this->db->update('sales',$sale_data); + + return $success; + } + + function save ($items,$customer_id,$employee_id,$comment,$payments,$sale_id=false) + { + if(count($items)==0) + return -1; + + //Alain Multiple payments + //Build payment types string + $payment_types=''; + foreach($payments as $payment_id=>$payment) + { + $payment_types=$payment_types.$payment['payment_type'].': '.to_currency($payment['payment_amount']).'
'; + } + + $sales_data = array( + 'sale_time' => date('Y-m-d H:i:s'), + 'customer_id'=> $this->Customer->exists($customer_id) ? $customer_id : null, + 'employee_id'=>$employee_id, + 'payment_type'=>$payment_types, + 'comment'=>$comment + ); + + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + $this->db->insert('sales',$sales_data); + $sale_id = $this->db->insert_id(); + + foreach($payments as $payment_id=>$payment) + { + if ( substr( $payment['payment_type'], 0, strlen( $this->lang->line('sales_giftcard') ) ) == $this->lang->line('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'] ); + $cur_giftcard_value = $this->Giftcard->get_giftcard_value( $splitpayment[1] ); + $this->Giftcard->update_giftcard_value( $splitpayment[1], $cur_giftcard_value - $payment['payment_amount'] ); + } + + $sales_payments_data = array + ( + 'sale_id'=>$sale_id, + 'payment_type'=>$payment['payment_type'], + 'payment_amount'=>$payment['payment_amount'] + ); + $this->db->insert('sales_payments',$sales_payments_data); + } + + foreach($items as $line=>$item) + { + $cur_item_info = $this->Item->get_info($item['item_id']); + + $sales_items_data = array + ( + 'sale_id'=>$sale_id, + 'item_id'=>$item['item_id'], + 'line'=>$item['line'], + 'description'=>$item['description'], + 'serialnumber'=>$item['serialnumber'], + 'quantity_purchased'=>$item['quantity'], + 'discount_percent'=>$item['discount'], + 'item_cost_price' => $cur_item_info->cost_price, + 'item_unit_price'=>$item['price'] + ); + + $this->db->insert('sales_items',$sales_items_data); + + //Update stock quantity + $item_data = array('quantity'=>$cur_item_info->quantity - $item['quantity']); + $this->Item->save($item_data,$item['item_id']); + + //Ramel Inventory Tracking + //Inventory Count Details + $qty_buy = -$item['quantity']; + $sale_remarks ='POS '.$sale_id; + $inv_data = array + ( + 'trans_date'=>date('Y-m-d H:i:s'), + 'trans_items'=>$item['item_id'], + 'trans_user'=>$employee_id, + 'trans_comment'=>$sale_remarks, + 'trans_inventory'=>$qty_buy + ); + $this->Inventory->insert($inv_data); + //------------------------------------Ramel + + $customer = $this->Customer->get_info($customer_id); + if ($customer_id == -1 or $customer->taxable) + { + foreach($this->Item_taxes->get_info($item['item_id']) as $row) + { + $this->db->insert('sales_items_taxes', array( + 'sale_id' =>$sale_id, + 'item_id' =>$item['item_id'], + 'line' =>$item['line'], + 'name' =>$row['name'], + 'percent' =>$row['percent'] + )); + } + } + } + $this->db->trans_complete(); + + if ($this->db->trans_status() === FALSE) + { + return -1; + } + + return $sale_id; + } + + function delete($sale_id) + { + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + $this->db->delete('sales_payments', array('sale_id' => $sale_id)); + $this->db->delete('sales_items_taxes', array('sale_id' => $sale_id)); + $this->db->delete('sales_items', array('sale_id' => $sale_id)); + $this->db->delete('sales', array('sale_id' => $sale_id)); + + $this->db->trans_complete(); + + return $this->db->trans_status(); + } + + function get_sale_items($sale_id) + { + $this->db->from('sales_items'); + $this->db->where('sale_id',$sale_id); + return $this->db->get(); + } + + function get_sale_payments($sale_id) + { + $this->db->from('sales_payments'); + $this->db->where('sale_id',$sale_id); + return $this->db->get(); + } + + function get_customer($sale_id) + { + $this->db->from('sales'); + $this->db->where('sale_id',$sale_id); + return $this->Customer->get_info($this->db->get()->row()->customer_id); + } + + //We create a temp table that allows us to do easy report/sales queries + public function create_sales_items_temp_table() + { + $this->db->query("CREATE TEMPORARY TABLE ".$this->db->dbprefix('sales_items_temp')." + (SELECT date(sale_time) as sale_date, ".$this->db->dbprefix('sales_items').".sale_id, comment,payment_type, customer_id, employee_id, + ".$this->db->dbprefix('items').".item_id, supplier_id, quantity_purchased, item_cost_price, item_unit_price, SUM(percent) as item_tax_percent, + discount_percent, (item_unit_price*quantity_purchased-item_unit_price*quantity_purchased*discount_percent/100) as subtotal, + ".$this->db->dbprefix('sales_items').".line as line, serialnumber, ".$this->db->dbprefix('sales_items').".description as description, + ROUND((item_unit_price*quantity_purchased-item_unit_price*quantity_purchased*discount_percent/100)*(1+(SUM(percent)/100)),2) as total, + ROUND((item_unit_price*quantity_purchased-item_unit_price*quantity_purchased*discount_percent/100)*(SUM(percent)/100),2) as tax, + (item_unit_price*quantity_purchased-item_unit_price*quantity_purchased*discount_percent/100) - (item_cost_price*quantity_purchased) as profit + FROM ".$this->db->dbprefix('sales_items')." + INNER JOIN ".$this->db->dbprefix('sales')." ON ".$this->db->dbprefix('sales_items').'.sale_id='.$this->db->dbprefix('sales').'.sale_id'." + INNER JOIN ".$this->db->dbprefix('items')." ON ".$this->db->dbprefix('sales_items').'.item_id='.$this->db->dbprefix('items').'.item_id'." + LEFT OUTER JOIN ".$this->db->dbprefix('suppliers')." ON ".$this->db->dbprefix('items').'.supplier_id='.$this->db->dbprefix('suppliers').'.person_id'." + LEFT OUTER JOIN ".$this->db->dbprefix('sales_items_taxes')." ON " + .$this->db->dbprefix('sales_items').'.sale_id='.$this->db->dbprefix('sales_items_taxes').'.sale_id'." and " + .$this->db->dbprefix('sales_items').'.item_id='.$this->db->dbprefix('sales_items_taxes').'.item_id'." and " + .$this->db->dbprefix('sales_items').'.line='.$this->db->dbprefix('sales_items_taxes').'.line'." + GROUP BY sale_id, item_id, line)"); + + //Update null item_tax_percents to be 0 instead of null + $this->db->where('item_tax_percent IS NULL'); + $this->db->update('sales_items_temp', array('item_tax_percent' => 0)); + + //Update null tax to be 0 instead of null + $this->db->where('tax IS NULL'); + $this->db->update('sales_items_temp', array('tax' => 0)); + + //Update null subtotals to be equal to the total as these don't have tax + $this->db->query('UPDATE '.$this->db->dbprefix('sales_items_temp'). ' SET total=subtotal WHERE total IS NULL'); + } + + public function get_giftcard_value( $giftcardNumber ) + { + if ( !$this->Giftcard->exists( $this->Giftcard->get_giftcard_id($giftcardNumber))) + return 0; + + $this->db->from('giftcards'); + $this->db->where('giftcard_number',$giftcardNumber); + return $this->db->get()->row()->value; + } +} +?> diff --git a/application/models/sale_suspended.php b/application/models/sale_suspended.php new file mode 100644 index 000000000..3c46b6274 --- /dev/null +++ b/application/models/sale_suspended.php @@ -0,0 +1,160 @@ +db->from('sales_suspended'); + $this->db->order_by('sale_id'); + return $this->db->get(); + } + + public function get_info($sale_id) + { + $this->db->from('sales_suspended'); + $this->db->where('sale_id',$sale_id); + return $this->db->get(); + } + + function exists($sale_id) + { + $this->db->from('sales_suspended'); + $this->db->where('sale_id',$sale_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + function update($sale_data, $sale_id) + { + $this->db->where('sale_id', $sale_id); + $success = $this->db->update('sales_suspended',$sale_data); + + return $success; + } + + function save ($items,$customer_id,$employee_id,$comment,$payments,$sale_id=false) + { + if(count($items)==0) + return -1; + + //Alain Multiple payments + //Build payment types string + $payment_types=''; + foreach($payments as $payment_id=>$payment) + { + $payment_types=$payment_types.$payment['payment_type'].': '.to_currency($payment['payment_amount']).'
'; + } + + $sales_data = array( + 'sale_time' => date('Y-m-d H:i:s'), + 'customer_id'=> $this->Customer->exists($customer_id) ? $customer_id : null, + 'employee_id'=>$employee_id, + 'payment_type'=>$payment_types, + 'comment'=>$comment + ); + + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + $this->db->insert('sales_suspended',$sales_data); + $sale_id = $this->db->insert_id(); + + foreach($payments as $payment_id=>$payment) + { + $sales_payments_data = array + ( + 'sale_id'=>$sale_id, + 'payment_type'=>$payment['payment_type'], + 'payment_amount'=>$payment['payment_amount'] + ); + $this->db->insert('sales_suspended_payments',$sales_payments_data); + } + + foreach($items as $line=>$item) + { + $cur_item_info = $this->Item->get_info($item['item_id']); + + $sales_items_data = array + ( + 'sale_id'=>$sale_id, + 'item_id'=>$item['item_id'], + 'line'=>$item['line'], + 'description'=>$item['description'], + 'serialnumber'=>$item['serialnumber'], + 'quantity_purchased'=>$item['quantity'], + 'discount_percent'=>$item['discount'], + 'item_cost_price' => $cur_item_info->cost_price, + 'item_unit_price'=>$item['price'] + ); + + $this->db->insert('sales_suspended_items',$sales_items_data); + + $customer = $this->Customer->get_info($customer_id); + if ($customer_id == -1 or $customer->taxable) + { + foreach($this->Item_taxes->get_info($item['item_id']) as $row) + { + $this->db->insert('sales_suspended_items_taxes', array( + 'sale_id' =>$sale_id, + 'item_id' =>$item['item_id'], + 'line' =>$item['line'], + 'name' =>$row['name'], + 'percent' =>$row['percent'] + )); + } + } + } + $this->db->trans_complete(); + + if ($this->db->trans_status() === FALSE) + { + return -1; + } + + return $sale_id; + } + + function delete($sale_id) + { + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + $this->db->delete('sales_suspended_payments', array('sale_id' => $sale_id)); + $this->db->delete('sales_suspended_items_taxes', array('sale_id' => $sale_id)); + $this->db->delete('sales_suspended_items', array('sale_id' => $sale_id)); + $this->db->delete('sales_suspended', array('sale_id' => $sale_id)); + + $this->db->trans_complete(); + + return $this->db->trans_status(); + } + + function get_sale_items($sale_id) + { + $this->db->from('sales_suspended_items'); + $this->db->where('sale_id',$sale_id); + return $this->db->get(); + } + + function get_sale_payments($sale_id) + { + $this->db->from('sales_suspended_payments'); + $this->db->where('sale_id',$sale_id); + return $this->db->get(); + } + + function get_customer($sale_id) + { + $this->db->from('sales_suspended'); + $this->db->where('sale_id',$sale_id); + return $this->Customer->get_info($this->db->get()->row()->customer_id); + } + + function get_comment($sale_id) + { + $this->db->from('sales_suspended'); + $this->db->where('sale_id',$sale_id); + return $this->db->get()->row()->comment; + } +} +?> diff --git a/application/models/supplier.php b/application/models/supplier.php new file mode 100644 index 000000000..d5ec68b73 --- /dev/null +++ b/application/models/supplier.php @@ -0,0 +1,260 @@ +db->from('suppliers'); + $this->db->join('people', 'people.person_id = suppliers.person_id'); + $this->db->where('suppliers.person_id',$person_id); + $query = $this->db->get(); + + return ($query->num_rows()==1); + } + + /* + Returns all the suppliers + */ + function get_all($limit=10000, $offset=0) + { + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->order_by("last_name", "asc"); + $this->db->limit($limit); + $this->db->offset($offset); + return $this->db->get(); + } + + function count_all() + { + $this->db->from('suppliers'); + $this->db->where('deleted',0); + return $this->db->count_all_results(); + } + + /* + Gets information about a particular supplier + */ + function get_info($supplier_id) + { + $this->db->from('suppliers'); + $this->db->join('people', 'people.person_id = suppliers.person_id'); + $this->db->where('suppliers.person_id',$supplier_id); + $query = $this->db->get(); + + if($query->num_rows()==1) + { + return $query->row(); + } + else + { + //Get empty base parent object, as $supplier_id is NOT an supplier + $person_obj=parent::get_info(-1); + + //Get all the fields from supplier table + $fields = $this->db->list_fields('suppliers'); + + //append those fields to base parent object, we we have a complete empty object + foreach ($fields as $field) + { + $person_obj->$field=''; + } + + return $person_obj; + } + } + + /* + Gets information about multiple suppliers + */ + function get_multiple_info($suppliers_ids) + { + $this->db->from('suppliers'); + $this->db->join('people', 'people.person_id = suppliers.person_id'); + $this->db->where_in('suppliers.person_id',$suppliers_ids); + $this->db->order_by("last_name", "asc"); + return $this->db->get(); + } + + /* + Inserts or updates a suppliers + */ + function save(&$person_data, &$supplier_data,$supplier_id=false) + { + $success=false; + //Run these queries as a transaction, we want to make sure we do all or nothing + $this->db->trans_start(); + + if(parent::save($person_data,$supplier_id)) + { + if (!$supplier_id or !$this->exists($supplier_id)) + { + $supplier_data['person_id'] = $person_data['person_id']; + $success = $this->db->insert('suppliers',$supplier_data); + } + else + { + $this->db->where('person_id', $supplier_id); + $success = $this->db->update('suppliers',$supplier_data); + } + + } + + $this->db->trans_complete(); + return $success; + } + + /* + Deletes one supplier + */ + function delete($supplier_id) + { + $this->db->where('person_id', $supplier_id); + return $this->db->update('suppliers', array('deleted' => 1)); + } + + /* + Deletes a list of suppliers + */ + function delete_list($supplier_ids) + { + $this->db->where_in('person_id',$supplier_ids); + return $this->db->update('suppliers', array('deleted' => 1)); + } + + /* + Get search suggestions to find suppliers + */ + function get_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->like("company_name",$search); + $this->db->order_by("company_name", "asc"); + $by_company_name = $this->db->get(); + foreach($by_company_name->result() as $row) + { + $suggestions[]=$row->company_name; + } + + + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where("(first_name LIKE '%".$this->db->escape_like_str($search)."%' or + last_name LIKE '%".$this->db->escape_like_str($search)."%' or + CONCAT(`first_name`,' ',`last_name`) LIKE '%".$this->db->escape_like_str($search)."%') and deleted=0"); + $this->db->order_by("last_name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->first_name.' '.$row->last_name; + } + + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->like("email",$search); + $this->db->order_by("email", "asc"); + $by_email = $this->db->get(); + foreach($by_email->result() as $row) + { + $suggestions[]=$row->email; + } + + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->like("phone_number",$search); + $this->db->order_by("phone_number", "asc"); + $by_phone = $this->db->get(); + foreach($by_phone->result() as $row) + { + $suggestions[]=$row->phone_number; + } + + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->like("account_number",$search); + $this->db->order_by("account_number", "asc"); + $by_account_number = $this->db->get(); + foreach($by_account_number->result() as $row) + { + $suggestions[]=$row->account_number; + } + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + + } + + /* + Get search suggestions to find suppliers + */ + function get_suppliers_search_suggestions($search,$limit=25) + { + $suggestions = array(); + + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where('deleted', 0); + $this->db->like("company_name",$search); + $this->db->order_by("company_name", "asc"); + $by_company_name = $this->db->get(); + foreach($by_company_name->result() as $row) + { + $suggestions[]=$row->person_id.'|'.$row->company_name; + } + + + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where("(first_name LIKE '%".$this->db->escape_like_str($search)."%' or + last_name LIKE '%".$this->db->escape_like_str($search)."%' or + CONCAT(`first_name`,' ',`last_name`) LIKE '%".$this->db->escape_like_str($search)."%') and deleted=0"); + $this->db->order_by("last_name", "asc"); + $by_name = $this->db->get(); + foreach($by_name->result() as $row) + { + $suggestions[]=$row->person_id.'|'.$row->first_name.' '.$row->last_name; + } + + //only return $limit suggestions + if(count($suggestions > $limit)) + { + $suggestions = array_slice($suggestions, 0,$limit); + } + return $suggestions; + + } + /* + Perform a search on suppliers + */ + function search($search) + { + $this->db->from('suppliers'); + $this->db->join('people','suppliers.person_id=people.person_id'); + $this->db->where("(first_name LIKE '%".$this->db->escape_like_str($search)."%' or + last_name LIKE '%".$this->db->escape_like_str($search)."%' or + company_name LIKE '%".$this->db->escape_like_str($search)."%' or + email LIKE '%".$this->db->escape_like_str($search)."%' or + phone_number LIKE '%".$this->db->escape_like_str($search)."%' or + account_number LIKE '%".$this->db->escape_like_str($search)."%' or + CONCAT(`first_name`,' ',`last_name`) LIKE '%".$this->db->escape_like_str($search)."%') and deleted=0"); + $this->db->order_by("last_name", "asc"); + + return $this->db->get(); + } + +} +?> diff --git a/application/third_party/index.html b/application/third_party/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/third_party/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/application/views/barcode.php b/application/views/barcode.php new file mode 100644 index 000000000..41f1bfa63 --- /dev/null +++ b/application/views/barcode.php @@ -0,0 +1,332 @@ + + + + + + +*/ +/*=============================================================================*/ + + +//----------------------------------------------------------------------------- +// Startup code +//----------------------------------------------------------------------------- + +if(isset($_GET["text"])) $text=$_GET["text"]; +if(isset($_GET["format"])) $format=$_GET["format"]; +if(isset($_GET["quality"])) $quality=$_GET["quality"]; +if(isset($_GET["width"])) $width=$_GET["width"]; +if(isset($_GET["height"])) $height=$_GET["height"]; +if(isset($_GET["type"])) $type=$_GET["type"]; +if(isset($_GET["barcode"])) $barcode=$_GET["barcode"]; + +if (!isset ($text)) $text = ''; +if (!isset ($type)) $type = 1; +if (empty ($quality)) $quality = 100; +if (empty ($width)) $width = 160; +if (empty ($height)) $height = 80; +if (!empty ($format)) $format = strtoupper ($format); + else $format="PNG"; + +switch ($type) +{ + default: + $type = 1; + case 1: + Barcode39 ($barcode, $width, $height, $quality, $format, $text); + break; +} + +//----------------------------------------------------------------------------- +// Generate a Code 3 of 9 barcode +//----------------------------------------------------------------------------- +function Barcode39 ($barcode, $width, $height, $quality, $format, $text) +{ + switch ($format) + { + default: + $format = "JPEG"; + case "JPEG": + header ("Content-type: image/jpeg"); + break; + case "PNG": + header ("Content-type: image/png"); + break; + case "GIF": + header ("Content-type: image/gif"); + break; + } + + + $im = ImageCreate ($width, $height) + or die ("Cannot Initialize new GD image stream"); + $White = ImageColorAllocate ($im, 255, 255, 255); + $Black = ImageColorAllocate ($im, 0, 0, 0); + //ImageColorTransparent ($im, $White); + ImageInterLace ($im, 1); + + + + $NarrowRatio = 20; + $WideRatio = 55; + $QuietRatio = 35; + + + $nChars = (strlen($barcode)+2) * ((6 * $NarrowRatio) + (3 * $WideRatio) + ($QuietRatio)); + $Pixels = $width / $nChars; + $NarrowBar = (int)(20 * $Pixels); + $WideBar = (int)(55 * $Pixels); + $QuietBar = (int)(35 * $Pixels); + + + $ActualWidth = (($NarrowBar * 6) + ($WideBar*3) + $QuietBar) * (strlen ($barcode)+2); + + if (($NarrowBar == 0) || ($NarrowBar == $WideBar) || ($NarrowBar == $QuietBar) || ($WideBar == 0) || ($WideBar == $QuietBar) || ($QuietBar == 0)) + { + ImageString ($im, 1, 0, 0, "Image is too small!", $Black); + OutputImage ($im, $format, $quality); + exit; + } + + $CurrentBarX = (int)(($width - $ActualWidth) / 2); + $Color = $White; + $BarcodeFull = "*".strtoupper ($barcode)."*"; + settype ($BarcodeFull, "string"); + + $FontNum = 3; + $FontHeight = ImageFontHeight ($FontNum); + $FontWidth = ImageFontWidth ($FontNum); + + if ($text != '') + { + $CenterLoc = (int)(($width) / 2) - (int)(($FontWidth * strlen($text)) / 2); + ImageString ($im, $FontNum, $CenterLoc, $height-$FontHeight, "$text", $Black); + } + + + for ($i=0; $i \ No newline at end of file diff --git a/application/views/barcode_sheet.php b/application/views/barcode_sheet.php new file mode 100644 index 000000000..eb196ebf4 --- /dev/null +++ b/application/views/barcode_sheet.php @@ -0,0 +1,28 @@ + + + + <?php echo $this->lang->line('items_generate_barcodes'); ?> + + + + +'; + } + echo ""; + $count++; +} +?> + +
+ + diff --git a/application/views/config.php b/application/views/config.php new file mode 100644 index 000000000..5e46b263a --- /dev/null +++ b/application/views/config.php @@ -0,0 +1,439 @@ +load->view("partial/header"); ?> +
lang->line('module_config'); ?>
+'config_form')); +?> +
+
+
lang->line('common_fields_required_message'); ?>
+
    +lang->line("config_info"); ?> + +
    +lang->line('config_company').':', 'company',array('class'=>'wide required')); ?> +
    + 'company', + 'id'=>'company', + 'value'=>$this->config->item('company')));?> +
    +
    + +
    +lang->line('config_address').':', 'address',array('class'=>'wide required')); ?> +
    + 'address', + 'id'=>'address', + 'rows'=>4, + 'cols'=>17, + 'value'=>$this->config->item('address')));?> +
    +
    + +
    +lang->line('config_phone').':', 'phone',array('class'=>'wide required')); ?> +
    + 'phone', + 'id'=>'phone', + 'value'=>$this->config->item('phone')));?> +
    +
    + +
    +lang->line('config_default_tax_rate_1').':', 'default_tax_1_rate',array('class'=>'wide required')); ?> +
    + 'default_tax_1_name', + 'id'=>'default_tax_1_name', + 'size'=>'10', + 'value'=>$this->config->item('default_tax_1_name')!==FALSE ? $this->config->item('default_tax_1_name') : $this->lang->line('items_sales_tax_1')));?> + + 'default_tax_1_rate', + 'id'=>'default_tax_1_rate', + 'size'=>'4', + 'value'=>$this->config->item('default_tax_1_rate')));?>% +
    +
    + +
    +lang->line('config_default_tax_rate_2').':', 'default_tax_1_rate',array('class'=>'wide')); ?> +
    + 'default_tax_2_name', + 'id'=>'default_tax_2_name', + 'size'=>'10', + 'value'=>$this->config->item('default_tax_2_name')!==FALSE ? $this->config->item('default_tax_2_name') : $this->lang->line('items_sales_tax_2')));?> + + 'default_tax_2_rate', + 'id'=>'default_tax_2_rate', + 'size'=>'4', + 'value'=>$this->config->item('default_tax_2_rate')));?>% +
    +
    + +
    + lang->line('config_currency_symbol').':', 'currency_symbol',array('class'=>'wide')); ?> +
    + 'currency_symbol', + 'id'=>'currency_symbol', + 'value'=>$this->config->item('currency_symbol')));?> +
    + + lang->line('config_currency_side').':', 'currency_side',array('class'=>''));?> +
    + 'currency_side', + 'id'=>'currency_side', + 'value'=>'currency_side', + 'checked'=>$this->config->item('currency_side')));?> +
    +
    + + +
    +lang->line('common_email').':', 'email',array('class'=>'wide')); ?> +
    + 'email', + 'id'=>'email', + 'value'=>$this->config->item('email')));?> +
    +
    + + +
    +lang->line('config_fax').':', 'fax',array('class'=>'wide')); ?> +
    + 'fax', + 'id'=>'fax', + 'value'=>$this->config->item('fax')));?> +
    +
    + +
    +lang->line('config_website').':', 'website',array('class'=>'wide')); ?> +
    + 'website', + 'id'=>'website', + 'value'=>$this->config->item('website')));?> +
    +
    + +
    +lang->line('common_return_policy').':', 'return_policy',array('class'=>'wide required')); ?> +
    + 'return_policy', + 'id'=>'return_policy', + 'rows'=>'4', + 'cols'=>'17', + 'value'=>$this->config->item('return_policy')));?> +
    +
    + +
    +lang->line('config_language').':', 'language',array('class'=>'wide required')); ?> +
    + 'Azerbaijan', + 'BahasaIndonesia' => 'BahasaIndonesia', + 'english' => 'English', + 'Spanish' => 'Spanish', + 'Russian' => 'Russian' + ), + $this->config->item('language')); + ?> +
    +
    + +
    +lang->line('config_timezone').':', 'timezone',array('class'=>'wide required')); ?> +
    + '(GMT-11:00) Midway Island, Samoa', + 'America/Adak'=>'(GMT-10:00) Hawaii-Aleutian', + 'Etc/GMT+10'=>'(GMT-10:00) Hawaii', + 'Pacific/Marquesas'=>'(GMT-09:30) Marquesas Islands', + 'Pacific/Gambier'=>'(GMT-09:00) Gambier Islands', + 'America/Anchorage'=>'(GMT-09:00) Alaska', + 'America/Ensenada'=>'(GMT-08:00) Tijuana, Baja California', + 'Etc/GMT+8'=>'(GMT-08:00) Pitcairn Islands', + 'America/Los_Angeles'=>'(GMT-08:00) Pacific Time (US & Canada)', + 'America/Denver'=>'(GMT-07:00) Mountain Time (US & Canada)', + 'America/Chihuahua'=>'(GMT-07:00) Chihuahua, La Paz, Mazatlan', + 'America/Dawson_Creek'=>'(GMT-07:00) Arizona', + 'America/Belize'=>'(GMT-06:00) Saskatchewan, Central America', + 'America/Cancun'=>'(GMT-06:00) Guadalajara, Mexico City, Monterrey', + 'Chile/EasterIsland'=>'(GMT-06:00) Easter Island', + 'America/Chicago'=>'(GMT-06:00) Central Time (US & Canada)', + 'America/New_York'=>'(GMT-05:00) Eastern Time (US & Canada)', + 'America/Havana'=>'(GMT-05:00) Cuba', + 'America/Bogota'=>'(GMT-05:00) Bogota, Lima, Quito, Rio Branco', + 'America/Caracas'=>'(GMT-04:30) Caracas', + 'America/Santiago'=>'(GMT-04:00) Santiago', + 'America/La_Paz'=>'(GMT-04:00) La Paz', + 'Atlantic/Stanley'=>'(GMT-04:00) Faukland Islands', + 'America/Campo_Grande'=>'(GMT-04:00) Brazil', + 'America/Goose_Bay'=>'(GMT-04:00) Atlantic Time (Goose Bay)', + 'America/Glace_Bay'=>'(GMT-04:00) Atlantic Time (Canada)', + 'America/St_Johns'=>'(GMT-03:30) Newfoundland', + 'America/Araguaina'=>'(GMT-03:00) UTC-3', + 'America/Montevideo'=>'(GMT-03:00) Montevideo', + 'America/Miquelon'=>'(GMT-03:00) Miquelon, St. Pierre', + 'America/Godthab'=>'(GMT-03:00) Greenland', + 'America/Argentina/Buenos_Aires'=>'(GMT-03:00) Buenos Aires', + 'America/Sao_Paulo'=>'(GMT-03:00) Brasilia', + 'America/Noronha'=>'(GMT-02:00) Mid-Atlantic', + 'Atlantic/Cape_Verde'=>'(GMT-01:00) Cape Verde Is.', + 'Atlantic/Azores'=>'(GMT-01:00) Azores', + 'Europe/Belfast'=>'(GMT) Greenwich Mean Time : Belfast', + 'Europe/Dublin'=>'(GMT) Greenwich Mean Time : Dublin', + 'Europe/Lisbon'=>'(GMT) Greenwich Mean Time : Lisbon', + 'Europe/London'=>'(GMT) Greenwich Mean Time : London', + 'Africa/Abidjan'=>'(GMT) Monrovia, Reykjavik', + 'Europe/Amsterdam'=>'(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna', + 'Europe/Belgrade'=>'(GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague', + 'Europe/Brussels'=>'(GMT+01:00) Brussels, Copenhagen, Madrid, Paris', + 'Africa/Algiers'=>'(GMT+01:00) West Central Africa', + 'Africa/Windhoek'=>'(GMT+01:00) Windhoek', + 'Asia/Beirut'=>'(GMT+02:00) Beirut', + 'Africa/Cairo'=>'(GMT+02:00) Cairo', + 'Asia/Gaza'=>'(GMT+02:00) Gaza', + 'Africa/Blantyre'=>'(GMT+02:00) Harare, Pretoria', + 'Asia/Jerusalem'=>'(GMT+02:00) Jerusalem', + 'Europe/Minsk'=>'(GMT+02:00) Minsk', + 'Asia/Damascus'=>'(GMT+02:00) Syria', + 'Europe/Moscow'=>'(GMT+03:00) Moscow, St. Petersburg, Volgograd', + 'Africa/Addis_Ababa'=>'(GMT+03:00) Nairobi', + 'Asia/Tehran'=>'(GMT+03:30) Tehran', + 'Asia/Dubai'=>'(GMT+04:00) Abu Dhabi, Muscat', + 'Asia/Yerevan'=>'(GMT+04:00) Yerevan', + 'Asia/Kabul'=>'(GMT+04:30) Kabul', + 'Asia/Baku'=>'(GMT+05:00) Baku',/*GARRISON ADDED 4/20/2013*/ + 'Asia/Yekaterinburg'=>'(GMT+05:00) Ekaterinburg', + 'Asia/Tashkent'=>'(GMT+05:00) Tashkent', + 'Asia/Kolkata'=>'(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi', + 'Asia/Katmandu'=>'(GMT+05:45) Kathmandu', + 'Asia/Dhaka'=>'(GMT+06:00) Astana, Dhaka', + 'Asia/Novosibirsk'=>'(GMT+06:00) Novosibirsk', + 'Asia/Rangoon'=>'(GMT+06:30) Yangon (Rangoon)', + 'Asia/Bangkok'=>'(GMT+07:00) Bangkok, Hanoi, Jakarta', + 'Asia/Krasnoyarsk'=>'(GMT+07:00) Krasnoyarsk', + 'Asia/Hong_Kong'=>'(GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi', + 'Asia/Irkutsk'=>'(GMT+08:00) Irkutsk, Ulaan Bataar', + 'Australia/Perth'=>'(GMT+08:00) Perth', + 'Australia/Eucla'=>'(GMT+08:45) Eucla', + 'Asia/Tokyo'=>'(GMT+09:00) Osaka, Sapporo, Tokyo', + 'Asia/Seoul'=>'(GMT+09:00) Seoul', + 'Asia/Yakutsk'=>'(GMT+09:00) Yakutsk', + 'Australia/Adelaide'=>'(GMT+09:30) Adelaide', + 'Australia/Darwin'=>'(GMT+09:30) Darwin', + 'Australia/Brisbane'=>'(GMT+10:00) Brisbane', + 'Australia/Hobart'=>'(GMT+10:00) Hobart', + 'Asia/Vladivostok'=>'(GMT+10:00) Vladivostok', + 'Australia/Lord_Howe'=>'(GMT+10:30) Lord Howe Island', + 'Etc/GMT-11'=>'(GMT+11:00) Solomon Is., New Caledonia', + 'Asia/Magadan'=>'(GMT+11:00) Magadan', + 'Pacific/Norfolk'=>'(GMT+11:30) Norfolk Island', + 'Asia/Anadyr'=>'(GMT+12:00) Anadyr, Kamchatka', + 'Pacific/Auckland'=>'(GMT+12:00) Auckland, Wellington', + 'Etc/GMT-12'=>'(GMT+12:00) Fiji, Kamchatka, Marshall Is.', + 'Pacific/Chatham'=>'(GMT+12:45) Chatham Islands', + 'Pacific/Tongatapu'=>'(GMT+13:00) Nuku\'alofa', + 'Pacific/Kiritimati'=>'(GMT+14:00) Kiritimati' + ), $this->config->item('timezone') ? $this->config->item('timezone') : date_default_timezone_get()); + ?> +
    +
    + +
    +lang->line('config_print_after_sale').':', 'print_after_sale',array('class'=>'wide')); ?> +
    + 'print_after_sale', + 'id'=>'print_after_sale', + 'value'=>'print_after_sale', + 'checked'=>$this->config->item('print_after_sale')));?> +
    +
    + +
    +lang->line('config_custom1').':', 'website',array('class'=>'wide')); ?> +
    + 'custom1_name', + 'id'=>'custom1_name', + 'value'=>$this->config->item('custom1_name')));?> +
    +
    + +
    +lang->line('config_custom2').':', 'website',array('class'=>'wide')); ?> +
    + 'custom2_name', + 'id'=>'custom2_name', + 'value'=>$this->config->item('custom2_name')));?> +
    +
    + +
    +lang->line('config_custom3').':', 'website',array('class'=>'wide')); ?> +
    + 'custom3_name', + 'id'=>'custom3_name', + 'value'=>$this->config->item('custom3_name')));?> +
    +
    + +
    +lang->line('config_custom4').':', 'website',array('class'=>'wide')); ?> +
    + 'custom4_name', + 'id'=>'custom4_name', + 'value'=>$this->config->item('custom4_name')));?> +
    +
    + +
    +lang->line('config_custom5').':', 'website',array('class'=>'wide')); ?> +
    + 'custom5_name', + 'id'=>'custom5_name', + 'value'=>$this->config->item('custom5_name')));?> +
    +
    + +
    +lang->line('config_custom6').':', 'website',array('class'=>'wide')); ?> +
    + 'custom6_name', + 'id'=>'custom6_name', + 'value'=>$this->config->item('custom6_name')));?> +
    +
    + +
    +lang->line('config_custom7').':', 'website',array('class'=>'wide')); ?> +
    + 'custom7_name', + 'id'=>'custom7_name', + 'value'=>$this->config->item('custom7_name')));?> +
    +
    + +
    +lang->line('config_custom8').':', 'website',array('class'=>'wide')); ?> +
    + 'custom8_name', + 'id'=>'custom8_name', + 'value'=>$this->config->item('custom8_name')));?> +
    +
    + +
    +lang->line('config_custom9').':', 'website',array('class'=>'wide')); ?> +
    + 'custom9_name', + 'id'=>'custom9_name', + 'value'=>$this->config->item('custom9_name')));?> +
    +
    + +
    +lang->line('config_custom10').':', 'website',array('class'=>'wide')); ?> +
    + 'custom10_name', + 'id'=>'custom10_name', + 'value'=>$this->config->item('custom10_name')));?> +
    +
    + +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
    +
    + +
    + +load->view("partial/footer"); ?> diff --git a/application/views/customers/excel_import.php b/application/views/customers/excel_import.php new file mode 100644 index 000000000..d46c54a2d --- /dev/null +++ b/application/views/customers/excel_import.php @@ -0,0 +1,63 @@ +'item_form')); +?> +
    Import customers from Excel sheet
    +
      +Download Import Excel Template (CSV) +
      +Import + +
      +'wide')); ?> +
      + 'file_path', + 'id'=>'file_path', + 'value'=>'') + );?> +
      +
      + +'submitf', + 'id'=>'submitf', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
      + + \ No newline at end of file diff --git a/application/views/customers/form.php b/application/views/customers/form.php new file mode 100644 index 000000000..2a1906a7a --- /dev/null +++ b/application/views/customers/form.php @@ -0,0 +1,73 @@ +person_id,array('id'=>'customer_form')); +?> +
      lang->line('common_fields_required_message'); ?>
      +
        +
        +lang->line("customers_basic_information"); ?> +load->view("people/form_basic_info"); ?> +
        +lang->line('customers_account_number').':', 'account_number'); ?> +
        + 'account_number', + 'id'=>'account_number', + 'value'=>$person_info->account_number) + );?> +
        +
        + +
        +lang->line('customers_taxable').':', 'taxable'); ?> +
        + taxable == '' ? TRUE : (boolean)$person_info->taxable);?> +
        +
        + +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
        + + \ No newline at end of file diff --git a/application/views/employees/form.php b/application/views/employees/form.php new file mode 100644 index 000000000..389c04612 --- /dev/null +++ b/application/views/employees/form.php @@ -0,0 +1,158 @@ +person_id,array('id'=>'employee_form')); +?> +
        lang->line('common_fields_required_message'); ?>
        +
          +
          +lang->line("employees_basic_information"); ?> +load->view("people/form_basic_info"); ?> +
          + +
          +lang->line("employees_login_info"); ?> +
          +lang->line('employees_username').':', 'username',array('class'=>'required')); ?> +
          + 'username', + 'id'=>'username', + 'value'=>$person_info->username));?> +
          +
          + +person_id == "" ? array('class'=>'required'):array(); +?> + +
          +lang->line('employees_password').':', 'password',$password_label_attributes); ?> +
          + 'password', + 'id'=>'password' + ));?> +
          +
          + + +
          +lang->line('employees_repeat_password').':', 'repeat_password',$password_label_attributes); ?> +
          + 'repeat_password', + 'id'=>'repeat_password' + ));?> +
          +
          +
          + +
          +lang->line("employees_permission_info"); ?> +

          lang->line("employees_permission_desc"); ?>

          + +
            +result() as $module) +{ +?> +
          • +module_id,$this->Employee->has_permission($module->module_id,$person_info->person_id)); ?> +lang->line('module_'.$module->module_id);?>: +lang->line('module_'.$module->module_id.'_desc');?> +
          • + +
          +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); + +?> +
          + + \ No newline at end of file diff --git a/application/views/giftcards/form.php b/application/views/giftcards/form.php new file mode 100644 index 000000000..8aac50422 --- /dev/null +++ b/application/views/giftcards/form.php @@ -0,0 +1,108 @@ +
          lang->line('common_fields_required_message'); ?>
          +
            +giftcard_id,array('id'=>'giftcard_form')); +?> +
            +lang->line("giftcards_basic_information"); ?> + + +
            +lang->line('giftcards_person_id').':', 'name',array('class'=>'required wide')); ?> +
            + 'person_id', + 'id'=>'person_id', + 'value'=>$giftcard_info->person_id) + );?> +
            +
            + + +
            +lang->line('giftcards_giftcard_number').':', 'name',array('class'=>'required wide')); ?> +
            + 'giftcard_number', + 'id'=>'giftcard_number', + 'value'=>$giftcard_info->giftcard_number) + );?> +
            +
            + +
            +lang->line('giftcards_card_value').':', 'name',array('class'=>'required wide')); ?> +
            + 'value', + 'id'=>'value', + 'value'=>$giftcard_info->value) + );?> +
            +
            + +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
            + + \ No newline at end of file diff --git a/application/views/giftcards/manage.php b/application/views/giftcards/manage.php new file mode 100644 index 000000000..0a3d49fe8 --- /dev/null +++ b/application/views/giftcards/manage.php @@ -0,0 +1,86 @@ +load->view("partial/header"); ?> + + +
            +
            lang->line('common_list_of').' '.$this->lang->line('module_'.$controller_name); ?>
            +
            + ".$this->lang->line($controller_name.'_new')."
            ", + array('class'=>'thickbox none','title'=>$this->lang->line($controller_name.'_new'))); + ?> +
            + +pagination->create_links();?> +
            +
              +
            • lang->line("common_delete"),array('id'=>'delete')); ?>
            • +
            • + spinner + 'search_form')); ?> + + +
            • +
            +
            + +
            + +
            +
            +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/application/views/home.php b/application/views/home.php new file mode 100644 index 000000000..caaccb417 --- /dev/null +++ b/application/views/home.php @@ -0,0 +1,19 @@ +load->view("partial/header"); ?> +
            +

            lang->line('common_welcome_message'); ?>

            +
            + result() as $module) + { + ?> +
            + module_id");?>"> + Menubar Image
            + module_id");?>">lang->line("module_".$module->module_id) ?> + - lang->line('module_'.$module->module_id.'_desc');?> +
            + +
            +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/application/views/index.html b/application/views/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/application/views/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

            Directory access is forbidden.

            + + + \ No newline at end of file diff --git a/application/views/item_kits/form.php b/application/views/item_kits/form.php new file mode 100644 index 000000000..f6fb20f37 --- /dev/null +++ b/application/views/item_kits/form.php @@ -0,0 +1,138 @@ +
            lang->line('common_fields_required_message'); ?>
            +
              +item_kit_id,array('id'=>'item_kit_form')); +?> +
              +lang->line("item_kits_info"); ?> + +
              +lang->line('item_kits_name').':', 'name',array('class'=>'wide required')); ?> +
              + 'name', + 'id'=>'name', + 'value'=>$item_kit_info->name) + );?> +
              +
              + +
              +lang->line('item_kits_description').':', 'description',array('class'=>'wide')); ?> +
              + 'description', + 'id'=>'description', + 'value'=>$item_kit_info->description, + 'rows'=>'5', + 'cols'=>'17') + );?> +
              +
              + + +
              +lang->line('item_kits_add_item').':', 'item',array('class'=>'wide')); ?> +
              + 'item', + 'id'=>'item' + ));?> +
              +
              + + + + + + + + + Item_kit_items->get_info($item_kit_info->item_kit_id) as $item_kit_item) {?> + + Item->get_info($item_kit_item['item_id']); + ?> + + + + + +
              lang->line('common_delete');?>lang->line('item_kits_item');?>lang->line('item_kits_quantity');?>
              Xname; ?>' type='text' size='3' name=item_kit_item[] value=''/>
              +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
              + + \ No newline at end of file diff --git a/application/views/item_kits/manage.php b/application/views/item_kits/manage.php new file mode 100644 index 000000000..5c27ffc8b --- /dev/null +++ b/application/views/item_kits/manage.php @@ -0,0 +1,99 @@ +load->view("partial/header"); ?> + + +
              +
              lang->line('common_list_of').' '.$this->lang->line('module_'.$controller_name); ?>
              +
              + ".$this->lang->line($controller_name.'_new')."
              ", + array('class'=>'thickbox none','title'=>$this->lang->line($controller_name.'_new'))); + ?> +
              + + +pagination->create_links();?> +
              +
                +
              • lang->line("common_delete"),array('id'=>'delete')); ?>
              • +
              • lang->line("items_generate_barcodes"),array('id'=>'generate_barcodes', 'target' =>'_blank','title'=>$this->lang->line('items_generate_barcodes'))); ?>
              • +
              • + spinner + 'search_form')); ?> + + +
              • +
              +
              + +
              + +
              +
              +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/application/views/items/count_details.php b/application/views/items/count_details.php new file mode 100644 index 000000000..22b48115c --- /dev/null +++ b/application/views/items/count_details.php @@ -0,0 +1,114 @@ +item_id,array('id'=>'item_form')); +?> +
              +lang->line("items_basic_information"); ?> + + +
              +
              + + + + + + + + + + + + + + + + +
              +lang->line('items_item_number').':', 'name',array('class'=>'wide')); ?> + + 'item_number', + 'id'=>'item_number', + 'value'=>$item_info->item_number, + 'style' => 'border:none', + 'readonly' => 'readonly' + ); + + echo form_input($inumber) + ?> +
              +lang->line('items_name').':', 'name',array('class'=>'wide')); ?> + + 'name', + 'id'=>'name', + 'value'=>$item_info->name, + 'style' => 'border:none', + 'readonly' => 'readonly' + ); + echo form_input($iname); + ?> +
              +lang->line('items_category').':', 'category',array('class'=>'wide')); ?> + + 'category', + 'id'=>'category', + 'value'=>$item_info->category, + 'style' => 'border:none', + 'readonly' => 'readonly' + ); + + echo form_input($cat); + ?> +
              +lang->line('items_current_quantity').':', 'quantity',array('class'=>'wide')); ?> + + 'quantity', + 'id'=>'quantity', + 'value'=>$item_info->quantity, + 'style' => 'border:none', + 'readonly' => 'readonly' + ); + + echo form_input($qty); + ?> +
              + +
              +
              +
              + +
              +
              +
              +
              + + + + +Inventory->get_inventory_data_for_item($item_info->item_id)->result_array() as $row) +{ +?> + + + + + + + + +
              Inventory Data Tracking
              DateEmployeeIn/Out QtyRemarks
              Employee->get_info($person_id); + echo $employee->first_name." ".$employee->last_name; + ?> +
              \ No newline at end of file diff --git a/application/views/items/excel_import.php b/application/views/items/excel_import.php new file mode 100644 index 000000000..2816cd04d --- /dev/null +++ b/application/views/items/excel_import.php @@ -0,0 +1,63 @@ +'item_form')); +?> +
              Import items from Excel sheet
              +
                +Download Import Excel Template (CSV) +
                +Import + +
                +'wide')); ?> +
                + 'file_path', + 'id'=>'file_path', + 'value'=>'') + );?> +
                +
                + +'submitf', + 'id'=>'submitf', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
                + + \ No newline at end of file diff --git a/application/views/items/form.php b/application/views/items/form.php new file mode 100644 index 000000000..1b7f452b2 --- /dev/null +++ b/application/views/items/form.php @@ -0,0 +1,491 @@ +
                lang->line('common_fields_required_message'); ?>
                +
                  +item_id,array('id'=>'item_form')); +?> +
                  +lang->line("items_basic_information"); ?> + +
                  +lang->line('items_item_number').':', 'name',array('class'=>'wide')); ?> +
                  + 'item_number', + 'id'=>'item_number', + 'value'=>$item_info->item_number) + );?> +
                  +
                  + +
                  +lang->line('items_name').':', 'name',array('class'=>'required wide')); ?> +
                  + 'name', + 'id'=>'name', + 'value'=>$item_info->name) + );?> +
                  +
                  + +
                  +lang->line('items_category').':', 'category',array('class'=>'required wide')); ?> +
                  + 'category', + 'id'=>'category', + 'value'=>$item_info->category) + );?> +
                  +
                  + +
                  +lang->line('items_supplier').':', 'supplier',array('class'=>'required wide')); ?> +
                  + +
                  +
                  + +
                  +lang->line('items_cost_price').':', 'cost_price',array('class'=>'required wide')); ?> +
                  + 'cost_price', + 'size'=>'8', + 'id'=>'cost_price', + 'value'=>$item_info->cost_price) + );?> +
                  +
                  + +
                  +lang->line('items_unit_price').':', 'unit_price',array('class'=>'required wide')); ?> +
                  + 'unit_price', + 'size'=>'8', + 'id'=>'unit_price', + 'value'=>$item_info->unit_price) + );?> +
                  +
                  + +
                  +lang->line('items_tax_1').':', 'tax_percent_1',array('class'=>'wide')); ?> +
                  + 'tax_names[]', + 'id'=>'tax_name_1', + 'size'=>'8', + 'value'=> isset($item_tax_info[0]['name']) ? $item_tax_info[0]['name'] : $this->config->item('default_tax_1_name')) + );?> +
                  +
                  + 'tax_percents[]', + 'id'=>'tax_percent_name_1', + 'size'=>'3', + 'value'=> isset($item_tax_info[0]['percent']) ? $item_tax_info[0]['percent'] : $default_tax_1_rate) + );?> + % +
                  +
                  + +
                  +lang->line('items_tax_2').':', 'tax_percent_2',array('class'=>'wide')); ?> +
                  + 'tax_names[]', + 'id'=>'tax_name_2', + 'size'=>'8', + 'value'=> isset($item_tax_info[1]['name']) ? $item_tax_info[1]['name'] : $this->config->item('default_tax_2_name')) + );?> +
                  +
                  + 'tax_percents[]', + 'id'=>'tax_percent_name_2', + 'size'=>'3', + 'value'=> isset($item_tax_info[1]['percent']) ? $item_tax_info[1]['percent'] : $default_tax_2_rate) + );?> + % +
                  +
                  + + +
                  +lang->line('items_quantity').':', 'quantity',array('class'=>'required wide')); ?> +
                  + 'quantity', + 'id'=>'quantity', + 'value'=>$item_info->quantity) + );?> +
                  +
                  + +
                  +lang->line('items_reorder_level').':', 'reorder_level',array('class'=>'required wide')); ?> +
                  + 'reorder_level', + 'id'=>'reorder_level', + 'value'=>$item_info->reorder_level) + );?> +
                  +
                  + +
                  +lang->line('items_location').':', 'location',array('class'=>'wide')); ?> +
                  + 'location', + 'id'=>'location', + 'value'=>$item_info->location) + );?> +
                  +
                  + +
                  +lang->line('items_description').':', 'description',array('class'=>'wide')); ?> +
                  + 'description', + 'id'=>'description', + 'value'=>$item_info->description, + 'rows'=>'5', + 'cols'=>'17') + );?> +
                  +
                  + +
                  +lang->line('items_allow_alt_desciption').':', 'allow_alt_description',array('class'=>'wide')); ?> +
                  + 'allow_alt_description', + 'id'=>'allow_alt_description', + 'value'=>1, + 'checked'=>($item_info->allow_alt_description)? 1 :0) + );?> +
                  +
                  + +
                  +lang->line('items_is_serialized').':', 'is_serialized',array('class'=>'wide')); ?> +
                  + 'is_serialized', + 'id'=>'is_serialized', + 'value'=>1, + 'checked'=>($item_info->is_serialized)? 1 : 0) + );?> +
                  +
                  + + +
                  +config->item('custom1_name') != NULL) +{ + echo form_label($this->config->item('custom1_name').':', 'custom1',array('class'=>'wide')); ?> +
                  + 'custom1', + 'id'=>'custom1', + 'value'=>$item_info->custom1) + );?> +
                  +
                  + + +
                  +config->item('custom2_name') != NULL) +{ + echo form_label($this->config->item('custom2_name').':', 'custom2',array('class'=>'wide')); ?> +
                  + 'custom2', + 'id'=>'custom2', + 'value'=>$item_info->custom2) + );?> +
                  +
                  + + +
                  +config->item('custom3_name') != NULL) +{ + echo form_label($this->config->item('custom3_name').':', 'custom3',array('class'=>'wide')); ?> +
                  + 'custom3', + 'id'=>'custom3', + 'value'=>$item_info->custom3) + );?> +
                  +
                  + + +
                  +config->item('custom4_name') != NULL) +{ + echo form_label($this->config->item('custom4_name').':', 'custom4',array('class'=>'wide')); ?> +
                  + 'custom4', + 'id'=>'custom4', + 'value'=>$item_info->custom4) + );?> +
                  +
                  + + +
                  +config->item('custom5_name') != NULL) +{ + echo form_label($this->config->item('custom5_name').':', 'custom5',array('class'=>'wide')); ?> +
                  + 'custom5', + 'id'=>'custom5', + 'value'=>$item_info->custom5) + );?> +
                  +
                  + + +
                  +config->item('custom6_name') != NULL) +{ + echo form_label($this->config->item('custom6_name').':', 'custom6',array('class'=>'wide')); ?> +
                  + 'custom6', + 'id'=>'custom6', + 'value'=>$item_info->custom6) + );?> +
                  +
                  + + +
                  +config->item('custom7_name') != NULL) +{ + echo form_label($this->config->item('custom7_name').':', 'custom7',array('class'=>'wide')); ?> +
                  + 'custom7', + 'id'=>'custom7', + 'value'=>$item_info->custom7) + );?> +
                  +
                  + + +
                  +config->item('custom8_name') != NULL) +{ + echo form_label($this->config->item('custom8_name').':', 'custom8',array('class'=>'wide')); ?> +
                  + 'custom8', + 'id'=>'custom8', + 'value'=>$item_info->custom8) + );?> +
                  +
                  + + +
                  +config->item('custom9_name') != NULL) +{ + echo form_label($this->config->item('custom9_name').':', 'custom9',array('class'=>'wide')); ?> +
                  + 'custom9', + 'id'=>'custom9', + 'value'=>$item_info->custom9) + );?> +
                  +
                  + + +
                  +config->item('custom10_name') != NULL) +{ + echo form_label($this->config->item('custom10_name').':', 'custom10',array('class'=>'wide')); ?> +
                  + 'custom10', + 'id'=>'custom10', + 'value'=>$item_info->custom10) + );?> +
                  +
                  + + + + +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
                  + + \ No newline at end of file diff --git a/application/views/items/form_bulk.php b/application/views/items/form_bulk.php new file mode 100644 index 000000000..5bfedc9b2 --- /dev/null +++ b/application/views/items/form_bulk.php @@ -0,0 +1,244 @@ +
                  lang->line('items_edit_fields_you_want_to_update'); ?>
                  +
                    +'item_form')); +?> +
                    +lang->line("items_basic_information"); ?> + +
                    +lang->line('items_name').':', 'name',array('class'=>'wide')); ?> +
                    + 'name', + 'id'=>'name') + );?> +
                    +
                    + +
                    +lang->line('items_category').':', 'category',array('class'=>'wide')); ?> +
                    + 'category', + 'id'=>'category') + );?> +
                    +
                    + +
                    +lang->line('items_supplier').':', 'supplier',array('class'=>'wide')); ?> +
                    + +
                    +
                    + + +
                    +lang->line('items_cost_price').':', 'cost_price',array('class'=>'wide')); ?> +
                    + 'cost_price', + 'size'=>'8', + 'id'=>'cost_price') + );?> +
                    +
                    + +
                    +lang->line('items_unit_price').':', 'unit_price',array('class'=>'wide')); ?> +
                    + 'unit_price', + 'size'=>'8', + 'id'=>'unit_price') + );?> +
                    +
                    + +
                    +lang->line('items_tax_1').':', 'tax_percent_1',array('class'=>'wide')); ?> +
                    + 'tax_names[]', + 'id'=>'tax_name_1', + 'size'=>'8', + 'value'=> isset($item_tax_info[0]['name']) ? $item_tax_info[0]['name'] : $this->lang->line('items_sales_tax')) + );?> +
                    +
                    + 'tax_percents[]', + 'id'=>'tax_percent_name_1', + 'size'=>'3', + 'value'=> isset($item_tax_info[0]['percent']) ? $item_tax_info[0]['percent'] : '') + );?> + % +
                    +
                    + +
                    +lang->line('items_tax_2').':', 'tax_percent_2',array('class'=>'wide')); ?> +
                    + 'tax_names[]', + 'id'=>'tax_name_2', + 'size'=>'8', + 'value'=> isset($item_tax_info[1]['name']) ? $item_tax_info[1]['name'] : '') + );?> +
                    +
                    + 'tax_percents[]', + 'id'=>'tax_percent_name_2', + 'size'=>'3', + 'value'=> isset($item_tax_info[1]['percent']) ? $item_tax_info[1]['percent'] : '') + );?> + % +
                    +
                    +
                    +lang->line('items_reorder_level').':', 'reorder_level',array('class'=>'wide')); ?> +
                    + 'reorder_level', + 'id'=>'reorder_level') + );?> +
                    +
                    + +
                    +lang->line('items_location').':', 'location',array('class'=>'wide')); ?> +
                    + 'location', + 'id'=>'location') + );?> +
                    +
                    + +
                    +lang->line('items_description').':', 'description',array('class'=>'wide')); ?> +
                    + 'description', + 'id'=>'description', + 'rows'=>'5', + 'cols'=>'17') + );?> +
                    +
                    + +
                    + +lang->line('items_allow_alt_desciption').':', 'allow_alt_description',array('class'=>'wide')); ?> +
                    + + +
                    + +
                    + + + +
                    + +lang->line('items_is_serialized').':', 'is_serialized',array('class'=>'wide')); ?> +
                    + + +
                    + +
                    + +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
                    + + \ No newline at end of file diff --git a/application/views/items/inventory.php b/application/views/items/inventory.php new file mode 100644 index 000000000..178c2d3b4 --- /dev/null +++ b/application/views/items/inventory.php @@ -0,0 +1,157 @@ +
                    lang->line('common_fields_required_message'); ?>
                    +
                      +item_id,array('id'=>'item_form')); +?> +
                      +lang->line("items_basic_information"); ?> + + +
                      +
                      + + + + + + + + + + + + + + + + +
                      +lang->line('items_item_number').':', 'name',array('class'=>'wide')); ?> + + 'item_number', + 'id'=>'item_number', + 'value'=>$item_info->item_number, + 'style' => 'border:none', + 'readonly' => 'readonly' + ); + + echo form_input($inumber) + ?> +
                      +lang->line('items_name').':', 'name',array('class'=>'wide')); ?> + + 'name', + 'id'=>'name', + 'value'=>$item_info->name, + 'style' => 'border:none', + 'readonly' => 'readonly' + ); + echo form_input($iname); + ?> +
                      +lang->line('items_category').':', 'category',array('class'=>'wide')); ?> + + 'category', + 'id'=>'category', + 'value'=>$item_info->category, + 'style' => 'border:none', + 'readonly' => 'readonly' + ); + + echo form_input($cat); + ?> +
                      +lang->line('items_current_quantity').':', 'quantity',array('class'=>'wide')); ?> + + 'quantity', + 'id'=>'quantity', + 'value'=>$item_info->quantity, + 'style' => 'border:none', + 'readonly' => 'readonly' + ); + + echo form_input($qty); + ?> +
                      + +
                      +lang->line('items_add_minus').':', 'quantity',array('class'=>'required wide')); ?> +
                      + 'newquantity', + 'id'=>'newquantity' + ) + );?> +
                      +
                      + +
                      +lang->line('items_inventory_comments').':', 'description',array('class'=>'wide')); ?> +
                      + 'trans_comment', + 'id'=>'trans_comment', + 'rows'=>'3', + 'cols'=>'17') + );?> +
                      +
                      +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
                      + + \ No newline at end of file diff --git a/application/views/items/manage.php b/application/views/items/manage.php new file mode 100644 index 000000000..094c0702a --- /dev/null +++ b/application/views/items/manage.php @@ -0,0 +1,183 @@ +load->view("partial/header"); ?> + + +
                      +
                      lang->line('common_list_of').' '.$this->lang->line('module_'.$controller_name); ?>
                      +
                      + ".$this->lang->line($controller_name.'_new')."
                      ", + array('class'=>'thickbox none','title'=>$this->lang->line($controller_name.'_new'))); + ?> + Excel Import
                      ", + array('class'=>'thickbox none','title'=>'Import Items from Excel')); + ?> + + + +
                      +
                      Search Options :
                      + + +
                      + +
                      + 'items_filter_form')); ?> + lang->line('items_low_inventory_items').' '.':', 'low_inventory');?> + 'low_inventory','id'=>'low_inventory','value'=>1,'checked'=> isset($low_inventory)? ( ($low_inventory)? 1 : 0) : 0)).' | ';?> + lang->line('items_serialized_items').' '.':', 'is_serialized');?> + 'is_serialized','id'=>'is_serialized','value'=>1,'checked'=> isset($is_serialized)? ( ($is_serialized)? 1 : 0) : 0)).' | ';?> + lang->line('items_no_description_items').' '.':', 'no_description');?> + 'no_description','id'=>'no_description','value'=>1,'checked'=> isset($no_description)? ( ($no_description)? 1 : 0) : 0)).' | ';?> + lang->line('items_search_custom_items').' '.':', 'search_custom');//GARRISON ADDED 4/21/2013?> + 'search_custom','id'=>'search_custom','value'=>1,'checked'=> isset($search_custom)? ( ($search_custom)? 1 : 0) : 0)).' | ';//GARRISON ADDED 4/21/2013?> + + +
                      +pagination->create_links();?> +
                      +
                        +
                      • lang->line("common_delete"),array('id'=>'delete')); ?>
                      • +
                      • lang->line("items_bulk_edit"),array('id'=>'bulk_edit','title'=>$this->lang->line('items_edit_multiple_items'))); ?>
                      • +
                      • lang->line("items_generate_barcodes"),array('id'=>'generate_barcodes', 'target' =>'_blank','title'=>$this->lang->line('items_generate_barcodes'))); ?>
                      • +
                      • + spinner + 'search_form')); ?> + + +
                      • +
                      +
                      + +
                      + +
                      +
                      +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/application/views/login.php b/application/views/login.php new file mode 100644 index 000000000..d0a782c79 --- /dev/null +++ b/application/views/login.php @@ -0,0 +1,52 @@ + + + + + + +Open Source Point Of Sale <?php echo $this->lang->line('login_login'); ?> + + + + +

                      Open Source Point Of Sale config->item('application_version'); ?>

                      + + +
                      + +
                      + lang->line('login_login'); ?> +
                      +
                      +
                      + lang->line('login_welcome_message'); ?> +
                      + +
                      lang->line('login_username'); ?>:
                      +
                      + 'username', + 'size'=>'20')); ?> +
                      + +
                      lang->line('login_password'); ?>:
                      +
                      + 'password', + 'size'=>'20')); ?> + +
                      + +
                      + +
                      +
                      +
                      + + + diff --git a/application/views/no_access.php b/application/views/no_access.php new file mode 100644 index 000000000..bd0db7601 --- /dev/null +++ b/application/views/no_access.php @@ -0,0 +1,3 @@ +lang->line('error_no_permission_module').' '.$module_name; +?> \ No newline at end of file diff --git a/application/views/partial/footer.php b/application/views/partial/footer.php new file mode 100644 index 000000000..fe1c50460 --- /dev/null +++ b/application/views/partial/footer.php @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/application/views/partial/footer_excel.php b/application/views/partial/footer_excel.php new file mode 100644 index 000000000..69fb64a9b --- /dev/null +++ b/application/views/partial/footer_excel.php @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/application/views/partial/header.php b/application/views/partial/header.php new file mode 100644 index 000000000..722c5ac8a --- /dev/null +++ b/application/views/partial/header.php @@ -0,0 +1,70 @@ + + + + + + <?php echo $this->config->item('company').' -- '.$this->lang->line('common_powered_by').' Open Source Point Of Sale' ?> + + + + + + + + + + + + + + + + + + + + + + + + + +
                      +
                      diff --git a/application/views/partial/header_excel.php b/application/views/partial/header_excel.php new file mode 100644 index 000000000..c60a36c20 --- /dev/null +++ b/application/views/partial/header_excel.php @@ -0,0 +1,54 @@ + + + + + <?php echo $this->config->item('company').' -- '.$this->lang->line('common_powered_by').' Open Source Point Of Sale' ?> + + + diff --git a/application/views/people/form_basic_info.php b/application/views/people/form_basic_info.php new file mode 100644 index 000000000..3e36f4889 --- /dev/null +++ b/application/views/people/form_basic_info.php @@ -0,0 +1,114 @@ +
                      +lang->line('common_first_name').':', 'first_name',array('class'=>'required')); ?> +
                      + 'first_name', + 'id'=>'first_name', + 'value'=>$person_info->first_name) + );?> +
                      +
                      +
                      +lang->line('common_last_name').':', 'last_name',array('class'=>'required')); ?> +
                      + 'last_name', + 'id'=>'last_name', + 'value'=>$person_info->last_name) + );?> +
                      +
                      + +
                      +lang->line('common_email').':', 'email'); ?> +
                      + 'email', + 'id'=>'email', + 'value'=>$person_info->email) + );?> +
                      +
                      + +
                      +lang->line('common_phone_number').':', 'phone_number'); ?> +
                      + 'phone_number', + 'id'=>'phone_number', + 'value'=>$person_info->phone_number));?> +
                      +
                      + +
                      +lang->line('common_address_1').':', 'address_1'); ?> +
                      + 'address_1', + 'id'=>'address_1', + 'value'=>$person_info->address_1));?> +
                      +
                      + +
                      +lang->line('common_address_2').':', 'address_2'); ?> +
                      + 'address_2', + 'id'=>'address_2', + 'value'=>$person_info->address_2));?> +
                      +
                      + +
                      +lang->line('common_city').':', 'city'); ?> +
                      + 'city', + 'id'=>'city', + 'value'=>$person_info->city));?> +
                      +
                      + +
                      +lang->line('common_state').':', 'state'); ?> +
                      + 'state', + 'id'=>'state', + 'value'=>$person_info->state));?> +
                      +
                      + +
                      +lang->line('common_zip').':', 'zip'); ?> +
                      + 'zip', + 'id'=>'zip', + 'value'=>$person_info->zip));?> +
                      +
                      + +
                      +lang->line('common_country').':', 'country'); ?> +
                      + 'country', + 'id'=>'country', + 'value'=>$person_info->country));?> +
                      +
                      + +
                      +lang->line('common_comments').':', 'comments'); ?> +
                      + 'comments', + 'id'=>'comments', + 'value'=>$person_info->comments, + 'rows'=>'5', + 'cols'=>'17') + );?> +
                      +
                      \ No newline at end of file diff --git a/application/views/people/manage.php b/application/views/people/manage.php new file mode 100644 index 000000000..8679a7c7a --- /dev/null +++ b/application/views/people/manage.php @@ -0,0 +1,91 @@ +load->view("partial/header"); ?> + + +
                      +
                      lang->line('common_list_of').' '.$this->lang->line('module_'.$controller_name); ?>
                      +
                      + ".$this->lang->line($controller_name.'_new')."
                      ", + array('class'=>'thickbox none','title'=>$this->lang->line($controller_name.'_new'))); + ?> + + Excel Import
                      ", + array('class'=>'thickbox none','title'=>'Import Items from Excel')); + ?> + +
                      +
                      +pagination->create_links();?> +
                      + +
                      +
                      + +
                      +
                      +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/application/views/receivings/receipt.php b/application/views/receivings/receipt.php new file mode 100644 index 000000000..8efc5f307 --- /dev/null +++ b/application/views/receivings/receipt.php @@ -0,0 +1,104 @@ +load->view("partial/header"); ?> +'.$error_message.''; + exit; +} +?> +
                      +
                      +
                      config->item('company'); ?>
                      +
                      config->item('address')); ?>
                      +
                      config->item('phone'); ?>
                      +
                      +
                      +
                      +
                      + +
                      lang->line('suppliers_supplier').": ".$supplier; ?>
                      + +
                      lang->line('recvs_id').": ".$receiving_id; ?>
                      +
                      lang->line('employees_employee').": ".$employee; ?>
                      +
                      + + + + + + + + + + $item) + { + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                      lang->line('items_item'); ?>lang->line('common_price'); ?>lang->line('sales_quantity'); ?>lang->line('sales_discount'); ?>lang->line('sales_total'); ?>
                      lang->line('sales_total'); ?>
                      lang->line('sales_payment'); ?>
                      lang->line('sales_amount_tendered'); ?>
                      lang->line('sales_change_due'); ?>
                      + +
                      + config->item('return_policy')); ?> +
                      +
                      + "; ?> +
                      +
                      +load->view("partial/footer"); ?> + +Appconfig->get('print_after_sale')) +{ +?> + + \ No newline at end of file diff --git a/application/views/receivings/receiving.php b/application/views/receivings/receiving.php new file mode 100644 index 000000000..da4f19ae3 --- /dev/null +++ b/application/views/receivings/receiving.php @@ -0,0 +1,294 @@ +load->view("partial/header"); ?> + +
                      lang->line('recvs_register'); ?>
                      + +".$error.""; +} +?> + + + +
                      + 'mode_form')); ?> + lang->line('recvs_mode') ?> + + + 'add_item_form')); ?> + +'item','id'=>'item','size'=>'40'));?> +
                      + ".$this->lang->line('sales_new_item')."
                      ", + array('class'=>'thickbox none','title'=>$this->lang->line('sales_new_item'))); + ?> +
                      + + + + + + + + + + + + + + + + + + + + + +$item) + { + echo form_open("receivings/edit_item/$line"); + ?> + + + + + + + + + + + + + + + + + + +
                      lang->line('common_delete'); ?>lang->line('recvs_item_name'); ?>lang->line('recvs_cost'); ?>lang->line('recvs_quantity'); ?>lang->line('recvs_discount'); ?>lang->line('recvs_total'); ?>lang->line('recvs_edit'); ?>
                      +
                      lang->line('sales_no_items_in_cart'); ?>
                      +
                      lang->line('common_delete').']');?>
                      + + +
                      + + + +
                      'price','value'=>$item['price'],'size'=>'6'));?> + 'quantity','value'=>$item['quantity'],'size'=>'2')); + ?> + 'discount','value'=>$item['discount'],'size'=>'3'));?>lang->line('sales_edit_item'));?>
                      + + + + +
                      + lang->line("recvs_supplier").': '.$supplier. '
                      '; + echo anchor("receivings/delete_supplier",'['.$this->lang->line('common_delete').' '.$this->lang->line('suppliers_supplier').']'); + } + else + { + echo form_open("receivings/select_supplier",array('id'=>'select_supplier_form')); ?> + + 'supplier','id'=>'supplier','size'=>'30','value'=>$this->lang->line('recvs_start_typing_supplier_name')));?> + +
                      +

                      lang->line('common_or'); ?>

                      + ".$this->lang->line('recvs_new_supplier')."
                      ", + array('class'=>'thickbox none','title'=>$this->lang->line('recvs_new_supplier'))); + ?> +
                      +
                       
                      + + +
                      +
                      lang->line('sales_total'); ?>:
                      +
                      +
                      + 0) + { + ?> +
                      + 'finish_sale_form')); ?> +
                      + + 'comment','value'=>'','rows'=>'4','cols'=>'23'));?> +

                      + + + + + + + +
                      + lang->line('sales_payment').': ';?> + + +
                      + lang->line('sales_amount_tendered').': ';?> + + 'amount_tendered','value'=>'','size'=>'10')); + ?> +
                      +
                      + ".$this->lang->line('recvs_complete_receiving')."
                      "; + ?> + + + + + 'cancel_sale_form')); ?> +
                      + Cancel +
                      + + + + + +
                       
                      + + +load->view("partial/footer"); ?> + + + \ No newline at end of file diff --git a/application/views/reports/date_input.php b/application/views/reports/date_input.php new file mode 100644 index 000000000..7e98c9bed --- /dev/null +++ b/application/views/reports/date_input.php @@ -0,0 +1,72 @@ +load->view("partial/header"); ?> +
                      lang->line('reports_report_input'); ?>
                      +".$error.""; +} +?> + lang->line('reports_date_range'), 'report_date_range_label', array('class'=>'required')); ?> +
                      + + +
                      + +
                      + + + + + - + + + +
                      + + lang->line('reports_sale_type'), 'reports_sale_type_label', array('class'=>'required')); ?> +
                      + $this->lang->line('reports_all'), 'sales' => $this->lang->line('reports_sales'), 'returns' => $this->lang->line('reports_returns')), 'all', 'id="sale_type"'); ?> +
                      +'generate_report', + 'id'=>'generate_report', + 'content'=>$this->lang->line('common_submit'), + 'class'=>'submit_button') +); +?> + +load->view("partial/footer"); ?> + + \ No newline at end of file diff --git a/application/views/reports/date_input_excel_export.php b/application/views/reports/date_input_excel_export.php new file mode 100644 index 000000000..188e26b79 --- /dev/null +++ b/application/views/reports/date_input_excel_export.php @@ -0,0 +1,83 @@ +load->view("partial/header"); ?> +
                      lang->line('reports_report_input'); ?>
                      +".$error.""; +} +?> + lang->line('reports_date_range'), 'report_date_range_label', array('class'=>'required')); ?> +
                      + + +
                      + +
                      + + + + + - + + + +
                      + + lang->line('reports_sale_type'), 'reports_sale_type_label', array('class'=>'required')); ?> +
                      + $this->lang->line('reports_all'), 'sales' => $this->lang->line('reports_sales'), 'returns' => $this->lang->line('reports_returns')), 'all', 'id="sale_type"'); ?> +
                      + +
                      + Export to Excel: Yes + No +
                      + +'generate_report', + 'id'=>'generate_report', + 'content'=>$this->lang->line('common_submit'), + 'class'=>'submit_button') +); +?> + +load->view("partial/footer"); ?> + + \ No newline at end of file diff --git a/application/views/reports/excel_export.php b/application/views/reports/excel_export.php new file mode 100644 index 000000000..ab628c26a --- /dev/null +++ b/application/views/reports/excel_export.php @@ -0,0 +1,39 @@ +load->view("partial/header"); ?> +
                      lang->line('reports_report_input'); ?>
                      +".$error.""; +} +?> +
                      + Export to Excel: Yes + No +
                      + +'generate_report', + 'id'=>'generate_report', + 'content'=>$this->lang->line('common_submit'), + 'class'=>'submit_button') +); +?> + +load->view("partial/footer"); ?> + + \ No newline at end of file diff --git a/application/views/reports/graphical.php b/application/views/reports/graphical.php new file mode 100644 index 000000000..3a89407ee --- /dev/null +++ b/application/views/reports/graphical.php @@ -0,0 +1,27 @@ +load->view("partial/header"); +?> +
                      +
                      +
                      + + + +
                      +
                      +
                      +
                      +
                      +$value) { ?> +
                      lang->line('reports_'.$name). ': '.to_currency($value); ?>
                      + +
                      +load->view("partial/footer"); +?> \ No newline at end of file diff --git a/application/views/reports/graphs/bar.php b/application/views/reports/graphs/bar.php new file mode 100644 index 000000000..c42baf1cf --- /dev/null +++ b/application/views/reports/graphs/bar.php @@ -0,0 +1,46 @@ +output->set_header("Cache-Control: no-store, no-cache, must-revalidate"); +$this->output->set_header("Pragma: public"); +$bar = new bar_filled( '#4386a1', '#577261' ); + +$bar_labels = array(); +$bar_values = array(); + +foreach($data as $label=>$value) +{ + $bar_labels[] = (string)$label; + $bar_values[] = (float)$value; +} + +$bar->set_values($bar_values); + +$chart = new open_flash_chart(); +$chart->set_title(new title($title)); +$x = new x_axis(); +$x->steps(1); +$x->set_labels_from_array($bar_labels); +$chart->set_x_axis( $x ); + +$y = new y_axis(); +$y->set_tick_length(7); +$y->set_range(0, (count($data) > 0 ? max($data) : 0) + 25, ((count($data) > 0 ? max($data) : 0)+25)/10); +$chart->set_y_axis( $y ); +$chart->set_bg_colour("#f3f3f3"); + +$chart->add_element($bar); + +if (isset($yaxis_label)) +{ + $y_legend = new y_legend($yaxis_label ); + $y_legend->set_style( '{font-size: 20px; color: #000000}' ); + $chart->set_y_legend( $y_legend ); +} + +if (isset($xaxis_label)) +{ + $x_legend = new x_legend($xaxis_label ); + $x_legend->set_style( '{font-size: 20px; color: #000000}' ); + $chart->set_x_legend( $x_legend ); +} +echo $chart->toPrettyString(); +?> \ No newline at end of file diff --git a/application/views/reports/graphs/hbar.php b/application/views/reports/graphs/hbar.php new file mode 100644 index 000000000..10463f5c4 --- /dev/null +++ b/application/views/reports/graphs/hbar.php @@ -0,0 +1,61 @@ +output->set_header("Cache-Control: no-store, no-cache, must-revalidate"); +$this->output->set_header("Pragma: public"); + +$title = new title($title); + +$hbar = new hbar( '#86BBEF' ); +$hbar->set_tooltip($this->lang->line('reports_revenue').': #val#' ); +$y_labels = array(); +$max_value = 0; +foreach($data as $label=>$value) +{ + if ($max_value < $value) + { + $max_value = $value; + } + $y_labels[] = (string)$label; + $hbar->append_value( new hbar_value(0,(float)$value) ); +} +$chart = new open_flash_chart(); +$chart->set_title( $title ); +$chart->add_element( $hbar ); + +$step_count = $max_value > 0 ? $max_value/10 : 1; +$x = new x_axis(); +$x->set_offset( false ); +$x->set_steps($max_value/10); + +$chart->set_x_axis( $x ); + +$y = new y_axis(); +$y->set_offset( true ); +$y->set_labels(array_reverse($y_labels)); +$chart->add_y_axis( $y ); + +if (isset($yaxis_label)) +{ + $y_legend = new y_legend($yaxis_label ); + $y_legend->set_style( '{font-size: 20px; color: #000000}' ); + $chart->set_y_legend( $y_legend ); +} + +if (isset($xaxis_label)) +{ + $x_legend = new x_legend($xaxis_label ); + $x_legend->set_style( '{font-size: 20px; color: #000000}' ); + $chart->set_x_legend( $x_legend ); +} + +$chart->set_bg_colour("#f3f3f3"); + +$tooltip = new tooltip(); +$tooltip->set_hover(); +$tooltip->set_stroke( 1 ); +$tooltip->set_colour( "#000000" ); +$tooltip->set_background_colour( "#ffffff" ); +$chart->set_tooltip( $tooltip ); + + +echo $chart->toPrettyString(); +?> \ No newline at end of file diff --git a/application/views/reports/graphs/line.php b/application/views/reports/graphs/line.php new file mode 100644 index 000000000..62fa570e6 --- /dev/null +++ b/application/views/reports/graphs/line.php @@ -0,0 +1,49 @@ +output->set_header("Cache-Control: no-store, no-cache, must-revalidate"); +$this->output->set_header("Pragma: public"); +$line_data = array(); +$labels = array(); +foreach($data as $label=>$value) +{ + $line_data[] = (float)$value; + $labels[] = (string)$label; +} + +$hol = new hollow_dot(); +$hol->size(3)->halo_size(1)->tooltip('#x_label#
                      #val#'); + +$line = new line(); +$line->set_default_dot_style($hol); +$line->set_values($line_data); + +$chart = new open_flash_chart(); +$chart->set_title(new title($title)); +$chart->add_element($line); + +$x = new x_axis(); +$x->steps(count($data) > 10 ? (int)(count($data)/4) : 1); +$x->set_labels_from_array($labels); +$chart->set_x_axis( $x ); + +$y = new y_axis(); +$y->set_tick_length(7); +$y->set_range(0, (count($data) > 0 ? max($data) : 0) + 25, ((count($data) > 0 ? max($data) : 0)+25)/10); +$chart->set_y_axis( $y ); +$chart->set_bg_colour("#f3f3f3"); + +if (isset($yaxis_label)) +{ + $y_legend = new y_legend($yaxis_label ); + $y_legend->set_style( '{font-size: 20px; color: #000000}' ); + $chart->set_y_legend( $y_legend ); +} + +if (isset($xaxis_label)) +{ + $x_legend = new x_legend($xaxis_label ); + $x_legend->set_style( '{font-size: 20px; color: #000000}' ); + $chart->set_x_legend( $x_legend ); +} + +echo $chart->toPrettyString(); +?> \ No newline at end of file diff --git a/application/views/reports/graphs/pie.php b/application/views/reports/graphs/pie.php new file mode 100644 index 000000000..fda94d8b6 --- /dev/null +++ b/application/views/reports/graphs/pie.php @@ -0,0 +1,25 @@ +output->set_header("Cache-Control: no-store, no-cache, must-revalidate"); +$this->output->set_header("Pragma: public"); +$title = new title($title); + +$pie = new pie(); +$pie->set_alpha(0.6); +$pie->set_start_angle( 35 ); +$pie->add_animation( new pie_fade() ); +$pie->set_tooltip( '#val# of #total#
                      #percent# of 100%' ); +$pie->set_colours(get_random_colors(count($data))); + +$pie_values = array(); +foreach($data as $label=>$value) +{ + $pie_values[] = new pie_value((float)$value, (string)$label); +} +$pie->set_values($pie_values); +$chart = new open_flash_chart(); +$chart->set_title( $title ); +$chart->set_bg_colour("#f3f3f3"); +$chart->add_element( $pie ); +$chart->x_axis = null; +echo $chart->toPrettyString(); +?> \ No newline at end of file diff --git a/application/views/reports/listing.php b/application/views/reports/listing.php new file mode 100644 index 000000000..44728e8c6 --- /dev/null +++ b/application/views/reports/listing.php @@ -0,0 +1,63 @@ + +load->view("partial/header"); ?> +
                      lang->line('reports_reports'); ?>
                      +"; +} +?> +load->view("partial/footer"); ?> + + diff --git a/application/views/reports/specific_input.php b/application/views/reports/specific_input.php new file mode 100644 index 000000000..7bb1710ac --- /dev/null +++ b/application/views/reports/specific_input.php @@ -0,0 +1,90 @@ +load->view("partial/header"); ?> +
                      lang->line('reports_report_input'); ?>
                      +".$error.""; +} +?> + lang->line('reports_date_range'), 'report_date_range_label', array('class'=>'required')); ?> +
                      + + +
                      + +
                      + + + + + - + + + +
                      + + 'required')); ?> + +
                      + +
                      + + lang->line('reports_sale_type'), 'reports_sale_type_label', array('class'=>'required')); ?> +
                      + $this->lang->line('reports_all'), 'sales' => $this->lang->line('reports_sales'), 'returns' => $this->lang->line('reports_returns')), 'all', 'id="sale_type"'); ?> +
                      + +
                      + Export to Excel: Yes + No +
                      + +'generate_report', + 'id'=>'generate_report', + 'content'=>$this->lang->line('common_submit'), + 'class'=>'submit_button') +); +?> + +load->view("partial/footer"); ?> + + \ No newline at end of file diff --git a/application/views/reports/tabular.php b/application/views/reports/tabular.php new file mode 100644 index 000000000..41643227b --- /dev/null +++ b/application/views/reports/tabular.php @@ -0,0 +1,70 @@ +load->view("partial/header_excel"); +}else{ + $this->load->view("partial/header"); +} +?> +
                      +
                      +
                      + + + + + + + + + + + + + + + + + +
                      +
                      +
                      +$value) { ?> +
                      lang->line('reports_'.$name). ': '.to_currency($value); ?>
                      + +
                      +load->view("partial/footer_excel"); + $content = ob_end_flush(); + + $filename = trim($filename); + $filename = str_replace(array(' ', '/', '\\'), '', $title); + $filename .= "_Export.xls"; + header('Content-type: application/ms-excel'); + header('Content-Disposition: attachment; filename='.$filename); + echo $content; + die(); + +}else{ + $this->load->view("partial/footer"); +?> + + + \ No newline at end of file diff --git a/application/views/reports/tabular_details.php b/application/views/reports/tabular_details.php new file mode 100644 index 000000000..133a749a4 --- /dev/null +++ b/application/views/reports/tabular_details.php @@ -0,0 +1,102 @@ +load->view("partial/header_excel"); +}else{ + $this->load->view("partial/header"); +} +?> +
                      +
                      +
                      + + + + + + + + + + + $row) { ?> + + + + + + + + + + + +
                      +
                      +
                      + + + + + + + + + + + + + + + + + + + +
                      + +
                      +
                      +
                      +$value) { ?> +
                      lang->line('reports_'.$name). ': '.to_currency($value); ?>
                      + +
                      +load->view("partial/footer_excel"); + $content = ob_end_flush(); + + $filename = trim($filename); + $filename = str_replace(array(' ', '/', '\\'), '', $title); + $filename .= "_Export.xls"; + header('Content-type: application/ms-excel'); + header('Content-Disposition: attachment; filename='.$filename); + echo $content; + die(); + +}else{ + $this->load->view("partial/footer"); +?> + + \ No newline at end of file diff --git a/application/views/sales/delete.php b/application/views/sales/delete.php new file mode 100644 index 000000000..56d182282 --- /dev/null +++ b/application/views/sales/delete.php @@ -0,0 +1,18 @@ +load->view("partial/header"); ?> +
                      + +

                      lang->line('sales_delete_successful'); ?>

                      + +

                      lang->line('sales_delete_unsuccessful'); ?>

                      + +
                      +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/application/views/sales/edit.php b/application/views/sales/edit.php new file mode 100644 index 000000000..a93f7577f --- /dev/null +++ b/application/views/sales/edit.php @@ -0,0 +1,109 @@ +load->view("partial/header"); ?> +
                      +

                      lang->line('sales_edit_sale'); ?> POS

                      + + 'sales_edit_form')); ?> +
                        + +
                        + lang->line('sales_receipt').':', 'customer'); ?> +
                        + '_blank'));?> +
                        +
                        + +
                        + lang->line('sales_date').':', 'date'); ?> +
                        + 'date','value'=>date('m/d/Y', strtotime($sale_info['sale_time'])), 'id'=>'date'));?> +
                        +
                        + +
                        + lang->line('sales_customer').':', 'customer'); ?> +
                        + +
                        +
                        + +
                        + lang->line('sales_employee').':', 'employee'); ?> +
                        + +
                        +
                        + +
                        + lang->line('sales_comment').':', 'comment'); ?> +
                        + 'comment','value'=>$sale_info['comment'],'rows'=>'4','cols'=>'23', 'id'=>'comment'));?> +
                        +
                        + + 'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_left') + ); + ?> + + 'sales_delete_form')); ?> + 'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('sales_delete_entire_sale'), + 'class'=>'delete_button float_right') + ); + ?> + + +
                        +
                        +load->view("partial/footer"); ?> + + \ No newline at end of file diff --git a/application/views/sales/receipt.php b/application/views/sales/receipt.php new file mode 100644 index 000000000..6031cc643 --- /dev/null +++ b/application/views/sales/receipt.php @@ -0,0 +1,120 @@ +load->view("partial/header"); ?> +'.$error_message.''; + exit; +} +?> +
                        +
                        +
                        config->item('company'); ?>
                        +
                        config->item('address')); ?>
                        +
                        config->item('phone'); ?>
                        +
                        +
                        +
                        +
                        + +
                        lang->line('customers_customer').": ".$customer; ?>
                        + +
                        lang->line('sales_id').": ".$sale_id; ?>
                        +
                        lang->line('employees_employee').": ".$employee; ?>
                        +
                        + + + + + + + + + + + $item) + { + ?> + + + + + + + + + + + + + + + + + + + + + + $value) { ?> + + + + + + + + + + + + + + $payment) + { ?> + + + + + + + + + + + + + + +
                        lang->line('sales_item_number'); ?>lang->line('items_item'); ?>lang->line('common_price'); ?>lang->line('sales_quantity'); ?>lang->line('sales_discount'); ?>lang->line('sales_total'); ?>
                        lang->line('sales_sub_total'); ?>
                        :
                        lang->line('sales_total'); ?>
                         
                        lang->line('sales_payment'); ?>
                         
                        lang->line('sales_change_due'); ?>
                        + +
                        + config->item('return_policy')); ?> +
                        +
                        + "; ?> +
                        +
                        +load->view("partial/footer"); ?> + +Appconfig->get('print_after_sale')) +{ +?> + + \ No newline at end of file diff --git a/application/views/sales/receipt_email.php b/application/views/sales/receipt_email.php new file mode 100644 index 000000000..721fc976c --- /dev/null +++ b/application/views/sales/receipt_email.php @@ -0,0 +1,95 @@ +
                        +
                        +
                        config->item('company'); ?>
                        +
                        config->item('address')); ?>
                        +
                        config->item('phone'); ?>
                        +
                        +
                        +
                        +
                        + +
                        lang->line('customers_customer').": ".$customer; ?>
                        + +
                        lang->line('sales_id').": ".$sale_id; ?>
                        +
                        lang->line('employees_employee').": ".$employee; ?>
                        +
                        + + + + + + + + + + + $item) + { + ?> + + + + + + + + + + + + + + + + + + + + + + $value) { ?> + + + + + + + + + + + + + + $payment) + { ?> + + + + + + + + + + + + + + +
                        lang->line('sales_item_number'); ?>lang->line('items_item'); ?>lang->line('common_price'); ?>lang->line('sales_quantity'); ?>lang->line('sales_discount'); ?>lang->line('sales_total'); ?>
                        lang->line('sales_sub_total'); ?>
                        :
                        lang->line('sales_total'); ?>
                         
                        lang->line('sales_payment'); ?>
                         
                        lang->line('sales_change_due'); ?>
                        + +
                        + config->item('return_policy')); ?> +
                        +
                        \ No newline at end of file diff --git a/application/views/sales/register.php b/application/views/sales/register.php new file mode 100644 index 000000000..d206ede20 --- /dev/null +++ b/application/views/sales/register.php @@ -0,0 +1,493 @@ +load->view("partial/header"); ?> +
                        lang->line('sales_register'); ?>
                        +".$error.""; +} + +if (isset($warning)) +{ + echo "
                        ".$warning."
                        "; +} + +if (isset($success)) +{ + echo "
                        ".$success."
                        "; +} +?> +
                        +'mode_form')); ?> + lang->line('sales_mode') ?> + +
                        + ".$this->lang->line('sales_suspended_sales')."
                        ", + array('class'=>'thickbox none','title'=>$this->lang->line('sales_suspended_sales'))); + ?> +
                        + +'add_item_form')); ?> + +'item','id'=>'item','size'=>'40'));?> +
                        + ".$this->lang->line('sales_new_item')."
                        ", + array('class'=>'thickbox none','title'=>$this->lang->line('sales_new_item'))); + ?> + + + + + + + + + + + + + + + + + + + +$item) + { + $cur_item_info = $this->Item->get_info($item['item_id']); + echo form_open("sales/edit_item/$line"); + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        lang->line('common_delete'); ?>lang->line('sales_item_number'); ?>lang->line('sales_item_name'); ?>lang->line('sales_price'); ?>lang->line('sales_quantity'); ?>lang->line('sales_discount'); ?>lang->line('sales_total'); ?>lang->line('sales_edit'); ?>
                        +
                        lang->line('sales_no_items_in_cart'); ?>
                        +
                        lang->line('common_delete').']');?>
                        [quantity; ?> in stock]
                        'price','value'=>$item['price'],'size'=>'6'));?> + 'quantity','value'=>$item['quantity'],'size'=>'2')); + } + ?> + 'discount','value'=>$item['discount'],'size'=>'3'));?>lang->line('sales_edit_item'));?>
                        lang->line('sales_description_abbrv').':';?> + + 'description','value'=>$item['description'],'size'=>'20')); + } + else + { + if ($item['description']!='') + { + echo $item['description']; + echo form_hidden('description',$item['description']); + } + else + { + echo 'None'; + echo form_hidden('description',''); + } + } + ?> +   + lang->line('sales_serial').':'; + } + ?> + + 'serialnumber','value'=>$item['serialnumber'],'size'=>'20')); + } + else + { + echo form_hidden('serialnumber', ''); + } + ?> +
                        + + + +
                        + lang->line("sales_customer").': '.$customer. '
                        '; + echo anchor("sales/remove_customer",'['.$this->lang->line('common_remove').' '.$this->lang->line('customers_customer').']'); + } + else + { + echo form_open("sales/select_customer",array('id'=>'select_customer_form')); ?> + + 'customer','id'=>'customer','size'=>'30','value'=>$this->lang->line('sales_start_typing_customer_name')));?> + +
                        +

                        lang->line('common_or'); ?>

                        + ".$this->lang->line('sales_new_customer')."
                        ", + array('class'=>'thickbox none','title'=>$this->lang->line('sales_new_customer'))); + ?> +
                        +
                         
                        + + +
                        +
                        lang->line('sales_sub_total'); ?>:
                        +
                        + + $value) { ?> +
                        :
                        +
                        + + +
                        lang->line('sales_total'); ?>:
                        +
                        +
                        + + + + + 0) + { + ?> + +
                        + 'cancel_sale_form')); ?> +
                        + lang->line('sales_cancel_sale'); ?> +
                        + +
                        +
                         
                        + 0) + { + ?> +
                        + 'finish_sale_form')); ?> + + 'comment', 'id' => 'comment', 'value'=>$comment,'rows'=>'4','cols'=>'23'));?> +

                        + + lang->line('sales_email_receipt'). ': '. form_checkbox(array( + 'name' => 'email_receipt', + 'id' => 'email_receipt', + 'value' => '1', + 'checked' => (boolean)$email_receipt, + )).'
                        ('.$customer_email.')
                        '; + } + + if ($payments_cover_total) + { + echo "
                        ".$this->lang->line('sales_complete_sale')."
                        "; + } + echo "
                        ".$this->lang->line('sales_suspend_sale')."
                        "; + ?> +
                        + + + + + + + + + + + + +
                        + +
                        + +
                        + + 'add_payment_form')); ?> + + + + + + + + + +
                        + lang->line('sales_payment').': ';?> + + +
                        + lang->line( 'sales_amount_tendered' ).': '; ?> + + 'amount_tendered', 'id'=>'amount_tendered', 'value'=>to_currency_no_money($amount_due), 'size'=>'10' ) ); ?> +
                        +
                        + lang->line('sales_add_payment'); ?> +
                        +
                        + + + 0) + { + ?> + + + + + + + + + + + + $payment) + { + echo form_open("sales/edit_payment/$payment_id",array('id'=>'edit_payment_form'.$payment_id)); + ?> + + + + + + + + + + + +
                        lang->line('common_delete'); ?>
                        lang->line('common_delete').']' ); ?>
                        +
                        + + + + +
                        + + + +
                         
                        + + +load->view("partial/footer"); ?> + + diff --git a/application/views/sales/suspended.php b/application/views/sales/suspended.php new file mode 100644 index 000000000..d84667cfe --- /dev/null +++ b/application/views/sales/suspended.php @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + +
                        lang->line('sales_suspended_sale_id'); ?>lang->line('sales_date'); ?>lang->line('sales_customer'); ?>lang->line('sales_comments'); ?>lang->line('sales_unsuspend_and_delete'); ?>
                        + Customer->get_info($suspended_sale['customer_id']); + echo $customer->first_name. ' '. $customer->last_name; + } + else + { + ?> +   + + + +
                        \ No newline at end of file diff --git a/application/views/suppliers/form.php b/application/views/suppliers/form.php new file mode 100644 index 000000000..02ace852e --- /dev/null +++ b/application/views/suppliers/form.php @@ -0,0 +1,78 @@ +person_id,array('id'=>'supplier_form')); +?> +
                        lang->line('common_fields_required_message'); ?>
                        +
                          +
                          +lang->line("suppliers_basic_information"); ?> + +
                          +lang->line('suppliers_company_name').':', 'company_name', array('class'=>'required')); ?> +
                          + 'company_name', + 'id'=>'company_name_input', + 'value'=>$person_info->company_name) + );?> +
                          +
                          + +load->view("people/form_basic_info"); ?> +
                          +lang->line('suppliers_account_number').':', 'account_number'); ?> +
                          + 'account_number', + 'id'=>'account_number', + 'value'=>$person_info->account_number) + );?> +
                          +
                          +'submit', + 'id'=>'submit', + 'value'=>$this->lang->line('common_submit'), + 'class'=>'submit_button float_right') +); +?> +
                          + + \ No newline at end of file diff --git a/application/views/suppliers/manage.php b/application/views/suppliers/manage.php new file mode 100644 index 000000000..db3bb7d71 --- /dev/null +++ b/application/views/suppliers/manage.php @@ -0,0 +1,85 @@ +load->view("partial/header"); ?> + + +
                          +
                          lang->line('common_list_of').' '.$this->lang->line('module_'.$controller_name); ?>
                          +
                          + ".$this->lang->line($controller_name.'_new')."
                          ", + array('class'=>'thickbox none','title'=>$this->lang->line($controller_name.'_new'))); + ?> +
                          + +pagination->create_links();?> +
                          + +
                          +
                          + +
                          +
                          +load->view("partial/footer"); ?> \ No newline at end of file diff --git a/css/autocomplete.css b/css/autocomplete.css new file mode 100644 index 000000000..a062d0410 --- /dev/null +++ b/css/autocomplete.css @@ -0,0 +1,54 @@ +.ac_results +{ + padding: 0px; + border: 1px solid black; + background-color: white; + overflow: hidden; + z-index: 99999; +} + +.ac_results ul +{ + width: 100%; + list-style-position: outside; + list-style: none; + padding: 0; + margin: 0; +} + +.ac_results li +{ + margin: 0px; + padding: 2px 5px; + cursor: default; + display: block; + /* + if width will be 100% horizontal scrollbar will apear + when scroll mode will be used + */ + /*width: 100%;*/ + font: menu; + font-size: 12px; + /* + it is very important, if line-height not setted or setted + in relative units scroll will be broken in firefox + */ + line-height: 16px; + overflow: hidden; +} + +.ac_loading +{ + background: white url('../images/spinner_small.gif') right center no-repeat; +} + +.ac_odd +{ + background-color: #eee; +} + +.ac_over +{ + background-color: #0A246A; + color: white; +} diff --git a/css/datepicker.css b/css/datepicker.css new file mode 100644 index 000000000..2b2a12805 --- /dev/null +++ b/css/datepicker.css @@ -0,0 +1,153 @@ +table.jCalendar { + border: 1px solid #000; + background: #aaa; + border-collapse: separate; + border-spacing: 2px; +} +table.jCalendar th { + background: #333; + color: #fff; + font-weight: bold; + padding: 3px 5px; +} + +table.jCalendar td { + background: #ccc; + color: #000; + padding: 3px 5px; + text-align: center; +} +table.jCalendar td.other-month { + background: #ddd; + color: #aaa; +} +table.jCalendar td.today { + background: #666; + color: #fff; +} +table.jCalendar td.selected { + background: #f66; + color: #fff; +} +table.jCalendar td.selected.dp-hover { + background: #f33; + color: #fff; +} +table.jCalendar td.dp-hover, +table.jCalendar tr.activeWeekHover td { + background: #fff; + color: #000; +} +table.jCalendar tr.selectedWeek td { + background: #f66; + color: #fff; +} +table.jCalendar td.disabled, table.jCalendar td.disabled.dp-hover { + background: #bbb; + color: #888; +} +table.jCalendar td.unselectable, +table.jCalendar td.unselectable:hover, +table.jCalendar td.unselectable.dp-hover { + background: #bbb; + color: #888; +} + +/* For the popup */ + +/* NOTE - you will probably want to style a.dp-choose-date - see how I did it in demo.css */ + +div.dp-popup { + position: relative; + background: #ccc; + font-size: 10px; + font-family: arial, sans-serif; + padding: 2px; + width: 171px; + line-height: 1.2em; +} +div#dp-popup { + position: absolute; + z-index: 199; +} +div.dp-popup h2 { + font-size: 12px; + text-align: center; + margin: 2px 0; + padding: 0; +} +a#dp-close { + font-size: 11px; + padding: 4px 0; + text-align: center; + display: block; +} +a#dp-close:hover { + text-decoration: underline; +} +div.dp-popup a { + color: #000; + text-decoration: none; + padding: 3px 2px 0; +} +div.dp-popup div.dp-nav-prev { + position: absolute; + top: 2px; + left: 4px; + width: 100px; +} +div.dp-popup div.dp-nav-prev a { + float: left; +} +/* Opera needs the rules to be this specific otherwise it doesn't change the cursor back to pointer after you have disabled and re-enabled a link */ +div.dp-popup div.dp-nav-prev a, div.dp-popup div.dp-nav-next a { + cursor: pointer; +} +div.dp-popup div.dp-nav-prev a.disabled, div.dp-popup div.dp-nav-next a.disabled { + cursor: default; +} +div.dp-popup div.dp-nav-next { + position: absolute; + top: 2px; + right: 4px; + width: 100px; +} +div.dp-popup div.dp-nav-next a { + float: right; +} +div.dp-popup a.disabled { + cursor: default; + color: #aaa; +} +div.dp-popup td { + cursor: pointer; +} +div.dp-popup td.disabled { + cursor: default; +} + +/* located in demo.css and creates a little calendar icon + * instead of a text link for "Choose date" + */ +a.dp-choose-date { + float: left; + width: 16px; + height: 16px; + padding: 0; + margin: 0px 3px 0; + display: block; + text-indent: -2000px; + overflow: hidden; + background: url(../images/calendar.png) no-repeat; +} +a.dp-choose-date.dp-disabled { + background-position: 0 -20px; + cursor: default; +} +/* makes the input field shorter once the date picker code + * has run (to allow space for the calendar icon + */ +input.dp-applied { + width: 100px; + float: left; +} \ No newline at end of file diff --git a/css/editsale.css b/css/editsale.css new file mode 100644 index 000000000..2ba8f43a9 --- /dev/null +++ b/css/editsale.css @@ -0,0 +1,11 @@ +#edit_sale_wrapper +{ + margin: 0 auto; + padding-bottom: 50px; + width: 60%; +} + +#edit_sale_wrapper h1 +{ + text-align: center; +} \ No newline at end of file diff --git a/css/general.css b/css/general.css new file mode 100644 index 000000000..5d8373ba9 --- /dev/null +++ b/css/general.css @@ -0,0 +1,154 @@ +.field_row +{ + margin: 0 0 10px 0; +} + +.field_row label +{ + float:left; + width:100px; + text-align:left; + line-height:2.3; +} + +.field_row label.wide +{ + width:150px; +} + +label.required +{ + color:red; +} + +.form_field +{ + float:left; + padding: 3px; + background-color: #f2f2f2; +} + +.form_field input, .form_field textarea +{ + border: 1px solid #ccc; + padding: 4px; +} + +.submit_button +{ + padding: 5px; + color: #fff; + background-color: #0a6184; + border: 2px solid #ddd; +} + +.delete_button +{ + padding: 5px; + color: #fff; + background-color: #ea4729; + border: 2px solid #ddd; +} +.small_button +{ + position:relative; + width:95px; + height:30px; + background-image: url(../images/small_action_button.jpg); + background-repeat:no-repeat; + cursor:pointer; +} +.small_button span +{ + position:absolute; + width:100%; + top:30%; + left:0%; + color:#FFF; + font-size:11px; + font-weight:bold; + text-align:center; +} + +.float_left +{ + float:left; +} + +.float_right +{ + float:right; +} + +.big_button +{ + position:relative; + width:119px; + height:45px; + background-image: url(../images/big_action_button.jpg); + background-repeat:no-repeat; + cursor:pointer; +} + +.big_button span +{ + position:absolute; + width:100%; + top:35%; + color:#FFF; + font-size:13px; + font-weight:bold; + text-align:center; +} + + +.warning_message +{ + text-align:center; + background-color:#fffcdd; + border:1px solid #fff4aa; + font-weight:bold; +} + +.error_message +{ + text-align:center; + background-color:#f68383; + border:1px solid #da3232; + font-weight:bold; +} + +.warning_mesage +{ + text-align:center; + background-color:#FBEC5D; + border:1px solid #da3232; + font-weight:bold; +} + +.success_message +{ + text-align:center; + background-color:#e1ffdd; + border:1px solid #2ca71c; + font-weight:bold; +} + +input +{ + font-family:arial; + padding: 3px; +} + +.clearfix:after +{ + content: "."; + display: block; + clear: both; + visibility: hidden; + line-height: 0; + height: 0; +} +.clearfix { display: inline-block; } +html[xmlns] .clearfix { display: block; } +* html .clearfix { height: 1%; } diff --git a/css/login.css b/css/login.css new file mode 100644 index 000000000..30809f1cf --- /dev/null +++ b/css/login.css @@ -0,0 +1,84 @@ +body +{ + text-align:center; +} +#container +{ + position:relative; + margin-left:auto; + margin-right:auto; + margin-top:20px; + width:360px; + +} + +#top +{ + position:relative; + width:100%; + height:20px; + padding:2px; + background-color:#005B7F; + text-align:center; + font-family:Verdana; + color:white; + font-size:12pt; +} + +#login_form +{ + position:relative; + width:100%; + height:230px; + padding:2px; + font-family:Verdana; + color:white; + font-size:10pt; + background-color:#A7A7A7; +} + +#welcome_message +{ + text-align:center; + margin-top:10px; + margin-bottom:20px; +} + +.error +{ + margin:0 auto; + border:3px solid #d3153b; + background-color:#fbe6f2; + padding:5px; + width:80%; + text-align:center; + font-size:18px; + margin-bottom:20px; + +} + +.form_field_label +{ + float:left; + margin-left:20px; + width:30%; +} + +.form_field +{ + float:left; + width:30%; +} + +#submit_button +{ + position:absolute; + bottom:60px; + right:60px; +} + +input +{ + font-family:Arial; +} + diff --git a/css/menubar.css b/css/menubar.css new file mode 100644 index 000000000..fe2133d1f --- /dev/null +++ b/css/menubar.css @@ -0,0 +1,93 @@ +#menubar +{ + position:relative; + margin:0px; + padding:0px; + background-image: url("../images/menubar/menubar_bg.gif"); + background-repeat: repeat-x; + width:100%; + height:100px; + color:#FFFFFF; + text-align:left; + text-align:center; +} + +#menubar_container +{ + position:relative; + margin:0 auto; + width:875px; + text-align:left; +} + +.menu_item +{ + float:left; + width:65px; + height:100%; + text-align:center; +} + + +#menubar a:link, #menubar a:visited, #menubar a +{ + color:#FFFFFF; + text-decoration:underline; +} + +#menubar a:hover +{ + color:#CCCCCC; + text-decoration:underline; +} + +.menu_item +{ + font-size:8pt; +} + +#menubar_company_info +{ + position:absolute; + left:0px; + top:18px; + width:250px; + height:55%; +} + +#company_title +{ + font-size:14pt; + font-weight:bold; +} + +#menubar_navigation +{ + position:relative; + width:75%; + left:200px; + top:8px; + height:45%; +} + +#menubar_footer +{ + position:absolute; + top:80px; + left:0px; + height:17%; + padding-top:3px; + font-size:8pt; + font-weight:bold; +} + +#menubar_date +{ + position:absolute; + top:80px; + right:0px; + height:17%; + padding-top:3px; + font-size:8pt; + font-weight:bold; +} \ No newline at end of file diff --git a/css/ospos.css b/css/ospos.css new file mode 100644 index 000000000..7cbf4c522 --- /dev/null +++ b/css/ospos.css @@ -0,0 +1,149 @@ +@import url(autocomplete.css); +@import url(menubar.css); +@import url(general.css); +@import url(popupbox.css); +@import url(register.css); +@import url(receipt.css); +@import url(reports.css); +@import url(tables.css); +@import url(thickbox.css); +@import url(datepicker.css); +@import url(editsale.css); + +body +{ + margin:0px; + padding:0px; + background-color:#f7f7f7; +} + +a.none +{ + text-decoration:none; +} + + +#content_area_wrapper +{ + position:relative; + width:100%; + background-color:#FFFFFF; + margin:0px; + padding:0px; + border-bottom:1px solid #CCCCCC; + text-align:center; + +} + +#content_area +{ + position:relative; + margin:0 auto; + width:875px; + text-align:left; + +} + +#title_bar +{ + position:relative; + margin-top:10px; + margin-bottom:10px; + width:100%; + height:50px; +} + +#title +{ + position:absolute; + bottom:0px; + left:0px; + font-size:30px; + font-weight:bold; + color:#000000; +} + +#page_title +{ + margin-top:8px; + font-size:30px; + font-weight:bold; + color:#000000; + text-align:center; + +} + +#page_subtitle +{ + margin-top:8px; + font-size:16px; + font-weight:bold; + color:#000000; + text-align:center; +} + +#new_button +{ + position:absolute; + bottom:-5px; + right:0px; +} + +#spinner +{ + position:absolute; + display:none; + right:21%; + top:5px; +} + +#feedback_bar +{ + position:fixed; + bottom:0; + left:0; + width:100%; + height:55px; + position:fixed; + opacity: 0; + filter: alpha(opacity=0); + z-index:1; + line-height:3.3; +} + +#home_module_list +{ + position: relative; +} + +.module_item +{ + padding: 10px; +} + +#config_wrapper +{ + text-align:center; +} + +#config_info +{ + width:70%; + margin:0 auto; + padding:10px; + margin-bottom:30px; + margin-top:10px; + text-align:left; +} + +#footer +{ + position:relative; + margin-top:25px; + margin-bottom:15px; + text-align:center; + font-size:11px; + color:#777777; + clear:both; + +} diff --git a/css/ospos_print.css b/css/ospos_print.css new file mode 100644 index 000000000..9e29b4149 --- /dev/null +++ b/css/ospos_print.css @@ -0,0 +1,41 @@ +body +{ + background-color:#FFFFFF; + font-size:75%; +} + +#menubar,#footer +{ + display:none; +} + +#content_area +{ + width:100%; +} + +#content_area_wrapper +{ + border:0px; +} + +#sale_return_policy +{ + width:100%; + text-align:center; +} + +.long_name +{ + display:none; +} + +.short_name +{ + display:inline; +} + +#receipt_items td +{ + white-space:nowrap; +} diff --git a/css/popupbox.css b/css/popupbox.css new file mode 100644 index 000000000..f81b2814c --- /dev/null +++ b/css/popupbox.css @@ -0,0 +1,99 @@ +#required_fields_message +{ + width: 100%; + text-align: center; + margin-bottom: 3px; + font-style: italic; +} + +#customer_basic_info,#item_basic_info,#item_number_info,#supplier_basic_info +{ + padding: 5px; +} + +#scan_item_number.loading +{ + background-image: url(../images/spinner_small.gif); + background-position:center right; + background-repeat:no-repeat; +} + +#info_provided_by +{ + display:none; + font-weight:bold; +} + +#employee_basic_info +{ + float:left; + width:47%; + padding:5px; +} + +#employee_login_info +{ + float:left; + width:47%; + margin-left:5px; + padding:5px; +} + +#permission_list +{ + list-style:none; +} + +#permission_list li +{ + padding:5px; +} + +#permission_list input +{ + top:3px; +} + +#employee_permission_info +{ + float:left; + width:47%; + margin-left:5px; + padding:5px; +} +#employee_permission_info p +{ + font-weight:bold; +} + +#employee_permission_info span.small +{ + font-style:italic; + font-size:80%; +} + +#error_message_box +{ + margin-bottom:7px; + margin-left:20px; + color:red; +} +#item_kit_items_title +{ + text-align: center; +} +#item_kit_items +{ + width: 100%; +} + +#item_kit_items th +{ + text-align: center; + font-weight: bold; +} + +#item_kit_items td +{ + text-align: center; +} \ No newline at end of file diff --git a/css/receipt.css b/css/receipt.css new file mode 100644 index 000000000..d891460b4 --- /dev/null +++ b/css/receipt.css @@ -0,0 +1,60 @@ +#receipt_wrapper +{ + font-family:Arial; + width:100%; +} + +#receipt_header +{ + text-align:center; +} + +#company_name +{ + font-size:150%; + font-weight:bold; +} + +#company_phone +{ + margin-bottom:15px; + +} + +#sale_time +{ + margin-bottom:5px; +} + +#receipt_items +{ + position:relative; + border-collapse:collapse; + margin-top:15px; + margin-bottom:15px; + width:100%; +} + +#receipt_items td +{ + position:relative; + padding:3px; +} + +.short_name +{ + display:none; +} + +#sale_return_policy +{ + width:80%; + margin:0 auto; + text-align:center; +} + +#barcode +{ + margin-top:10px; + text-align:center; +} \ No newline at end of file diff --git a/css/register.css b/css/register.css new file mode 100644 index 000000000..090886586 --- /dev/null +++ b/css/register.css @@ -0,0 +1,165 @@ +#register_wrapper +{ + float:left; + width:70%; + font-family:Arial; + font-size:13px; +} +#mode_form +{ + position:relative; + background-color:#DDD; + padding: 8px 0px 8px 0px; +} + +#show_suspended_sales_button +{ + position:absolute; + top:3px; + right:4px; +} + +#mode_form span +{ + font-weight:bold; +} + +#add_item_form +{ + position:relative; + background-color:#BBBBBB; + width:100%; + padding: 8px 0px 8px 0px; + +} + +#new_item_button_register +{ + position:absolute; + top:3px; + right:4px; +} + +#add_item_form input +{ + border: 1px solid #ccc; + padding: 2px; + +} + +#item_label,#customer_label +{ + font-weight:bold; +} + +#add_item_form label +{ + margin: 0px 5px 0px 5px; +} + +#register +{ + position:relative; + width:100%; + padding:0px; + border-collapse:collapse; +} + +#register th +{ + background-color:#4386a1; + padding:5px; + text-align:center; + color:#FFFFFF; +} + +#register td +{ + background-color:#EEEEEE; + padding:3px; + text-align:center; +} + +#overall_sale +{ + float:left; + margin-left:4px; + background-color:#BBBBBB; + width:28%; + padding:5px; + font-family:Arial; + font-size:13px; + +} + +#sale_details +{ + position:relative; + width:100%; + margin-top:5px; + border-top:2px solid #000; +} + +#finish_sale +{ + position:relative; +} + +#Payment_Types +{ + float:left; + width:100%; + margin-top:5px; + border-top:2px solid #000; + background-color:#DDD; + margin-bottom:0px; + clear:both; +} + +#Cancel_sale +{ + float:left; + width:100%; + margin-top:5px; + clear:both; +} +#suspended_sales_table th +{ + text-align:center; +} + +#suspended_sales_table td +{ + padding: 7px; +} + +#credit_card_form fieldset +{ + overflow: auto; + border: 0; + margin: 0; + padding: 0; +} + +#credit_card_form fieldset div +{ + float: left; +} + +#credit_card_form fieldset.centered div +{ + text-align: center; +} + +#credit_card_form label +{ + display: block; + margin-bottom: 5px; +} + +#credit_card_form input.text +{ + border: 1px solid #bfbab4; + margin: 0 4px 8px 0; +} + diff --git a/css/reports.css b/css/reports.css new file mode 100644 index 000000000..088071ab3 --- /dev/null +++ b/css/reports.css @@ -0,0 +1,26 @@ +#report_list li ul li +{ + margin-left: 35px; +} +#report_date_range_simple +{ + margin-bottom: 3px; +} +.report +{ + font-size: .85em; +} +#report_summary +{ + margin: 0 auto; + text-align: center; +} + +#report_summary .summary_row +{ +} + +#chart_wrapper +{ + text-align: center; +} \ No newline at end of file diff --git a/css/tables.css b/css/tables.css new file mode 100644 index 000000000..d734ab881 --- /dev/null +++ b/css/tables.css @@ -0,0 +1,126 @@ +#table_action_header +{ + position:relative; + width:100%; + background-color:#EEEEEE; + background-image:url(../images/checkbox_arrow.gif); + height:20px; + border-top:1px solid #CCCCCC; + background-position:5px 10px; + background-repeat:no-repeat; + padding:3px 0px 3px 0px; +} + +#table_action_header ul +{ + list-style:none; + padding:0px; + margin:0px; + margin-left:15px; +} + +#table_action_header ul li +{ + margin-left:8px; + margin-right:4px; + +} + +#table_action_header ul li span +{ + background-color:#0a6184; + border:2px solid #DDDDDD; + font-size:14px; + padding:2px 5px 2px 5px; + +} + +#table_action_header a +{ + text-decoration:none; + color:#FFF; +} + +#table_holder +{ + position:relative; + margin-bottom:50px; +} + +table.tablesorter +{ + position:relative; + width:100%; + border-top:3px solid #0a6184; + border-collapse:collapse; +} + +table.tablesorter thead tr th, table.tablesorter tfoot tr th +{ + color:#FFFFFF; + text-align:left; + background-color:#4386a1; + padding: 0px 5px 0px 5px; +} + +table.tablesorter thead tr .header +{ + background-image: url(../images/tables/bg.gif); + background-repeat: no-repeat; + background-position: center right; + cursor: pointer; +} + +table.tablesorter tbody td +{ + color: #3D3D3D; + background-color: #FFF; + vertical-align: top; + padding: 0px 5px 0px 5px; + +} + +table.tablesorter tbody td +{ + border-bottom:1px solid #DDDDDD; +} + +table.tablesorter tbody td.over +{ + background-color:#CCCCCC; +} + +table.tablesorter tbody td.selected +{ + background-color:#BBBBBB; +} + +table.tablesorter thead tr .headerSortUp +{ + background-image: url(../images/tables/asc.gif); +} + +table.tablesorter thead tr .headerSortDown +{ + background-image: url(../images/tables/desc.gif); +} + +table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp +{ + background-color: #8dbdd8; +} + +table.innertable +{ + display: none; +} + +table.innertable thead tr th +{ + background-color: #0a6184; +} + +table.innertable tbody tr td +{ + background-color: #DDD; +} \ No newline at end of file diff --git a/css/thickbox.css b/css/thickbox.css new file mode 100644 index 000000000..57242c5d4 --- /dev/null +++ b/css/thickbox.css @@ -0,0 +1,165 @@ +/* ----------------------------------------------------------------------------------------------------------------*/ +/* ---------->>> global settings needed for thickbox <<<-----------------------------------------------------------*/ +/* ----------------------------------------------------------------------------------------------------------------*/ +*{padding: 0; margin: 0;} + +/* ----------------------------------------------------------------------------------------------------------------*/ +/* ---------->>> thickbox specific link and font settings <<<------------------------------------------------------*/ +/* ----------------------------------------------------------------------------------------------------------------*/ +#TB_window { + font: 12px Arial, Helvetica, sans-serif; + color: #333333; +} + +#TB_secondLine { + font: 10px Arial, Helvetica, sans-serif; + color:#666666; +} + +#TB_window a:link {color: #666666;} +#TB_window a:visited {color: #666666;} +#TB_window a:hover {color: #000;} +#TB_window a:active {color: #666666;} +#TB_window a:focus{color: #666666;} + +/* ----------------------------------------------------------------------------------------------------------------*/ +/* ---------->>> thickbox settings <<<-----------------------------------------------------------------------------*/ +/* ----------------------------------------------------------------------------------------------------------------*/ +#TB_overlay { + position: fixed; + z-index:100; + top: 0px; + left: 0px; + height:100%; + width:100%; +} + +.TB_overlayMacFFBGHack {background: url(macFFBgHack.png) repeat;} +.TB_overlayBG { + background-color:#000; + filter:alpha(opacity=75); + -moz-opacity: 0.75; + opacity: 0.75; +} + +* html #TB_overlay { /* ie6 hack */ + position: absolute; + height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); +} + +#TB_window { + position: fixed; + background: #ffffff; + z-index: 102; + color:#000000; + display:none; + border: 4px solid #525252; + text-align:left; + bottom:10%; + left:50%; +} + +* html #TB_window { /* ie6 hack */ +position: absolute; +margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); +} + +#TB_window img#TB_Image { + display:block; + margin: 15px 0 0 15px; + border-right: 1px solid #ccc; + border-bottom: 1px solid #ccc; + border-top: 1px solid #666; + border-left: 1px solid #666; +} + +#TB_caption{ + height:25px; + padding:7px 30px 10px 25px; + float:left; +} + +#TB_closeWindow{ + height:25px; + padding:11px 25px 10px 0; + float:right; +} + +#TB_closeAjaxWindow{ + padding:7px 10px 5px 0; + margin-bottom:1px; + text-align:right; + float:right; +} + +#TB_ajaxWindowTitle{ + float:left; + padding:7px 0 5px 10px; + margin-bottom:1px; +} + +#TB_title{ + background-color:#e8e8e8; + font-size:1.25em; + font-weight:bold; + height:27px; +} + +#TB_ajaxContent{ + clear:both; + padding:2px 15px 15px 15px; + overflow:auto; + text-align:left; + line-height:1.4em; +} + +#TB_ajaxContent.TB_modal{ + padding:15px; +} + +#TB_ajaxContent p{ + padding:5px 0px 5px 0px; +} + +#TB_load{ + position: fixed; + display:none; + height:13px; + width:208px; + z-index:103; + top: 50%; + left: 50%; + margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */ +} + +* html #TB_load { /* ie6 hack */ +position: absolute; +margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); +} + +#TB_HideSelect{ + z-index:99; + position:fixed; + top: 0; + left: 0; + background-color:#fff; + border:none; + filter:alpha(opacity=0); + -moz-opacity: 0; + opacity: 0; + height:100%; + width:100%; +} + +* html #TB_HideSelect { /* ie6 hack */ + position: absolute; + height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); +} + +#TB_iframeContent{ + clear:both; + border:none; + margin-bottom:-1px; + margin-top:1px; + _margin-bottom:1px; +} diff --git a/database/database.sql b/database/database.sql new file mode 100644 index 000000000..13e4d0d8f --- /dev/null +++ b/database/database.sql @@ -0,0 +1,696 @@ +-- phpMyAdmin SQL Dump +-- version 3.3.9 +-- http://www.phpmyadmin.net +-- +-- Host: localhost +-- Generation Time: Apr 08, 2011 at 04:27 PM +-- Server version: 5.1.54 +-- PHP Version: 5.3.3 + +-- +-- Database: `pos` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_app_config` +-- + +CREATE TABLE `ospos_app_config` ( + `key` varchar(255) NOT NULL, + `value` varchar(255) NOT NULL, + PRIMARY KEY (`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_app_config` +-- + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES +('address', '123 Nowhere street'), +('company', 'Open Source Point of Sale'), +('default_tax_rate', '8'), +('email', 'admin@pappastech.com'), +('fax', ''), +('phone', '555-555-5555'), +('return_policy', 'Test'), +('timezone', 'America/New_York'), +('website', ''); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_customers` +-- + +CREATE TABLE `ospos_customers` ( + `person_id` int(10) NOT NULL, + `account_number` varchar(255) DEFAULT NULL, + `taxable` int(1) NOT NULL DEFAULT '1', + `deleted` int(1) NOT NULL DEFAULT '0', + UNIQUE KEY `account_number` (`account_number`), + KEY `person_id` (`person_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_customers` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_employees` +-- + +CREATE TABLE `ospos_employees` ( + `username` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `person_id` int(10) NOT NULL, + `deleted` int(1) NOT NULL DEFAULT '0', + UNIQUE KEY `username` (`username`), + KEY `person_id` (`person_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_employees` +-- + +INSERT INTO `ospos_employees` (`username`, `password`, `person_id`, `deleted`) VALUES +('admin', '439a6de57d475c1a0ba9bcb1c39f0af6', 1, 0); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_giftcards` +-- + +CREATE TABLE `ospos_giftcards` ( + `giftcard_id` int(11) NOT NULL AUTO_INCREMENT, + `giftcard_number` varchar(25) COLLATE utf8_unicode_ci NOT NULL, + `value` double(15,2) NOT NULL, + `deleted` int(1) NOT NULL DEFAULT '0', + `person_id` INT NOT NULL, + PRIMARY KEY (`giftcard_id`), + UNIQUE KEY `giftcard_number` (`giftcard_number`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=48 ; + +-- +-- Dumping data for table `ospos_giftcards` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_inventory` +-- + +CREATE TABLE `ospos_inventory` ( + `trans_id` int(11) NOT NULL AUTO_INCREMENT, + `trans_items` int(11) NOT NULL DEFAULT '0', + `trans_user` int(11) NOT NULL DEFAULT '0', + `trans_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `trans_comment` text NOT NULL, + `trans_inventory` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`trans_id`), + KEY `ospos_inventory_ibfk_1` (`trans_items`), + KEY `ospos_inventory_ibfk_2` (`trans_user`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- +-- Dumping data for table `ospos_inventory` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_items` +-- + +CREATE TABLE `ospos_items` ( + `name` varchar(255) NOT NULL, + `category` varchar(255) NOT NULL, + `supplier_id` int(11) DEFAULT NULL, + `item_number` varchar(255) DEFAULT NULL, + `description` varchar(255) NOT NULL, + `cost_price` double(15,2) NOT NULL, + `unit_price` double(15,2) NOT NULL, + `quantity` double(15,2) NOT NULL DEFAULT '0.00', + `reorder_level` double(15,2) NOT NULL DEFAULT '0.00', + `location` varchar(255) NOT NULL, + `item_id` int(10) NOT NULL AUTO_INCREMENT, + `allow_alt_description` tinyint(1) NOT NULL, + `is_serialized` tinyint(1) NOT NULL, + `deleted` int(1) NOT NULL DEFAULT '0', + `custom1` VARCHAR(25) NOT NULL, + `custom2` VARCHAR(25) NOT NULL, + `custom3` VARCHAR(25) NOT NULL, + `custom4` VARCHAR(25) NOT NULL, + `custom5` VARCHAR(25) NOT NULL, + `custom6` VARCHAR(25) NOT NULL, + `custom7` VARCHAR(25) NOT NULL, + `custom8` VARCHAR(25) NOT NULL, + `custom9` VARCHAR(25) NOT NULL, + `custom10` VARCHAR(25) NOT NULL, + PRIMARY KEY (`item_id`), + UNIQUE KEY `item_number` (`item_number`), + KEY `ospos_items_ibfk_1` (`supplier_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- +-- Dumping data for table `ospos_items` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_items_taxes` +-- + +CREATE TABLE `ospos_items_taxes` ( + `item_id` int(10) NOT NULL, + `name` varchar(255) NOT NULL, + `percent` double(15,3) NOT NULL, + PRIMARY KEY (`item_id`,`name`,`percent`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_items_taxes` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_item_kits` +-- + +CREATE TABLE `ospos_item_kits` ( + `item_kit_id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `description` varchar(255) NOT NULL, + PRIMARY KEY (`item_kit_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- +-- Dumping data for table `ospos_item_kits` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_item_kit_items` +-- + +CREATE TABLE `ospos_item_kit_items` ( + `item_kit_id` int(11) NOT NULL, + `item_id` int(11) NOT NULL, + `quantity` double(15,2) NOT NULL, + PRIMARY KEY (`item_kit_id`,`item_id`,`quantity`), + KEY `ospos_item_kit_items_ibfk_2` (`item_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_item_kit_items` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_modules` +-- + +CREATE TABLE `ospos_modules` ( + `name_lang_key` varchar(255) NOT NULL, + `desc_lang_key` varchar(255) NOT NULL, + `sort` int(10) NOT NULL, + `module_id` varchar(255) NOT NULL, + PRIMARY KEY (`module_id`), + UNIQUE KEY `desc_lang_key` (`desc_lang_key`), + UNIQUE KEY `name_lang_key` (`name_lang_key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_modules` +-- + +INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES +('module_config', 'module_config_desc', 100, 'config'), +('module_customers', 'module_customers_desc', 10, 'customers'), +('module_employees', 'module_employees_desc', 80, 'employees'), +('module_giftcards', 'module_giftcards_desc', 90, 'giftcards'), +('module_items', 'module_items_desc', 20, 'items'), +('module_item_kits', 'module_item_kits_desc', 30, 'item_kits'), +('module_receivings', 'module_receivings_desc', 60, 'receivings'), +('module_reports', 'module_reports_desc', 50, 'reports'), +('module_sales', 'module_sales_desc', 70, 'sales'), +('module_suppliers', 'module_suppliers_desc', 40, 'suppliers'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_people` +-- + +CREATE TABLE `ospos_people` ( + `first_name` varchar(255) NOT NULL, + `last_name` varchar(255) NOT NULL, + `phone_number` varchar(255) NOT NULL, + `email` varchar(255) NOT NULL, + `address_1` varchar(255) NOT NULL, + `address_2` varchar(255) NOT NULL, + `city` varchar(255) NOT NULL, + `state` varchar(255) NOT NULL, + `zip` varchar(255) NOT NULL, + `country` varchar(255) NOT NULL, + `comments` text NOT NULL, + `person_id` int(10) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`person_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ; + +-- +-- Dumping data for table `ospos_people` +-- + +INSERT INTO `ospos_people` (`first_name`, `last_name`, `phone_number`, `email`, `address_1`, `address_2`, `city`, `state`, `zip`, `country`, `comments`, `person_id`) VALUES +('John', 'Doe', '555-555-5555', 'admin@pappastech.com', 'Address 1', '', '', '', '', '', '', 1); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_permissions` +-- + +CREATE TABLE `ospos_permissions` ( + `module_id` varchar(255) NOT NULL, + `person_id` int(10) NOT NULL, + PRIMARY KEY (`module_id`,`person_id`), + KEY `person_id` (`person_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_permissions` +-- + +INSERT INTO `ospos_permissions` (`module_id`, `person_id`) VALUES +('config', 1), +('customers', 1), +('employees', 1), +('giftcards', 1), +('items', 1), +('item_kits', 1), +('receivings', 1), +('reports', 1), +('sales', 1), +('suppliers', 1); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_receivings` +-- + +CREATE TABLE `ospos_receivings` ( + `receiving_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `supplier_id` int(10) DEFAULT NULL, + `employee_id` int(10) NOT NULL DEFAULT '0', + `comment` text NOT NULL, + `receiving_id` int(10) NOT NULL AUTO_INCREMENT, + `payment_type` varchar(20) DEFAULT NULL, + PRIMARY KEY (`receiving_id`), + KEY `supplier_id` (`supplier_id`), + KEY `employee_id` (`employee_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- +-- Dumping data for table `ospos_receivings` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_receivings_items` +-- + +CREATE TABLE `ospos_receivings_items` ( + `receiving_id` int(10) NOT NULL DEFAULT '0', + `item_id` int(10) NOT NULL DEFAULT '0', + `description` varchar(30) DEFAULT NULL, + `serialnumber` varchar(30) DEFAULT NULL, + `line` int(3) NOT NULL, + `quantity_purchased` int(10) NOT NULL DEFAULT '0', + `item_cost_price` decimal(15,2) NOT NULL, + `item_unit_price` double(15,2) NOT NULL, + `discount_percent` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`receiving_id`,`item_id`,`line`), + KEY `item_id` (`item_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_receivings_items` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sales` +-- + +CREATE TABLE `ospos_sales` ( + `sale_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `customer_id` int(10) DEFAULT NULL, + `employee_id` int(10) NOT NULL DEFAULT '0', + `comment` text NOT NULL, + `sale_id` int(10) NOT NULL AUTO_INCREMENT, + `payment_type` varchar(512) DEFAULT NULL, + PRIMARY KEY (`sale_id`), + KEY `customer_id` (`customer_id`), + KEY `employee_id` (`employee_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- +-- Dumping data for table `ospos_sales` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sales_items` +-- + +CREATE TABLE `ospos_sales_items` ( + `sale_id` int(10) NOT NULL DEFAULT '0', + `item_id` int(10) NOT NULL DEFAULT '0', + `description` varchar(30) DEFAULT NULL, + `serialnumber` varchar(30) DEFAULT NULL, + `line` int(3) NOT NULL DEFAULT '0', + `quantity_purchased` double(15,2) NOT NULL DEFAULT '0.00', + `item_cost_price` decimal(15,2) NOT NULL, + `item_unit_price` double(15,2) NOT NULL, + `discount_percent` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`sale_id`,`item_id`,`line`), + KEY `item_id` (`item_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_sales_items` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sales_items_taxes` +-- + +CREATE TABLE `ospos_sales_items_taxes` ( + `sale_id` int(10) NOT NULL, + `item_id` int(10) NOT NULL, + `line` int(3) NOT NULL DEFAULT '0', + `name` varchar(255) NOT NULL, + `percent` double(15,3) NOT NULL, + PRIMARY KEY (`sale_id`,`item_id`,`line`,`name`,`percent`), + KEY `item_id` (`item_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_sales_items_taxes` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sales_payments` +-- + +CREATE TABLE `ospos_sales_payments` ( + `sale_id` int(10) NOT NULL, + `payment_type` varchar(40) NOT NULL, + `payment_amount` decimal(15,2) NOT NULL, + PRIMARY KEY (`sale_id`,`payment_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_sales_payments` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sales_suspended` +-- + +CREATE TABLE `ospos_sales_suspended` ( + `sale_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `customer_id` int(10) DEFAULT NULL, + `employee_id` int(10) NOT NULL DEFAULT '0', + `comment` text NOT NULL, + `sale_id` int(10) NOT NULL AUTO_INCREMENT, + `payment_type` varchar(512) DEFAULT NULL, + PRIMARY KEY (`sale_id`), + KEY `customer_id` (`customer_id`), + KEY `employee_id` (`employee_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; + +-- +-- Dumping data for table `ospos_sales_suspended` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sales_suspended_items` +-- + +CREATE TABLE `ospos_sales_suspended_items` ( + `sale_id` int(10) NOT NULL DEFAULT '0', + `item_id` int(10) NOT NULL DEFAULT '0', + `description` varchar(30) DEFAULT NULL, + `serialnumber` varchar(30) DEFAULT NULL, + `line` int(3) NOT NULL DEFAULT '0', + `quantity_purchased` double(15,2) NOT NULL DEFAULT '0.00', + `item_cost_price` decimal(15,2) NOT NULL, + `item_unit_price` double(15,2) NOT NULL, + `discount_percent` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`sale_id`,`item_id`,`line`), + KEY `item_id` (`item_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_sales_suspended_items` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sales_suspended_items_taxes` +-- + +CREATE TABLE `ospos_sales_suspended_items_taxes` ( + `sale_id` int(10) NOT NULL, + `item_id` int(10) NOT NULL, + `line` int(3) NOT NULL DEFAULT '0', + `name` varchar(255) NOT NULL, + `percent` double(15,3) NOT NULL, + PRIMARY KEY (`sale_id`,`item_id`,`line`,`name`,`percent`), + KEY `item_id` (`item_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_sales_suspended_items_taxes` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sales_suspended_payments` +-- + +CREATE TABLE `ospos_sales_suspended_payments` ( + `sale_id` int(10) NOT NULL, + `payment_type` varchar(40) NOT NULL, + `payment_amount` decimal(15,2) NOT NULL, + PRIMARY KEY (`sale_id`,`payment_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_sales_suspended_payments` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_sessions` +-- + +CREATE TABLE `ospos_sessions` ( + `session_id` varchar(40) NOT NULL DEFAULT '0', + `ip_address` varchar(16) NOT NULL DEFAULT '0', + `user_agent` varchar(120) NOT NULL, + `last_activity` int(10) unsigned NOT NULL DEFAULT '0', + `user_data` text, + PRIMARY KEY (`session_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_sessions` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ospos_suppliers` +-- + +CREATE TABLE `ospos_suppliers` ( + `person_id` int(10) NOT NULL, + `company_name` varchar(255) NOT NULL, + `account_number` varchar(255) DEFAULT NULL, + `deleted` int(1) NOT NULL DEFAULT '0', + UNIQUE KEY `account_number` (`account_number`), + KEY `person_id` (`person_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `ospos_suppliers` +-- + + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `ospos_customers` +-- +ALTER TABLE `ospos_customers` + ADD CONSTRAINT `ospos_customers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`); + +-- +-- Constraints for table `ospos_employees` +-- +ALTER TABLE `ospos_employees` + ADD CONSTRAINT `ospos_employees_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`); + +-- +-- Constraints for table `ospos_inventory` +-- +ALTER TABLE `ospos_inventory` + ADD CONSTRAINT `ospos_inventory_ibfk_1` FOREIGN KEY (`trans_items`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_inventory_ibfk_2` FOREIGN KEY (`trans_user`) REFERENCES `ospos_employees` (`person_id`); + +-- +-- Constraints for table `ospos_items` +-- +ALTER TABLE `ospos_items` + ADD CONSTRAINT `ospos_items_ibfk_1` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`); + +-- +-- Constraints for table `ospos_items_taxes` +-- +ALTER TABLE `ospos_items_taxes` + ADD CONSTRAINT `ospos_items_taxes_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE; + +-- +-- Constraints for table `ospos_item_kit_items` +-- +ALTER TABLE `ospos_item_kit_items` + ADD CONSTRAINT `ospos_item_kit_items_ibfk_1` FOREIGN KEY (`item_kit_id`) REFERENCES `ospos_item_kits` (`item_kit_id`) ON DELETE CASCADE, + ADD CONSTRAINT `ospos_item_kit_items_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE; + +-- +-- Constraints for table `ospos_permissions` +-- +ALTER TABLE `ospos_permissions` + ADD CONSTRAINT `ospos_permissions_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_employees` (`person_id`), + ADD CONSTRAINT `ospos_permissions_ibfk_2` FOREIGN KEY (`module_id`) REFERENCES `ospos_modules` (`module_id`); + +-- +-- Constraints for table `ospos_receivings` +-- +ALTER TABLE `ospos_receivings` + ADD CONSTRAINT `ospos_receivings_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`), + ADD CONSTRAINT `ospos_receivings_ibfk_2` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`); + +-- +-- Constraints for table `ospos_receivings_items` +-- +ALTER TABLE `ospos_receivings_items` + ADD CONSTRAINT `ospos_receivings_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_receivings_items_ibfk_2` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`); + +-- +-- Constraints for table `ospos_sales` +-- +ALTER TABLE `ospos_sales` + ADD CONSTRAINT `ospos_sales_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`), + ADD CONSTRAINT `ospos_sales_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`); + +-- +-- Constraints for table `ospos_sales_items` +-- +ALTER TABLE `ospos_sales_items` + ADD CONSTRAINT `ospos_sales_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_sales_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`); + +-- +-- Constraints for table `ospos_sales_items_taxes` +-- +ALTER TABLE `ospos_sales_items_taxes` + ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_items` (`sale_id`), + ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`); + +-- +-- Constraints for table `ospos_sales_payments` +-- +ALTER TABLE `ospos_sales_payments` + ADD CONSTRAINT `ospos_sales_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`); + +-- +-- Constraints for table `ospos_sales_suspended` +-- +ALTER TABLE `ospos_sales_suspended` + ADD CONSTRAINT `ospos_sales_suspended_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`), + ADD CONSTRAINT `ospos_sales_suspended_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`); + +-- +-- Constraints for table `ospos_sales_suspended_items` +-- +ALTER TABLE `ospos_sales_suspended_items` + ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`), + ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`); + +-- +-- Constraints for table `ospos_sales_suspended_items_taxes` +-- +ALTER TABLE `ospos_sales_suspended_items_taxes` + ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended_items` (`sale_id`), + ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`); + +-- +-- Constraints for table `ospos_sales_suspended_payments` +-- +ALTER TABLE `ospos_sales_suspended_payments` + ADD CONSTRAINT `ospos_sales_suspended_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`); + +-- +-- Constraints for table `ospos_suppliers` +-- +ALTER TABLE `ospos_suppliers` + ADD CONSTRAINT `ospos_suppliers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`); diff --git a/images/Thumbs.db b/images/Thumbs.db new file mode 100644 index 0000000000000000000000000000000000000000..10eecf861d0ecbcaf1963963574c9ba61786b86f GIT binary patch literal 5632 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 E7rc}$I{*Lx literal 0 HcmV?d00001 diff --git a/images/big_action_button.jpg b/images/big_action_button.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8303329606d021dc463b04c1021770c5dfc6ac9c GIT binary patch literal 22091 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 XHXhwvRQa;j#Q>M#BeQ@bY8 literal 0 HcmV?d00001 diff --git a/images/calendar.png b/images/calendar.png new file mode 100644 index 0000000000000000000000000000000000000000..94e66d4badc35ec7fdb03056b5950d0651fc38d3 GIT binary patch literal 1091 zcmV-J1ibr+P)k00004b3#c}2nYxW zd>Mx1l$TjLV`1Q_y+)SLX|jh;KJX41hl0{s9X>N6_ut%fQV2f(xyoSvGc1*oy7L8 zcV-@k@vpSKRJk(J=*{fzeBbwd=e@T|M1&)Z5MW_7X0g_0KQ=h$unvrKSnIG(FxCxB zi#5XJc*MJ}9`^t@*J56OcKDGzpF6+QXV6S60EG+hfCyLv&O(~{bvuEy4M_@VO5=kc zX~m`wU|m-RfhQ)w89&8zKoUq3Fm1S510Xea0KmEqfP(54i1SRG^Gs~l0+k8??G6AU zBA?&pI_M!5s@!`UKbIOFR%Lj`D=cEY2MqddQ0B^^j8rP2?0{;a3X{OT=->^ zAkJT4sj4_`1ZFgZft$R^~-{Y5dQH#S}T^9R|#~$*Vi|gDry8b z0AL&Z^JsxqeE;V* z0Lv?@C=@>|Y?C^0PPkpIGd3Ji8qHztKnTVduYrbFPL&9Q_jvhaiJ$)3=B1M*F3xYU zw6;gF5HV5A;hYd?`V3O*LpXI}nA%Q@nM$7J^#i8HBmVxU&QuYK!x81Nyk{CHx-}RA zoG9h^_^Txj5<_Y%sj*n&NUg)z^r5xz%<&PQdPgm1eU!uh1NadF?6n+?*kPQ{e-RKm z_P)In|4lBVnJ(u&z(LDW84DlD^J2BpXJ9%lEvPQ|x8C*P&Lj?;U)$L;y*Buu+g#)i zF$m)NAp42;F$i!d8RK^6Fasd;pJgM!YtdmVa%UqJW1akaHx?0*wfk&!$J<)RCaIO* zmv;L-Q98;hpth5sl%lqqpfs%COV~*kxx4PQQS~`SazQTy-PH_0X~pEREK0%Tcoq#j zK9&U(!$Sp7ib^rtyUv~lP6PoIuu*SwFS*U`hL2m-XHiPgY&KDNX8DZjN!AxpKr1L0 zBX(mb4CQGwTa=3tO3gA}$RHv#VnY;a0<9hrf`YBRHUQ0L3k7WNwQ-$HY$k?GsEIQA za7XHH6i^zCP-=$KNW|U!Hjj-&)OOo6V?!8dqEI8^o%I-W1sTnU#Hpo_4QM8YTt;)y zO37s)3^dt{?lC>2K|Tt&Rc-W&$%%BbSn&U>2ghjMC-ISc;(rc3dJpu#2|54(002ov JPDHLkV1h&H;*udLj0i>JHfQrdgw Q@I!Js3(O}4GBQ{L01*BW$^ZZW literal 0 HcmV?d00001 diff --git a/images/loading_animation.gif b/images/loading_animation.gif new file mode 100644 index 0000000000000000000000000000000000000000..82290f48334c81272ff5991962951758137a08ba GIT binary patch literal 5886 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 Dl)1NK literal 0 HcmV?d00001 diff --git a/images/menubar/config.png b/images/menubar/config.png new file mode 100644 index 0000000000000000000000000000000000000000..49fcee2659945d57f9b85853c9c78473ce575aae GIT binary patch literal 5127 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 literal 0 HcmV?d00001 diff --git a/images/menubar/customers.png b/images/menubar/customers.png new file mode 100644 index 0000000000000000000000000000000000000000..5b8e6deb9a81f5410d5534dfe95dacc6d5ceee14 GIT binary patch literal 3745 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 LNkvXXu0mjfD498n literal 0 HcmV?d00001 diff --git a/images/menubar/employees.png b/images/menubar/employees.png new file mode 100644 index 0000000000000000000000000000000000000000..9e9ba4d97a23a180f43162fc441f9d56f80f5e98 GIT binary patch literal 5989 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 literal 0 HcmV?d00001 diff --git a/images/menubar/home.png b/images/menubar/home.png new file mode 100644 index 0000000000000000000000000000000000000000..327dc7535479e2946bae04da6b2235c97850006a GIT binary patch literal 5755 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 ukglL3w2 z>KZ$B9dymJ2h9PR%#!B~1uPd-1yt4h4$wacXMY0|Q=nQb9+&>wsJ=$iVB>m- zM?D3l3wBizhohFw-~8|kTv!zazWH;utBQL`*V(V@5b#Z}F#sV1j^oVE(^U_ss`+Zv zDB`+s=?YAaz@`XnNJ7Shm;pwZT@i!x-*|%`Jo7)SyBz}hQa^tCS7?Rl(u-lk_)8_I zDMEs9L8zbzP<`*$7Nl886%V{3y|EJC)4m#-3hfzaO-XvLj50biLw!0%T_Qp@ZsJOX z8wK`HSJ?ZFH~4qU=KDW-l>BWIcW z1SUrF-O0KH*<6B(>!&@%Q$Y$BQJKaqPGU`s;aC=qWi28A-a4sW?70|hTmz-bG$;B; zaK&8gg>{8zwaTy9P8aRKk^lHS zR~KcWZQnZ~0n&9bHs8CBWHv>~0at=>UF>p+(o~+p*awvI<5N|c>NS+aCw zUx&G58m$tjwq!cW=6jo2)3An;3r;mPx{~751ck8=iH`TOqalEv+ssM3m5Sqm*A!@t zLxU+fdu^EOlhbplPk|@eWBlpH7^*S{yxLbkmmSHO;UdSc7kO{AJp12~eI3ej1a<=d z0PL(K5>G~G?`$NyzK)`!;8wGXn5(Wr&V`JrdEg_O&9UA=CQFssXVsY+fAL_7wq#%t z@P!0wKR@;Qz*=BG@br;=9bLC9WZS-X;vwL9U{~$$W;9I4mL?invlQK>i6n#25`#*) z$S-<_DBE+X>N8CS&)gHo2&hW}zZC(~G?kBBiC;TI_&Pfq@&7oV@ZO!hg1*EBskkoNa5vD2lQy@Kq=9&O7f&DJ6rGg8%CkygTHD zO0|VT0ow0rqPZ~^C2QznnLMP@;K;sjjR#dTdKOOm(VS9y0hfGy? z?|+Z6zOxi=4s!p~&)?Z*?si)wAo-KFG7qn>aB3*TmKL2abY$mw?{?d-Ui=z`{`07A ziJ%5rvcXS;cacD~8M@@N>&qnKp=HNR6)oQXaGFaa)2z!x_{`?q{8%11NrR~p&@?nf zp%l731@&8b>(r@JD-0=Xa79qEU-{N7Fl%aaNT?wwbaFe(g zr<8Ja6j-kP_pc{0Vo3tYH6-f`q;l&Ku7e(!Su|Gj4?Z9J#n!D_ER!RdZ6cPgCv3)0 zHH|`kjBA&FxAge$oc_q~xT^{X*Cl^*gkpZ2YZp&bnwcaRj?h{kTeWxGih#1xhY$Dl zu%>YX@yuG9+V7{O>mlq)iTd#PlH;de+`cLVs=&3C5@_A}heQ%vF?=2qiq_h>fG^?vMkG0)~?%?|M>w(#Pud4sr)YLRJFfeeqHk@ihs7k^F5xYz*QmI5__djB1@1dfF=MGNcFot1Z7zUG)*&8Tgr7^SN*N^9TTa7E*6WFN+pC4(69|%*NK{D6|~eeO<6D}0vrau1eBIa zl}b&pss|4qd^4F$&SbOMM#C_oilQK;L`sR`F_QjyLaBNzolY;g_pgG^=ktt@k5ecV za9x*hI7~bqC!J2qbULk=rb#duL{SvQaU7+q7+cuh}5e|n5g+c^_ zL8)n)QmamtV5wBXvaDH>j^h;L@i?he%B+U45Ta5n7LOMSg`c#wwY?&xw3TH-sH#T5 zClXmeB-!2Fz5R(Np4gMiAcSJKCRo^2t3N9Ub@inZ%J&mhQXn zKGQG^tu~x4U%q_h!i5VLUw--J6Q@s~zUqU{`@m;_N)2e&H|g(n4y)74tl)6+BW4(Lt@EJq|z6IziPMdF>Eoy~jq?)}`%%*?<`FTHerYHDhH0qAMp z%N4(nIzDh&W6KuAl^$A_BVzg%@fW}5d$I%+d@K9rEC`QVf?jO`w;~es`|5_w^|vY3 tNU0RXS6i)myQprZf)002ovPDHLkV1j<4D*6Bb literal 0 HcmV?d00001 diff --git a/images/menubar/item_kits.png b/images/menubar/item_kits.png new file mode 100644 index 0000000000000000000000000000000000000000..d6266204db48f6908c4cae1fb940e1b61104fcef GIT binary patch literal 3303 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 literal 0 HcmV?d00001 diff --git a/images/menubar/items.png b/images/menubar/items.png new file mode 100644 index 0000000000000000000000000000000000000000..948db99ff9a8b3cac3240eca9ac4968987033fbe GIT binary patch literal 4702 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 I3^*990g}SA&Hw-a literal 0 HcmV?d00001 diff --git a/images/menubar/receivings.png b/images/menubar/receivings.png new file mode 100644 index 0000000000000000000000000000000000000000..f3b1130af280e9765f79bb920a2b2a8f370c8f43 GIT binary patch literal 59454 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 literal 0 HcmV?d00001 diff --git a/images/menubar/sales.png b/images/menubar/sales.png new file mode 100644 index 0000000000000000000000000000000000000000..afc7e21f91f4de064ef602d5a36170856e846648 GIT binary patch literal 4792 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 literal 0 HcmV?d00001 diff --git a/images/menubar/thumb_clock.png b/images/menubar/thumb_clock.png new file mode 100644 index 0000000000000000000000000000000000000000..40c969bfb0720aa31b56714e56d73a6aded43d65 GIT binary patch literal 19783 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 literal 0 HcmV?d00001 diff --git a/images/menubar/thumb_colorscheme.png b/images/menubar/thumb_colorscheme.png new file mode 100644 index 0000000000000000000000000000000000000000..acb711ae703f6866807798ef0dc95c6075c75b44 GIT binary patch literal 29555 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