From ec6a542bc3aac4fe73a8bc1d0683867e56d76fb5 Mon Sep 17 00:00:00 2001 From: Deon George Date: Tue, 30 Nov 2010 09:41:08 +1100 Subject: [PATCH] OSB enhancements to date --- .htaccess | 8 +- application/bootstrap.php | 43 +- application/cache/.htaccess | 2 + application/classes/block.php | 4 + application/classes/breadcrumb.php | 4 + application/classes/company.php | 50 + application/classes/config.php | 4 + application/classes/controller/default.php | 4 + .../classes/controller/lnapp/default.php | 75 + .../classes/controller/lnapp/logout.php | 26 + .../controller/lnapp/templatedefault.php | 279 + application/classes/controller/lnapp/tree.php | 110 + application/classes/controller/login.php | 209 + application/classes/controller/logout.php | 4 + .../classes/controller/templatedefault.php | 56 + application/classes/controller/tree.php | 90 + application/classes/controller/welcome.php | 43 +- application/classes/database/mysql.php | 20 + application/classes/headimages.php | 4 + application/classes/htmlrender.php | 4 + application/classes/lnapp/block.php | 81 + application/classes/lnapp/breadcrumb.php | 64 + application/classes/lnapp/config.php | 129 + application/classes/lnapp/headimages.php | 45 + application/classes/lnapp/htmlrender.php | 94 + application/classes/lnapp/meta.php | 34 + application/classes/lnapp/script.php | 59 + application/classes/lnapp/style.php | 54 + application/classes/lnapp/systemmessage.php | 129 + application/classes/meta.php | 4 + application/classes/model/.htaccess | 2 + application/classes/model/module.php | 34 + application/classes/ormosb.php | 153 + application/classes/period.php | 124 + application/classes/script.php | 4 + application/classes/staticlist.php | 63 + application/classes/staticlist/module.php | 23 + application/classes/staticlist/pricetype.php | 30 + .../classes/staticlist/recurschedule.php | 56 + application/classes/staticlist/title.php | 29 + application/classes/staticlist/yesno.php | 29 + application/classes/staticlistmodule.php | 83 + application/classes/style.php | 4 + application/classes/systemmessage.php | 4 + application/classes/validate.php | 29 + application/config/.htaccess | 2 + application/config/auth.php | 19 + application/config/cache.php | 10 + application/config/config.php | 37 + application/config/database.php | 30 + application/i18n/.htaccess | 2 + application/media/1/img/logo-small.png | Bin 0 -> 2225 bytes application/media/css/default.css | 292 + application/media/css/jquery.gritter.css | 92 + application/media/css/jquery.jstree.css | 56 + application/media/css/list.css | 33 + application/media/css/login.css | 43 + application/media/img/ajax-progress.gif | Bin 0 -> 7685 bytes application/media/img/dialog-error-big.png | Bin 0 -> 2383 bytes application/media/img/dialog-error.png | Bin 0 -> 1126 bytes .../media/img/dialog-information-big.png | Bin 0 -> 3165 bytes application/media/img/dialog-information.png | Bin 0 -> 1242 bytes application/media/img/dialog-password-big.png | Bin 0 -> 2992 bytes application/media/img/dialog-password.png | Bin 0 -> 1196 bytes application/media/img/dialog-question-big.png | Bin 0 -> 2502 bytes application/media/img/dialog-question.png | Bin 0 -> 1086 bytes application/media/img/dialog-warning-big.png | Bin 0 -> 2844 bytes application/media/img/dialog-warning.png | Bin 0 -> 1074 bytes application/media/img/forum-big.png | Bin 0 -> 1615 bytes .../media/img/jquery.gritter.close-ie6.gif | Bin 0 -> 718 bytes application/media/img/jquery.gritter.png | Bin 0 -> 4880 bytes application/media/img/jquery.jstree.d.png | Bin 0 -> 7635 bytes .../media/img/jquery.jstree.throbber.gif | Bin 0 -> 1849 bytes application/media/img/login.user.png | Bin 0 -> 654 bytes application/media/img/logo-small.png | Bin 0 -> 3978 bytes application/media/img/logo.png | Bin 0 -> 10495 bytes application/media/img/toggle-closed.png | Bin 0 -> 102 bytes application/media/img/toggle-open.png | Bin 0 -> 98 bytes application/media/js/jquery-1.4.2.js | 154 + application/media/js/jquery.cookie.js | 96 + application/media/js/jquery.gritter-1.5.js | 21 + application/media/js/jquery.jstree-1.0rc.js | 142 + .../media/js/jquery.stickyfloat-1.0.js | 48 + .../media/js/themes/default/dot_for_ie.gif | Bin 0 -> 43 bytes application/messages/.htaccess | 2 + application/views/.htaccess | 2 + application/views/lnapp/default.php | 93 + application/views/login.php | 15 + application/views/login_reset.php | 14 + application/views/login_reset_sent.php | 13 + application/views/template.php | 1 + config.inc.php | 74 +- includes/files/tracking.txt | 0 .../simplehtmldom/classes/simple_html_dom.php | 975 ++++ includes/phplayers/layerstreemenu-hidden.css | 1 + includes/phplayers/layerstreemenu.css | 8 + includes/phplayers/treemenu.inc.php | 22 +- includes/smarty/plugins/block.translate.php | 11 + includes/smarty/plugins/function.osb.php | 2 +- .../smarty/plugins/function.popup_init.php | 2 +- index.php | 13 +- install/install.inc | 2 +- kh.php | 2 +- .../core/{english_core.xml => en_core.xml} | 0 modules/account/account.inc.php | 69 +- modules/account/account_construct.xml | 9 +- modules/account/account_install_data.xml | 2 +- modules/account/classes/auth/osb.php | 289 + .../account/classes/controller/account.php | 16 + .../classes/controller/user/account.php | 115 + modules/account/classes/model/account.php | 76 + .../classes/model/auth/roledefault.php | 54 + .../classes/model/auth/userdefault.php | 77 + modules/account/views/account/edit.php | 84 + .../account/views/account/password_reset.php | 16 + modules/account/views/bregister.php | 135 + .../account_billing_install.xml | 4 +- modules/account_fee/account_fee.inc.php | 71 + modules/account_fee/account_fee_construct.xml | 91 + modules/account_fee/account_fee_install.xml | 59 + modules/account_group/classes/model/group.php | 39 + .../account_memo/account_memo_construct.xml | 2 +- modules/adsl/adsl.inc.php | 36 + modules/adsl/adsl_construct.xml | 153 + modules/adsl/adsl_install.xml | 55 + modules/adsl/classes/adsl.php | 151 + modules/adsl/classes/model/adsl/plan.php | 59 + modules/adsl/classes/model/adsl/supplier.php | 40 + .../adsl/classes/model/adsl/supplier/plan.php | 39 + modules/adsl/views/adsl/contract_view.php | 12 + modules/adsl/views/adsl/product_view.php | 26 + modules/adsl_supplier/adsl_supplier.inc.php | 22 + .../adsl_supplier/adsl_supplier_construct.xml | 82 + .../adsl_supplier/adsl_supplier_install.xml | 44 + .../adsl_supplier_install_data.xml | 29 + modules/asset/asset.inc.php | 99 +- modules/asset/asset_construct.xml | 181 +- modules/asset/asset_install.xml | 109 +- modules/asset_pool/asset_pool.inc.php | 94 +- modules/asset_pool/asset_pool_construct.xml | 104 +- modules/asset_pool/asset_pool_install.xml | 93 +- .../blocked_email/blocked_email_install.xml | 2 +- modules/blocked_ip/blocked_ip_install.xml | 2 +- modules/campaign/campaign_install.xml | 2 +- modules/cart/cart.inc.php | 164 +- modules/cart/cart_install.xml | 2 +- modules/cart/classes/cart.php | 105 + modules/cart/classes/controller/cart.php | 116 + modules/cart/classes/model/cart.php | 25 + modules/cart/media/css/cart_blocklist.css | 32 + modules/cart/media/css/cart_contents.css | 46 + modules/cart/media/css/checkout_cartlist.css | 34 + .../img/accessories-calculator-small.png | Bin 0 -> 576 bytes .../cart/media/img/accessories-calculator.png | Bin 0 -> 1020 bytes modules/cart/media/img/edit-delete.png | Bin 0 -> 1219 bytes modules/cart/views/cart/block_list.php | 5 + modules/cart/views/cart/checkout_list.php | 11 + modules/cart/views/cart/checkout_total.php | 25 + modules/cart/views/cart/list_item.php | 17 + modules/cart/views/cart/list_pricebox.php | 27 + modules/charge/charge.inc.php | 436 +- modules/charge/charge_construct.xml | 21 +- modules/charge/charge_install.xml | 2 +- modules/charge/classes/model/charge.php | 24 + modules/checkout/auth.inc.php | 3 +- .../checkout/base_checkout_plugin.class.php | 4 + modules/checkout/checkout.inc.php | 747 +-- modules/checkout/checkout_construct.xml | 10 +- modules/checkout/checkout_install_data.xml | 1921 +++---- .../checkout/classes/controller/checkout.php | 150 + modules/checkout/classes/model/checkout.php | 67 + .../views/checkout/payment_option.php | 3 + modules/core/database.inc.php | 5 +- modules/core/database_add.inc.php | 9 +- modules/core/database_update.inc.php | 26 +- modules/core/list.inc.php | 533 +- modules/core/list_menu_files.inc.php | 2 +- modules/core/list_staticlist.inc.php | 288 + modules/core/login.inc.php | 362 +- modules/core/method.inc.php | 13 +- modules/core/search.inc.php | 14 +- modules/core/session.inc.php | 663 ++- modules/core/setup.inc.php | 2 +- modules/core/static_var.inc.php | 10 +- modules/core/translate.inc.php | 6 +- modules/core/validate.inc.php | 2 +- modules/core/vars.inc.php | 4 +- modules/country/classes/country.php | 21 + modules/country/media/img/country/AU.gif | Bin 0 -> 620 bytes modules/country/media/img/country/CA.gif | Bin 0 -> 366 bytes modules/country/media/img/country/CH.gif | Bin 0 -> 333 bytes modules/country/media/img/country/DK.gif | Bin 0 -> 217 bytes modules/country/media/img/country/EU.gif | Bin 0 -> 313 bytes modules/country/media/img/country/GB.gif | Bin 0 -> 673 bytes modules/country/media/img/country/HK.gif | Bin 0 -> 337 bytes modules/country/media/img/country/JP.gif | Bin 0 -> 202 bytes modules/country/media/img/country/MX.gif | Bin 0 -> 1462 bytes modules/country/media/img/country/MY.gif | Bin 0 -> 1109 bytes modules/country/media/img/country/NO.gif | Bin 0 -> 359 bytes modules/country/media/img/country/NZ.gif | Bin 0 -> 609 bytes modules/country/media/img/country/RU.gif | Bin 0 -> 144 bytes modules/country/media/img/country/SE.gif | Bin 0 -> 343 bytes modules/country/media/img/country/US.gif | Bin 0 -> 96 bytes modules/country/media/img/country/ZA.gif | Bin 0 -> 584 bytes modules/currency/classes/currency.php | 17 + modules/discount/auth.inc.php | 3 +- modules/discount/discount.inc.php | 553 +- modules/discount/discount_construct.xml | 30 +- modules/discount/discount_install.xml | 4 +- modules/email_queue/email_queue_install.xml | 2 +- .../email_template_translate_construct.xml | 2 - .../email_template_translate_install_data.xml | 94 +- .../controller/admin/emailtemplate.php | 131 + .../emailtemplate/classes/emailtemplate.php | 106 + .../classes/model/emailtemplate.php | 31 + .../classes/model/emailtemplate/translate.php | 34 + .../views/admin/emailtemplate/add.php | 14 + .../admin/emailtemplate/add_translate.php | 18 + .../views/admin/emailtemplate/edit.php | 14 + .../admin/emailtemplate/edit_translate.php | 18 + .../views/admin/emailtemplate/list_body.php | 4 + .../views/admin/emailtemplate/list_footer.php | 1 + .../views/admin/emailtemplate/list_header.php | 6 + .../classes/controller/admin/export.php | 88 + modules/export/classes/export.php | 22 + modules/export/classes/export/quicken.php | 198 + modules/export/classes/model/export.php | 14 + modules/export/classes/osbexport.php | 35 + modules/export/classes/quicken.php | 66 + modules/export/classes/quicken/invoice.php | 26 + .../export/classes/quicken/invoiceitem.php | 14 + modules/export/classes/quicken/payment.php | 17 + modules/export/export.inc.php | 65 + modules/export/export_construct.xml | 122 + modules/export/export_install.xml | 59 + modules/export/views/export/payment/body.php | 7 + .../export/views/export/payment/header.php | 12 + modules/export/views/invoices.php | 28 + modules/faq/faq_install.xml | 2 +- modules/faq_category/faq_category_install.xml | 2 +- .../faq_translate/faq_translate_install.xml | 2 +- modules/gchart/classes/googlechart.php | 399 ++ .../classes/controller/hostserver.php | 104 + .../host_server/classes/model/hostserver.php | 16 + modules/host_server/classes/plesk.php | 321 ++ modules/host_tld/host_tld_construct.xml | 2 +- modules/import/import_install.xml | 2 +- .../PDF/pdf_invoice_itemised-fpdf.inc.php | 20 +- .../PDF/pdf_invoice_itemised-fpdi.inc.php | 20 +- .../PDF/pdf_invoice_itemised-tcpdf.inc.php | 194 +- .../classes/controller/admin/invoice.php | 21 + .../invoice/classes/controller/invoice.php | 21 + .../classes/controller/user/invoice.php | 55 + modules/invoice/classes/invoice.php | 92 + modules/invoice/classes/model/invoice.php | 267 + .../invoice/classes/model/invoice/item.php | 93 + modules/invoice/invoice.inc.php | 4682 ++++++++--------- modules/invoice/invoice_base_fpdf.inc.php | 6 +- modules/invoice/invoice_base_fpdi.inc.php | 6 +- modules/invoice/invoice_base_tcpdf.inc.php | 6 +- modules/invoice/invoice_construct.xml | 97 +- modules/invoice/invoice_install.xml | 6 +- modules/invoice/receipt_print.php | 10 +- modules/invoice/views/invoice/html.php | 138 + modules/invoice/views/invoice/list.php | 21 + modules/invoice_item/invoice_item.inc.php | 187 + .../invoice_item/invoice_item_construct.xml | 21 +- modules/module.inc.php | 123 +- .../classes/controller/admin/module.php | 101 + .../controller/admin/module/method.php | 138 + modules/module/classes/controller/module.php | 52 + modules/module/classes/model/group/method.php | 26 + .../module/classes/model/module/method.php | 37 + .../classes/model/module/method/token.php | 26 + modules/module/classes/model/record/id.php | 41 + modules/module/classes/module/method.php | 53 + modules/module/module.inc.php | 5 +- .../module/views/module/admin/list_body.php | 4 + .../module/views/module/admin/list_footer.php | 1 + .../module/views/module/admin/list_header.php | 6 + .../module/views/module/admin/method_add.php | 21 + .../views/module/admin/method_detail_body.php | 8 + .../module/admin/method_detail_footer.php | 1 + .../module/admin/method_detail_header.php | 8 + .../views/module/admin/method_list_body.php | 11 + .../views/module/admin/method_list_footer.php | 1 + .../views/module/admin/method_list_header.php | 7 + .../views/module/admin/method_list_spacer.php | 3 + .../module_method/module_method_construct.xml | 1 + modules/payment/auth.inc.php | 33 + modules/payment/classes/model/payment.php | 41 + .../payment/classes/model/payment/item.php | 15 + modules/payment/payment.inc.php | 241 + modules/payment/payment_construct.xml | 248 + modules/payment/payment_install.xml | 61 + modules/payment_item/payment_item.inc.php | 159 + .../payment_item/payment_item_construct.xml | 82 + modules/payment_item/payment_item_install.xml | 58 + .../product/classes/controller/product.php | 75 + .../classes/controller/product/category.php | 38 + modules/product/classes/model/product.php | 89 + .../classes/model/product/category.php | 20 + .../classes/model/product/translate.php | 18 + modules/product/product.inc.php | 76 +- modules/product/product_construct.xml | 25 +- modules/product/product_install.xml | 2 +- .../product/views/product/category/list.php | 7 + .../product/views/product/category/view.php | 40 + modules/product/views/product/view.php | 85 + .../product_attr/product_attr_construct.xml | 10 +- modules/product_attr/product_attr_install.xml | 2 +- modules/product_cat/product_cat_construct.xml | 10 +- modules/product_cat/product_cat_install.xml | 2 +- .../product_cat_translate_construct.xml | 10 +- .../product_cat_translate_install.xml | 2 +- .../product_cat_translate_install_data.xml | 6 +- modules/product_img/product_img_install.xml | 2 +- .../product_translate.inc.php | 127 +- .../product_translate_construct.xml | 32 +- .../product_translate_install.xml | 2 +- .../product_translate_install_data.xml | 28 +- .../classes/controller/admin/service.php | 425 ++ .../classes/controller/task/service.php | 50 + .../classes/controller/user/service.php | 110 + modules/service/classes/model/service.php | 101 + .../service/classes/model/service/adsl.php | 328 ++ .../classes/model/service/adsl/traffic.php | 23 + .../service/classes/service/traffic/adsl.php | 158 + .../service/traffic/adsl/exetelhspa.php | 176 + .../service/traffic/adsl/exetelvisp.php | 65 + .../service/traffic/adsl/iinetadsl.php | 124 + .../service/traffic/adsl/peopleagent.php | 62 + modules/service/service_construct.xml | 36 +- modules/service/views/service/list.php | 21 + .../views/service/list/adslbilling_body.php | 10 + .../views/service/list/adslbilling_foot.php | 4 + .../views/service/list/adslbilling_head.php | 7 + .../service/list/adslbilling_summary.php | 10 + .../list/adslbilling_summary_exception.php | 6 + .../views/service/list/adslservices_body.php | 12 + .../service/list/adslservices_header.php | 23 + .../views/service/list/bycheckout_body.php | 9 + .../views/service/list/bycheckout_header.php | 16 + .../service/list/bycheckout_subtotal.php | 5 + modules/service/views/service/view.php | 39 + .../views/service/view_detail_adsl.php | 32 + .../service/view_detail_adsl_traffic.php | 9 + modules/session/session_construct.xml | 4 +- modules/setup/setup_install_data.xml | 2 +- modules/staff/staff.inc.php | 50 + modules/staff/staff_construct.xml | 12 +- .../staff_department_construct.xml | 16 +- .../staff_department_install.xml | 2 + .../classes/controller/staticpage.php | 36 + .../controller/staticpage/category.php | 72 + .../static_page/classes/model/staticpage.php | 27 + .../classes/model/staticpage/category.php | 19 + .../classes/model/staticpage/translate.php | 19 + .../views/staticpage/category/list.php | 7 + .../views/staticpage/category/view.php | 40 + modules/static_page/views/staticpage/view.php | 32 + .../static_page_category.inc.php | 60 +- modules/task/task.inc.php | 164 +- modules/task/task_construct.xml | 12 +- modules/task/task_install.xml | 2 + modules/task_log/task_log_construct.xml | 31 +- modules/task_log/task_log_install.xml | 2 + .../tax/classes/model/invoice/item/tax.php | 15 + modules/tax/classes/model/tax.php | 15 + modules/tax/classes/tax.php | 58 + plugins/checkout/PAYPAL.php | 55 +- plugins/checkout/PAYPAL/PAYPAL.php | 2 +- plugins/import/WHMCS.php | 126 + plugins/product/ADSL.php | 28 + themes/default/blocks/account/view.tpl | 67 +- themes/default/blocks/account_fee/add.tpl | 72 + .../blocks/account_fee/search_show.tpl | 12 + themes/default/blocks/account_fee/view.tpl | 72 + themes/default/blocks/adsl/add.tpl | 43 + themes/default/blocks/adsl/search_show.tpl | 12 + themes/default/blocks/adsl/view.tpl | 104 + themes/default/blocks/adsl_supplier/add.tpl | 36 + .../blocks/adsl_supplier/search_show.tpl | 12 + themes/default/blocks/adsl_supplier/view.tpl | 49 + themes/default/blocks/asset/add.tpl | 99 +- themes/default/blocks/asset/search_show.tpl | 125 +- themes/default/blocks/asset/view.tpl | 221 +- themes/default/blocks/asset_pool/add.tpl | 71 +- .../default/blocks/asset_pool/search_show.tpl | 101 +- themes/default/blocks/asset_pool/view.tpl | 133 +- themes/default/blocks/cart/admin_view.tpl | 2 +- themes/default/blocks/cart/cart.tpl | 2 +- .../default/blocks/cart/cart_table_type_2.tpl | 8 +- .../default/blocks/cart/cart_table_type_3.tpl | 8 +- .../default/blocks/cart/cart_table_type_x.tpl | 14 +- .../blocks/cart/cart_tr_adhocdiscount.tpl | 2 +- themes/default/blocks/charge/add.tpl | 4 + themes/default/blocks/charge/search_form.tpl | 5 +- themes/default/blocks/charge/view.tpl | 4 + themes/default/blocks/checkout/add.tpl | 2 +- themes/default/blocks/checkout/checkout.tpl | 10 +- themes/default/blocks/core/bottom_clean.tpl | 2 + themes/default/blocks/core/search.tpl | 4 +- themes/default/blocks/core/search_iframe.tpl | 4 +- .../default/blocks/core/search_show_pre.tpl | 1 + .../blocks/core/search_show_tr_record.tpl | 6 +- themes/default/blocks/core/test.tpl | 1 - .../blocks/discount/user_search_show.tpl | 138 +- themes/default/blocks/export/add.tpl | 54 + .../blocks/export/add_quickenproduct.tpl | 27 + themes/default/blocks/export/search_show.tpl | 12 + themes/default/blocks/export/view.tpl | 57 + themes/default/blocks/host_tld/host_tld.js | 6 + themes/default/blocks/invoice/InvoiceSoon.tpl | 45 + themes/default/blocks/invoice/invoicesoon.tpl | 72 - themes/default/blocks/invoice/thankyou.tpl | 18 +- .../blocks/invoice/user_search_show.tpl | 3 +- themes/default/blocks/invoice/user_view.tpl | 37 +- themes/default/blocks/invoice/view.tpl | 29 +- .../blocks/module_method/view_methods.tpl | 2 +- .../blocks/payment/ListInvoicesBalance.tpl | 34 + .../blocks/payment/ListUnallocated.tpl | 34 + .../default/blocks/payment/ListUnbalanced.tpl | 34 + themes/default/blocks/payment/add.tpl | 66 + themes/default/blocks/payment/allocate.tpl | 51 + themes/default/blocks/payment/search_form.tpl | 62 + themes/default/blocks/payment/search_show.tpl | 12 + themes/default/blocks/payment/view.tpl | 77 + themes/default/blocks/product/add.tpl | 5 + .../default/blocks/product/admin_details.tpl | 227 +- themes/default/blocks/product/details.tpl | 335 +- .../default/blocks/product/details_wizard.tpl | 736 +-- .../default/blocks/product/iframe_hosting.tpl | 257 +- .../default/blocks/product/iframe_plugins.tpl | 148 +- themes/default/blocks/product/product.js | 49 + .../blocks/product/ti_product-host.tpl | 32 + .../product/ti_product-price_type-1.tpl | 21 + .../product/ti_product-price_type-2.tpl | 17 + .../product/ti_product-price_type-x.tpl | 13 + .../ti_product_attr-collect_type-0.tpl | 25 + .../ti_product_attr-collect_type-1.tpl | 25 + .../ti_product_attr-collect_type-2.tpl | 33 + .../ti_product_attr-collect_type-3.tpl | 25 + themes/default/blocks/product/view.tpl | 188 +- themes/default/blocks/product_attr/view.tpl | 2 +- themes/default/blocks/product_cat/view.tpl | 2 +- .../product_plugin/plugin_order_ADSL.tpl | 122 + .../product_plugin/plugin_prod_ADSL.tpl | 131 + .../product_plugin/plugin_prod_ASSET.tpl | 2 +- .../product_plugin/plugin_view_ADSL.tpl | 78 + .../default/blocks/product_translate/add.tpl | 132 +- .../default/blocks/product_translate/edit.tpl | 200 +- .../blocks/product_translate/search_show.tpl | 87 +- .../default/blocks/product_translate/view.tpl | 192 +- themes/default/blocks/service/search_show.tpl | 7 +- themes/default/blocks/service/user_modify.tpl | 20 +- themes/default/blocks/service/user_view.tpl | 23 + themes/default/blocks/service/view.tpl | 20 +- themes/default/blocks/staff/add.tpl | 3 - themes/default/blocks/staff/view.tpl | 7 +- .../default/blocks/static_page/page_list.tpl | 36 - .../default/blocks/static_page/page_show.tpl | 22 - .../blocks/static_page_category/menu.tpl | 28 - themes/default/blocks/task/view.tpl | 4 +- .../default/blocks/task_log/search_show.tpl | 12 + themes/default/cart.js | 41 - themes/default/images/logo-small.png | Bin 5653 -> 2225 bytes themes/default/invoice/invoice-logo.png | Bin 7880 -> 2225 bytes themes/default/invoice/invoice-payment-dd.png | Bin 6352 -> 7104 bytes themes/default/template.tpl | 4 +- themes/default/user_view.js | 2 +- themes/default_admin/blocks/core/admin.tpl | 124 +- .../blocks/core/invalid_page.tpl | 1 - .../blocks/core/leftFrameBlue.tpl | 12 +- .../default_admin/blocks/core/top_frame.tpl | 1 + themes/default_admin/search.js | 11 +- themes/default_admin/view-advanced.js | 6 +- themes/default_admin/view.js | 2 +- 478 files changed, 23423 insertions(+), 9309 deletions(-) create mode 100644 application/cache/.htaccess create mode 100644 application/classes/block.php create mode 100644 application/classes/breadcrumb.php create mode 100644 application/classes/company.php create mode 100644 application/classes/config.php create mode 100644 application/classes/controller/default.php create mode 100644 application/classes/controller/lnapp/default.php create mode 100644 application/classes/controller/lnapp/logout.php create mode 100644 application/classes/controller/lnapp/templatedefault.php create mode 100644 application/classes/controller/lnapp/tree.php create mode 100644 application/classes/controller/login.php create mode 100644 application/classes/controller/logout.php create mode 100644 application/classes/controller/templatedefault.php create mode 100644 application/classes/controller/tree.php create mode 100644 application/classes/database/mysql.php create mode 100644 application/classes/headimages.php create mode 100644 application/classes/htmlrender.php create mode 100644 application/classes/lnapp/block.php create mode 100644 application/classes/lnapp/breadcrumb.php create mode 100644 application/classes/lnapp/config.php create mode 100644 application/classes/lnapp/headimages.php create mode 100644 application/classes/lnapp/htmlrender.php create mode 100644 application/classes/lnapp/meta.php create mode 100644 application/classes/lnapp/script.php create mode 100644 application/classes/lnapp/style.php create mode 100644 application/classes/lnapp/systemmessage.php create mode 100644 application/classes/meta.php create mode 100644 application/classes/model/.htaccess create mode 100644 application/classes/model/module.php create mode 100644 application/classes/ormosb.php create mode 100644 application/classes/period.php create mode 100644 application/classes/script.php create mode 100644 application/classes/staticlist.php create mode 100644 application/classes/staticlist/module.php create mode 100644 application/classes/staticlist/pricetype.php create mode 100644 application/classes/staticlist/recurschedule.php create mode 100644 application/classes/staticlist/title.php create mode 100644 application/classes/staticlist/yesno.php create mode 100644 application/classes/staticlistmodule.php create mode 100644 application/classes/style.php create mode 100644 application/classes/systemmessage.php create mode 100644 application/classes/validate.php create mode 100644 application/config/.htaccess create mode 100644 application/config/auth.php create mode 100644 application/config/cache.php create mode 100644 application/config/config.php create mode 100644 application/config/database.php create mode 100644 application/i18n/.htaccess create mode 100644 application/media/1/img/logo-small.png create mode 100644 application/media/css/default.css create mode 100644 application/media/css/jquery.gritter.css create mode 100644 application/media/css/jquery.jstree.css create mode 100644 application/media/css/list.css create mode 100644 application/media/css/login.css create mode 100644 application/media/img/ajax-progress.gif create mode 100644 application/media/img/dialog-error-big.png create mode 100644 application/media/img/dialog-error.png create mode 100644 application/media/img/dialog-information-big.png create mode 100644 application/media/img/dialog-information.png create mode 100644 application/media/img/dialog-password-big.png create mode 100644 application/media/img/dialog-password.png create mode 100644 application/media/img/dialog-question-big.png create mode 100644 application/media/img/dialog-question.png create mode 100644 application/media/img/dialog-warning-big.png create mode 100644 application/media/img/dialog-warning.png create mode 100644 application/media/img/forum-big.png create mode 100644 application/media/img/jquery.gritter.close-ie6.gif create mode 100644 application/media/img/jquery.gritter.png create mode 100644 application/media/img/jquery.jstree.d.png create mode 100644 application/media/img/jquery.jstree.throbber.gif create mode 100644 application/media/img/login.user.png create mode 100644 application/media/img/logo-small.png create mode 100644 application/media/img/logo.png create mode 100644 application/media/img/toggle-closed.png create mode 100644 application/media/img/toggle-open.png create mode 100644 application/media/js/jquery-1.4.2.js create mode 100644 application/media/js/jquery.cookie.js create mode 100644 application/media/js/jquery.gritter-1.5.js create mode 100644 application/media/js/jquery.jstree-1.0rc.js create mode 100644 application/media/js/jquery.stickyfloat-1.0.js create mode 100644 application/media/js/themes/default/dot_for_ie.gif create mode 100644 application/messages/.htaccess create mode 100644 application/views/.htaccess create mode 100644 application/views/lnapp/default.php create mode 100644 application/views/login.php create mode 100644 application/views/login_reset.php create mode 100644 application/views/login_reset_sent.php create mode 100644 application/views/template.php delete mode 100644 includes/files/tracking.txt create mode 100644 includes/kohana/modules/simplehtmldom/classes/simple_html_dom.php create mode 100644 includes/smarty/plugins/block.translate.php rename language/core/{english_core.xml => en_core.xml} (100%) create mode 100644 modules/account/classes/auth/osb.php create mode 100644 modules/account/classes/controller/account.php create mode 100644 modules/account/classes/controller/user/account.php create mode 100644 modules/account/classes/model/account.php create mode 100644 modules/account/classes/model/auth/roledefault.php create mode 100644 modules/account/classes/model/auth/userdefault.php create mode 100644 modules/account/views/account/edit.php create mode 100644 modules/account/views/account/password_reset.php create mode 100644 modules/account/views/bregister.php create mode 100644 modules/account_fee/account_fee.inc.php create mode 100644 modules/account_fee/account_fee_construct.xml create mode 100644 modules/account_fee/account_fee_install.xml create mode 100644 modules/account_group/classes/model/group.php create mode 100644 modules/adsl/adsl.inc.php create mode 100644 modules/adsl/adsl_construct.xml create mode 100644 modules/adsl/adsl_install.xml create mode 100644 modules/adsl/classes/adsl.php create mode 100644 modules/adsl/classes/model/adsl/plan.php create mode 100644 modules/adsl/classes/model/adsl/supplier.php create mode 100644 modules/adsl/classes/model/adsl/supplier/plan.php create mode 100644 modules/adsl/views/adsl/contract_view.php create mode 100644 modules/adsl/views/adsl/product_view.php create mode 100644 modules/adsl_supplier/adsl_supplier.inc.php create mode 100644 modules/adsl_supplier/adsl_supplier_construct.xml create mode 100644 modules/adsl_supplier/adsl_supplier_install.xml create mode 100644 modules/adsl_supplier/adsl_supplier_install_data.xml create mode 100644 modules/cart/classes/cart.php create mode 100644 modules/cart/classes/controller/cart.php create mode 100644 modules/cart/classes/model/cart.php create mode 100644 modules/cart/media/css/cart_blocklist.css create mode 100644 modules/cart/media/css/cart_contents.css create mode 100644 modules/cart/media/css/checkout_cartlist.css create mode 100644 modules/cart/media/img/accessories-calculator-small.png create mode 100644 modules/cart/media/img/accessories-calculator.png create mode 100644 modules/cart/media/img/edit-delete.png create mode 100644 modules/cart/views/cart/block_list.php create mode 100644 modules/cart/views/cart/checkout_list.php create mode 100644 modules/cart/views/cart/checkout_total.php create mode 100644 modules/cart/views/cart/list_item.php create mode 100644 modules/cart/views/cart/list_pricebox.php create mode 100644 modules/charge/classes/model/charge.php create mode 100644 modules/checkout/classes/controller/checkout.php create mode 100644 modules/checkout/classes/model/checkout.php create mode 100644 modules/checkout/views/checkout/payment_option.php create mode 100644 modules/core/list_staticlist.inc.php create mode 100644 modules/country/classes/country.php create mode 100644 modules/country/media/img/country/AU.gif create mode 100644 modules/country/media/img/country/CA.gif create mode 100644 modules/country/media/img/country/CH.gif create mode 100644 modules/country/media/img/country/DK.gif create mode 100644 modules/country/media/img/country/EU.gif create mode 100644 modules/country/media/img/country/GB.gif create mode 100644 modules/country/media/img/country/HK.gif create mode 100644 modules/country/media/img/country/JP.gif create mode 100644 modules/country/media/img/country/MX.gif create mode 100644 modules/country/media/img/country/MY.gif create mode 100644 modules/country/media/img/country/NO.gif create mode 100644 modules/country/media/img/country/NZ.gif create mode 100644 modules/country/media/img/country/RU.gif create mode 100644 modules/country/media/img/country/SE.gif create mode 100644 modules/country/media/img/country/US.gif create mode 100644 modules/country/media/img/country/ZA.gif create mode 100644 modules/currency/classes/currency.php create mode 100644 modules/emailtemplate/classes/controller/admin/emailtemplate.php create mode 100644 modules/emailtemplate/classes/emailtemplate.php create mode 100644 modules/emailtemplate/classes/model/emailtemplate.php create mode 100644 modules/emailtemplate/classes/model/emailtemplate/translate.php create mode 100644 modules/emailtemplate/views/admin/emailtemplate/add.php create mode 100644 modules/emailtemplate/views/admin/emailtemplate/add_translate.php create mode 100644 modules/emailtemplate/views/admin/emailtemplate/edit.php create mode 100644 modules/emailtemplate/views/admin/emailtemplate/edit_translate.php create mode 100644 modules/emailtemplate/views/admin/emailtemplate/list_body.php create mode 100644 modules/emailtemplate/views/admin/emailtemplate/list_footer.php create mode 100644 modules/emailtemplate/views/admin/emailtemplate/list_header.php create mode 100644 modules/export/classes/controller/admin/export.php create mode 100644 modules/export/classes/export.php create mode 100644 modules/export/classes/export/quicken.php create mode 100644 modules/export/classes/model/export.php create mode 100644 modules/export/classes/osbexport.php create mode 100644 modules/export/classes/quicken.php create mode 100644 modules/export/classes/quicken/invoice.php create mode 100644 modules/export/classes/quicken/invoiceitem.php create mode 100644 modules/export/classes/quicken/payment.php create mode 100644 modules/export/export.inc.php create mode 100644 modules/export/export_construct.xml create mode 100644 modules/export/export_install.xml create mode 100644 modules/export/views/export/payment/body.php create mode 100644 modules/export/views/export/payment/header.php create mode 100644 modules/export/views/invoices.php create mode 100644 modules/gchart/classes/googlechart.php create mode 100644 modules/host_server/classes/controller/hostserver.php create mode 100644 modules/host_server/classes/model/hostserver.php create mode 100644 modules/host_server/classes/plesk.php create mode 100644 modules/invoice/classes/controller/admin/invoice.php create mode 100644 modules/invoice/classes/controller/invoice.php create mode 100644 modules/invoice/classes/controller/user/invoice.php create mode 100644 modules/invoice/classes/invoice.php create mode 100644 modules/invoice/classes/model/invoice.php create mode 100644 modules/invoice/classes/model/invoice/item.php create mode 100644 modules/invoice/views/invoice/html.php create mode 100644 modules/invoice/views/invoice/list.php create mode 100644 modules/module/classes/controller/admin/module.php create mode 100644 modules/module/classes/controller/admin/module/method.php create mode 100644 modules/module/classes/controller/module.php create mode 100644 modules/module/classes/model/group/method.php create mode 100644 modules/module/classes/model/module/method.php create mode 100644 modules/module/classes/model/module/method/token.php create mode 100644 modules/module/classes/model/record/id.php create mode 100644 modules/module/classes/module/method.php create mode 100644 modules/module/views/module/admin/list_body.php create mode 100644 modules/module/views/module/admin/list_footer.php create mode 100644 modules/module/views/module/admin/list_header.php create mode 100644 modules/module/views/module/admin/method_add.php create mode 100644 modules/module/views/module/admin/method_detail_body.php create mode 100644 modules/module/views/module/admin/method_detail_footer.php create mode 100644 modules/module/views/module/admin/method_detail_header.php create mode 100644 modules/module/views/module/admin/method_list_body.php create mode 100644 modules/module/views/module/admin/method_list_footer.php create mode 100644 modules/module/views/module/admin/method_list_header.php create mode 100644 modules/module/views/module/admin/method_list_spacer.php create mode 100644 modules/payment/auth.inc.php create mode 100644 modules/payment/classes/model/payment.php create mode 100644 modules/payment/classes/model/payment/item.php create mode 100644 modules/payment/payment.inc.php create mode 100644 modules/payment/payment_construct.xml create mode 100644 modules/payment/payment_install.xml create mode 100644 modules/payment_item/payment_item.inc.php create mode 100644 modules/payment_item/payment_item_construct.xml create mode 100644 modules/payment_item/payment_item_install.xml create mode 100644 modules/product/classes/controller/product.php create mode 100644 modules/product/classes/controller/product/category.php create mode 100644 modules/product/classes/model/product.php create mode 100644 modules/product/classes/model/product/category.php create mode 100644 modules/product/classes/model/product/translate.php create mode 100644 modules/product/views/product/category/list.php create mode 100644 modules/product/views/product/category/view.php create mode 100644 modules/product/views/product/view.php create mode 100644 modules/service/classes/controller/admin/service.php create mode 100644 modules/service/classes/controller/task/service.php create mode 100644 modules/service/classes/controller/user/service.php create mode 100644 modules/service/classes/model/service.php create mode 100644 modules/service/classes/model/service/adsl.php create mode 100644 modules/service/classes/model/service/adsl/traffic.php create mode 100644 modules/service/classes/service/traffic/adsl.php create mode 100644 modules/service/classes/service/traffic/adsl/exetelhspa.php create mode 100644 modules/service/classes/service/traffic/adsl/exetelvisp.php create mode 100644 modules/service/classes/service/traffic/adsl/iinetadsl.php create mode 100644 modules/service/classes/service/traffic/adsl/peopleagent.php create mode 100644 modules/service/views/service/list.php create mode 100644 modules/service/views/service/list/adslbilling_body.php create mode 100644 modules/service/views/service/list/adslbilling_foot.php create mode 100644 modules/service/views/service/list/adslbilling_head.php create mode 100644 modules/service/views/service/list/adslbilling_summary.php create mode 100644 modules/service/views/service/list/adslbilling_summary_exception.php create mode 100644 modules/service/views/service/list/adslservices_body.php create mode 100644 modules/service/views/service/list/adslservices_header.php create mode 100644 modules/service/views/service/list/bycheckout_body.php create mode 100644 modules/service/views/service/list/bycheckout_header.php create mode 100644 modules/service/views/service/list/bycheckout_subtotal.php create mode 100644 modules/service/views/service/view.php create mode 100644 modules/service/views/service/view_detail_adsl.php create mode 100644 modules/service/views/service/view_detail_adsl_traffic.php create mode 100644 modules/static_page/classes/controller/staticpage.php create mode 100644 modules/static_page/classes/controller/staticpage/category.php create mode 100644 modules/static_page/classes/model/staticpage.php create mode 100644 modules/static_page/classes/model/staticpage/category.php create mode 100644 modules/static_page/classes/model/staticpage/translate.php create mode 100644 modules/static_page/views/staticpage/category/list.php create mode 100644 modules/static_page/views/staticpage/category/view.php create mode 100644 modules/static_page/views/staticpage/view.php create mode 100644 modules/tax/classes/model/invoice/item/tax.php create mode 100644 modules/tax/classes/model/tax.php create mode 100644 modules/tax/classes/tax.php create mode 100644 plugins/product/ADSL.php create mode 100644 themes/default/blocks/account_fee/add.tpl create mode 100644 themes/default/blocks/account_fee/search_show.tpl create mode 100644 themes/default/blocks/account_fee/view.tpl create mode 100644 themes/default/blocks/adsl/add.tpl create mode 100644 themes/default/blocks/adsl/search_show.tpl create mode 100644 themes/default/blocks/adsl/view.tpl create mode 100644 themes/default/blocks/adsl_supplier/add.tpl create mode 100644 themes/default/blocks/adsl_supplier/search_show.tpl create mode 100644 themes/default/blocks/adsl_supplier/view.tpl create mode 100644 themes/default/blocks/core/bottom_clean.tpl delete mode 100644 themes/default/blocks/core/test.tpl create mode 100644 themes/default/blocks/export/add.tpl create mode 100644 themes/default/blocks/export/add_quickenproduct.tpl create mode 100644 themes/default/blocks/export/search_show.tpl create mode 100644 themes/default/blocks/export/view.tpl create mode 100644 themes/default/blocks/host_tld/host_tld.js create mode 100644 themes/default/blocks/invoice/InvoiceSoon.tpl delete mode 100644 themes/default/blocks/invoice/invoicesoon.tpl create mode 100644 themes/default/blocks/payment/ListInvoicesBalance.tpl create mode 100644 themes/default/blocks/payment/ListUnallocated.tpl create mode 100644 themes/default/blocks/payment/ListUnbalanced.tpl create mode 100644 themes/default/blocks/payment/add.tpl create mode 100644 themes/default/blocks/payment/allocate.tpl create mode 100644 themes/default/blocks/payment/search_form.tpl create mode 100644 themes/default/blocks/payment/search_show.tpl create mode 100644 themes/default/blocks/payment/view.tpl create mode 100644 themes/default/blocks/product/product.js create mode 100644 themes/default/blocks/product/ti_product-host.tpl create mode 100644 themes/default/blocks/product/ti_product-price_type-1.tpl create mode 100644 themes/default/blocks/product/ti_product-price_type-2.tpl create mode 100644 themes/default/blocks/product/ti_product-price_type-x.tpl create mode 100644 themes/default/blocks/product/ti_product_attr-collect_type-0.tpl create mode 100644 themes/default/blocks/product/ti_product_attr-collect_type-1.tpl create mode 100644 themes/default/blocks/product/ti_product_attr-collect_type-2.tpl create mode 100644 themes/default/blocks/product/ti_product_attr-collect_type-3.tpl create mode 100644 themes/default/blocks/product_plugin/plugin_order_ADSL.tpl create mode 100644 themes/default/blocks/product_plugin/plugin_prod_ADSL.tpl create mode 100644 themes/default/blocks/product_plugin/plugin_view_ADSL.tpl delete mode 100644 themes/default/blocks/static_page/page_list.tpl delete mode 100644 themes/default/blocks/static_page/page_show.tpl delete mode 100644 themes/default/blocks/static_page_category/menu.tpl create mode 100644 themes/default/blocks/task_log/search_show.tpl delete mode 100644 themes/default/cart.js delete mode 100644 themes/default_admin/blocks/core/invalid_page.tpl diff --git a/.htaccess b/.htaccess index 87b9cf81..7238b8dc 100644 --- a/.htaccess +++ b/.htaccess @@ -2,7 +2,7 @@ RewriteEngine On # Installation directory -RewriteBase /kohana/ +RewriteBase /osb/ # Protect hidden files from being viewed @@ -11,11 +11,11 @@ RewriteBase /kohana/ # Protect application and system files from being viewed -RewriteRule ^(?:application|modules|system)\b.* index.php/$0 [L] +RewriteRule ^(?:application|modules|includes/kohana)\b.* kh.php/$0 [L] # Allow any files or directories that exist to be displayed directly RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d -# Rewrite all other URLs to index.php/URL -RewriteRule .* index.php/$0 [PT] +# Rewrite all other URLs to kh.php/URL +RewriteRule .* kh.php/$0 [PT] diff --git a/application/bootstrap.php b/application/bootstrap.php index f87c7454..d0af2600 100644 --- a/application/bootstrap.php +++ b/application/bootstrap.php @@ -8,7 +8,7 @@ * @see http://kohanaframework.org/guide/using.configuration * @see http://php.net/timezones */ -date_default_timezone_set('America/Chicago'); +date_default_timezone_set('Australia/Melbourne'); /** * Set the default locale. @@ -50,7 +50,8 @@ ini_set('unserialize_callback_func', 'spl_autoload_call'); * - boolean caching enable or disable internal caching FALSE */ Kohana::init(array( - 'base_url' => '/', + 'base_url' => '/osb', + 'index_file' => '', )); /** @@ -67,16 +68,32 @@ Kohana::$config->attach(new Kohana_Config_File); * Enable modules. Modules are referenced by a relative or absolute path. */ Kohana::modules(array( - // 'auth' => SMDPATH.'auth', // Basic authentication - // 'cache' => SMDPATH.'cache', // Caching with multiple backends + 'auth' => SMDPATH.'auth', // Basic authentication + 'cache' => SMDPATH.'cache', // Caching with multiple backends // 'codebench' => SMDPATH.'codebench', // Benchmarking tool - // 'database' => SMDPATH.'database', // Database access + 'database' => SMDPATH.'database', // Database access // 'image' => SMDPATH.'image', // Image manipulation - // 'orm' => SMDPATH.'orm', // Object Relationship Mapping + 'orm' => SMDPATH.'orm', // Object Relationship Mapping // 'oauth' => SMDPATH.'oauth', // OAuth authentication // 'pagination' => SMDPATH.'pagination', // Paging of results // 'unittest' => SMDPATH.'unittest', // Unit testing // 'userguide' => SMDPATH.'userguide', // User guide and API documentation + 'xml' => SMDPATH.'xml', // XML module for Kohana 3 PHP Framework + 'email' => SMDPATH.'email', // Email module for Kohana 3 PHP Framework + 'gchart' => MODPATH.'gchart', // Google Chart Module + )); + +/** + * Load our modules defined in the DB + */ +Kohana::modules(array_merge(Kohana::modules(),Config::appmodules())); + +/** + * Enable admin, user (account), reseller and affiliate interfaces + */ +Route::set('sections', '/(/(/(/)))', + array( + 'directory' => '('.implode('|',Kohana::config('config.method_directory')).')' //(account|admin|affiliate|reseller|task)' )); /** @@ -89,6 +106,20 @@ Route::set('default', '((/(/)))') 'action' => 'index', )); +// Static file serving (CSS, JS, images) +Route::set('default/media', 'media(/)', array('file' => '.+')) + ->defaults(array( + 'controller' => 'welcome', + 'action' => 'media', + 'file' => NULL, + )); + +// Make sure their PHP version is current enough +if (strcmp(phpversion(),'5.3') < 0) { + echo 'This application requires PHP 5.3 or newer to run'; + die(); +} + if ( ! defined('SUPPRESS_REQUEST')) { /** diff --git a/application/cache/.htaccess b/application/cache/.htaccess new file mode 100644 index 00000000..281d5c33 --- /dev/null +++ b/application/cache/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/application/classes/block.php b/application/classes/block.php new file mode 100644 index 00000000..0b6b536a --- /dev/null +++ b/application/classes/block.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/breadcrumb.php b/application/classes/breadcrumb.php new file mode 100644 index 00000000..61fc6976 --- /dev/null +++ b/application/classes/breadcrumb.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/company.php b/application/classes/company.php new file mode 100644 index 00000000..fd19965e --- /dev/null +++ b/application/classes/company.php @@ -0,0 +1,50 @@ +') { + // @todo Company address should be calculated + return implode($ln,array('PO Box 149','Bendigo, VIC 3550')); + } + + public static function contacts() { + // @todo Company phone should be calculated + return 'Tel: 03 5410 1135'; + } + + public static function render() { + echo static::name(); + echo static::address(); + echo static::contacts(); + } + + /** + * Return the HTML to render the company address + */ + public function __toString() { + try { + return static::render(); + } + + // Display the exception message + catch (Exception $e) { + Kohana::exception_handler($e); + + return ''; + } + } +} +?> diff --git a/application/classes/config.php b/application/classes/config.php new file mode 100644 index 00000000..fd71789f --- /dev/null +++ b/application/classes/config.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/controller/default.php b/application/classes/controller/default.php new file mode 100644 index 00000000..478f8eeb --- /dev/null +++ b/application/classes/controller/default.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/controller/lnapp/default.php b/application/classes/controller/lnapp/default.php new file mode 100644 index 00000000..fe5d1d91 --- /dev/null +++ b/application/classes/controller/lnapp/default.php @@ -0,0 +1,75 @@ + 'admin' will only allow users with the role admin to access action_adminpanel + * 'moderatorpanel' => array('login', 'moderator') will only allow users with the roles login and moderator to access action_moderatorpanel + * + * @var array actions that require a valid user + */ + protected $secure_actions = array(); + + /** + * Check and see if this controller needs authentication + * + * if $this->auth_required is TRUE, then the user must be logged in only. + * if $this->auth_required is FALSE, AND $this->secure_actions has an array of + * methods set to TRUE, then the user must be logged in AND a member of the + * role. + * + * @return boolean + */ + protected function _auth_required() { + // If our global configurable is disabled, then continue + if (! Kohana::Config('config.method_security')) + return FALSE; + + return (($this->auth_required !== FALSE && Auth::instance()->logged_in() === FALSE) || + (is_array($this->secure_actions) && array_key_exists($this->request->action,$this->secure_actions) && + Auth::instance()->logged_in($this->secure_actions[$this->request->action]) === FALSE)); + } + + public function before() { + parent::before(); + + // Check user auth and role + if ($this->_auth_required()) { + // For AJAX/JSON requests, authorisation is controlled in the method. + if (Request::$is_ajax && $this->request->action === 'json') { + // Nothing required. + + // For no AJAX/JSON requests, display an access page + } elseif (Auth::instance()->logged_in(NULL,get_class($this).'|'.__METHOD__)) { + Request::instance()->redirect('login/noaccess'); + + } else { + Session::instance()->set('afterlogin',Request::instance()->uri()); + Request::instance()->redirect($this->noauth_redirect); + } + } + } +} +?> diff --git a/application/classes/controller/lnapp/logout.php b/application/classes/controller/lnapp/logout.php new file mode 100644 index 00000000..7e964ed4 --- /dev/null +++ b/application/classes/controller/lnapp/logout.php @@ -0,0 +1,26 @@ +logged_in()!= 0) { + Auth::instance()->logout(); + + Request::instance()->redirect('login'); + } + + Request::instance()->redirect('welcome/index'); + } +} +?> diff --git a/application/classes/controller/lnapp/templatedefault.php b/application/classes/controller/lnapp/templatedefault.php new file mode 100644 index 00000000..343804f3 --- /dev/null +++ b/application/classes/controller/lnapp/templatedefault.php @@ -0,0 +1,279 @@ + 'admin' will only allow users with the role admin to access action_adminpanel + * 'moderatorpanel' => array('login', 'moderator') will only allow users with the roles login and moderator to access action_moderatorpanel + * + * @var array actions that require a valid user + */ + protected $secure_actions = array( + 'menu' => TRUE, + ); + + /** + * Check and see if this controller needs authentication + * + * if $this->auth_required is TRUE, then the user must be logged in only. + * if $this->auth_required is FALSE, AND $this->secure_actions has an array of + * methods set to TRUE, then the user must be logged in AND a member of the + * role. + * + * @return boolean + */ + protected function _auth_required() { + // If our global configurable is disabled, then continue + if (! Kohana::Config('config.method_security')) + return FALSE; + + return (($this->auth_required !== FALSE && Auth::instance()->logged_in() === FALSE) || + (is_array($this->secure_actions) && array_key_exists($this->request->action,$this->secure_actions) && + Auth::instance()->logged_in($this->secure_actions[$this->request->action]) === FALSE)); + } + + /** + * Loads the template [View] object. + * + * Page information is provided by [meta]. + * @uses meta + */ + public function before() { + // Do not template media files + if ($this->request->action === 'media') { + $this->auto_render = FALSE; + return; + } + + parent::before(); + + // Check user auth and role + if ($this->_auth_required()) { + if (Kohana::$is_cli) + throw new Kohana_Exception('Cant run :method, authentication not possible',array(':method'=>$this->request->action)); + + // If auth is required and the user is logged in, then they dont have access. + // (We have already checked authorisation.) + if (Auth::instance()->logged_in(NULL,get_class($this).'|'.__METHOD__)) { + if (Config::sitemode() == Kohana::DEVELOPMENT) + SystemMessage::add(array( + 'title'=>_('Insufficient Access'), + 'type'=>'debug', + 'body'=>Kohana::debug(array('required'=>$this->auth_required,'action'=>$this->request->action,'user'=>Auth::instance()->get_user()->username)), + )); + + // @todo Login No Access redirects are not handled in JS? + if (Request::$is_ajax) { + echo _('You dont have enough permissions.'); + die(); + } else + Request::instance()->redirect('login/noaccess'); + + } else { + Session::instance()->set('afterlogin',Request::instance()->uri()); + Request::instance()->redirect($this->noauth_redirect); + } + } + + // For AJAX calls, we dont need to render the complete page. + if (Request::$is_ajax) { + $this->auto_render = FALSE; + return; + } + + // Bind our template meta variable + $this->meta = new meta; + View::bind_global('meta',$this->meta); + + // Our default style sheet + Style::add(array( + 'type'=>'file', + 'data'=>'css/default.css', + )); + + // Our default scripts + // This is in a reverse list, since we push them to the beginging of the scripts to render. + foreach (array('file'=>array( + 'js/jquery.cookie.js', + 'js/jquery.jstree-1.0rc.js', + 'js/jquery-1.4.2.js', + )) as $type => $datas) { + + foreach ($datas as $data) { + Script::add(array( + 'type'=>$type, + 'data'=>$data, + ),TRUE); + } + } + + // Initialise our content + $this->template->left = ''; + $this->template->content = ''; + $this->template->right = ''; + } + + public function after() { + if ($this->auto_render) { + // Application Title + $this->meta->title = 'Application Title'; + $this->template->title = ''; + + // Style Sheets Properties + $this->meta->styles = Style::factory(); + + // Script Properties + $this->meta->scripts = Script::factory(); + + // Application logo + $this->template->logo = Config::logo(); + + // Link images on the header line + $this->template->headimages = $this->_headimages(); + + // Control Line + $this->template->control = $this->_control(); + + // System Messages line + $this->template->sysmsg = $this->_sysmsg(); + + // Left Item + $this->template->left = $this->_left(); + + // Right Item + $this->template->right = $this->_right(); + + // Footer + $this->template->footer = $this->_footer(); + + // For any ajax rendered actions, we'll need to capture the content and put it in the response + } elseif (Request::$is_ajax && isset($this->template->content) && ! $this->request->response) { + // @todo move this formatting to a view? + if ($s = $this->_sysmsg() AND (string)$s) { + $this->request->response = sprintf('
%s
',$s); + } else + $this->request->response = ''; + + # In case there any style sheets or scrpits for this render. + $this->request->response .= Style::factory(); + + # Get the response body + $this->request->response .= sprintf('
%s
',$this->template->content); + } + + parent::after(); + } + + /** + * Default Method to call from the tree menu + */ + public function action_menu() { + $this->template->content = 'See menu on tree'; + } + + protected function _headimages() { + HeadImages::add(array( + 'url'=>'http://dev.leenooks.net', + 'img'=>'img/forum-big.png', + 'attrs'=>array('onclick'=>"target='_blank';",'title'=>'Link') + )); + + return HeadImages::factory(); + } + + /** + * Render our control menu bar + */ + protected function _control() { + return Breadcrumb::factory(); + } + + protected function _sysmsg() { + return SystemMessage::factory(); + } + + protected function _left() { + return empty($this->template->left) ? Controller_Tree::js() : $this->template->left; + } + + protected function _right() { + return empty($this->template->right) ? '' : $this->template->right; + } + + public function _footer() { + return sprintf('© %s',Config::SiteName()); + } + + /** + * This action will render all the media related files for a page + * @return void + */ + final public function action_media() { + // Generate and check the ETag for this file + $this->request->check_cache(sha1($this->request->uri)); + + // Get the file path from the request + $file = $this->request->param('file'); + + // Find the file extension + $ext = pathinfo($file, PATHINFO_EXTENSION); + + // Remove the extension from the filename + $file = substr($file, 0, -(strlen($ext) + 1)); + + // First try and find media files for the site_id + if ($f = Kohana::find_file(sprintf('media/%s',Config::siteid()), $file, $ext)) { + // Send the file content as the response + $this->request->response = file_get_contents($f); + + // If not found try a default media file + } elseif ($f = Kohana::find_file('media', $file, $ext)) { + // Send the file content as the response + $this->request->response = file_get_contents($f); + + } else { + // Return a 404 status + $this->request->status = 404; + } + + // Set the proper headers to allow caching + $this->request->headers['Content-Type'] = File::mime_by_ext($ext); + $this->request->headers['Content-Length'] = filesize($f); + $this->request->headers['Last-Modified'] = date('r', filemtime($f)); + } +} +?> diff --git a/application/classes/controller/lnapp/tree.php b/application/classes/controller/lnapp/tree.php new file mode 100644 index 00000000..4d6fd587 --- /dev/null +++ b/application/classes/controller/lnapp/tree.php @@ -0,0 +1,110 @@ +request->headers['Content-Type'] = 'application/json'; + $this->request->response = sprintf('[%s]',json_encode($this->treedata)); + } + + public static function js() { + $mediapath = Route::get(static::$mediaroute); + + return ' +
+'; + } + + /** + * Draw the Tree Menu + * + * The incoming ID is either a Branch B_x or a Node N_x + * Where X is actually the module. + * + * @param id + */ + public function action_json($id=null) { + if ($this->_auth_required()) { + $this->treedata = array('attr'=>array('id'=>'a_login'), + 'data'=>array('title'=>_('Please Login').'...','attr'=>array('id'=>'login','href'=>URL::site('/login')))); + + return; + } + + $this->treedata = array(); + $data = array(); + + foreach ($data as $branch) { + array_push($this->treedata,array( + 'attr'=>array('id'=>sprintf('B_%s',$branch['id'])), + 'state'=>$branch['state'], + 'data'=>array('title'=>$branch['name']), + 'attr'=>array('id'=>sprintf('N_%s',$branch['id']),'href'=>empty($branch['attr_href']) ? URL::site(sprintf('/%s/menu',$branch['name'])) : $branch['attr_href']), + ) + ); + } + } +} +?> diff --git a/application/classes/controller/login.php b/application/classes/controller/login.php new file mode 100644 index 00000000..e9e1a5ba --- /dev/null +++ b/application/classes/controller/login.php @@ -0,0 +1,209 @@ +logged_in()!= 0) { + // Redirect to the user account + Request::instance()->redirect('welcome/index'); + } + + // If there is a post and $_POST is not empty + if ($_POST) { + // Instantiate a new user + $user = ORM::factory('account'); + + // Check Auth + $status = $user->login($_POST); + + // If the post data validates using the rules setup in the user model + if ($status) { + // Redirect to the user account + if ($redir = Session::instance()->get('afterlogin')) { + Session::instance()->delete('afterlogin'); + Request::instance()->redirect($redir); + + } else + Request::instance()->redirect('welcome/index'); + + } else { + SystemMessage::add(array( + 'title'=>_('Invalid username or password'), + 'type'=>'error', + 'body'=>_('The username or password was invalid.') + )); + } + } + + Block::add(array( + 'title'=>_('Login to server'), + 'body'=>View::factory('login'), + 'style'=>array('css/login.css'=>'screen'), + )); + + $this->template->control = HTML::anchor($this->request->uri(),'Login',array('id'=>'ajxbody')); + $this->template->content = Block::factory(); + + Script::add(array('type'=>'stdin','data'=>' + $(document).ready(function() { + $("#ajxbody").click(function() {$("#ajBODY").load("'.$this->request->uri().'/"); return false;}); + });' + )); + } + + public function action_register() { + // If user already signed-in + if (Auth::instance()->logged_in()!= 0) { + // Redirect to the user account + Request::instance()->redirect('welcome/index'); + } + + // Instantiate a new user + $account = ORM::factory('account'); + + // If there is a post and $_POST is not empty + if ($_POST) { + // Check Auth + $status = $account->values($_POST)->check(); + + if (! $status) { + foreach ($account->validate()->errors() as $f=>$r) { + // $r[0] has our reason for validation failure + switch ($r[0]) { + // Generic validation reason + default: + SystemMessage::add(array( + 'title'=>_('Validation failed'), + 'type'=>'error', + 'body'=>sprintf(_('The defaults on your submission were not valid for field %s (%s).'),$f,$r[0]) + )); + } + } + } + + $ido = ORM::factory('module') + ->where('name','=','account') + ->find(); + + $account->id = $ido->record_id->next_id($ido->id); + // Save the user details + if ($account->save()) {} + + } + + SystemMessage::add(array( + 'title'=>_('Already have an account?'), + 'type'=>'info', + 'body'=>_('If you already have an account, please login..') + )); + + Block::add(array( + 'title'=>_('Register'), + 'body'=>View::factory('bregister') + ->set('account',$account) + ->set('errors',$account->validate()->errors()), + 'style'=>array('css/bregister.css'=>'screen'), + )); + + $this->template->control = HTML::anchor($this->request->uri(),'Register',array('id'=>'ajxbody')); + $this->template->content = Block::factory(); + $this->template->left = HTML::anchor('login','Login').'...'; + } + + /** + * Enable user password reset + */ + public function action_reset() { + // If user already signed-in + if (Auth::instance()->logged_in()!= 0) { + // Redirect to the user account + Request::instance()->redirect('welcome/index'); + } + + // If the user posted their details to reset their password + if ($_POST) { + // If the email address is correct, create a method token + if (! empty($_POST['email']) AND ($ao=ORM::factory('account',array('email'=>$_POST['email']))) AND $ao->loaded()) { + $mt = ORM::factory('module_method_token'); + + // Find out our password reset method id + // @todo move this to a more generic method, so that it can be called by other methods + $mo = ORM::factory('module',array('name'=>'account')); + $mmo = ORM::factory('module_method',array('name'=>'user_resetpassword','module_id'=>$mo->id)); + + // Check to see if there is already a token, if so, do nothing. + if ($mt->where('account_id','=',$ao->id)->and_where('method_id','=',$mmo->id)->find()) { + if ($mt->date_expire < time()) { + $mt->delete(); + $mt->clear(); + } + } + + if (! $mt->loaded()) { + $mt->account_id = $ao->id; + $mt->method_id = $mmo->id; + $mt->date_expire = time() + 15*3600; + $mt->token = md5(sprintf('%s:%s:%s',$mt->account_id,$mt->method_id,$mt->date_expire)); + $mt->save(); + + // Send our email with the token + $et = EmailTemplate::instance('account_reset_password'); + $et->to = array($mt->account->email=>sprintf('%s %s',$mt->account->first_name,$mt->account->last_name)); + $et->variables = array( + 'SITE'=>URL::base(TRUE,TRUE), + 'SITE_ADMIN'=>Config::sitename(), + 'SITE_NAME'=>Config::sitename(), + 'TOKEN'=>$mt->token, + 'USER_NAME'=>sprintf('%s %s',$mt->account->first_name,$mt->account->last_name), + ); + $et->send(); + } + + // Redirect to our password reset, the Auth will validate the token. + } elseif (! empty($_REQUEST['token'])) { + Request::instance()->redirect(sprintf('user/account/resetpassword?token=%s',$_REQUEST['token'])); + } + + // Show our token screen even if the email was invalid. + if (isset($_POST['email'])) + Block::add(array( + 'title'=>_('Reset your password'), + 'body'=>View::factory('login_reset_sent'), + 'style'=>array('css/login.css'=>'screen'), + )); + else + Request::instance()->redirect('login'); + + } else { + Block::add(array( + 'title'=>_('Reset your password'), + 'body'=>View::factory('login_reset'), + 'style'=>array('css/login.css'=>'screen'), + )); + } + + $this->template->content = Block::factory(); + } + + public function action_noaccess() { + $this->template->content = ' '; + + SystemMessage::add(array( + 'title'=>_('No access to requested resource'), + 'type'=>'error', + 'body'=>_('You do not have access to the requested resource, please contact your administrator.') + )); + } +} +?> diff --git a/application/classes/controller/logout.php b/application/classes/controller/logout.php new file mode 100644 index 00000000..671e24d0 --- /dev/null +++ b/application/classes/controller/logout.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/controller/templatedefault.php b/application/classes/controller/templatedefault.php new file mode 100644 index 00000000..d7070879 --- /dev/null +++ b/application/classes/controller/templatedefault.php @@ -0,0 +1,56 @@ +auth_required is TRUE, then the user must be logged in only. + * if $this->auth_required is FALSE, AND $this->secure_actions has an array of + * methods set to TRUE, then the user must be logged in AND a member of the + * role. + * + * @return boolean + */ + protected function _auth_required() { + // If our global configurable is disabled, then continue + if (! Kohana::Config('config.method_security')) + return FALSE; + + return (($this->auth_required !== FALSE && Auth::instance()->logged_in(NULL,get_class($this).'|'.__METHOD__) === FALSE) || + (is_array($this->secure_actions) && array_key_exists($this->request->action,$this->secure_actions) && + Auth::instance()->logged_in($this->secure_actions[$this->request->action],get_class($this).'|'.__METHOD__) === FALSE)); + } + + protected function _left() { + if ($this->template->left) + return $this->template->left; + + elseif (Auth::instance()->logged_in(NULL,get_class($this).'|'.__METHOD__)) + return Controller_Tree::js(); + } + + protected function _right() { + if ($this->template->right) + return $this->template->right; + else + return $this->_cart(); + } + + private function _cart() { + if (! Cart::instance()->contents()->reset(FALSE)->count_all()) + return ''; + + return Cart::instance()->cart_block(); + } +} +?> diff --git a/application/classes/controller/tree.php b/application/classes/controller/tree.php new file mode 100644 index 00000000..d21effe9 --- /dev/null +++ b/application/classes/controller/tree.php @@ -0,0 +1,90 @@ +_auth_required()) { + $this->treedata = array('attr'=>array('id'=>'a_login'), + 'data'=>array('title'=>_('Please Login').'...','attr'=>array('id'=>'N_login','href'=>URL::site('login')))); + + return; + } + + // Get the user details + $id = (is_null($id) && isset($_REQUEST['id'])) ? substr($_REQUEST['id'],2) : $id; + $user = Auth::instance()->get_user(); + + if (! $id) { + $modules = array(); + foreach ($user->groups() as $go) + $modules = array_merge($modules,Module_Method::groupmodules($go->id)); + + ksort($modules); + + $data = array(); + foreach ($modules as $module => $details) + if (! $details['parent_id']) + array_push($data, + array('id'=>$details['id'],'name'=>$module,'state'=>'closed') + ); + + } else { + $module = preg_replace('/^N_/','',$id); + $methods = array(); + foreach ($user->groups() as $go) + $methods = array_merge($methods,Module_Method::groupmethods($go->id,$module)); + + ksort($methods); + + $data = array(); + foreach ($methods as $method => $details) { + if (preg_match('/_/',$method)) { + list($mode,$action) = explode('_',$method); + $url = URL::site(sprintf('/%s/%s/%s',$mode,$details['module'],$action)); + } else { + $url = URL::site(sprintf('/%s/%s',$details['module'],$method)); + } + + array_push($data,array( + 'id'=>sprintf('%s_%s',$module,$details['id']), + 'name'=>$method, + 'state'=>'none', + 'attr_id'=>sprintf('%s_%s',$module,$details['id']), + 'attr_href'=>(empty($details['page']) ? $url : $details['page']) + )); + } + } + + $this->treedata = array(); + + foreach ($data as $branch) { + array_push($this->treedata,array( + 'attr'=>array('id'=>sprintf('B_%s',$branch['id'])), + 'state'=>$branch['state'], + 'data'=>array('title'=>$branch['name']), + 'attr'=>array('id'=>sprintf('N_%s',$branch['id']),'href'=>empty($branch['attr_href']) ? URL::site(sprintf('/%s/menu',$branch['name'])) : $branch['attr_href']), + ) + ); + } + } +} +?> diff --git a/application/classes/controller/welcome.php b/application/classes/controller/welcome.php index e3b27d60..20d37caf 100644 --- a/application/classes/controller/welcome.php +++ b/application/classes/controller/welcome.php @@ -1,10 +1,39 @@ -add(array( + 'title'=>'Welcome to lnApp (public)!', + 'subtitle'=>'Using lnApp', + 'body'=>'Sample lnApp application', + 'footer'=>'lnApp makes building websites easy! '.time(), + )); - public function action_index() - { - $this->request->response = 'hello, world!'; + if (Auth::instance()->logged_in()) { + $this->template->control = HTML::anchor('/logout',_('Logout'),array('id'=>'ajxbody')); + } else { + $this->template->control = HTML::anchor('/login',_('Login'),array('id'=>'ajxbody')); + + Script::add(array('type'=>'stdin','data'=>' + $(document).ready(function() { + $("#ajxbody").click(function() {$("#ajBODY").load("'.URL::site('/login').'",null,function(x,s,r) {}); return false;}); + $("#ajBODY").ajaxSend(function() {$(this).html(\''.sprintf('%s %s<\/span>...',HTML::image('media/img/ajax-progress.gif',array('alt'=>_('Loading Login').'...')),_('Loading Login')).'\');return true;}); + });' + )); + } + + $this->template->content = $block; } - -} // End Welcome +} +?> diff --git a/application/classes/database/mysql.php b/application/classes/database/mysql.php new file mode 100644 index 00000000..4cf17ba6 --- /dev/null +++ b/application/classes/database/mysql.php @@ -0,0 +1,20 @@ + diff --git a/application/classes/headimages.php b/application/classes/headimages.php new file mode 100644 index 00000000..74d735ed --- /dev/null +++ b/application/classes/headimages.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/htmlrender.php b/application/classes/htmlrender.php new file mode 100644 index 00000000..e887d1bb --- /dev/null +++ b/application/classes/htmlrender.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/lnapp/block.php b/application/classes/lnapp/block.php new file mode 100644 index 00000000..1d738473 --- /dev/null +++ b/application/classes/lnapp/block.php @@ -0,0 +1,81 @@ + '; + protected static $_required_keys = array('body'); + + /** + * Add a block to be rendered + * + * @param array Block attributes + */ + public static function add($block,$prepend=FALSE) { + parent::add($block); + + // Detect any style sheets. + if (! empty($block['style']) && is_array($block['style'])) + foreach ($block['style'] as $data=>$media) + Style::add(array( + 'type'=>'file', + 'data'=>$data, + 'media'=>$media, + )); + } + + /** + * Return an instance of this class + * + * @return Block + */ + public static function factory() { + return new Block; + } + + /** + * Render this block + * + * @see HTMLRender::render() + */ + protected function render() { + $output = ''; + $styles = array(); + + $i = 0; + foreach (static::$_data as $value) { + if ($i++) + $output .= static::$_spacer; + + $output .= ''; + + if (! empty($value['title'])) + $output .= sprintf('',$value['title']); + + if (! empty($value['subtitle'])) + $output .= sprintf('',$value['subtitle']); + + $output .= sprintf('',$value['body']); + + if (! empty($value['footer'])) + $output .= sprintf('',$value['footer']); + + $output .= '
%s
%s
%s
'; + } + + return $output; + } +} +?> diff --git a/application/classes/lnapp/breadcrumb.php b/application/classes/lnapp/breadcrumb.php new file mode 100644 index 00000000..25b32a0b --- /dev/null +++ b/application/classes/lnapp/breadcrumb.php @@ -0,0 +1,64 @@ +uri) : static::$_data['path']; + + foreach ($data as $k => $v) { + $output .= static::$_spacer; + + $p = join('/',array_slice($data,0,$k+1)); + $output .= HTML::anchor($p,empty(static::$_data['name'][$p]) ? ucfirst($v) : static::$_data['name'][$p]); + } + + return $output; + } +} +?> diff --git a/application/classes/lnapp/config.php b/application/classes/lnapp/config.php new file mode 100644 index 00000000..d8ce71e0 --- /dev/null +++ b/application/classes/lnapp/config.php @@ -0,0 +1,129 @@ +get('modules')) + return $cache->get('modules'); + + } else + $cache = ''; + + $modules = array(); + $module_table = 'module'; + + if (class_exists('Model_'.ucfirst($module_table))) { + $mo = ORM::factory($module_table)->where('status','=',1)->find_all()->as_array(); + + foreach ($mo as $o) + $modules[$o->name] = MODPATH.$o->name; + } + + if ($cache) + $cache->set('modules',$modules); + + return $modules; + } + + /** + * Return our site name + */ + public static function site() { + if (! empty($_SERVER['SERVER_NAME'])) + return $_SERVER['SERVER_NAME']; + + if (! $site = CLI::options('site')) + throw new Kohana_Exception(_('Cant figure out the site, use --site= for CLI')); + + return $site['site']; + } + + /** + * Work out our site ID for multiehosting + * @todo Change this to query the DB for site number. + */ + public static function siteid() { + $sites = Kohana::config('config.site'); + + // If we havent been configured for sites + if (is_null($sites) OR ! is_array($sites) OR ! isset($sites[static::site()])) + return 0; + else + return $sites[static::site()]; + } + + /** + * Work out our site mode (dev,test,prod) + * @todo Change this to query the DB for mode. + */ + public static function sitemode() { + $sites = Kohana::config('config.site_mode'); + + // If we havent been configured for sites + if (is_null($sites) OR ! is_array($sites) OR ! isset($sites[static::site()])) + return Kohana::PRODUCTION; + else + return $sites[static::site()]; + } + + public static function sitename() { + return Kohana::config('config.site_name'); + } + + public static function logo() { + $mediapath = Route::get('default/media'); + $logo = $mediapath->uri(array('file'=>'img/logo-small.png'),array('alt'=>static::sitename())); + + return HTML::image($logo,array('class'=>'headlogo','alt'=>_('Logo'))); + } + + /** + * Return our caching mechanism + */ + public static function cachetype() { + return is_null(Kohana::config('config.cache_type')) ? 'file' : Kohana::config('config.cache_type'); + } + + /** + * Show a date using a site configured format + */ + public static function date($date) { + return date(Kohana::config('config.date_format'),$date); + } + + /** + * See if our emails for the template should be sent to configured admin(s) + * + * @param string template - Template to test for + * @return mixed|array - Email to send test emails to + */ + public static function testmail($template) { + $config = Kohana::config('config.email_admin_only'); + + if (is_null($config) OR ! is_array($config) OR empty($config[$template])) + return FALSE; + else + return $config[$template]; + } +} +?> diff --git a/application/classes/lnapp/headimages.php b/application/classes/lnapp/headimages.php new file mode 100644 index 00000000..21f3ac77 --- /dev/null +++ b/application/classes/lnapp/headimages.php @@ -0,0 +1,45 @@ +uri(array('file'=>$value['img'])),array('alt'=>isset($value['attrs']['title']) ? $value['attrs']['title'] : '')); + $output .= HTML::anchor($value['url'],$i,(isset($value['attrs']) && is_array($value['attrs'])) ? $value['attrs'] : null); + $output .= static::$_spacer; + } + + return $output; + } +} +?> diff --git a/application/classes/lnapp/htmlrender.php b/application/classes/lnapp/htmlrender.php new file mode 100644 index 00000000..b1404011 --- /dev/null +++ b/application/classes/lnapp/htmlrender.php @@ -0,0 +1,94 @@ +get_called_class())); + } + + /** + * Add an item to be rendered + * + * @param array Item to be added + */ + public static function add($item,$prepend=FALSE) { + foreach (static::$_required_keys as $key) + if (! isset($item[$key])) + throw new Kohana_Exception('Missing key :key for image',array(':key'=>$key)); + + // Check for unique keys + if (static::$_unique_vals) + foreach (static::$_unique_vals as $v=>$u) + foreach (static::$_data as $d) + if (isset($d[$u]) && $d['data'] == $item['data']) + return; + + if ($prepend) + array_unshift(static::$_data,$item); + else + array_push(static::$_data,$item); + } + + /** + * Set the space used between rendering output + */ + public static function setSpacer($spacer) { + static::$_spacer = $spacer; + } + + /** + * Set the Kohana Media Path, used to determine where to find additional + * HTML content required for rendering. + */ + public static function setMediaPath($path) { + static::$_media_path = $path; + } + + /** + * Factory instance method must be declared by the child class + */ + public static function factory() { + throw new Kohana_Exception(':class is calling :method, when it should have its own method', + array(':class'=>get_called_class(),':method'=>__METHOD__)); + } + + /** + * Return the HTML to render the header images + */ + public function __toString() { + try { + return static::render(); + } + + // Display the exception message + catch (Exception $e) { + Kohana::exception_handler($e); + + return ''; + } + } + + /** + * Rendering must be declared by the child class + */ + protected function render() { + throw new Kohana_Exception(':class is calling :method, when it should have its own method', + array(':class'=>get_called_class(),':method'=>__METHOD__)); + } +} +?> diff --git a/application/classes/lnapp/meta.php b/application/classes/lnapp/meta.php new file mode 100644 index 00000000..4fcce6da --- /dev/null +++ b/application/classes/lnapp/meta.php @@ -0,0 +1,34 @@ +_array_keys) && empty($this->_data[$key])) + return array(); + + if (empty($this->_data[$key])) + return null; + else + return $this->_data[$key]; + } + + public function __set($key,$value) { + if (in_array($key,$this->_array_keys) && ! is_array($value)) + throw new Kohana_Exception('Key :key must be an array',array(':key'=>$key)); + + $this->_data[$key] = $value; + } +} +?> diff --git a/application/classes/lnapp/script.php b/application/classes/lnapp/script.php new file mode 100644 index 00000000..07635121 --- /dev/null +++ b/application/classes/lnapp/script.php @@ -0,0 +1,59 @@ +'type'); + + /** + * Return an instance of this class + * + * @return Script + */ + public static function factory() { + return new Script; + } + + /** + * Render the script tag + * + * @see HTMLRender::render() + */ + protected function render() { + $foutput = $soutput = ''; + $mediapath = Route::get(static::$_media_path); + + $i = $j = 0; + foreach (static::$_data as $value) { + + switch ($value['type']) { + case 'file': + $foutput .= HTML::script($mediapath->uri(array('file'=>$value['data']))); + if ($i++) + $foutput .= static::$_spacer; + break; + case 'stdin': + $soutput .= sprintf("",$value['data']); + if ($j++) + $soutput .= static::$_spacer; + break; + default: + throw new Kohana_Exception('Unknown style type :type',array(':type'=>$value['type'])); + } + } + + return $foutput.static::$_spacer.$soutput; + } +} +?> diff --git a/application/classes/lnapp/style.php b/application/classes/lnapp/style.php new file mode 100644 index 00000000..14815672 --- /dev/null +++ b/application/classes/lnapp/style.php @@ -0,0 +1,54 @@ +uri(array('file'=>$value['data'])), + array('media'=>(! empty($value['media'])) ? $value['media'] : 'screen'),TRUE); + break; + default: + throw new Kohana_Exception('Unknown style type :type',array(':type'=>$value['type'])); + } + } + + return $output; + } +} +?> diff --git a/application/classes/lnapp/systemmessage.php b/application/classes/lnapp/systemmessage.php new file mode 100644 index 00000000..237bf01c --- /dev/null +++ b/application/classes/lnapp/systemmessage.php @@ -0,0 +1,129 @@ + '; + protected static $_required_keys = array('title','body','type'); + + /** + * Add a system message to be rendered + * + * @param array System Message attributes + */ + public static function add($msg,$prepend=FALSE) { + if ($msgs = Session::instance()->get('sessionmsgs')) { + static::$_data = $msgs; + } + + parent::add($msg); + + // Add a gribber popup + Style::add(array( + 'type'=>'file', + 'data'=>'css/jquery.gritter.css', + 'media'=>'screen', + )); + Script::add(array( + 'type'=>'file', + 'data'=>'js/jquery.gritter-1.5.js', + )); + Script::add(array( + 'type'=>'stdin', + 'data'=>sprintf( +'$(document).ready(function() { + $.extend($.gritter.options, { + fade_in_speed: "medium", + fade_out_speed: 2000, + time: "3000", + sticky: false, + }); + $.gritter.add({ + title: "%s", + text: "%s", + image: "%s", +});});',$msg['title'],$msg['body'],URL::site().static::image($msg['type'],true)))); + + // Save our messages in our session, so that we get them for redirects + Session::instance()->set('sessionmsgs',static::$_data); + } + + /** + * Return an instance of this class + * + * @return SystemMessage + */ + public static function factory() { + return new SystemMessage; + } + + /** + * Render an image for the System Message + */ + private static function image($type,$raw=false,$big=false,$alt='') { + $mediapath = Route::get(static::$_media_path); + + switch ($type) { + case 'error': + $file = sprintf('img/dialog-error%s.png',$big ? '-big' : ''); + break; + case 'info': + $file = sprintf('img/dialog-information%s.png',$big ? '-big' : ''); + break; + case 'warning': + $file = sprintf('img/dialog-warning%s.png',$big ? '-big' : ''); + break; + case 'debug': + $file = sprintf('img/dialog-question%s.png',$big ? '-big' : ''); + break; + default: + throw new Kohana_Exception('Unknown system message type :type',array(':type'=>$value['type'])); + } + + if ($raw) + return $mediapath->uri(array('file'=>$file)); + else + return HTML::image($mediapath->uri(array('file'=>$file)),array('alt'=>$alt ? $alt : '','class'=>'sysicon')); + } + + /** + * Render this system message + * + * @see HTMLRender::render() + */ + protected function render() { + $output = ''; + $mediapath = Route::get(static::$_media_path); + + // Reload our message from the session + if ($msgs = Session::instance()->get('sessionmsgs')) { + Session::instance()->delete('sessionmsgs'); + static::$_data = $msgs; + } + + $i = 0; + foreach (static::$_data as $value) { + if ($i++) + $output .= static::$_spacer; + + $output .= ''; + $output .= sprintf('',static::image($value['type'],false,false,isset($value['alt']) ? $value['alt'] : '')); + $output .= sprintf('',$value['title']); + $output .= ''; + $output .= sprintf('',$value['body']); + $output .= '
%s%s
%s
'; + } + + return $output; + } +} +?> diff --git a/application/classes/meta.php b/application/classes/meta.php new file mode 100644 index 00000000..006de23e --- /dev/null +++ b/application/classes/meta.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/model/.htaccess b/application/classes/model/.htaccess new file mode 100644 index 00000000..281d5c33 --- /dev/null +++ b/application/classes/model/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/application/classes/model/module.php b/application/classes/model/module.php new file mode 100644 index 00000000..0d72a32e --- /dev/null +++ b/application/classes/model/module.php @@ -0,0 +1,34 @@ +array(), + ); + protected $_has_one = array( + 'record_id'=>array() + ); + + protected $_sorting = array( + 'status'=>'DESC', + 'name'=>'ASC', + ); + + protected $_formats = array( + 'status'=>array('StaticList_YesNo::display'=>array()), + ); +} +?> diff --git a/application/classes/ormosb.php b/application/classes/ormosb.php new file mode 100644 index 00000000..b8a3b7e6 --- /dev/null +++ b/application/classes/ormosb.php @@ -0,0 +1,153 @@ +'date_orig','format'=>TRUE); + protected $_updated_column = array('column'=>'date_last','format'=>TRUE); + + protected $_callbacks = array( + 'id'=>array('get_next_id'), + 'site_id'=>array('set_site_id'), + ); + + /** + * Format fields for display purposes + * + * @param string column name + * @return mixed + */ + protected function _format() { + $format = Validate::factory($this->_object); + + foreach ($this->_formats as $column => $formats) + $format->filters($column,$formats); + + if ($format->check()) + foreach ($format as $column => $value) + $this->_object_formated[$column] = $value; + + $this->_formated = TRUE; + } + + /** + * Return a formated columns, as per the model definition + */ + public function display($column) { + // Trigger a load of the record. + $value = $this->__get($column); + + // If some of our fields need to be formated for display purposes. + if ($this->_loaded AND ! $this->_formated AND $this->_formats) + $this->_format(); + + if (isset($this->_object_formated[$column])) + return $this->_object_formated[$column]; + else + return $value; + } + + /** + * Our child models should provide an invoice display, this is shown + * on printed invoices. + */ + public function invoice_display() { + throw new Kohana_Exception(':module has not configured an :method, but has made the call',array(':module'=>get_class($this),'method'=>__METHOD__)); + } + + /** + * Override the _load_result() function so that our site ID is automatically + * added to the SQL query + * @todo This is not picked up by all queries. Need to investigate why + * @todo This is not being done by inserts + */ + protected function _load_result($multiple = FALSE) + { + $this->_db_builder->where($this->_table_name.'.site_id','=',Config::siteid()); + + return parent::_load_result($multiple); + } + + /** + * This function will enhance the [Validate::filter], since it always passes + * the value as the first argument and sometimes functions need that to not + * be the first argument. + * + * Currently this implements: + * [date()][date-ref] + * + * [date-ref]: http://www.php.net/date + * + * This function will throw an exception if called without a function + * defined. + * + * @param mixed $val Value to be processed + * @param string $func Name of function to call + * @param string $arg Other arguments for the function + */ + final public static function _filters($val,$func,$arg) { + switch ($func) { + case 'date': + return date($arg,$val); + default: + throw new Exception(sprintf(_('Unknown function: %s (%s,%s)'),$func,$arg,$val)); + } + } + + /** + * Get Next record id + * + * @param array Validate object + * @param string Primary Key + */ + public function get_next_id(Validate $array,$field) { + if (! is_null($array[$field])) + return TRUE; + + $this->_changed[$field] = $field; + + $ido = ORM::factory('module') + ->where('name','=',$this->_table_name) + ->find(); + + if (! $ido->loaded()) + throw new Kohana_Exception('Problem getting record_id for :table',array(':table'=>$this->_table_name)); + + $array[$field] = $ido->record_id->next_id($ido->id); + + return TRUE; + } + + public function set_site_id(Validate $array,$field) { + if (! is_null($array[$field])) + return TRUE; + + // @todo This should be a config item + $this->_changed[$field] = $field; + $array[$field] = Config::siteid(); + + return TRUE; + } +} +?> diff --git a/application/classes/period.php b/application/classes/period.php new file mode 100644 index 00000000..c5042bb1 --- /dev/null +++ b/application/classes/period.php @@ -0,0 +1,124 @@ +$start,'date'=>$start,'end'=>$period_end,'prorate'=>1); + + # Monthly + case 1: + $inc_months = 1; + break; + + # Quarterly + case 2: + # @todo Make this configurable. + $strict = TRUE; + $inc_months = 3; + break; + + # Half Yearly + case 3: + # @todo Make this configurable. + $strict = TRUE; + $inc_months = 6; + break; + + # Yearly + case 4: + $inc_months = 12; + break; + + # Biennial + case 5: + $inc_months = 24; + break; + + # Triennial + case 6: + $inc_months = 36; + break; + + default: + return FALSE; + } + + // If workout a day of week we calculate to. + if (is_null($weekday)) + $weekday = date('d',$start); + + $used_months = 0; + if ($strict && $type > 0 && $type < 5) + $used_months = $inc_months-(($inc_months-(date('n',$start)%$inc_months))%$inc_months+1); + + $d = mktime(0,0,0,date('m',$start)-$used_months,$weekday,date('y',$start)); + if ($d <= $start) + $period_start = $d; + else + $period_start = mktime(0,0,0,date('m',$d)-1-$used_months,$weekday,date('y',$d)); + + $period_end = mktime(0,0,0,date('m',$period_start)+$inc_months,$weekday,date('y',$period_start)); + + $total_time = $period_end-$period_start; + $remain_time = $period_end-$start; + $used_time = $start-$period_start; + + // Change our end date to the day before + $period_end -= 86400; + + $return = array( + 'start'=>$period_start, + 'date'=>$start, + 'end'=>$period_end, + 'weekday'=>$weekday, + 'prorata'=>round($remain_time/$total_time,$precision), + 'total_time'=>sprintf('%3.1f',$total_time/86400), + 'remain_time'=>sprintf('%3.1f',$remain_time/86400), + 'used_time'=>sprintf('%3.1f',$used_time/86400)); + + // @todo Use the configured data format + if ($df) + foreach (array('start','date','end') as $key) + $return[$key] = date('Y-m-d',$return[$key]); + + return $return; + } +} +?> diff --git a/application/classes/script.php b/application/classes/script.php new file mode 100644 index 00000000..1e03000f --- /dev/null +++ b/application/classes/script.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/staticlist.php b/application/classes/staticlist.php new file mode 100644 index 00000000..e2e16679 --- /dev/null +++ b/application/classes/staticlist.php @@ -0,0 +1,63 @@ +get_called_class(),':method'=>__METHOD__)); + } + + /** + * Display a static name for a value + * + * @param key $id value to render + * @see _display() + */ + public static function display($value) { + return static::_display($value); + } + + // Due to static scope, sometimes we need to call this function from the child class. + protected static function _display($id) { + $table = static::factory()->table(); + + if (! $table OR empty($table[$id])) + return sprintf('No Value (%s)',$id); + else + return $table[$id]; + } + + /** + * Renders form input + * + * @param string Form name to render + * @param string Default value to populate in the Form input. + */ + public static function form($name,$default='',$addblank=FALSE) { + $table = static::factory()->table(); + + if ($addblank) + $table = array_merge(array(''=>' '),$table); + + return Form::Select($name,$table,$default); + } +} +?> diff --git a/application/classes/staticlist/module.php b/application/classes/staticlist/module.php new file mode 100644 index 00000000..c6541ef6 --- /dev/null +++ b/application/classes/staticlist/module.php @@ -0,0 +1,23 @@ + diff --git a/application/classes/staticlist/pricetype.php b/application/classes/staticlist/pricetype.php new file mode 100644 index 00000000..db981351 --- /dev/null +++ b/application/classes/staticlist/pricetype.php @@ -0,0 +1,30 @@ +_('One-time Charge'), + 1=>_('Recurring Membership/Subscription'), + 2=>_('Trial for Membership/Subscription') + ); + } + + public static function factory() { + return new StaticList_PriceType; + } + + public static function display($value) { + return static::_display($value); + } +} +?> diff --git a/application/classes/staticlist/recurschedule.php b/application/classes/staticlist/recurschedule.php new file mode 100644 index 00000000..079bc091 --- /dev/null +++ b/application/classes/staticlist/recurschedule.php @@ -0,0 +1,56 @@ +_('Weekly'), + 1=>_('Monthly'), + 2=>_('Quarterly'), + 3=>_('Semi-Annually'), + 4=>_('Annually'), + 5=>_('Two years'), + 6=>_('Three Years') + ); + } + + public static function factory() { + return new StaticList_RecurSchedule; + } + + public static function display($value) { + return static::_display($value); + } + + /** + * Renders the price display for a product + * + * @uses product + */ + public static function form($name,$product='',$addblank=FALSE) { + if (empty($product)) + throw new Kohana_Exception('Product is a required field for :method',array(':method'=>__METHOD__)); + + $x = ''; + $table = static::factory()->table(); + + foreach ($product->get_price_array() as $term => $price) { + $x[$term] = sprintf('%s %s',Currency::display($price['price_base']),$table[$term]); + + if ($price['price_setup'] > 0) + $x[$term] .= sprintf(' + %s %s',Currency::display($price['price_setup']),_('Setup')); + } + + return Form::select($name,$x,$product->price_recurr_default); + } +} +?> diff --git a/application/classes/staticlist/title.php b/application/classes/staticlist/title.php new file mode 100644 index 00000000..38786475 --- /dev/null +++ b/application/classes/staticlist/title.php @@ -0,0 +1,29 @@ +_('Mr'), + 'ms'=>_('Ms'), + 'mrs'=>_('Mrs'), + 'miss'=>_('Miss'), + 'dr'=>_('Dr'), + 'prof'=>_('Prof') + ); + } + + public static function factory() { + return new StaticList_Title; + } +} +?> diff --git a/application/classes/staticlist/yesno.php b/application/classes/staticlist/yesno.php new file mode 100644 index 00000000..9422a58b --- /dev/null +++ b/application/classes/staticlist/yesno.php @@ -0,0 +1,29 @@ +_('No'), + 1=>_('Yes'), + ); + } + + public static function factory() { + return new StaticList_YesNo; + } + + public static function display($value) { + return static::_display($value); + } +} +?> diff --git a/application/classes/staticlistmodule.php b/application/classes/staticlistmodule.php new file mode 100644 index 00000000..d2765ae6 --- /dev/null +++ b/application/classes/staticlistmodule.php @@ -0,0 +1,83 @@ +from($table)->where($skey,'=',$value)->execute(); + + if ($db->count() !== 1) + return sprintf('No Value (%s)',$value); + else + return $db->get($key); + } + + /** + * This function is to return the cached value of the current active record + * This is so that a follow up call to get an attribute of a value retrieved + * can reuse the active record values. + * This gets over a limitation where the query to form() to get a default + * no longer exists (or is invalid) and you want other attributes of the + * remaining active record, which may not be the default record. + */ + public static function record($table,$attribute,$skey,$value) { + if (empty(static::$record[$table])) + return static::display($table,$attribute,$skey,$value); + else + return static::$record[$table][$attribute]; + } + + /** + * Renders form input + */ + public static function form($name,$default='',$addblank=FALSE) { + // Override our argument list as defined in parent + list($name,$table,$default,$key,$value,$where) = func_get_args(); + + // @todo - our query type should come from our configuration? + $db = DB::select()->from($table); + + foreach ($where as $k=>$v) { + list ($op,$v) = explode(':',$v); + $db->where($k,$op,$v); + } + + $db = $db->execute(); + + // If we only have one record, dont make a select list + if ($db->count() == 1) { + static::$record[$table] = $db->as_array(); + static::$record[$table] = array_shift(static::$record[$table]); + + return Form::hidden($name,$db->get($key)).$db->get($value); + } + + // Else we return a select list + $x = array(); + foreach ($db as $record) { + $x[$record[$key]] = $record[$value]; + + // Save our static record, in case we reference this item again. + if ($record[$key] == $default) + static::$record[$table] = $record; + } + + return Form::select($name,$x,$default); + } +} +?> diff --git a/application/classes/style.php b/application/classes/style.php new file mode 100644 index 00000000..18e54da5 --- /dev/null +++ b/application/classes/style.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/systemmessage.php b/application/classes/systemmessage.php new file mode 100644 index 00000000..6753b7c4 --- /dev/null +++ b/application/classes/systemmessage.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/validate.php b/application/classes/validate.php new file mode 100644 index 00000000..2fdf9286 --- /dev/null +++ b/application/classes/validate.php @@ -0,0 +1,29 @@ +_empty_rules + * + * @param string field value + * @param string field name to match + * @return boolean + */ + protected function matches_ifset($value, $match) + { + return ($value === $this[$match]); + } +} +?> diff --git a/application/config/.htaccess b/application/config/.htaccess new file mode 100644 index 00000000..281d5c33 --- /dev/null +++ b/application/config/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/application/config/auth.php b/application/config/auth.php new file mode 100644 index 00000000..1155c350 --- /dev/null +++ b/application/config/auth.php @@ -0,0 +1,19 @@ + 'OSB', + 'hash_method' => 'md5', + 'salt_pattern' => null, + 'lifetime' => 1209600, + 'session_key' => 'auth_user', +); +?> diff --git a/application/config/cache.php b/application/config/cache.php new file mode 100644 index 00000000..9a083da9 --- /dev/null +++ b/application/config/cache.php @@ -0,0 +1,10 @@ + array + ( + 'driver' => 'file', + 'cache_dir' => '/dev/shm/osb', + 'default_expire' => 3600, + ) +); diff --git a/application/config/config.php b/application/config/config.php new file mode 100644 index 00000000..5fe42c77 --- /dev/null +++ b/application/config/config.php @@ -0,0 +1,37 @@ + 'file', + 'date_format' => 'd-M-Y', + 'email_admin_only'=> array( + 'adsl_traffic_notice'=>array('deon@c5t61p.leenooks.vpn'=>'Deon George'), + ), + 'method_directory'=> array( // Out method paths for the different functions + 'admin', + 'affiliate', + 'reseller', + 'task', + 'user', + ), + 'method_security' => TRUE, // Enables Method Security. Setting to false means any method can be run without authentication + 'site' => array( + '172.31.9.4'=>1, + 'www.graytech.net.au'=>1, + ), + 'site_debug' => FALSE, + 'site_mode' => array( + '172.31.10.200'=>Kohana::DEVELOPMENT, + 'www.graytech.net.au'=>Kohana::PRODUCTION, + ), + 'site_name' => 'Graytech Hosting Pty Ltd', // @todo This should come from the DB +); +?> diff --git a/application/config/database.php b/application/config/database.php new file mode 100644 index 00000000..8e74ebe7 --- /dev/null +++ b/application/config/database.php @@ -0,0 +1,30 @@ + array + ( + 'type' => 'mysql', + 'connection' => array( + 'hostname' => 'mysql.leenooks.vpn', + 'username' => 'gh-webbill', + 'password' => 'ws0593', + 'persistent' => FALSE, + 'database' => 'webghosb', + ), + 'table_prefix' => 'ab_', + 'charset' => 'utf8', + 'caching' => FALSE, + 'profiling' => TRUE, + ), +); +?> diff --git a/application/i18n/.htaccess b/application/i18n/.htaccess new file mode 100644 index 00000000..281d5c33 --- /dev/null +++ b/application/i18n/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/application/media/1/img/logo-small.png b/application/media/1/img/logo-small.png new file mode 100644 index 0000000000000000000000000000000000000000..2fc13978cef1e3304a5c891cfa040a571cea2ff2 GIT binary patch literal 2225 zcmV;i2u}BjP)Px##!yUDMG06&_xJbj@9+Hl`~V++=jZ3%-rmN>#?8&n*4EYm9B=>^Spp`SBuAe| zZoQhIt_muL!N=04th_c>tg^)4GeU0x5=Cfyx3sy(c8$fr!NZTC+YC0xjg+VbEwW^6 zgu%?=RCmK5Mzxflzbi+PQgh%LJeQKR<8GPUE?C`VbDT|DgQ&sr2op1Sevv&zUM*ex zccb|eC0u5K;4xUo$JFLie)(dN`wTnXEH+Zv;Os|Xpd(A)#@_Mb=k3_r;N|G`0001( zMG;p30004WQchCmc74NO)>PtsWBM7Yl%N zk6)T$=k#>cV=Rc?LEleVk@xT2Lu{#^s~cpzG|n8(`CZ6@j^j8)CC+MGb+c(^fBw`+ z^9ne8ZIG(t{1}}9lF!F1XgLm1O>w--V4>J>)ck3b=4sgjt#0s8fa!UhpEQ7pa05MB zdsh6tR+~Q?=3c0s!dw**eBuMs^DdF;<OT2>GqRkyMxv)L@u&~+^?>QR zE;2+P;^~P2AvU&P?es#fo)^4{)x5%8<+2H!b zv2xrU)a%X3KY1IQ?ReS@Z_dvjK(7IM?Pw3vAYZQQxEvdk_A4XteLqkFnBV|Nd-9V~ zd@`kR-F=B`#4NMUOqr%Mme~h%?8Y0N-0GI%4j~w@O(DA0KMBZ6_AZmCLy~QzLKrD4Kes2Mk>VN{iud_v~ z)qkyHJM!GO`k4^3+Ys8PF#X@IOqrK6O_(niEI8wy=Yq`*Cajgv*I*4hq~}fHKZbkq zo!St!bWw)AizN&{kV#?wfN-czqX9B&QM15Q0z1AlcIsU=i44-E_Vbv%64Sk&2FL`x zq`)jo?Hrf^G9kbXCgj#vWE3hSAZDMK-Zx;nP(b5JJdE7h{XH_DKo7T)1DMW_G4q2C zhSS`NGcehkz|QL;Q<%W+klCG5)zurX_cNI!6elvdQ?@4<=H&oNV&>LrH#ncQO{Q@1 z*Q8;YeV5vXdBd!XCy`~k6zD!CY#vu_bz@7N>_tHJna#|bq>I|IxhCb1D1shRGZiyMe26v_{5tvXL zVH1kVFj3}=!AbK3uEmk5AwR`xj*Z6kHCw`p0iVK?{NyWVLYTf<)K*B`0@&3}+(PCI z7Ln)8nZNM72~K>weICbCe?cp#eHRat&hV`lfD5>4+130qKjO=nV4AfX=Ole(;ugTd z!MF+Q^VVzvOas|7Cjl%Ewy1fuYFV9R2}swQ;v9vIQB?NWX5(zIRnbFqpxwda!dK`_ zb1;Sz^(GJ;c1Q1upe!(+7#CpVvPEt8f%IhQlY(JBj_NBYYc@I%QPd2X>OYR*81c_w zKf77b(Z#*!d<2M;lLuZ4*NPu3T(diIK7<>Zmpv0#bEe-Ip>;Z!UX!sX8p*^kvn;x zl6_B_whTRs+>I){wyoP+{Rg}ZR##A`SnavuCT{x$e(Tlxptt+{F@B?H3Y=XQHg9YV zIPfjd7W;YzfA8m+BJ@+AEdGbjPY0~5-}eRTLt?7ZUj!vmN&cx%J2I2`Po-3ae;%2k zh>Fm9$7eH@CEF@GTg9oetb*EGLW(lW60Wo{!IMg+%+D0=XW+Po8=%XjO0DBsC(x(3$U1>mc%BUuM%z9^s^sA~Nwd z7P=^Sn$g@UlLyK)F|jBlUDgH-jGIbdRRb~Mnwq&t=xP+PG%yxqCKQdbi8p1SEmNB~ z!4jIq)oX@G@=uX>Yi4H4i%L49RiG(hq^PW2g*6P*V7e+;VHl_>G^$>-m*O%>Op%bk z)R3!s(aNqgnbMvBH!^L)vk62+MOLntSF9)TCG;#t}Q0pY^%aP zRM=BC1%gs5 ins { background-position:-72px 0; } +.jstree-default .jstree-closed > ins { background-position:-54px 0; } +.jstree-default .jstree-leaf > ins { background-position:-36px 0; } + +.jstree-default .jstree-hovered { background:#FFF0C0; border:1px solid #841212; padding:0 2px 0 1px; color: #841212;} +.jstree-default .jstree-clicked { background:#FCFCFC; border:1px solid #FCFCFC; padding:0 2px 0 1px; color: #841212;} +.jstree-default a .jstree-icon { background-position:-56px -19px; } +.jstree-default a.jstree-loading .jstree-icon { background:url("../img/jquery.jstree.throbber.gif") center center no-repeat !important; } + +.jstree-default.jstree-focused { background:#FCFCFC; } + +.jstree-default .jstree-no-dots li, +.jstree-default .jstree-no-dots .jstree-leaf > ins { background:transparent; } +.jstree-default .jstree-no-dots .jstree-open > ins { background-position:-18px 0; } +.jstree-default .jstree-no-dots .jstree-closed > ins { background-position:0 0; } + +.jstree-default .jstree-no-icons a .jstree-icon { display:none; } + +.jstree-default .jstree-search { font-style:italic; } + +.jstree-default .jstree-no-icons .checkbox { display:inline-block; } +.jstree-default .jstree-no-checkboxes .checkbox { display:none !important; } +.jstree-default .jstree-checked > a > .checkbox { background-position:-38px -19px; } +.jstree-default .jstree-unchecked > a > .checkbox { background-position:-2px -19px; } +.jstree-default .jstree-undetermined > a > .checkbox { background-position:-20px -19px; } +.jstree-default .jstree-checked > a > .checkbox:hover { background-position:-38px -37px; } +.jstree-default .jstree-unchecked > a > .checkbox:hover { background-position:-2px -37px; } +.jstree-default .jstree-undetermined > a > .checkbox:hover { background-position:-20px -37px; } + +#vakata-dragged.jstree-default ins { background:transparent !important; } +#vakata-dragged.jstree-default .jstree-ok { background:url("../img/jquery.jstree.d.png") -2px -53px no-repeat !important; } +#vakata-dragged.jstree-default .jstree-invalid { background:url("../img/jquery.jstree.d.png") -18px -53px no-repeat !important; } +#jstree-marker.jstree-default { background:url("../img/jquery.jstree.d.png") -41px -57px no-repeat !important; } + +.jstree-default a.jstree-search { color:aqua; } + +#vakata-contextmenu.jstree-default-context, +#vakata-contextmenu.jstree-default-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; } +#vakata-contextmenu.jstree-default-context li { } +#vakata-contextmenu.jstree-default-context a { color:black; } +#vakata-contextmenu.jstree-default-context a:hover, +#vakata-contextmenu.jstree-default-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; } +#vakata-contextmenu.jstree-default-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; } +#vakata-contextmenu.jstree-default-context li ul { margin-left:-4px; } + +/* TODO: IE6 support - the `>` selectors */ diff --git a/application/media/css/list.css b/application/media/css/list.css new file mode 100644 index 00000000..77bba7ee --- /dev/null +++ b/application/media/css/list.css @@ -0,0 +1,33 @@ +/* CSS for Output Lists */ + +table.list { + width: 100%; + border: 0px solid #505050; + font-weight: normal; + color: #000000; + + font-family: "bitstream vera sans","luxi sans",verdana,geneva,arial,helvetica,sans-serif; + background-color: #99999B; + font-size: 13px; + empty-cells: hide; +} + +table.list tr.heading { + color: #FFFFFF; + background-color: #11111A; + font-weight: bold; +} + +table.list tr td.title { + color: #000000; + background-color: #0777DD; + +} + +table.list tr.odd { + background-color: #EEEEEF; +} + +table.list tr.even { + background-color: #FFFFFF; +} diff --git a/application/media/css/login.css b/application/media/css/login.css new file mode 100644 index 00000000..baabd9e2 --- /dev/null +++ b/application/media/css/login.css @@ -0,0 +1,43 @@ +/** Login Style Sheet **/ + +table.login { + margin-left: auto; + margin-right: auto; + background-color: #F9F9FA; + border: 1px solid #AAAACC; + padding: 10px; +} + +#login-uid { + background: url('../img/login.user.png') no-repeat 0 1px; + background-color: #FAFAFF; + color: #000000; + padding-left: 24px; +} + +#login-uid:focus { + background-color: #F0F0FF; + color: #000000; +} + +#login-uid:disabled { + background-color: #DDDDFF; + color: #000000; +} + +#login-pwd { + background: url('../img/dialog-password.png') no-repeat 0 1px; + background-color: #FAFAFF; + color: #000000; + padding-left: 24px; +} + +#login-pwd:focus { + background-color: #F0F0FF; + color: #000000; +} + +#login-pwd:disabled { + background-color: #DDDDFF; + color: #000000; +} diff --git a/application/media/img/ajax-progress.gif b/application/media/img/ajax-progress.gif new file mode 100644 index 0000000000000000000000000000000000000000..994bfab65524de391b10d7e2c9fc1115a154b43a GIT binary patch literal 7685 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 TRS@nf!FPIzm+~vs(zpKy%_B!@ literal 0 HcmV?d00001 diff --git a/application/media/img/dialog-error-big.png b/application/media/img/dialog-error-big.png new file mode 100644 index 0000000000000000000000000000000000000000..49ed530368b4d517321e0d3c1d28b3248129d604 GIT binary patch literal 2383 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 mYou!?%3zeFt4YZUR7b;x1fW{b? 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 literal 0 HcmV?d00001 diff --git a/application/media/img/dialog-question.png b/application/media/img/dialog-question.png new file mode 100644 index 0000000000000000000000000000000000000000..ec0776145dd1f81ce086d6a742b97ff7672253e8 GIT binary patch literal 1086 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 literal 0 HcmV?d00001 diff --git a/application/media/img/forum-big.png b/application/media/img/forum-big.png new file mode 100644 index 0000000000000000000000000000000000000000..bbda895a99d6cb9d1a10e4a698fb8f939ab02871 GIT binary patch literal 1615 zcmV-V2C(^wP)8wQ zK~#9!m6mI4Tt^jvzx(p8?W`ZM<2X%>A4%&+OyZ~&;Hs^Ks6b6xf`Wq5{sDyeL4Op1 z_yMSdN7WS61|lJ70il9gMWD1zDhP$Rv~KH~*p1`HapTx=yz$yzuOGW!@8iDa&b|EL zx>!M|%8{;SG@5h1d*+-uXB2KtlnwLXRuyiRO$}}PTB<5zPnDIG-60*b!gU-~Hw@p` zqWN@Y^_pv2k1xirOaW`R1ZZg6x2JYX-E;Td)7|~hg9oUqsU}uYNoi>*bEzfP3Kq%a z0x!REhSB#g4z6XEA4|_(8wTV@0y;j?^Yv0yKKM&x=qzPT zG+k#UXHs+}uJBMbm8w`7mhG~A$2L0mbQ!}J-n+kOiBm7oB{15U_PX zjm2Vj8<7Za42)1;SIba;A7k&Fpt`Od#0r7$BC_vdxXaYnYWT92=Z_!aiRVu6%NI|R z%bOG|7t6AVltch!FHiwwbwKev*<4w@1(_={HMfMKsA$pKu(KabC77@McJ_np{t;@YydML3k3+lW4j| zHkZej9zhUzfDWiS5cr-OFJxEt=_L_tSJ1Qn5W1$J=_fS15wd|R@Fq&@o|K}b;HkbC@f6O z0AoNN@YVsN>FGRKB++W%|%T6ooeTwh=RtyC(t zzWz7hPhrgRKqfSr4x!@a*M{;DFAfce0MT$<_gIGB+F@hy!gT*1`8P&w9Xc2aXUzZr N002ovPDHLkV1f>g7GVGY literal 0 HcmV?d00001 diff --git a/application/media/img/jquery.gritter.close-ie6.gif b/application/media/img/jquery.gritter.close-ie6.gif new file mode 100644 index 0000000000000000000000000000000000000000..aea6e427ede71a9f7f709aeb7daa48e6fb5f07e0 GIT binary patch literal 718 zcmZ?wbhEHb6k`x$c$UP#%F258?%jtEA8y~i-NM4c)YNp%nl%Rx9<;W$uCK3;i;Fvd z{`~Xj&v|%wTwPs_jErPuWxc$-G&D4(PoG{>Q?p{liYHH=T)upH)~s3P=H@9WDTaoI zot>RNK0a1fRb&dSOvEG*2;&HeM|kAi~2*|TTgy?gib=g&uv9_8ib855-6)ej#& ztX;cy+O%l`0s?k+cG=n485tSJj~{n%aEOYEI(6z)Wo2bpSlIgY>lZIx{Nu-u_V)Iw zswxo?ksCK|?Afzt-MV#$4joEJNSHEZNCMki?(^G9DBs4DA0KlA4-XUF{g-;~8~>S)2Qt zr4^YHrt(BjO<>ZDo6y8!o1iYtm$)pEH7Y*AOKt*-K?1YN@~w$NZVB8R69W^p8MbX> z2v1<=Z;IJ;@X(=<1m7f9COv`W{2W_#B6*itXfVlfC0H&un##G%Tr5F&xm1FqNdn7q zmDLHH)^8GImisBQu{=oBX0p?n%41+0%5+gUQE*yHP=>bWBJM*fH78PBXE3_T=XfRr zWU^RA$1;U5B%i&)KPiEy-n&Lx;gRF-Jl+UR$iBA%yu2tBQB0m*KZV klO;q&G-@>)84n8x&q`bHRhy%cqp_2ThePmiumXcM0E(Ob2mk;8 literal 0 HcmV?d00001 diff --git a/application/media/img/jquery.gritter.png b/application/media/img/jquery.gritter.png new file mode 100644 index 0000000000000000000000000000000000000000..0ca3bc0a0f8068194082db9719d6e20a8645985f GIT binary patch literal 4880 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 Zf3P5-;PGuo@D~?gbJgKWjfL<1{{eTAuA%?{ literal 0 HcmV?d00001 diff --git a/application/media/img/jquery.jstree.d.png b/application/media/img/jquery.jstree.d.png new file mode 100644 index 0000000000000000000000000000000000000000..8540175a04b0cd303e3966d1727f30ee9b8a7254 GIT binary patch literal 7635 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 EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/application/media/img/login.user.png b/application/media/img/login.user.png new file mode 100644 index 0000000000000000000000000000000000000000..7be48fb8cd09d6adfc48954e1907f38d3bb0c3b1 GIT binary patch literal 654 zcmV;90&)F`P)jL%;Pn)6~ zp+z7;99L)q8&6i(@;pDhvS!nc7x4PcUW2hXn?r(7S4e~~4wNS)&tLR1=iDr~xz%s_ zpCYEMNeNI9QX-`U1SCOHp6#ty*-X@(cLimD^%ZdQkQYW-ZbURRu<80K^-R;In0T@uAMdL%H@{m-*2~J%XyJ%VN zE@#($GnW&I^uH7h;s`cp6e}0&OCWbNaqnkKr2DFgq@H3 zGts7?ud1dvE>`|~(zIvbA{ONS6{SQaYpg6)B3o60TPim(N oN=PK6hSf)_xH~Spv5tS$Z>|sW3LxX?DF6Tf07*qoM6N<$f^GL0UH||9 literal 0 HcmV?d00001 diff --git a/application/media/img/logo-small.png b/application/media/img/logo-small.png new file mode 100644 index 0000000000000000000000000000000000000000..726933b130f4c934d8d48f3dab6d7e91ba332731 GIT binary patch literal 3978 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 literal 0 HcmV?d00001 diff --git a/application/media/js/jquery-1.4.2.js b/application/media/js/jquery-1.4.2.js new file mode 100644 index 00000000..7c243080 --- /dev/null +++ b/application/media/js/jquery-1.4.2.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/application/media/js/jquery.cookie.js b/application/media/js/jquery.cookie.js new file mode 100644 index 00000000..6036754e --- /dev/null +++ b/application/media/js/jquery.cookie.js @@ -0,0 +1,96 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain + * used when the cookie was set. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + // CAUTION: Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason... + var path = options.path ? '; path=' + (options.path) : ''; + var domain = options.domain ? '; domain=' + (options.domain) : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; \ No newline at end of file diff --git a/application/media/js/jquery.gritter-1.5.js b/application/media/js/jquery.gritter-1.5.js new file mode 100644 index 00000000..bf3bd473 --- /dev/null +++ b/application/media/js/jquery.gritter-1.5.js @@ -0,0 +1,21 @@ +(function($){$.gritter={};$.gritter.options={fade_in_speed:'medium',fade_out_speed:2000,time:6000} +$.gritter.add=function(params){try{if(!params.title||!params.text){throw'You need to fill out the first 2 params: "title" and "text"';}}catch(e){alert('Gritter Error: '+e);} +return Gritter.add(params);} +$.gritter.remove=function(id,params){Gritter.removeSpecific(id,params||'');} +$.gritter.removeAll=function(params){Gritter.stop(params||'');} +var Gritter={fade_in_speed:'',fade_out_speed:'',time:'',_custom_timer:0,_item_count:0,_is_setup:0,_tpl_close:'
',_tpl_item:'',_tpl_wrap:'
',add:function(params){if(!this._is_setup){this._runSetup();} +var user=params.title,text=params.text,image=params.image||'',sticky=params.sticky||false,time_alive=params.time||'';this._verifyWrapper();this._item_count++;var number=this._item_count,tmp=this._tpl_item;this['_before_open_'+number]=($.isFunction(params.before_open))?params.before_open:function(){};this['_after_open_'+number]=($.isFunction(params.after_open))?params.after_open:function(){};this['_before_close_'+number]=($.isFunction(params.before_close))?params.before_close:function(){};this['_after_close_'+number]=($.isFunction(params.after_close))?params.after_close:function(){};this._custom_timer=0;if(time_alive){this._custom_timer=time_alive;} +var image_str=(image!='')?'':'',class_name=(image!='')?'gritter-with-image':'gritter-without-image';tmp=this._str_replace(['[[username]]','[[text]]','[[image]]','[[number]]','[[class_name]]'],[user,text,image_str,this._item_count,class_name],tmp);this['_before_open_'+number]();$('#gritter-notice-wrapper').append(tmp);var item=$('#gritter-item-'+this._item_count);item.fadeIn(this.fade_in_speed,function(){Gritter['_after_open_'+number]($(this));});if(!sticky){this._setFadeTimer(item,number);} +$(item).bind('mouseenter mouseleave',function(event){if(event.type=='mouseenter'){if(!sticky){Gritter.restoreItemIfFading(this,number);}} +else{if(!sticky){Gritter._setFadeTimer(this,number);}} +Gritter._hoverState(this,event.type);});return number;},_countRemoveWrapper:function(unique_id){this['_after_close_'+unique_id]($('#gritter-item-'+unique_id));if($('.gritter-item-wrapper').length==0){$('#gritter-notice-wrapper').remove();}},_fade:function(e,unique_id){Gritter['_before_close_'+unique_id]($(e));$(e).animate({opacity:0},Gritter.fade_out_speed,function(){$(e).animate({height:0},300,function(){$(e).remove();Gritter._countRemoveWrapper(unique_id);})})},_hoverState:function(e,type){if(type=='mouseenter'){$(e).addClass('hover');if($(e).find('img').length){$(e).find('img').before(this._tpl_close);} +else{$(e).find('span').before(this._tpl_close);} +$(e).find('.gritter-close').click(function(){Gritter._remove(this);});} +else{$(e).removeClass('hover');$(e).find('.gritter-close').remove();}},_remove:function(e){var gritter_wrap=$(e).parents('.gritter-item-wrapper');var unique_id=gritter_wrap.attr('id').split('-')[2];this['_before_close_'+unique_id](gritter_wrap);gritter_wrap.fadeOut('medium',function(){$(this).remove();Gritter._countRemoveWrapper(unique_id);});},removeSpecific:function(unique_id,params){var e=$('#gritter-item-'+unique_id);this['_before_close_'+unique_id](e);if(typeof(params)==='object'){if(params.fade){var speed=this.fade_out_speed;if(params.speed){speed=params.speed;} +e.fadeOut(speed,function(){e.remove();});}} +else{e.remove();} +this._countRemoveWrapper(unique_id);},restoreItemIfFading:function(e,number){window.clearTimeout(Gritter['_int_id_'+number]);$(e).stop().css({opacity:1});},_runSetup:function(){for(opt in $.gritter.options){this[opt]=$.gritter.options[opt];} +this._is_setup=1;},_setFadeTimer:function(item,number){var timer_str=(this._custom_timer)?this._custom_timer:this.time;Gritter['_int_id_'+number]=window.setTimeout(function(){Gritter._fade(item,number);},timer_str);},stop:function(params){var before_close=($.isFunction(params.before_close))?params.before_close:function(){};var after_close=($.isFunction(params.after_close))?params.after_close:function(){};var wrap=$('#gritter-notice-wrapper');before_close(wrap);wrap.fadeOut(function(){$(this).remove();after_close();});},_str_replace:function(search,replace,subject,count){var i=0,j=0,temp='',repl='',sl=0,fl=0,f=[].concat(search),r=[].concat(replace),s=subject,ra=r instanceof Array,sa=s instanceof Array;s=[].concat(s);if(count){this.window[count]=0;} +for(i=0,sl=s.length;if.length+5)return false;if(f[b].selectorText&&f[b].selectorText.toLowerCase()==a)if(d===true){g.removeRule&&g.removeRule(b);g.deleteRule&&g.deleteRule(b);return true}else return f[b]}while(f[++b]);return false},add_css:function(a,d){if(c.jstree.css.get_css(a,false,d))return false;d.insertRule?d.insertRule(a+" { }",0):d.addRule(a,null,0);return c.vakata.css.get_css(a)},remove_css:function(a, +d){return c.vakata.css.get_css(a,true,d)},add_sheet:function(a){var d;if(a.str){d=document.createElement("style");d.setAttribute("type","text/css");if(d.styleSheet){document.getElementsByTagName("head")[0].appendChild(d);d.styleSheet.cssText=a.str}else{d.appendChild(document.createTextNode(a.str));document.getElementsByTagName("head")[0].appendChild(d)}return d.sheet||d.styleSheet}if(a.url)if(document.createStyleSheet)try{document.createStyleSheet(a.url)}catch(g){}else{d=document.createElement("link"); +d.rel="stylesheet";d.type="text/css";d.media="all";d.href=a.url;document.getElementsByTagName("head")[0].appendChild(d);return d.styleSheet}}}})(jQuery); +(function(c){var a=[],d=-1,g={},f={};c.fn.jstree=function(b){var e=typeof b=="string",h=Array.prototype.slice.call(arguments,1),k=this;!e&&c.meta&&h.push(c.metadata.get(this).jstree);b=!e&&h.length?c.extend.apply(null,[true,b].concat(h)):b;if(e&&b.substring(0,1)=="_")return k;e?this.each(function(){var j=a[c.data(this,"jstree-instance-id")];j=j&&c.isFunction(j[b])?j[b].apply(j,h):j;if(typeof j!=="undefined"&&j!==true&&j!==false){k=j;return false}}):this.each(function(){var j=c.data(this,"jstree-instance-id"), +i=false;j&&a[j]&&a[j].destroy();j=parseInt(a.push({}),10)-1;c.data(this,"jstree-instance-id",j);b.plugins=c.isArray(b.plugins)?b.plugins:c.jstree.defaults.plugins;c.inArray("core",b.plugins)===-1&&b.plugins.unshift("core");i=c.extend(true,{},c.jstree.defaults,b);i.plugins=b.plugins;a[j]=new c.jstree._instance(j,c(this).addClass("jstree jstree-"+j),i);c.each(a[j].get_settings().plugins,function(m,l){a[j].data[l]={}});c.each(a[j].get_settings().plugins,function(m,l){g[l]&&g[l].__init.apply(a[j])}); +a[j].init()});return k};c.jstree={defaults:{plugins:[]},_focused:function(){return a[d]||null},_reference:function(b){if(a[b])return a[b];var e=c(b);if(!e.length&&typeof b==="string")e=c("#"+b);if(!e.length)return null;return a[e.closest(".jstree").data("jstree-instance-id")]||null},_instance:function(b,e,h){this.data={core:{}};this.get_settings=function(){return c.extend(true,{},h)};this.get_index=function(){return b};this.get_container=function(){return e};this._set_settings=function(k){h=c.extend(true, +{},h,k)}},_fn:{},plugin:function(b,e){e=c.extend({},{__init:c.noop,__destroy:c.noop,_fn:{},defaults:false},e);g[b]=e;c.jstree.defaults[b]=e.defaults;c.each(e._fn,function(h,k){k.plugin=b;k.old=c.jstree._fn[h];c.jstree._fn[h]=function(){var j,i=k,m=Array.prototype.slice.call(arguments);j=this.get_settings();var l=new c.Event("before.jstree"),o=false;do{if(i&&i.plugin&&c.inArray(i.plugin,j.plugins)!==-1)break;i=i.old}while(i);if(i){j=this.get_container().triggerHandler(l,{func:h,inst:this,args:m}); +if(j!==false){if(typeof j!=="undefined")m=j;return j=i.apply(c.extend({},this,{__callback:function(n){this.get_container().triggerHandler(h+".jstree",{inst:this,args:m,rslt:n,rlbk:o})},__rollback:function(){return o=this.get_rollback()},__call_old:function(n){return i.old.apply(this,n?Array.prototype.slice.call(arguments,1):m)}}),m)}}};c.jstree._fn[h].old=k.old;c.jstree._fn[h].plugin=b})},rollback:function(b){if(b){c.isArray(b)||(b=[b]);c.each(b,function(e,h){a[h.i].set_rollback(h.h,h.d)})}}};c.jstree._fn= +c.jstree._instance.prototype={};c(function(){var b=navigator.userAgent.toLowerCase(),e=(b.match(/.+?(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],h=".jstree ul, .jstree li { display:block; margin:0 0 0 0; padding:0 0 0 0; list-style-type:none; } .jstree li { display:block; min-height:18px; line-height:18px; white-space:nowrap; margin-left:18px; } .jstree > ul > li { margin-left:0px; } .jstree ins { display:inline-block; text-decoration:none; width:18px; height:18px; margin:0 0 0 0; padding:0; } .jstree a { display:inline-block; line-height:16px; height:16px; color:black; white-space:nowrap; text-decoration:none; padding:1px 2px; margin:0; } .jstree a:focus { outline: none; } .jstree a > ins { height:16px; width:16px; } .jstree a > .jstree-icon { margin-right:3px; } li.jstree-open > ul { display:block; } li.jstree-closed > ul { display:none; } "; +if(/msie/.test(b)&&parseInt(e,10)==6)h+=".jstree li { height:18px; margin-left:0; } .jstree li li { margin-left:18px; } li.jstree-open ul { display:block; } li.jstree-closed ul { display:none !important; } .jstree li a { display:inline; } .jstree li a ins { height:16px; width:16px; margin-right:3px; } ";c.vakata.css.add_sheet({str:h})});c.jstree.plugin("core",{__init:function(){this.data.core.to_open=c.map(c.makeArray(this.get_settings().core.initially_open),function(b){return"#"+b.toString().replace(/^#/, +"").replace("\\/","/").replace("/","\\/")})},defaults:{html_titles:false,animation:500,initially_open:[]},_fn:{init:function(){this.set_focus();this.get_container().html("");this.data.core.li_height=this.get_container().find("ul li.jstree-closed, ul li.jstree-leaf").eq(0).height()||18;this.get_container().delegate("li > ins","click.jstree",c.proxy(function(b){var e= +c(b.target);e.is("ins")&&b.pageY-e.offset().top ul > li:first-child");if(!b.length)return false;if(e)return b.nextAll("li").size()>0?b.nextAll("li:eq(0)"):false;return b.hasClass("jstree-open")?b.find("li:eq(0)"):b.nextAll("li").size()> +0?b.nextAll("li:eq(0)"):b.parentsUntil(this.get_container(),"li").next("li").eq(0)},_get_prev:function(b,e){b=this._get_node(b);if(b===-1)return this.get_container().find("> ul > li:last-child");if(!b.length)return false;if(e)return b.prevAll("li").length>0?b.prevAll("li:eq(0)"):false;if(b.prev("li").length){for(b=b.prev("li").eq(0);b.hasClass("jstree-open");)b=b.children("ul:eq(0)").children("li:last");return b}else{var h=b.parentsUntil(this.get_container(),"li:eq(0)");return h.length?h:false}}, +_get_parent:function(b){b=this._get_node(b);if(b==-1||!b.length)return false;b=b.parentsUntil(this.get_container(),"li:eq(0)");return b.length?b:-1},_get_children:function(b){b=this._get_node(b);if(b===-1)return this.get_container().children("ul:eq(0)").children("li");if(!b.length)return false;return b.children("ul:eq(0)").children("li")},get_path:function(b,e){var h=[],k=this;b=this._get_node(b);if(b===-1||!b||!b.length)return false;b.parentsUntil(this.get_container(),"li").each(function(){h.push(e? +this.id:k.get_text(this))});h.reverse();h.push(e?b.attr("id"):this.get_text(b));return h},open_node:function(b,e,h){b=this._get_node(b);if(!b.length)return false;var k=h?0:this.get_settings().core.animation,j=this;if(this._is_loaded(b)){k&&b.children("ul").css("display","none");b.removeClass("jstree-closed").addClass("jstree-open").children("a").removeClass("jstree-loading");k&&b.children("ul").slideDown(k,function(){this.style.display=""});this.__callback({obj:b});e&&e.call()}else{b.children("a").addClass("jstree-loading"); +this.load_node(b,function(){j.open_node(b,e,h)},e)}},close_node:function(b,e){b=this._get_node(b);var h=e?0:this.get_settings().core.animation;if(!b.length)return false;h&&b.children("ul").attr("style","display:block !important");b.removeClass("jstree-open").addClass("jstree-closed");h&&b.children("ul").slideUp(h,function(){this.style.display=""});this.__callback({obj:b})},toggle_node:function(b){b=this._get_node(b);if(b.hasClass("jstree-closed"))return this.open_node(b);if(b.hasClass("jstree-open"))return this.close_node(b)}, +open_all:function(b,e){b=b?this._get_node(b):this.get_container();if(e)b=b.find("li.jstree-closed");else{e=b;b=b.is(".jstree-closed")?b.find("li.jstree-closed").andSelf():b.find("li.jstree-closed")}var h=this;b.each(function(){var k=this;h._is_loaded(this)?h.open_node(this,false,true):h.open_node(this,function(){h.open_all(k,e)},true)});e.find("li.jstree-closed").length===0&&this.__callback({obj:e})},close_all:function(b){var e=this;b=b?this._get_node(b):this.get_container();b.find("li.jstree-open").andSelf().each(function(){e.close_node(this)}); +this.__callback({obj:b})},clean_node:function(b){b=b&&b!=-1?c(b):this.get_container();b=b.is("li")?b.find("li").andSelf():b.find("li");b.removeClass("jstree-last").filter("li:last-child").addClass("jstree-last").end().filter(":has(ul)").not(".jstree-open").removeClass("jstree-leaf").addClass("jstree-closed");b.not(".jstree-open, .jstree-closed").addClass("jstree-leaf");this.__callback({obj:b})},get_rollback:function(){this.__callback();return{i:this.get_index(),h:this.get_container().children("ul").clone(true), +d:this.data}},set_rollback:function(b,e){this.get_container().empty().append(b);this.data=e;this.__callback()},load_node:function(b){this.__callback({obj:b})},_is_loaded:function(){return true},create_node:function(b,e,h,k,j){b=this._get_node(b);e=typeof e==="undefined"?"last":e;var i=c("
  • "),m=this.get_settings().core.html_titles,l;if(b!==-1&&!b.length)return false;if(!j&&!this._is_loaded(b)){this.load_node(b,function(){this.create_node(b,e,h,k,true)});return false}this.__rollback();if(typeof h=== +"string")h={data:h};h||(h={});h.attr&&i.attr(h.attr);h.state&&i.addClass("jstree-"+h.state);if(!h.data)h.data="New node";if(!c.isArray(h.data)){l=h.data;h.data=[];h.data.push(l)}c.each(h.data,function(o,n){l=c("");if(c.isFunction(n))n=n.call(this,h);if(typeof n=="string")l.attr("href","#")[m?"html":"text"](n);else{if(!n.attr)n.attr={};if(!n.attr.href)n.attr.href="#";l.attr(n.attr)[m?"html":"text"](n.title);n.language&&l.addClass(n.language)}l.prepend(" ");if(n.icon)n.icon.indexOf("/")=== +-1?l.children("ins").addClass(n.icon):l.children("ins").css("background","url('"+n.icon+"') center center no-repeat;");i.append(l)});i.prepend(" ");if(b===-1){b=this.get_container();if(e==="before")e="first";if(e==="after")e="last"}switch(e){case "before":b.before(i);l=this._get_parent(b);break;case "after":b.after(i);l=this._get_parent(b);break;case "inside":case "first":b.children("ul").length||b.append("
      ");b.children("ul").prepend(i);l=b;break;case "last":b.children("ul").length|| +b.append("
        ");b.children("ul").append(i);l=b;break;default:b.children("ul").length||b.append("
          ");e||(e=0);l=b.children("ul").children("li").eq(e);l.length?l.before(i):b.children("ul").append(i);l=b;break}if(l===-1||l.get(0)===this.get_container().get(0))l=-1;this.clean_node(l);this.__callback({obj:i,parent:l});k&&k.call(this,i);return i},get_text:function(b){b=this._get_node(b);if(!b.length)return false;var e=this.get_settings().core.html_titles;b=b.children("a:eq(0)");if(e){b=b.clone();b.children("INS").remove(); +return b.html()}else{b=b.contents().filter(function(){return this.nodeType==3})[0];return b.nodeValue}},set_text:function(b,e){b=this._get_node(b);if(!b.length)return false;b=b.children("a:eq(0)");if(this.get_settings().core.html_titles){var h=b.children("INS").clone();b.html(e).prepend(h);this.__callback({obj:b,name:e});return true}else{b=b.contents().filter(function(){return this.nodeType==3})[0];this.__callback({obj:b,name:e});return b.nodeValue=e}},rename_node:function(b,e){b=this._get_node(b); +this.__rollback();b&&b.length&&this.set_text.apply(this,Array.prototype.slice.call(arguments))&&this.__callback({obj:b,name:e})},delete_node:function(b){b=this._get_node(b);if(!b.length)return false;this.__rollback();var e=this._get_parent(b);this.deselect_node(b);b=b.remove();e!==-1&&e.find("> ul > li").length===0&&e.removeClass("jstree-open, jstree-closed").addClass("jstree-leaf");this.clean_node(e);this.__callback({obj:b});return b},prepare_move:function(b,e,h,k,j){var i={};i.ot=c.jstree._reference(i.o)|| +this;i.o=i.ot._get_node(b);i.r=e===-1?-1:this._get_node(e);i.p=typeof i==="undefined"?"last":h;if(!(!j&&f.o&&f.o[0]===i.o[0]&&f.r[0]===i.r[0]&&f.p===i.p)){i.ot=c.jstree._reference(i.o)||this;i.rt=e===-1?i.ot:c.jstree._reference(i.r)||this;if(i.r===-1){i.cr=-1;switch(i.p){case "first":case "before":case "inside":i.cp=0;break;case "after":case "last":i.cp=i.rt.get_container().find(" > ul > li").length;break;default:i.cp=i.p;break}}else{if(!/^(before|after)$/.test(i.p)&&!this._is_loaded(i.r))return this.load_node(i.r, +function(){this.prepare_move(b,e,i,k,true)});switch(i.p){case "before":i.cp=i.r.index();i.cr=i.rt._get_parent(i.r);break;case "after":i.cp=i.r.index()+1;i.cr=i.rt._get_parent(i.r);break;case "inside":case "first":i.cp=0;i.cr=i.r;break;case "last":i.cp=i.r.find(" > ul > li").length;i.cr=i.r;break;default:i.cp=i.p;i.cr=i.r;break}}i.np=i.cr==-1?i.rt.get_container():i.cr;i.op=i.ot._get_parent(i.o);i.or=i.np.find(" > ul > li:nth-child("+(i.cp+1)+")");f=i}this.__callback(f);k&&k.call(this,f)},check_move:function(){var b= +f;if(b.or[0]===b.o[0]||b.r.parentsUntil(".jstree").andSelf().filter("li").index(b.o)!==-1)return false;return true},move_node:function(b,e,h,k,j,i){if(!j)return this.prepare_move(b,e,h,function(l){this.move_node(l,false,false,k,true,i)});if(!i&&!this.check_move())return false;this.__rollback();e=false;if(k){e=b.o.clone();e.find("*[id]").andSelf().each(function(){if(this.id)this.id="copy_"+this.id})}else e=b.o;if(b.or.length)b.or.before(e);else{b.np.children("ul").length||c("
            ").appendTo(b.np); +b.np.children("ul:eq(0)").append(e)}try{b.ot.clean_node(b.op);b.rt.clean_node(b.np);b.op.find("> ul > li").length||b.op.removeClass("jstree-open jstree-closed").addClass("jstree-leaf").children("ul").remove()}catch(m){}if(k){f.cy=true;f.oc=e}this.__callback(f);return f},_get_move:function(){return f}}})})(jQuery); +(function(c){c.jstree.plugin("ui",{__init:function(){this.data.ui.selected=c();this.data.ui.last_selected=false;this.data.ui.hovered=null;this.data.ui.to_select=this.get_settings().ui.initially_select;this.get_container().delegate("a","click.jstree",c.proxy(function(a){a.preventDefault();this.select_node(a.currentTarget,true,a)},this)).delegate("a","mouseenter.jstree",c.proxy(function(a){this.hover_node(a.target)},this)).delegate("a","mouseleave.jstree",c.proxy(function(a){this.dehover_node(a.target)}, +this)).bind("reopen.jstree",c.proxy(function(){this.reselect()},this)).bind("get_rollback.jstree",c.proxy(function(){this.dehover_node();this.save_selected()},this)).bind("set_rollback.jstree",c.proxy(function(){this.reselect()},this)).bind("close_node.jstree",c.proxy(function(a,d){var g=this.get_settings().ui,f=this._get_node(d.args[0]),b=f&&f.length?f.find(".jstree-clicked"):[],e=this;g.selected_parent_close===false||!b.length||b.each(function(){e.deselect_node(this);g.selected_parent_close==="select_parent"&& +e.select_node(f)})},this)).bind("delete_node.jstree",c.proxy(function(a,d){var g=this._get_node(d.rslt.obj),f=this;(g&&g.length?g.find(".jstree-clicked"):[]).each(function(){f.deselect_node(this)})},this)).bind("move_node.jstree",c.proxy(function(a,d){d.rslt.cy&&d.rslt.oc.find(".jstree-clicked").removeClass("jstree-clicked")},this))},defaults:{select_limit:-1,select_multiple_modifier:"ctrl",selected_parent_close:"select_parent",initially_select:[]},_fn:{_get_node:function(a,d){if(typeof a==="undefined"|| +a===null)return d?this.data.ui.selected:this.data.ui.last_selected;return this.__call_old()},save_selected:function(){var a=this;this.data.ui.to_select=[];this.data.ui.selected.each(function(){a.data.ui.to_select.push("#"+this.id.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/"))});this.__callback(this.data.ui.to_select)},reselect:function(){var a=this,d=this.data.ui.to_select;d=c.map(c.makeArray(d),function(g){return"#"+g.toString().replace(/^#/,"").replace("\\/","/").replace("/", +"\\/")});this.deselect_all();c.each(d,function(g,f){f&&f!=="#"&&a.select_node(f)});this.__callback()},refresh:function(){this.save_selected();return this.__call_old()},hover_node:function(a){a=this._get_node(a);if(!a.length)return false;a.hasClass("jstree-hovered")||this.dehover_node();this.data.ui.hovered=a.children("a").addClass("jstree-hovered").parent();this.__callback({obj:a})},dehover_node:function(){var a=this.data.ui.hovered;if(!a||!a.length)return false;if(this.data.ui.hovered[0]===a.children("a").removeClass("jstree-hovered").parent()[0])this.data.ui.hovered= +null;this.__callback({obj:a})},select_node:function(a,d,g){a=this._get_node(a);if(!a.length)return false;var f=this.get_settings().ui;g=f.select_multiple_modifier=="on"||f.select_multiple_modifier!==false&&g&&g[f.select_multiple_modifier+"Key"];var b=this.is_selected(a),e=true;if(d){e=false;switch(true){case b&&!g:break;case !b&&!g:if(f.select_limit==-1||f.select_limit>0){this.deselect_all();e=true}break;case b&&g:this.deselect_node(a);break;case !b&&g:if(f.select_limit==-1||this.data.ui.selected.length+ +1<=f.select_limit)e=true;break}}if(e&&!b){a.children("a").addClass("jstree-clicked");this.data.ui.selected=this.data.ui.selected.add(a);this.data.ui.last_selected=a;this.__callback({obj:a})}},deselect_node:function(a){a=this._get_node(a);if(!a.length)return false;if(this.is_selected(a)){a.children("a").removeClass("jstree-clicked");this.data.ui.selected=this.data.ui.selected.not(a);if(this.data.ui.last_selected.get(0)===a.get(0))this.data.ui.last_selected=this.data.ui.selected.eq(0);this.__callback({obj:a})}}, +toggle_select:function(a){a=this._get_node(a);if(!a.length)return false;this.is_selected(a)?this.deselect_node(a):this.select_node(a)},is_selected:function(a){return this.data.ui.selected.index(this._get_node(a))>=0},get_selected:function(a){return a?c(a).find(".jstree-clicked").parent():this.data.ui.selected},deselect_all:function(a){a?c(a).find(".jstree-clicked").removeClass("jstree-clicked"):this.get_container().find(".jstree-clicked").removeClass("jstree-clicked");this.data.ui.selected=c([]); +this.data.ui.last_selected=false;this.__callback()}}});c.jstree.defaults.plugins.push("ui")})(jQuery); +(function(c){c.jstree.plugin("crrm",{__init:function(){this.get_container().bind("move_node.jstree",c.proxy(function(a,d){if(this.get_settings().crrm.move.open_onmove){var g=this;d.rslt.np.parentsUntil(".jstree").andSelf().filter(".jstree-closed").each(function(){g.open_node(this,false,true)})}},this))},defaults:{input_width_limit:200,move:{always_copy:false,open_onmove:true,default_position:"last",check_move:function(){return true}}},_fn:{_show_input:function(a,d){a=this._get_node(a);var g=this.get_settings().crrm.input_width_limit, +f=a.children("ins").width(),b=a.find("> a:visible > ins").width()*a.find("> a:visible > ins").length,e=this.get_text(a),h=c("
            ",{css:{position:"absolute",top:"-200px",left:"-1000px",visibility:"hidden"}}).appendTo("body"),k=a.css("position","relative").append(c("",{value:e,css:{padding:"0",border:"1px solid silver",position:"absolute",left:f+b+4+"px",top:"0px",height:this.data.core.li_height-2+"px",lineHeight:this.data.core.li_height-2+"px",width:"150px"},blur:c.proxy(function(){var j= +a.children("input"),i=j.val();if(i==="")i=e;this.rename_node(a,i);d.call(this,a,i,e);j.remove();a.css("position","")},this),keyup:function(j){j=j.keyCode||j.which;if(j==27){this.value=e;this.blur()}else j==13?this.blur():k.width(Math.min(h.text("pW"+this.value).width(),g))}})).children("input");this.set_text(a,"");h.css({fontFamily:k.css("fontFamily")||"",fontSize:k.css("fontSize")||"",fontWeight:k.css("fontWeight")||"",fontStyle:k.css("fontStyle")||"",fontStretch:k.css("fontStretch")||"",fontVariant:k.css("fontVariant")|| +"",letterSpacing:k.css("letterSpacing")||"",wordSpacing:k.css("wordSpacing")||""});k.width(Math.min(h.text("pW"+k[0].value).width(),g))[0].select()},rename:function(a){a=this._get_node(a);this.__rollback();var d=this.__callback;this._show_input(a,function(g,f,b){d.call(this,{obj:g,new_name:f,old_name:b})})},create:function(a,d,g,f,b){var e=this;(a=this._get_node(a))||(a=-1);this.__rollback();return this.create_node(a,d,g,function(h){var k=this._get_parent(h),j=c(h).index();f&&f.call(this,h);k.length&& +k.hasClass("jstree-closed")&&this.open_node(k,false,true);b?e.__callback({obj:h,name:this.get_text(h),parent:k,position:j}):this._show_input(h,function(i,m){e.__callback({obj:i,name:m,parent:k,position:j})})})},remove:function(a){a=this._get_node(a,true);this.__rollback();this.delete_node(a);this.__callback({obj:a})},check_move:function(){if(!this.__call_old())return false;if(!this.get_settings().crrm.move.check_move.call(this,this._get_move()))return false;return true},move_node:function(a,d,g,f, +b,e){var h=this.get_settings().crrm.move;if(!b){if(!g)g=h.default_position;return this.__call_old(true,a,d,g,f,false,e)}if(h.always_copy===true||h.always_copy==="multitree"&&a.rt.get_index()===a.ot.get_index())f=true;this.__call_old(true,a,d,g,f,true,e)},cut:function(a){a=this._get_node(a);this.data.crrm.cp_nodes=false;this.data.crrm.ct_nodes=false;if(!a||!a.length)return false;this.data.crrm.ct_nodes=a},copy:function(a){a=this._get_node(a);this.data.crrm.cp_nodes=false;this.data.crrm.ct_nodes=false; +if(!a||!a.length)return false;this.data.crrm.cp_nodes=a},paste:function(a){a=this._get_node(a);if(!a||!a.length)return false;if(!this.data.crrm.ct_nodes&&!this.data.crrm.cp_nodes)return false;this.data.crrm.ct_nodes&&this.move_node(this.data.crrm.ct_nodes,a);this.data.crrm.cp_nodes&&this.move_node(this.data.crrm.cp_nodes,a,false,true)}}});c.jstree.defaults.plugins.push("crrm")})(jQuery); +(function(c){var a=[];c.jstree._themes=false;c.jstree.plugin("themes",{__init:function(){this.get_container().bind("init.jstree",c.proxy(function(){var d=this.get_settings().themes;this.data.themes.dots=d.dots;this.data.themes.icons=d.icons;this.set_theme(d.theme,d.url)},this)).bind("loaded.jstree",c.proxy(function(){this.data.themes.dots?this.show_dots():this.hide_dots();this.data.themes.icons?this.show_icons():this.hide_icons()},this))},defaults:{theme:"default",url:false,dots:true,icons:true}, +_fn:{set_theme:function(d,g){if(!d)return false;g||(g=c.jstree._themes+d+"/style.css");if(c.inArray(g,a)==-1){c.vakata.css.add_sheet({url:g,rel:"jstree"});a.push(g)}if(this.data.theme!=d){this.get_container().removeClass("jstree-"+this.data.theme);this.data.themes.theme=d}this.get_container().addClass("jstree-"+d);this.data.themes.dots?this.show_dots():this.hide_dots();this.data.themes.icons?this.show_icons():this.hide_icons();this.__callback()},get_theme:function(){return this.data.themes.theme}, +show_dots:function(){this.data.themes.dots=true;this.get_container().children("ul").removeClass("jstree-no-dots")},hide_dots:function(){this.data.themes.dots=false;this.get_container().children("ul").addClass("jstree-no-dots")},toggle_dots:function(){this.data.themes.dots?this.hide_dots():this.show_dots()},show_icons:function(){this.data.themes.icons=true;this.get_container().children("ul").removeClass("jstree-no-icons")},hide_icons:function(){this.data.themes.icons=false;this.get_container().children("ul").addClass("jstree-no-icons")}, +toggle_icons:function(){this.data.themes.icons?this.hide_icons():this.show_icons()}}});c(function(){c.jstree._themes===false&&c("script").each(function(){if(this.src.toString().match(/jquery\.jstree[^\/]*?\.js(\?.*)?$/)){c.jstree._themes=this.src.toString().replace(/jquery\.jstree[^\/]*?\.js(\?.*)?$/,"")+"themes/";return false}});if(c.jstree._themes===false)c.jstree._themes="themes/"});c.jstree.defaults.plugins.push("themes")})(jQuery); +(function(c){c.jstree.plugin("html_data",{__init:function(){this.data.html_data.original_container_html=this.get_container().html().replace(/<\/([^>]+)>\s+<").replace(/>\s+<([a-z]{1})/ig,"><$1")},defaults:{data:false,ajax:false,correct_state:false},_fn:{load_node:function(a,d,g){var f=this;this.load_node_html(a,function(){f.__callback({obj:a});d.call(this)},g)},_is_loaded:function(a){a=this._get_node(a);return a==-1||!a||!this.get_settings().html_data.ajax||a.is(".jstree-open, .jstree-leaf")|| +a.children("ul").children("li").size()>0},load_node_html:function(a,d,g){var f,b=this.get_settings().html_data,e=function(){};switch(true){case !b.data&&!b.ajax:if(!a||a==-1){this.get_container().html(this.data.html_data.original_container_html).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend(" ");this.clean_node()}d&&d.call(this);break;case !!b.data&&!b.ajax||!!b.data&&!!b.ajax&&(!a||a===-1):if(!a||a==-1){f=c(b.data);f.is("ul")|| +(f=c("
              ").append(f));this.get_container().children("ul").empty().append(f.children()).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend(" ");this.clean_node()}d&&d.call(this);break;case !b.data&&!!b.ajax||!!b.data&&!!b.ajax&&a&&a!==-1:a=this._get_node(a);e=function(h,k,j){var i=this.get_settings().html_data.ajax.error;i&&i.call(this,h,k,j);if(a!=-1&&a.length){a.children(".jstree-loading").removeClass("jstree-loading");b.correct_state&& +a.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}g&&g.call(this)};b.ajax.context=this;b.ajax.error=e;b.ajax.success=function(h,k,j){if(j.responseText=="")return e.call(this,j,k,"");var i=this.get_settings().html_data.ajax.success;if(i)h=i.call(this,h,k,j)||h;if(h){h=c(h);h.is("ul")||(h=c("
                ").append(h));if(a==-1||!a)this.get_container().children("ul").empty().append(h.children()).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend(" "); +else{a.children(".jstree-loading").removeClass("jstree-loading");a.append(h).find("li, a").filter(function(){return this.firstChild.tagName!=="INS"}).prepend(" ")}this.clean_node(a);d&&d.call(this)}else{a.children(".jstree-loading").removeClass("jstree-loading");b.correct_state&&a.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}};if(c.isFunction(b.ajax.data))b.ajax.data=b.ajax.data.call(this,a);c.ajax(b.ajax);break}}}});c.jstree.defaults.plugins.push("html_data")})(jQuery); +(function(c){var a=[];c.jstree.plugin("hotkeys",{__init:function(){if(typeof c.hotkeys==="undefined")throw"jsTree hotkeys: jQuery hotkeys plugin not included.";if(!this.data.ui)throw"jsTree hotkeys: jsTree UI plugin not included.";c.each(this.get_settings().hotkeys,function(d){if(c.inArray(d,a)==-1){c(document).bind("keydown",d,function(g){var f;var b=c.jstree._focused();if(b&&b.data&&b.data.hotkeys&&b.data.hotkeys.enabled)if(b.get_settings().hotkeys[d])f=b.get_settings().hotkeys[d].call(b,g);return f}); +a.push(d)}});this.enable_hotkeys()},defaults:{up:function(){this.hover_node(this._get_prev(this.data.ui.hovered||this.data.ui.last_selected||-1));return false},down:function(){this.hover_node(this._get_next(this.data.ui.hovered||this.data.ui.last_selected||-1));return false},left:function(){var d=this.data.ui.hovered||this.data.ui.last_selected;if(d)d.hasClass("jstree-open")?this.close_node(d):this.hover_node(this._get_prev(d));return false},right:function(){var d=this.data.ui.hovered||this.data.ui.last_selected; +if(d&&d.length)d.hasClass("jstree-closed")?this.open_node(d):this.hover_node(this._get_next(d));return false},space:function(){this.data.ui.hovered&&this.data.ui.hovered.children("a:eq(0)").click();return false},"ctrl+space":function(d){d.type="click";this.data.ui.hovered&&this.data.ui.hovered.children("a:eq(0)").trigger(d);return false},f2:function(){this.rename(this.data.ui.hovered||this.data.ui.last_selected)},del:function(){this.remove(this.data.ui.hovered||this._get_node(null))}},_fn:{enable_hotkeys:function(){this.data.hotkeys.enabled= +true},disable_hotkeys:function(){this.data.hotkeys.enabled=false}}})})(jQuery); +(function(c){c.jstree.plugin("json_data",{defaults:{data:false,ajax:false,correct_state:false,progressive_render:false},_fn:{load_node:function(a,d,g){var f=this;this.load_node_json(a,function(){f.__callback({obj:a});d.call(this)},g)},_is_loaded:function(a){var d=this.get_settings().json_data;if((a=this._get_node(a))&&a!==-1&&d.progressive_render){a.append(this.parse_json(a.data("jstree-children")));c.removeData(a,"jstree-children");this.clean_node(a)}return a==-1||!a||!d.ajax||a.is(".jstree-open, .jstree-leaf")|| +a.children("ul").children("li").size()>0},load_node_json:function(a,d,g){var f=this.get_settings().json_data,b=function(){};switch(true){case !f.data&&!f.ajax:throw"Neither data nor ajax settings supplied.";case !!f.data&&!f.ajax||!!f.data&&!!f.ajax&&(!a||a===-1):if(!a||a==-1){this.get_container().children("ul").empty().append(this.parse_json(f.data).children());this.clean_node()}d&&d.call(this);break;case !f.data&&!!f.ajax||!!f.data&&!!f.ajax&&a&&a!==-1:a=this._get_node(a);b=function(e,h,k){var j= +this.get_settings().json_data.ajax.error;j&&j.call(this,e,h,k);if(a!=-1&&a.length){a.children(".jstree-loading").removeClass("jstree-loading");f.correct_state&&a.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}g&&g.call(this)};f.ajax.context=this;f.ajax.error=b;f.ajax.success=function(e,h,k){if(k.responseText==""||!c.isArray(e)&&!c.isPlainObject(e))return b.call(this,k,h,"");var j=this.get_settings().json_data.ajax.success;if(j)e=j.call(this,e,h,k)||e;if(e=this.parse_json(e)){a== +-1||!a?this.get_container().children("ul").empty().append(e.children()):a.append(e).children(".jstree-loading").removeClass("jstree-loading");this.clean_node(a);d&&d.call(this)}else{a.children(".jstree-loading").removeClass("jstree-loading");f.correct_state&&a.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}};if(c.isFunction(f.ajax.data))f.ajax.data=f.ajax.data.call(this,a);c.ajax(f.ajax);break}},parse_json:function(a,d){var g=c(),f,b,e;b=this.get_settings().json_data;var h=this.get_settings().core.html_titles; +if(!a)return g;if(c.isFunction(a))a=a.call(this);if(c.isArray(a)){if(!a.length)return false;b=0;for(e=a.length;b");a.attr&&g.attr(a.attr);a.metadata&&g.data("jstree",a.metadata);a.state&&g.addClass("jstree-"+a.state);if(!c.isArray(a.data)){f=a.data;a.data=[];a.data.push(f)}c.each(a.data,function(k,j){f=c("");if(c.isFunction(j))j=j.call(this,a);if(typeof j== +"string")f.attr("href","#")[h?"html":"text"](j);else{if(!j.attr)j.attr={};if(!j.attr.href)j.attr.href="#";f.attr(j.attr)[h?"html":"text"](j.title);j.language&&f.addClass(j.language)}f.prepend(" ");if(j.icon)j.icon.indexOf("/")===-1?f.children("ins").addClass(j.icon):f.children("ins").css("background","url('"+j.icon+"') center center no-repeat;");g.append(f)});g.prepend(" ");if(a.children)if(b.progressive_render&&a.state!=="open")g.addClass("jstree-closed").data("jstree-children", +a.children);else{if(c.isFunction(a.children))a.children=a.children.call(this,a);if(c.isArray(a.children)&&a.children.length){f=this.parse_json(a.children,true);if(f.length){b=c("
                  ");b.append(f);g.append(b)}}}}if(!d){b=c("
                    ");b.append(g);g=b}return g},get_json:function(a,d,g){var f=[],b=this.get_settings(),e=this,h,k,j,i,m,l;a=this._get_node(a);if(!a||a===-1)a=this.get_container().find("> ul > li");d=c.isArray(d)?d:["id","class"];this.data.types&&d.push(b.types.type_attr);g=c.isArray(g)?g:[]; +a.each(function(){j=c(this);h={data:[]};if(d.length)h.attr={};c.each(d,function(o,n){if((k=j.attr(n))&&k.length&&k.replace(/jstree[^ ]*|$/ig,"").length)h.attr[n]=k.replace(/jstree[^ ]*|$/ig,"")});if(j.hasClass("jstree-open"))h.state="open";if(j.hasClass("jstree-closed"))h.state="closed";i=j.children("a");i.each(function(){m=c(this);if(g.length||c.inArray("languages",b.plugins)!==-1||m.children("ins").get(0).style.backgroundImage.length||m.children("ins").get(0).className&&m.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig, +"").length){l=false;c.inArray("languages",b.plugins)!==-1&&c.isArray(b.languages)&&b.languages.length&&c.each(b.languages,function(o,n){if(m.hasClass(n)){l=n;return false}});k={attr:{},title:e.get_text(m,l)};c.each(g,function(o,n){h.attr[n]=j.attr(n).replace(/jstree[^ ]*|$/ig,"")});c.each(b.languages,function(o,n){if(m.hasClass(n)){k.language=n;return true}});if(m.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig,"").replace(/^\s+$/ig,"").length)k.icon=m.children("ins").get(0).className.replace(/jstree[^ ]*|$/ig, +"").replace(/^\s+$/ig,"");if(m.children("ins").get(0).style.backgroundImage.length)k.icon=m.children("ins").get(0).style.backgroundImage.replace("url(","").replace(")","")}else k=e.get_text(m);if(i.length>1)h.data.push(k);else h.data=k});j=j.find("> ul > li");if(j.length)h.children=e.get_json(j,d,g);f.push(h)});return f}}})})(jQuery); +(function(c){c.jstree.plugin("languages",{__init:function(){this._load_css()},defaults:[],_fn:{set_lang:function(a){var d=this.get_settings().languages,g=false,f=".jstree-"+this.get_index()+" a";if(!c.isArray(d)||d.length===0)return false;if(c.inArray(a,d)==-1)if(d[a])a=d[a];else return false;if(a==this.data.languages.current_language)return true;g=c.vakata.css.get_css(f+"."+this.data.languages.current_language,false,this.data.languages.language_css);if(g!==false)g.style.display="none";g=c.vakata.css.get_css(f+ +"."+a,false,this.data.languages.language_css);if(g!==false)g.style.display="";this.data.languages.current_language=a;this.__callback(a);return true},get_lang:function(){return this.data.languages.current_language},get_text:function(a,d){a=this._get_node(a)||this.data.ui.last_selected;if(!a.size())return false;var g=this.get_settings().languages,f=this.get_settings().core.html_titles;if(c.isArray(g)&&g.length){d=d&&c.inArray(d,g)!=-1?d:this.data.languages.current_language;a=a.children("a."+d)}else a= +a.children("a:eq(0)");if(f){a=a.clone();a.children("INS").remove();return a.html()}else{a=a.contents().filter(function(){return this.nodeType==3})[0];return a.nodeValue}},set_text:function(a,d,g){a=this._get_node(a)||this.data.ui.last_selected;if(!a.size())return false;var f=this.get_settings().languages,b=this.get_settings().core.html_titles;if(c.isArray(f)&&f.length){g=g&&c.inArray(g,f)!=-1?g:this.data.languages.current_language;a=a.children("a."+g)}else a=a.children("a:eq(0)");if(b){f=a.children("INS").clone(); +a.html(d).prepend(f);this.__callback({obj:a,name:d,lang:g});return true}else{a=a.contents().filter(function(){return this.nodeType==3})[0];this.__callback({obj:a,name:d,lang:g});return a.nodeValue=d}},_load_css:function(){var a=this.get_settings().languages,d="/* languages css */",g=".jstree-"+this.get_index()+" a",f;if(c.isArray(a)&&a.length){this.data.languages.current_language=a[0];for(f=0;fthis.get_text(d)? +1:-1},_fn:{sort:function(a){var d=this.get_settings().sort,g=this;a.append(c.makeArray(a.children("li")).sort(c.proxy(d,g)));a.find("> li > ul").each(function(){g.sort(c(this))});this.clean_node(a)}}})})(jQuery); +(function(c){var a=false,d=false,g=false;c.vakata.dnd={is_down:false,is_drag:false,helper:false,init_x:0,init_y:0,threshold:5,user_data:{},drag_start:function(f,b,e){c.vakata.dnd.is_drag&&c.vakata.drag_stop({});try{f.currentTarget.unselectable="on";f.currentTarget.onselectstart=function(){return false};if(f.currentTarget.style)f.currentTarget.style.MozUserSelect="none"}catch(h){}c.vakata.dnd.init_x=f.pageX;c.vakata.dnd.init_y=f.pageY;c.vakata.dnd.user_data=b;c.vakata.dnd.is_down=true;c.vakata.dnd.helper= +c("
                    ").html(e).css("opacity","0.75");c(document).bind("mousemove",c.vakata.dnd.drag);c(document).bind("mouseup",c.vakata.dnd.drag_stop);return false},drag:function(f){if(c.vakata.dnd.is_down){if(!c.vakata.dnd.is_drag)if(Math.abs(f.pageX-c.vakata.dnd.init_x)>5||Math.abs(f.pageY-c.vakata.dnd.init_y)>5){c.vakata.dnd.helper.appendTo("body");c.vakata.dnd.is_drag=true;c(document).triggerHandler("vakata.drag_start",{event:f,data:c.vakata.dnd.user_data})}else return;c.vakata.dnd.helper.css({left:f.pageX+ +5+"px",top:f.pageY+10+"px"});c(document).triggerHandler("vakata.drag",{event:f,data:c.vakata.dnd.user_data})}},drag_stop:function(f){c(document).unbind("mousemove",c.vakata.dnd.drag);c(document).unbind("mouseup",c.vakata.dnd.drag_stop);c(document).triggerHandler("vakata.drag_stop",{event:f,data:c.vakata.dnd.user_data});c.vakata.dnd.helper.remove();c.vakata.dnd.init_x=0;c.vakata.dnd.init_y=0;c.vakata.dnd.user_data={};c.vakata.dnd.is_down=false;c.vakata.dnd.is_drag=false}};c(function(){c.vakata.css.add_sheet({str:"#vakata-dragged { display:block; margin:0 0 0 0; padding:4px 4px 4px 24px; position:absolute; left:-2000px; top:-2000px; line-height:16px; } "})}); +c.jstree.plugin("dnd",{__init:function(){this.data.dnd={active:false,after:false,inside:false,before:false,off:false,prepared:false,w:0,to1:false,to2:false,cof:false,cw:false,ch:false,i1:false,i2:false};this.get_container().bind("mouseenter.jstree",c.proxy(function(){if(c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree&&this.data.themes){g.attr("class","jstree-"+this.data.themes.theme);c.vakata.dnd.helper.attr("class","jstree-dnd-helper jstree-"+this.data.themes.theme)}},this)).bind("mouseleave.jstree", +c.proxy(function(){if(c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree){this.data.dnd.i1&&clearInterval(this.data.dnd.i1);this.data.dnd.i2&&clearInterval(this.data.dnd.i2)}},this)).bind("mousemove.jstree",c.proxy(function(b){if(c.vakata.dnd.is_drag&&c.vakata.dnd.user_data.jstree){var e=this.get_container()[0];if(b.pageX+20>this.data.dnd.cof.left+this.data.dnd.cw){this.data.dnd.i1&&clearInterval(this.data.dnd.i1);this.data.dnd.i1=setInterval(c.proxy(function(){this.scrollLeft+=5},e),100)}else if(b.pageX- +20this.data.dnd.cof.top+this.data.dnd.ch){this.data.dnd.i2&&clearInterval(this.data.dnd.i2);this.data.dnd.i2=setInterval(c.proxy(function(){this.scrollTop+=5},e),100)}else if(b.pageY-20"+c(b.target).text()); +if(this.data.themes){g.attr("class","jstree-"+this.data.themes.theme);c.vakata.dnd.helper.attr("class","jstree-dnd-helper jstree-"+this.data.themes.theme)}c.vakata.dnd.helper.children("ins").attr("class","jstree-invalid");b=this.get_container();this.data.dnd.cof=b.children("ul").offset();this.data.dnd.cw=parseInt(b.width(),10);this.data.dnd.ch=parseInt(b.height(),10);this.data.dnd.foreign=true;return false},this));f.drop_target&&c(document).delegate(f.drop_target,"mouseenter.jstree",c.proxy(function(b){this.data.dnd.active&& +this.get_settings().dnd.drop_check.call(this,{o:a,r:c(b.target)})&&c.vakata.dnd.helper.children("ins").attr("class","jstree-ok")},this)).delegate(f.drop_target,"mouseleave.jstree",c.proxy(function(){this.data.dnd.active&&c.vakata.dnd.helper.children("ins").attr("class","jstree-invalid")},this)).delegate(f.drop_target,"mouseup.jstree",c.proxy(function(b){this.data.dnd.active&&c.vakata.dnd.helper.children("ins").hasClass("jstree-ok")&&this.get_settings().dnd.drop_finish.call(this,{o:a,r:c(b.target)})}, +this))},defaults:{copy_modifier:"ctrl",check_timeout:200,open_timeout:500,drop_target:".jstree-drop",drop_check:function(){return true},drop_finish:c.noop,drag_target:".jstree-draggable",drag_finish:c.noop,drag_check:function(){return{after:false,before:false,inside:true}}},_fn:{dnd_prepare:function(){this.data.dnd.off=d.offset();if(this.data.dnd.foreign){var f=this.get_settings().dnd.drag_check.call(this,{o:a,r:d});this.data.dnd.after=f.after;this.data.dnd.before=f.before;this.data.dnd.inside=f.inside; +this.data.dnd.prepared=true;return this.dnd_show()}this.prepare_move(a,d,"before");this.data.dnd.before=this.check_move();this.prepare_move(a,d,"after");this.data.dnd.after=this.check_move();if(this._is_loaded(d)){this.prepare_move(a,d,"inside");this.data.dnd.inside=this.check_move()}else this.data.dnd.inside=false;this.data.dnd.prepared=true;return this.dnd_show()},dnd_show:function(){if(this.data.dnd.prepared){var f=["before","inside","after"],b=false;f=this.data.dnd.w"+(a.length>1?"Multiple selection":this.get_text(a)));if(this.data.themes){g.attr("class","jstree-"+this.data.themes.theme);c.vakata.dnd.helper.attr("class", +"jstree-dnd-helper jstree-"+this.data.themes.theme)}var e=this.get_container();this.data.dnd.cof=e.children("ul").offset();this.data.dnd.cw=parseInt(e.width(),10);this.data.dnd.ch=parseInt(e.height(),10);this.data.dnd.active=true}}});c(function(){c.vakata.css.add_sheet({str:"#vakata-dragged ins { display:block; text-decoration:none; width:16px; height:16px; margin:0 0 0 0; padding:0; position:absolute; top:4px; left:4px; } #vakata-dragged .jstree-ok { background:green; } #vakata-dragged .jstree-invalid { background:red; } #jstree-marker { padding:0; margin:0; line-height:12px; font-size:1px; overflow:hidden; height:12px; width:8px; position:absolute; left:-45px; top:-30px; z-index:1000; background-repeat:no-repeat; display:none; background-color:silver; } "}); +g=c("
                    ").attr({id:"jstree-marker"}).hide().appendTo("body");c(document).bind("vakata.drag_start",function(f,b){b.data.jstree&&g.show()});c(document).bind("vakata.drag_stop",function(f,b){b.data.jstree&&g.hide()})})})(jQuery); +(function(c){c.jstree.plugin("checkbox",{__init:function(){if(!this.data.ui)throw"jsTree checkboxes: jsTree UI plugin not included";this.select_node=this.deselect_node=this.deselect_all=c.noop;this.get_selected=this.get_checked;this.get_container().bind("open_node.jstree create_node.jstree",c.proxy(function(a,d){this._prepare_checkboxes(d.rslt.obj)},this)).bind("loaded.jstree",c.proxy(function(){this._prepare_checkboxes()},this)).bind("clean_node.jstree",c.proxy(function(a,d){this._repair_state(d.args[0])}, +this)).delegate("a","click.jstree",c.proxy(function(a){this.change_state(a.target);this.save_selected();this.data.cookies&&this.save_cookie("select_node");a.preventDefault()},this))},_fn:{_prepare_checkboxes:function(a){a=!a||a==-1?this.get_container():this._get_node(a);var d=a.is("li")&&a.hasClass("jstree-checked")?"jstree-checked":"jstree-unchecked";a.find("a").not(":has(.checkbox)").prepend(" ").parent().addClass(d)},change_state:function(a,d){a=this._get_node(a); +if(d=d===false||d===true?d:a.hasClass("jstree-checked"))a.find("li").andSelf().removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");else{a.find("li").andSelf().removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked");this.data.ui.last_selected=a}var g=this;a.parentsUntil(this.get_container(),"li").each(function(){var f=c(this);if(d)if(f.children("ul").children(".jstree-checked, .jstree-undetermined").length){f.parentsUntil(g.get_container(),"li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined"); +return false}else f.removeClass("jstree-checked jstree-undetermined").addClass("jstree-unchecked");else if(f.children("ul").children(".jstree-unchecked, .jstree-undetermined").length){f.parentsUntil(g.get_container(),"li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined");return false}else f.removeClass("jstree-unchecked jstree-undetermined").addClass("jstree-checked")});this.data.ui.selected=this.get_checked();this.__callback(a)},check_node:function(a){this.change_state(a, +false)},uncheck_node:function(a){this.change_state(a,true)},check_all:function(){var a=this;this.get_container().children("ul").children("li").each(function(){a.check_node(this,false)})},uncheck_all:function(){var a=this;this.get_container().children("ul").children("li").each(function(){a.change_state(this,true)})},is_checked:function(a){a=this._get_node(a);return a.length?a.is(".jstree-checked"):false},get_checked:function(a){a=!a||a===-1?this.get_container():this._get_node(a);return a.find("> ul > .jstree-checked, .jstree-undetermined > ul > .jstree-checked")}, +get_unchecked:function(a){a=!a||a===-1?this.get_container():this._get_node(a);return a.find("> ul > .jstree-unchecked, .jstree-undetermined > ul > .jstree-unchecked")},show_checkboxes:function(){this.get_container().children("ul").removeClass("jstree-no-checkboxes")},hide_checkboxes:function(){this.get_container().children("ul").addClass("jstree-no-checkboxes")},_repair_state:function(a){a=this._get_node(a);if(a.length){var d=a.find("> ul > .jstree-checked").length,g=a.find("> ul > .jstree-undetermined").length, +f=a.find("> ul > li").length;if(f===0)a.hasClass("jstree-undetermined")&&this.check_node(a);else if(d===0&&g===0)this.uncheck_node(a);else d===f?this.check_node(a):a.parentsUntil(this.get_container(),"li").andSelf().removeClass("jstree-checked jstree-unchecked").addClass("jstree-undetermined")}},reselect:function(){var a=this,d=this.data.ui.to_select;d=c.map(c.makeArray(d),function(g){return"#"+g.toString().replace(/^#/,"").replace("\\/","/").replace("/","\\/")});this.deselect_all();c.each(d,function(g, +f){a.check_node(f)});this.__callback()}}})})(jQuery); +(function(c){c.vakata.xslt=function(d,g){var f="",b,e;if(document.recalc){b=document.createElement("xml");e=document.createElement("xml");b.innerHTML=d;e.innerHTML=g;c("body").append(b).append(e);f=b.transformNode(e.XMLDocument);c("body").remove(b).remove(e);return f}if(typeof window.DOMParser!=="undefined"&&typeof window.XMLHttpRequest!=="undefined"&&typeof window.XSLTProcessor!=="undefined"){b=new XSLTProcessor;f=c.isFunction(b.transformDocument)?typeof window.XMLSerializer!=="undefined":true;if(!f)return false; +d=(new DOMParser).parseFromString(d,"text/xml");g=(new DOMParser).parseFromString(g,"text/xml");if(c.isFunction(b.transformDocument)){f=document.implementation.createDocument("","",null);b.transformDocument(d,g,f,null);return(new XMLSerializer).serializeToString(f)}else{b.importStylesheet(g);f=b.transformToFragment(d,document);return c("
                    ").append(f).html()}}return false};var a={nest:'\t\t\t\t\t\t', +flat:'\t
                      \t\t\t\t\t\t\t\t\t\t\t\t\t
                    \t\t\t\t
                  • \t\t\tjstree-last \t\t\t\t\tjstree-open \t\t\tjstree-closed \t\t\tjstree-leaf \t\t\t\t\t\t\t\t\t\t\t\t\t\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t#\t\t\t\t\t\t\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tjstree-icon \t\t\t\t\t\t\t\t\t\t\t\t\tbackground:url() center center no-repeat;\t\t\t\t \t\t\t\t\t\t\t\t\t\t\t\t
                      \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t
                    \t
                    \t
                  • '}; +c.jstree.plugin("xml_data",{defaults:{data:false,ajax:false,xsl:"flat",clean_node:false},_fn:{load_node:function(d,g,f){var b=this;this.load_node_xml(d,function(){b.__callback({obj:d});g.call(this)},f)},_is_loaded:function(d){var g=this.get_settings().xml_data;return d==-1||!d||!g.ajax||d.is(".jstree-open, .jstree-leaf")||d.children("ul").children("li").size()>0},load_node_xml:function(d,g,f){var b=this.get_settings().xml_data,e=function(){};switch(true){case !b.data&&!b.ajax:throw"Neither data nor ajax settings supplied."; +case !!b.data&&!b.ajax||!!b.data&&!!b.ajax&&(!d||d===-1):if(!d||d==-1){this.get_container().children("ul").empty().append(this.parse_xml(b.data).children());b.clean_node&&this.clean_node(d)}g&&g.call(this);break;case !b.data&&!!b.ajax||!!b.data&&!!b.ajax&&d&&d!==-1:d=this._get_node(d);e=function(h,k,j){var i=this.get_settings().xml_data.ajax.error;i&&i.call(this,h,k,j);if(d!==-1&&d.length){d.children(".jstree-loading").removeClass("jstree-loading");b.correct_state&&d.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}f&& +f.call(this)};b.ajax.context=this;b.ajax.error=e;b.ajax.success=function(h,k,j){if(j.responseText=="")return e.call(this,j,k,"");h=j.responseText;var i=this.get_settings().xml_data.ajax.success;if(i)h=i.call(this,h,k,j)||h;if(h=this.parse_xml(h)){d===-1||!d?this.get_container().children("ul").empty().append(this.parse_xml(j.responseText).children()):d.append(this.parse_xml(j.responseText)).children(".jstree-loading").removeClass("jstree-loading");b.clean_node&&this.clean_node(d);g&&g.call(this)}else{d.children(".jstree-loading").removeClass("jstree-loading"); +b.correct_state&&d.removeClass("jstree-open jstree-closed").addClass("jstree-leaf")}};if(c.isFunction(b.ajax.data))b.ajax.data=b.ajax.data.call(null,d);c.ajax(b.ajax);break}},parse_xml:function(d){var g=this.get_settings().xml_data;d=c.vakata.xslt(d,a[g.xsl]);if(d!==false)d=c(d);return d},get_xml:function(d,g,f,b,e){var h="",k=this.get_settings(),j=this,i,m,l,o,n;d||(d="flat");e||(e=0);g=this._get_node(g);if(!g||g===-1)g=this.get_container().find("> ul > li");f=c.isArray(f)?f:["id","class"];this.data.types&& +f.push(k.types.type_attr);b=c.isArray(b)?b:[];e||(h+="");g.each(function(){h+="";h+=""});h+="";m=l[0].id;l=l.find("> ul > li");if(l.length)m=j.get_xml(d,l,f,b,m);if(d=="nest")h+=m;h+="";if(d=="flat")h+=m});e||(h+="");return h}}})})(jQuery); +(function(c){c.expr[":"].jstree_contains=function(a,d,g){return(a.textContent||a.innerText||"").toLowerCase().indexOf(g[3].toLowerCase())>=0};c.jstree.plugin("search",{__init:function(){this.data.search.str="";this.data.search.result=c()},defaults:{ajax:false,case_insensitive:false},_fn:{search:function(a,d){var g=this.get_settings().search,f=this;this.data.search.str=a;if(!d&&g.ajax!==false&&this.get_container().find(".jstree-closed:eq(0)").length>0){this.search.supress_callback=true;g.ajax.context= +this;g.ajax.error=function(){};g.ajax.success=function(b,e,h){var k=this.get_settings().search.ajax.success;if(k)b=k.call(this,b,e,h)||b;this.data.search.to_open=b;this._search_open()};if(c.isFunction(g.ajax.data))g.ajax.data=g.ajax.data.call(this,a);if(!g.ajax.data)g.ajax.data={search_string:a};if(!g.ajax.dataType||/^json/.exec(g.ajax.dataType))g.ajax.dataType="json";c.ajax(g.ajax)}else{this.data.search.result.length&&this.clear_search();this.data.search.result=this.get_container().find("a"+(this.data.languages? +"."+this.get_lang():"")+":"+(g.case_insensitive?"jstree_contains":"contains")+"("+this.data.search.str+")");this.data.search.result.addClass("jstree-search").parents(".jstree-closed").each(function(){f.open_node(this,false,true)});this.__callback({nodes:this.data.search.result,str:a})}},clear_search:function(){this.data.search.result.removeClass("jstree-search");this.__callback(this.data.search.result);this.data.search.result=c()},_search_open:function(){var a=this,d=true,g=[],f=[];if(this.data.search.to_open.length){c.each(this.data.search.to_open, +function(b,e){if(e=="#")return true;c(e).length&&c(e).is(".jstree-closed")?g.push(e):f.push(e)});if(g.length){this.data.search.to_open=f;c.each(g,function(b,e){a.open_node(e,function(){a._search_open(true)})});d=false}}d&&this.search(this.data.search.str,true)}}})})(jQuery); +(function(c){c.vakata.context={cnt:c("
                    "),vis:false,tgt:false,func:false,data:false,show:function(a,d,g,f,b){if(a=c.vakata.context.parse(a)){c.vakata.context.vis=true;c.vakata.context.tgt=d;c.vakata.context.data=b||null;c.vakata.context.cnt.html(a).css({visibility:"hidden",display:"block",left:0,top:0});b=c.vakata.context.cnt.height();a=c.vakata.context.cnt.width();if(g+a>c(document).width()){g=c(document).width()-(a+5);c.vakata.context.cnt.find("li > ul").addClass("right")}if(f+ +b>c(document).height()){f-=b+d[0].offsetHeight;c.vakata.context.cnt.find("li > ul").addClass("bottom")}c.vakata.context.cnt.css({left:g,top:f}).find("li:has(ul)").bind("mouseenter",function(){var e=c(document).width(),h=c(document).height(),k=c(this).children("ul").show();e!==c(document).width()&&k.toggleClass("right");h!==c(document).height()&&k.toggleClass("bottom")}).bind("mouseleave",function(){c(this).children("ul").hide()}).end().css({visibility:"visible"}).show();c(document).triggerHandler("vakata.context_show")}}, +hide:function(){c.vakata.context.vis=false;c.vakata.context.cnt.attr("class","").hide();c(document).triggerHandler("vakata.context_hide")},parse:function(a,d){var g="",f=false;if(!d)c.vakata.context.func={};g+="
                      ";c.each(a,function(b,e){if(!e)return true;c.vakata.context.func[b]=e.action;if(e.separator_before)g+="
                    • ";g+="
                    • "+e.label;if(e.submenu)g+="»";g+="";if(e.submenu)if(f=c.vakata.context.parse(e.submenu,true))g+=f;g+="
                    • ";if(e.separator_after)g+="
                    • "});g+="
                    ";return g.length>10?g:false},exec:function(a){if(c.isFunction(c.vakata.context.func[a])){c.vakata.context.func[a].call(c.vakata.context.data,c.vakata.context.tgt);return true}else return false}}; +c(function(){c.vakata.css.add_sheet({str:"#vakata-contextmenu { display:none; position:absolute; margin:0; padding:0; min-width:180px; background:#ebebeb; border:1px solid silver; } #vakata-contextmenu ul { min-width:180px; } #vakata-contextmenu ul, #vakata-contextmenu li { margin:0; padding:0; list-style-type:none; display:block; } #vakata-contextmenu li { line-height:20px; min-height:20px; position:relative; padding:0px; } #vakata-contextmenu li a { padding:1px 6px; line-height:17px; display:block; text-decoration:none; margin:1px 1px 0 1px; } #vakata-contextmenu li ins { float:left; width:16px; height:16px; text-decoration:none; margin-right:2px; } #vakata-contextmenu li a:hover, #vakata-contextmenu li.vakata-hover > a { background:gray; color:white; } #vakata-contextmenu li ul { display:none; position:absolute; top:-2px; left:100%; background:#ebebeb; border:1px solid gray; } #vakata-contextmenu .right { right:100%; left:auto; } #vakata-contextmenu .bottom { bottom:-1px; top:auto; } #vakata-contextmenu li.vakata-separator { min-height:0; height:1px; line-height:1px; font-size:1px; overflow:hidden; margin:0 2px; background:silver; /* border-top:1px solid #fefefe; */ padding:0; } "}); +c.vakata.context.cnt.delegate("a","click",function(a){a.preventDefault()}).delegate("a","mouseup",function(){c.vakata.context.exec(c(this).attr("rel"))&&c.vakata.context.hide()}).delegate("a","mouseover",function(){c.vakata.context.cnt.find(".vakata-hover").removeClass("vakata-hover")}).appendTo("body");c(document).bind("mousedown",function(a){c.vakata.context.vis&&!c.contains(c.vakata.context.cnt[0],a.target)&&c.vakata.context.hide()});typeof c.hotkeys!=="undefined"&&c(document).bind("keydown","up", +function(a){if(c.vakata.context.vis){var d=c.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").prevAll("li:not(.vakata-separator)").first();d.length||(d=c.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").last());d.addClass("vakata-hover");a.stopImmediatePropagation();a.preventDefault()}}).bind("keydown","down",function(a){if(c.vakata.context.vis){var d=c.vakata.context.cnt.find("ul:visible").last().children(".vakata-hover").removeClass("vakata-hover").nextAll("li:not(.vakata-separator)").first(); +d.length||(d=c.vakata.context.cnt.find("ul:visible").last().children("li:not(.vakata-separator)").first());d.addClass("vakata-hover");a.stopImmediatePropagation();a.preventDefault()}}).bind("keydown","right",function(a){if(c.vakata.context.vis){c.vakata.context.cnt.find(".vakata-hover").children("ul").show().children("li:not(.vakata-separator)").removeClass("vakata-hover").first().addClass("vakata-hover");a.stopImmediatePropagation();a.preventDefault()}}).bind("keydown","left",function(a){if(c.vakata.context.vis){c.vakata.context.cnt.find(".vakata-hover").children("ul").hide().children(".vakata-separator").removeClass("vakata-hover"); +a.stopImmediatePropagation();a.preventDefault()}}).bind("keydown","esc",function(a){c.vakata.context.hide();a.preventDefault()}).bind("keydown","space",function(a){c.vakata.context.cnt.find(".vakata-hover").last().children("a").click();a.preventDefault()})});c.jstree.plugin("contextmenu",{__init:function(){this.get_container().delegate("a","contextmenu.jstree",c.proxy(function(a){a.preventDefault();this.show_contextmenu(a.currentTarget,a.pageX,a.pageY)},this))},defaults:{show_at_node:true,items:{create:{separator_before:false, +separator_after:true,label:"Create",action:function(a){this.create(a)}},rename:{separator_before:false,separator_after:false,label:"Rename",action:function(a){this.rename(a)}},remove:{separator_before:false,icon:false,separator_after:false,label:"Delete",action:function(a){this.remove(a)}},ccp:{separator_before:true,icon:false,separator_after:false,label:"Edit",action:function(a){this.remove(a)},submenu:{cut:{separator_before:false,separator_after:false,label:"Cut",action:function(a){this.cut(a)}}, +copy:{separator_before:false,icon:false,separator_after:false,label:"Copy",action:function(a){this.copy(a)}},paste:{separator_before:false,icon:false,separator_after:false,label:"Paste",action:function(a){this.paste(a)}}}}}},_fn:{show_contextmenu:function(a,d,g){a=this._get_node(a);var f=this.get_settings().contextmenu,b=a.children("a:visible:eq(0)"),e=false;if(f.show_at_node||typeof d==="undefined"||typeof g==="undefined"){e=b.offset();d=e.left;g=e.top+this.data.core.li_height}if(c.isFunction(f.items))f.items= +f.items.call(this,a);c.vakata.context.show(f.items,b,d,g,this);this.data.themes&&c.vakata.context.cnt.attr("class","jstree-"+this.data.themes.theme+"-context")}}})})(jQuery); +(function(c){c.jstree.plugin("types",{__init:function(){var a=this.get_settings().types;this.data.types.attach_to=[];this.get_container().bind("init.jstree",c.proxy(function(){var d=a.type_attr,g="",f=this;c.each(a.types,function(b,e){c.each(e,function(h){/^(max_depth|max_children|icon|valid_children)$/.test(h)||f.data.types.attach_to.push(h)});if(!e.icon)return true;if(e.icon.image||e.icon.position){g+=b=="default"?".jstree-"+f.get_index()+" a > .jstree-icon { ":".jstree-"+f.get_index()+" li["+d+ +"="+b+"] > a > .jstree-icon { ";if(e.icon.image)g+=" background-image:url("+e.icon.image+"); ";g+=e.icon.position?" background-position:"+e.icon.position+"; ":" background-position:0 0; ";g+="} "}});g!=""&&c.vakata.css.add_sheet({str:g})},this)).bind("before.jstree",c.proxy(function(d,g){if(c.inArray(g.func,this.data.types.attach_to)!==-1){var f=this.get_settings().types.types,b=this._get_type(g.args[0]);if(f[b]&&typeof f[b][g.func]!=="undefined"&&!this._check(g.func,g.args[0])){d.stopImmediatePropagation(); +return false}}},this))},defaults:{max_children:-1,max_depth:-1,valid_children:"all",type_attr:"rel",types:{"default":{max_children:-1,max_depth:-1,valid_children:"all"}}},_fn:{_get_type:function(a){a=this._get_node(a);return!a||!a.length?false:a.attr(this.get_settings().types.type_attr)||"default"},set_type:function(a,d){d=this._get_node(d);return!d.length||!a?false:d.attr(this.get_settings().types.type_attr,a)},_check:function(a,d,g){var f=false,b=this._get_type(d),e=0,h=this,k=this.get_settings().types; +if(d===-1)if(k[a])f=k[a];else return;else{if(b===false)return;if(k.types[b]&&k.types[b][a])f=k.types[b][a];else if(k.types["default"]&&k.types["default"][a])f=k.types["default"][a]}if(c.isFunction(f))f=f.call(this,d);a==="max_depth"&&d!==-1&&g!==false&&k.max_depth!==-2&&f!==0&&this._get_node(d).parentsUntil(this.get_container(),"li").each(function(j){e=h._check(a,this,false);if(e!==-1&&e-(j+1)<=0){f=0;return false}if(e>=0&&(e-(j+1) ul > li").not(a.o).length:a.cr.children("> ul > li").not(a.o).length;if(e+a.o.length>g)return false}if(d.max_depth!== +-2&&f!==-1){h=0;if(f===0)return false;if(typeof a.o.d==="undefined"){for(d=a.o;d.length>0;){d=d.find("> ul > li");h++}a.o.d=h}if(f-a.o.d<0)return false}return true},create_node:function(a,d,g,f,b,e){if(!e&&(b||this._is_loaded(a))){var h=d&&d.match(/^before|after$/i)?this._get_parent(a):this._get_node(a),k=this.get_settings().types,j=this._check("max_children",h),i=this._check("max_depth",h),m=this._check("valid_children",h);g||(g={});if(m==="none")return false;if(c.isArray(m))if(!g.attr||!g.attr[k.type_attr]){if(!g.attr)g.attr= +{};g.attr[k.type_attr]=m[0]}else if(c.inArray(g.attr[k.type_attr],m)===-1)return false;if(k.max_children!==-2&&j!==-1){h=h===-1?this.get_container().children("> ul > li").length:h.children("> ul > li").length;if(h+1>j)return false}if(k.max_depth!==-2&&i!==-1&&i-1<=0)return false}return this.__call_old(true,a,d,g,f,b,e)}}})})(jQuery); \ No newline at end of file diff --git a/application/media/js/jquery.stickyfloat-1.0.js b/application/media/js/jquery.stickyfloat-1.0.js new file mode 100644 index 00000000..9ef886e7 --- /dev/null +++ b/application/media/js/jquery.stickyfloat-1.0.js @@ -0,0 +1,48 @@ +/* + * stickyfloat - jQuery plugin for verticaly floating anything in a constrained area + * + * Example: jQuery('#menu').stickyfloat({duration: 400}); + * parameters: + * duration - the duration of the animation + * startOffset - the amount of scroll offset after it the animations kicks in + * offsetY - the offset from the top when the object is animated + * lockBottom - 'true' by default, set to false if you don't want your floating box to stop at parent's bottom + * $Version: 05.16.2009 r1 + * Copyright (c) 2009 Yair Even-Or + * vsync.design@gmail.com + */ + +$.fn.stickyfloat = function(options, lockBottom) { + var $obj = this; + var parentPaddingTop = parseInt($obj.parent().css('padding-top')); + var startOffset = $obj.parent().offset().top; + var opts = $.extend({ startOffset: startOffset, offsetY: parentPaddingTop, duration: 200, lockBottom:true }, options); + + $obj.css({ position: 'absolute' }); + + if(opts.lockBottom){ + var bottomPos = $obj.parent().height() - $obj.height() + parentPaddingTop; //get the maximum scrollTop value + if( bottomPos < 0 ) + bottomPos = 0; + } + + $(window).scroll(function () { + $obj.stop(); // stop all calculations on scroll event + + var pastStartOffset = $(document).scrollTop() > opts.startOffset; // check if the window was scrolled down more than the start offset declared. + var objFartherThanTopPos = $obj.offset().top > startOffset; // check if the object is at it's top position (starting point) + var objBiggerThanWindow = $obj.outerHeight() < $(window).height(); // if the window size is smaller than the Obj size, then do not animate. + + // if window scrolled down more than startOffset OR obj position is greater than + // the top position possible (+ offsetY) AND window size must be bigger than Obj size + if( (pastStartOffset || objFartherThanTopPos) && objBiggerThanWindow ){ + var newpos = ($(document).scrollTop() -startOffset + opts.offsetY ); + if ( newpos > bottomPos ) + newpos = bottomPos; + if ( $(document).scrollTop() < opts.startOffset ) // if window scrolled < starting offset, then reset Obj position (opts.offsetY); + newpos = parentPaddingTop; + + $obj.animate({ top: newpos }, opts.duration ); + } + }); +}; diff --git a/application/media/js/themes/default/dot_for_ie.gif b/application/media/js/themes/default/dot_for_ie.gif new file mode 100644 index 0000000000000000000000000000000000000000..c0cc5fda7cfb9539720de442a3caca9c9a3fc4cb GIT binary patch literal 43 vcmZ?wbhEHbWMW`qXkcKFla>7c|G(l-7DfgJMg|=QAOOiQFfqBrF<1it%E1S( literal 0 HcmV?d00001 diff --git a/application/messages/.htaccess b/application/messages/.htaccess new file mode 100644 index 00000000..281d5c33 --- /dev/null +++ b/application/messages/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/application/views/.htaccess b/application/views/.htaccess new file mode 100644 index 00000000..281d5c33 --- /dev/null +++ b/application/views/.htaccess @@ -0,0 +1,2 @@ +order allow,deny +deny from all diff --git a/application/views/lnapp/default.php b/application/views/lnapp/default.php new file mode 100644 index 00000000..57d95662 --- /dev/null +++ b/application/views/lnapp/default.php @@ -0,0 +1,93 @@ + + + + + <?php echo $meta->title; ?> + + + + + + + styles; ?> + scripts; ?> + + + + + + + + + + + + + + + + + + + + +
                    +
                    + + + + + + +
                    +
                    +
                    +
                    + + + + +
                    +
                    +
                    > +
                    + + + + +
                    +
                    +
                    +
                    + + + + + +
                    + + + + + +
                    +
                    +
                    > +
                    + + + + +
                    +
                    +
                    +
                    + + + + +
                    + + diff --git a/application/views/login.php b/application/views/login.php new file mode 100644 index 00000000..c76e139f --- /dev/null +++ b/application/views/login.php @@ -0,0 +1,15 @@ +
                    + + + + + + + + + + + + + + diff --git a/application/views/login_reset.php b/application/views/login_reset.php new file mode 100644 index 00000000..5d4294d6 --- /dev/null +++ b/application/views/login_reset.php @@ -0,0 +1,14 @@ +
                    +

                    If you have forgotten your password, we can issue you a temporary access code via email that will allow you to change your password.

                    +

                    To start this process, please enter your email address.

                    +
                    + + + + + + + + + + diff --git a/application/views/login_reset_sent.php b/application/views/login_reset_sent.php new file mode 100644 index 00000000..dd2554be --- /dev/null +++ b/application/views/login_reset_sent.php @@ -0,0 +1,13 @@ +
                    +

                    You should have received an email with a pass code. Please enter that pass code here.

                    +
                    + + + + + + + + + + diff --git a/application/views/template.php b/application/views/template.php new file mode 100644 index 00000000..6f727648 --- /dev/null +++ b/application/views/template.php @@ -0,0 +1 @@ + diff --git a/config.inc.php b/config.inc.php index 63b667e4..41d338c9 100644 --- a/config.inc.php +++ b/config.inc.php @@ -1,3 +1,71 @@ - + '_news', 'p' => 'newsletter:newsletter'), + array('s' => '_affiliate','p' => 'affiliate:affiliate'), + array('s' => '_contact', 'p' => 'staff:staff'), + array('s' => '_account', 'p' => 'account:account'), + array('s' => '_products', 'p' => 'product:cat'), + array('s' => '_product', 'p' => 'product:details'), + array('s' => '_cart', 'p' => 'cart:cart'), + array('s' => '_checkout', 'p' => 'checkout:checkout'), + array('s' => '_static', 'p' => 'static_page:show') + ); +?> diff --git a/includes/files/tracking.txt b/includes/files/tracking.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/includes/kohana/modules/simplehtmldom/classes/simple_html_dom.php b/includes/kohana/modules/simplehtmldom/classes/simple_html_dom.php new file mode 100644 index 00000000..fbe43df5 --- /dev/null +++ b/includes/kohana/modules/simplehtmldom/classes/simple_html_dom.php @@ -0,0 +1,975 @@ + +Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/) +Contributions by: + Yousuke Kumakura (Attribute filters) + Vadim Voituk (Negative indexes supports of "find" method) + Antcs (Constructor with automatically load contents either text or file/url) +Licensed under The MIT License +Redistributions of files must retain the above copyright notice. +*******************************************************************************/ + +define('HDOM_TYPE_ELEMENT', 1); +define('HDOM_TYPE_COMMENT', 2); +define('HDOM_TYPE_TEXT', 3); +define('HDOM_TYPE_ENDTAG', 4); +define('HDOM_TYPE_ROOT', 5); +define('HDOM_TYPE_UNKNOWN', 6); +define('HDOM_QUOTE_DOUBLE', 0); +define('HDOM_QUOTE_SINGLE', 1); +define('HDOM_QUOTE_NO', 3); +define('HDOM_INFO_BEGIN', 0); +define('HDOM_INFO_END', 1); +define('HDOM_INFO_QUOTE', 2); +define('HDOM_INFO_SPACE', 3); +define('HDOM_INFO_TEXT', 4); +define('HDOM_INFO_INNER', 5); +define('HDOM_INFO_OUTER', 6); +define('HDOM_INFO_ENDSPACE',7); + +// helper functions +// ----------------------------------------------------------------------------- +// get html dom form file +function file_get_html() { + $dom = new simple_html_dom; + $args = func_get_args(); + $dom->load(call_user_func_array('file_get_contents', $args), true); + return $dom; +} + +// get html dom form string +function str_get_html($str, $lowercase=true) { + $dom = new simple_html_dom; + $dom->load($str, $lowercase); + return $dom; +} + +// dump html dom tree +function dump_html_tree($node, $show_attr=true, $deep=0) { + $lead = str_repeat(' ', $deep); + echo $lead.$node->tag; + if ($show_attr && count($node->attr)>0) { + echo '('; + foreach($node->attr as $k=>$v) + echo "[$k]=>\"".$node->$k.'", '; + echo ')'; + } + echo "\n"; + + foreach($node->nodes as $c) + dump_html_tree($c, $show_attr, $deep+1); +} + +// get dom form file (deprecated) +function file_get_dom() { + $dom = new simple_html_dom; + $args = func_get_args(); + $dom->load(call_user_func_array('file_get_contents', $args), true); + return $dom; +} + +// get dom form string (deprecated) +function str_get_dom($str, $lowercase=true) { + $dom = new simple_html_dom; + $dom->load($str, $lowercase); + return $dom; +} + +// simple html dom node +// ----------------------------------------------------------------------------- +class simple_html_dom_node { + public $nodetype = HDOM_TYPE_TEXT; + public $tag = 'text'; + public $attr = array(); + public $children = array(); + public $nodes = array(); + public $parent = null; + public $_ = array(); + private $dom = null; + + function __construct($dom) { + $this->dom = $dom; + $dom->nodes[] = $this; + } + + function __destruct() { + $this->clear(); + } + + function __toString() { + return $this->outertext(); + } + + // clean up memory due to php5 circular references memory leak... + function clear() { + $this->dom = null; + $this->nodes = null; + $this->parent = null; + $this->children = null; + } + + // dump node's tree + function dump($show_attr=true) { + dump_html_tree($this, $show_attr); + } + + // returns the parent of node + function parent() { + return $this->parent; + } + + // returns children of node + function children($idx=-1) { + if ($idx===-1) return $this->children; + if (isset($this->children[$idx])) return $this->children[$idx]; + return null; + } + + // returns the first child of node + function first_child() { + if (count($this->children)>0) return $this->children[0]; + return null; + } + + // returns the last child of node + function last_child() { + if (($count=count($this->children))>0) return $this->children[$count-1]; + return null; + } + + // returns the next sibling of node + function next_sibling() { + if ($this->parent===null) return null; + $idx = 0; + $count = count($this->parent->children); + while ($idx<$count && $this!==$this->parent->children[$idx]) + ++$idx; + if (++$idx>=$count) return null; + return $this->parent->children[$idx]; + } + + // returns the previous sibling of node + function prev_sibling() { + if ($this->parent===null) return null; + $idx = 0; + $count = count($this->parent->children); + while ($idx<$count && $this!==$this->parent->children[$idx]) + ++$idx; + if (--$idx<0) return null; + return $this->parent->children[$idx]; + } + + // get dom node's inner html + function innertext() { + if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER]; + if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); + + $ret = ''; + foreach($this->nodes as $n) + $ret .= $n->outertext(); + return $ret; + } + + // get dom node's outer text (with tag) + function outertext() { + if ($this->tag==='root') return $this->innertext(); + + // trigger callback + if ($this->dom->callback!==null) + call_user_func_array($this->dom->callback, array($this)); + + if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER]; + if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); + + // render begin tag + $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup(); + + // render inner text + if (isset($this->_[HDOM_INFO_INNER])) + $ret .= $this->_[HDOM_INFO_INNER]; + else { + foreach($this->nodes as $n) + $ret .= $n->outertext(); + } + + // render end tag + if(isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END]!=0) + $ret .= 'tag.'>'; + return $ret; + } + + // get dom node's plain text + function text() { + if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER]; + switch ($this->nodetype) { + case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); + case HDOM_TYPE_COMMENT: return ''; + case HDOM_TYPE_UNKNOWN: return ''; + } + if (strcasecmp($this->tag, 'script')===0) return ''; + if (strcasecmp($this->tag, 'style')===0) return ''; + + $ret = ''; + foreach($this->nodes as $n) + $ret .= $n->text(); + return $ret; + } + + function xmltext() { + $ret = $this->innertext(); + $ret = str_ireplace('', '', $ret); + return $ret; + } + + // build node's text with tag + function makeup() { + // text, comment, unknown + if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); + + $ret = '<'.$this->tag; + $i = -1; + + foreach($this->attr as $key=>$val) { + ++$i; + + // skip removed attribute + if ($val===null || $val===false) + continue; + + $ret .= $this->_[HDOM_INFO_SPACE][$i][0]; + //no value attr: nowrap, checked selected... + if ($val===true) + $ret .= $key; + else { + switch($this->_[HDOM_INFO_QUOTE][$i]) { + case HDOM_QUOTE_DOUBLE: $quote = '"'; break; + case HDOM_QUOTE_SINGLE: $quote = '\''; break; + default: $quote = ''; + } + $ret .= $key.$this->_[HDOM_INFO_SPACE][$i][1].'='.$this->_[HDOM_INFO_SPACE][$i][2].$quote.$val.$quote; + } + } + $ret = $this->dom->restore_noise($ret); + return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>'; + } + + // find elements by css selector + function find($selector, $idx=null) { + $selectors = $this->parse_selector($selector); + if (($count=count($selectors))===0) return array(); + $found_keys = array(); + + // find each selector + for ($c=0; $c<$count; ++$c) { + if (($levle=count($selectors[0]))===0) return array(); + if (!isset($this->_[HDOM_INFO_BEGIN])) return array(); + + $head = array($this->_[HDOM_INFO_BEGIN]=>1); + + // handle descendant selectors, no recursive! + for ($l=0; $l<$levle; ++$l) { + $ret = array(); + foreach($head as $k=>$v) { + $n = ($k===-1) ? $this->dom->root : $this->dom->nodes[$k]; + $n->seek($selectors[$c][$l], $ret); + } + $head = $ret; + } + + foreach($head as $k=>$v) { + if (!isset($found_keys[$k])) + $found_keys[$k] = 1; + } + } + + // sort keys + ksort($found_keys); + + $found = array(); + foreach($found_keys as $k=>$v) + $found[] = $this->dom->nodes[$k]; + + // return nth-element or array + if (is_null($idx)) return $found; + else if ($idx<0) $idx = count($found) + $idx; + return (isset($found[$idx])) ? $found[$idx] : null; + } + + // seek for given conditions + protected function seek($selector, &$ret) { + list($tag, $key, $val, $exp, $no_key) = $selector; + + // xpath index + if ($tag && $key && is_numeric($key)) { + $count = 0; + foreach ($this->children as $c) { + if ($tag==='*' || $tag===$c->tag) { + if (++$count==$key) { + $ret[$c->_[HDOM_INFO_BEGIN]] = 1; + return; + } + } + } + return; + } + + $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0; + if ($end==0) { + $parent = $this->parent; + while (!isset($parent->_[HDOM_INFO_END]) && $parent!==null) { + $end -= 1; + $parent = $parent->parent; + } + $end += $parent->_[HDOM_INFO_END]; + } + + for($i=$this->_[HDOM_INFO_BEGIN]+1; $i<$end; ++$i) { + $node = $this->dom->nodes[$i]; + $pass = true; + + if ($tag==='*' && !$key) { + if (in_array($node, $this->children, true)) + $ret[$i] = 1; + continue; + } + + // compare tag + if ($tag && $tag!=$node->tag && $tag!=='*') {$pass=false;} + // compare key + if ($pass && $key) { + if ($no_key) { + if (isset($node->attr[$key])) $pass=false; + } + else if (!isset($node->attr[$key])) $pass=false; + } + // compare value + if ($pass && $key && $val && $val!=='*') { + $check = $this->match($exp, $val, $node->attr[$key]); + // handle multiple class + if (!$check && strcasecmp($key, 'class')===0) { + foreach(explode(' ',$node->attr[$key]) as $k) { + $check = $this->match($exp, $val, $k); + if ($check) break; + } + } + if (!$check) $pass = false; + } + if ($pass) $ret[$i] = 1; + unset($node); + } + } + + protected function match($exp, $pattern, $value) { + switch ($exp) { + case '=': + return ($value===$pattern); + case '!=': + return ($value!==$pattern); + case '^=': + return preg_match("/^".preg_quote($pattern,'/')."/", $value); + case '$=': + return preg_match("/".preg_quote($pattern,'/')."$/", $value); + case '*=': + if ($pattern[0]=='/') + return preg_match($pattern, $value); + return preg_match("/".$pattern."/i", $value); + } + return false; + } + + protected function parse_selector($selector_string) { + // pattern of CSS selectors, modified from mootools + $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is"; + preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER); + $selectors = array(); + $result = array(); + //print_r($matches); + + foreach ($matches as $m) { + $m[0] = trim($m[0]); + if ($m[0]==='' || $m[0]==='/' || $m[0]==='//') continue; + // for borwser grnreated xpath + if ($m[1]==='tbody') continue; + + list($tag, $key, $val, $exp, $no_key) = array($m[1], null, null, '=', false); + if(!empty($m[2])) {$key='id'; $val=$m[2];} + if(!empty($m[3])) {$key='class'; $val=$m[3];} + if(!empty($m[4])) {$key=$m[4];} + if(!empty($m[5])) {$exp=$m[5];} + if(!empty($m[6])) {$val=$m[6];} + + // convert to lowercase + if ($this->dom->lowercase) {$tag=strtolower($tag); $key=strtolower($key);} + //elements that do NOT have the specified attribute + if (isset($key[0]) && $key[0]==='!') {$key=substr($key, 1); $no_key=true;} + + $result[] = array($tag, $key, $val, $exp, $no_key); + if (trim($m[7])===',') { + $selectors[] = $result; + $result = array(); + } + } + if (count($result)>0) + $selectors[] = $result; + return $selectors; + } + + function __get($name) { + if (isset($this->attr[$name])) return $this->attr[$name]; + switch($name) { + case 'outertext': return $this->outertext(); + case 'innertext': return $this->innertext(); + case 'plaintext': return $this->text(); + case 'xmltext': return $this->xmltext(); + default: return array_key_exists($name, $this->attr); + } + } + + function __set($name, $value) { + switch($name) { + case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value; + case 'innertext': + if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value; + return $this->_[HDOM_INFO_INNER] = $value; + } + if (!isset($this->attr[$name])) { + $this->_[HDOM_INFO_SPACE][] = array(' ', '', ''); + $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; + } + $this->attr[$name] = $value; + } + + function __isset($name) { + switch($name) { + case 'outertext': return true; + case 'innertext': return true; + case 'plaintext': return true; + } + //no value attr: nowrap, checked selected... + return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]); + } + + function __unset($name) { + if (isset($this->attr[$name])) + unset($this->attr[$name]); + } + + // camel naming conventions + function getAllAttributes() {return $this->attr;} + function getAttribute($name) {return $this->__get($name);} + function setAttribute($name, $value) {$this->__set($name, $value);} + function hasAttribute($name) {return $this->__isset($name);} + function removeAttribute($name) {$this->__set($name, null);} + function getElementById($id) {return $this->find("#$id", 0);} + function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);} + function getElementByTagName($name) {return $this->find($name, 0);} + function getElementsByTagName($name, $idx=null) {return $this->find($name, $idx);} + function parentNode() {return $this->parent();} + function childNodes($idx=-1) {return $this->children($idx);} + function firstChild() {return $this->first_child();} + function lastChild() {return $this->last_child();} + function nextSibling() {return $this->next_sibling();} + function previousSibling() {return $this->prev_sibling();} +} + +// simple html dom parser +// ----------------------------------------------------------------------------- +class simple_html_dom { + public $root = null; + public $nodes = array(); + public $callback = null; + public $lowercase = false; + protected $pos; + protected $doc; + protected $char; + protected $size; + protected $cursor; + protected $parent; + protected $noise = array(); + protected $token_blank = " \t\r\n"; + protected $token_equal = ' =/>'; + protected $token_slash = " />\r\n\t"; + protected $token_attr = ' >'; + // use isset instead of in_array, performance boost about 30%... + protected $self_closing_tags = array('img'=>1, 'br'=>1, 'input'=>1, 'meta'=>1, 'link'=>1, 'hr'=>1, 'base'=>1, 'embed'=>1, 'spacer'=>1); + protected $block_tags = array('root'=>1, 'body'=>1, 'form'=>1, 'div'=>1, 'span'=>1, 'table'=>1); + protected $optional_closing_tags = array( + 'tr'=>array('tr'=>1, 'td'=>1, 'th'=>1), + 'th'=>array('th'=>1), + 'td'=>array('td'=>1), + 'li'=>array('li'=>1), + 'dt'=>array('dt'=>1, 'dd'=>1), + 'dd'=>array('dd'=>1, 'dt'=>1), + 'dl'=>array('dd'=>1, 'dt'=>1), + 'p'=>array('p'=>1), + 'nobr'=>array('nobr'=>1), + ); + + function __construct($str=null) { + if ($str) { + if (preg_match("/^http:\/\//i",$str) || is_file($str)) + $this->load_file($str); + else + $this->load($str); + } + } + + function __destruct() { + $this->clear(); + } + + // load html from string + function load($str, $lowercase=true) { + // prepare + $this->prepare($str, $lowercase); + // strip out comments + $this->remove_noise("''is"); + // strip out cdata + $this->remove_noise("''is", true); + // strip out '; + + $return .= ''; + $return .= ''; + #$return .= sprintf('',sprintf('%s/%s','/ab/themes/'.DEFAULT_THEME,'invoice/invoice-logo.png')); + $return .= ''; + $return .= ''; + $return .= ''; + $return .= ''; + + $return .= sprintf('', + _('Tax Invoice'),$this->getPrintInvoiceNum()); + $return .= sprintf('', + _('Issue Date'),date(UNIX_DATE_FORMAT,$this->print['invoice']['date_orig'])); + $return .= sprintf('', + _('Amount Due'),date(UNIX_DATE_FORMAT,$this->print['invoice']['due_date'])); + $return .= sprintf('', + _('Current Charges'),$C_list->format_currency_num($this->print['invoice']['total_amt'],$this->getRecordAttr('currency_id'))); + $return .= ''; + $return .= ''; + $return .= ''; + $return .= '
                    logologo'; + $return .= ''; + $return .= sprintf('',$this->print['site']['NAME']); + $return .= sprintf('', + $this->print['site']['ADDRESS'],$this->print['site']['STATE'],$this->print['site']['ZIP']); + $return .= ''; + $return .= sprintf('',$this->print['site']['TAXID']); + $return .= '
                    %s
                    %s %s %s
                     
                    %s
                    '; + $return .= '
                     
                     %s%s
                     %s%s
                     %s%s
                     %s%s
                     
                    '; + $return .= ''; + + foreach ($this->sInvoiceItems() as $index => $items) { + # Get the date range if set + if (! empty($items['date_start']) && ! empty($items['date_stop'])) { + global $C_translate; + $C_translate->value('invoice','start',date(UNIX_DATE_FORMAT,$items['date_start'])); + $C_translate->value('invoice','stop',date(UNIX_DATE_FORMAT,$items['date_stop'])); + } + + $return .= sprintf('', + $items['quantity'],$this->sLineItemDesc($index),$C_list->format_currency_num($items['price_base'],$this->getRecordAttr('currency_id'))); + + if ($items['price_setup']) + $return .= sprintf('', + $this->sLineItemDesc($index),_('Setup'),$C_list->format_currency_num($items['price_base'],$this->getRecordAttr('currency_id'))); + } + + $return .= ''; + if ($this->print['invoice']['discount_amt']) + $return .= sprintf('', + _('Discount'),$C_list->format_currency_num($this->print['invoice']['discount_amt'],$this->getRecordAttr('currency_id'))); + + if ($this->print['invoice']['tax_amt']) + $return .= sprintf('', + _('Taxes'),$C_list->format_currency_num($this->print['invoice']['tax_amt'],$this->getRecordAttr('currency_id'))); + + $return .= ''; + + $return .= sprintf('', + _('Total Due'),$C_list->format_currency_num($this->print['invoice']['total_amt'],$this->getRecordAttr('currency_id'))); + + $return .= '
                    %s%s%s
                     %s %s%s
                     
                     %s%s
                     %s%s
                     
                     %s%s
                    '; + $return .= '
                    '; + + return $return; + } + + /** + * Display a PDF invoice in the browser for download. + * + * This method can be called directly via do[]. + * + * @return string PDF Output (only if dest=>S), otherwise PDF returns an empty string. + */ + public function pdf($VAR,$object,$args=array('dest'=>'I')) { + if (! isset($this->record) && isset($VAR['id'])) + $this->sql_LoadRecord($VAR['id']); + + if (! $pdf = $this->initInvoicePDF()) + return false; + + # If we called as a do[] method, we need to set the output correctly + if (isset($VAR['_page'])) + $args = array('dest'=>'I'); + + $this->pdfInvoiceSummary($pdf); + return $pdf->Output($args['file'] ? $args['file'] : sprintf('%s.pdf',$this->getPrintInvoiceID()),$args['dest']); + } + /** * Initialise a PDF invoice * * This function is resonsible for setting up a PDF invoice */ - private function initInvoicePDF($VAR) { + private function initInvoicePDF() { # Get our invoice details - if (! $this->print = $this->initInvoicePrint($VAR)) + if (! $this->print = $this->initInvoicePrint()) return false; #@todo since the view template dynamic finds available plugins, this should also find the plugin (incase the prefix/dir is moved). require_once(sprintf('%sinvoice/PDF/pdf_invoice_%s.inc.php',PATH_MODULES,$this->print['invcfg']['invoice_pdf_plugin'])); $pdf = new pdf_invoice_overview($this); - - #@todo This should be deprecated - $null = false; - $pdf->load_setup($null); + $pdf->load_setup(); if ($pdf->getTemplate()) { $pagecount = $pdf->setSourceFile($pdf->getTemplate()); @@ -2289,22 +2164,11 @@ AND ( return $pdf; } - /** - * Display a PDF invoice in the browser for download. - */ - public function pdf($VAR) { - if (! $pdf = $this->initInvoicePDF($VAR)) - return false; - - $this->pdfInvoiceSummary($VAR['id'],$pdf); - $pdf->Output(sprintf('%s.pdf',$this->getInvoiceID()),'I'); - } - +/** HERE **/ /** Export multiple invoices */ function pdfExport(&$rs) { $db =& DB(); - $invcfg = $db->Execute(sqlSelect($db,"setup_invoice","*","")); ob_start(); $pdf = new pdf_invoice_overview(); @@ -2313,16 +2177,16 @@ AND ( $pdf->companyCity = SITE_CITY; $pdf->companyState = SITE_STATE; $pdf->companyZip = SITE_ZIP; - $pdf->load_setup($invcfg); + $pdf->load_setup(); if ($pdf->getTemplate()) $pagecount = $pdf->setSourceFile($pdf->getTemplate()); $tplidx = $pdf->ImportPage(1); while(!$rs->EOF) { $pdf->addPage(); $pdf->useTemplate($tplidx); - $this->pdfInvoiceSummary($rs->fields['id'], $pdf); - $rs->MoveNext(); - unset($pdf->itemsSummary); + $this->pdfInvoiceSummary($pdf); + $rs->MoveNext(); + unset($pdf->itemsSummary); } $pdf->Output(); ob_end_flush(); @@ -2330,10 +2194,11 @@ AND ( /** * Render an invoice with the summary page + * * @todo Draw discounts * @todo Draw tax details */ - private function pdfInvoiceSummary($id,$pdf) { + private function pdfInvoiceSummary($pdf) { # Invoice details: $db = &DB(); @@ -2342,7 +2207,7 @@ AND ( $pdf->drawCompanyAddress($this); $pdf->drawInvoiceHeader($this); - $pdf->drawNews($this->print['invcfg']['news']); + $pdf->drawNews($this->print['invcfg']['news']); $pdf->drawRemittenceStub($this); $pdf->drawPaymentMethods($this); @@ -2351,8 +2216,8 @@ AND ( elseif($this->print['invoice']['billing_status'] == 1) $pdf->drawInvoicePaidNotice(); - if ($this->getPreviousBalance()) - $pdf->drawSummaryInvoicesDue($this->print['previousinvoices']); + if ($this->sPreviousBalance()) + $pdf->drawSummaryInvoicesDue($this->sPreviousInvoices()); $pdf->drawSummaryLineItems($this); unset($pdf->itemsSummary); @@ -2360,74 +2225,82 @@ AND ( # BEGIN loop for enumerating information in multiple ways on the invoice $iteration = 0; while ($pdf->drawLineItems_pre($iteration)) { - # Get the line items: - $items = $db->Execute(sqlSelect($db,'invoice_item','*',array('invoice_id'=>$this->getInvoiceNum()))); - if ($items && $items->RecordCount()) { - while (! $items->EOF) { - # Get the date range if set - if (! empty($items->fields['date_start']) && ! empty($items->fields['date_stop'])) { - global $C_translate; - $C_translate->value('invoice','start',date(UNIX_DATE_FORMAT,$items->fields['date_start'])); - $C_translate->value('invoice','stop',date(UNIX_DATE_FORMAT,$items->fields['date_stop'])); - } + foreach ($this->sInvoiceItems() as $index => $items) { + # Get the date range if set + if (! empty($items['date_start']) && ! empty($items['date_stop'])) { + global $C_translate; + $C_translate->value('invoice','start',date(UNIX_DATE_FORMAT,$items['date_start'])); + $C_translate->value('invoice','stop',date(UNIX_DATE_FORMAT,$items['date_stop'])); + } - $cost = $items->fields['price_base']; - $total = $cost * $items->fields['quantity']; - $desc = $this->getLineItemDesc($items->fields['sku'],$items->fields['product_id'],strtolower($items->fields['domain_name'].'.'.$items->fields['domain_tld']),$items->fields['product_name']); + $line = array( + 'name'=>$this->sLineItemDesc($index), + 'domain'=>$items['domain_name'], + 'amount'=>$items['price_base'], + 'sku'=>$items['sku'], + 'qty'=>$items['quantity'], + 'cost'=>$items['price_base'], + 'attr'=>$items['product_attr'], + 'price_type'=>$items['price_type'], + 'price_base'=>$items['price_base'], + 'item_type'=>$items['item_type'], + 'total_amt'=>$items['total_amt'] + ); + + if ($items['date_start'] && $items['date_stop']) + if ($items['date_start'] == $items['date_stop']) + $line['daterange'] = sprintf('%s',date(UNIX_DATE_FORMAT,$items['date_start'])); + else + $line['daterange'] = sprintf('%s - %s',date(UNIX_DATE_FORMAT,$items['date_start']),date(UNIX_DATE_FORMAT,$items['date_stop'])); + + $pdf->drawLineItems($db,$line,$this->getRecordAttr('id')); + + if ($items['price_setup']) { $line = array( - 'name' => $desc, - 'domain' => $items->fields['domain_name'], - 'amount' => $cost, - 'sku'=>$items->fields['sku'], - 'qty'=>$items->fields['quantity'], - 'cost'=>$cost, - 'attr'=>$items->fields['product_attr'], - 'price_type'=>$items->fields['price_type'], - 'price_base'=>$items->fields['price_base'], - 'item_type'=>$items->fields['item_type'], - 'daterange'=>sprintf('%s - %s',date(UNIX_DATE_FORMAT,$items->fields['date_start']),date(UNIX_DATE_FORMAT,$items->fields['date_stop'])), - 'total_amt'=>$items->fields['total_amt'] + 'name'=>sprintf('%s - %s',$this->sLineItemDesc($index),_('Setup Charge')), + 'amount'=>$items['price_setup'], + 'qty'=>'1', + 'sku'=>$items['sku'], + 'cost'=>$items['price_setup'], + 'price_base'=>$items['price_setup'], + 'price_type'=>999 ); - $pdf->drawLineItems($db,$line,$this->getInvoiceNum()); - - if ($items->fields['price_setup']) { - $desc .= ' Set-up Charge'; - $total = $items->fields['price_setup']; - $line = array('name'=>$desc,'amount'=>$total,'qty'=>'1','sku'=>$items->fields['sku'],'cost'=>$total,'price_base'=>$total,'price_type'=>999); - $pdf->drawLineItems($db,$line,$this->getInvoiceNum()); - } - - $items->MoveNext(); + $pdf->drawLineItems($db,$line,$this->getRecordAttr('id')); } } if ($this->print['invoice']['discount_amt']) { - $desc = 'Discount'; - $total = -($this->print['invoice']['discount_amt']); - $line = array('name'=>$desc,'amount'=>$total,'qty'=>'1','cost'=>$total,'price_base'=>$total,'price_type'=>999); - $pdf->drawLineItems($db,$line,$this->getInvoiceNum()); + $line = array( + 'name'=>_('Discount'), + 'amount'=>-($this->print['invoice']['discount_amt']), + 'qty'=>'1', + 'cost'=>-($this->print['invoice']['discount_amt']), + 'price_base'=>-($this->print['invoice']['discount_amt']), + 'price_type'=>999); + + $pdf->drawLineItems($db,$line,$this->getRecordAttr('id')); } if ($this->print['invoice']['tax_amt']) { - $trs = $db->Execute(sqlSelect($db,array('invoice_item_tax','tax'),'A.amount,B.description',sprintf('A.tax_id=B.id AND A.invoice_id=%s',$this->getInvoiceNum()))); - if ($trs && $trs->RecordCount()) { - $taxes = array(); + $rs = $db->Execute(sqlSelect($db,array('invoice_item_tax','tax'),'A.amount,B.description',sprintf('A.tax_id=B.id AND A.invoice_id=%s',$this->getRecordAttr('id')))); + if ($rs && $rs->RecordCount()) { + $taxes = array(); - while (! $trs->EOF) { - if (! isset($taxes[$trs->fields['description']])) - $taxes[$trs->fields['description']] = $trs->fields['amount']; + while (! $rs->EOF) { + if (! isset($taxes[$rs->fields['description']])) + $taxes[$rs->fields['description']] = $rs->fields['amount']; else - $taxes[$trs->fields['description']] += $trs->fields['amount']; + $taxes[$rs->fields['description']] += $rs->fields['amount']; - $trs->MoveNext(); - } + $rs->MoveNext(); + } - foreach ($taxes as $txds=>$txamt) { + foreach ($taxes as $txds => $txamt) { $line = array('name'=>$txds,'amount'=>$txamt,'total_amt'=>$txamt,'price_type'=>999); - $pdf->drawLineItems($db,$line,$this->getInvoiceNum()); - } - } + $pdf->drawLineItems($db,$line,$this->getRecordAttr('id')); + } + } } # Increment the iteration @@ -2436,92 +2309,39 @@ AND ( # Custom functions: $pdf->drawCustom(); - unset($db); } - - /** RESEND DUE NOTICE - */ - function resend($VAR) - { - global $C_debug; - - # User invoice creation confirmation - include_once(PATH_MODULES.'email_template/email_template.inc.php'); - $mail = new email_template; - $mail->send('invoice_resend', $VAR['account_id'], $VAR['id'], '', ''); - - # Alert - $C_debug->alert('Sent payment due notice to user'); - - # Update invoice - $db = &DB(); - $q = "SELECT notice_count FROM ".AGILE_DB_PREFIX."invoice WHERE - id = ".$db->qstr($VAR['id'])." AND - site_id = ".$db->qstr(DEFAULT_SITE); - $rs = $db->Execute($q); - $count = $rs->fields['notice_count'] + 1; - $q = "UPDATE ".AGILE_DB_PREFIX."invoice SET - notice_count = ".$db->qstr($count)." WHERE - id = ".$db->qstr($VAR['id'])." AND - site_id = ".$db->qstr(DEFAULT_SITE); - $rs = $db->Execute($q); - } - - /** * Generate all invoices for recurring services/charges/domains */ - public function generate() { - # Check if charge module installed + public function task_GenerateRecurrInvoices() { global $C_list; - $isChargeInstalled = $C_list->is_installed('charge'); - // get services to be billed grouped by account and date - if (! defined('MAX_INV_GEN_PERIOD') || MAX_INV_GEN_PERIOD <= 0) - $max_date = time()+86400; - else - $max_date = time()+(MAX_INV_GEN_PERIOD*86400); + $db = &DB(); - #$p=AGILE_DB_PREFIX; $s=DEFAULT_SITE; -/* - $sql = "SELECT DISTINCT service.id as serviceId, account.id as accountId, invoice.id as invoiceId, from_unixtime(service.date_next_invoice,'%Y-%m-%d') as dayGroup - FROM {$p}service as service - JOIN {$p}account as account ON ( service.account_id=account.id and account.site_id={$s} ) - LEFT JOIN {$p}invoice as invoice ON ( service.invoice_id=invoice.id and invoice.site_id={$s} ) - WHERE service.site_id={$s} - AND service.active = 1 - AND ( service.suspend_billing IS NULL OR service.suspend_billing = 0 ) - AND ( service.date_next_invoice > 0 AND service.date_next_invoice IS NOT NULL ) - AND - (( - (account.invoice_advance_gen!='' OR account.invoice_advance_gen is not null) AND service.date_next_invoice <= (UNIX_TIMESTAMP(CURDATE())+(account.invoice_advance_gen*86400)) - ) OR ( - (account.invoice_advance_gen='' OR account.invoice_advance_gen is null) AND service.date_next_invoice <= {$max_date} - )) - ORDER BY accountId, dayGroup, serviceId"; -*/ - $db=&DB(); - $rs = $db->Execute($sql = $this->sql_invoice_soon()); + $rs = $db->Execute($this->sql_InvoiceSoon()); if (! $rs) { global $C_debug; $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); - } elseif($rs->RecordCount()) { + # There are invoices. + } elseif ($rs->RecordCount()) { $ids = ''; $account = ''; $date = ''; $invoice = ''; + # Group all the service IDs and generate one invoice for all services. while (! $rs->EOF) { - if ($ids && (($rs->fields['aid'] != $account) || ($rs->fields['invoice_date'] != $date))) { - $this->generateInvoices($ids,$account,$invoice,$isChargeInstalled); + if ($ids && (($rs->fields['account_id'] != $account) || ($rs->fields['invoice_date'] != $date))) { + $io = new invoice; + $io->generateInvoice($ids,$invoice); $ids = ''; } # Set the current account and date - $account = $rs->fields['aid']; + $account = $rs->fields['account_id']; $invoice = $rs->fields['iid']; $date = $rs->fields['invoice_date']; @@ -2534,11 +2354,13 @@ AND ( $rs->MoveNext(); } - if ($ids) - $this->generateInvoices($ids,$account,$invoice,$isChargeInstalled); + if ($ids) { + $io = new invoice; + $io->generateInvoice($ids,$invoice); + } } - // Generate invoices for any domains expiring in X days. + # Generate invoices for any domains expiring in X days. if ($C_list->is_installed('host_tld')) $this->generateDomains(); @@ -2549,10 +2371,8 @@ AND ( # Check if charge module installed global $C_list; - $charge_installed = $C_list->is_installed('charge'); - $db = &DB(); - $rs = $db->Execute($q = $this->sql_invoice_soon(null,0,$VAR['account_id'])); + $rs = $db->Execute($this->sql_InvoiceSoon(null,0,$VAR['account_id'])); if (! $rs) { global $C_debug; @@ -2568,7 +2388,8 @@ AND ( while (! $rs->EOF) { if ($ids && ($rs->fields['invoice_date'] != $date)) { - $this->generateInvoices($ids,$VAR['account_id'],$invoice,$charge_installed); + $io = new invoice; + $io->generateInvoice($ids,$invoice); $ids = ''; } @@ -2580,29 +2401,34 @@ AND ( $rs->MoveNext(); } + $io = new invoice; if ($ids) - $this->generateInvoices($ids,$VAR['account_id'],$invoice,$charge_installed); + $io->generateInvoice($ids,$invoice); if (isset($VAR['_page_next'])) define('REDIRECT_PAGE','?_page='.$VAR['_page_next']); } /** - * Generate an Invoice + * Generate an Invoice for the service Ids */ - private function generateInvoices($ids,$account_id,$invoice_id,$charge_installed=false) { - if (empty($ids)) + private function generateInvoice($sids,$piid) { + global $C_list; + + # If there are no service ID's, we'll just return + if (empty($sids)) return false; # Load required elements + include_once(PATH_MODULES.'account/account.inc.php'); include_once(PATH_MODULES.'service/service.inc.php'); - $serviceObj = new service; + include_once(PATH_MODULES.'product/product.inc.php'); - include_once(PATH_MODULES.'discount/discount.inc.php'); - $discountObj = new discount; - - include_once(PATH_MODULES.'tax/tax.inc.php'); - $taxObj = new tax; + $afo = false; + if ($C_list->is_installed('account_fee')) { + include_once(PATH_MODULES.'account_fee/account_fee.inc.php'); + $afo = new account_fee; + } # Start a transaction $db = &DB(); @@ -2620,262 +2446,88 @@ AND ( } } - # Generate an invoice id - $invoice = sqlGenID($db,'invoice'); + # Start + $this->clearRecord(); - # Check for any discounts for the parent invoice or account_id - # applied at checkout and should continue to be applied if recurring type discount - $discountObj->available_discounts($account_id,1,$invoice_id); + # Generate an invoice id + $this->setRecordAttr('id',sqlGenID($db,'invoice')); # Beginning totals - $sub_total = 0; - $total = 0; - $taxable_amount = 0; - $tax_amt = 0; - $discount_amt = 0; + $invoice = array(); + $invoice['recur_schedules'] = array(); - # Get the full account and service and invoice details - $p=AGILE_DB_PREFIX; $s=DEFAULT_SITE; - $sql = "SELECT DISTINCT - service.id, service.parent_id, service.invoice_id, service.invoice_item_id, service.account_id, service.account_billing_id, service.product_id, - service.sku, service.active, service.bind, service.type, service.price, service.price_type, service.taxable, service.date_last_invoice, service.date_next_invoice, - service.recur_type, service.recur_schedule, service.recur_weekday, service.recur_week, service.domain_name, - service.domain_tld, service.domain_type, service.domain_term, service.prod_attr, service.prod_attr_cart, - account.currency_id, account.first_name, account.last_name, account.country_id, account.state, account.invoice_grace, account.invoice_advance_gen, account.affiliate_id as account_affiliate_id, - invoice.affiliate_id, invoice.campaign_id, invoice.reseller_id, invoice.checkout_plugin_id, invoice.checkout_plugin_data, invoice.billed_currency_id, invoice.actual_billed_currency_id - FROM {$p}service as service - JOIN {$p}account as account ON (service.account_id=account.id AND account.site_id={$s}) - LEFT JOIN {$p}invoice as invoice ON (service.invoice_id=invoice.id AND invoice.site_id={$s}) - WHERE service.id in ({$ids})"; + foreach (explode(',',$sids) as $sid) { + $so = new service($sid); + $po = new product($so->getRecordAttr('product_id')); - $service = $db->Execute($sql); - if ($service === false) { - global $C_debug; + if (! isset($ao)) { + $ao = new account($so->getRecordAttr('account_id')); - $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); - $db->FailTrans(); + $this->setRecordAttr('account_id',$so->getRecordAttr('account_id')); + $this->setRecordAttr('account_billing_id',$so->getRecordAttr('account_billing_id')); + $this->setRecordAttr('billed_currency_id',$ao->getRecordAttr('currency_id')); + $this->setRecordAttr('actual_billed_currency_id',DEFAULT_CURRENCY); + $this->setRecordAttr('reseller_id',$ao->getRecordAttr('reseller_id')); + $this->setRecordAttr('checkout_plugin_id',$ao->getRecordAttr('checkout_plugin_id')); + $this->setRecordAttr('checkout_plugin_data',$ao->getRecordAttr('checkout_plugin_data')); + $this->setRecordAttr('grace_period',$ao->getRecordAttr('invoice_grace')); - return false; - } + # @todo this may unintentially allocate all service revenue to an affiliate, which should be configurable (not just the service that the account signed up for initially) + $this->setRecordAttr('affiliate_id',$ao->getRecordAttr('affiliate_id')); - if ($service && $service->RecordCount()) { - while (! $service->EOF) { - if (empty($service->fields['billed_currency_id'])) - $service->fields['billed_currency_id'] = DEFAULT_CURRENCY; - if (empty($service->fields['actual_billed_currency_id'])) - $service->fields['actual_billed_currency_id'] = $service->fields['billed_currency_id']; - - $this->account_id = $service->fields['account_id']; - $this->parent_id = $service->fields['invoice_id']; - $this->account_billing_id = $service->fields['account_billing_id']; - - if (! empty($service->fields['account_affiliate_id'])) - $this->affiliate_id = $service->fields['account_affiliate_id']; - else - $this->affiliate_id = $service->fields['affiliate_id']; - - $this->campaign_id = $service->fields['campaign_id']; - $this->reseller_id = $service->fields['reseller_id']; - $this->checkout_plugin_id = $service->fields['checkout_plugin_id']; - $this->checkout_plugin_data = $service->fields['checkout_plugin_data']; - $this->billed_currency_id = $service->fields['billed_currency_id']; - $this->actual_billed_currency_id = $service->fields['actual_billed_currency_id']; - $this->invoice_grace = $service->fields['invoice_grace']; - - $item_tax_amt = 0; - $item_total_amt = 0; - $item_discount_amt = 0; - - # Gen item_id - $item = sqlGenID($db,'invoice_item'); - - # Calculate any recurring discounts for this item - $item_total_amt = $service->fields['price']; - $item_discount_amt = $discountObj->calc_all_discounts(1,$item,$service->fields['product_id'],$service->fields['price'],$service->fields['account_id'],$sub_total+$service->fields['price']); - $item_total_amt -= $item_discount_amt; - $sub_total += $item_total_amt; - $discount_amt += $item_discount_amt; - - # Calculate any taxes for this item - if ($service->fields['taxable'] == 1) { - $item_tax_amt = 0; - $item_tax_arr = $taxObj->calculate($item_total_amt,$service->fields['country_id'],$service->fields['state']); - - if (is_array($item_tax_arr)) - foreach($item_tax_arr as $tx) - $item_tax_amt += $tx['rate']; - - $tax_amt += $item_tax_amt; - } - - # Calculate next invoice date - $next_invoice = $serviceObj->calcNextInvoiceDate($service->fields['date_next_invoice'],$service->fields['recur_schedule'],$service->fields['recur_type'],$service->fields['recur_weekday']); - $due_date = $service->fields['date_next_invoice']; - - $recur_schedule = 0; - if (! empty($service->fields['recur_schedule'])) - $recur_schedule = $service->fields['recur_schedule']; - - # Create the invoice item - $itemrs = $db->Execute(sqlInsert($db,'invoice_item',array( - 'date_orig'=>time(), - 'invoice_id'=>$invoice, - 'account_id'=>$service->fields['account_id'], - 'service_id'=>$service->fields['id'], - 'product_id'=>$service->fields['product_id'], - 'product_attr'=>$service->fields['prod_attr'], - 'product_attr_cart'=>$service->fields['prod_attr_cart'], - 'sku'=>$service->fields['sku'], - 'quantity'=>1, - 'item_type'=>0, - 'price_type'=>$service->fields['price_type'], - 'price_base'=>$service->fields['price'], - 'price_setup'=>0, - 'recurring_schedule'=>$recur_schedule, - 'date_start'=>$service->fields['date_next_invoice'], - 'date_stop'=>$next_invoice, - 'domain_name'=>$service->fields['domain_name'], - 'domain_tld'=>$service->fields['domain_tld'], - 'domain_type'=>$service->fields['domain_type'], - 'tax_amt'=>$tax_amt, - 'total_amt'=>$item_total_amt, - 'discount_amt'=>$item_discount_amt - ),$item)); - - if ($itemrs === false) { - global $C_debug; - - $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); - $db->FailTrans(); - - return false; - } - - # Insert tax records - $taxObj->invoice_item($invoice,$item,$service->fields['account_id'],@$item_tax_arr); - - # Insert discount records - $discountObj->invoice_item($invoice,$item,$service->fields['account_id'],@$discountObj->discount_arr); - - # Update the last & next invoice date for this service - $srvsrs = $db->Execute(sqlUpdate($db,'service',array('date_last_invoice'=>$service->fields['date_next_invoice'],'date_next_invoice'=>$next_invoice),array('id'=>$service->fields['id']))); - if ($srvsrs === false) { - global $C_debug; - - $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); - $db->FailTrans(); - - return false; - } - - # Get any charges for this service and create them as invoice items - if ($charge_installed) { - $sql = "SELECT * FROM ".AGILE_DB_PREFIX."charge WHERE (status=0 or status is null) and site_id=".DEFAULT_SITE." AND service_id = ".$service->fields['id']." AND date_orig < ". $service->fields['date_next_invoice']; - $charge = $db->Execute($sql); - if($charge && $charge->RecordCount()) { - while(!$charge->EOF) { - $item_tax_amt=0; - $item_total_amt=0; - $item_discount_amt=0; - - // Calculate any recurring discounts for this charge item - $item_total_amt = ($charge->fields['quantity']*$charge->fields['amount']); - $item_discount_amt = $discountObj->calc_all_discounts(1, $item, $charge->fields['product_id'], $item_total_amt, $service->fields['account_id'], $sub_total+$item_total_amt); - $item_total_amt -= $item_discount_amt; - $sub_total += $item_total_amt; - $discount_amt += $item_discount_amt; - - // calculate any taxes for this item - if($charge->fields['taxable'] == 1) { - $item_tax_amt=0; - $item_tax_arr = $taxObj->calculate($chargeamt, $service->fields['country_id'], $service->fields['state']); - if(is_array($item_tax_arr)) foreach($item_tax_arr as $tx) $item_tax_amt += $tx['rate']; - $tax_amt += $item_tax_amt; - } - - // create the invoice item - $charge_item_id = sqlGenID($db, 'invoice_item'); - - $sql = "INSERT INTO {$p}invoice_item SET - id = $charge_item_id, - site_id = $s, - charge_id = {$charge->fields['id']}, - date_orig = ".time().", - invoice_id = $invoice, - account_id = ".$this->account_id.", - service_id = ".$db->qstr($service->fields['id']).", - product_id = ".$db->qstr($charge->fields['product_id']).", - product_attr= ".$db->qstr($charge->fields['attributes']).", - sku = ".$db->qstr($service->fields['sku']).", - price_base = ".$db->qstr($charge->fields['amount']).", - quantity = ".$charge->fields['quantity'].", - item_type = 5, - price_type = 0, - price_setup = 0, - tax_amt = $item_tax_amt, - total_amt = $item_total_amt, - discount_amt= $item_discount_amt"; - $itemrs=$db->Execute($sql); - if($itemrs === false) {global $C_debug; $C_debug->error('invoice.inc.php','generateInvoices()4', $sql . " \r\n\r\n " . @$db->ErrorMsg()); $db->FailTrans(); return false; } - - # Insert tax records - $taxObj->invoice_item($invoice, $charge_item_id, $charge->fields['account_id'], @$item_tax_arr); - - # Insert discount records - $discountObj->invoice_item($invoice, $charge_item_id, $charge->fields['account_id'], @$discountObj->discount_arr); - - # update charge status - $chargers=$db->Execute("UPDATE ".AGILE_DB_PREFIX."charge set status=1 WHERE id={$charge->fields['id']} AND site_id=".DEFAULT_SITE); - if($chargers === false) {global $C_debug; $C_debug->error('invoice.inc.php','generateInvoices()2', $sql . " \r\n\r\n " . @$db->ErrorMsg()); $db->FailTrans(); return false; } - - $charge->MoveNext(); - } - } - } - $service->MoveNext(); + # @todo the parent invoice should bring this campaign id. + $this->setRecordAttr('campaign_id',null); } - # Add any taxes - $total = $sub_total+$tax_amt; + $this->setRecordAttr('due_date',$so->getRecordAttr('date_next_invoice')); - # Get invoice grace period from global/account - if (! empty($this->invoice_grace)) - $grace_period = $this->invoice_grace; - else - $grace_period = GRACE_PERIOD; + $last_invoice = $so->getRecordAttr('date_next_invoice'); + $next_invoice = $so->getRecordAttr('date_next_invoice'); - $invoicers = $db->Execute($a=sqlInsert($db,'invoice',array( - 'date_orig'=>time(), - 'date_last'=>time(), - 'notice_next_date'=>time(), - 'type'=>1, - 'process_status'=>0, - 'billing_status'=>0, - 'suspend_billing'=>0, - 'print_status'=>0, - 'refund_status'=>0, - 'billed_amt'=>0, - 'actual_billed_amt'=>0, - 'notice_count'=>0, - 'parent_id'=>$this->parent_id, - 'account_id'=>$this->account_id, - 'account_billing_id'=>$this->account_billing_id, - 'affiliate_id'=>$this->affiliate_id, - 'campaign_id'=>$this->campaign_id, - 'reseller_id'=>$this->reseller_id, - 'checkout_plugin_id'=>$this->checkout_plugin_id, - 'checkout_plugin_data'=>$this->checkout_plugin_data, - 'actual_billed_currency_id'=>$this->actual_billed_currency_id, - 'billed_currency_id'=>$this->billed_currency_id, - 'notice_max'=>MAX_BILLING_NOTICE, - 'grace_period'=>$grace_period, - 'tax_amt'=>$tax_amt, - 'discount_amt'=>$discount_amt, - 'total_amt'=>$total, - 'due_date'=>$due_date - ),$invoice)); + while ($next_invoice < (time()+($this->sInvoiceDays()*86400))) { + if ($po->getRecord()) { + $billdates = $po->recurrDates($so->getRecordAttr('recur_schedule'),$so->getRecordAttr('recur_weekday'),null,$next_invoice); + $next_invoice = $billdates['end']; + $x = $billdates['end']; - if ($invoicers === false) { + } else { + $x = $next_invoice; + $next_invoice = $so->calcNextInvoiceDate( + $last_invoice,$so->getRecordAttr('recur_schedule'),$so->getRecordAttr('recur_type'),$so->getRecordAttr('recur_weekday')); + } + + $iid = $this->aaddItem(array( + 'charge_id'=>null, + 'date_start'=>$last_invoice, + 'date_stop'=>$next_invoice, + 'domain_name'=>$so->getRecordAttr('domain_name'), + 'domain_tld'=>$so->getRecordAttr('domain_tld'), + 'domain_type'=>$so->getRecordAttr('domain_type'), + 'domain_term'=>$so->getRecordAttr('domain_term'), + 'item_type'=>0, + 'price_setup'=>0, + 'price_base'=>$so->getRecordAttr('price'), + 'price_type'=>$so->getRecordAttr('price_type'), + 'product_id'=>$so->getRecordAttr('product_id'), + 'product_attr'=>$so->getRecordAttr('prod_attr'), + 'product_attr_cart'=>null, + 'quantity'=>1, + 'recurring_schedule'=>$so->getRecordAttr('recur_schedule'), + 'service_id'=>$so->getRecordAttr('id'), + 'type'=>$so->getRecordAttr('type') + )); + + $last_invoice = $x; + } + + array_push($invoice['recur_schedules'],$so->getRecordAttr('recur_schedule')); + + # Update the last & next invoice date for this service + $rs = $db->Execute(sqlUpdate($db,'service', + array('date_last_invoice'=>$so->getRecordAttr('date_next_invoice'),'date_next_invoice'=>$next_invoice), + array('id'=>$so->getRecordAttr('id')))); + + if (! $rs) { global $C_debug; $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); @@ -2883,6 +2535,108 @@ AND ( return false; } + + # Get any charges for this service and create them as invoice items + if ($C_list->is_installed('charge')) { + include_once(PATH_MODULES.'charge/charge.inc.php'); + + $co = new charge(); + + foreach ($co->sql_GetRecords( + array('where'=>sprintf('(status=0 OR status IS NULL) AND service_id=%s', + $so->getRecordAttr('id'),$so->getRecordAttr('date_next_invoice')))) as $record) { + + $iid = $this->aaddItem(array( + 'charge_id'=>$record['id'], + 'date_start'=>$record['date_orig'], + 'date_stop'=>$record['date_orig'], + 'domain_name'=>null, + 'domain_tld'=>null, + 'domain_type'=>null, + 'domain_term'=>null, + 'item_type'=>5, + 'price_setup'=>0, + 'price_base'=>$record['amount'], + 'price_type'=>3, + 'product_id'=>$record['product_id'], + 'product_name'=>$record['description'], + 'product_attr'=>$record['attributes'], + 'product_attr_cart'=>null, + 'quantity'=>$record['quantity'], + 'recurring_schedule'=>null, + 'service_id'=>$so->getRecordAttr('id'), + 'sku'=>$record['sku'] + )); + + # Update charge status + $rs = $db->Execute(sqlUpdate($db,'charge',array('status'=>1),array('id'=>$record['id']))); + + if (false && ! $rs) { + global $C_debug; + + $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); + $db->FailTrans(); + + return false; + } + } + } + } + + # See if there is an account fee for this invoice + if ($afo && count($invoice['recur_schedules'])) { + foreach ($invoice['recur_schedules'] as $recur_schedule) { + include_once(PATH_MODULES.'invoice_item/invoice_item.inc.php'); + $ito = new invoice_item(); + + if ($fee = $afo->sAccountFee($ao->getRecordAttr('id'),$recur_schedule)) { + # Create the invoice item + $ito->setRecordAttr('charge_id',null); + $ito->setRecordAttr('invoice_id',$this->getRecordAttr('id')); + $ito->setRecordAttr('account_id',$ao->getRecordAttr('id')); + $ito->setRecordAttr('service_id',null); + $ito->setRecordAttr('product_id',null); + $ito->setRecordAttr('product_attr',null); + $ito->setRecordAttr('product_name',_('Account Fee')); + $ito->setRecordAttr('sku','ACCOUNT_FEE'); + $ito->setRecordAttr('quantity',1); + $ito->setRecordAttr('item_type',6); + $ito->setRecordAttr('price_type',0); + $ito->setRecordAttr('price_base',$fee); + $ito->setRecordAttr('price_setup',0); + $ito->setRecordAttr('discount_amt',0); + $ito->setRecordAttr('recurring_schedule',$recur_schedule); + } + } + } + + # Add any taxes + # Get invoice grace period from global/account + if (! empty($this->invoice_grace)) + $grace_period = $this->invoice_grace; + else + $grace_period = GRACE_PERIOD; + + $this->setRecordAttr('notice_next_date',time()); + $this->setRecordAttr('billing_status',0); + $this->setRecordAttr('print_status',0); + $this->setRecordAttr('process_status',0); + $this->setRecordAttr('status',1); +// $this->setRecordAttr('suspend_billing',0); + $this->setRecordAttr('billed_amt',0); + $this->setRecordAttr('actual_billed_amt',0); + $this->setRecordAttr('notice_count',0); + $this->setRecordAttr('type',1); + $this->setRecordAttr('notice_max',MAX_BILLING_NOTICE); + $rs = $this->sql_SaveRecord(true); + + if (! $rs) { + global $C_debug; + + $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); + $db->FailTrans(); + + return false; } if (AGILE_DB_TYPE == 'mysqlt') @@ -2956,7 +2710,7 @@ AND ( $rs = $db->Execute(sqlSelect($db, 'account', '*', " id = {$service['account_id']} ", "")); $account = $rs->fields; - # Get the account price + # Get the account price include_once(PATH_MODULES.'host_tld/host_tld.inc.php'); $tldObj=new host_tld; $tld_arr = $tldObj->price_tld_arr($service['domain_tld'], 'renew', false, false, false, $service['account_id']); @@ -3054,8 +2808,6 @@ AND ( } } - - /** Run AutoBilling and Due Notices */ function autobill($VAR) @@ -3251,7 +3003,7 @@ AND ( # overdue - cancel services $vara['id'] = $invoice->fields['id']; - $this->voidInvoice($vara, $this); + $this->pVoid($invoice->fields['id']); # suspend billing activity $sql = 'UPDATE ' . AGILE_DB_PREFIX . 'invoice SET @@ -3305,8 +3057,8 @@ AND ( return false; $total = 0; - foreach ($this->unpaid(SESS_ACCOUNT) as $amount) - $total += $amount; + foreach ($this->sInvoicesBal(SESS_ACCOUNT) as $details) + $total += $details['balance']; if ($total) $smarty->assign('has_unpaid',$C_list->format_currency_num($total,SESS_CURRENCY)); @@ -3332,10 +3084,10 @@ AND ( # Get invoice totals $total = 0; - $rs = $db->Execute(sqlSelect($db,'invoice','id,total_amt,billed_amt',sprintf('%s account_id=%s AND billing_status=0 AND refund_status=0',$id_list,SESS_ACCOUNT))); + $rs = $db->Execute(sqlSelect($db,'invoice','id,total_amt,billed_amt,credit_amt',sprintf('%s account_id=%s AND billing_status=0 AND (refund_status=0 OR refund_status IS NULL) AND status=1',$id_list,SESS_ACCOUNT))); if ($rs && $rs->RecordCount()) { while (! $rs->EOF) { - $this->invoice[$rs->fields['id']] = $rs->fields['total_amt']-$rs->fields['billed_amt']; + $this->invoice[$rs->fields['id']] = $rs->fields['total_amt']-$rs->fields['billed_amt']-$rs->fields['credit_amt']; $total += $this->invoice[$rs->fields['id']]; $rs->MoveNext(); } @@ -3379,7 +3131,7 @@ AND ( include_once(PATH_MODULES.'checkout/checkout.inc.php'); $checkout = new checkout; - $checkoutoptions = $checkout->get_checkout_options(SESS_ACCOUNT,$total,false,$account->fields['country_id'],true); + $checkoutoptions = $checkout->get_checkout_options(SESS_ACCOUNT,$total,false,true); # Get a temporary id (48 hours) $id = sqlGenID($db,'temporary_data'); @@ -3401,7 +3153,6 @@ AND ( } } - /** * Make a payment now */ @@ -3576,7 +3327,7 @@ AND ( # Submit the invoice for approval $arr['id'] = $this->invoice_id; - $this->approveInvoice($arr, $this); + $this->pApprove($this->invoice_id); } } else { @@ -3599,7 +3350,7 @@ AND ( } # Admin e-mail alert of manual payment processing - if ( $PLG->name == 'MANUAL' ) { + if ( $PLG->getName() == 'MANUAL' ) { $date_due = $C_list->date(time()); foreach($this->invoice as $this->invoice_id) { $email = new email_template; @@ -3612,436 +3363,137 @@ AND ( } } + /** GENERIC INVOICE METHODS **/ + /** - * Create modified array for invoice summarization + * Return a list of accounts with their current outsanding invoices balance * - * This function will summarise the invoice items based on the same - * SKU, BASE_PRICE, SETUP_PRICE & PRODUCT_ATTR - */ - public function summarizeLineItems($smart_items) { - //$ignore['SKU']=true; - $sum = array(); - - if (is_array($smart_items)) { - foreach ($smart_items as $it) { - # Unique line item - if (! isset($sum[$it['sku']])) { - if (! isset($ignore[$it['sku']])) - $sum[$it['sku']] = array($it); - $sum[$it['sku']][0]['summaryname'] = $this->getLineItemDesc($it['sku'],$it['product_id'],false,$it['sku'] ? false : $it['product_name']); - - } else { - # Is unique price/attributes? - $unique = true; - foreach ($sum[$it['sku']] as $sid => $flds) { - if ($flds['price_base'] == $it['price_base'] && - $flds['price_setup'] == $it['price_setup'] && - $flds['product_attr'] == $it['product_attr']) { - - $sum[$it['sku']][$sid]['quantity'] += 1; - $unique = false; - break; - } - } - - # Unique line item - if ($unique) { - $a = count($sum[$it['sku']]); - array_push($sum[$it['sku']],$it); - $sum[$it['sku']][$a]['summaryname'] = $this->getLineItemDesc($it['sku'],$it['product_id'],false,$it['sku'] ? false : $it['product_name']); - } - } - } - } - - if (count($sum)) { - $smart_items = array(); - foreach ($sum as $sku => $item) - foreach ($item as $sitem) - array_push($smart_items,$sitem); - - return $smart_items; - } - } - - /** - * View an Invoice - * Shown both in the admin pages and after checkout - * - * @uses net_term + * @return array List of Accounts and their current balance */ - public function view($VAR) { - global $C_translate,$C_list; + public function sAccountsBal() { + static $sAccountBal = array(); - $db = &DB(); + if (! count($sAccountBal)) { + $db = &DB(); - if ($smart = parent::view($VAR)) { - # Get the product checkout plugin name - if (! empty($smart['checkout_plugin_id'])) { - $cplg = $db->Execute(sqlSelect($db,'checkout','name',sprintf('id=%s',$smart['checkout_plugin_id']))); + $rs = $db->Execute(sqlSelect($db,'invoice','account_id,ROUND(SUM(total_amt-billed_amt-IFNULL(credit_amt,0)),2) AS balance',false,'account_id','','','account_id')); - if ($cplg && $cplg->RecordCount()) - $smart['checkout_plugin'] = $cplg->fields['name']; - } - - if ($smart['total_amt'] == 0) - $smart['balance'] = 0; - else - $smart['balance'] = $smart['total_amt']-$smart['billed_amt']; - - # Get the tax details - if (! empty($smart['tax_amt'])) { - $trs = $db->Execute(sqlSelect($db,array('invoice_item_tax','tax'),'A.amount,B.description',sprintf('A.tax_id=B.id AND A.invoice_id=%s',$smart['id']))); - - if ($trs && $trs->RecordCount()) { - $taxes = array(); - while (!$trs->EOF) { - @$taxes[$trs->fields['description']] += $trs->fields['amount']; - $trs->MoveNext(); - } - - $smart['tax_arr'] = array(); - foreach ($taxes as $txds => $txamt) - array_push($smart['tax_arr'],array('description'=>$txds,'amount'=>$txamt)); - } - } - - # Get the discount details - if (! empty($smart['discount_amt'])) { - $drs = $db->Execute(sqlSelect($db,'invoice_item_discount','amount,discount',sprintf('invoice_id=%s',$smart['id']))); - - if ($drs && $drs->RecordCount()) { - $discounts = array(); - while(!$drs->EOF) { - @$discounts[$drs->fields['discount']] += $drs->fields["amount"]; - $drs->MoveNext(); - } - - $dhtml = ''; - foreach ($discounts as $dsds=>$dsamt) - $dhtml .= sprintf('%s -
                    ',$dsds,$dsds,number_format($dsamt,2)); - - $smart['discount_popup'] = $dhtml; - - $dhtml = ''; - foreach ($discounts as $dsds=>$dsamt) - $dhtml .= sprintf('%s - %s
                    ',$dsds,number_format($dsamt,2)); - - $smart['discount_popup_user'] = $dhtml; - } - } - - # Get the checkout plugin details - if (! empty($smart['checkout_plugin_data'])) { - $plugin_data = unserialize($smart['checkout_plugin_data']); - - if (is_array($plugin_data)) - $smart['checkout_plugin_data'] = $plugin_data; - else - $smart['checkout_plugin_data'] = array(0=>$smart['checkout_plugin_data']); - } - - # Get the line items - $q = sqlSelect($db,'invoice_item','*',sprintf('invoice_id=%s',$smart['id'])); - if ($C_list->is_installed('voip')) - $q .= ' AND item_type!=5'; - - $items = $db->Execute($q); - if ($items === false) { - global $C_debug; - $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); - - return false; - } - - # Get the term dates - include_once(PATH_MODULES.'net_term/net_term.inc.php'); - $net_term = new net_term; - - $smart['termdates'] = $net_term->getTermDates($smart['net_term_id'],$smart['date_orig'],$smart['due_date']); - - $ii =0; - while (! $items->EOF) { - $smart_items[$ii] = $items->fields; - - # Get the product attribs - if (! empty($items->fields['product_attr'])) { - @$attrib = explode("\r\n",$items->fields['product_attr']); - $js = ''; - - for ($attr_i=0; $attr_i%s
                    : %s
                    ',$attributei[0],$attributei[1]); - } - - $smart_items[$ii]['attribute_popup'] = $js; - } - - # Get the date range if set - if (! empty($items->fields['date_start']) && ! empty($items->fields['date_stop'])) { - $C_translate->value('invoice','start',date(UNIX_DATE_FORMAT,$items->fields['date_start'])); - $C_translate->value('invoice','stop',date(UNIX_DATE_FORMAT,$items->fields['date_stop'])); - - $smart_items[$ii]['range'] = $C_translate->translate('recur_date_range','invoice',''); - } - - # Set charge type for payment option list - $any_new = true; - if ($items->fields['price_type']=='1' && ! empty($smart['recurr_arr']) && is_array(unserialize($smart['recurr_arr']))) - $any_recurring = true; - - $items->MoveNext(); - $ii++; - } - - # Create a summary (for duplicate skus w/identical price,and attributes, roll into a single value - if ($this->summarizeInvoice) - $smart_items = $this->summarizeLineItems($smart_items); - - # Get the checkout (payment) options - if ($VAR['_page'] != 'invoice:view') { - # Get the converted amount due: - if ($smart['billed_currency_id'] != $smart['actual_billed_currency_id']) { - global $C_list; - - $CURRENCY = $smart['actual_billed_currency_id']; - if ($smart['billed_amt'] <= 0) - $total = $C_list->format_currency_decimal($smart['total_amt'],$CURRENCY); - else - $total = $C_list->format_currency_decimal($smart['total_amt'],$CURRENCY)-$smart['actual_billed_amt']; - - } else { - $CURRENCY = $smart['billed_currency_id']; - $total = $smart['total_amt']-$smart['billed_amt']; - } - - $q = sqlSelect($db,'checkout','*','active=1'); - - if ($any_trial) - $q .= sprintf(' AND allow_trial = %s',$db->qstr('1')); - - if ($any_recurring) - $q .= sprintf(' AND allow_recurring = %s',$db->qstr('1')); - - if ($any_new) - $q .= sprintf(' AND allow_new = %s',$db->qstr('1')); - - $chopt = $db->Execute($q); - - if ($chopt === false) { - global $C_debug; - $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); - - return false; - } - - if ($chopt != false && $chopt->RecordCount() > 0) { - while (! $chopt->EOF) { - $show = true; - - # Check that the cart total is not to high: - if ($chopt->fields['total_maximum'] != '' && $smart['total_amt'] >= $chopt->fields['total_maximum']) - $show = false; - - # Check that the cart total is not to low: - if ($chopt->fields['total_miniumum'] != '' && $smart['total_amt'] <= $chopt->fields['total_miniumum']) - $show = false; - - # Check that the group requirement is met: - if ($show && ! empty($chopt->fields['required_groups'])) { - global $C_auth; - - $arr = unserialize($chopt->fields['required_groups']); - if (count($arr) > 0 && ! empty($arr[0])) - $show = false; - - for ($i=0; $iauth_group_by_id($arr)) { - $show = true; - $i = count($arr); - } - } - } - - # Check that the customer is not ordering a blocked SKU - if ($show && ! empty($chopt->fields['excluded_products'])) { - $arr = unserialize($chopt->fields['excluded_products']); - if (count($arr) > 0) { - for ($i=0; $ifields['default_when_amount'])) { - $arr = unserialize($chopt->fields['default_when_amount']); - - for ($idx=0; $idx= $arr[$idx]) - $list_ord--; - - $idx = count($arr); - } - } - - # By Currency - if (! empty($chopt->fields['default_when_currency'])) { - $arr = unserialize($chopt->fields['default_when_currency']); - - for ($idx=0; $idxfields['default_when_group'])) { - $arr = unserialize($chopt->fields['default_when_group']); - global $C_auth; - - for ($idx=0; $idxauth_group_by_id($arr[$idx])) - $list_ord--; - - $idx = count($arr); - } - } - - # By Country - if (! empty($chopt->fields['default_when_country'])) { - $arr = unserialize($chopt->fields['default_when_country']); - - for ($idx=0; $idxfields['country_id'] == $arr[$idx]) - $list_ord--; - - $idx = count($arr); - } - } - - # Add to the array - $checkout_optionsx[] = array('sort'=>$list_ord,'fields'=>$chopt->fields); - } - - $chopt->MoveNext(); - } - - # Sort the checkout_options array by the [fields] element - if (count($checkout_optionsx)>0) { - foreach ($checkout_optionsx as $key => $row) - $sort[$key] = $row['sort']; - - array_multisort($sort,SORT_ASC,$checkout_optionsx); - } - } - } - - # No results - if (count($smart) == 0) { - global $C_debug; - $C_debug->error(__FILE__, __METHOD__,'The selected record does not exist any longer, or your account is not authorized to view it'); - - return; - } - - # Define the DB vars as a Smarty accessible block - global $smarty; - - # Define the results - $smarty->assign('cart',$smart_items); - $smarty->assign('record',$smart); - $smarty->assign('checkoutoptions',$checkout_optionsx); - } - } - - /** - * Delete an invoice - */ - public function delete($VAR) { - $db = &DB(); - - # Get the array - if (isset($VAR['delete_id'])) - $ids = explode(',',preg_replace('/,$/','',$VAR['delete_id'])); - elseif (isset($VAR['id'])) - $ids = explode(',',preg_replace('/,$/','',$VAR['id'])); - - # Load the service module - include_once(PATH_MODULES.'service/service.inc.php'); - $service = new service; - - # Loop: - for ($i=0; $iExecute(sqlSelect($db,'service',array('invoice_id'=>$ids[$i]))); - - if ($rs === false) { - global $C_debug; - - $C_debug->error(__FILE__,'delete', $db->ErrorMsg()); - return false; - } - - if ($rs->RecordCount() > 0) { + if ($rs && $rs->RecordCount()) { while (! $rs->EOF) { - $service->delete($rs->fields['id'],$service); + $sAccountBal[$rs->fields['account_id']] = $rs->fields['balance']; $rs->MoveNext(); } } - - # Delete the service record - $this->associated_DELETE = array(); - array_push($this->associated_DELETE,array('table'=>'invoice_commission','field'=>'invoice_id')); - array_push($this->associated_DELETE,array('table'=>'invoice_item','field'=>'invoice_id')); - array_push($this->associated_DELETE,array('table'=>'invoice_memo','field'=>'invoice_id')); -// array_push($this->associated_DELETE,array('table'=>'service','field'=>'invoice_id')); - array_push($this->associated_DELETE,array('table'=>'invoice_item_tax','field'=>'invoice_id')); - array_push($this->associated_DELETE,array('table'=>'invoice_item_discount','field'=>'invoice_id')); - - $result = parent::delete($VAR); } + + return $sAccountBal; } /** - * User view an invoice + * Get a list of invoices with a non-zero balance + * + * @param $account_id Get the invoices for this account, otherwise all invoices are returned. + * @param $refresh If true, force re-reading database to get the list of invoices. + * @return array List of invoices with balance */ - public function user_view($VAR) { - global $C_auth; + public function sInvoicesBal($account_id=null,$refresh=false) { + static $sInvoicesBal = array(); - if (! SESS_LOGGED) - return false; - - # Verify the account_id for this order is the SESS_ACCOUNT - if ($C_auth->auth_method_by_name('invoice','view') == false) { - $id = preg_replace('/,$/','',$VAR['id']); + if ($refresh || ! count($sInvoicesBal)) { + $sInvoicesBal = array(); $db = &DB(); - $rs = $db->Execute($q=sqlSelect($db,'invoice','account_id',array('id'=>$id))); - if ($rs === false) { - global $C_debug; - $C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg()); - - return false; + $rs = $db->Execute(sqlSelect('invoice','date_orig,account_id,id,total_amt,billed_amt,IFNULL(credit_amt,0) as credit_amt,ROUND(total_amt-billed_amt-IFNULL(credit_amt,0),2) as balance', + array('where'=>'(refund_status=0 OR refund_status IS NULL) AND status=1 AND total_amt-billed_amt-IFNULL(credit_amt,0)!=0','orderby'=>'account_id,date_orig,id'))); + if ($rs && $rs->RecordCount()) { + while (! $rs->EOF) { + $invoice = array(); + $invoice['invoice_id'] = $rs->fields['id']; + $invoice['balance'] = $rs->fields['balance']; + $invoice['total_amt'] = $rs->fields['total_amt']; + $invoice['billed_amt'] = $rs->fields['billed_amt']; + $invoice['credit_amt'] = $rs->fields['credit_amt']; + $invoice['date_orig'] = $rs->fields['date_orig']; + $sInvoicesBal[$rs->fields['account_id']][$rs->fields['id']] = $invoice; + $rs->MoveNext(); + } } - - if ($rs->fields['account_id'] != SESS_ACCOUNT) - return false; } - $this->view($VAR,$this); + return (is_null($account_id) ? $sInvoicesBal : isset($sInvoicesBal[$account_id]) ? $sInvoicesBal[$account_id] : array()); + } + + /** + * Get a list of invoices for an account. + * + * @param $account_id + * @param $invoices Optional array of invoices to retrieve, otherwise all invoices are return. + * @return array Requested invoices + */ + public function sInvoicesAcc($account_id,$invoices=array()) { + static $sInvoicesAccount = array(); + $return = array(); + + if (count($invoices)) { + foreach ($invoices as $invoice) + if (isset($sInvoicesAccount[$account_id][$invoice_id])) + $return[$invoice_id] = $sInvoicesAccount[$account_id][$invoice_id]; + + } else { + if (isset($sInvoicesAccount[$account_id])) + $return = $sInvoicesAccount[$account_id]; + } + + # Do we need to get the invoices from the DB? + if ((! count($invoices) && ! count($return)) || count($invoices) != count($return)) { + $db = &DB(); + + if (count($invoices)) + $where = sprintf('AND id IN (%s)',join(',',$invoices)); + else + $where = ''; + + $rs = $db->Execute(sqlSelect('invoice','id,date_orig,total_amt,billed_amt,IFNULL(credit_amt,0) as credit_amt,ROUND(total_amt-billed_amt-IFNULL(credit_amt,0),2) AS balance',array('where'=>sprintf('account_id=%s %s',$account_id,$where),'orderby'=>'id'))); + if ($rs && $rs->RecordCount()) { + while (! $rs->EOF) { + $sInvoicesAccount[$account_id][$rs->fields['id']] = $rs->fields; + $return[$rs->fields['id']] = $rs->fields; + $rs->MoveNext(); + } + } + } + + return $return; + } + + public function invoice_days() { return $this->sInvoiceDays(); } + /** + * Determine the number of days in advance an invoice should be generated. + * Invoices are generated when the greater of: + * + system default (setup:max_inv_gen_period), (to be deprecated) + * + system default (setup_invoice:invoice_advance_gen), + * + * @return int Days in Advance to Issue Invoices. + */ + public function sInvoiceDays() { + $db = &DB(); + + # Get the max invoice days from the setup_invoice table + $days = 0; + + # First from the setup table. + $setup = $db->Execute(sqlSelect($db,'setup','max_inv_gen_period','')); + if (isset($setup->fields['max_inv_gen_period'])) + $days = $setup->fields['max_inv_gen_period']; + + # Then from the setup_invoice table. + $setup = $db->Execute(sqlSelect($db,'setup_invoice','invoice_advance_gen,advance_notice','')); + if (isset($setup->fields['invoice_advance_gen']) && $setup->fields['invoice_advance_gen'] > $days) + $days = $setup->fields['invoice_advance_gen']; + + if (isset($setup->fields['advance_notice']) && $setup->fields['advance_notice'] > $days) + $days = $setup->fields['advance_notice']; + + return $days; } } ?> diff --git a/modules/invoice/invoice_base_fpdf.inc.php b/modules/invoice/invoice_base_fpdf.inc.php index 3a9b8295..505aac33 100644 --- a/modules/invoice/invoice_base_fpdf.inc.php +++ b/modules/invoice/invoice_base_fpdf.inc.php @@ -60,15 +60,15 @@ abstract class pdf_invoice_base extends fpdf { $this->SetCreator('Open Source Billing'); $this->SetAuthor($inv->print['site']['NAME']); $this->SetTitle(sprintf('%s Invoice',$inv->print['site']['NAME'])); - $this->SetSubject(sprintf('Invoice #%06s',$inv->getInvoiceNum())); - $this->SetKeywords($inv->getInvoiceID()); + $this->SetSubject(sprintf('Invoice #%06s',$inv->getPrintInvoiceNum())); + $this->SetKeywords($inv->getPrintInvoiceID()); $this->SetAutoPageBreak(TRUE,25); $this->SetDisplayMode('fullwidth'); return $this; } - public function load_setup(&$rs) { + public function load_setup($rs=false) { if (! $rs) { $db =& DB(); $rs = $db->Execute(sqlSelect($db,'setup_invoice','*','')); diff --git a/modules/invoice/invoice_base_fpdi.inc.php b/modules/invoice/invoice_base_fpdi.inc.php index 7f498b46..a7606219 100644 --- a/modules/invoice/invoice_base_fpdi.inc.php +++ b/modules/invoice/invoice_base_fpdi.inc.php @@ -62,15 +62,15 @@ abstract class pdf_invoice_base extends fpdi { $this->SetCreator('Open Source Billing'); $this->SetAuthor($inv->print['site']['NAME']); $this->SetTitle(sprintf('%s Invoice',$inv->print['site']['NAME'])); - $this->SetSubject(sprintf('Invoice #%06s',$inv->getInvoiceNum())); - $this->SetKeywords($inv->getInvoiceID()); + $this->SetSubject(sprintf('Invoice #%06s',$inv->getPrintInvoiceNum())); + $this->SetKeywords($inv->getPrintInvoiceID()); $this->SetAutoPageBreak(TRUE,25); $this->SetDisplayMode('fullwidth'); return $this; } - public function load_setup(&$rs) { + public function load_setup($rs=false) { if (! $rs) { $db =& DB(); $rs = $db->Execute(sqlSelect($db,'setup_invoice','*','')); diff --git a/modules/invoice/invoice_base_tcpdf.inc.php b/modules/invoice/invoice_base_tcpdf.inc.php index 49a1c7e1..7072e6eb 100644 --- a/modules/invoice/invoice_base_tcpdf.inc.php +++ b/modules/invoice/invoice_base_tcpdf.inc.php @@ -60,8 +60,8 @@ abstract class pdf_invoice_base extends TCPDF { $this->SetCreator('Open Source Billing'); $this->SetAuthor($inv->print['site']['NAME']); $this->SetTitle(sprintf('%s Invoice',$inv->print['site']['NAME'])); - $this->SetSubject(sprintf('Invoice #%06s',$inv->getInvoiceNum())); - $this->SetKeywords($inv->getInvoiceID()); + $this->SetSubject(sprintf('Invoice #%06s',$inv->getPrintInvoiceNum())); + $this->SetKeywords($inv->getPrintInvoiceID()); $this->SetAutoPageBreak(TRUE,25); $this->SetHeaderMargin(1); $this->SetFooterMargin(10); @@ -72,7 +72,7 @@ abstract class pdf_invoice_base extends TCPDF { return $this; } - public function load_setup(&$rs) { + public function load_setup($rs=false) { if (! $rs) { $db =& DB(); $rs = $db->Execute(sqlSelect($db,'setup_invoice','*','')); diff --git a/modules/invoice/invoice_construct.xml b/modules/invoice/invoice_construct.xml index 24bca908..39a0cad7 100644 --- a/modules/invoice/invoice_construct.xml +++ b/modules/invoice/invoice_construct.xml @@ -66,15 +66,17 @@ Active L - - + + + --> + L - + L @@ -89,18 +91,21 @@ L + + --> + L - I8 account first_name,last_name + Account + I8 @@ -115,9 +120,11 @@ I4 + C(32) @@ -126,54 +133,65 @@ I4 - + C(255) array - + Total Taxes F + + + Total Credits + F + + Total Discounts F + Amount F - + Amount Paid F - + I4 - + F - + I4 @@ -201,9 +219,10 @@ date-time + X @@ -221,23 +240,24 @@ I4 + - id,site_id,date_orig,date_last,type,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_id,tax_amt,discount_arr,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date - id,site_id,date_orig,date_last,type,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_id,tax_amt,discount_arr,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,site_id,date_orig,date_last,type,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_id,tax_amt,discount_arr,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date - id,site_id,date_orig,date_last,type,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_id,tax_amt,discount_arr,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals,ip - id,site_id,date_orig,date_last,type,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_id,tax_amt,discount_arr,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals,ip - id,date_orig,date_last,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,suspend_billing,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,type,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,status + id,date_last,type,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id + id,date_orig,date_last,type,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_amt,discount_amt,total_amt,billed_amt,credit_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,date_orig,date_last,type,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals @@ -250,6 +270,30 @@ + + + id + checkbox + 25px + + + account_id + + + service_id + + + invoice_date + next_invoice_date + + + price + currency + + + 120px + + id @@ -278,7 +322,6 @@ 120px - id @@ -296,6 +339,10 @@ total_amt currency + + balance + currency + 60px diff --git a/modules/invoice/invoice_install.xml b/modules/invoice/invoice_install.xml index 85be723b..b0039843 100644 --- a/modules/invoice/invoice_install.xml +++ b/modules/invoice/invoice_install.xml @@ -57,11 +57,11 @@ view - + Upcoming Invoices 1 - Invoice Soon - + tmInvoiceSoon + resend diff --git a/modules/invoice/receipt_print.php b/modules/invoice/receipt_print.php index e565188e..e35dc7a4 100644 --- a/modules/invoice/receipt_print.php +++ b/modules/invoice/receipt_print.php @@ -33,7 +33,7 @@ class receipt_print extends FPDF var $active=false; var $save_path = ''; - function add(&$invoiceRs, $payment_amt, $paid_amt) { + function add($invoice, $payment_amt, $paid_amt) { if(!$this->active) return false; @@ -46,16 +46,16 @@ class receipt_print extends FPDF $this->drawCompanyAddress(); $this->SetXY(0,50); - $this->Cell(50,10,"*** INVOICE# {$invoiceRs->fields['id']} ***"); + $this->Cell(50,10,"*** INVOICE# {$invoice['id']} ***"); $this->SetXY(0,60); $this->Cell(50,10,"DATE ".date("d/m/Y D H:i")); $this->SetXY(0,70); $this->Cell(50,5,"INVOICE TOTAL: "); - $this->SetXY(45,70); $this->Cell(50,5, number_format($invoiceRs->fields['total_amt'],2)); + $this->SetXY(45,70); $this->Cell(50,5, number_format($invoice['total_amt'],2)); $this->SetXY(0,75); $this->Cell(50,5,"PREV AMT DUE: " ); - $this->SetXY(45,75); $this->Cell(50,5, number_format($invoiceRs->fields['total_amt']-$invoiceRs->fields['billed_amt'],2)); + $this->SetXY(45,75); $this->Cell(50,5, number_format($invoice['total_amt']-$invoice['billed_amt'],2)); $this->SetXY(0,80); $this->Cell(50,5,"CURRENT PAYMENT: " ); $this->SetXY(45,80); $this->Cell(50,5, $payment_amt); @@ -64,7 +64,7 @@ class receipt_print extends FPDF $this->SetXY(45,85); $this->Cell(50,5, number_format($paid_amt,2)); $this->SetXY(0,90); $this->Cell(50,5,"CURRENY AMT DUE: " ); - $this->SetXY(45,90); $this->Cell(50,5, number_format($invoiceRs->fields['total_amt']-$paid_amt,2)); + $this->SetXY(45,90); $this->Cell(50,5, number_format($invoice['total_amt']-$paid_amt,2)); $this->SetXY(0,100); $this->Cell(50,5,"Thank You!" ); diff --git a/modules/invoice/views/invoice/html.php b/modules/invoice/views/invoice/html.php new file mode 100644 index 00000000..c3c2191d --- /dev/null +++ b/modules/invoice/views/invoice/html.php @@ -0,0 +1,138 @@ + + + + + + + + + + + +
                    + + + + + +


                    +
                      + + + + + + + + + + + + + + + + + + + + + + + + + +
                    TAX INVOICEinvnum(); ?>
                    Issue Datedisplay('date_orig'); ?>
                    Due Datedisplay('due_date'); ?>
                    Current Charges Duedisplay('total_amt'); ?>
                    Payments Received to Datedisplay('billed_amt'); ?>
                    Total Charges Duedue(TRUE); ?>
                    +
                     
                    + + + + + sorted_service_items('recur_schedule') as $cat => $catitems) { ?> + + + + + + + + + + + + + + + + + + + tax_summary() as $tid => $amount) { + $m = ORM::factory('tax',$tid); + ?> + + + + + + + + + + + +
                    Charges Detail:
                    uri(array('file'=>'img/toggle-closed.png')),array('alt'=>'+')); ?>
                      +
                    + + + + + + + + + + + + + + + + + + + + + items_sub($item->service_id) as $subitem) { + if (! is_null($subitem->module_id)) { + $m = StaticList_Module::record('module','name','id',$subitem->module_id); + // @todo Need to remove the explicit test for 'charge' and be more dynamic + $mi = ORM::factory($m,$m == 'charge' ? $subitem->charge_id : $subitem->id); + $display = $mi->invoice_display(); + } else { + $display = 'Other'; + } + ?> + + + + + + + + + + + + + + + + + +
                    service->id,$item->service->svcnum()); ?>product->product_translate->find()->name; ?> (product_id; ?>)items_service_total($item->service_id));?>
                     trannum();?>period();?>subtotal());?>
                     trannum(); ?>subtotal());?>
                     items_service_tax($item->service_id));?>
                    +
                    +
                    Sub Total:subtotal(TRUE); ?>
                    Taxes Included:
                     description; ?>
                    Total:total(TRUE); ?>
                    +
                    diff --git a/modules/invoice/views/invoice/list.php b/modules/invoice/views/invoice/list.php new file mode 100644 index 00000000..cf456017 --- /dev/null +++ b/modules/invoice/views/invoice/list.php @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +
                    IDTotalCreditsPaymentsDueActive
                    id,$invoice->invnum()); ?>display('total_amt'); ?>display('credit_amt'); ?>display('billed_amt'); ?>due()); ?>display('status'); ?>
                    diff --git a/modules/invoice_item/invoice_item.inc.php b/modules/invoice_item/invoice_item.inc.php index 6869a66d..ecfa88ac 100644 --- a/modules/invoice_item/invoice_item.inc.php +++ b/modules/invoice_item/invoice_item.inc.php @@ -29,5 +29,192 @@ * @subpackage Module:Invoice */ class invoice_item extends OSB_module { + # Hold the Tax information for this object + private $tax_arr; + # Hold the Discount information for this object + private $discount_arr; + # The prorate rate for this item + private $prorata = 1; + # Set the base price - used to work out the recurring amount + private $base = 0; + + private function setBase() { + if ($this->base && $this->prorata) + $this->setRecordAttr('price_base',$this->base*$this->prorata); + } + + public function setProRata($amt) { + $this->prorata = $amt; + + # Automatically reduce the base rate + $this->setBase(); + } + + public function setBaseRate($amt) { + $this->base = $amt; + + # Automatically reduce the base rate + $this->setBase(); + } + + /** + * Calculate the tax for an item record + * + * @uses account + * @uses tax + */ + private function pCalcTax() { + $total = 0; + + foreach ($this->getTaxArr() as $tax) + $total += $tax['rate']; + + return $total; + } + + public function getTaxArr() { + if (! is_array($this->tax_arr)) { + # If we dont have an Account ID we cant calculate tax + if (is_null($this->getRecordAttr('account_id'))) + return false; + + include_once(PATH_MODULES.'tax/tax.inc.php'); + $to = new tax; + + include_once(PATH_MODULES.'account/account.inc.php'); + $ao = new account($this->getRecordAttr('account_id')); + + $total = ($this->getRecordAttr('price_base')+$this->getRecordAttr('price_setup'))*$this->getRecordAttr('quantity')-$this->getRecordAttr('discount_amt'); + $this->tax_arr = $to->calculate($total,$ao->getRecordAttr('country_id'),$ao->getRecordAttr('state')); + + $this->setRecordAttr('tax_amt',$this->pCalcTax()); + } + + return $this->tax_arr; + } + + public function sGetTaxAmt() { + return $this->pCalcTax(); + } + + /** + * Calculate Discounts applicable for item + * + * @uses discount + */ + private function pCalcDiscount($iamt) { + $total = 0; + + foreach ($this->getDiscountArr($iamt) as $discount) + $total += $discount['amount']; + + return $total; + } + + public function getDiscountArr($iamt) { + if (! is_array($this->discount_arr)) { + include_once(PATH_MODULES.'discount/discount.inc.php'); + $do = new discount; + + $total = ($this->getRecordAttr('price_base')+$this->getRecordAttr('price_setup'))*$this->getRecordAttr('quantity'); + $this->discount_arr = $do->calc_all_discounts(1,$this->getRecordAttr('product_id'),$total,$this->getRecordAttr('account_id'),$iamt); + + $this->setRecordAttr('discount_amt',$this->pCalcDiscount($iamt)); + } + + return $this->discount_arr; + } + + /** + * Get the Discount Total for this Item + */ + public function sGetDiscountAmt($total=0) { + return $this->pCalcDiscount($total); + } + + public function sGetSubTotalAmt() { + return ($this->getRecordAttr('price_base')+$this->getRecordAttr('price_setup'))*$this->getRecordAttr('quantity'); + } + + public function sGetTotalAmt($recalc=false) { + static $total; + + if ($total && ! $recalc) + return $total; + else + $total = 0; + + # Work out our discount if we havent already + if (is_null($this->getRecordAttr('discount_amt'))) + $this->setRecordAttr('discount_amt',$this->pCalcDiscount($this->sGetSubTotalAmt())); + + # Work out our tax if we havent already + if (is_null($this->getRecordAttr('tax_amt'))) + $this->setRecordAttr('tax_amt',$this->sGetTaxAmt()); + + $total = ($this->getRecordAttr('price_base')+$this->getRecordAttr('price_setup'))*$this->getRecordAttr('quantity') + -$this->getRecordAttr('discount_amt') + +$this->getRecordAttr('tax_amt'); + + $this->setRecordAttr('total_amt',$total); + + return $total; + } + + /** + * Work out the recurring amount + * + * This amount excludes taxes and discounts + * + * @uses product + */ + public function sGetRecurAmt() { + if ($this->getRecordAttr('price_type') != 1) + return 0; + + return $this->base*$this->getRecordAttr('quantity'); + } + + /** + * Save records + * + * Taxes and discounts should already be set and configured. + * + * @uses discount + * @uses tax + */ + public function sql_SaveRecord($noconvert=false,$calc=true) { + # If our discounts and taxes were calculated already we can skip them + if ($calc) { + $this->setRecordAttr('discount_amt',$this->pCalcDiscount($this->sGetSubTotalAmt())); + $this->setRecordAttr('tax_amt',$this->sGetTaxAmt()); + $this->setRecordAttr('total_amt',$this->sGetTotalAmt(true)); + } + + if ($id = parent::sql_SaveRecord($noconvert)) { + # Save the Discount Object + include_once(PATH_MODULES.'discount/discount.inc.php'); + $do = new discount; + + include_once(PATH_MODULES.'tax/tax.inc.php'); + $to = new tax; + + # Save the Tax & Discount Details + if ($this->discount_arr) + $do->invoice_item($this->getRecordAttr('invoice_id'),$id,$this->getRecordAttr('account_id'),$this->discount_arr); + + if ($this->tax_arr) + $to->invoice_item($this->getRecordAttr('invoice_id'),$id,$this->getRecordAttr('account_id'),$this->tax_arr); + } + + return $id; + } + + /** + * Return the items on an invoice + */ + public function sInvoiceItems($id) { + return $this->sql_GetRecords(array('where'=>array('invoice_id'=>$id))); + } } ?> diff --git a/modules/invoice_item/invoice_item_construct.xml b/modules/invoice_item/invoice_item_construct.xml index b27ff4ab..e83504b3 100644 --- a/modules/invoice_item/invoice_item_construct.xml +++ b/modules/invoice_item/invoice_item_construct.xml @@ -38,16 +38,22 @@ I8 - + + + + I8 + I8 @@ -57,19 +63,22 @@ I8 + - I4 + F L - X2 array + 1 + X2 X2 @@ -86,7 +95,7 @@ F - + L @@ -121,8 +130,8 @@ - id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id - id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id + account_id,invoice_id,product_id,product_name,service_id,charge_id,quantity,item_type,product_attr,product_attr_cart,price_type,price_base,price_setup,total_amt,discount_amt,tax_amt,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,date_start,date_stop + date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id diff --git a/modules/module.inc.php b/modules/module.inc.php index 0936caab..0ea9d810 100644 --- a/modules/module.inc.php +++ b/modules/module.inc.php @@ -25,6 +25,8 @@ * @subpackage Modules */ +require_once(PATH_CORE.'xml.inc.php'); + /** * Module Abstract Class * This abstract class provides the basic variables and methods for all modules. @@ -35,11 +37,26 @@ abstract class OSB_module { # Validation error array public $val_error = array(); + # Debug output to STDOUT + protected $debug = false; + # Inbound VAR value + protected $VAR = array(); + # Object database ID & Record + private $record = array(); + # Last Record ID read from DB + private $record_id = null; /** * Initialise the module */ - public function __construct() { + public function __construct($id=null) { + global $VAR; + + $this->VAR = $VAR; + + if (isset($this->VAR['debug']) && $this->VAR['debug']) + $this->debug = true; + $f = sprintf('%s%s/%s_construct.xml',PATH_MODULES,get_class($this),get_class($this)); if (is_file($f)) { @@ -64,6 +81,36 @@ abstract class OSB_module { bindtextdomain($this->module,PATH_LANGUAGE); bind_textdomain_codeset($this->module,'UTF-8'); } + + $this->sql_LoadRecord($id); + } + + /** + * Return this record from the database + */ + protected function getRecord() { + return isset($this->record) ? $this->record : null; + } + + protected function clearRecord() { + $this->record = array(); + } + + protected function delRecordAttr($attr) { + if (isset($this->record[$attr])) + unset($this->record[$attr]); + } + + /** + * Return a field from the database record + */ + protected function getRecordAttr($attr) { + return isset($this->record[$attr]) ? $this->record[$attr] : null; + } + + protected function setRecordAttr($attr,$value) { + $this->record[$attr] = $value; + return $value; } public function getlist() { @@ -98,7 +145,7 @@ abstract class OSB_module { * Basic module helper when interacting with the database. */ private function database($type,$VAR,$method=null) { - if ($type) + if ($type && ! is_array($this->method[$type])) $this->method[$type] = explode(',',$this->method[$type]); if (is_null($method) && $type) @@ -246,7 +293,11 @@ abstract class OSB_module { public function user_search($VAR) { if (! SESS_LOGGED) return false; - $VAR[$this->module.'_account_id'] = SESS_ACCOUNT; + if (get_class($this) == 'discount') + $VAR[$this->module.'_avail_account_id'] = SESS_ACCOUNT; + else + $VAR[$this->module.'_account_id'] = SESS_ACCOUNT; + $this->database('search',$VAR); } @@ -256,7 +307,7 @@ abstract class OSB_module { public function user_search_show($VAR) { if (! SESS_LOGGED) return false; - $this->database('search',$VAR,'search_show'); + return $this->database('search',$VAR,'search_show'); } /** @@ -301,6 +352,8 @@ abstract class OSB_module { list($class,$method) = explode(':',$VAR['_page']); + $method = strtolower($method); + if (! isset($this->tpl[$method])) return; @@ -325,7 +378,9 @@ abstract class OSB_module { default: printf('',isset($details['width']) ? sprintf(' style="width: %s;"',$details['width']) : ''); printf('', - isset($details['translate']) ? $C_translate->translate($details['translate'],$this->module) : $C_translate->tf(array('module'=>$this->module,'field'=>$details['field']),null), + isset($details['translate']) + ? $C_translate->translate($details['translate'],$this->module) + : $C_translate->tf(array('module'=>$this->module,'field'=>$details['field']),null), $details['field']); echo ''; } @@ -336,7 +391,7 @@ abstract class OSB_module { # Loop through each record if (is_array($args) && count($args[0])) { foreach ($args[0] as $key => $values) { - printf('', + printf('', $values['id'],$values['id'],$this->module,$values['id'],$values['id'],$values['id'],$values['_C'],$values['_C']); foreach ($this->tpl[$method] as $index => $details) { @@ -457,5 +512,61 @@ abstract class OSB_module { return $arr; } + + protected function sql_SaveRecord($noconvert=false,$ignoreval=false) { + global $VAR; + + $lVAR = array(); + if (is_array($VAR)) + $lVAR = array_merge($VAR); + + foreach ($this->record as $k => $v) + $lVAR[sprintf('%s_%s',$this->table,$k)] = $v; + $lVAR['_noredirect'] = true; + + if ($noconvert) + $lVAR['_noconvert'] = true; + if ($ignoreval) + $lVAR['_ignoreval'] = true; + + # Adding record + if (! isset($this->record['id']) || $this->record['id'] != $this->record_id) + return $this->add($lVAR); + else + return $this->update($lVAR); + } + + protected function sql_LoadRecord($id) { + $record = $this->sql_GetRecords(array('where'=>array('id'=>$id))); + + if (count($record) == 1) { + $this->record = array_pop($record); + $this->record_id = $id; + + } else { + $this->record = null; + $this->record_id = null; + } + } + + /** + * Get Data out of the tables for the module + * + * @return array Table records + */ + protected function sql_GetRecords($opt=array()) { + $db = &DB(); + + $data = array(); + $result = $db->Execute(sqlSelect($this->table,'*',$opt)); + + if ($result && $result->RecordCount()) + while (! $result->EOF) { + array_push($data,$result->fields); + $result->MoveNext(); + } + + return $data; + } } ?> diff --git a/modules/module/classes/controller/admin/module.php b/modules/module/classes/controller/admin/module.php new file mode 100644 index 00000000..6ee48956 --- /dev/null +++ b/modules/module/classes/controller/admin/module.php @@ -0,0 +1,101 @@ +template->content = _('See menu on tree'); + } + + /** + * List our installed modules + */ + public function action_list() { + $modules = ORM::factory('module'); + + $output = ''; + + $output .= View::factory('module/admin/list_header'); + foreach ($modules->find_all() as $mo) { + $output .= View::factory('module/admin/list_body') + ->set('module',$mo); + } + $output .= View::factory('module/admin/list_footer'); + + Block::add(array( + 'title'=>_('Currently installed modules'), + 'body'=>$output, + )); + + $this->template->content = Block::factory(); + } + + /** + * Edit a Module Configuration + * + * @param int $mid Module ID + */ + public function action_edit($mid) { + $mo = ORM::factory('module',$mid); + + if (! $mo->loaded()) { + SystemMessage::add(array( + 'title'=>_('Invalid Module ID'), + 'type'=>'error', + 'body'=>sprintf(_('Module with ID %s doesnt appear to exist?'),$mid), + )); + + return; + } + + $output = ''; + $methods = $this->_methods($mo->name); + + // Show methods defined in the DB already. + $output .= View::factory('module/admin/method_list_header'); + foreach ($mo->module_method->find_all() as $meo) { + if (($method = array_search($meo->name,$methods)) !== false) + unset($methods[$method]); + + $output .= View::factory('module/admin/method_list_body') + ->set('method',$meo) + ->set('module',$mo) + ->set('defined',$method !== false); + } + + $output .= View::factory('module/admin/method_list_spacer'); + + // Show new methods NOT defined in the DB already. + foreach ($methods as $method) { + $meo = ORM::factory('module_method') + ->values(array('name'=>$method,'notes'=>_('Not defined in DB'))); + + $output .= View::factory('module/admin/method_list_body') + ->set('method',$meo) + ->set('module',$mo) + ->set('defined',$method === false); + } + $output .= View::factory('module/admin/method_list_footer'); + + Block::add(array( + 'title'=>sprintf(_('%s Methods'),strtoupper($mo->name)), + 'body'=>$output, + )); + + $this->template->content = Block::factory(); + } +} +?> diff --git a/modules/module/classes/controller/admin/module/method.php b/modules/module/classes/controller/admin/module/method.php new file mode 100644 index 00000000..438ce62c --- /dev/null +++ b/modules/module/classes/controller/admin/module/method.php @@ -0,0 +1,138 @@ +loaded() OR ! in_array($method,$this->_methods($mo->name))) + throw new Kohana_Exception('Method (:method) does not exist in :class',array(':method'=>$method,':class'=>$mo->name)); + + $mmo->name = $method; + $mmo->module_id = $mo->id; + $mmo->values($_POST); + + $output = ''; + + if ($_POST AND $mmo->values($_POST)->check()) { + $mmo->save(); + + if ($mmo->saved()) { + SystemMessage::add(array( + 'title'=>_('Method Added'), + 'type'=>'info', + 'body'=>sprintf(_('Method %s defined to database'),$mmo->name), + )); + + Request::instance()->redirect(sprintf('admin/module/edit/%s',$mo->id)); + + } else { + SystemMessage::add(array( + 'title'=>_('Method Not Saved'), + 'type'=>'error', + 'body'=>sprintf(_('Unable to define Method %s to database?'),$mmo->name), + )); + } + } + + $output .= View::factory('module/admin/method_add') + ->set('module',$mo) + ->set('method',$mmo); + + Block::add(array( + 'title'=>sprintf(_('Add Method (%s) to Database for (%s)'),strtoupper($mmo->name),strtoupper($mo->name)), + 'body'=>$output, + )); + + $this->template->content = Block::factory(); + } + + /** + * Edit a Module Configuration + * + * @param int $mid Module ID + */ + public function action_edit($mid) { + $mmo = ORM::factory('module_method',$mid); + + if (! $mmo->loaded()) { + SystemMessage::add(array( + 'title'=>_('Invalid Method ID'), + 'type'=>'error', + 'body'=>sprintf(_('Method with ID %s doesnt appear to exist?'),$mid), + )); + + return; + } + + $output = ''; + + // The groups that can run this method. + $groups = ORM::factory('group'); + + if ($_POST) { + foreach ($groups->find_all() as $go) { + // If the group was defined and no longer + if ($mmo->has('group',$go) AND (! isset($_POST['groups']) OR ! in_array($go->id,$_POST['groups']))) { + $gm = ORM::factory('group_method',array('method_id'=>$mmo->id,'group_id'=>$go->id)); + + if (! $gm->delete()) + SystemMessage::add(array( + 'title'=>_('Unable to DELETE Group Method'), + 'type'=>'error', + 'body'=>sprintf(_('Unable to delete Group Method for method %s and group %s'),$mmo->name,$go->name), + )); + + // If the group was not defined and now is + } elseif (! $mmo->has('group',$go) AND isset($_POST['groups']) AND in_array($go->id,$_POST['groups'])) { + $gm = ORM::factory('group_method') + ->values(array( + 'method_id'=>$mmo->id, + 'group_id'=>$go->id, + )); + + if (! $gm->check() OR ! $gm->save()) + SystemMessage::add(array( + 'title'=>_('Unable to SAVE Group Method'), + 'type'=>'error', + 'body'=>sprintf(_('Unable to save Group Method for method %s and group %s'),$mmo->name,$go->name), + )); + } + } + } + + $output .= Form::open(); + + $output .= View::factory('module/admin/method_detail_header'); + foreach ($groups->find_all() as $go) { + $output .= View::factory('module/admin/method_detail_body') + ->set('group',$go) + ->set('defined',$mmo->has('group',$go)); + } + $output .= View::factory('module/admin/method_detail_footer'); + + $output .= '
                    '.Form::submit('submit',_('Update')).'
                    '; + $output .= Form::close(); + + Block::add(array( + 'title'=>sprintf(_('%s->%s Method'),strtoupper($mmo->module->name),strtoupper($mmo->name)), + 'body'=>$output, + )); + + $this->template->content = Block::factory(); + } +} +?> diff --git a/modules/module/classes/controller/module.php b/modules/module/classes/controller/module.php new file mode 100644 index 00000000..8a8328e7 --- /dev/null +++ b/modules/module/classes/controller/module.php @@ -0,0 +1,52 @@ +TRUE, + 'list'=>TRUE, + 'menu'=>TRUE, + ); + + public function action_menu() { + // Redirect us to the admin menu, no user facilities here! + Request::instance()->redirect('/admin/module/menu'); + } + + /** + * Get the list of methods for a class + */ + protected function _methods($class) { + // Get a list of methods this module has + $ch = 'Controller_%s'; + $methods = array(); + + // List of classes where all our methods are, including this one. + $classes = Kohana::config('config.method_directory'); + array_unshift($classes,''); + + foreach ($classes as $c) { + $cn = sprintf($ch,$c ? $c.'_'.$class : $class); + + if (class_exists($cn)) { + $r = new ReflectionClass($cn); + + foreach ($r->getMethods() as $method) + if (preg_match('/^Controller_(.*_)?'.$class.'$/i',$method->class) AND ! preg_match('/^_/',$method->name)) + array_push($methods,str_replace('action_',($c ? $c.'_' : $c),$method->name)); + } + } + + return $methods; + } +} +?> diff --git a/modules/module/classes/model/group/method.php b/modules/module/classes/model/group/method.php new file mode 100644 index 00000000..6b44eaac --- /dev/null +++ b/modules/module/classes/model/group/method.php @@ -0,0 +1,26 @@ +array(), + ); + protected $_belongs_to = array( + 'group'=>array(), + ); + + // This module doesnt keep track of column updates automatically + protected $_created_column = FALSE; + protected $_updated_column = FALSE; +} +?> diff --git a/modules/module/classes/model/module/method.php b/modules/module/classes/model/module/method.php new file mode 100644 index 00000000..70eed89d --- /dev/null +++ b/modules/module/classes/model/module/method.php @@ -0,0 +1,37 @@ +array(), + ); + protected $_has_one = array( + 'record_id'=>array(), + ); + protected $_has_many = array( + 'group'=>array('through'=>'group_method','foreign_key'=>'method_id') + ); + + protected $_sorting = array( + 'name'=>'ASC', + ); + + protected $_formats = array( + 'menu_display'=>array('StaticList_YesNo::display'=>array()), + ); + + // This module doesnt keep track of column updates automatically + protected $_created_column = FALSE; + protected $_updated_column = FALSE; +} +?> diff --git a/modules/module/classes/model/module/method/token.php b/modules/module/classes/model/module/method/token.php new file mode 100644 index 00000000..42ee3249 --- /dev/null +++ b/modules/module/classes/model/module/method/token.php @@ -0,0 +1,26 @@ +array(), + 'module_method'=>array(), + ); + protected $_has_one = array( + 'record_id'=>array(), + ); + + // This module doesnt keep track of column updates automatically + protected $_update_column = FALSE; +} +?> diff --git a/modules/module/classes/model/record/id.php b/modules/module/classes/model/record/id.php new file mode 100644 index 00000000..5a364801 --- /dev/null +++ b/modules/module/classes/model/record/id.php @@ -0,0 +1,41 @@ +id)) { + $this->module_id = $mid; + + // We'll get the next ID as the MAX(id) of the table + $mo = ORM::factory('module',$mid); + + $max = DB::select(array('MAX(id)','id')) + ->from($mo->name) + ->where('site_id','=',Config::siteid()); + + $this->id = $max->execute()->get('id'); + } + + $this->id++; + + if (! $this->save()) + throw new Koahan_Exception(_('Unable to increase ID for :table'),array(':table'=>$mid)); + + return $this->id; + } +} +?> diff --git a/modules/module/classes/module/method.php b/modules/module/classes/module/method.php new file mode 100644 index 00000000..3a1e38b9 --- /dev/null +++ b/modules/module/classes/module/method.php @@ -0,0 +1,53 @@ +param(':siteid',Config::siteid()) + ->param(':gid',$gid); + + foreach ($query->execute() as $record) { + $modules[$record['module']]['id'] = $record['MOD_ID']; + $modules[$record['module']]['parent_id'] = $record['PARENT_ID']; + $modules[$record['module']]['parent'] = $record['parent']; + } + + return $modules; + } + + /** + * Display the methods available for a group + */ + public static function groupmethods($gid,$mid) { + $methods = array(); + // @todo the database prefix needs to be added to this query + $query = DB::query(Database::SELECT,'SELECT C.id,C.name AS METHOD,A.name AS MODULE,C.page FROM ab_module A, ab_module_method C, ab_group_method D WHERE A.id=C.module_id AND A.site_id=C.site_id AND D.method_id=C.id AND D.site_id=C.site_id AND D.group_id=:gid AND C.module_id=:mid AND C.menu_display=1 AND A.site_id=:siteid') + ->param(':siteid',Config::siteid()) + ->param(':gid',$gid) + ->param(':mid',$mid); + + foreach ($query->execute() as $record) { + $methods[$record['METHOD']]['id'] = $record['id']; + $methods[$record['METHOD']]['page'] = $record['page']; + $methods[$record['METHOD']]['module'] = $record['MODULE']; + } + + return $methods; + } +} +?> diff --git a/modules/module/module.inc.php b/modules/module/module.inc.php index 88a9ae54..ca0f1dfb 100644 --- a/modules/module/module.inc.php +++ b/modules/module/module.inc.php @@ -32,8 +32,8 @@ class module extends OSB_module { /** * Initialise the module */ - public function __construct() { - parent::__construct(); + public function __construct($id=null) { + parent::__construct($id); $this->dev_inst_excl = array( 'staff','staff_department', @@ -239,6 +239,7 @@ class module extends OSB_module { $dependancy = sprintf('%s,%s',$parent,$install['install']['module_properties']['dependancy']); else $dependancy = $parent; + $dependancy = preg_replace('/,$/','',$dependancy); if ($dependancy) { if (preg_match('/,/', $dependancy)) diff --git a/modules/module/views/module/admin/list_body.php b/modules/module/views/module/admin/list_body.php new file mode 100644 index 00000000..029b6ef3 --- /dev/null +++ b/modules/module/views/module/admin/list_body.php @@ -0,0 +1,4 @@ + + name; ?> + display('status'); ?> + diff --git a/modules/module/views/module/admin/list_footer.php b/modules/module/views/module/admin/list_footer.php new file mode 100644 index 00000000..000ca4b0 --- /dev/null +++ b/modules/module/views/module/admin/list_footer.php @@ -0,0 +1 @@ + diff --git a/modules/module/views/module/admin/list_header.php b/modules/module/views/module/admin/list_header.php new file mode 100644 index 00000000..fb7b110b --- /dev/null +++ b/modules/module/views/module/admin/list_header.php @@ -0,0 +1,6 @@ + + + + + + diff --git a/modules/module/views/module/admin/method_add.php b/modules/module/views/module/admin/method_add.php new file mode 100644 index 00000000..c14616e9 --- /dev/null +++ b/modules/module/views/module/admin/method_add.php @@ -0,0 +1,21 @@ + +
                    ModuleActive
                    + + + + + + + + + + + + + + + + +
                    Modulename; ?>
                    Namename; ?>
                    Notesname); ?>
                    Menu Display
                    + + diff --git a/modules/module/views/module/admin/method_detail_body.php b/modules/module/views/module/admin/method_detail_body.php new file mode 100644 index 00000000..20546ce5 --- /dev/null +++ b/modules/module/views/module/admin/method_detail_body.php @@ -0,0 +1,8 @@ + + + display('name'); ?> + + display('notes'); ?> + display('status'); ?> + id,$defined); ?> + diff --git a/modules/module/views/module/admin/method_detail_footer.php b/modules/module/views/module/admin/method_detail_footer.php new file mode 100644 index 00000000..000ca4b0 --- /dev/null +++ b/modules/module/views/module/admin/method_detail_footer.php @@ -0,0 +1 @@ + diff --git a/modules/module/views/module/admin/method_detail_header.php b/modules/module/views/module/admin/method_detail_header.php new file mode 100644 index 00000000..b0b73358 --- /dev/null +++ b/modules/module/views/module/admin/method_detail_header.php @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/module/views/module/admin/method_list_body.php b/modules/module/views/module/admin/method_list_body.php new file mode 100644 index 00000000..9faa0db2 --- /dev/null +++ b/modules/module/views/module/admin/method_list_body.php @@ -0,0 +1,11 @@ + + + + + diff --git a/modules/module/views/module/admin/method_list_footer.php b/modules/module/views/module/admin/method_list_footer.php new file mode 100644 index 00000000..000ca4b0 --- /dev/null +++ b/modules/module/views/module/admin/method_list_footer.php @@ -0,0 +1 @@ +
                    MethodNotesGroup ActiveMethod Enabled
                    + + name; ?> + + name; ?> + + display('notes'); ?>display('menu_display'); ?>
                    diff --git a/modules/module/views/module/admin/method_list_header.php b/modules/module/views/module/admin/method_list_header.php new file mode 100644 index 00000000..a70da832 --- /dev/null +++ b/modules/module/views/module/admin/method_list_header.php @@ -0,0 +1,7 @@ + + + + + + + diff --git a/modules/module/views/module/admin/method_list_spacer.php b/modules/module/views/module/admin/method_list_spacer.php new file mode 100644 index 00000000..673ad726 --- /dev/null +++ b/modules/module/views/module/admin/method_list_spacer.php @@ -0,0 +1,3 @@ + + + diff --git a/modules/module_method/module_method_construct.xml b/modules/module_method/module_method_construct.xml index aa980ae1..b33058d4 100644 --- a/modules/module_method/module_method_construct.xml +++ b/modules/module_method/module_method_construct.xml @@ -54,6 +54,7 @@ C2(128) + 1 C(128) diff --git a/modules/payment/auth.inc.php b/modules/payment/auth.inc.php new file mode 100644 index 00000000..474549d7 --- /dev/null +++ b/modules/payment/auth.inc.php @@ -0,0 +1,33 @@ + + * @copyright 2009 Deon George + * @link http://osb.leenooks.net + * + * @link http://www.agileco.com/ + * @copyright 2004-2008 Agileco, LLC. + * @license http://www.agileco.com/agilebill/license1-4.txt + * @author Tony Landis + * @package AgileBill + * @subpackage Modules:Invoice + */ + +/** + * The main AgileBill Payment Class + * + * @package AgileBill + */ + +$auth_methods = array ( +); +?> diff --git a/modules/payment/classes/model/payment.php b/modules/payment/classes/model/payment.php new file mode 100644 index 00000000..b66cd605 --- /dev/null +++ b/modules/payment/classes/model/payment.php @@ -0,0 +1,41 @@ +array(), + 'invoice'=>array('through'=>'payment_item'), + ); + protected $_belongs_to = array( + 'account'=>array(), + 'checkout'=>array('foreign_key'=>'checkout_plugin_id'), + ); + + protected $_sorting = array('date_payment'=>'DESC'); + + protected $_formats = array( + 'date_payment'=>array('Model_Invoice::_filters'=>array('date','d-m-Y')), + 'total_amt'=>array('Currency::display'=>array()), + ); + + /** + * Find all items that are exportable. + * + * @param int $start List payments that were modified this many days ago + */ + public function export($start) { + return ORM::factory('payment') + ->where('date_payment','>=',time()-$start*86400) + ->find_all(); + } +} diff --git a/modules/payment/classes/model/payment/item.php b/modules/payment/classes/model/payment/item.php new file mode 100644 index 00000000..79a52364 --- /dev/null +++ b/modules/payment/classes/model/payment/item.php @@ -0,0 +1,15 @@ +array(),'invoice'=>array()); +} diff --git a/modules/payment/payment.inc.php b/modules/payment/payment.inc.php new file mode 100644 index 00000000..8d51309d --- /dev/null +++ b/modules/payment/payment.inc.php @@ -0,0 +1,241 @@ +. + * + * Originally authored by Deon George + * + * @author Deon George + * @copyright 2009 Deon George + * @link http://osb.leenooks.net + * @license http://www.gnu.org/licenses/ + * @package AgileBill + * @subpackage Modules:Payment + */ + +/** + * The main AgileBill Payment Class + * + * @package AgileBill + * @subpackage Modules:Payment + */ +class payment extends OSB_module { + public function allocate($VAR) { return $this->tmAllocate($VAR); } + /** + * Template Method to support the allocation of payments to invoices + * + * @uses payment_item + * @uses invoice + */ + public function tmAllocate($VAR) { + $db = DB(); + $invoices = array(); + + include_once(PATH_MODULES.'payment_item/payment_item.inc.php'); + $pi = new payment_item; + + include_once(PATH_MODULES.'invoice/invoice.inc.php'); + $io = new Invoice; + + # Get our payment information + $payment = $this->sPaymentsBal($VAR['payment_id']); + + # If this payment has been allocated to some invoices, collect those details + $payment_items = $pi->sPaymentAllocation($VAR['payment_id']); + + foreach ($io->sInvoicesBal($payment['account_id']) as $index => $details) { + $invoices[$index] = $details; + + # Get additional information on the invoices to be displayed. + $invoices[$index]['id'] = $index; + $invoices[$index]['_C'] = sprintf('row%s',$i++%2 ? 1 : 2); + if (isset($payment_items[$index])) { + $invoices[$index]['alloc_amt'] = $payment_items[$index]; + unset($payment_items[$index]); + } + } + + # Left over payment_items are fully paid invoices + if (count($payment_items)) { + foreach ($io->sInvoicesAcc($payment['account_id'],array_keys($payment_items)) as $index => $details) { + $invoices[$index] = $details; + + # Get additional information on the invoices to be displayed. + $invoices[$index]['id'] = $index; + $invoices[$index]['_C'] = sprintf('row%s',$i++%2 ? 1 : 2); + $invoices[$index]['alloc_amt'] = $payment_items[$index]; + } + } + + # Sort the entries + ksort($invoices); + + global $smarty; + $smarty->assign('invoices',$invoices); + $smarty->assign('results',count($invoices)); + } + + /** + * Compare the billed_amt with the payments, and auto fix when the allocation is not correct + */ + public function taskAuditPaymentItems() { + $db = DB(); + + $rs = $db->Execute(sprintf('SELECT A.id,A.account_id,A.billed_amt,A.total_amt,IFNULL(A.credit_amt,0) as credit_amt,ROUND(SUM(IFNULL(B.alloc_amt,0)),4) AS alloc_amt FROM %sinvoice A LEFT OUTER JOIN %spayment_item B ON (A.id=B.invoice_id) WHERE A.site_id=%s GROUP BY A.id HAVING A.billed_amt != alloc_amt',AGILE_DB_PREFIX,AGILE_DB_PREFIX,DEFAULT_SITE)); + if ($rs && $rs->RecordCount()) { + while (! $rs->EOF) { + $db->Execute(sqlUpdate('invoice',array('billed_amt'=>$rs->fields['alloc_amt']),array('where'=>array('id'=>$rs->fields['id'])))); + + # Add a memo + $db->Execute(sqlInsert($db,'invoice_memo',array('date_orig'=>time(),'invoice_id'=>$rs->fields['id'],'account_id'=>$rs->fields['account_id'],'type'=>'audit','memo'=>sprintf('Payments applied to this invoice have been changed, due to over allocation, was: %3.2f, payments applied: %3.2f, credits applied: %3.2f',$rs->fields['billed_amt'],$rs->fields['alloc_amt'],$rs->fields['credit_amt'])))); + + $rs->MoveNext(); + } + } + } + + public function ListUnbalanced($VAR) { return $this->tmListUnbalanced($VAR); } + /** + * List all invoices that are out of balance with the payment tables. + * + * @return void + */ + public function tmListUnbalanced() { + global $smarty; + + $db = DB(); + $smart = array(); + + $counter = 0; + $rs = $db->Execute(sprintf('SELECT B.payment_id AS id,A.account_id,B.invoice_id,A.billed_amt,A.total_amt,IFNULL(A.credit_amt,0) as credit_amt,B.payment_id,ROUND(SUM(IFNULL(B.alloc_amt,0)),4) AS alloc_amt,A.date_orig FROM %sinvoice A LEFT OUTER JOIN %spayment_item B ON (A.id=B.invoice_id) WHERE A.site_id=%s GROUP BY A.id HAVING A.billed_amt != alloc_amt OR A.total_amt < A.billed_amt ORDER BY A.account_id,A.id',AGILE_DB_PREFIX,AGILE_DB_PREFIX,DEFAULT_SITE)); + if ($rs && $rs->RecordCount()) { + while (! $rs->EOF) { + $rs->fields['_C'] = ++$counter%s ? 'row1' : 'row2'; + array_push($smart,$rs->fields); + $rs->MoveNext(); + } + } + + $smarty->assign('results',count($smart)); + $smarty->assign('limit',count($smart)); + $smarty->assign('search_show',$smart); + } + + public function ListUnallocated($VAR) { return $this->tmListUnallocated($VAR); } + /** + * Return payments that still have unallocated balances + * + * @return void + * @uses invoice + */ + public function tmListUnallocated($VAR) { + global $smarty; + + require_once(PATH_MODULES.'invoice/invoice.inc.php'); + $io = new invoice; + $accounts = $io->sAccountsBal(); + + $smart = array(); + $counter = 0; + foreach ($this->sPaymentsBal() as $payment) { + $payment['_C'] = ++$counter%s ? 'row1' : 'row2'; + $payment['balance'] = $payment['total_amt']-$payment['alloc_amt']; + $payment['acct_bal'] = isset($accounts[$payment['account_id']]) ? $accounts[$payment['account_id']] : 0; + array_push($smart,$payment); + } + + $smarty->assign('results',count($smart)); + $smarty->assign('limit',count($smart)); + $smarty->assign('search_show',$smart); + } + + public function ListInvoicesBalance($VAR) { return $this->tmListInvoicesBalance($VAR); } + public function tmListInvoicesBalance($VAR) { + global $smarty; + + $smart = array(); + $counter = 0; + foreach ($this->sAccountsBal() as $account_id => $invoices) { + foreach ($invoices as $index => $values) { + $smart[$index] = $values; + $smart[$index]['_C'] = ++$counter%s ? 'row1' : 'row2'; + } + } + + $smarty->assign('results',count($smart)); + $smarty->assign('limit',count($smart)); + $smarty->assign('search_show',$smart); + } + + /** + * Return a list of payments with an unallocated balance + * + * @param $payment_id Return only this payment ID, otherwise return all payment IDs. + * @return array Payments with a unallocated balance + */ + public function sPaymentsBal($payment_id=null) { + static $sPaymentsBal = array(); + + if (! count($sPaymentsBal) || (! is_null($payment_id) && ! isset($sPaymentsBal[$payment_id]))) { + $db = &DB(); + + $rs = $db->Execute(sprintf('SELECT A.id,A.account_id,A.total_amt,ROUND(SUM(IFNULL(B.alloc_amt,0)),4) AS alloc_amt,A.date_orig FROM %spayment A LEFT OUTER JOIN %spayment_item B ON (B.payment_id=A.id) WHERE A.site_id=%s GROUP BY (A.id) HAVING %s alloc_amt != A.total_amt ORDER BY A.account_id', + AGILE_DB_PREFIX,AGILE_DB_PREFIX,DEFAULT_SITE,is_null($payment_id) ? '' : sprintf('A.id=%s OR',$payment_id))); + if ($rs && $rs->RecordCount()) { + while (! $rs->EOF) { + $sPaymentsBal[$rs->fields['id']]['id'] = $rs->fields['id']; + $sPaymentsBal[$rs->fields['id']]['account_id'] = $rs->fields['account_id']; + $sPaymentsBal[$rs->fields['id']]['total_amt'] = $rs->fields['total_amt']; + $sPaymentsBal[$rs->fields['id']]['alloc_amt'] = $rs->fields['alloc_amt']; + $sPaymentsBal[$rs->fields['id']]['date_orig'] = $rs->fields['date_orig']; + $rs->MoveNext(); + } + } + } + + return (is_null($payment_id) ? $sPaymentsBal : (isset($sPaymentsBal[$payment_id]) ? $sPaymentsBal[$payment_id] : array())); + } + + /** + * Return a list of invoices with unbalanced payments + * + * @param $account_id Return invoices with unbalanced payments for an account, otherwise return all accounts + * @return array Invoices with unbalanced payments + */ + public function sAccountsBal($account_id) { + static $sAccountsBal = array(); + + if (! count($sAccountsBal) || (! is_null($account_id) && ! isset($sAccountsBal[$account_id]))) { + $db = &DB(); + + $rs = $db->Execute(sprintf('SELECT A.id,A.account_id,A.total_amt,A.billed_amt,IFNULL(A.credit_amt,0) as credit_amt,ROUND(SUM(IFNULL(B.alloc_amt,0)),4) AS alloc_amt,A.date_orig,B.payment_id FROM %sinvoice A INNER JOIN %spayment_item B ON (B.invoice_id=A.id) WHERE A.site_id=%s GROUP BY (A.id) HAVING %s A.total_amt!=alloc_amt+credit_amt ORDER BY A.account_id,A.id', + AGILE_DB_PREFIX,AGILE_DB_PREFIX,DEFAULT_SITE,is_null($account_id) ? '' : sprintf('A.account_id=%s AND',$account_id))); + if ($rs && $rs->RecordCount()) { + while (! $rs->EOF) { + $sAccountsBal[$rs->fields['account_id']][$rs->fields['id']]['id'] = $rs->fields['payment_id']; + $sAccountsBal[$rs->fields['account_id']][$rs->fields['id']]['invoice_id'] = $rs->fields['id']; + $sAccountsBal[$rs->fields['account_id']][$rs->fields['id']]['account_id'] = $rs->fields['account_id']; + $sAccountsBal[$rs->fields['account_id']][$rs->fields['id']]['total_amt'] = $rs->fields['total_amt']; + $sAccountsBal[$rs->fields['account_id']][$rs->fields['id']]['alloc_amt'] = $rs->fields['alloc_amt']; + $sAccountsBal[$rs->fields['account_id']][$rs->fields['id']]['date_orig'] = $rs->fields['date_orig']; + $rs->MoveNext(); + } + } + } + + return (is_null($account_id) ? $sAccountsBal : (isset($sAccountsBal[$account_id]) ? $sAccountsBal[$account_id] : array())); + } +} +?> diff --git a/modules/payment/payment_construct.xml b/modules/payment/payment_construct.xml new file mode 100644 index 00000000..655af6dc --- /dev/null +++ b/modules/payment/payment_construct.xml @@ -0,0 +1,248 @@ + + + + payment + +
                    MethodNotesMenu
                     
                    payment
                    + + invoice + + 0 + + date_orig + + 25 + + 1 + + + + + + + + + + Payment + 1 + I4 + 1 + + + + 1 + I4 + + + + date-now + Date Created + I8 + + + + date-now + Date Updated + I8 + + + + account + first_name,last_name + I8 + any + + + + date-time + Payment Date + I8 + + + + checkout + name + Checkout Plugin + I4 + any + + + + C(255) + array + + + + F + float + + + + F + + + + I4 + + + + F + + + + I4 + + + + Refund Status + L + + + + account + username + Source + I8 + any + + + + Pending + L + + + + X + + + + C(32) + + + + + + account_id,date_payment,checkout_plugin_id,total_amt,fees_amt,notes,source_id + account_id,date_payment,checkout_plugin_id,total_amt,fees_amt,notes,pending_status + id,account_id,date_payment,checkout_plugin_id,total_amt,source_id + id,date_orig,account_id,date_payment,checkout_plugin_id,total_amt,fees_amt,notes,source_id + + + + + + + + <view>Payment</view> + + + + + + + id + checkbox + 25px + + + account_id + + + source_id + + + checkout_plugin_id + + + date_payment + date + + + total_amt + currency + + + + + id + checkbox + 25px + + + id + + + date_orig + date + + + total_amt + currency + + + + + id + checkbox + 25px + + + id + + + account_id + + + date_orig + date + + + total_amt + currency + + + alloc_amt + currency + + + balance + currency + + + acct_bal + + + + + id + checkbox + 25px + + + id + + + account_id + + + invoice_id + + + date_orig + date + + + total_amt + currency + + + billed_amt + currency + + + alloc_amt + currency + + + + diff --git a/modules/payment/payment_install.xml b/modules/payment/payment_install.xml new file mode 100644 index 00000000..76546150 --- /dev/null +++ b/modules/payment/payment_install.xml @@ -0,0 +1,61 @@ + + + + + + + + Payment + + 1 + + payment + + + + invoice + + + + + + + + + + Add + 1 + add + + + + delete + + + + List + 1 + search + + + + + Search + 1 + search_form + + + + search_show + + + + update + + + + view + + + + diff --git a/modules/payment_item/payment_item.inc.php b/modules/payment_item/payment_item.inc.php new file mode 100644 index 00000000..7869adf2 --- /dev/null +++ b/modules/payment_item/payment_item.inc.php @@ -0,0 +1,159 @@ +. + * + * Originally authored by Deon George + * + * @author Deon George + * @copyright 2009 Deon George + * @link http://osb.leenooks.net + * @license http://www.gnu.org/licenses/ + * @package AgileBill + * @subpackage Modules:Payment + */ + +/** + * The main AgileBill Payment Class + * + * @package AgileBill + * @subpackage Modules:Payment + */ +class payment_item extends OSB_module { + public function allocate($VAR) { return $this->doAllocate($VAR); } + /** + * Allocate a payment to invoices + * + * @uses invoice + * @uses payment + */ + public function doAllocate($VAR) { + $db = DB(); + + # Get the payment invoices for this account. + include_once(PATH_MODULES.'payment/payment.inc.php'); + $po = new payment; + + # Get our payment information + if (! $payment = $po->sPaymentsBal($VAR['payment_id'])) + return false; + + # Check that our allocation is correct. + $total = round(array_sum($VAR['payment_item_allocate']),2); + + if ($total > $payment['total_amt']) { + global $C_debug; + $C_debug->alert(sprintf('%s: (%3.2f/%3.2f) ?',_('Payment over allocated'),$total,$payment['total_amt'])); + return false; + } + + # If this payment has been allocated to some invoices, collect those details + $payment_items = $this->sPaymentAllocation($VAR['payment_id']); + + # Get the unpaid invoices for this account. + include_once(PATH_MODULES.'invoice/invoice.inc.php'); + $io = new invoice; + $invoices = $io->sInvoicesAcc($payment['account_id'],array_keys($VAR['payment_item_allocate'])); + + # Apply the new allocation + foreach ($VAR['payment_item_allocate'] as $invoice => $alloc) { + if (! trim($alloc)) + continue; + + # Sanity check + if (! isset($invoices[$invoice])) { + global $C_debug; + $C_debug->alert(sprintf('Payment for invoice doesnt exist? (%s)?',$invoices['invoice'])); + + # This payment has been processed + if (isset($payment_items[$invoice])) + unset($payment_items[$invoice]); + + continue; + + } elseif ((isset($payment_items[$invoice]) && $invoices[$invoice]['balance']+$payment_items[$invoice] < $alloc) + || (! isset($payment_items[$invoice]) && $invoices[$invoice]['balance'] < $alloc)) { + + global $C_debug; + $C_debug->alert(sprintf('Over allocation for invoice %s - remaining balance is %s?',$invoice,$invoices[$invoice]['balance'])); + + # This payment has been processed + if (isset($payment_items[$invoice])) + unset($payment_items[$invoice]); + + continue; + } + + # Have we already applied payments to this invoice in the past + if (isset($payment_items[$invoice])) { + if ($alloc != $payment_items[$invoice]) { + # Record the adjusted payment details + $db->Execute(sqlUpdate('payment_item',array('date_last'=>time(),'alloc_amt'=>$alloc),array('where'=>array('payment_id'=>$VAR['payment_id'],'invoice_id'=>$invoice,'alloc_amt'=>$payment_items[$invoice])))); + + # Adjust the invoice balance + $db->Execute(sqlUpdate('invoice',array('billed_amt'=>$invoices[$invoice]['billed_amt']+$alloc-$payment_items[$invoice]),array('where'=>array('id'=>$invoice,'billed_amt'=>$invoices[$invoice]['billed_amt'])))); + } + + # This payment has been processed + unset($payment_items[$invoice]); + + # New payment allocation + } else { + # Reduce the invoice balance + $db->Execute(sqlUpdate('invoice',array('billed_amt'=>$invoices[$invoice]['billed_amt']+$alloc),array('where'=>array('id'=>$invoice)))); + + # Record the payment + $db->Execute(sqlInsert($db,'payment_item',array('date_orig'=>time(),'date_last'=>time(),'payment_id'=>$VAR['payment_id'],'invoice_id'=>$invoice,'alloc_amt'=>$alloc))); + } + } + + # Any left over payments need to be reversed + foreach ($payment_items as $invoice => $alloc) { + if (! $alloc) + continue; + + $db->Execute(sqlUpdate('payment_item',array('date_last'=>time(),'alloc_amt'=>0),array('where'=>array('payment_id'=>$VAR['payment_id'],'invoice_id'=>$invoice,'alloc_amt'=>$payment_items[$invoice])))); + $db->Execute(sqlUpdate('invoice',array('billed_amt'=>$invoices[$invoice]['billed_amt']-$alloc),array('where'=>array('id'=>$invoice,'billed_amt'=>$invoices[$invoice]['billed_amt'])))); + } + + # Force the refresh of the account balances + $io->sInvoicesBal(null,true); + } + + /** + * Get the payment allocation for a payment ID + * + * @param $payment_id Payment ID to retrieve + * @return array Invoices and the payment location + */ + public function sPaymentAllocation($payment_id) { + static $sPaymentAllocation = array(); + + if (! isset($sPaymentsBalance[$payment_id])) { + $db = DB(); + $rs = $db->Execute(sqlSelect('payment_item','invoice_id,alloc_amt',array('where'=>array('payment_id'=>$payment_id)))); + + if ($rs && $rs->RecordCount()) { + while (! $rs->EOF) { + $sPaymentsBalance[$payment_id][$rs->fields['invoice_id']] = $rs->fields['alloc_amt']; + $rs->MoveNext(); + } + } + } + + return $sPaymentsBalance[$payment_id]; + } +} +?> diff --git a/modules/payment_item/payment_item_construct.xml b/modules/payment_item/payment_item_construct.xml new file mode 100644 index 00000000..e7dc725d --- /dev/null +++ b/modules/payment_item/payment_item_construct.xml @@ -0,0 +1,82 @@ + + + + payment_item + + payment_item
                    + + payment + + 0 + + date_orig + + 25 + + 1 + + + + + + + + + + + 1 + I4 + 1 + + + + 1 + I4 + + + + date-now + Date Created + I8 + + + + date-now + Date Updated + I8 + + + + account + I8 + + + + invoice + I8 + + + + F + float + + + + + + payment_id,invoice_id,alloc_amt + + + + + + + + + + + + +
                    diff --git a/modules/payment_item/payment_item_install.xml b/modules/payment_item/payment_item_install.xml new file mode 100644 index 00000000..c62c3651 --- /dev/null +++ b/modules/payment_item/payment_item_install.xml @@ -0,0 +1,58 @@ + + + + + + payment + + + + 0 + + payment_item + + + + payment + + + + + + + + + + add + + + + delete + + + + search + + + + + search_form + + + + search_show + + + + update + + + + view + + + + + + + diff --git a/modules/product/classes/controller/product.php b/modules/product/classes/controller/product.php new file mode 100644 index 00000000..577ca1af --- /dev/null +++ b/modules/product/classes/controller/product.php @@ -0,0 +1,75 @@ +loaded()) + Request::instance()->redirect('welcome/index'); + + Breadcrumb::name($this->request->uri(),$cat->name); + + Block::add(array( + 'title'=>sprintf('%s: %s',_('Category'),$cat->name), + 'body'=>View::factory('product/category/view') + ->set('results',$this->_get_category($cat->id)) + ->set('cat',$cat->id), + )); + + $this->template->content = Block::factory(); + } + + /** + * Obtain a list of pages in a category + */ + private function _get_category($id) { + return ORM::factory('product')->category($id); + } + + /** + * Show a product + */ + public function action_view($id) { + $po = ORM::factory('product',$id); + + if (! $po->loaded()) + Request::instance()->redirect('product_category/index'); + + Breadcrumb::name($this->request->uri(),$po->product_translate->find()->name); + + // Work out our category id for the control line + if (! empty($_GET['cid'])) { + $co = ORM::factory('product_category',$_GET['cid']); + + // If the product category doesnt exist, or doesnt match the product + if (! $co->loaded() OR ! in_array($co->id,unserialize($po->avail_category_id))) + Request::instance()->redirect('product_category/index'); + + Breadcrumb::name('product/view',$co->name); + } + + Block::add(array( + 'title'=>$po->product_translate->find()->description_short, + 'body'=>View::factory('product/view') + ->set('record',$po), + )); + + $this->template->content = Block::factory(); + } +} +?> diff --git a/modules/product/classes/controller/product/category.php b/modules/product/classes/controller/product/category.php new file mode 100644 index 00000000..389bab7d --- /dev/null +++ b/modules/product/classes/controller/product/category.php @@ -0,0 +1,38 @@ +_('Product Categories'), + 'body'=>View::factory('product/category/list') + ->set('results',$this->_get_categories()), + )); + + $this->template->content = Block::factory(); + } + + /** + * Obtain a list of our categories + * @todo Only show categories according to the users group memeberhsip + * @todo Obey sort order + */ + private function _get_categories() { + return ORM::factory('product_category') + ->where('status','=',TRUE) + ->find_all(); + } +} +?> diff --git a/modules/product/classes/model/product.php b/modules/product/classes/model/product.php new file mode 100644 index 00000000..af3463ad --- /dev/null +++ b/modules/product/classes/model/product.php @@ -0,0 +1,89 @@ +array(), + ); + + protected $_sorting = array( + 'position'=>'asc', + 'sku'=>'asc', + ); + + protected $_formats = array( + 'price_type'=>array('StaticList_PriceType::display'=>array()), + ); + + /** + * Return the products for a given category + */ + public function category($cat) { + $results = array(); + foreach ($this->where('active','=',TRUE)->find_all() as $po) { + if ($c = unserialize($po->avail_category_id) AND in_array($cat,$c)) + array_push($results,$po); + } + + return $results; + } + + /** + * Return the best price to the uesr based on the users group's memberships + * @todo This needs to be tested with more than one price group enabled + */ + public function get_price_array() { + if (! $this->loaded()) + throw new Kohana_Exception('Call to :method where no object loaded?',array(':method'=>__METHOD__)); + + // Figure out our eligable groups + // @todo Need to work out our default groups elsewhere, not in product + // All users are members of the all user group "0" + $groups = array(0); + $pg = unserialize($this->price_group); + if (Auth::instance()->logged_in()) + foreach (Auth::instance()->get_user()->group->find_all() as $go) + array_push($groups,$go->id); + + // Work out the best price for the user + $price = array(); + foreach (unserialize($this->price_group) as $bill_freq => $pg) { + if ($pg['show']) + foreach ($groups as $gid) { + if (! empty($pg[$gid])) { + if (empty($price[$bill_freq]['price_base']) + OR ($pg[$gid]['price_base'] AND $price[$bill_freq]['price_base'] > $pg[$gid]['price_base'])) { + $price[$bill_freq]['price_setup'] = $pg[$gid]['price_setup']; + $price[$bill_freq]['price_base'] = $pg[$gid]['price_base']; + } + } + } + } + + return $price; + } + + /** + * Test if the product is a TRIAL product + * (price_type == 2) + * + * @return boolean + */ + public function is_trial() { + if ($this->price_type == 2) + return TRUE; + else + return FALSE; + } +} +?> diff --git a/modules/product/classes/model/product/category.php b/modules/product/classes/model/product/category.php new file mode 100644 index 00000000..8c1f91e4 --- /dev/null +++ b/modules/product/classes/model/product/category.php @@ -0,0 +1,20 @@ +'asc', + ); +} +?> diff --git a/modules/product/classes/model/product/translate.php b/modules/product/classes/model/product/translate.php new file mode 100644 index 00000000..e19e93e5 --- /dev/null +++ b/modules/product/classes/model/product/translate.php @@ -0,0 +1,18 @@ +array(), + ); +} +?> diff --git a/modules/product/product.inc.php b/modules/product/product.inc.php index f1c15260..4c0af71a 100644 --- a/modules/product/product.inc.php +++ b/modules/product/product.inc.php @@ -50,29 +50,30 @@ class product extends OSB_module { $this->details($VAR); } + public function details($VAR) { return $this->tmdetails($VAR); } /** * Show the product details to the user - used on the order form */ - public function details($VAR) { + public function tmdetails($VAR) { global $smarty, $C_auth; if (empty($VAR['id'])) return false; - $db = &DB(); - # Able to view inactive items? if (! $C_auth->auth_method_by_name('invoice','add')) $active = ''; else $active = ' AND active=1'; - $result = $db->Execute($sql = sqlSelect($db,'product','*',sprintf('id=::%s::%s',$VAR['id'],$active))); - if (! count($result->RecordCount())) + $result = $this->sql_GetRecords(array('where'=>sprintf('id=%s%s',$VAR['id'],$active))); + if (! count($result)) return false; + $result = array_pop($result); + # Check for group settings - $groups = unserialize($result->fields['group_avail']); + $groups = unserialize($result['group_avail']); $auth = false; for ($ii=0; $iiauth_group_by_id($groups[$ii])) { @@ -82,20 +83,22 @@ class product extends OSB_module { } } - if (!$auth) + if (! $auth) return false; # Define the DB vars as a Smarty accessible block - $smarty->assign('product',$result->fields); + $smarty->assign('record',$result); # If trial, get the sku of the trial product: - if($result->fields['price_type'] == '2') { - $trial = $db->Execute(sqlSelect($db,'*','product',sprintf('id=::%s::',$result->fields['price_trial_prod']))); - $smarty->assign('trial',$trial->fields); + if ($result['price_type'] == '2') { + $trial = $this->sql_GetRecords(array('where'=>array('id'=>$result['price_trial_prod']))); + + if (count($trial)) + $smarty->assign('trial',array_pop($trial)); } # Get the best price for base, setup, & any attributes: - $this->price_arr($result->fields); + $this->price_arr($result); $smarty->assign('price',$this->price); # Get any attributes & attribute pricing: @@ -323,20 +326,24 @@ class product extends OSB_module { * @param int $weekday Day of Month for fixed billing * @param int $week Unused * @return array + * @todo $temp is a temporary hack to stop the rounding of the dates to the begining of the BILLING_WEEKDAY */ - public function recurrDates($type,$weekday,$week,$period_date=false) { + public function recurrDates($type,$weekday,$week,$period_date=false,$temp=false) { # Make the period consistent, eg: Quarterly = Jan-Mar,Apr-Jun; HalfYearly = Jan-Jun,Jul-Dec $strict = false; $used_months = 0; + # Round the time integer to a whole day. if (! $period_date) $period_date = strtotime('today'); + else + $period_date = strtotime(date('Y-m-d',$period_date)); switch ($type) { # Weekly case 0: $period_end = $period_date+(86400*7); - return array('start'=>$period_date,'date'=>$period_date,'end'=>$period_end); + return array('start'=>$period_date,'date'=>$period_date,'end'=>$period_end,'prorate'=>1); # Monthly case 1: @@ -376,6 +383,11 @@ class product extends OSB_module { return false; } + if (is_null($weekday) && ! $temp) + $weekday = BILLING_WEEKDAY; + elseif ($temp) + $weekday = date('d',$period_date); + if ($strict && $type > 0 && $type < 5) $used_months = $inc_months-(($inc_months-(date('n',$period_date)%$inc_months))%$inc_months+1); @@ -387,7 +399,10 @@ class product extends OSB_module { $period_end = mktime(0,0,0,date('m',$period_start)+$inc_months,$weekday,date('y',$period_start)); - return array('start'=>$period_start,'date'=>$period_date,'end' => $period_end); + $total_time = $period_end-$period_start; + $remain_time = $period_end-$period_date; + + return array('start'=>$period_start,'date'=>$period_date,'end'=>$period_end,'prorata'=>round($remain_time/$total_time,4)); } /** @@ -398,17 +413,13 @@ class product extends OSB_module { * @param int $week * @return float */ - private function prorate($type,$weekday,$week,$period_start=false) { + public function prorate($type,$weekday,$week,$period_start=false) { $arr = $this->recurrDates($type,$weekday,$week,$period_start); - if (!$arr) + if (! $arr) return 0; - - $total_time = $arr['end']-$arr['start']; - $remain_time = $arr['end']-$arr['date']; - $percent_remain = ($remain_time/$total_time) ; - - return round($percent_remain,4); + else + return $arr['prorata']; } /** @@ -770,5 +781,24 @@ class product extends OSB_module { $db = new CORE_database; $db->mass_delete($VAR, $this, ""); } + + public function getTranslateField($field) { + static $CACHE = array(); + + if (! $id = $this->getRecordAttr('id')) + return null; + + if (! isset($CACHE[$id][$field])) { + $db = &DB(); + $rs = $db->Execute(sqlSelect('product_translate',$field,array('where'=>array('product_id'=>$id)))); + + if ($rs && $rs->RecordCount() && isset($rs->fields[$field])) + $CACHE[$id][$field] = $rs->fields[$field]; + else + $CACHE[$id][$field] = null; + } + + return $CACHE[$id][$field]; + } } ?> diff --git a/modules/product/product_construct.xml b/modules/product/product_construct.xml index 591a031f..8f2ded6d 100644 --- a/modules/product/product_construct.xml +++ b/modules/product/product_construct.xml @@ -80,27 +80,39 @@ array 1 + + Hosting L + + Hosting Server I4 X2 array + + Allow Domain Purchases with this Hosting Plan? L + + Allow Purchases without a domain? L + - X2 array + Discount the following TLDs + X2 + + Domain Purchase Discount Amount F @@ -109,6 +121,7 @@ F + I4 @@ -213,11 +226,11 @@ - id,site_id,date_orig,date_last,sku,taxable,active,group_avail,position,cart_multiple,avail_category_id,discount,discount_amount,price_type,price_base,price_setup,price_group,price_recurr_type,price_recurr_weekday,price_recurr_week,price_recurr_schedule,price_recurr_cancel,price_trial_length_type,price_trial_length,price_trial_prod,assoc_req_prod,assoc_req_prod_type,assoc_grant_prod,assoc_grant_group,assoc_grant_group_type,assoc_grant_group_days,thumbnail,price_recurr_default,price_recurr_modify,modify_waive_setup,modify_product_arr - id,site_id,date_orig,date_last,sku,taxable,active,group_avail,position,cart_multiple,avail_category_id,discount,discount_amount,price_type,price_base,price_setup,price_group,price_recurr_type,price_recurr_weekday,price_recurr_week,price_recurr_schedule,price_recurr_cancel,price_trial_length_type,price_trial_length,price_trial_prod,assoc_req_prod,assoc_req_prod_type,assoc_grant_prod,assoc_grant_group,assoc_grant_group_type,assoc_grant_group_days,thumbnail,price_recurr_default,host,host_server_id,host_provision_plugin_data,host_allow_domain,host_allow_host_only,host_discount_tld,host_discount_tld_amt,prod_plugin,prod_plugin_file,prod_plugin_data,price_recurr_modify,modify_waive_setup,modify_product_arr - id,site_id - id,site_id,date_orig,date_last,sku,taxable,active,group_avail,position,cart_multiple,avail_category_id,discount,discount_amount,price_type,price_base,price_setup,price_group,price_recurr_type,price_recurr_weekday,price_recurr_week,price_recurr_schedule,price_recurr_cancel,price_trial_length_type,price_trial_length,price_trial_prod,assoc_req_prod,assoc_req_prod_type,assoc_grant_prod,assoc_grant_group,assoc_grant_group_type,assoc_grant_group_days,thumbnail,price_recurr_default,host,host_server_id,host_provision_plugin_data,host_allow_domain,host_allow_host_only,host_discount_tld,host_discount_tld_amt,prod_plugin,prod_plugin_file,prod_plugin_data,price_recurr_modify,modify_waive_setup,modify_product_arr - id,site_id,date_orig,date_last,sku,taxable,active,group_avail,position,cart_multiple,avail_category_id,price_type,price_recurr_schedule,price_recurr_cancel,price_base,price_setup + sku,taxable,active,group_avail,avail_category_id,discount,price_type,price_base,price_setup,price_group,price_recurr_type,price_recurr_weekday,price_recurr_week,price_recurr_default + id,date_last,sku,taxable,active,group_avail,position,cart_multiple,avail_category_id,discount,discount_amount,price_type,price_base,price_setup,price_group,price_recurr_type,price_recurr_weekday,price_recurr_week,price_recurr_schedule,price_recurr_cancel,price_trial_length_type,price_trial_length,price_trial_prod,assoc_req_prod,assoc_req_prod_type,assoc_grant_prod,assoc_grant_group,assoc_grant_group_type,assoc_grant_group_days,thumbnail,price_recurr_default,host,host_server_id,host_provision_plugin_data,host_allow_domain,host_allow_host_only,host_discount_tld,host_discount_tld_amt,prod_plugin,prod_plugin_file,prod_plugin_data,price_recurr_modify,modify_waive_setup,modify_product_arr + id + id,date_orig,date_last,sku,taxable,active,group_avail,position,cart_multiple,avail_category_id,discount,discount_amount,price_type,price_base,price_setup,price_group,price_recurr_type,price_recurr_weekday,price_recurr_week,price_recurr_schedule,price_recurr_cancel,price_trial_length_type,price_trial_length,price_trial_prod,assoc_req_prod,assoc_req_prod_type,assoc_grant_prod,assoc_grant_group,assoc_grant_group_type,assoc_grant_group_days,thumbnail,price_recurr_default,host,host_server_id,host_provision_plugin_data,host_allow_domain,host_allow_host_only,host_discount_tld,host_discount_tld_amt,prod_plugin,prod_plugin_file,prod_plugin_data,price_recurr_modify,modify_waive_setup,modify_product_arr + id,date_orig,date_last,sku,taxable,active,group_avail,position,cart_multiple,avail_category_id,price_type,price_recurr_schedule,price_recurr_cancel,price_base,price_setup diff --git a/modules/product/product_install.xml b/modules/product/product_install.xml index fa6c8a25..195e21d9 100644 --- a/modules/product/product_install.xml +++ b/modules/product/product_install.xml @@ -17,7 +17,7 @@ - base + diff --git a/modules/product/views/product/category/list.php b/modules/product/views/product/category/list.php new file mode 100644 index 00000000..49d90c29 --- /dev/null +++ b/modules/product/views/product/category/list.php @@ -0,0 +1,7 @@ + + + + + + +
                    diff --git a/modules/product/views/product/category/view.php b/modules/product/views/product/category/view.php new file mode 100644 index 00000000..c32386ba --- /dev/null +++ b/modules/product/views/product/category/view.php @@ -0,0 +1,40 @@ +product_translate->where('product_id','=',$record->id)->and_where('language_id','=','fr')->find(); + + // If there isnt a translated page, show the default language + // @todo - default language should come from configuration + if (! $translate->loaded()) + $translate = $record->product_translate->where('product_id','=',$record->id)->and_where('language_id','=','en')->find(); +?> + + + + + +
                    + + + + + + + +
                    name; ?> (price_base); ?>/mth)
                    + + + + +
                    description_short; ?>
                    +
                    +
                    +
                    + diff --git a/modules/product/views/product/view.php b/modules/product/views/product/view.php new file mode 100644 index 00000000..df26f841 --- /dev/null +++ b/modules/product/views/product/view.php @@ -0,0 +1,85 @@ +product_translate->where('product_id','=',$record->id)->and_where('language_id','=','fr')->find(); + +// If there isnt a translated page, show the default language +// @todo - default language should come from configuration +if (! $translate->loaded()) + $translate = $record->product_translate->where('product_id','=',$record->id)->and_where('language_id','=','en')->find(); + +// @todo Need to add in product attributes +// @todo Need to add in product plugins + +echo Form::open('cart/add'); +?> + + + + +
                    + id); ?> + + + + + + + + +
                    + + + + prod_plugin && method_exists($record->prod_plugin_file,'product_view')) { + $pio = new $record->prod_plugin_file; + echo ''; + } ?> + + + + prod_plugin && method_exists($record->prod_plugin_file,'contract_view')) { + $pio = new $record->prod_plugin_file; + echo ''; + } ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                    description_full; ?>'.$pio->product_view($record->prod_plugin_data).'
                     '.$pio->contract_view($record->prod_plugin_data,$record->price_base,$record->price_setup).'
                     
                    SKUCurrency
                    sku;?>'=:1'));?>
                    Price TypeTaxable
                    price_type);?>taxable);?>
                    Recurring Billing Schedule 
                    +
                    | 'disabled')); ?>
                    +
                    + +
                    diff --git a/modules/product_attr/product_attr_construct.xml b/modules/product_attr/product_attr_construct.xml index 731fa777..f639c737 100644 --- a/modules/product_attr/product_attr_construct.xml +++ b/modules/product_attr/product_attr_construct.xml @@ -76,11 +76,11 @@ - id,site_id,name,description,sort_order,collect_type,collect_default,price_base,price_setup,price_group,product_id,required - id,site_id,name,description,sort_order,collect_type,collect_default,price_base,price_setup,price_group,product_id,required - id,site_id,name,description,sort_order,collect_type,collect_default,price_base,price_setup,price_group,product_id,required - id,site_id,name,description,sort_order,collect_type,collect_default,price_base,price_setup,price_group,product_id,required - id,site_id,name,sort_order,collect_type,collect_default,price_base,price_group,product_id,required + name,description,collect_type,collect_default,price_base,price_setup,price_group,product_id + id,name,description,sort_order,collect_type,collect_default,price_base,price_setup,price_group,product_id,required + id + id,name,description,sort_order,collect_type,collect_default,price_base,price_setup,price_group,product_id,required + id,name,sort_order,collect_type,collect_default,price_base,price_group,product_id,required diff --git a/modules/product_attr/product_attr_install.xml b/modules/product_attr/product_attr_install.xml index 6e413ed0..d6a59940 100644 --- a/modules/product_attr/product_attr_install.xml +++ b/modules/product_attr/product_attr_install.xml @@ -17,7 +17,7 @@ - base + diff --git a/modules/product_cat/product_cat_construct.xml b/modules/product_cat/product_cat_construct.xml index 9ba49da2..5c557ac6 100644 --- a/modules/product_cat/product_cat_construct.xml +++ b/modules/product_cat/product_cat_construct.xml @@ -85,11 +85,11 @@ - id,site_id,name,notes,status,template,thumbnail,image,position,max,group_avail,parent_id - id,site_id,name,notes,status,template,thumbnail,image,position,max,group_avail,parent_id - id,site_id,name,notes,status,template,thumbnail,image,position,max,group_avail,parent_id - id,site_id,name,notes,status,template,thumbnail,image,position,max,group_avail,parent_id - id,site_id,name,notes,status,template,thumbnail,image,position,max,group_avail,parent_id + name,max,template,group_avail + id,name,notes,status,template,thumbnail,image,position,max,group_avail,parent_id + id + id,name,notes,status,template,thumbnail,image,position,max,group_avail,parent_id + id,name,notes,status,template,thumbnail,image,position,max,group_avail,parent_id diff --git a/modules/product_cat/product_cat_install.xml b/modules/product_cat/product_cat_install.xml index 13c5254a..b30ba66d 100644 --- a/modules/product_cat/product_cat_install.xml +++ b/modules/product_cat/product_cat_install.xml @@ -17,7 +17,7 @@ - base + diff --git a/modules/product_cat_translate/product_cat_translate_construct.xml b/modules/product_cat_translate/product_cat_translate_construct.xml index 908df80d..c8faaeac 100644 --- a/modules/product_cat_translate/product_cat_translate_construct.xml +++ b/modules/product_cat_translate/product_cat_translate_construct.xml @@ -56,11 +56,11 @@ - id,site_id,product_cat_id,language_id,name,description - id,site_id,product_cat_id,language_id,name,description - id,site_id,product_cat_id,language_id,name,description - id,site_id,product_cat_id,language_id,name,description - id,site_id,product_cat_id,language_id,name + product_cat_id,language_id,name,description + product_cat_id,language_id,name,description + id + id,product_cat_id,language_id,name,description + id,product_cat_id,language_id,name diff --git a/modules/product_cat_translate/product_cat_translate_install.xml b/modules/product_cat_translate/product_cat_translate_install.xml index 5d10e310..7cf7a2bb 100644 --- a/modules/product_cat_translate/product_cat_translate_install.xml +++ b/modules/product_cat_translate/product_cat_translate_install.xml @@ -17,7 +17,7 @@ - base + diff --git a/modules/product_cat_translate/product_cat_translate_install_data.xml b/modules/product_cat_translate/product_cat_translate_install_data.xml index 3bdc8496..d0b96682 100644 --- a/modules/product_cat_translate/product_cat_translate_install_data.xml +++ b/modules/product_cat_translate/product_cat_translate_install_data.xml @@ -4,7 +4,7 @@ 2 1 1 - english + en Sample Directory links, images, font sizes and colors, @@ -14,7 +14,7 @@ 3 1 5 - english + en Membership View our selection of memberships @@ -22,7 +22,7 @@ 5 1 7 - english + en test test diff --git a/modules/product_img/product_img_install.xml b/modules/product_img/product_img_install.xml index b17efdc6..b5860249 100644 --- a/modules/product_img/product_img_install.xml +++ b/modules/product_img/product_img_install.xml @@ -17,7 +17,7 @@ - base + diff --git a/modules/product_translate/product_translate.inc.php b/modules/product_translate/product_translate.inc.php index 4e00994d..b15ae65c 100644 --- a/modules/product_translate/product_translate.inc.php +++ b/modules/product_translate/product_translate.inc.php @@ -1,125 +1,32 @@ + * @copyright 2009 Deon George + * @link http://osb.leenooks.net * * @link http://www.agileco.com/ * @copyright 2004-2008 Agileco, LLC. * @license http://www.agileco.com/agilebill/license1-4.txt - * @author Tony Landis + * @author Tony Landis * @package AgileBill - * @version 1.4.93 */ - -class product_translate -{ - # Open the constructor for this mod - function product_translate() - { - # name of this module: - $this->module = "product_translate"; - - # location of the construct XML file: - $this->xml_construct = PATH_MODULES . "" . $this->module . "/" . $this->module . "_construct.xml"; - - # open the construct file for parsing - $C_xml = new CORE_xml; - $construct = $C_xml->xml_to_array($this->xml_construct); - - $this->method = $construct["construct"]["method"]; - $this->trigger = $construct["construct"]["trigger"]; - $this->field = $construct["construct"]["field"]; - $this->table = $construct["construct"]["table"]; - $this->module = $construct["construct"]["module"]; - $this->cache = $construct["construct"]["cache"]; - $this->order_by = $construct["construct"]["order_by"]; - $this->limit = $construct["construct"]["limit"]; - } - - - - ############################## - ## ADD ## - ############################## - function add($VAR) - { - $type = "add"; - $this->method["$type"] = explode(",", $this->method["$type"]); - $db = new CORE_database; - $db->add($VAR, $this, $type); - } - - ############################## - ## VIEW ## - ############################## - function view($VAR) - { - $type = "view"; - $this->method["$type"] = explode(",", $this->method["$type"]); - $db = new CORE_database; - $db->view($VAR, $this, $type); - } - - ############################## - ## UPDATE ## - ############################## - function update($VAR) - { - $type = "update"; - $this->method["$type"] = explode(",", $this->method["$type"]); - $db = new CORE_database; - $db->update($VAR, $this, $type); - } - - ############################## - ## DELETE ## - ############################## - function delete($VAR) - { - $db = new CORE_database; - $db->mass_delete($VAR, $this, ""); - } - - ############################## - ## SEARCH FORM ## - ############################## - function search_form($VAR) - { - $type = "search"; - $this->method["$type"] = explode(",", $this->method["$type"]); - $db = new CORE_database; - $db->search_form($VAR, $this, $type); - } - - ############################## - ## SEARCH ## - ############################## - function search($VAR) - { - $type = "search"; - $this->method["$type"] = explode(",", $this->method["$type"]); - $db = new CORE_database; - $db->search($VAR, $this, $type); - } - - ############################## - ## SEARCH SHOW ## - ############################## - - function search_show($VAR) - { - $type = "search"; - $this->method["$type"] = explode(",", $this->method["$type"]); - $db = new CORE_database; - $db->search_show($VAR, $this, $type); - } +/** + * The main AgileBill Product Translate Class + * + * @package AgileBill + * @subpackage Module:Product + */ +class product_translate extends OSB_module { } -?> \ No newline at end of file +?> diff --git a/modules/product_translate/product_translate_construct.xml b/modules/product_translate/product_translate_construct.xml index 9374caf1..b04f308f 100644 --- a/modules/product_translate/product_translate_construct.xml +++ b/modules/product_translate/product_translate_construct.xml @@ -45,31 +45,36 @@ C(16) - C(128) + Name 1 128 + C(128) any - X2 + Short Description 1 + X2 + Full Description X2 1 + + Email Template X2 - id,site_id,product_id,language_id,name,description_short,description_full,email_template - id,site_id,product_id,language_id,name,description_short,description_full,email_template - id,site_id,product_id,language_id,name,description_short,description_full,email_template - id,site_id,product_id,language_id,name,description_short,description_full,email_template - id,site_id,product_id,language_id,name,description_short,description_full,email_template + product_id,language_id,name,description_short,description_full,email_template + id,product_id,language_id,name,description_short,description_full,email_template + id + id,product_id,language_id,name,description_short,description_full,email_template + id,product_id,language_id,name,description_short,description_full,email_template @@ -81,5 +86,18 @@ + + + id + checkbox + 25px + + + language_id + + + name + + diff --git a/modules/product_translate/product_translate_install.xml b/modules/product_translate/product_translate_install.xml index 0fe865b5..3d8c06bf 100644 --- a/modules/product_translate/product_translate_install.xml +++ b/modules/product_translate/product_translate_install.xml @@ -17,7 +17,7 @@ - base + diff --git a/modules/product_translate/product_translate_install_data.xml b/modules/product_translate/product_translate_install_data.xml index 7a9699b8..c9795ded 100644 --- a/modules/product_translate/product_translate_install_data.xml +++ b/modules/product_translate/product_translate_install_data.xml @@ -1,16 +1,16 @@ - - 2 - 1 - 2 - english - Sample Product - -]]> - This is just a sample product, edit as needed or delete. - - - 2 - - \ No newline at end of file + + 2 + 1 + 2 + en + Sample Product + + This is just a sample product, edit as needed or delete. + + + + 2 + + diff --git a/modules/service/classes/controller/admin/service.php b/modules/service/classes/controller/admin/service.php new file mode 100644 index 00000000..903a9cf8 --- /dev/null +++ b/modules/service/classes/controller/admin/service.php @@ -0,0 +1,425 @@ +'services'); + + public $secure_actions = array( + 'listbycheckout'=>TRUE, + 'listadslservices'=>TRUE, + 'listhspaservices'=>TRUE, + ); + + /** + * List all services by their default checkout method + */ + public function action_listbycheckout() { + // @todo need to add the DB prefix here + $services = DB::query(Database::SELECT,' +SELECT c.id AS cid,c.name as checkout_plugin_name,s.id AS sid,a.company,a.first_name,a.last_name,a.id as aid +FROM ab_service s LEFT JOIN ab_account_billing ab ON (s.account_billing_id=ab.id) LEFT JOIN ab_checkout c ON (ab.checkout_plugin_id=c.id),ab_account a, ab_account_group ag +WHERE s.active=1 AND s.price > 0 AND s.account_id=a.id AND a.id=ag.account_id AND ((s.account_billing_id IS NOT NULL AND ag.group_id IS NOT NULL) OR (a.id=ag.account_id and ag.group_id=1003)) +ORDER BY c.id,s.recur_schedule,c.name,a.company,a.last_name,a.first_name + ') + ->execute(); + + // @todo If no items, show a nice message. This is not correct for ORM. + if (! count($services)) { + echo Kohana::debug('No services with account_billing'); + die(); + } + + $last_checkout = ''; + $last_account = ''; + $i = 0; + $sc = $st = 0; + $output = ''; + foreach ($services as $service) { + $so = ORM::factory('service',$service['sid']); + $si = $so->account_id.$so->recur_schedule; + + if (($si != $last_account) AND $last_account) { + if ($sc > 1) + $output .= View::factory('service/list/bycheckout_subtotal') + ->set('subtotal',Currency::display($st)) + ->set('i',$i++%2); + $sc = $st = 0; + } + + if (($service['cid'] != $last_checkout) OR (! is_null($last_checkout) AND ! $last_checkout)) { + $output .= View::factory('service/list/bycheckout_header') + ->set('checkout_name',$service['checkout_plugin_name']) + ->set('last_checkout',$last_checkout); + } + + $last_checkout = $service['cid']; + $last_account = $si; + // @todo This rounding should be a system default + $st += round($so->price+$so->tax(),2); + $sc++; + + $output .= View::factory('service/list/bycheckout_body') + ->set('service',$so) + ->set('i',$i++%2); + } + + // Last subtotal + if ($sc > 1) + $output .= View::factory('service/list/bycheckout_subtotal') + ->set('subtotal',$st) + ->set('i',$i++%2); + + $output .= '
                    '; + + Block::add(array( + 'title'=>_('List all Services by Default Payment Method'), + 'body'=>$output, + )); + + Style::add(array( + 'type'=>'file', + 'data'=>'css/list.css', + )); + + $this->template->content = Block::factory(); + } + + //@todo this should really be in a different class, since adsl wont be part of the main app + public function action_listadslservices() { + // @todo need to add the DB prefix here + $services = DB::query(Database::SELECT,' +SELECT A.service_id +FROM ab_service__adsl A,ab_service B,ab_account C,ab_service D,ab_product E +WHERE B.active=1 AND A.service_id=B.id AND A.site_id=B.site_id +AND B.account_id=C.id AND B.site_id=C.site_id +AND A.service_id=D.id AND A.site_id=D.site_id +AND D.product_id=E.id AND D.site_id=E.site_id +AND E.sku like "%ADSL%" +ORDER BY C.last_name,B.account_id,A.service_number + ') + ->execute(); + + // @todo If no items, show a nice message. This is not correct for ORM. + if (! count($services)) { + echo Kohana::debug('No services for ADSL'); + die(); + } + + $last_account = ''; + $i = 0; + $output = ''; + foreach ($services as $service) { + $so = ORM::factory('service',$service['service_id']); + + if ($last_account != $so->account_id) { + if ($i) + $output .= ''; + + $output .= View::factory('service/list/adslservices_header') + ->set('service',$so); + + $last_account = $so->account_id; + } + + $output .= View::factory('service/list/adslservices_body') + ->set('service',$so) + ->set('i',$i++%2); + } + $output .= '
                     
                    '; + + // Chart the traffic for the last 12 months. + // @todo need to add the DB prefix here + $traffic = DB::query(Database::SELECT,sprintf(' +SELECT DATE_FORMAT(DATE,"%%y-%%m") AS MONTH,SID,MAX(NUM) AS NUM,SUM(DOWN_PEAK) AS DOWN_PEAK,SUM(IFNULL(DOWN_OFFPEAK,0)+IFNULL(PEER,0)+IFNULL(INTERNAL,0)) AS DOWN_OFFPEAK +FROM ab_view_traffic_adsl_daily +WHERE SID in (%s) AND DATE>"%s" +GROUP BY DATE_FORMAT(DATE,"%%Y-%%m"),SID + ','1,2',date('Y-m',time()-365*86400))) + ->execute(); + + $peak = $offpeak = $services = array(); + + foreach ($traffic as $a => $v) { + $peak[$v['SID']]['Peak'][$v['MONTH']] = $v['DOWN_PEAK']; + $peak[$v['SID']]['OffPeak'][$v['MONTH']] = $v['DOWN_OFFPEAK']; + $peak[$v['SID']]['Services'][$v['MONTH']] = $v['NUM']; + } + + $google = GoogleChart::factory('vertical_bar'); + $google->title = sprintf('ADSL traffic as at %s',date('Y-m-d',strtotime('yesterday'))); + $google->series(array( + 'title'=>array('Exetel-Peak','Exetel-Offpeak'), + 'axis'=>'x', + 'data'=>array('Exetel-Peak'=>$peak[1]['Peak'],'Exetel-OffPeak'=>$peak[1]['OffPeak']))); + $google->series(array( + 'title'=>array('People-Peak','People-Offpeak'), + 'axis'=>'x', + 'data'=>array('People-Peak'=>$peak[2]['Peak'],'People-OffPeak'=>$peak[2]['OffPeak']))); + $google->series(array( + 'title'=>'Exetel-Services', + 'axis'=>'r', + 'data'=>array('Exetel-Services'=>$peak[1]['Services']))); + $google->series(array( + 'title'=>'People-Services', + 'axis'=>'r', + 'data'=>array('People-Services'=>$peak[2]['Services']))); + + Block::add(array( + 'body'=>$google, + )); + + Block::add(array( + 'title'=>_('List all ADSL Services'), + 'body'=>$output, + )); + + Style::add(array( + 'type'=>'file', + 'data'=>'css/list.css', + )); + + $this->template->content = Block::factory(); + } + + public function action_listhspaservices() { + // @todo need to add the DB prefix here + $services = DB::query(Database::SELECT,' +SELECT A.service_id +FROM ab_service__adsl A,ab_service B,ab_account C,ab_service D,ab_product E +WHERE B.active=1 AND A.service_id=B.id AND A.site_id=B.site_id +AND B.account_id=C.id AND B.site_id=C.site_id +AND A.service_id=D.id AND A.site_id=D.site_id +AND D.product_id=E.id AND D.site_id=E.site_id +AND E.sku like "%HSPA%" +ORDER BY C.last_name,B.account_id,A.service_number + ') + ->execute(); + + // @todo If no items, show a nice message. This is not correct for ORM. + if (! count($services)) { + echo Kohana::debug('No services for HSPA'); + die(); + } + + $last_account = ''; + $i = 0; + $output = ''; + foreach ($services as $service) { + $so = ORM::factory('service',$service['service_id']); + + if ($last_account != $so->account_id) { + if ($i) + $output .= ''; + + $output .= View::factory('service/list/adslservices_header') + ->set('service',$so); + + $last_account = $so->account_id; + } + + $output .= View::factory('service/list/adslservices_body') + ->set('service',$so) + ->set('i',$i++%2); + } + $output .= '
                     
                    '; + + // Chart the traffic for the last 12 months. + // @todo need to add the DB prefix here + $traffic = DB::query(Database::SELECT,sprintf(' +SELECT DATE_FORMAT(DATE,"%%y-%%m") AS MONTH,SID,MAX(NUM) AS NUM,SUM(DOWN_PEAK)*1000 AS DOWN_PEAK,SUM(IFNULL(DOWN_OFFPEAK,0)+IFNULL(PEER,0)+IFNULL(INTERNAL,0))*1000 AS DOWN_OFFPEAK +FROM ab_view_traffic_adsl_daily +WHERE SID=%s AND DATE>"%s" +GROUP BY DATE_FORMAT(DATE,"%%Y-%%m"),SID + ',3,date('Y-m',time()-365*86400))) + ->execute(); + + $peak = $offpeak = $services = array(); + + foreach ($traffic as $a => $v) { + $peak['Peak'][$v['MONTH']] = $v['DOWN_PEAK']; + $peak['OffPeak'][$v['MONTH']] = $v['DOWN_OFFPEAK']; + $peak['Services'][$v['MONTH']] = $v['NUM']; + } + + $google = GoogleChart::factory('vertical_bar'); + $google->title = sprintf('HSPA traffic as at %s',date('Y-m-d',strtotime('yesterday'))); + $google->series(array('title'=>array('Peak','Offpeak'),'axis'=>'x','data'=>array('Peak'=>$peak['Peak'],'OffPeak'=>$peak['OffPeak']))); + $google->series(array('title'=>'Services','axis'=>'r','data'=>array('Services'=>$peak['Services']))); + + Block::add(array( + 'body'=>$google, + )); + + Block::add(array( + 'title'=>_('List all HSPA Services'), + 'body'=>$output, + )); + + Style::add(array( + 'type'=>'file', + 'data'=>'css/list.css', + )); + + $this->template->content = Block::factory(); + } + + /** + * Reconcile billing for an ADSL supplier + * + * @todo this should really be in a different class, since adsl wont be part of the main app + */ + public function action_listadslbilling($id) { + $aso = ORM::factory('adsl_supplier',$id); + + // Process upload + // @todo This should be separated out by supplier in case each supplier has a different format + $files = Validate::factory($_FILES); + $files->rules('csv',array( + 'Upload::valid'=>array(), + 'Upload::not_empty'=>array(), + 'Upload::type'=>array('Upload::type' => array('csv')), + 'Upload::size'=>array('10M')) + ); + + if ($files->check()) { + foreach ($files as $file) { + $csv = $this->process($file); + } + } + + // @todo add a display if there are no items + $i = $j = 0; + $total = 0; + $summary = ''; + $output = View::factory('service/list/adslbilling_head'); + $output .= ''; + foreach ($aso->services(TRUE) as $so) { + // Reset our uploaded data + $uploaded = array(); + // If our uploaded file has some cost data. + if (! empty($csv[$so->service_adsl->service_number])) { + $uploaded['amount'] = + (empty($csv[$so->service_adsl->service_number]['cost']) ? 0 : $csv[$so->service_adsl->service_number]['cost']) + + (empty($csv[$so->service_adsl->service_number]['credit']) ? 0 : $csv[$so->service_adsl->service_number]['credit']); + + // Record the the exception if the cost is not expected + if (round($so->service_adsl->adsl_plan->adsl_supplier_plan->base_cost+$so->service_adsl->adsl_plan->adsl_supplier_plan->tax(),2) != $uploaded['amount']) { + $summary .= View::factory('service/list/adslbilling_summary') + ->set('service',$so) + ->set('amount',$uploaded['amount']) + ->set('i',$j++%2); + + $uploaded['checked'] = ''; + } else { + $uploaded['checked'] = 'checked="checked"'; + } + + unset($csv[$so->service_adsl->service_number]); + + } else { + $uploaded['checked'] = ''; + $uploaded['amount'] = 0; + } + $total += $uploaded['amount']; + + $output .= View::factory('service/list/adslbilling_body') + ->set('service',$so) + ->set('checked',$uploaded['checked']) + ->set('amount',$uploaded['amount']) + ->set('adsl',$so->service_adsl) + ->set('i',$i++%2); + } + + $output .= View::factory('service/list/adslbilling_foot') + ->set('total',$total); + + $output .= '
                    '; + + // Summary Report of remaining CSV items. + if (! empty($csv)) + foreach ($csv as $service => $item) { + $summary .= View::factory('service/list/adslbilling_summary_exception') + ->set('service',$service) + ->set('item',$item) + ->set('i',$j++%2); + } + + $output .= Form::open(NULL,array('enctype'=>'multipart/form-data')); + $output .= '
                    '; + $output .= Form::file('csv'); + $output .= Form::submit('submit','upload'); + $output .= '
                    '; + $output .= Form::close(); + + Block::add(array( + 'title'=>_('ADSL Services'), + 'body'=>$output, + )); + + if ($summary) + Block::add(array( + 'title'=>_('Exception Charges'), + 'body'=>''.$summary.'
                    ', + )); + + Style::add(array( + 'type'=>'file', + 'data'=>'css/list.css', + )); + + $this->template->content = Block::factory(); + } + + private function process(array $file) { + $data = file_get_contents($file['tmp_name']); + + if (! $data) + return; + + $start = $end = FALSE; + $return = array(); + foreach (preg_split("/\n/",$data) as $line) { + // Items start after "Item ID" + if (! $start && preg_match('/^Item ID,/',$line)) { + $start = true; + continue; + // Items end after "Subtotal" + } elseif ($start && ! $end && preg_match('/^Subtotal:,/',$line)) { + $end = true; + continue; + // If we havent started or not ended, continue + } elseif (! $start || $end) { + continue; + } + + list($id,$ref,$unknown,$linedata,$q,$cost,$total) = explode(',',$line); + + // Extract the phone number from the $linedata + @list($service,$description) = explode(':',(preg_replace('/([0-9]+)\s+-\s+(.*)$/',"$1:$2",$linedata))); + + // If the description says Monthly Charge, we know its the monthly fee. + if (preg_match('/^Monthly Charge/',$description)) + $return[$service]['cost'] = preg_replace('/\$/','',$total); + // If the description says VISP credit, we know this is commission. + elseif (preg_match('/^VISP Credit/',$description)) + $return[$service]['credit'] = preg_replace('/\$/','',$total); + // If the description says Excess, we know this is commission. + elseif (preg_match('/^Excess usage/',$description)) + $return[$service]['excess'] = preg_replace('/\$/','',$total); + else + $return[$service]['info'] = $line; + } + + return $return; + } +} +?> diff --git a/modules/service/classes/controller/task/service.php b/modules/service/classes/controller/task/service.php new file mode 100644 index 00000000..5537a96c --- /dev/null +++ b/modules/service/classes/controller/task/service.php @@ -0,0 +1,50 @@ +update_traffic(); + } + } + + /** + * Charges for excess traffic usage + */ + public function action_chargetraffic() { + // @todo This things to collect traffic on needs to be configurable + foreach (array('ExetelVisp','ExetelHSPA','PeopleAgent','iiNetADSL') as $source) { + $traffic = Service_Traffic_ADSL::instance($source); + + $traffic->charge_excess_traffic(); + } + } + + /** + * Send alerts to users when they exceed their traffic allowance + */ + public function action_alerttraffic() { + // @todo This things to collect traffic on needs to be configurable + foreach (array('ExetelVisp','ExetelHSPA','PeopleAgent','iiNetADSL') as $source) { + $traffic = Service_Traffic_ADSL::instance($source); + + $traffic->alert_traffic(); + } + } +} +?> diff --git a/modules/service/classes/controller/user/service.php b/modules/service/classes/controller/user/service.php new file mode 100644 index 00000000..885f8e61 --- /dev/null +++ b/modules/service/classes/controller/user/service.php @@ -0,0 +1,110 @@ +TRUE, + 'view'=>TRUE, + ); + // Our acccount object + private $ao; + + public function before() { + parent::before(); + + $this->ao = ORM::factory('account',Auth::instance()->get_user()->id); + if (! $this->ao->loaded()) + throw new Kohana_Exception('Account doesnt exist :account ?',array(':account'=>Auth::instance()->get_user()->id)); + } + + /** + * Show a product + */ + public function action_list() { + Block::add(array( + 'title'=>sprintf('%s: %s - %s',_('Services For'),$this->ao->accnum(),$this->ao->name(TRUE)), + 'body'=>View::factory('service/list') + ->set('services',$this->ao->service->find_all()), + )); + + $this->template->content = Block::factory(); + } + + public function action_view($id) { + $so = ORM::factory('service',$id); + + if (! $so->loaded() OR ! Auth::instance()->authorised($so->account_id)) { + $this->template->content = 'Unauthorised or doesnt exist?'; + return FALSE; + } + + $graph = $graph_data = $product_info = $product_detail = ''; + + // @todo Work this out dynamically + if ($so->product->prod_plugin AND in_array($so->product->prod_plugin_file,array('ADSL'))) { + + $google = GoogleChart::factory('vertical_bar'); + + // If we came in via a post to show a particular month, then show that, otherwise show the yearly result + if ($_POST AND isset($_POST['month'])) { + $google->title = sprintf('DSL traffic usage for %s',$_POST['month']); + $traffic_data = $so->service_adsl->get_traffic_data_daily(strtotime($_POST['month'].'-01')); + + foreach ($traffic_data as $k => $details) + $google->series(array( + 'title'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)), + 'axis'=>'x', + 'data'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)=>$traffic_data[$k]))); + + foreach ($traffic_data as $k => $details) + $google->series(array( + 'title'=>array((isset($friendly['cumulative'.$k]) ? $friendly['cumulative'.$k] : 'cumulative'.$k)), + 'axis'=>'r', + 'data'=>array((isset($friendly['cumulative'.$k]) ? $friendly['cumulative'.$k] : 'cumulative'.$k)=>$so->service_adsl->cumulative($traffic_data[$k])))); + + $graph_data = View::factory('service/view_detail_adsl_traffic') + ->set('traffic',$so->service_adsl->traffic_month(strtotime($_POST['month'].'-01'),FALSE)); + + } else { + // @todo Change the date to the last record date + $google->title = sprintf('Monthly DSL traffic usage as at %s',Config::date(strtotime('yesterday'))); + $traffic_data = $so->service_adsl->get_traffic_data_monthly(); + + foreach ($traffic_data as $k => $details) + $google->series(array( + 'title'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)), + 'axis'=>'x', + 'data'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)=>$traffic_data[$k]))); + } + + $graph = (string)$google; + + $product_info = ADSL::instance()->product_view($so->service_adsl->adsl_plan_id,$so->price,$so->product->price_setup); + $product_detail = View::factory('service/view_detail_adsl') + ->set('graph',$graph) + ->set('graph_data',$graph_data) + ->set('service',$so); + } + + // @todo need to get the monthly price + Block::add(array( + 'title'=>sprintf('%06s: %s',$so->id,$so->product->product_translate->find()->name), + 'body'=>View::factory('service/view') + ->set('service',$so) + ->set('product_info',$product_info) + ->set('product_detail',$product_detail), + )); + + $this->template->content = Block::factory(); + } +} +?> diff --git a/modules/service/classes/model/service.php b/modules/service/classes/model/service.php new file mode 100644 index 00000000..5f718bcc --- /dev/null +++ b/modules/service/classes/model/service.php @@ -0,0 +1,101 @@ +array('through'=>'invoice_item'), + 'adsl_plan'=>array('through'=>'service__adsl'), + ); + protected $_has_one = array( + 'service_adsl'=>array(), + ); + protected $_belongs_to = array( + 'product'=>array(), + 'account'=>array(), + ); + + protected $_formats = array( + 'active'=>array('StaticList_YesNo::display'=>array()), + 'date_next_invoice'=>array('Config::date'=>array()), + 'recur_schedule'=>array('StaticList_RecurSchedule::display'=>array()), + 'price'=>array( + 'Tax::add'=>array(), + 'Currency::display'=>array(), + ), + ); + + /** + * Display the service number + */ + public function svcnum() { + return sprintf('%05s',$this->id); + } + + // Nothing to directly display on invoices for this module. + public function invoice_display() { + if ($this->sku) + return sprintf('%s: %s',_('Service'),$this->sku); + else + return ''; + } + + public function name() { + return $this->product->product_translate->find()->name; + } + + /** + * Find invoices associated with this service + */ + public function invoices() { + $return = array(); + + foreach ($this->invoice->distinct('id')->find_all() as $invoice) { + $return[$invoice->id]['due'] = $invoice->due(); + } + + return $return; + } + + /** + * Find invoices currently outstanding associated with this service + */ + public function invoices_due() { + $return = array(); + + foreach ($this->invoices() as $id => $invoice) + if ($invoice['due']) + array_push($return,$invoice); + + return $return; + } + + /** + * Calculate the total of invoices due for this service + */ + public function invoices_due_total() { + $total = 0; + foreach ($this->invoices_due() as $invoice) + $total += $invoice['due']; + + return $total; + } + + // @todo To implement + /** + * Calculate the tax for this item + */ + public function tax() { + return $this->price * .1; + } +} +?> diff --git a/modules/service/classes/model/service/adsl.php b/modules/service/classes/model/service/adsl.php new file mode 100644 index 00000000..e501fdd7 --- /dev/null +++ b/modules/service/classes/model/service/adsl.php @@ -0,0 +1,328 @@ +array('foreign_key'=>'adsl_plan_id'), + 'service'=>array(), + ); + + /** + * Return the IP Address for the service + */ + public function ipaddress() { + return $this->ipaddress ? $this->ipaddress : _('Dynamic'); + } + + public function contract_date_start() { + //@todo Use the system configured date format + return date('Y-m-d',$this->service_connect_date); + } + + public function contract_date_end() { + //@todo Use the system configured date format + return date('Y-m-d',strtotime(sprintf('+%s months',$this->adsl_plan->contract_term),$this->service_connect_date)); + } + + /** + * This function will return the months that have traffic data. + * This array can be used in a select list to display the traffic for that month + */ + public function get_traffic_months() { + $keys = $months = array(); + + foreach ($this->get_traffic_data_monthly() as $metric => $data) + $keys = array_unique(array_merge($keys,array_keys($data))); + + foreach ($keys as $v) + $months[$v] = $v; + + arsort($months); + + return $months; + } + + /** + * Calculate the total traffic used in a month + */ + private function get_traffic_data_month($period=NULL) { + $return = array(); + + foreach ($this->get_traffic_data_daily($period,TRUE) as $tdata) + foreach ($tdata as $k => $v) + if (isset($return[$k])) + $return[$k] += $v; + else + $return[$k] = $v; + + return $return; + } + + /** + * Return an array of the data used in a month by day + */ + public function get_traffic_data_daily($period=NULL,$bydate=FALSE) { + $cacheable = TRUE; + if (is_null($period)) + $period = strtotime('yesterday'); + + $cache = $this->service_id.date('M-Y',$period).$bydate; + + // @todo This cache needs to be improved, so that we cache the query regardless of bydate setting + if ($cacheable AND $return = Cache::instance(Config::cachetype())->get($cache)) + return $return; + + $return = array(); + + $to = ORM::factory('service_adsl_traffic') + ->where('service','=',$this->service_username) + ->and_where('date','>=',date('Y-m-d',mktime(0,0,0,date('m',$period),1,date('Y',$period)))) + ->and_where('date','<=',date('Y-m-d',strtotime('last day of '.date('M Y',$period)))); + + foreach ($to->find_all() as $traffic) { + // Roll up the charges according to the configuration + $data = ADSL::allowance(array( + 'base_down_peak'=>is_null($this->adsl_plan->base_down_peak) ? NULL : $traffic->down_peak, + 'base_down_offpeak'=>is_null($this->adsl_plan->base_down_offpeak) ? NULL : $traffic->down_offpeak, + 'base_up_peak'=>is_null($this->adsl_plan->base_up_peak) ? NULL : $traffic->up_peak, + 'base_up_offpeak'=>is_null($this->adsl_plan->base_up_offpeak) ? NULL : $traffic->up_offpeak, + 'extra_down_peak'=>$this->adsl_plan->extra_down_peak, + 'extra_down_offpeak'=>$this->adsl_plan->extra_down_offpeak, + 'extra_up_peak'=>$this->adsl_plan->extra_up_peak, + 'extra_up_offpeak'=>$this->adsl_plan->extra_up_offpeak, + )); + + $day = date('d',strtotime($traffic->date)); + if ($bydate) + $return[$day] = $data; + else + foreach ($data as $k => $v) + $return[$k][$day] = $v; + } + + // Cache our data + // @todo Our cache time should be a configuration parameter + Cache::instance(Config::cachetype())->set($cache,$return,43200); + + return $return; + } + + /** + * Return an array of the data used in a year by month + */ + public function get_traffic_data_monthly($period=NULL,$bydate=FALSE) { + $cacheable = FALSE; + if (is_null($period)) + $period = strtotime('yesterday'); + + $cache = $this->service_id.date('M-Y',$period).$bydate.__METHOD__; + + // @todo This cache needs to be improved, so that we cache the query regardless of bydate setting + if ($cacheable AND $return = Cache::instance(Config::cachetype())->get($cache)) + return $return; + + $return = array(); + + $to = ORM::factory('service_adsl_traffic') + ->select( + array('date_format(date,\'%y-%m\')','month'), + array('sum(up_peak)','up_peak'), + array('sum(up_offpeak)','up_offpeak'), + array('sum(down_peak)','down_peak'), + array('sum(down_offpeak)','down_offpeak') + ) + ->where('service','=',$this->service_username) + ->and_where('date','>=',date('Y-m-d',mktime(0,0,0,date('m',$period),1,date('Y',$period)-1))) + ->and_where('date','<=',date('Y-m-d',strtotime('last day of '.date('M Y',$period)))) + ->group_by('date_format(date,\'%Y-%m\')'); + + foreach ($to->find_all() as $traffic) { + // Roll up the charges according to the configuration + $data = ADSL::allowance(array( + 'base_down_peak'=>is_null($this->adsl_plan->base_down_peak) ? NULL : $traffic->down_peak, + 'base_down_offpeak'=>is_null($this->adsl_plan->base_down_offpeak) ? NULL : $traffic->down_offpeak, + 'base_up_peak'=>is_null($this->adsl_plan->base_up_peak) ? NULL : $traffic->up_peak, + 'base_up_offpeak'=>is_null($this->adsl_plan->base_up_offpeak) ? NULL : $traffic->up_offpeak, + 'extra_down_peak'=>$this->adsl_plan->extra_down_peak, + 'extra_down_offpeak'=>$this->adsl_plan->extra_down_offpeak, + 'extra_up_peak'=>$this->adsl_plan->extra_up_peak, + 'extra_up_offpeak'=>$this->adsl_plan->extra_up_offpeak, + )); + + if ($bydate) + $return[$traffic->month] = $data; + else + foreach ($data as $k => $v) + $return[$k][$traffic->month] = $v; + } + + // Cache our data + // @todo Our cache time should be a configuration parameter + Cache::instance(Config::cachetype())->set($cache,$return,43200); + + return $return; + } + + public function traffic_month($month,$string=TRUE) { + return $string ? implode('/',$this->get_traffic_data_month($month)) : + $this->get_traffic_data_month($month); + } + + public function traffic_lastmonth($string=TRUE) { + return $this->traffic_month(strtotime('last month'),$string); + } + + public function traffic_thismonth($string=TRUE) { + return $this->traffic_month(strtotime('yesterday'),$string); + } + + public function traffic_lastmonth_exceed($all=FALSE) { + $return = array(); + + foreach ($this->traffic_month(strtotime('last month'),FALSE) as $k => $v) { + // We shouldnt need to eval for nulls, since the traffic calc does that + if ($all OR ($v > $this->adsl_plan->$k)) { + $return[$k]['allowance'] = $this->adsl_plan->$k; + $return[$k]['used'] = $v; + $return[$k]['shaped'] = (! empty($this->adsl_plan->extra_shaped) AND $this->adsl_plan->extra_shaped AND $v > $this->adsl_plan->$k) ? TRUE : FALSE; + $return[$k]['excess'] = (! empty($this->adsl_plan->extra_charged) AND $this->adsl_plan->extra_charged AND $v > $this->adsl_plan->$k) ? $v-$this->adsl_plan->$k : 0; + $return[$k]['rate'] = $this->adsl_plan->{ADSL::map($k)}; + $return[$k]['charge'] = ceil(($return[$k]['excess'])/1000)*$return[$k]['rate']; + } + } + + return $return; + } + + public function template_variables($array) { + $friendly = array( + 'base_down_peak'=>'Peak', + 'base_down_offpeak'=>'OffPeak', + 'cumulative_base_down_peak'=>'Total Peak', + 'cumulative_base_down_offpeak'=>'Total OffPeak', + ); + + $return = array(); + $allowance = $this->adsl_plan->allowance(FALSE); + + $period = strtotime('yesterday'); + $traffic_data = $this->get_traffic_data_daily($period,FALSE); + $traffic = $this->get_traffic_data_month($period); + + $traffic_type = $this->get_traffic_data_daily($period,TRUE); + $day = count($traffic_type) ? max(array_keys($traffic_type)) : 1; + $date = mktime(0,0,0,date('m',$period),$day,date('Y',$period)); + $daysleft = date('d',strtotime('last day ',$date))-$day; + + $google = GoogleChart::factory('vertical_bar'); + $google->title = sprintf('DSL traffic usage as at %s',Config::date($date)); + + foreach ($traffic_data as $k => $details) + $google->series(array( + 'title'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)), + 'axis'=>'x', + 'data'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)=>$traffic_data[$k]))); + + // Work out comulative numbers + foreach ($traffic_data as $k => $details) + $google->series(array( + 'title'=>array((isset($friendly['cumulative_'.$k]) ? $friendly['cumulative_'.$k] : 'cumulative_'.$k)), + 'axis'=>'r', + 'data'=>array((isset($friendly['cumulative_'.$k]) ? $friendly['cumulative_'.$k] : 'cumulative_'.$k)=>$this->cumulative($traffic_data['cumulative_'.$k])))); + + foreach ($array as $item) { + switch ($item) { + case 'MONTH_GRAPH': $value = (string)$google; break; + case 'MONTH_TABLE': $value = $google->html_table(FALSE,array( + 'table'=>'style="border: 1px solid #bebcb7; padding: 5px 5px; background: none repeat scroll 0% 0% #f8f7f5;"', + )); break; + + case 'OFFPEAK_ALLOWANCE': $value = isset($allowance['base_down_offpeak']) ? $allowance['base_down_offpeak'].' MB' : '-'; break; + case 'OFFPEAK_USAGE': $value = isset($traffic['base_down_offpeak']) ? $traffic['base_down_offpeak'].' MB' : '-'; break; + + case 'PEAK_ALLOWANCE': $value = isset($allowance['base_down_peak']) ? $allowance['base_down_peak'].' MB' : '-'; break; + case 'PEAK_USAGE': $value = isset($traffic['base_down_peak']) ? $traffic['base_down_peak'].' MB' : '-'; break; + + case 'OFFPEAK_AVERAGE': $value = isset($traffic['base_down_offpeak']) ? round($traffic['base_down_offpeak']/$day,2).' MB' : '-'; break; + case 'OFFPEAK_AVERAGE_REMAIN': $value = ((isset($traffic['base_down_offpeak']) AND ($allowance['base_down_offpeak'] > $traffic['base_down_offpeak']) AND $daysleft) ? round(($allowance['base_down_offpeak']-$traffic['base_down_offpeak'])/$daysleft,2).' MB' : '-'); break; + + case 'PEAK_AVERAGE': $value = isset($traffic['base_down_peak']) ? round($traffic['base_down_peak']/$day,2).' MB' : '-'; break; + case 'PEAK_AVERAGE_REMAIN': $value = ((isset($traffic['base_down_peak']) AND ($allowance['base_down_peak'] > $traffic['base_down_peak']) AND $daysleft) ? round(($allowance['base_down_peak']-$traffic['base_down_peak'])/$daysleft,2).' MB' : '-'); break; + + case 'SERVICE_NUMBER': $value = $this->service_number; break; + case 'USAGE_DATE': $value = Config::date($date); break; + case 'USER_NAME': $value = $this->service->account->name(); break; + default: + $value = ''; + } + + $return[$item] = $value; + } + + return $return; + } + + /** + * This function will take an array of numbers and change it into a cumulative array + */ + public function cumulative($array) { + $result = array(); + $s = 0; + + foreach ($array as $k => $v) + $result[$k] = ($s += $v); + + return $result; + } + + /** + * Determine if we alert traffic + * + * We alert traffic if: + * + 80% of usage every 3 days + * + average daily usage > allowance every 5 days + * + last day of the period + */ + public function report_traffic() { + $allowance = $this->adsl_plan->allowance(FALSE); + + $period = strtotime('yesterday'); + $traffic_data = $this->get_traffic_data_daily($period,FALSE); + $traffic = $this->get_traffic_data_month($period); + + $traffic_type = $this->get_traffic_data_daily($period,TRUE); + $day = count($traffic_type) ? max(array_keys($traffic_type)) : 1; + $lastday = date('d',strtotime('last day of',$period)); + + foreach ($traffic as $k => $v) { + // If we are the last day of the period + if ($day == $lastday AND $v) + return TRUE; + + // If we are at 80% usage + if ($v/($allowance[$k] > 0 ? $allowance[$k] : 1) >= .8 AND $day%3 == 3) + return TRUE; + + // If our average is greater than our allowance + if ($day%5 == 5 AND ($v/$day > $allowance[$k]/$day)) + return TRUE; + } + + // If we get here, then we dont need to report usage. + return FALSE; + } +} +?> diff --git a/modules/service/classes/model/service/adsl/traffic.php b/modules/service/classes/model/service/adsl/traffic.php new file mode 100644 index 00000000..1ba0f8bb --- /dev/null +++ b/modules/service/classes/model/service/adsl/traffic.php @@ -0,0 +1,23 @@ +array('set_site_id'), + ); + + protected $_created_column = FALSE; + protected $_updated_column = FALSE; +} +?> diff --git a/modules/service/classes/service/traffic/adsl.php b/modules/service/classes/service/traffic/adsl.php new file mode 100644 index 00000000..d7329775 --- /dev/null +++ b/modules/service/classes/service/traffic/adsl.php @@ -0,0 +1,158 @@ + 60, + CURLOPT_FAILONERROR => TRUE, + CURLOPT_FOLLOWLOCATION => FALSE, + CURLOPT_HEADER => FALSE, + CURLOPT_HTTPPROXYTUNNEL => FALSE, + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_TIMEOUT => 30, + CURLOPT_SSL_VERIFYHOST => FALSE, + CURLOPT_SSL_VERIFYPEER => FALSE, + CURLOPT_VERBOSE => FALSE, + ); + + /** + * Setup this class. We need to get our supplier details out of the database. + */ + public function __construct() { + // Our DB record must be the suffix of this class name + $supplier = preg_replace('/^'.get_parent_class($this).'_/','',get_class($this)); + + $so = ORM::factory('adsl_supplier') + ->where('name','=',$supplier) + ->find(); + + if (! $so->loaded()) + throw new Kohana_Exception('Supplier :supplier not defined in the database',array(':supplier'=>$supplier)); + + $this->so = $so; + $this->today = date('Y-m-d',strtotime('yesterday')); + } + + /** + * Return an instance of this class + * + * @return HeadImage + */ + public static function instance($supplier) { + $sc = sprintf('%s_%s',get_called_class(),$supplier); + + if (! class_exists($sc)) + throw new Kohana_Exception('Class doesnt exist for :supplier',array(':supplier'=>$supplier)); + else + return new $sc; + } + + /** + * Get the last date we obtained the stats. + */ + private function last_update() { + return $this->so->stats_lastupdate; + } + + /** + * Traffic data from supplier + */ + public function update_traffic() { + $alreadyrun = FALSE; + for ($querydate=date('Y-m-d',strtotime($this->last_update().'+1 day')); + $querydate<=$this->today; + $querydate=date('Y-m-d',strtotime($querydate.'+1 day'))) { + + $goodfetch = false; + // @todo log this fetch in a "log" + + // Supplier specific output + // Data returned should be in MB's + $data = $this->getdata($querydate); + + if (! $this->fetchresult) { + echo 'Bad fetch'.get_class($this); + break; + } + + $traffic = ORM::factory('service_adsl_traffic'); + foreach ($data as $item) { + $traffic->values($item); + $traffic->supplier_id = $this->so->id; + + if ($traffic->check()) + $traffic->save(); + + if (! $traffic->saved()) + throw new Kohana_Exception('Unable to save traffic record'); + + $traffic->clear(); + } + } + + $this->so->stats_lastupdate = $this->today; + $this->so->save(); + } + + public function charge_excess_traffic() { + // @todo need a way to find out services that have traffic charges dynamically. + foreach ($this->so->services() as $so) { + if ($charge = $so->service_adsl->traffic_lastmonth_exceed(FALSE)) { + foreach ($charge as $metric => $details) { + $co = ORM::factory('charge'); + + $co->status = 0; + $co->sweep_type = 6; + $co->account_id = $so->account_id; + $co->service_id = $so->id; + $co->amount = $details['rate']; + // @todo This needs to be calculated. + $co->taxable = TRUE; + $co->quantity = ceil($details['excess']/1000); + $co->description = _('Excess Traffic'); + // @todo This need to be improved = strtotime function should be the one used in the function call + $co->attributes = implode("\n",array( + sprintf('ADSL Service==%s',$so->service_adsl->service_number), + sprintf('Allowance==%s',$details['allowance']), + sprintf('Metric==%s',$metric), + sprintf('Used==%s',$details['used']), + sprintf('Month==%s',date('Y-m',strtotime('last month'))), + )); + + $co->check(); + $co->save(); + } + + print_r(array('s'=>$so->id,'a'=>$so->service_adsl->service_number,'al'=>$so->service_adsl->adsl_plan->allowance(FALSE),'charge'=>$charge)); + } + } + } + + public function alert_traffic() { + $et = EmailTemplate::instance('adsl_traffic_notice'); + + foreach ($this->so->services() as $so) { + if (! $so->service_adsl->report_traffic()) + continue; + + // Get our variable data + $et->to = array($so->account->email=>sprintf('%s %s',$so->account->first_name,$so->account->last_name)); + $et->variables = $so->service_adsl->template_variables($et->variables()); + + $et->send(); + } + } +} +?> diff --git a/modules/service/classes/service/traffic/adsl/exetelhspa.php b/modules/service/classes/service/traffic/adsl/exetelhspa.php new file mode 100644 index 00000000..f13510f8 --- /dev/null +++ b/modules/service/classes/service/traffic/adsl/exetelhspa.php @@ -0,0 +1,176 @@ +fetchresult = TRUE; + + // If we have already collected the date data, return it. + if (! empty(Service_Traffic_ADSL_ExetelHSPA::$return[$date])) + return Service_Traffic_ADSL_ExetelHSPA::$return[$date]; + + // Find our services that need to be collected this way. + $update = array(); + foreach ($this->so->services() as $so) { + if ($so->service_adsl->service_stats_collect AND $so->service_adsl->service_stats_lastupdate < $date) { + $postfields = http_build_query(array( + $this->login_user_field=>$so->service_adsl->service_username, + $this->login_pass_field=>$so->service_adsl->service_password, + 'doLogin'=>1, + 'submit'=>'Login', + )); + + // Start Session + Remote::clear(); + $data = Remote::get($this->so->stats_url, + $this->curlopts+array( + CURLOPT_POSTFIELDS=>$postfields, + CURLOPT_COOKIEJAR=>sprintf('/tmp/usage.cookies.%s.txt',$so->service_adsl->service_number), + ), + TRUE); + + if (! $data) { + // @todo Log into a log file + printf('Bad fetch for %s [%s]',$so->service_adsl->service_number,$this->so->stats_lastupdate); + #$html = new simple_html_dom(); + #$html->load($data); + #$html->save(sprintf('/afs/local/tmp/usage.%s.%s.login.html',$so->service_adsl->service_number,'login')); + continue; + } + + for ($servicedate=date('Y-m-d',strtotime($this->so->stats_lastupdate.'+1 day')); + $servicedate <= $this->today; + $servicedate=date('Y-m-d',strtotime('+1 month',strtotime(date('Y-m',strtotime($servicedate)).'-01')))) { + + $lastday = date('Y-m-d',strtotime('-1 second',strtotime('+1 month',strtotime(date('Y-m',strtotime($servicedate)).'-01')))); + if (strtotime($lastday) > time()) + $lastday = date('Y-m-d',strtotime('yesterday')); + + $postfields = http_build_query(array( + 'year_search_key'=>date('Y',strtotime($servicedate)), + 'month_search_key'=>date('m',strtotime($servicedate)), + 'start_day_search_key'=>date('d',strtotime($servicedate)), + 'end_day_search_key'=>date('d',strtotime($lastday)), + 'do_usage_search'=>1, + )); + + $html = new simple_html_dom(); + $notdebug = TRUE; + if ($notdebug) { + $result = Remote::get($this->so->stats_url.'usage_customize_query.php',$this->curlopts+array(CURLOPT_POSTFIELDS=>$postfields),TRUE); + + $html->load($result); + $html->save(sprintf('/afs/local/tmp/usage.%s.%s.html',$so->service_adsl->service_number,$servicedate)); + } else { + $html->load_file(sprintf('/tmp/usage.%s.%s.txt',$so->service_adsl->service_number,$servicedate)); + } + + $header = array(); + $data = array(); + + foreach ($html->find('fieldset') as $index => $fieldset) { + if (! preg_match('/^Usage Detail/',$fieldset->find('legend',0)->plaintext)) + continue; + + #echo "X:";print_r($fieldset->find('legend',0)->plaintext); echo "\n"; + foreach ($fieldset->find('table',0)->find('tr') as $key => $values) { + foreach ($values->children() as $a => $b) { + #print_r(array('a'=>$a,'b'=>$b)); + + # Header + if ($key == 0) { + switch ($b->plaintext) { + case 'Date': $header[$a] = 'date'; break; + case 'OffPeak Upload': $header[$a] = 'up_offpeak'; break; + case 'Peak Upload': $header[$a] = 'up_peak'; break; + case 'Upload': $header[$a] = 'up_peak'; break; + case 'OffPeak Download': $header[$a] = 'down_offpeak'; break; + case 'Peak Download': $header[$a] = 'down_peak'; break; + case 'Download': $header[$a] = 'down_peak'; break; + case 'Duration': break; + default: + printf('Unkown header :%s',$b->plaintext); + $this->fetchresult = FALSE; + continue; + } + #echo "INDEX: $key:$a\n"; + #echo "TAG: ".$b->tag."\n"; + #echo "HEADER: ".$b->plaintext."\n"; + + # Data + } else { + if (isset($header[$a])) + $data[$header[$a]] = $b->plaintext; + #echo "INDEX: $key:$a\n"; + #echo "TAG: ".$b->tag."\n"; + #echo "VALUES: ".$b->plaintext."\n"; + } + } + + if (isset($data['date']) && preg_match('/^[0-9]{4}/',$data['date'])) { + $sdate = date('Y-m-d',strtotime($data['date'])); + unset($data['date']); + + if (isset($update[$so->service_adsl->service_number][$sdate])) + foreach ($data as $key => $value) + $update[$so->service_adsl->service_number][$sdate][$key] += $value; + else + $update[$so->service_adsl->service_number][$sdate] = $data; + + $update[$so->service_adsl->service_number][$sdate]['service'] = $so->service_adsl->service_number; + $update[$so->service_adsl->service_number][$sdate]['date'] = $sdate; + } + } + } + } + + // If we got here and have data, we had a good fetch, update the stats date + $so->service_adsl->service_stats_lastupdate = $lastday; + $so->service_adsl->save(); + } + } + + // If there are no updates, return an empty array + if (! $update) + return array(); + + // Reformat the data into date order. + foreach ($update as $service => $sdata) + foreach ($sdata as $sdate => $details) + Service_Traffic_ADSL_ExetelHSPA::$return[$sdate][$service] = $details; + + // If the date we want is empty, return an array + if (empty(Service_Traffic_ADSL_ExetelHSPA::$return[$date])) + return array(); + + // Return the date we asked for + return Service_Traffic_ADSL_ExetelHSPA::$return[$date]; + } +} +?> diff --git a/modules/service/classes/service/traffic/adsl/exetelvisp.php b/modules/service/classes/service/traffic/adsl/exetelvisp.php new file mode 100644 index 00000000..e3f602c8 --- /dev/null +++ b/modules/service/classes/service/traffic/adsl/exetelvisp.php @@ -0,0 +1,65 @@ +fetchresult = FALSE; + + $return = array(); + + $data = Remote::get($this->so->stats_url,$this->curlopts+array( + CURLOPT_POST => TRUE, + CURLOPT_POSTFIELDS => http_build_query(array( + $this->login_user_field=>$this->so->stats_username, + $this->login_pass_field=>$this->so->stats_password, + $this->date_field=>$date, + ) + )) + ); + + $resultarray = explode("\n",$data); + + // The first field should be a header, so we can ignore it: + if (preg_match('/^Login/',$resultarray[0])) { + array_shift($resultarray); + $this->fetchresult = TRUE; + } + + // If we got the expected data, we can parse it. + if ($this->fetchresult) + foreach ($resultarray as $details) { + if (! trim($details)) + continue; + + $valuesarray = explode(',',$details); + + // Extel VISP stores data in MB's*100. + $attrs = array(); + $attrs['service'] = $valuesarray[0]; + $attrs['date'] = $valuesarray[1]; + $attrs['up_peak'] = $valuesarray[2]/100; + $attrs['down_peak'] = $valuesarray[3]/100; + $attrs['up_offpeak'] = $valuesarray[4]/100; + $attrs['down_offpeak'] = $valuesarray[5]/100; + + array_push($return,$attrs); + } + + return $return; + } +} +?> diff --git a/modules/service/classes/service/traffic/adsl/iinetadsl.php b/modules/service/classes/service/traffic/adsl/iinetadsl.php new file mode 100644 index 00000000..b59c7c75 --- /dev/null +++ b/modules/service/classes/service/traffic/adsl/iinetadsl.php @@ -0,0 +1,124 @@ +'down_peak', + 'offpeak'=>'down_offpeak', + 'uploads'=>'up_peak', + 'freezone'=>'internal', + ); + + /** + * Get the data for iiNet ADSL services + * + * @return array + */ + protected function getdata($date) { + // Assume we have a bad fetch, unless otherwise specified. + $this->fetchresult = FALSE; + + // If we have already collected the date data, return it. + if (! empty(Service_Traffic_ADSL_iiNetADSL::$return[$date])) + return Service_Traffic_ADSL_iiNetADSL::$return[$date]; + + // Find our services that need to be collected this way. + $update = array(); + foreach ($this->so->services() as $so) { + if ($so->service_adsl->service_stats_collect AND $so->service_adsl->service_stats_lastupdate < $date) { + $lastperiod = ''; + for ($servicedate=date('Y-m-d',strtotime($this->so->stats_lastupdate.'+1 day')); + $servicedate <= $this->today; + $servicedate=date('Y-m-d',strtotime('+1 day',strtotime($servicedate)))) { + + $debug = FALSE; + $debug_file = '/tmp/data'; + + // IINET gives us data a month at a time. + if ($lastperiod != date('Ym',strtotime($servicedate))) { + $lastperiod = date('Ym',strtotime($servicedate)); + + $postfields = http_build_query(array( + $this->login_user_field=>$so->service_adsl->service_username, + $this->login_pass_field=>$so->service_adsl->service_password, + 'period'=>$lastperiod, + 'usage_view'=>'month', + 'action'=>'login', + )); + + if ($debug AND file_exists($debug_file)) + $data = file_get_contents($debug_file); + else + $data = Remote::get($this->so->stats_url,$this->curlopts+array(CURLOPT_POSTFIELDS=>$postfields)); + + // @todo There exists a possibility to skip a month, if we get a bad fetch on a previous month. + if ($data) + $this->fetchresult = TRUE; + + if ($debug AND ! file_exists($debug_file)) + file_put_contents($debug_file,$data); + } + + $return = array(); + foreach (XML::factory(null,'ii_feed',$data)->volume_usage->volume_usage->get('day_hour') as $day_hour) { + $attrs = array(); + + $period = $day_hour->attributes(); + // If we find a field we dont understand, we'll return. + if (empty($period['period'])) + return array(); + + foreach ($day_hour->get('usage') as $usage) { + $fields = $usage->attributes(); + + // If we find a field we dont understand, we'll return. + if (empty($fields['type']) OR empty($this->fields[$fields['type']])) + return array(); + + // Traffic is in bytes, need to convert to MB + if (empty($attrs[$this->fields[$fields['type']]])) + $attrs[$this->fields[$fields['type']]] = $usage->value()/1000/1000; + else + $attrs[$this->fields[$fields['type']]] += $usage->value()/1000/1000; + } + + Service_Traffic_ADSL_iiNetADSL::$return[$period['period']][$so->service_adsl->service_username] = $attrs; + Service_Traffic_ADSL_iiNetADSL::$return[$period['period']][$so->service_adsl->service_username]['date'] = $period['period']; + Service_Traffic_ADSL_iiNetADSL::$return[$period['period']][$so->service_adsl->service_username]['service'] = $so->service_adsl->service_username; + } + } + + // If we got here and have data, we had a good fetch, update the stats date + $so->service_adsl->service_stats_lastupdate = $date; + $so->service_adsl->save(); + } + } + + // If the date we want is empty, return an array + if (empty(Service_Traffic_ADSL_iiNetADSL::$return[$date])) + return array(); + + // Return the date we asked for + return Service_Traffic_ADSL_iiNetADSL::$return[$date]; + } +} +?> diff --git a/modules/service/classes/service/traffic/adsl/peopleagent.php b/modules/service/classes/service/traffic/adsl/peopleagent.php new file mode 100644 index 00000000..43fdc863 --- /dev/null +++ b/modules/service/classes/service/traffic/adsl/peopleagent.php @@ -0,0 +1,62 @@ +fetchresult = FALSE; + + $return = array(); + $url_suffix = sprintf('traffic_V34_%s.xml',date('Ymd',strtotime($date))); + + try { + $data = Remote::get($this->so->stats_url.$url_suffix,$this->curlopts+array( + CURLOPT_HTTPAUTH => CURLAUTH_BASIC, + CURLOPT_USERPWD => sprintf('%s:%s',$this->so->stats_username,$this->so->stats_password), + )); + } + + catch (Exception $e) { + return; + } + + $this->fetchresult = TRUE; + foreach (XML::factory(null,null,$data)->get('user') as $user) { + $attrs = array(); + + $userattrs = $user->attributes(); + $attrs['service'] = $userattrs['username']; + $attrs['date'] = $date; + + foreach ($user->year->month->day->get('hour') as $hour => $traffic) { + foreach (array('external'=>'down_peak','internal'=>'internal','peering'=>'peer') as $t => $k) { + $tatters = $traffic->$t->attributes(); + + // Traffic is in bytes, need to convert to MB + if (empty($attrs[$k])) + $attrs[$k] = $tatters['bytes']/1000/1000; + else + $attrs[$k] += $tatters['bytes']/1000/1000; + } + } + + array_push($return,$attrs); + } + + return $return; + } +} +?> diff --git a/modules/service/service_construct.xml b/modules/service/service_construct.xml index 4c8ba87c..be8915e3 100644 --- a/modules/service/service_construct.xml +++ b/modules/service/service_construct.xml @@ -63,16 +63,6 @@ Date Updated I8 - - I8 - - - Invoice - I8 - - - I8 - Account I8 @@ -95,9 +85,6 @@ Active L - - L - Type C(16) @@ -210,6 +197,7 @@ I4 + array X2 @@ -219,8 +207,8 @@ C(128) - X2 array + X2 User May Modify @@ -233,16 +221,16 @@ - id,site_id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify - id,site_id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify - id,site_id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify - id,site_id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify - id,site_id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify - id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing - id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing - id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing - id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing - id,date_orig,date_last,parent_id,invoice_id,invoice_item_id,account_id,account_billing_id,product_id,sku,active,bind,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing + id,account_id,account_billing_id,product_id,sku,active,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify + id,date_last,account_id,account_billing_id,product_id,sku,active,type,price,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify,prod_attr + id + id,date_orig,date_last,account_id,account_billing_id,product_id,sku,active,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify,prod_attr + id,date_orig,date_last,account_id,account_billing_id,product_id,sku,active,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,recur_week,recur_schedule_change,recur_cancel,group_grant,group_type,group_days,host_server_id,host_provision_plugin_data,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing,prod_plugin_name,prod_plugin_data,recur_modify,prod_attr + id,date_last,account_id,account_billing_id,product_id,sku,active,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing + id,date_orig,date_last,account_id,account_billing_id,product_id,sku,active,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing + id,date_orig,date_last,account_id,account_billing_id,product_id,sku,active,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing + id,date_orig,date_last,account_id,account_billing_id,product_id,sku,active,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing + id,date_orig,date_last,account_id,account_billing_id,product_id,sku,active,type,price,price_type,taxable,queue,date_last_invoice,date_next_invoice,recur_type,recur_schedule,recur_weekday,host_server_id,host_ip,host_username,host_password,domain_name,domain_tld,domain_term,domain_type,domain_date_expire,domain_host_tld_id,domain_host_registrar_id,suspend_billing diff --git a/modules/service/views/service/list.php b/modules/service/views/service/list.php new file mode 100644 index 00000000..15534b3b --- /dev/null +++ b/modules/service/views/service/list.php @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +
                    IDTypeDetailsBillingPriceActive
                    id,$service->id); ?>display('type'); ?>invoice_display(); ?>display('recur_schedule');?>display('price'); ?>display('active'); ?>
                    diff --git a/modules/service/views/service/list/adslbilling_body.php b/modules/service/views/service/list/adslbilling_body.php new file mode 100644 index 00000000..cd3ba000 --- /dev/null +++ b/modules/service/views/service/list/adslbilling_body.php @@ -0,0 +1,10 @@ + + service_adsl->display('service_number'); ?> + service_adsl->adsl_plan->adsl_supplier_plan->name(); ?> + service_adsl->contract_date_start(); ?> + service_adsl->contract_date_end(); ?> + service_adsl->adsl_plan->adsl_supplier_plan->base_cost); ?> + service_adsl->adsl_plan->adsl_supplier_plan->base_cost+$service->service_adsl->adsl_plan->adsl_supplier_plan->tax()); ?> + onchange="paid(this);"/> + + diff --git a/modules/service/views/service/list/adslbilling_foot.php b/modules/service/views/service/list/adslbilling_foot.php new file mode 100644 index 00000000..51a9b955 --- /dev/null +++ b/modules/service/views/service/list/adslbilling_foot.php @@ -0,0 +1,4 @@ + +   + + diff --git a/modules/service/views/service/list/adslbilling_head.php b/modules/service/views/service/list/adslbilling_head.php new file mode 100644 index 00000000..5ad3ace7 --- /dev/null +++ b/modules/service/views/service/list/adslbilling_head.php @@ -0,0 +1,7 @@ + diff --git a/modules/service/views/service/list/adslbilling_summary.php b/modules/service/views/service/list/adslbilling_summary.php new file mode 100644 index 00000000..265b6820 --- /dev/null +++ b/modules/service/views/service/list/adslbilling_summary.php @@ -0,0 +1,10 @@ + + service_adsl->display('service_number'); ?> + service_adsl->adsl_plan->adsl_supplier_plan->name(); ?> + service_adsl->contract_date_start(); ?> + service_adsl->contract_date_end(); ?> + service_adsl->adsl_plan->adsl_supplier_plan->base_cost); ?> + service_adsl->adsl_plan->adsl_supplier_plan->base_cost+$service->service_adsl->adsl_plan->adsl_supplier_plan->tax()); ?> + + service_adsl->adsl_plan->adsl_supplier_plan->base_cost+$service->service_adsl->adsl_plan->adsl_supplier_plan->tax()-$amount; ?> + diff --git a/modules/service/views/service/list/adslbilling_summary_exception.php b/modules/service/views/service/list/adslbilling_summary_exception.php new file mode 100644 index 00000000..8515b45e --- /dev/null +++ b/modules/service/views/service/list/adslbilling_summary_exception.php @@ -0,0 +1,6 @@ + + + + + + diff --git a/modules/service/views/service/list/adslservices_body.php b/modules/service/views/service/list/adslservices_body.php new file mode 100644 index 00000000..fc5b2467 --- /dev/null +++ b/modules/service/views/service/list/adslservices_body.php @@ -0,0 +1,12 @@ + + service_adsl->display('service_number'); ?> + service_adsl->ipaddress(); ?> + name(),$service->id); ?> + service_adsl->adsl_plan->allowance(); ?> + service_adsl->traffic_thismonth(); ?> + service_adsl->traffic_lastmonth(); ?> + display('price'); ?> + display('recur_schedule'); ?> + display('date_next_invoice'); ?> + + diff --git a/modules/service/views/service/list/adslservices_header.php b/modules/service/views/service/list/adslservices_header.php new file mode 100644 index 00000000..69dbd986 --- /dev/null +++ b/modules/service/views/service/list/adslservices_header.php @@ -0,0 +1,23 @@ + + + + + + + + + +
                    account->accnum(),$service->account->name()); ?>invoices_due_total())); ?>
                    + + + + Service + IP Address + Plan + Plan Allowance + This Month + Last Month + Amount + Freq + Next Invoice Date + diff --git a/modules/service/views/service/list/bycheckout_body.php b/modules/service/views/service/list/bycheckout_body.php new file mode 100644 index 00000000..fd8d1103 --- /dev/null +++ b/modules/service/views/service/list/bycheckout_body.php @@ -0,0 +1,9 @@ + + account->accnum(); ?> + account->name(); ?> + name(),$service->id); ?> + display('recur_schedule'); ?> + display('price'); ?> + invoices_due_total(); ?> + display('date_next_invoice'); ?> + diff --git a/modules/service/views/service/list/bycheckout_header.php b/modules/service/views/service/list/bycheckout_header.php new file mode 100644 index 00000000..bb81ec5b --- /dev/null +++ b/modules/service/views/service/list/bycheckout_header.php @@ -0,0 +1,16 @@ + + + + + + + + Account ID + Account + Service + Frequency + Amount + Invoices Due + Next Payment Date + + diff --git a/modules/service/views/service/list/bycheckout_subtotal.php b/modules/service/views/service/list/bycheckout_subtotal.php new file mode 100644 index 00000000..e4cabf7c --- /dev/null +++ b/modules/service/views/service/list/bycheckout_subtotal.php @@ -0,0 +1,5 @@ + +   + +   + diff --git a/modules/service/views/service/view.php b/modules/service/views/service/view.php new file mode 100644 index 00000000..ed677ac4 --- /dev/null +++ b/modules/service/views/service/view.php @@ -0,0 +1,39 @@ + + + + + + +
                    + + + + + + + + + + + + + + + + + + + + + + + + + + +
                    Service Nameproduct->product_translate->find()->name; ?>
                    Service Activedisplay('active'); ?>
                    Billing Perioddisplay('recur_schedule');?>
                    Costdisplay('price'); ?>
                    Date Next Invoicedate_next_invoice); ?>
                    Current Invoices Dueinvoices_due_total()); ?>
                    +
                    + + +
                    + diff --git a/modules/service/views/service/view_detail_adsl.php b/modules/service/views/service/view_detail_adsl.php new file mode 100644 index 00000000..0f04a4a7 --- /dev/null +++ b/modules/service/views/service/view_detail_adsl.php @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + +
                    View Daily Traffic for Monthservice_adsl->get_traffic_months(),(isset($_POST['month']) ? $_POST['month'] : '')); echo Form::submit('submit',_('Show')); echo Form::close(); ?>
                     
                    + + + + + + + + + + + + + +
                    ADSL Serviceservice_adsl->service_number; ?>
                    Contract Termservice_adsl->contract_term; ?>
                    Contract Endservice_adsl->contract_date_end(); ?>
                    +
                    diff --git a/modules/service/views/service/view_detail_adsl_traffic.php b/modules/service/views/service/view_detail_adsl_traffic.php new file mode 100644 index 00000000..a90e29e8 --- /dev/null +++ b/modules/service/views/service/view_detail_adsl_traffic.php @@ -0,0 +1,9 @@ + + + $usage) { ?> + + + + + +
                    diff --git a/modules/session/session_construct.xml b/modules/session/session_construct.xml index db30d4bd..b8bfbdeb 100644 --- a/modules/session/session_construct.xml +++ b/modules/session/session_construct.xml @@ -49,9 +49,9 @@ I8 - I8 date Date Expire + I8 L @@ -100,6 +100,7 @@ Campaign + 1 C(255) @@ -112,6 +113,7 @@ id,site_id,date_orig,date_last,date_expire,logged,ip,theme_id,country_id,language_id,currency_id,weight_id,account_id,reseller_id,affiliate_id,discounts id,site_id,date_orig,date_last,date_expire,logged,ip,theme_id,country_id,language_id,currency_id,weight_id,account_id,reseller_id,affiliate_id,discounts id,site_id,date_orig,date_last,date_expire,logged,ip,theme_id,country_id,language_id,currency_id,weight_id,account_id,reseller_id,affiliate_id,discounts + id,site_id,date_orig,date_last,date_expire,logged,ip,theme_id,country_id,language_id,currency_id,weight_id,account_id,reseller_id,affiliate_id,discounts
                    diff --git a/modules/setup/setup_install_data.xml b/modules/setup/setup_install_data.xml index df5dbfd2..6d849be8 100644 --- a/modules/setup/setup_install_data.xml +++ b/modules/setup/setup_install_data.xml @@ -4,7 +4,7 @@ 1 1 61 - english + en 6 1 default diff --git a/modules/staff/staff.inc.php b/modules/staff/staff.inc.php index 1f464ea3..9b937519 100644 --- a/modules/staff/staff.inc.php +++ b/modules/staff/staff.inc.php @@ -29,6 +29,56 @@ * @subpackage Module:Staff */ class staff extends OSB_module { + /** + * Get the staff who are a member of a department + * + * @param string $dep Department to find users + * @return array Staff Ids who are a member of the department + * @uses staff_department + */ + public function sDepartmentMember($dep) { + require_once(PATH_MODULES.'staff_department/staff_department.inc.php'); + $sdo = new staff_department; + + if (! $department = $sdo->sql_GetRecords(array('where'=>array('name'=>$dep)))) + return array(); + + $department = array_pop($department); + $result = array(); + + foreach ($this->sql_GetRecords(array('where'=>'department_avail IS NOT NULL')) as $record) { + $department_avail = unserialize($record['department_avail']); + + if (in_array($department['id'],$department_avail)) + array_push($result,$record['account_id']); + } + + return $result; + } + + /** + * Get the list of emails and names of users in a department + * + * @param string $dep Name of Department to obtain + * @return array Emails and Full Names + * @uses account + */ + public function sDepartmentMemberEmail($dep) { + $result = array(); + + $members = $this->sDepartmentMember($dep); + + if (count($members)) { + require_once(PATH_MODULES.'account/account.inc.php'); + $ao = new account; + + foreach ($ao->sql_GetRecords(array('where'=>sprintf('id IN (%s)',implode(',',$members)))) as $record) + $result[$record['email']] = sprintf('%s %s',$record['first_name'],$record['last_name']); + } + + return $result; + } + /** * EMAIL ONE STAFF MEMBER */ diff --git a/modules/staff/staff_construct.xml b/modules/staff/staff_construct.xml index 76d909e8..b94024fc 100644 --- a/modules/staff/staff_construct.xml +++ b/modules/staff/staff_construct.xml @@ -74,11 +74,11 @@ - account_id,department_avail,nickname - id,site_id,date_orig,account_id,department_avail,nickname,notify_new,notify_change,signature - id,site_id,date_orig,account_id,department_avail,nickname,notify_new,notify_change,signature - id,site_id,date_orig,account_id,department_avail,nickname,notify_new,notify_change,signature - id,site_id,date_orig,account_id,department_avail,nickname,notify_new,notify_change,signature + account_id,nickname + account_id,department_avail,nickname,signature + id + id,date_orig,account_id,department_avail,nickname,signature + id,date_orig,account_id,department_avail,nickname,signature @@ -86,6 +86,8 @@ + <add>Add Staff</add> + <view>View Staff</view> diff --git a/modules/staff_department/staff_department_construct.xml b/modules/staff_department/staff_department_construct.xml index 3cfd163e..7152af2c 100644 --- a/modules/staff_department/staff_department_construct.xml +++ b/modules/staff_department/staff_department_construct.xml @@ -51,24 +51,28 @@ any + Show Users on Contact Form L - date_orig,name,description,default_staff_id,contact_display - id,site_id,name,description,default_staff_id,contact_display - id,site_id,name,description,default_staff_id,contact_display - id,site_id,name,description,default_staff_id,contact_display - id,site_id,name,description,default_staff_id,contact_display + name,description,default_staff_id,contact_display + name,description,default_staff_id,contact_display + id + id,name,description,default_staff_id,contact_display + id,name,default_staff_id,contact_display - + + <add>Add Department</add> + <view>View Department</view> + diff --git a/modules/staff_department/staff_department_install.xml b/modules/staff_department/staff_department_install.xml index 26669704..9658ee1f 100644 --- a/modules/staff_department/staff_department_install.xml +++ b/modules/staff_department/staff_department_install.xml @@ -14,6 +14,8 @@ setup + + diff --git a/modules/static_page/classes/controller/staticpage.php b/modules/static_page/classes/controller/staticpage.php new file mode 100644 index 00000000..9bc63c85 --- /dev/null +++ b/modules/static_page/classes/controller/staticpage.php @@ -0,0 +1,36 @@ +loaded()) + Request::instance()->redirect('staticpage_category/index'); + + array_push($this->_control, + array($sp->staticpage_category->name=>sprintf('staticpage_category/view/'.$sp->static_page_category_id))); + array_push($this->_control,array($sp->staticpage_translate->title=>$this->request->uri())); + + Block::add(array( + 'title'=>$sp->staticpage_translate->title, + 'body'=>View::factory('staticpage/view') + ->set('record',$sp), + )); + + $this->template->content = Block::factory(); + } +} diff --git a/modules/static_page/classes/controller/staticpage/category.php b/modules/static_page/classes/controller/staticpage/category.php new file mode 100644 index 00000000..2d513404 --- /dev/null +++ b/modules/static_page/classes/controller/staticpage/category.php @@ -0,0 +1,72 @@ +'staticpage_category'), + ); + + /** + * By default show a menu of available categories + */ + public function action_index() { + + Block::add(array( + 'title'=>_('Site Index Categories'), + 'body'=>View::factory('staticpage/category/list') + ->set('results',$this->_get_categories()), + )); + + $this->template->content = Block::factory(); + } + + /** + * Show the available topics in a category + * @todo Only show categories according to their validity dates + * @todo Obey sort order + */ + public function action_view($id) { + $spc = ORM::factory('staticpage_category',$id); + + if (! $spc->loaded()) + Request::instance()->redirect('welcome/index'); + + array_push($this->_control,array($spc->name=>$this->request->uri())); + + Block::add(array( + 'title'=>sprintf('%s: %s',_('Category'),$spc->name), + 'body'=>View::factory('staticpage/category/view') + ->set('results',$this->_get_category($spc->id)), + )); + + $this->template->content = Block::factory(); + } + + /** + * Obtain a list of pages in a category + */ + private function _get_category($id) { + return ORM::factory('staticpage') + ->where('static_page_category_id','=',$id) + ->find_all(); + } + + /** + * Obtain a list of our categories + * @todo Only show categories according to the users group memeberhsip + * @todo Obey sort order + */ + private function _get_categories() { + return ORM::factory('staticpage_category') + ->find_all(); + } +} diff --git a/modules/static_page/classes/model/staticpage.php b/modules/static_page/classes/model/staticpage.php new file mode 100644 index 00000000..b9f0d439 --- /dev/null +++ b/modules/static_page/classes/model/staticpage.php @@ -0,0 +1,27 @@ +'asc', + ); + + protected $_has_many = array( + 'staticpage_translate'=>array('foreign_key'=>'static_page_id'), + ); + + protected $_belongs_to = array( + 'staticpage_category'=>array('foreign_key'=>'static_page_category_id'), + ); +} diff --git a/modules/static_page/classes/model/staticpage/category.php b/modules/static_page/classes/model/staticpage/category.php new file mode 100644 index 00000000..43c965f3 --- /dev/null +++ b/modules/static_page/classes/model/staticpage/category.php @@ -0,0 +1,19 @@ +'asc', + ); +} diff --git a/modules/static_page/classes/model/staticpage/translate.php b/modules/static_page/classes/model/staticpage/translate.php new file mode 100644 index 00000000..18cf92f3 --- /dev/null +++ b/modules/static_page/classes/model/staticpage/translate.php @@ -0,0 +1,19 @@ +array('foreign_key'=>'id'), + ); +} diff --git a/modules/static_page/views/staticpage/category/list.php b/modules/static_page/views/staticpage/category/list.php new file mode 100644 index 00000000..6934e5e9 --- /dev/null +++ b/modules/static_page/views/staticpage/category/list.php @@ -0,0 +1,7 @@ + + + + + + +
                    diff --git a/modules/static_page/views/staticpage/category/view.php b/modules/static_page/views/staticpage/category/view.php new file mode 100644 index 00000000..8e16ca7e --- /dev/null +++ b/modules/static_page/views/staticpage/category/view.php @@ -0,0 +1,40 @@ +staticpage_translate->where('static_page_id','=',$record->id)->and_where('language_id','=','fr')->find(); + + // If there isnt a translated page, show the default language + // @todo - default language should come from configuration + if (! $translate->loaded()) + $translate = $record->staticpage_translate->where('static_page_id','=',$record->id)->and_where('language_id','=','en')->find(); +?> + + + + + +
                    + + + + + + + +
                    title; ?>
                    + + + + +
                    body_intro; ?>
                    +
                    +
                    +
                    + diff --git a/modules/static_page/views/staticpage/view.php b/modules/static_page/views/staticpage/view.php new file mode 100644 index 00000000..2270be31 --- /dev/null +++ b/modules/static_page/views/staticpage/view.php @@ -0,0 +1,32 @@ +staticpage_translate->where('static_page_id','=',$record->id)->and_where('language_id','=','fr')->find(); + + // If there isnt a translated page, show the default language + // @todo - default language should come from configuration + if (! $translate->loaded()) + $translate = $record->staticpage_translate->where('static_page_id','=',$record->id)->and_where('language_id','=','en')->find(); +?> + + + + + +
                    + + + + +
                    + + + + +
                    body_full; ?>
                    +
                    +
                    diff --git a/modules/static_page_category/static_page_category.inc.php b/modules/static_page_category/static_page_category.inc.php index bc64c50d..674b3cbc 100644 --- a/modules/static_page_category/static_page_category.inc.php +++ b/modules/static_page_category/static_page_category.inc.php @@ -20,64 +20,8 @@ * @author Tony Landis * @package AgileBill * @subpackage Modules:StaticPages + * @deprecated Now using KH */ -/** - * The main AgileBill Static Page Categories Class - * - * @package AgileBill - * @subpackage Modules:StaticPages - */ -class static_page_category extends OSB_module { - /** - * Get the page categories - */ - public function get_page_categories($VAR) { - global $C_auth; - - $categories = array(); - $db = &DB(); - - if (isset($VAR['id']) && trim($VAR['id'])) - $result = $db->Execute(sqlSelect($db,'static_page_category','id,name,group_avail',array('status'=>1,'id'=>$VAR['id']),'sort_order,name')); - else - $result = $db->Execute(sqlSelect($db,'static_page_category','id,name,group_avail',array('status'=>1),'sort_order,name')); - - if ($result && $result->RecordCount()) - while (! $result->EOF) { - @$arr = unserialize($result->fields['group_avail']); - - for ($i=0; $iauth_group_by_id($arr[$i])) { - array_push($categories,array('name'=>$result->fields['name'],'id'=>$result->fields['id'])); - $i=count($arr); - } - } - - $result->MoveNext(); - } - - return $categories; - } - - /** - * Get all the page categories to a user - */ - public function menu() { - global $smarty; - - $smart = $this->get_page_categories(array()); - - if (! count($smart)) { - $smarty->assign('static_page_category_display',false); - return false; - - } else { - $smarty->assign('static_page_category_display',true); - $smarty->assign('static_page_category_results',$smart); - - return true; - } - } -} +class static_page_category extends OSB_module {} ?> diff --git a/modules/task/task.inc.php b/modules/task/task.inc.php index e3fd0cb9..ff69742e 100644 --- a/modules/task/task.inc.php +++ b/modules/task/task.inc.php @@ -27,52 +27,64 @@ * * @package AgileBill * @subpackage Module:Task + * @todo Change the debug printing to use central debugging calls ie: C_alert */ class task extends OSB_module { + # Schedule Task ID + private $id = null; + # Does this task need authorisation + private $noauth = false; + /** * Run all scheduled tasks + * + * @uses cron; */ public function run_all() { + include_once(PATH_INCLUDES.'cron/cron.inc.php'); + $cron = new cron; + # Ensure that tasks complete and dont hang on running=1 set_time_limit(2*60*60); # Loop through the tasks: - global $VAR; + foreach ($this->sql_GetRecords(array('where'=>'(running=0 OR running IS NULL) AND status=1')) as $result) { + # Initialise the task + $this->id = $result['id']; + $this->noauth = false; - $db = &DB(); - $result = $db->Execute(sqlSelect($db,'task','*','(running=0 OR running IS NULL) AND status=1')); - if ($result && $result->RecordCount() > 0) { - include_once(PATH_INCLUDES.'cron/cron.inc.php'); - $cron = new cron; + if ($this->debug) + printf("%s: Selecting Job [%s] (%s)\n",__METHOD__,$result['command'],$this->id); - while (! $result->EOF) { - $_r = false; - $_s = (int) $result->fields['date_start']; - $_e = (int) $result->fields['date_expire']; - $_l = (int) $result->fields['date_run']; - $_c = sprintf('%s %s %s %s %s', - $result->fields['int_min'], - $result->fields['int_hour'], - $result->fields['int_month_day'], - $result->fields['int_month'], - $result->fields['int_week_day']); - $_n = (int) time(); - if (! $_l > 0) - $_l = $_n-86400*365; + $task = array(); + $task['start'] = (int)$result['date_start']; + $task['end'] = (int)$result['date_expire']; + $task['lastrun'] = (int)$result['date_run']; + $task['cron'] = sprintf('%s %s %s %s %s', + $result['int_min'], + $result['int_hour'], + $result['int_month_day'], + $result['int_month'], + $result['int_week_day']); + $task['now'] = (int)time(); - # Verify it has not expired: - if ($_s <= $_n || $_s == '' || $_s == '0') { - # Verify it is past the start date: - if ($_e >= $_n || $_e == '' || $_e == '0') { - # Verify that it is time to run: - if ($cron->due($_l,$_n,$_c)) { - # Run the task: - $this->id = $result->fields['id']; - $this->run($VAR); - } + # Default the last run time, if it isnt set + if (! $task['lastrun'] > 0) + $task['lastrun'] = $task['now']-86400*365; + + # Verify it has not expired: + if ($task['start'] <= $task['now'] || $task['start'] == '' || $task['start'] == '0') { + # Verify it is past the start date: + if ($task['end'] >= $task['now'] || $task['end'] == '' || $task['end'] == '0') { + # Verify that it is time to run: + if ($cron->due($task['lastrun'],$task['now'],$task['cron'])) { + # Run the task: + if ($this->debug) + printf("%s: Running Job [%s] (%s)\n",__METHOD__,$result['command'],$this->id); + + $this->run($this->VAR); } } - $result->MoveNext(); } } } @@ -83,97 +95,93 @@ class task extends OSB_module { * @uses task_log */ public function run($VAR) { - global $VAR,$C_auth,$_ENV,$_SERVER,$_COOKIE,$C_list; + global $VAR,$C_auth,$_ENV,$_SERVER,$_COOKIE,$C_list,$C_method; + $db = &DB(); - $noauth = false; - $debug_out = false; + # Check if we are on a console, we'll debug output if we are if (isset($_ENV['S']) || (isset($_ENV['SESSIONNAME']) && $_ENV['SESSIONNAME'] == 'Console') || (isset($_SERVER['SESSIONNAME']) && $_SERVER['SESSIONNAME'] == 'Console') || (isset($_SERVER['CLIENTNAME']) && $_SERVER['CLIENTNAME'] == 'Console') || empty($_COOKIE)) { - $debug_out = true; - $noauth = true; + $this->debug = true; + $this->noauth = true; + + # Can this task be run without authorisation } elseif($C_auth->auth_method_by_name('task','run')) { - $noauth = true; - - } else { - $noauth = false; + $this->noauth = true; } - if (isset($this->id)) - $id = $this->id; - elseif (isset($VAR['id'])) - $id = $VAR['id']; - else - return; + if (! isset($this->id)) { + if (isset($VAR['id'])) + $this->id = $VAR['id']; + else + return false; + } # Get task details - $db = &DB(); - $result = $db->Execute(sqlSelect($db,'task','*',array('id'=>$id))); - - if (! $result || $result->RecordCount() == 0) - return; - - $type = $result->fields['type']; - $cmd = $result->fields['command']; - $log = $result->fields['log']; + if (! $task = $this->sql_GetRecords(array('where'=>array('id'=>$this->id)))) + return false; + $task = array_shift($task); # Record task running - $db->Execute(sqlUpdate($db,'task',array('running'=>1),array('id'=>$id))); + $db->Execute(sqlUpdate($db,'task',array('running'=>1),array('id'=>$this->id))); + + if ($this->debug) + printf("%s: Running Task [%s]\n",__METHOD__,$task['command']); # Run task - switch ($type) { + switch ($task['type']) { + # Internal function case 0: - # Internal function: - global $C_method; - $arr = explode(":",$cmd); + $cm = explode(':',$task['command']); - if ($noauth) { - # run from console, no auth req - $C_method->exe_noauth($arr[0],$arr[1]); - } else { - # run from web, auth required - $C_method->exe($arr[0],$arr[1]); - } + if ($this->noauth) + $C_method->exe_noauth($cm[0],$cm[1]); + else + $C_method->exe($cm[0],$cm[1]); if ($C_method->result) $result = 1; else $result = 0; - @$message = $C_method->error; + $message = isset($C_method->error) ? $C_method->error : ''; + break; + # Run System Command: case 1: - $message = `$cmd`; + $message = `{$task['command']}`; $result = 1; break; default: - printf('ERROR: Unknown task type [%s]',$type); + printf('ERROR: Unknown task type [%s]',$result['type']); } # Update last run date & flip run toggle - $db->Execute(sqlUpdate($db,'task',array('running'=>0,'date_run'=>time()),array('id'=>$id))); + $db->Execute(sqlUpdate($db,'task',array('running'=>0,'date_run'=>time()),array('id'=>$this->id))); # Store task log if required - if ($log && $C_list->is_installed('task_log')) { + if ($task['log'] && $C_list->is_installed('task_log')) { include_once(PATH_MODULES.'task_log/task_log.inc.php'); $tl = new task_log; - $VAR['task_log_task_id'] = $id; - $VAR['task_log_result'] = $result; - $VAR['task_log_message'] = $message; - if (! isset($VAR['_page_current'])) - $VAR['_page_current'] = ''; - $result = $tl->add($VAR); + $tl->add(array( + 'task_log_task_id'=>$this->id, + 'task_log_result'=>$result, + 'task_log_message'=>$message, + '_page_current'=>isset($VAR['_page_current']) ? $VAR['_page_current'] : '', + '_noredirect'=>1 + )); } # If admin, print success message if (DEFAULT_ADMIN_THEME == SESS_THEME) { global $C_translate,$C_debug; + $C_debug->alert($C_translate->translate('true','','')); } } diff --git a/modules/task/task_construct.xml b/modules/task/task_construct.xml index cd652315..6515d1a2 100644 --- a/modules/task/task_construct.xml +++ b/modules/task/task_construct.xml @@ -135,13 +135,13 @@ - + - date_start,date_expire,date_last,name,description,log,type,command,int_min,int_hour,int_month_day,int_month,int_week_day - id,site_id,status,date_start,date_expire,date_last,name,description,log,type,command,int_min,int_hour,int_month_day,int_month,int_week_day,running - id,site_id,date_start,date_expire,date_last,name,description,log,type,command,int_min,int_hour,int_month_day,int_month,int_week_day,running - id,site_id,status,date_start,date_expire,date_last,name,description,log,type,command,int_min,int_hour,int_month_day,int_month,int_week_day,running - id,site_id,status,date_start,date_expire,date_last,name,description,log,type,command,int_min,int_hour,int_month_day,int_month,int_week_day,running + date_start,date_expire,name,description,type,command,int_min,int_hour,int_month_day,int_month,int_week_day + id,name,status,log,date_start,date_expire,description,type,command,int_min,int_hour,int_month_day,int_month,int_week_day,running + id + id,name,date_last,date_run,status,log,date_start,date_expire,description,type,command,int_min,int_hour,int_month_day,int_month,int_week_day,running + id,name,date_last,date_run,command,status diff --git a/modules/task/task_install.xml b/modules/task/task_install.xml index 7fe1b894..760d681f 100644 --- a/modules/task/task_install.xml +++ b/modules/task/task_install.xml @@ -14,6 +14,8 @@ setup + + base diff --git a/modules/task_log/task_log_construct.xml b/modules/task_log/task_log_construct.xml index 4dddb53b..671f21c0 100644 --- a/modules/task_log/task_log_construct.xml +++ b/modules/task_log/task_log_construct.xml @@ -51,13 +51,11 @@ - + task_id,result,message - id,site_id,task_id,date_orig,result,message - id,site_id,task_id,date_orig,result,message - id,site_id,task_id,date_orig,result,message - id,site_id,task_id,date_orig,result,message + id + id,task_id,date_orig,result,message @@ -69,5 +67,26 @@ - + + + + id + checkbox + 25px + + + date_orig + date + + + task_id + + + result + + + message + + + diff --git a/modules/task_log/task_log_install.xml b/modules/task_log/task_log_install.xml index 7c4b819b..11cbbdcf 100644 --- a/modules/task_log/task_log_install.xml +++ b/modules/task_log/task_log_install.xml @@ -14,6 +14,8 @@ task + + base diff --git a/modules/tax/classes/model/invoice/item/tax.php b/modules/tax/classes/model/invoice/item/tax.php new file mode 100644 index 00000000..4db80941 --- /dev/null +++ b/modules/tax/classes/model/invoice/item/tax.php @@ -0,0 +1,15 @@ + diff --git a/modules/tax/classes/model/tax.php b/modules/tax/classes/model/tax.php new file mode 100644 index 00000000..70093d88 --- /dev/null +++ b/modules/tax/classes/model/tax.php @@ -0,0 +1,15 @@ + diff --git a/modules/tax/classes/tax.php b/modules/tax/classes/tax.php new file mode 100644 index 00000000..e14b83f8 --- /dev/null +++ b/modules/tax/classes/tax.php @@ -0,0 +1,58 @@ +where('country_id','=',$cid) + ->and_where('zone','=',$zone); + + $taxes = array(); + foreach ($tax->find_all() as $item) { + $total = array(); + + $total['id'] = $item->id; + $total['description'] = $item->description; + $total['amount'] = $item->rate*$value; + $total['rate'] = $item->rate; + + array_push($taxes,$total); + } + + return $taxes; + } + + // Calculate the tax amount + public static function total($cid,$zone,$value) { + $total = 0; + + foreach (static::detail($cid,$zone,$value) as $tax) + $total += $tax['amount']; + + return $total; + } + + public static function add($value) { + // @todo Tax details should come from session + // @todo Rounding should be a global config + return round($value+static::total(61,NULL,$value),2); + } +} +?> diff --git a/plugins/checkout/PAYPAL.php b/plugins/checkout/PAYPAL.php index 711a84b5..f2ae0d0d 100644 --- a/plugins/checkout/PAYPAL.php +++ b/plugins/checkout/PAYPAL.php @@ -124,6 +124,7 @@ class plg_chout_PAYPAL extends plg_chout_base_PAYPAL { # Read the post from PayPal system and add 'cmd' global $_POST,$C_debug; + $ret = array(); $req = 'cmd=_notify-validate'; foreach ($_POST as $key => $value) { @@ -131,30 +132,33 @@ class plg_chout_PAYPAL extends plg_chout_base_PAYPAL { $req .= sprintf('&%s=%s',$key,$value); } - $C_debug->error(__FILE__,__METHOD__,sprintf("%s: %s - Invoice: %s\r\n%s",$this->name,$_POST['txn_type'],$_POST['invoice'],$req)); - # Post back to PayPal system to validate $header = "POST /cgi-bin/webscr HTTP/1.0\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= sprintf("Content-Length: %s\r\n\r\n",strlen($req)); - $fp = fsockopen($this->getLocation(false,true),80,$errno,$errstr,30); - - # Needed for validation - $ret['invoice_id'] = $_POST['invoice']; - $ret['transaction_id'] = $_POST['txn_id']; - $ret['currency'] = $_POST['mc_currency']; - - if (! empty($_POST['mc_gross'])) - $ret['amount'] = $_POST['mc_gross']; - else - $ret['amount'] = $_POST['payment_gross']; - # Validate + $fp = fsockopen($this->getLocation(false,true),80,$errno,$errstr,30); if (! $fp) { $C_debug->error(__FILE__,__METHOD__,sprintf('Unable to connect to %s',$this->getLocation(false,true))); } else { + $ret['invoice_id'] = $_POST['invoice']; + $ret['transaction_id'] = $_POST['txn_id']; + $ret['currency'] = $_POST['mc_currency']; + + if (! empty($_POST['mc_gross'])) + $ret['amount'] = $_POST['mc_gross']; + else + $ret['amount'] = $_POST['payment_gross']; + + # Get a list of items paid + $i = array('item_number','item_name','mc_gross_'); + foreach ($_POST as $k => $v) + foreach ($i as $j) + if (preg_match("/^{$j}([0-9]+)/",$k,$m)) + $ret['items'][$m[1]][$j] = $v; + fputs($fp,$header.$req); while (! feof($fp)) { @@ -174,10 +178,11 @@ class plg_chout_PAYPAL extends plg_chout_base_PAYPAL { case 'VERIFIED': # Get the payment status $ret['status'] = true; - switch($_POST['txn_type']) { - case 'cart': $ret['status'] = true; break; - default: $ret['status'] = false; break; - } + if (isset($_POST['txn_type'])) + switch($_POST['txn_type']) { + case 'cart': $ret['status'] = true; break; + default: $ret['status'] = false; break; + } if ($ret['status'] != false) { switch($_POST['payment_status']) { @@ -189,11 +194,13 @@ class plg_chout_PAYPAL extends plg_chout_base_PAYPAL { # Get the processor details $this->getDetailsName($this->name); + $ret['checkout_id'] = $this->checkout_id; $cfg = unserialize($this->flds['plugin_data']); if ($_POST['receiver_email'] == $cfg['email']) { include_once(PATH_MODULES.'checkout/checkout.inc.php'); - $checkout = new checkout; - $checkout->postback($ret); + $checkout = new checkout($this->checkout_id); + $C_debug->error(__FILE__,__METHOD__,sprintf("Calling checkout %s: with: %s",$this->name,print_r($ret,true))); + $checkout->postback($ret,$this->name); } fclose($fp); @@ -222,13 +229,19 @@ class plg_chout_PAYPAL extends plg_chout_base_PAYPAL { # Postback Function if (empty($VAR) && empty($VAR['do'])) { - include_once('../../config.inc.php'); + require_once('../../config.inc.php'); require_once(PATH_ADODB.'adodb.inc.php'); require_once(PATH_CORE.'database.inc.php'); require_once(PATH_CORE.'setup.inc.php'); + require_once(PATH_CORE.'list.inc.php'); + require_once(PATH_CORE.'translate.inc.php'); + require_once(PATH_MODULES.'module.inc.php'); + $C_debug = new CORE_debugger; + $C_translate = new CORE_translate; $C_db = &DB(); $C_setup = new CORE_setup; + $C_list = new CORE_list; $plg = new plg_chout_PAYPAL; $plg->postback(); } diff --git a/plugins/checkout/PAYPAL/PAYPAL.php b/plugins/checkout/PAYPAL/PAYPAL.php index e9f616f8..53e4ada5 100644 --- a/plugins/checkout/PAYPAL/PAYPAL.php +++ b/plugins/checkout/PAYPAL/PAYPAL.php @@ -40,7 +40,7 @@ abstract class plg_chout_base_PAYPAL extends base_checkout_plugin { $this->success_url = URL.'?_page=invoice:thankyou&_next_page=invoice:user_view&id='; $this->decline_url = URL.'?_page=invoice:checkout_multiple&id='; } else { - $this->success_url = URL.'?_page=invoice:thankyou&_next_page=account:account&id='; + $this->success_url = URL.'?_page=invoice:thankyou&_next_page=invoice:user_view&id='; $this->decline_url = URL.'?_page=invoice:user_view&id='; } diff --git a/plugins/import/WHMCS.php b/plugins/import/WHMCS.php index 30851812..12efbee0 100644 --- a/plugins/import/WHMCS.php +++ b/plugins/import/WHMCS.php @@ -122,6 +122,12 @@ that will be used to process all recurring charges... this should be a gateway 'desc' => 'Step 10: Import the Invoices Items', 'depn' => array('invoices') )); + + array_push($this->actions,array( + 'name' => 'payments', + 'desc' => 'Step 11: Import the Payments', + 'depn' => array('invoices') + )); } protected function pre_services() { @@ -443,6 +449,7 @@ that will be used to process all recurring charges... this should be a gateway foreach ($map as $a => $b) $update[$a] = $rs->fields[$b]; + $update['date_orig'] = time(); $update['date_last'] = time(); $update['language_id'] = DEFAULT_LANGUAGE; # @todo Work out currency based on country address @@ -1099,5 +1106,124 @@ FROM tblhosting,tblproducts where tblhosting.packageid=tblproducts.id'; printf("", $VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']); } + + /** + * Payments + */ + protected function payments() { + global $VAR,$C_debug; + + # Connect to the remote DB + $dbr = &NewADOConnection($this->type); + $dbr->Connect($this->host,$this->user,$this->pass,$this->db); + + # Determine the offset for the account + if (empty($VAR['offset'])) + $VAR['offset'] = 0; + + $offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit); + $remote_table = 'tblaccounts'; + $ab_table = 'payment'; + + # Select + $sql = sprintf('SELECT * FROM %s',$remote_table); + $rs = $dbr->SelectLimit($sql,$this->select_limit,$offset); + + if ($rs === false) { + $C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table)); + + return false; + } + + if ($rs->RecordCount() == 0) { + $C_debug->alert('No more records to process!'); + printf("",$VAR['plugin']); + + return; + } + + # Load Checkout Plugins + $db = &DB(); + $imprs = $db->Execute(sqlSelect($db,'checkout','id,checkout_plugin','')); + while (! $imprs->EOF) { + $co[$imprs->fields['checkout_plugin']] = $imprs->fields['id']; + $imprs->MoveNext(); + } + + # Load Accounts Imported + $imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'accounts','tblclients'))); + while (! $imprs->EOF) { + $account[$imprs->fields['remote_id']] = $imprs->fields['ab_id']; + $imprs->MoveNext(); + } + + $msg = sprintf('Processing %s Records...
                    ',$rs->RecordCount()); + + # If there is a map file, open it + $pmap = $this->read_map(); + + # Table mapping + $map = array(); + $map['notes'] = 'description'; + $map['total_amt'] = 'amountin'; + $map['fees_amt'] = 'fees'; + + # Loop through each remote item + while (! $rs->EOF) { + $msg .= sprintf('
                    Processing : %s...',$rs->fields['invoiceid']); + + # Start a new transaction for the insert: + $db = &DB(); + $db->StartTrans(); + + $update = array(); + foreach ($map as $a => $b) + $update[$a] = $rs->fields[$b]; + + $update['account_id'] = $account[$rs->fields['userid']*1]; + $update['checkout_plugin_id'] = $account[$rs->fields['userid']*1]; + $update['date_payment'] = strtotime($rs->fields['date']); + $update['date_orig'] = strtotime($rs->fields['date']); + if ($rs->fields['transid']) + $update['checkout_plugin_data'] = serialize(array('transid'=>$rs->fields['transid'])); + # Get the fixed items in the map table. + if (isset($pmap[$ab_table][$rs->fields['gateway']])) { + foreach ($pmap[$ab_table][$rs->fields['gateway']] as $field => $value) { + if (isset($co[$value])) + $update[$field] = $co[$value]; + else { + $update[$field] = sprintf('NOMAP-%s',$rs->fields['gateway']); + } + } + } + + # Import the item + $db->Execute($r=sqlInsert($db,$ab_table,$update)); + $id = $db->Execute($q=sqlSelect($db,$ab_table,'id',$update,'','0,1')); + + # Insert the import record + $this->import_transaction($this->plugin,$VAR['action'],$ab_table,$id->fields['id'],$remote_table,$rs->fields['id'],$db); + + $update = array(); + $update['date_orig'] = strtotime($rs->fields['date']); + $update['payment_id'] = $id->fields['id']; + $update['invoice_id'] = $rs->fields['invoiceid']; + $update['alloc_amt'] = $rs->fields['amountin']; + + $db->Execute($r=sqlInsert($db,'payment_item',$update)); + $pi = $db->Execute($q=sqlSelect($db,'payment_item','id',$update,'','0,1')); + + $this->import_transaction($this->plugin,$VAR['action'],'payment_item',$pi->fields['id'],'',null,$db); + + # Complete the transaction + $db->CompleteTrans(); + $rs->MoveNext(); + } + + $C_debug->alert($msg); + + printf("", + $VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']); + } } ?> diff --git a/plugins/product/ADSL.php b/plugins/product/ADSL.php new file mode 100644 index 00000000..c3ff09f3 --- /dev/null +++ b/plugins/product/ADSL.php @@ -0,0 +1,28 @@ + + * @copyright 2009 Deon George + * @link http://osb.leenooks.net + * @package osBilling + * @subpackage Modules:ADSL + */ + +require_once PATH_MODULES.'product/base_product_plugin.inc.php'; + +/** + * This class provides the ability to define ADSL Supplier Products. + * + * @package osBilling + * @subpackage Modules:ADSL + */ +class plgn_prov_ADSL extends base_product_plugin { + # Plugin Name + protected $name = 'ADSL'; + # If this plugin provisions remote services + public $remote_based = false; +} +?> diff --git a/themes/default/blocks/account/view.tpl b/themes/default/blocks/account/view.tpl index 49a130be..d831ebd9 100644 --- a/themes/default/blocks/account/view.tpl +++ b/themes/default/blocks/account/view.tpl @@ -24,7 +24,11 @@ function accountJumpView(account_id,parent_account_id) { var module = document.getElementById('JumpView').value; document.getElementById('JumpView').value = ''; - var url = '?_page=core:search&module='+module+'&_next_page_one=view&'+module+'_account_id='+account_id; + if(module == 'discount') + var url = '?_page=core:search&module='+module+'&_next_page_one=view&'+module+'_avail_account_id='+account_id; + else + var url = '?_page=core:search&module='+module+'&_next_page_one=view&'+module+'_account_id='+account_id; + if(module != 'invoice' && module != 'service' && module != 'subaccount' && module != 'parentaccount' ) { view_show('collapse'); showIFrame('iframe',getPageWidth(600),500,url); @@ -189,10 +193,8 @@ - - + - {if $record.invoice} @@ -208,29 +210,32 @@ {/if} - - + - - + {/foreach} {/if} {if $record.service} + - + {foreach from=$record.service item=service} @@ -260,13 +265,45 @@
                     
                    {$invoice.id} + + {$invoice.id} + {if $invoice.due > 0} {$list->format_currency_num($invoice.total_amt,'')} {else} {$list->format_currency_num($invoice.total_amt,'')} {/if} - {if $invoice.due > 0} + + {if $invoice.due > 0 && $invoice.status} {$list->format_currency_num($invoice.due,'')} {else} {$list->format_currency_num('0','')} {/if}     {$list->date($invoice.date_orig)}    {$list->date($invoice.date_orig)}
                     

                    {t}Service Overview{/t}
                    {t}Service Overview{/t}
                    - - + - - {if $record.duesoon} + + {if $record.payment} - + + + {foreach from=$record.payment item=invoice} + + + + + + + + + + {/foreach} + {/if} + {if $record.duesoon} + + + {foreach from=$record.duesoon item=service} diff --git a/themes/default/blocks/account_fee/add.tpl b/themes/default/blocks/account_fee/add.tpl new file mode 100644 index 00000000..a09bda08 --- /dev/null +++ b/themes/default/blocks/account_fee/add.tpl @@ -0,0 +1,72 @@ +{assign var=meth value=':'|explode:$VAR._page} + + + +{if $form_validation} + {$block->display('core:alert_fields')} +{/if} + + + + +
                     

                    {t}Invoices Due Soon{/t}
                    {t}Payments Overview{/t}
                      + {if $invoice.pending_status == '1'} + + {else} + + {/if} + + {$invoice.id} + + {if $invoice.total_amt-$invoice.alloc_amt > 0} + {$list->format_currency_num($invoice.total_amt,'')} + {else} + {$list->format_currency_num($invoice.total_amt,'')} + {/if} + + {$list->format_currency_num($invoice.alloc_amt,'')} +  {$list->date($invoice.date_payment)}
                     
                    {t}Services Invoiced Soon{/t}
                    + + + +
                    + + + + + + + + + + + + + +
                    {osb f=tt}
                    + + + + + + + + +
                    {osb f=tf field=name}
                    {t}Group Pricing Structure{/t}
                    +
                    + + {assign var=groups_fee_array value=$VAR.account_fee_groups_fee} + {foreach from=$list->menu_staticlist('recur_schedule',true,'',0,'') key=key item=schedule} + + + + + + {/foreach} +
                    {$list->menu_staticlist('recur_schedule','','',$key,'')}Active {$list->bool("account_fee_groups_fee[$key][show]",$groups_fee_array[$key].show,'form_menu')} + {if ($list->smarty_array('group','name'," AND pricing='1' ",'group_array'))} + {foreach from=$group_array item=arr} + {assign var='idx' value=$arr.id} + + + + + +
                    {$arr.name}{t}Fee{/t} {$list->currency_iso('')}
                    + {/foreach} + {/if} +
                    +
                    + + {include file='file:../core/add_tr_submit.tpl'} +
                    +
                    +
                    + +
                    +
                    + diff --git a/themes/default/blocks/account_fee/search_show.tpl b/themes/default/blocks/account_fee/search_show.tpl new file mode 100644 index 00000000..2e593f28 --- /dev/null +++ b/themes/default/blocks/account_fee/search_show.tpl @@ -0,0 +1,12 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/search_show_pre.tpl'} + {$method->exe_noauth($meth.0,'tpl_search_show',$search_show)} + {include file='file:../core/search_show_post-1.tpl'} + {include file='file:../core/search_show_post-2.tpl'} +{/if} diff --git a/themes/default/blocks/account_fee/view.tpl b/themes/default/blocks/account_fee/view.tpl new file mode 100644 index 00000000..a3df7732 --- /dev/null +++ b/themes/default/blocks/account_fee/view.tpl @@ -0,0 +1,72 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/view_pre.tpl'} + + + {if $form_validation} + {$block->display('core:alert_fields')} + {/if} + + +
                    + + + + + +
                    + + + + + + + + + + + {include file='file:../core/view_tr_submit_delete.tpl'} +
                    {osb f=tt}
                    + + + + + + + + +
                    {osb f=tf field=name}
                    {t}Group Pricing Structure{/t}
                    +
                    + + {$list->unserial($record.groups_fee,'groups_fee_array')} + {foreach from=$list->menu_staticlist('recur_schedule',true,'',0,'') key=key item=schedule} + + + + + + {/foreach} +
                    {$list->menu_staticlist('recur_schedule','','',$key,'')}Active {$list->bool("account_fee_groups_fee[$key][show]",$groups_fee_array[$key].show,'form_menu')} + {if ($list->smarty_array('group','name'," AND pricing='1' ",'group_array'))} + {foreach from=$group_array item=arr} + {assign var='idx' value=$arr.id} + + + + + +
                    {$arr.name}{t}Fee{/t} {$list->currency_iso('')}
                    + {/foreach} + {/if} +
                    +
                    +
                    + + {include file='file:../core/view_post.tpl'} +
                    +{/if} diff --git a/themes/default/blocks/adsl/add.tpl b/themes/default/blocks/adsl/add.tpl new file mode 100644 index 00000000..8356db21 --- /dev/null +++ b/themes/default/blocks/adsl/add.tpl @@ -0,0 +1,43 @@ +{assign var=meth value=':'|explode:$VAR._page} + + + +{if $form_validation} + {$block->display('core:alert_fields')} +{/if} + + +
                    + + + + + +
                    + + + + + + + +
                    {osb f=tt}
                    + + + + + + + + + + + + + + {include file='file:../core/add_tr_submit.tpl'} +
                    {osb f=tf field=supplier_id}{$list->menu('','adsl_supplier_id','adsl_supplier','name',$VAR.adsl_supplier_id,'form_field',true)}
                    {osb f=tf field=product_id}
                    {osb f=tf field=product_desc}
                    +
                    +
                    + +
                    diff --git a/themes/default/blocks/adsl/search_show.tpl b/themes/default/blocks/adsl/search_show.tpl new file mode 100644 index 00000000..2e593f28 --- /dev/null +++ b/themes/default/blocks/adsl/search_show.tpl @@ -0,0 +1,12 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/search_show_pre.tpl'} + {$method->exe_noauth($meth.0,'tpl_search_show',$search_show)} + {include file='file:../core/search_show_post-1.tpl'} + {include file='file:../core/search_show_post-2.tpl'} +{/if} diff --git a/themes/default/blocks/adsl/view.tpl b/themes/default/blocks/adsl/view.tpl new file mode 100644 index 00000000..e70da85a --- /dev/null +++ b/themes/default/blocks/adsl/view.tpl @@ -0,0 +1,104 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/view_pre.tpl'} + + + {if $form_validation} + {$block->display('core:alert_fields')} + {/if} + + +
                    + + + + + +
                    + + + + + + + + {include file='file:../core/view_tr_submit_delete.tpl'} +
                    {osb f=tt}
                    + + + + + + + + + + + + + + + + + + + + + +
                    {osb f=tf field=supplier_id}{$record.supplier_id}.{$record.id}
                    {osb f=tf field=product_id}
                    {osb f=tf field=product_desc}
                    {osb f=tf field=status}{$list->bool('adsl_status',$record.status)}
                      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                    {osb f=tf field=base_cost}{osb f=tf field=contract_term}
                    {osb f=tf field=base_down_peak}{osb f=tf field=base_up_peak}
                    {osb f=tf field=base_down_offpeak}{osb f=tf field=base_up_offpeak}
                    {osb f=tf field=extra_charged}{$list->bool('adsl_extra_charged',$record.extra_charged)}{osb f=tf field=extra_shaped}
                    {osb f=tf field=offpeak_start}{osb f=tf field=offpeak_end}
                    {osb f=tf field=extra_down_peak}{osb f=tf field=extra_up_peak}
                    {osb f=tf field=extra_down_offpeak}{osb f=tf field=extra_up_offpeak}
                    +
                    +
                    +
                    + + {include file='file:../core/view_post.tpl'} +
                    +{/if} diff --git a/themes/default/blocks/adsl_supplier/add.tpl b/themes/default/blocks/adsl_supplier/add.tpl new file mode 100644 index 00000000..5ab77a06 --- /dev/null +++ b/themes/default/blocks/adsl_supplier/add.tpl @@ -0,0 +1,36 @@ +{assign var=meth value=':'|explode:$VAR._page} + + + +{if $form_validation} + { $block->display("core:alert_fields") } +{/if} + + +
                    + + + + + +
                    + + + + + + + + +
                    {osb f=tt}
                    + + + + + + {include file='file:../core/add_tr_submit.tpl'} +
                    {osb f=tf field=name}
                    +
                    +
                    + +
                    diff --git a/themes/default/blocks/adsl_supplier/search_show.tpl b/themes/default/blocks/adsl_supplier/search_show.tpl new file mode 100644 index 00000000..2e593f28 --- /dev/null +++ b/themes/default/blocks/adsl_supplier/search_show.tpl @@ -0,0 +1,12 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/search_show_pre.tpl'} + {$method->exe_noauth($meth.0,'tpl_search_show',$search_show)} + {include file='file:../core/search_show_post-1.tpl'} + {include file='file:../core/search_show_post-2.tpl'} +{/if} diff --git a/themes/default/blocks/adsl_supplier/view.tpl b/themes/default/blocks/adsl_supplier/view.tpl new file mode 100644 index 00000000..f5afa2cf --- /dev/null +++ b/themes/default/blocks/adsl_supplier/view.tpl @@ -0,0 +1,49 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/view_pre.tpl'} + + + {if $form_validation} + {$block->display('core:alert_fields')} + {/if} + + +
                    + + + + + +
                    + + + + + + + + {include file='file:../core/view_tr_submit_delete.tpl'} +
                    {osb f=tt}
                    + + + + + + + + + + + +
                    {osb f=tf field=name}
                    {osb f=tf field=status}{$list->bool('adsl_supplier_status',$record.status)}
                    +
                    +
                    + + {include file='file:../core/view_post.tpl'} +
                    +{/if} diff --git a/themes/default/blocks/asset/add.tpl b/themes/default/blocks/asset/add.tpl index 9f0b80ba..638a9a88 100644 --- a/themes/default/blocks/asset/add.tpl +++ b/themes/default/blocks/asset/add.tpl @@ -1,67 +1,46 @@ - +{assign var=meth value=':'|explode:$VAR._page} + {if $form_validation} - { $block->display("core:alert_fields") } + {$block->display('core:alert_fields')} {/if} -
                    -{$COOKIE_FORM} - - - - -
                    - - - - - - - -
                    -
                    - {translate module=asset}title_add{/translate} -
                    -
                    - - - - - - - - - - - - - - - - - -
                    - {translate module=asset} - field_pool_id - {/translate} - { $list->menu("no", "asset_pool_id", "asset_pool", "name", $VAR.asset_pool_id, "") }
                    - {translate module=asset} - field_asset - {/translate} -
                    - {translate module=asset} - field_misc - {/translate} -
                    - - - - - - -
                    -
                    -
                    + + + + + + +
                    + + + + + + + +
                    {osb f=tt}
                    + + + + + + + + + + + + + + {include file='file:../core/add_tr_submit.tpl'} +
                    {osb f=tf field=pool_id}{$list->menu('no','asset_pool_id','asset_pool','name',$VAR.asset_pool_id,'')}
                    {osb f=tf field=asset}
                    {osb f=tf field=misc}
                    +
                    +
                    + +
                    + +
                    diff --git a/themes/default/blocks/asset/search_show.tpl b/themes/default/blocks/asset/search_show.tpl index 801634b3..2e593f28 100644 --- a/themes/default/blocks/asset/search_show.tpl +++ b/themes/default/blocks/asset/search_show.tpl @@ -1,119 +1,12 @@ +{assign var=meth value=':'|explode:$VAR._page} + - -{$method->exe("asset","search_show")} -{if ($method->result == FALSE)} - {$block->display("core:method_error")} +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} {else} - {if $results == 1} - {translate results=$results}search_result_count{/translate} - {else} - {translate results=$results}search_results_count{/translate} - {/if} -
                    - - - {literal} - - - {/literal} - - -
                    - - -
                    - - - - - - -
                    - - - - - - - - - - - - {foreach from=$asset item=record} - - - - - - - - - - - {literal} - - {/literal} - {/foreach} - - -
                      - {literal} - - {/literal} - - {literal} - - {/literal} - - {literal} - - {/literal} - - {literal} - - {/literal} -
                    - -  {$list->date_time($record.date_last)} {if $record.status == "1"}{translate}true{/translate}{else}{translate}false{/translate}{/if} {$record.pool_id} {$record.asset}
                    -
                    -{if $VAR._print != TRUE}
                    -
                    - - - - - -
                    -
                    + {include file='file:../core/search_show_pre.tpl'} + {$method->exe_noauth($meth.0,'tpl_search_show',$search_show)} + {include file='file:../core/search_show_post-1.tpl'} + {include file='file:../core/search_show_post-2.tpl'} {/if} -{/if} -
                    diff --git a/themes/default/blocks/asset/view.tpl b/themes/default/blocks/asset/view.tpl index 76073db7..8e67f005 100644 --- a/themes/default/blocks/asset/view.tpl +++ b/themes/default/blocks/asset/view.tpl @@ -1,158 +1,73 @@ +{assign var=meth value=':'|explode:$VAR._page} + -{ $method->exe("asset","view") } { if ($method->result == FALSE) } { $block->display("core:method_error") } {else} +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/view_pre.tpl'} -{literal} - - -{/literal} + + {if $form_validation} + {$block->display('core:alert_fields')} + {/if} - -{foreach from=$asset item=asset} + +
                    - -{if $form_validation} - { $block->display("core:alert_fields") } -{/if} - - - -{$COOKIE_FORM} - - - - -
                    - - - - - - - -
                    -
                    - {translate module=asset}title_view{/translate} -
                    -
                    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    - {translate module=asset} - field_date_orig - {/translate} - {$list->date_time($asset.date_orig)} -
                    - {translate module=asset} - field_date_last - {/translate} - {$list->date_time($asset.date_last)} -
                    - {translate module=asset} - field_status - {/translate} - {if $asset.status == "1"}{translate}true{/translate}{else}{translate}false{/translate}{/if} -
                    - {translate module=asset} - field_service_id - {/translate} - {if $asset.service_id} - ID {$asset.service_id} - {else} - --- - {/if} -
                    - {translate module=asset} - field_pool_id - {/translate} - { $list->menu("no", "asset_pool_id", "asset_pool", "name", $asset.pool_id, "") } -
                    - {translate module=asset} - field_asset - {/translate} - -
                    - {translate module=asset} - field_misc - {/translate} - -
                    - - - - - -
                    - - - -
                    -
                    -
                    -
                    - - - - -
                    - {/foreach} + + + + +
                    + + + + + + + + {include file='file:../core/view_tr_submit_delete.tpl'} +
                    {osb f=tt}
                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                    {osb f=tf field=date_orig}{$list->date_time($record.date_orig)}
                    {osb f=tf field=date_last}{$list->date_time($record.date_last)}
                    {osb f=tf field=status}{$list->bool('',$record.status)}
                    {osb f=tf field=service_id} + {if $record.service_id} + ID {$record.service_id} + {else} + --- + {/if} +
                    {osb f=tf field=pool_id}{$list->menu('no','asset_pool_id','asset_pool','name',$record.pool_id,'')}
                    {osb f=tf field=asset}
                    {osb f=tf field=misc}
                    +
                    +
                    + + {include file='file:../core/view_post.tpl'} + {/if} diff --git a/themes/default/blocks/asset_pool/add.tpl b/themes/default/blocks/asset_pool/add.tpl index 66ee371f..1942e4bd 100644 --- a/themes/default/blocks/asset_pool/add.tpl +++ b/themes/default/blocks/asset_pool/add.tpl @@ -1,50 +1,35 @@ - +{assign var=meth value=':'|explode:$VAR._page} + {if $form_validation} - { $block->display("core:alert_fields") } + {$block->display('core:alert_fields')} {/if} -
                    -{$COOKIE_FORM} - - - - -
                    - - - - - - - -
                    -
                    - {translate module=asset_pool}title_add{/translate} -
                    -
                    - - - - - - - - - -
                    - {translate module=asset_pool} - field_name - {/translate} - -
                    - - - - -
                    -
                    -
                    + + + + + + +
                    + + + + + + + +
                    {osb f=tt}
                    + + + + + + {include file='file:../core/add_tr_submit.tpl'} +
                    {osb f=tf field=name}
                    +
                    +
                    +
                    diff --git a/themes/default/blocks/asset_pool/search_show.tpl b/themes/default/blocks/asset_pool/search_show.tpl index aef34b0d..2e593f28 100644 --- a/themes/default/blocks/asset_pool/search_show.tpl +++ b/themes/default/blocks/asset_pool/search_show.tpl @@ -1,95 +1,12 @@ +{assign var=meth value=':'|explode:$VAR._page} + - -{$method->exe("asset_pool","search_show")} -{if ($method->result == FALSE)} - {$block->display("core:method_error")} +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} {else} - {if $results == 1} - {translate results=$results}search_result_count{/translate} - {else} - {translate results=$results}search_results_count{/translate} - {/if} -
                    - - - {literal} - - - {/literal} - - -
                    - - -
                    - - - - - - -
                    - - - - - - - - - {foreach from=$asset_pool item=record} - - - - - - - - {literal} - - {/literal} - {/foreach} - - -
                      - {literal} - - {/literal} -
                    - -  {$record.name}
                    -
                    -{if $VAR._print != TRUE}
                    -
                    - - - - - -
                    -
                    + {include file='file:../core/search_show_pre.tpl'} + {$method->exe_noauth($meth.0,'tpl_search_show',$search_show)} + {include file='file:../core/search_show_post-1.tpl'} + {include file='file:../core/search_show_post-2.tpl'} {/if} -{/if} -
                    diff --git a/themes/default/blocks/asset_pool/view.tpl b/themes/default/blocks/asset_pool/view.tpl index d3e7f35e..37f86e10 100644 --- a/themes/default/blocks/asset_pool/view.tpl +++ b/themes/default/blocks/asset_pool/view.tpl @@ -1,100 +1,43 @@ +{assign var=meth value=':'|explode:$VAR._page} + -{ $method->exe("asset_pool","view") } { if ($method->result == FALSE) } { $block->display("core:method_error") } {else} +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/view_pre.tpl'} -{literal} - - -{/literal} + + {if $form_validation} + {$block->display('core:alert_fields')} + {/if} - -{foreach from=$asset_pool item=asset_pool} + +
                    - -{if $form_validation} - { $block->display("core:alert_fields") } -{/if} - - - -{$COOKIE_FORM} - - - - -
                    - - - - - - - -
                    -
                    - {translate module=asset_pool}title_view{/translate} -
                    -
                    - - - - - - - - - -
                    - {translate module=asset_pool} - field_name - {/translate} - -
                    - - - - - -
                    - - - -
                    -
                    -
                    -
                    - - - - -
                    - {/foreach} + + + + +
                    + + + + + + + + {include file='file:../core/view_tr_submit_delete.tpl'} +
                    {osb f=tt}
                    + + + + + +
                    {osb f=tf field=name}
                    +
                    +
                    + + {include file='file:../core/view_post.tpl'} + {/if} diff --git a/themes/default/blocks/cart/admin_view.tpl b/themes/default/blocks/cart/admin_view.tpl index 46da174f..17caeb04 100644 --- a/themes/default/blocks/cart/admin_view.tpl +++ b/themes/default/blocks/cart/admin_view.tpl @@ -62,7 +62,7 @@ {foreach from=$cart item=cart} -
                    +
                    {if $cart.cart_type == '2'} {include file='file:cart_table_type_2.tpl' showadmin=true} {elseif $cart.cart_type == '3'} diff --git a/themes/default/blocks/cart/cart.tpl b/themes/default/blocks/cart/cart.tpl index 3ff04af9..4ae1d9cc 100644 --- a/themes/default/blocks/cart/cart.tpl +++ b/themes/default/blocks/cart/cart.tpl @@ -52,7 +52,7 @@ {foreach from=$cart item=cart} -
                    +
                    {if $cart.cart_type == '2'} {include file='file:cart_table_type_2.tpl'} {elseif $cart.cart_type == '3'} diff --git a/themes/default/blocks/cart/cart_table_type_2.tpl b/themes/default/blocks/cart/cart_table_type_2.tpl index af3f19fa..fbcb0488 100644 --- a/themes/default/blocks/cart/cart_table_type_2.tpl +++ b/themes/default/blocks/cart/cart_table_type_2.tpl @@ -11,7 +11,7 @@ - +
                    {$cart.domain_name|upper}.{$cart.domain_tld|upper}{if $disable} {else}Remove from Cart{/if}{if $disable} {else}Remove from Cart{/if}
                    @@ -27,8 +27,8 @@ {t}Base Price{/t}
                    -
                    {$list->format_currency_num($cart.price, $smarty.const.SESS_CURRENCY)}
                    -
                    +
                    {$list->format_currency_num($cart.price, $smarty.const.SESS_CURRENCY)}
                    +
                    @@ -38,7 +38,7 @@ {/if} {if $cart.host_type == 'register'} - {foreach from=$cart.tld_arr item=tld_price key=tld_term} {/foreach} diff --git a/themes/default/blocks/cart/cart_table_type_3.tpl b/themes/default/blocks/cart/cart_table_type_3.tpl index 5ca959a5..857584d6 100644 --- a/themes/default/blocks/cart/cart_table_type_3.tpl +++ b/themes/default/blocks/cart/cart_table_type_3.tpl @@ -8,7 +8,7 @@ - + @@ -20,8 +20,8 @@ @@ -29,7 +29,7 @@ {foreach from=$discount item=discount} - {if $discount.total > 0} + {if $discounttotal > 0} @@ -221,10 +221,10 @@ {/if} {/foreach} {if $tax != false} - {foreach from=$tax item=tax } + {foreach from=$tax item=amount key=name} - - + + {/foreach} {/if} diff --git a/themes/default/blocks/core/bottom_clean.tpl b/themes/default/blocks/core/bottom_clean.tpl new file mode 100644 index 00000000..308b1d01 --- /dev/null +++ b/themes/default/blocks/core/bottom_clean.tpl @@ -0,0 +1,2 @@ + + diff --git a/themes/default/blocks/core/search.tpl b/themes/default/blocks/core/search.tpl index a09e7dc6..68bd21ed 100644 --- a/themes/default/blocks/core/search.tpl +++ b/themes/default/blocks/core/search.tpl @@ -22,7 +22,7 @@ - - - - - - - - - {foreach from=$invoice item=record} - - - - - - - - - {/foreach} - -
                    {$cart.ad_hoc_name}{if $disable} {else}Remove from Cart{/if}{if $disable} {else}Remove from Cart{/if}
                      {t}Pricing Structure{/t}: {$list->menu_staticlist('pricetype','','',0,'form_menu')}
                    {t}Base Price{/t} -
                    {$list->format_currency_num($cart.price_base, $smarty.const.SESS_CURRENCY)}
                    -
                    +
                    {$list->format_currency_num($cart.price_base, $smarty.const.SESS_CURRENCY)}
                    +
                    - +
                    Calc
                    diff --git a/themes/default/blocks/cart/cart_table_type_x.tpl b/themes/default/blocks/cart/cart_table_type_x.tpl index 7c653675..0fd1295c 100644 --- a/themes/default/blocks/cart/cart_table_type_x.tpl +++ b/themes/default/blocks/cart/cart_table_type_x.tpl @@ -8,7 +8,7 @@ - + @@ -16,7 +16,7 @@ @@ -73,7 +73,7 @@ - + diff --git a/themes/default/blocks/charge/add.tpl b/themes/default/blocks/charge/add.tpl index 76dbd31d..84f57937 100644 --- a/themes/default/blocks/charge/add.tpl +++ b/themes/default/blocks/charge/add.tpl @@ -57,6 +57,10 @@ + + + + - + + + + + + + + diff --git a/themes/default/blocks/checkout/add.tpl b/themes/default/blocks/checkout/add.tpl index 58c758e3..04f03ce2 100644 --- a/themes/default/blocks/checkout/add.tpl +++ b/themes/default/blocks/checkout/add.tpl @@ -173,7 +173,7 @@ - + {include file='file:../core/add_tr_submit.tpl'}
                    {if $list->translate('product_translate','name','product_id',$cart.product_id,'translate_product')}{/if} {$translate_product.name}{if $disable} {else}Remove from Cart{/if}{if $disable} {else}Remove from Cart{/if}
                      {t}Pricing Structure{/t}: {$list->menu_staticlist('pricetype','','',$cart.product.price_type,'form_menu')}
                    {if $cart.product.price_type == '1'}  - {foreach from=$cart.price item=price_recurr key=key}
                    {t}Base Price{/t} -
                    {$list->format_currency_num($cart.price_base, $smarty.const.SESS_CURRENCY)}
                    -
                    +
                    {$list->format_currency_num($cart.price_base, $smarty.const.SESS_CURRENCY)}
                    +
                    {t}Setup Price{/t} -
                    {$list->format_currency_num($cart.price_setup, $smarty.const.SESS_CURRENCY)}
                    -
                    +
                    {$list->format_currency_num($cart.price_setup, $smarty.const.SESS_CURRENCY)}
                    +
                    - +
                    0}disabled="disabled"{/if}/> 0}disabled="disabled"{/if}/> Calc
                    diff --git a/themes/default/blocks/cart/cart_tr_adhocdiscount.tpl b/themes/default/blocks/cart/cart_tr_adhocdiscount.tpl index 1b2a9e0c..79c036ec 100644 --- a/themes/default/blocks/cart/cart_tr_adhocdiscount.tpl +++ b/themes/default/blocks/cart/cart_tr_adhocdiscount.tpl @@ -1,4 +1,4 @@
                    Ad Hoc Discount
                    {osb f=tf field=taxable} {$list->bool('charge_taxable',$VAR.charge_taxable,'form_menu')}
                    {osb f=tf field=description}
                    {osb f=tf field=attributes} diff --git a/themes/default/blocks/charge/search_form.tpl b/themes/default/blocks/charge/search_form.tpl index 83ed8c40..74fbb25b 100644 --- a/themes/default/blocks/charge/search_form.tpl +++ b/themes/default/blocks/charge/search_form.tpl @@ -50,7 +50,10 @@ {osb f=tf field=taxable} {$list->bool('charge_taxable','all')}
                    {osb f=tf field=description}
                    {osb f=tf field=attributes} diff --git a/themes/default/blocks/charge/view.tpl b/themes/default/blocks/charge/view.tpl index aeb48f38..227c95a4 100644 --- a/themes/default/blocks/charge/view.tpl +++ b/themes/default/blocks/charge/view.tpl @@ -62,6 +62,10 @@ {osb f=tf field=taxable} {$list->bool('charge_taxable',$record.taxable,'')}
                    {osb f=tf field=description}
                    {osb f=tf field=attributes} {$record.attributes|nl2br|replace:'==':' -> '}
                    {$list->menu_multi($VAR.checkout_allowed_currencies,'checkout_allowed_currencies','currency','name','5','5','form_menu')}
                    diff --git a/themes/default/blocks/checkout/checkout.tpl b/themes/default/blocks/checkout/checkout.tpl index 1242e972..45abd69a 100644 --- a/themes/default/blocks/checkout/checkout.tpl +++ b/themes/default/blocks/checkout/checkout.tpl @@ -25,7 +25,7 @@ } function addDiscount() { var discount = document.getElementById("discount").value; - document.location='{/literal}{$SSL_URL}{literal}?_page=checkout:checkout&discount='+discount+'&do[]=checkout:adddiscount'; + document.location='{/literal}{$SSL_URL}{literal}?_page=checkout:checkout&discount='+discount+'&do[]=discount:add_cart_discount'; } {/literal} //--> @@ -213,7 +213,7 @@
                    {$list->format_currency_num($sub_total, $smarty.const.SESS_CURRENCY)}
                    {t}Discount{/t} ({$discount.name}) - {$list->format_currency_num($discount.total, $smarty.const.SESS_CURRENCY)}
                    {$tax.name}{$list->format_currency_num($tax.rate, $smarty.const.SESS_CURRENCY)}{$name}{$list->format_currency_num($amount, $smarty.const.SESS_CURRENCY)}
                    - - - - - -  
                    - - - {$record.last_name}, {$record.first_name}{$record.sid} ({$record.sku}){$record.invoice_date}
                    {$list->format_currency_num($record.price,$record.billed_currency_id)} 
                    -
                    - {if $record.billing_status == '1'} - - {else} - - {/if} - {if $record.process_status == '1'} - - {else} - - {/if} - Services - -
                    -
                    - - - - - {include file='file:../core/search_show_post-1.tpl'} - {include file='file:../core/search_show_post-2.tpl'} -{/if} diff --git a/themes/default/blocks/invoice/thankyou.tpl b/themes/default/blocks/invoice/thankyou.tpl index 93d00eaf..4d2b5f4c 100644 --- a/themes/default/blocks/invoice/thankyou.tpl +++ b/themes/default/blocks/invoice/thankyou.tpl @@ -3,24 +3,26 @@ - + diff --git a/themes/default/blocks/invoice/user_search_show.tpl b/themes/default/blocks/invoice/user_search_show.tpl index ebbdb225..72c32c2a 100644 --- a/themes/default/blocks/invoice/user_search_show.tpl +++ b/themes/default/blocks/invoice/user_search_show.tpl @@ -38,7 +38,8 @@ {include file='file:../core/user_search_show_tr_record.tpl'} - + + @@ -323,12 +135,61 @@
                    - +

                    - - + +

                    + + + diff --git a/themes/default/blocks/product/details_wizard.tpl b/themes/default/blocks/product/details_wizard.tpl index 2f084097..ebb3a0c3 100644 --- a/themes/default/blocks/product/details_wizard.tpl +++ b/themes/default/blocks/product/details_wizard.tpl @@ -1,549 +1,187 @@ -{ $method->exe("product","details") } { if ($method->result == FALSE || !$product) } { $block->display("core:method_error") } {else} -{if $product} - - - - - - - {if $list->translate("product_translate","name,description_full", "product_id", $product.id, "translate_product")} - {/if} -
                    {translate module=invoice}thank_you{/translate}{t}Thank You{/t}
                    - + - - -
                    {translate module=invoice}thank_you_text{/translate}{t}We want to take this opportunity to thank you for your purchase/invoice payment!{/t}
                    - {if $VAR.id != ''} - {translate module="invoice"}invoice_link{/translate} - {/if} + {t}From here you may{/t} +
                    {translate module="invoice"}account_link{/translate}
                    {$record.id} {$list->date_time($record.date_orig)}
                    {$list->format_currency_num($record.total_amt, $record.actual_billed_currency_id)}
                    {$list->format_currency_num($record.total_amt,$record.actual_billed_currency_id)}
                    {$list->format_currency_num($record.balance,$record.actual_billed_currency_id)}
                    {if $record.billing_status == '1'} diff --git a/themes/default/blocks/invoice/user_view.tpl b/themes/default/blocks/invoice/user_view.tpl index db640979..2626f9f4 100644 --- a/themes/default/blocks/invoice/user_view.tpl +++ b/themes/default/blocks/invoice/user_view.tpl @@ -147,6 +147,41 @@

                    + {if $record.payment_data} + + + + +
                    + + + + + + + + +
                    {t}Payments Applied{/t}
                    + + + + + + + {foreach from=$record.payment_data item=pd} + + + + + + {/foreach} +
                    {t}Payment Date{/t}{t}Payment Amount{/t}{t}Applied to this invoice{/t}
                    {$list->date($pd.date_payment)}{$list->format_currency_num($pd.total,$record.actual_billed_currency_id)}{$list->format_currency_num($pd.alloc,$record.actual_billed_currency_id)}
                    +
                    +
                    +
                    +
                    +
                    + {/if} - + - + @@ -563,7 +556,7 @@ + + + - {if $product.cart_multiple} + {if $record.cart_multiple} {/if} - {if $product.prod_plugin} - - - - {/if}
                    @@ -423,5 +458,5 @@ {/if} - {$method->exe('invoice','custom_tracking')} + {$method->exe('invoice','drCustomTracking')} {/if} diff --git a/themes/default/blocks/invoice/view.tpl b/themes/default/blocks/invoice/view.tpl index c40cf00c..6ccc67d3 100644 --- a/themes/default/blocks/invoice/view.tpl +++ b/themes/default/blocks/invoice/view.tpl @@ -18,11 +18,11 @@ elements[2] = 'affiliate'; {literal} - function approveInvoice(id,status) { - if(status.value == '1') { - document.location = '?_page=invoice:view&id='+id+'&do[]=invoice:approveInvoice'; + function pApproveVoid(id,status) { + if(status == '1') { + document.location = '?_page=invoice:view&id='+id+'&do[]=invoice:pApproveInvoice'; } else { - document.location = '?_page=invoice:view&id='+id+'&do[]=invoice:voidInvoice'; + document.location = '?_page=invoice:view&id='+id+'&do[]=invoice:pVoidInvoice'; } } @@ -32,14 +32,6 @@ document.forms.view.submit(); } - function approveInvoice(id,status,ids) { - if(status == '1') { - document.location = '?_page=invoice:view&id='+id+'&do[]=invoice:approveInvoice&ids='+ids; - } else { - document.location = '?_page=invoice:view&id='+id+'&do[]=invoice:voidInvoice&ids='+ids; - } - } - function displayArea() { {/literal} {if $VAR.area == ""} @@ -155,6 +147,7 @@ {else} {$list->format_currency_num($record.balance,$record.billed_currency_id)} ({t}Reconcile Invoice{/t}) {/if} + ({$list->format_currency_num($record.credit_amt,$record.billed_currency_id)})   @@ -198,9 +191,9 @@   {if $record.process_status == 1} - Yes ({t}Void Invoice & Services{/t}) + Yes ({t}Void Invoice & Services{/t}) {elseif $record.billing_status == 1} - No ({t}Approve Invoice & Services{/t}) + No ({t}Approve Invoice & Services{/t}) {else} {t}Pending Billing{/t} {/if} @@ -299,13 +292,13 @@ {$record.notice_count} Resend Invoice {osb f=tf field=due_date}{$list->calender_view('invoice_due_date',$record.due_date,'form_field')}{$list->calender_view('invoice_due_date',$record.due_date,'form_field','')}
                    {osb f=tf field=notice_max} {osb f=tf field=notice_next_date}{$list->calender_view('invoice_notice_next_date',$record.notice_next_date,'form_field')}{$list->calender_view('invoice_notice_next_date',$record.notice_next_date,'form_field','')}
                    {osb f=tf field=grace_period}  {if $record.type == 1 || $cart.service_id > 0}{$cart.service_id} -{/if} {$cart.sku} - {if $cart.domain_name != ''}({$cart.domain_name}. {$cart.domain_tld}){/if} + {if $cart.domain_name != ''}({$cart.domain_name}.{$cart.domain_tld}){/if} {if $cart.attribute_popup != ''} @@ -682,7 +675,7 @@ +{/if} diff --git a/themes/default/blocks/product/add.tpl b/themes/default/blocks/product/add.tpl index 8b7c7d68..0cca260a 100644 --- a/themes/default/blocks/product/add.tpl +++ b/themes/default/blocks/product/add.tpl @@ -107,5 +107,10 @@
                    + + + + +
                    diff --git a/themes/default/blocks/product/admin_details.tpl b/themes/default/blocks/product/admin_details.tpl index 527dcd9b..a81bbedb 100644 --- a/themes/default/blocks/product/admin_details.tpl +++ b/themes/default/blocks/product/admin_details.tpl @@ -7,12 +7,13 @@ {else}
                    -
                    +

                    -
                    - {if $list->translate('product_translate','name,description_full','product_id',$product.id,'translate_product')}{/if} + + + {if $list->translate('product_translate','name,description_full','product_id',$record.id,'translate_product')}{/if} @@ -27,8 +28,8 @@ - - + +
                    {$translate_product.name} 
                    {$product.sku}{if $product.cart_multiple} {t}Quantity{/t}: {/if}{$record.sku}{if $record.cart_multiple} {t}Quantity{/t}: {/if}
                    @@ -37,190 +38,38 @@ - - + +
                    {osb f=tf field=taxable}
                    {$list->menu_staticlist('pricetype','','',$product.price_type,'form_menu')}{$list->bool('',$product.taxable,'form_field')}{$list->menu_staticlist('pricetype','','',$record.price_type,'form_menu')}{$list->bool('',$record.taxable,'form_field')}
                    - {if $product.price_type == '1'} - - - - - - - -
                    {osb f=tf field=price_recurr_type}
                    - -
                    + {if $record.price_type == '1'} + {include file='file:ti_product-price_type-1.tpl'} + {elseif $record.price_type == '2'} + {include file='file:ti_product-price_type-2.tpl'} {else} - - - - - - - - - -
                    {osb f=tf field=price_base}{osb f=tf field=price_setup}
                    {$list->format_currency($price.base,$smarty.const.SESS_CURRENCY)}{$list->format_currency($price.setup,$smarty.const.SESS_CURRENCY)}
                    - {/if} - {if $product.price_type == '2'} - - - - -
                    - {translate module=product sku=$trial.sku}trial_desc{/translate}
                    - {if $product.price_trial_length_type == '0'}{translate module=product sku1=$trial.sku length=$product.price_trial_length}trial_length_days{/translate}{/if} - {if $product.price_trial_length_type == '1'}{translate module=product sku1=$trial.sku length=$product.price_trial_length}trial_length_weeks{/translate}{/if} - {if $product.price_trial_length_type == '2'}{translate module=product sku1=$trial.sku length=$product.price_trial_length}trial_length_months{/translate}{/if} -
                    - {translate module=product sku2=$trial.sku}trial_bill_desc{/translate} -
                    + {include file='file:ti_product-price_type-x.tpl'} {/if} {if $attr}
                    {foreach from=$attr item=attr_arr key=key} {assign var=attr_id value=$attr_arr.id} {if $attr_arr.type == '0'} - - - - - {if $attr_arr.description} - - - - {/if} -
                      - - - - - -
                    {$attr_arr.name} - {if $attr_arr.price_base != 0}{$list->format_currency($attr_arr.price_base, $smarty.const.SESS_CURRENCY)}{/if} - {if $attr_arr.price_setup != 0} - {if $attr_arr.price_base != 0} + {/if} - {$list->format_currency($attr_arr.price_setup,$smarty.const.SESS_CURRENCY)} - {translate module=product}setup{/translate} - {/if} -
                    -
                       {$attr_arr.description}
                    + {include file='file:ti_product_attr-collect_type-0.tpl'} {elseif $attr_arr.type == '1'} - - - - - {if $attr_arr.description} - - - - {/if} -
                      - - - - - -
                    {$attr_arr.name} - {if $attr_arr.price_base != 0}{$list->format_currency($attr_arr.price_base, $smarty.const.SESS_CURRENCY)}{/if} - {if $attr_arr.price_setup != 0} - {if $attr_arr.price_base != 0} + {/if} - {$list->format_currency($attr_arr.price_setup, $smarty.const.SESS_CURRENCY)} - {translate module=product}setup{/translate} - {/if} -
                    -
                       {$attr_arr.description}
                    + {include file='file:ti_product_attr-collect_type-1.tpl'} {elseif $attr_arr.type == '2'} - - - - - - - -
                      - - - - - -
                    {$attr_arr.name} - {if $attr_arr.price_base != 0}{$list->format_currency($attr_arr.price_base, $smarty.const.SESS_CURRENCY)}{/if} - {if $attr_arr.price_setup != 0} - {if $attr_arr.price_base != 0} + {/if} - {$list->format_currency($attr_arr.price_setup, $smarty.const.SESS_CURRENCY)} - {translate module=product}setup{/translate} - {/if} -
                    -
                    - -  {$attr_arr.description} -
                    + {include file='file:ti_product_attr-collect_type-2.tpl'} {/if} {/foreach} {/if} - {if $product.host} + {if $record.host}
                    - - - - - - - -
                      - - - - -
                    {translate module=product}domain_options{/translate}
                    -
                    - {if $product.host_allow_domain} - - {translate module=product}domain_register{/translate}
                    - - {translate module=product}domain_transfer{/translate} - {/if} -
                    - - {translate module=product}domain_ns_transfer{/translate} - {if $product.host_allow_host_only} -
                    - - {translate module=product}domain_ip{/translate}
                    - {/if} - - - - -
                    + {include file='file:ti_product_host.tpl'} {/if} - {if $product.prod_plugin} + {if $record.prod_plugin} - +
                    {osb f=plugin type=product name=$product.prod_plugin_file name_prefix=order_ data=$product.prod_plugin_data admin=true}{osb f=plugin type=product name=$record.prod_plugin_file name_prefix=order_ data=$record.prod_plugin_data admin=true}
                    {/if} @@ -228,38 +77,48 @@
                    - +
                    - + - +
                    + {if $record.price_type == '1'} + {include file='file:ti_product-price_type-1.tpl'} + {elseif $record.price_type == '2'} + {include file='file:ti_product-price_type-2.tpl'} + {else} + {include file='file:ti_product-price_type-x.tpl'} + {/if} + {if $attr} +
                    + {foreach from=$attr item=attr_arr key=key} + {assign var=attr_id value=$attr_arr.id} + {if $attr_arr.type == '0'} + {include file='file:ti_product_attr-collect_type-0.tpl'} + {elseif $attr_arr.type == '1'} + {include file='file:ti_product_attr-collect_type-1.tpl'} + {elseif $attr_arr.type == '2'} + {include file='file:ti_product_attr-collect_type-2.tpl'} + {elseif $attr_arr.type == '3'} + {include file='file:ti_product_attr-collect_type-3.tpl'} + {/if} + {/foreach} + {/if} + {if $record.host} +
                    + {include file='file:ti_product-host.tpl'} + {/if} {/if}
                    Quantity:
                    {osb f=plugin type=product name=$product.prod_plugin_file name_prefix=order_ data=$product.prod_plugin_data}
                    - - - -
                    - - - - - - - -
                    - - - - - -
                    -

                    - {if $list->translate("product_translate","name,description_short,description_full","product_id", $product.id, "prod_translate") } - {$prod_translate.name}, - {translate module=product} field_sku {/translate} "{$product.sku}" - {else} - {$product.sku} - {/if} -

                    -
                    -
                    - - - - - - - - - - - - - -
                    - - - - -
                    - {if $product.thumbnail != ""} - - {/if} - {$translate_product.description_full} -
                    -
                    - {if $product.price_type == "1" } - - - - - - - -
                    - {translate module=product} - field_price_recurr_type - {/translate} -
                    - -
                    - {else} - - - - - - - - - -
                    - {translate module=product} - field_price_base - {/translate} - - {translate module=product} - field_price_setup - {/translate} -
                    - {$list->format_currency($price.base, $smarty.const.SESS_CURRENCY)} - - {$list->format_currency($price.setup, $smarty.const.SESS_CURRENCY)} -
                    - {/if} - {if $product.price_type == "2"} - - - - -
                    - {translate module=product sku=$trial.sku} - trial_desc - {/translate} - - {translate} - view - {/translate} -
                    - {if $product.price_trial_length_type == "0"} - {translate module=product sku1=$trial.sku length=$product.price_trial_length} - trial_length_days - {/translate} - {/if} - {if $product.price_trial_length_type == "1"} - {translate module=product sku1=$trial.sku length=$product.price_trial_length} - trial_length_weeks - {/translate} - {/if} - {if $product.price_trial_length_type == "2"} - {translate module=product sku1=$trial.sku length=$product.price_trial_length} - trial_length_months - {/translate} - {/if} -
                    - {translate module=product sku2=$trial.sku} - trial_bill_desc - {/translate} -
                    - {/if} - {if $attr} -
                    - {foreach from=$attr item=attr_arr key=key} - {assign var=attr_id value=$attr_arr.id} - {if $attr_arr.type == "0"} - - - - - - - -
                    - - - - - -
                    - {$attr_arr.name} - - {if $attr_arr.price_base != 0} - {$list->format_currency_num($attr_arr.price_base, $smarty.const.SESS_CURRENCY)} - {/if} - {if $attr_arr.price_setup != 0} - {if $attr_arr.price_base != 0} - + - {/if} - {$list->format_currency_num($attr_arr.price_setup, $smarty.const.SESS_CURRENCY)} - {translate module=product} - setup - {/translate} - {/if} -
                    -
                    - -   - {$attr_arr.description} -
                    - {elseif $attr_arr.type == "1"} - - - - - - - -
                    - - - - - -
                    - {$attr_arr.name} - - {if $attr_arr.price_base != 0} - {$list->format_currency_num($attr_arr.price_base, $smarty.const.SESS_CURRENCY)} - {/if} - {if $attr_arr.price_setup != 0} - {if $attr_arr.price_base != 0} - + - {/if} - {$list->format_currency_num($attr_arr.price_setup, $smarty.const.SESS_CURRENCY)} - {translate module=product} - setup - {/translate} - {/if} -
                    -
                    - -   - {$attr_arr.description} -
                    - {elseif $attr_arr.type == "3"} - - - - - - - -
                    - - - - - -
                    - {$attr_arr.name} - - {if $attr_arr.price_base != 0} - {$list->format_currency_num($attr_arr.price_base, $smarty.const.SESS_CURRENCY)} - {/if} - {if $attr_arr.price_setup != 0} - {if $attr_arr.price_base != 0} - + - {/if} - {$list->format_currency_num($attr_arr.price_setup, $smarty.const.SESS_CURRENCY)} - {translate module=product} - setup - {/translate} - {/if} -
                    -
                    - -   - {$attr_arr.description} -
                    - {elseif $attr_arr.type == "2"} - - - - - - - -
                    - - - - - -
                    - {$attr_arr.name} -
                    -
                    - -   - {$attr_arr.description} -
                    - {/if} - {/foreach} - {/if} - {if $product.host} -
                    - - - - - - - -
                    - - - - -
                    - {translate module=product} - domain_options - {/translate} -
                    -
                    - {if $product.host_allow_domain} - - {translate module=product} - domain_register - {/translate} -
                    - - {translate module=product} - domain_transfer - {/translate} - {/if} -
                    - - {translate module=product} - domain_ns_transfer - {/translate} - {if $product.host_allow_host_only} -
                    - - {translate module=product} - domain_ip - {/translate} -
                    - {/if} - - - -
                    - {/if} - {literal} - - - {/literal} - {/if} -
                    - - - - - - - -
                    {translate module=product}wizard_finalize_purchase{/translate}
                    - {if $smarty.const.SESS_LOGGED != 1} - - - {translate module=product} - wizard_checkout_login - {/translate} -
                    - - - {translate module=product} - wizard_checkout_register - {/translate} -
                    - {else} - - {translate - module=product}wizard_checkout{/translate} - {/if} -
                    -
                    - -
                    -
                    -
                    - - -{/if} +{assign var=meth value=':'|explode:$VAR._page} + + +{$method->exe($meth.0,'details')} +{if ($method->result == false) || ! $record} + {$block->display('core:method_error')} +{else} + +
                    + + {if $list->translate('product_translate','name,description_full','product_id',$record.id,'translate_product')}{/if} + + + + +
                    + + + + + + + +
                    + + + + + +
                    + {if $translate_product.name} + {$translate_product.name} + {else} + {$record.sku} + {/if} +  
                    +
                    + + + + + {if $record.prod_plugin} + + + + {/if} + + + + + + + + + +
                    + + + + +
                    + {if $record.thumbnail != ''}{/if} + {$translate_product.description_full} +
                    +
                    {osb f=plugin type=product name=$record.prod_plugin_file name_prefix=order_ data=$record.prod_plugin_data}
                    + {if $record.price_type == '1'} + {include file='file:ti_product-price_type-1.tpl'} + {elseif $record.price_type == '2'} + {include file='file:ti_product-price_type-2.tpl'} + {else} + {include file='file:ti_product-price_type-x.tpl'} + {/if} + {if $attr} +
                    + {foreach from=$attr item=attr_arr key=key} + {assign var=attr_id value=$attr_arr.id} + {if $attr_arr.type == '0'} + {include file='file:ti_product_attr-collect_type-0.tpl'} + {elseif $attr_arr.type == '1'} + {include file='file:ti_product_attr-collect_type-1.tpl'} + {elseif $attr_arr.type == '2'} + {include file='file:ti_product_attr-collect_type-2.tpl'} + {elseif $attr_arr.type == '3'} + {include file='file:ti_product_attr-collect_type-3.tpl'} + {/if} + {/foreach} + {/if} + {if $record.host} +
                    + {include file='file:ti_product-host.tpl'} + {/if} + + + {/literal} + {/if} +
                    + + + + + + + +
                    {t}Finalise Purchase{/t}
                    + {if $smarty.const.SESS_LOGGED != 1} + {t}Login to existing client account{/t}
                    + {t}Register for new client account{/t}
                    + {else} + {t}Proceed to checkout{/t} + {/if} +
                    +
                    + +
                    +
                    +
                    + + + +
                    + + + + +
                    +
                    diff --git a/themes/default/blocks/product/iframe_hosting.tpl b/themes/default/blocks/product/iframe_hosting.tpl index 0b4234df..e7562aeb 100644 --- a/themes/default/blocks/product/iframe_hosting.tpl +++ b/themes/default/blocks/product/iframe_hosting.tpl @@ -1,148 +1,117 @@ -{ $block->display("core:top_clean") } - -{ $method->exe("product","view") } { if ($method->result == FALSE) } { $block->display("core:method_error") } {else} - +{assign var=meth value=':'|explode:$VAR._page} + - -{foreach from=$product item=product} - -{if $product.prod_plugin == "1"} -Both hosting and product plugins cannot be configured for the same product. +{$method->exe($meth.0,'view')} +{if ($method->result == false)} + {$block->display('core:method_error')} {else} + {include file='file:../core/view_pre.tpl'} -
                    - - - - -
                    - - - - - - - - - - - { if ($list->smarty_array("host_server","provision_plugin", "", "plugin")) } {foreach from=$plugin item=arr} {if $product.host_server_id == $arr.id} - - - - {/if} {/foreach} {/if} - - - -
                    - - - - - - - - - -
                    - {translate module=product} - field_host - {/translate} - - { $list->bool("product_host", $product.host, "onchange=\"submit();\"") } -
                    - {translate module=product} - field_host_server_id - {/translate} - - { $list->menu("no", "product_host_server_id", "host_server", "name", $product.host_server_id, "\" onchange=\"document.product_view.submit();") } -
                    -
                    - - - - - - - - - -
                    - {translate module=product} - field_host_allow_domain - {/translate} - - {if $product.host_allow_domain == ""} - { $list->bool("product_host_allow_domain", "1", "form_menu") } - {else} - { $list->bool("product_host_allow_domain", $product.host_allow_domain, "form_menu") } - {/if} -
                    - {translate module=product} - field_host_allow_host_only - {/translate} - - {if $product.host_allow_host_only != ""} - { $list->bool("product_host_allow_host_only", $product.host_allow_host_only, "form_menu") } - {else} - { $list->bool("product_host_allow_host_only", "0", "form_menu") } - {/if} -
                    -
                    - - - - - - - - - -
                    - {translate module=product} - field_host_discount_tld - {/translate} - - {translate module=product} - field_host_discount_tld_amount - {/translate} -
                    - { $list->menu_multi($product.host_discount_tld, "product_host_discount_tld", "host_tld", "name", "5", "5", "form_menu") } - - - (example: 0.10 = 10%)
                    -
                    - {assign var="afile" value=$arr.provision_plugin} - {assign var="ablock" value="host_provision_plugin:plugin_prod_"} - {assign var="blockfile" value="$ablock$afile"} - { $block->display($blockfile) } -
                    - - - - -
                    - -
                    -
                    -
                    - - - - - - - - - - - - - - - - -
                    -{/if} -{/foreach} + {if $record.prod_plugin == '1'} + {t}Both hosting and product plugins cannot be configured for the same product.{/t} + {else} + +
                    + + + + + +
                    + + + + + + + + + + + {if ($list->smarty_array('host_server','provision_plugin','','plugin'))} + {foreach from=$plugin item=arr} + {if $record.host_server_id == $arr.id} + + + + {/if} + {/foreach} + {/if} + + + +
                    + + + + + + + + + +
                    {osb f=tf field=host}{$list->bool('product_host',$record.host,'" onchange="submit();')}
                    {osb f=tf field=host_server_id}{$list->menu('no','product_host_server_id','host_server','name',$record.host_server_id,'" onchange="document.product_view.submit();')}
                    +
                    + + + + + + + + + +
                    {osb f=tf field=host_allow_domain} + {if $record.host_allow_domain == ''} + {$list->bool('product_host_allow_domain','1','form_menu')} + {else} + {$list->bool('product_host_allow_domain',$record.host_allow_domain,'form_menu')} + {/if} +
                    {osb f=tf field=host_allow_host_only} + {if $record.host_allow_host_only != ''} + {$list->bool('product_host_allow_host_only',$record.host_allow_host_only,'form_menu')} + {else} + {$list->bool('product_host_allow_host_only','0','form_menu')} + {/if} +
                    +
                    + + + + + + + + + +
                    {osb f=tf field=host_discount_tld}{osb f=tf field=host_discount_tld_amount}
                    {$list->menu_multi($record.host_discount_tld,'product_host_discount_tld','host_tld','name','5','5','form_menu')} (example: 0.10 = 10%)
                    +
                    + {assign var="afile" value=$arr.provision_plugin} + {assign var="ablock" value="host_provision_plugin:plugin_prod_"} + {assign var="blockfile" value="$ablock$afile"} + {$block->display($blockfile)} +
                    + + + {include file='file:../core/view_td_submit.tpl'} + +
                    +
                    +
                    + + {include file='file:../core/view_post.tpl'} +
                    + + + + + + + + + + +
                    +
                    + {/if} {/if} diff --git a/themes/default/blocks/product/iframe_plugins.tpl b/themes/default/blocks/product/iframe_plugins.tpl index 781e8be2..f7c4b529 100644 --- a/themes/default/blocks/product/iframe_plugins.tpl +++ b/themes/default/blocks/product/iframe_plugins.tpl @@ -1,83 +1,75 @@ -{ $block->display("core:top_clean") } - -{ $method->exe("product","view") } { if ($method->result == FALSE) } { $block->display("core:method_error") } {else} - +{assign var=meth value=':'|explode:$VAR._page} + - -{foreach from=$product item=product} - -{if $product.host == "1"} -Both hosting and product plugins cannot be configured for the same product. +{$method->exe($meth.0,'view')} +{if ($method->result == false)} + {$block->display('core:method_error')} {else} + {include file='file:../core/view_pre.tpl'} -
                    - - - - -
                    - - - - - { if $product.prod_plugin_file != ""} - - - - {/if} - - - -
                    - - - - - - - - - -
                    Enable Product Plugins? - { $list->bool("product_prod_plugin", $product.prod_plugin, "onchange=\"submit();\"") } -
                    Plugin to Enable - { $list->menu_files("", "product_prod_plugin_file", $product.prod_plugin_file, "product", "", ".php", "\" onchange=\"document.product_view.submit();") } -
                    -
                    - {assign var="afile" value=$product.prod_plugin_file} - {assign var="ablock" value="product_plugin:plugin_prod_"} - {assign var="blockfile" value="$ablock$afile"} - { $block->display($blockfile) } -
                    - - - - -
                    - -
                    -
                    -
                    - - - - - - - - - - - - - - - - - - -
                    + {if $record.host == '1'} + {t}Both hosting and product plugins cannot be configured for the same product.{/t} + {else} + +
                    -{/if} -{/foreach} + + + + +
                    + + + + + {if $record.prod_plugin && $record.prod_plugin_file != ''} + + + + {/if} + + + +
                    + + + + + + + + + +
                    {t}Enable Product Plugins?{/t}{$list->bool('product_prod_plugin',$record.prod_plugin,'" onchange="submit();')}
                    {t}Plugin to Enable{/t}{$list->menu_files('','product_prod_plugin_file',$record.prod_plugin_file,'product','','.php','" onchange="submit();')}
                    +
                    + {assign var="afile" value=$record.prod_plugin_file} + {assign var="ablock" value="product_plugin:plugin_prod_"} + {assign var="blockfile" value="$ablock$afile"} + {$block->display($blockfile)} +
                    + + + {include file='file:../core/view_td_submit.tpl'} + +
                    +
                    +
                    + + {include file='file:../core/view_post.tpl'} +
                    + + + + + + + + + + + + +
                    +
                    + {/if} {/if} diff --git a/themes/default/blocks/product/product.js b/themes/default/blocks/product/product.js new file mode 100644 index 00000000..ee823591 --- /dev/null +++ b/themes/default/blocks/product/product.js @@ -0,0 +1,49 @@ +function addCart(addtype,hosting) { + if (hosting == '1') { + var domain_option = document.getElementById('domain_option').value; + var domain_name = document.getElementById('domain_name').value; + var domain_tld = document.getElementById('domain_tld').value; + + if (domain_option == '0') { + //@todo To Translate + alert("You must choose a 'Domain Transfer / Registration Option' to continue."); + return; + } + + if ((domain_name == '0' || domain_tld == '0') && (domain_option != 'ip')) { + //@todo To Translate + alert("You must select a valid domain name to continue."); + return; + } + } + + attrValidate(addtype); +} + +function doCart(addtype) { + form = document.getElementById('view'); + + switch(addtype) { + case 'cart': + //document.getElementById('page').value = 'cart:admin_view'; + document.getElementById('page').value = 'cart:cart'; + break; + + case 'login': + if (document.getElementById('wiz_username').value == '') + return; + if (document.getElementById('wiz_password').value == '') + return; + + case 'register': + case 'checkout': + document.getElementById('page').value = 'checkout:checkout'; + break; + + default: + alert('Unknown addtype: '+addtype); + } + + form.action = ''; + form.submit(); +} diff --git a/themes/default/blocks/product/ti_product-host.tpl b/themes/default/blocks/product/ti_product-host.tpl new file mode 100644 index 00000000..e1bebe5c --- /dev/null +++ b/themes/default/blocks/product/ti_product-host.tpl @@ -0,0 +1,32 @@ + + + + + + + + + + +
                    + + + + +
                    {t}Domain Transfer / Registrations Options{/t}
                    +
                    + {if $record.host_allow_domain} + {t}Register new domain name{/t}
                    + {t}Transfer existing domain name{/t}
                    + {/if} + {t}I will use an existing domain name and update my nameservers only.{/t} + {if $record.host_allow_host_only} +
                    + {t}All I need is an IP based hosting plan.{/t}
                    + {/if} + + + +
                    +
                    + diff --git a/themes/default/blocks/product/ti_product-price_type-1.tpl b/themes/default/blocks/product/ti_product-price_type-1.tpl new file mode 100644 index 00000000..ce9f985f --- /dev/null +++ b/themes/default/blocks/product/ti_product-price_type-1.tpl @@ -0,0 +1,21 @@ + + + + + + + + + +
                    {osb f=tf field=price_recurr_type}
                    + +
                    + diff --git a/themes/default/blocks/product/ti_product-price_type-2.tpl b/themes/default/blocks/product/ti_product-price_type-2.tpl new file mode 100644 index 00000000..5d58d31a --- /dev/null +++ b/themes/default/blocks/product/ti_product-price_type-2.tpl @@ -0,0 +1,17 @@ + + + + + + +
                    + {t 1=$trial.sku}This product is a trial for SKU %1, which can be viewed in detail here:{/t} + {$trial.sku}
                    + {if $record.price_trial_length_type == '0'}{assign var=time value='days'} + {elseif $record.price_trial_length_type == '1'}{assign var=time value='weeks'} + {elseif $record.price_trial_length_type == '2'}{assign var=time value='months'} + {/if} + {t 1=$trial.sku 2=$record.price_trial_length 3=$time}This trial will last for %2 %3 before it expires and you are billed for the full cost of SKU %1.{/t}
                    + {t 1=$trial.sku}If you wish to cancel prior to the trial expiring, you may do so and you will not be billed for SKU %1.{/t} +
                    + diff --git a/themes/default/blocks/product/ti_product-price_type-x.tpl b/themes/default/blocks/product/ti_product-price_type-x.tpl new file mode 100644 index 00000000..c5fbfa72 --- /dev/null +++ b/themes/default/blocks/product/ti_product-price_type-x.tpl @@ -0,0 +1,13 @@ + + + + + + + + + + + +
                    {osb f=tf field=price_base}{osb f=tf field=price_setup}
                    {$list->format_currency($record.price_base,$smarty.const.SESS_CURRENCY)}{$list->format_currency($record.price_setup,$smarty.const.SESS_CURRENCY)}
                    + diff --git a/themes/default/blocks/product/ti_product_attr-collect_type-0.tpl b/themes/default/blocks/product/ti_product_attr-collect_type-0.tpl new file mode 100644 index 00000000..f5c211e4 --- /dev/null +++ b/themes/default/blocks/product/ti_product_attr-collect_type-0.tpl @@ -0,0 +1,25 @@ + + + + + + + + + +
                    + + + + + +
                    {$attr_arr.name} + {if $attr_arr.price_base != 0}{$list->format_currency_num($attr_arr.price_base, $smarty.const.SESS_CURRENCY)}{/if} + {if $attr_arr.price_setup != 0} + {if $attr_arr.price_base != 0} + {/if} + {$list->format_currency_num($attr_arr.price_setup, $smarty.const.SESS_CURRENCY)} + {t}Setup{/t} + {/if} +
                    +
                    {$attr_arr.description}
                    + diff --git a/themes/default/blocks/product/ti_product_attr-collect_type-1.tpl b/themes/default/blocks/product/ti_product_attr-collect_type-1.tpl new file mode 100644 index 00000000..13a7d219 --- /dev/null +++ b/themes/default/blocks/product/ti_product_attr-collect_type-1.tpl @@ -0,0 +1,25 @@ + + + + + + + + + +
                    + + + + + +
                    {$attr_arr.name} + {if $attr_arr.price_base != 0}{$list->format_currency_num($attr_arr.price_base, $smarty.const.SESS_CURRENCY)}{/if} + {if $attr_arr.price_setup != 0} + {if $attr_arr.price_base != 0} + {/if} + {$list->format_currency_num($attr_arr.price_setup, $smarty.const.SESS_CURRENCY)} + {t}Setup{/t} + {/if} +
                    +
                    {$attr_arr.description}
                    + diff --git a/themes/default/blocks/product/ti_product_attr-collect_type-2.tpl b/themes/default/blocks/product/ti_product_attr-collect_type-2.tpl new file mode 100644 index 00000000..6d1636f0 --- /dev/null +++ b/themes/default/blocks/product/ti_product_attr-collect_type-2.tpl @@ -0,0 +1,33 @@ + + + + + + + + + +
                    + + + + + +
                    {$attr_arr.name} 
                    +
                    + + {$attr_arr.description} +
                    + diff --git a/themes/default/blocks/product/ti_product_attr-collect_type-3.tpl b/themes/default/blocks/product/ti_product_attr-collect_type-3.tpl new file mode 100644 index 00000000..99877bed --- /dev/null +++ b/themes/default/blocks/product/ti_product_attr-collect_type-3.tpl @@ -0,0 +1,25 @@ + + + + + + + + + +
                    + + + + + +
                    {$attr_arr.name} + {if $attr_arr.price_base != 0}{$list->format_currency_num($attr_arr.price_base, $smarty.const.SESS_CURRENCY)}{/if} + {if $attr_arr.price_setup != 0} + {if $attr_arr.price_base != 0} + {/if} + {$list->format_currency_num($attr_arr.price_setup, $smarty.const.SESS_CURRENCY)} + {t}Setup{/t} + {/if} +
                    +
                     {$attr_arr.description}
                    + diff --git a/themes/default/blocks/product/view.tpl b/themes/default/blocks/product/view.tpl index 044b0dcf..0ed32b7b 100644 --- a/themes/default/blocks/product/view.tpl +++ b/themes/default/blocks/product/view.tpl @@ -26,143 +26,135 @@ - - + + - - + +
                    {osb f=tf field=date_orig}{osb f=tf field=date_last}{osb f=tf field=date_orig}{osb f=tf field=date_last}
                    {$list->date($record.date_orig)}{$list->date($record.date_last)}{$list->date($record.date_orig)}{$list->date($record.date_last)}
                    - + - - + + - - + +
                    {osb f=tf field=sku}{osb f=tf field=position}{osb f=tf field=sku}{osb f=tf field=position}
                    - + - - + + - - + +
                    {osb f=tf field=active}{osb f=tf field=taxable}{osb f=tf field=active}{osb f=tf field=taxable}
                    {$list->bool('product_active',$record.active)}{$list->bool('product_taxable',$record.taxable)}{$list->bool('product_active',$record.active)}{$list->bool('product_taxable',$record.taxable)}
                    - + - - + + - - + +
                    {osb f=tf field=price_base}{osb f=tf field=price_setup}{osb f=tf field=price_base}{osb f=tf field=price_setup}
                    {$list->currency_iso('')}{$list->currency_iso('')}{$list->currency_iso('')}{$list->currency_iso('')}
                    - + - - + + - - + +
                    {osb f=tf field=avail_category_id}
                    {osb f=tf field=group_avail}{osb f=tf field=avail_category_id}
                    {osb f=tf field=group_avail}
                    {$method->exe_noauth('product_cat','tpl_admin_menu_product')}{$list->menu_multi($record.group_avail,'product_group_avail','group','name','','5','form_menu')}{$method->exe_noauth('product_cat','tpl_admin_menu_product')}{$list->menu_multi($record.group_avail,'product_group_avail','group','name','','5','form_menu')}
                    {if $record.price_type == '1'} - - - - - - - - - - - - - - - -
                    {osb f=tf field=price_recurr_default}{$list->menu_staticlist('recur_schedule','product_price_recurr_default','product_price_recurr_default',$product.price_recurr_default,'form_menu',false)}
                    {osb f=tf field=price_recurr_type}{t}Options Available to Subscribers{/t}
                    - - {$list->menu_staticlist('recur_type','','product_price_recurr_type',0,'form_menu',false)}
                    - - {$list->menu_staticlist('recur_type','','product_price_recurr_type',1,'form_menu',false)}
                    - - (1-28) - {osb f=tf field=price_recurr_weekday} -
                    - {$list->bool('product_price_recurr_schedule',$record.price_recurr_schedule)} - {osb f=tf field=price_recurr_schedule} -
                    - {$list->bool('product_price_recurr_cancel',$record.price_recurr_cancel)} - {osb f=tf field=price_recurr_cancel} -
                    - {$list->bool('product_cart_multiple',$record.cart_multiple)} - {osb f=tf field=cart_multiple} -
                    - - - {/if} - {if $record.price_type == '2'} - - - - - - - - - - - -
                    {osb f=tf field=price_trial_prod}{osb f=tf field=price_trial_length}
                    {$list->menu('','product_price_trial_prod','product','sku',$record.price_trial_prod,'form_menu')} - - -
                    - - + + + + + + + + + + + + + + + +
                    {osb f=tf field=price_recurr_default}{$list->menu_staticlist('recur_schedule','product_price_recurr_default','product_price_recurr_default',$record.price_recurr_default,'form_menu',false)}
                    {osb f=tf field=price_recurr_type}{t}Options Available to Subscribers{/t}
                    + + {$list->menu_staticlist('recur_type','','product_price_recurr_type',0,'form_menu',false)}
                    + + {$list->menu_staticlist('recur_type','','product_price_recurr_type',1,'form_menu',false)}
                    + + (1-28) + {osb f=tf field=price_recurr_weekday} +
                    + {$list->bool('product_price_recurr_schedule',$record.price_recurr_schedule)} + {osb f=tf field=price_recurr_schedule} +
                    + {$list->bool('product_price_recurr_cancel',$record.price_recurr_cancel)} + {osb f=tf field=price_recurr_cancel} +
                    + {$list->bool('product_cart_multiple',$record.cart_multiple)} + {osb f=tf field=cart_multiple} +
                    + + + {elseif $record.price_type == '2'} + + + + + + + + + + + +
                    {osb f=tf field=price_trial_prod}{osb f=tf field=price_trial_length}
                    {$list->menu('','product_price_trial_prod','product','sku',$record.price_trial_prod,'form_menu')} {$list->menu_staticlist('trial_length','product_price_trial_length_type','product_price_trial_length_type',$record.price_trial_length_type,'form_menu',false)}
                    + + {/if} - + - -
                    + {if $record.thumbnail != ''} {/if} {osb f=tf field=thumbnail} + {if $record.thumbnail != ''} @@ -174,18 +166,12 @@
                    - + {include file='file:../core/view_tr_submit_delete.tpl'} + - - {include file='file:../core/view_tr_submit_delete.tpl'} -
                    - - - - - - {include file='file:../core/view_tr_submit_delete.tpl'}
                    + {t}Name & Description{/t} | @@ -232,11 +218,13 @@ {literal} function viewTranslations(product_id,language_id) { - document.getElementById("code").innerHTML = ''; - var product_id = {/literal}{$record.id}{literal}; - var language_id = {/literal}'{$smarty.const.DEFAULT_LANGUAGE}'{literal}; - var url = '?_page=core:search_iframe&module=product_translate&product_translate_language_id='+language_id+'&product_translate_product_id='+product_id+'&_escape=1&_escape_next=1&_next_page_one=view&_next_page_none=add&name_id1=product_translate_product_id&val_id1='+product_id+'&name_id2=product_translate_language_id&val_id2='+language_id; + {/literal} + document.getElementById('code').innerHTML = ''; + var product_id = {$record.id}; + var language_id = '{$smarty.const.DEFAULT_LANGUAGE}'; + var url = '?_page=core:search_iframe&module=product_translate&product_translate_language_id='+language_id+'&product_translate_product_id='+product_id+'&_next_page_one=view&_next_page_none=add&name_id1=product_translate_product_id&val_id1='+product_id+'&name_id2=product_translate_language_id&val_id2='+language_id; showIFrame('iframe',getPageWidth(600),300,url); + {literal} } viewTranslations(); @@ -280,12 +268,12 @@ function showHosting() { document.getElementById('code').innerHTML = ''; - showIFrame('iframe',getPageWidth(600),300,'?_page=product:iframe_hosting&_escape=1&id='+product_id); + showIFrame('iframe',getPageWidth(600),300,'?_page=product:iframe_hosting&id='+product_id); } function showPlugins() { document.getElementById('code').innerHTML = ''; - showIFrame('iframe',getPageWidth(600),300,'?_page=product:iframe_plugins&_escape=1&id='+product_id); + showIFrame('iframe',getPageWidth(600),300,'?_page=product:iframe_plugins&id='+product_id); } function clone() { diff --git a/themes/default/blocks/product_attr/view.tpl b/themes/default/blocks/product_attr/view.tpl index bfa24db2..c709683f 100644 --- a/themes/default/blocks/product_attr/view.tpl +++ b/themes/default/blocks/product_attr/view.tpl @@ -44,7 +44,7 @@
                    - + {translate module=product_attr}type_checkbox{/translate}
                    {translate module=product_attr}type_text{/translate}
                    diff --git a/themes/default/blocks/product_cat/view.tpl b/themes/default/blocks/product_cat/view.tpl index a256d29a..1ad1ac44 100644 --- a/themes/default/blocks/product_cat/view.tpl +++ b/themes/default/blocks/product_cat/view.tpl @@ -81,10 +81,10 @@ {/if}
                    + {include file='file:../core/view_tr_submit_delete.tpl'} diff --git a/themes/default/blocks/product_plugin/plugin_order_ADSL.tpl b/themes/default/blocks/product_plugin/plugin_order_ADSL.tpl new file mode 100644 index 00000000..bbfeb431 --- /dev/null +++ b/themes/default/blocks/product_plugin/plugin_order_ADSL.tpl @@ -0,0 +1,122 @@ + + +{$list->unserial($record.prod_plugin_data,'plugin_data')} + + +
                    + + + +
                    + + + + + + + + + + + + + + + + + + + + + + {assign var='sid' value=$plugin_data.supplier_product} + {if $list->smarty_array('adsl','offpeak_start,offpeak_end'," AND id=$sid",'supplier') && $supplier.0.offpeak_start && $supplier.0.offpeak_end} + + + + + + + + {/if} + + + + + + + + + + + + + {if $plugin_data.extra_charged} + + {else} + + {/if} + + {if $supplier && $supplier.0.offpeak_start && $supplier.0.offpeak_end} + + + + + {/if} + {if $plugin_data.contract_term} + + + + + {/if} +
                    ADSL Inclusions
                    ADSL Data
                     DownloadsExcess/GBUploadsExcess/GB
                    Peak{$plugin_data.base_down_peak}{$list->format_currency_num($plugin_data.extra_down_peak,$smarty.const.SESS_CURRENCY)}{$plugin_data.base_up_peak}{$list->format_currency_num($plugin_data.extra_up_peak,$smarty.const.SESS_CURRENCY)}
                    Off Peak{$plugin_data.base_down_offpeak}{$list->format_currency_num($plugin_data.extra_down_offpeak,$smarty.const.SESS_CURRENCY)}{$plugin_data.base_up_offpeak}{$list->format_currency_num($plugin_data.extra_up_offpeak,$smarty.const.SESS_CURRENCY)}
                     
                    ADSL Extra Information
                    {t}Static IP address{/t}{if $plugin_data.staticip}{t}Included{/t}{else}{t}No{/t}{/if}
                    {t}Extra Traffic Charged{/t}{t}Yes{/t} ({t}See the table above{/t}){t}No{/t} {if $plugin_data.extra_shape}({t}Your service will be shapped to{/t} {$plugin_data.extra_shape}){/if}
                    {t}Offpeak Period{/t}{$list->time($supplier.0.offpeak_start)} - {$list->time($supplier.0.offpeak_end)}
                    {t}Contract Term{/t}{$plugin_data.contract_term} {t}Months{/t}
                    +
                    +
                    + + + + + +
                    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                    ADSL Service Number
                    ADSL Service Address
                    Do you have an ADSL service connected, already?
                    Requested CHURN date
                    Have you viewed and accepted the terms and conditions?
                    +
                    diff --git a/themes/default/blocks/product_plugin/plugin_prod_ADSL.tpl b/themes/default/blocks/product_plugin/plugin_prod_ADSL.tpl new file mode 100644 index 00000000..b478d74b --- /dev/null +++ b/themes/default/blocks/product_plugin/plugin_prod_ADSL.tpl @@ -0,0 +1,131 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$list->unserial($record.prod_plugin_data,'plugin_data')} +{$list->unserial($record.prod_attr,'prod_attr')} + +{if $meth.0 == 'service'} + + + + +
                    + + + + + + + + + + + + + +
                    {t}Service Number{/t}{assign var=key value='Service Phone Number'}{t}Service Account Name{/t}{assign var=key value='Service Phone Name'}
                    {t}Contact End Date{/t}{assign var=key value='Contract End Date'}{t}Service Address{/t}{assign var=key value='Service Address'}
                    +
                    +{/if} + + + {if $meth.0 == 'service'} + + + + + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                    {t}Override Product Details{/t}{$plugin_data.override}
                    {osb f=tf field=supplier_product}{$list->menu('no','product_prod_plugin_data[supplier_product]','adsl','product_desc',$plugin_data.supplier_product,'')}{osb f=tf field=contract_term}
                    {osb f=tf field=churnable}{osb f=tf field=churnsetup_discount}
                    {osb f=tf field=staticip}
                    {osb f=tf field=product_base_down_peak}{osb f=tf field=product_base_up_peak}
                    {osb f=tf field=product_base_down_offpeak}{osb f=tf field=product_base_up_offpeak}
                    {osb f=tf field=product_extra_charged}{$list->bool('product_prod_plugin_data[extra_charged]',$plugin_data.extra_charged,'form_menu')}{osb f=tf field=product_extra_shape}
                    {osb f=tf field=product_extra_down_peak}{osb f=tf field=product_extra_up_peak}
                    {osb f=tf field=product_extra_down_offpeak}{osb f=tf field=product_extra_up_offpeak}
                    + + diff --git a/themes/default/blocks/product_plugin/plugin_prod_ASSET.tpl b/themes/default/blocks/product_plugin/plugin_prod_ASSET.tpl index 281cf955..4bbbce53 100644 --- a/themes/default/blocks/product_plugin/plugin_prod_ASSET.tpl +++ b/themes/default/blocks/product_plugin/plugin_prod_ASSET.tpl @@ -1,4 +1,4 @@ -{$list->unserial($product.prod_plugin_data, "plugin_data")} +{$list->unserial($record.prod_plugin_data,'plugin_data')} {if $service.id} diff --git a/themes/default/blocks/product_plugin/plugin_view_ADSL.tpl b/themes/default/blocks/product_plugin/plugin_view_ADSL.tpl new file mode 100644 index 00000000..a55ee63b --- /dev/null +++ b/themes/default/blocks/product_plugin/plugin_view_ADSL.tpl @@ -0,0 +1,78 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$list->unserial($record.prod_plugin_data,'plugin_data')} +{$list->unserial($record.prod_attr,'prod_attr')} + +
                    + + + +
                    + + + + + + + + + + + + + +
                    {t}Service Number{/t}{$prod_attr.service_number}{t}Service Account Name{/t}{$prod_attr.service_account_name}
                    {t}Contact End Date{/t}{$prod_attr.contract_end_date}{t}Service Address{/t}{$prod_attr.service_address}
                    +
                    + + + + {assign var="pid" value=$record.product_id} + {if ($list->smarty_array('product_translate','description_short'," AND product_id=$pid ",'product'))} + + + + + {/if} + {if $meth.1 != 'user_view'} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/if} +
                    {osb f=tf field=product}{$product.0.description_short}
                    {osb f=tf field=contract_term}{$plugin_data.contract_term}{osb f=tf field=staticip}{$list->bool('',$plugin_data.staticip,'')}
                    {osb f=tf field=product_base_down_peak}{$plugin_data.base_down_peak}{osb f=tf field=product_base_up_peak}{$plugin_data.base_up_peak}
                    {osb f=tf field=product_base_down_offpeak}{$plugin_data.base_down_offpeak}{osb f=tf field=product_base_up_offpeak}{$plugin_data.base_up_offpeak}
                    {osb f=tf field=product_extra_charged}{$list->bool('',$plugin_data.extra_charged,'')}{osb f=tf field=product_extra_shape}{$plugin_data.extra_shape}
                    {osb f=tf field=product_extra_down_peak}{$plugin_data.extra_down_peak}{osb f=tf field=product_extra_up_peak}{$plugin_data.extra_up_peak}
                    {osb f=tf field=product_extra_down_offpeak}{$plugin_data.extra_down_offpeak}{osb f=tf field=product_extra_up_offpeak}{$plugin_data.extra_up_offpeak}
                    diff --git a/themes/default/blocks/product_translate/add.tpl b/themes/default/blocks/product_translate/add.tpl index 5d42afe4..0e9af4d6 100644 --- a/themes/default/blocks/product_translate/add.tpl +++ b/themes/default/blocks/product_translate/add.tpl @@ -1,78 +1,70 @@ -{ $block->display("core:top_clean") } - +{assign var=meth value=':'|explode:$VAR._page} + + {if $form_validation} - { $block->display("core:alert_fields") } + {$block->display('core:alert_fields')} {/if} + + + +
                    - - - -
                    - - - - -
                    - - - - - - - - - - - - - - - - - - - - - -
                    - {translate module=product_translate} - field_name - {/translate} - - -
                    - {translate module=product_translate} - field_description_short - {/translate} - - -
                    - {translate module=product_translate} - field_description_full - {/translate} - - -
                    - {translate module=product_translate} - field_email_template - {/translate} - - -
                    - - - - - - - - -
                    -
                    -
                    -
                    + + + + + + +
                    + + + + + + + + + + + + + + + + + + + + + + +
                    {osb f=tf field=name}
                    {osb f=tf field=description_short}
                    {osb f=tf field=description_full}
                    {osb f=tf field=email_template}
                      + + + + + +
                    +
                    + + + + +
                    + + + {if $VAR._escape} + + {/if} +
                    + diff --git a/themes/default/blocks/product_translate/edit.tpl b/themes/default/blocks/product_translate/edit.tpl index 711ef497..bff9308d 100644 --- a/themes/default/blocks/product_translate/edit.tpl +++ b/themes/default/blocks/product_translate/edit.tpl @@ -1,121 +1,89 @@ -{ $block->display("core:top_clean") } +{$block->display('core:top_clean')} -{literal} - - -{/literal} +{assign var=meth value=':'|explode:$VAR._page} + -{ $method->exe("product_translate","view") } { if ($method->result == FALSE) } { $block->display("core:method_error") } {else} +{$method->exe($meth.0,'view')} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/view_pre.tpl'} - -{foreach from=$product_translate item=product_translate} - - -{if $form_validation} -{ $block->display("core:alert_fields") } + + {if $form_validation} + {$block->display('core:alert_fields')} + {/if} + + + + + + +
                    + + + + + +
                    + + + + + + + +
                    + + + + + + + + + +
                    {osb f=tf field=name}
                    {osb f=tf field=description_short}
                    +
                    + + + + + + + + + + +
                     
                    {osb f=tf field=description_full}
                    +
                    + + + + + + + +
                    {osb f=tf field=email_template}
                    +
                    + + + + + +
                    +
                    +
                    + +
                    + + + + + + +
                    +
                    {/if} - -
                    - - - - -
                    - - - - -
                    - - - - - - - - - -
                    - {translate module=product_translate} - field_name - {/translate} - - -
                    - {translate module=product_translate} - field_email_template - {/translate} -
                    -
                    - -
                    - -
                    -
                    - - - - - - - - - - - - - - - - -
                    - {translate module=product_translate} - field_description_short - {/translate} -
                    - -
                     
                    - {translate module=product_translate} - field_description_full - {/translate} -
                    - -
                    - - - - -
                    - -
                    -
                    -
                    - - - - - - -
                    - {/foreach} -{/if} +{$block->display('core:bottom_clean')} diff --git a/themes/default/blocks/product_translate/search_show.tpl b/themes/default/blocks/product_translate/search_show.tpl index 12eb2d7b..2e593f28 100644 --- a/themes/default/blocks/product_translate/search_show.tpl +++ b/themes/default/blocks/product_translate/search_show.tpl @@ -1,81 +1,12 @@ -{ $block->display("core:top_clean") } +{assign var=meth value=':'|explode:$VAR._page} + -{$method->exe("product_translate","search_show")} -{if ($method->result == FALSE)} - {$block->display("core:method_error")} +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} {else} - - - {literal} - - - {/literal} - - -
                    - - -
                    - - - - - - -
                    - - - - - {foreach from=$product_translate item=record} - - - - - - - - - - - {literal} - - {/literal} - {/foreach} - - -
                    - -   - {$record.language_id} -   - {$record.product_id} -  {$record.name}
                    -
                    -
                    -
                    - - - - - -
                    -
                    - + {include file='file:../core/search_show_pre.tpl'} + {$method->exe_noauth($meth.0,'tpl_search_show',$search_show)} + {include file='file:../core/search_show_post-1.tpl'} + {include file='file:../core/search_show_post-2.tpl'} {/if} -
                    diff --git a/themes/default/blocks/product_translate/view.tpl b/themes/default/blocks/product_translate/view.tpl index 88c4cc51..66700da3 100644 --- a/themes/default/blocks/product_translate/view.tpl +++ b/themes/default/blocks/product_translate/view.tpl @@ -1,28 +1,34 @@ -{ $block->display("core:top_clean") } +{assign var=meth value=':'|explode:$VAR._page} + -{ $method->exe("product_translate","view") } { if ($method->result == FALSE) } { $block->display("core:method_error") } {else} +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/view_pre.tpl'} -{literal}{/literal} +
                    @@ -37,98 +43,52 @@ function viewTranslations(product_id) - - - -
                    - { $list->menu_files("1", "language_id", $smarty.const.DEFAULT_LANGUAGE, "language", "", "_core.xml", "\" onChange=\"viewTranslations(`$product_translate.product_id`);") } - Edit -
                    - - - - - - - - - - - - - -
                    - {translate module=product_translate} - field_name - {/translate} -
                    - - - - - -
                      - {$product_translate.name} -
                    -
                    - - - - - - - - - - - - - - -
                    - {translate module=product_translate} - field_description_short - {/translate} -
                    - - - - - -
                      - {$product_translate.description_short} -
                    -
                    - - - - - - - - - - - -
                    - {translate module=product_translate} - field_description_full - {/translate} -
                    - - - - - -
                      - {$product_translate.description_full} -
                    -
                    - - - - - - -
                    + + {$list->menu_files('','language_id',$record.language_id,'language','','_core.xml',"\" onchange=\"viewTranslations(`$record.product_id`);") } {t}Edit{/t} + + + + + + + + + + + + + +
                    {osb f=tf field=name}
                    {$record.name}
                    + + + + + + + + + + + +
                    {osb f=tf field=description_short}
                    {$record.description_short}
                    + + + + + + + + + + + +
                    {osb f=tf field=description_full}
                    {$record.description_full}
                    + + + + + + + + {/if} diff --git a/themes/default/blocks/service/search_show.tpl b/themes/default/blocks/service/search_show.tpl index dbfaba05..34395128 100644 --- a/themes/default/blocks/service/search_show.tpl +++ b/themes/default/blocks/service/search_show.tpl @@ -21,7 +21,12 @@ {elseif ($record.type == 'host' || $record.type == 'host_group') && trim($record.server_name)} {$record.server_name|trim:25} {else} - {t}{$record.type}{/t} + {if $record.type == 'product' && $record.prod_plugin_name == 'ADSL'} + {$list->unserial($record.prod_attr,'prod_attr')} + {$prod_attr.service_number} + {else} + {t}{$record.type}{/t} + {/if} {/if} diff --git a/themes/default/blocks/service/user_modify.tpl b/themes/default/blocks/service/user_modify.tpl index 8840bf3f..36491308 100644 --- a/themes/default/blocks/service/user_modify.tpl +++ b/themes/default/blocks/service/user_modify.tpl @@ -49,10 +49,10 @@ {else} {if $product_show} {$method->exe('product','details')} - {if ($method->result == false || !$product)} + {if ($method->result == false || !$record)} {$block->display('core:method_error')} {else} - {if $product} + {if $record}
                    @@ -62,10 +62,10 @@ @@ -77,15 +77,15 @@
                    - {if $list->translate('product_translate','name,description_short,description_full','product_id',$product.id,'prod_translate')} + {if $list->translate('product_translate','name,description_short,description_full','product_id',$record.id,'prod_translate')} {$prod_translate.name} {else} - {$product.sku} + {$record.sku} {/if}
                    - {if $product.thumbnail != ''} - + {if $record.thumbnail != ''} + {/if} {$prod_translate.description_full}
                    - {if $product.price_type == '1'} + {if $record.price_type == '1'} @@ -94,7 +94,7 @@ diff --git a/themes/default/blocks/task_log/search_show.tpl b/themes/default/blocks/task_log/search_show.tpl new file mode 100644 index 00000000..2e593f28 --- /dev/null +++ b/themes/default/blocks/task_log/search_show.tpl @@ -0,0 +1,12 @@ +{assign var=meth value=':'|explode:$VAR._page} + + +{$method->exe($meth.0,$meth.1)} +{if ($method->result == false)} + {$block->display('core:method_error')} +{else} + {include file='file:../core/search_show_pre.tpl'} + {$method->exe_noauth($meth.0,'tpl_search_show',$search_show)} + {include file='file:../core/search_show_post-1.tpl'} + {include file='file:../core/search_show_post-2.tpl'} +{/if} diff --git a/themes/default/cart.js b/themes/default/cart.js deleted file mode 100644 index ce9dbcec..00000000 --- a/themes/default/cart.js +++ /dev/null @@ -1,41 +0,0 @@ -function domainUpdate(domain,tld,type) { - document.getElementById("domain_name").value = domain; - document.getElementById("domain_tld").value = tld; - document.getElementById("domain_option").value = type; -} - -function addCart(addtype,hosting) { - if (hosting == "1") { - var domain_option = document.getElementById("domain_option").value; - var domain_name = document.getElementById("domain_name").value; - var domain_tld = document.getElementById("domain_tld").value; - - if(domain_option == "0") { - //@todo To Translate - alert("You must choose a 'Domain Transfer / Registration Option' to continue."); - return; - } - - if(domain_name == "0" || domain_tld == "0") { - if(domain_option != "ip") { - //@todo To Translate - alert("You must select a valid domain name to continue."); - return; - } - } - } - attrValidate(addtype); -} - -function doCart(addtype) { - form = document.getElementById('view'); - if(addtype == 'cart') { - //document.getElementById('page').value = 'cart:admin_view'; - document.getElementById('page').value = 'cart:cart'; - } else if(addtype == 'checkout') { - document.getElementById('page').value = 'checkout:checkout'; - } - - form.action = ''; - form.submit(); -} diff --git a/themes/default/images/logo-small.png b/themes/default/images/logo-small.png index 85c2c16e6eb0e396e5a69251865eaa7704960ef0..2fc13978cef1e3304a5c891cfa040a571cea2ff2 100644 GIT binary patch delta 2221 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 vE4}vGYXPLCrOoUOf&eqn}0UU4u7g+)( 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 diff --git a/themes/default/template.tpl b/themes/default/template.tpl index 9e4a55ac..69a31641 100644 --- a/themes/default/template.tpl +++ b/themes/default/template.tpl @@ -40,8 +40,8 @@
                    {osb f=tf module=product field=price_recurr_type} - - - -
                    - - - - - - - -
                    {$record.title}
                    - - - - -
                    {$record.intro}
                    -
                    -
                    -
                    - {/foreach} - {else} - {t}Sorry, no pages were found in this category, or your account is not authorized for this category.{/t} - {/if} -{/if} diff --git a/themes/default/blocks/static_page/page_show.tpl b/themes/default/blocks/static_page/page_show.tpl deleted file mode 100644 index fe3b5331..00000000 --- a/themes/default/blocks/static_page/page_show.tpl +++ /dev/null @@ -1,22 +0,0 @@ -{assign var=meth value=':'|explode:$VAR._page} - - -{$method->exe($meth.0,$meth.1)} -{if ($method->result == false)} - {$block->display('core:method_error')} -{else} - - {if $static_page_display == true} - - - - - - - -
                    {$static_page_results.title}
                    {$static_page_results.body}
                    - {else} - {t}Sorry, the requested page was not found, or you do not have the required level of authorisation to view it.{/t} - {/if} - -{/if} diff --git a/themes/default/blocks/static_page_category/menu.tpl b/themes/default/blocks/static_page_category/menu.tpl deleted file mode 100644 index 92064009..00000000 --- a/themes/default/blocks/static_page_category/menu.tpl +++ /dev/null @@ -1,28 +0,0 @@ -{assign var=meth value=':'|explode:$VAR._page} - - -{$method->exe_noauth($meth.0,$meth.1)} -{if ($method->result == false)} - {$block->display('core:method_error')} -{else} - - {if $static_page_category_display == true} - - - - - -
                    - {/if} -{/if} diff --git a/themes/default/blocks/task/view.tpl b/themes/default/blocks/task/view.tpl index 3ee1024b..16cbea03 100644 --- a/themes/default/blocks/task/view.tpl +++ b/themes/default/blocks/task/view.tpl @@ -92,8 +92,8 @@
                    - - + +
                    {osb f=tt module=task_log method=view} {t}Run{/t}{osb f=tt module=task_log method=view} {t}Run{/t}
                    - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + {if $show_affiliates == true} - - - - - - + + + + + + {/if}
                    {t}Indicator{/t}{t}Period{/t}{t}Current{/t}{t}Previous{/t}{t}Change{/t}{t}Indicator{/t}{t}Period{/t}{t}Current{/t}{t}Previous{/t}{t}Change{/t}
                    {t}Sales{/t}{$period_compare}{$list->format_currency_num($sales_current,'')}{$list->format_currency_num($sales_previous,'')}{$sales_change}
                    {t}Sales{/t}{$period_compare}{$list->format_currency_num($sales_current)}{$list->format_currency_num($sales_previous)} + {if $sales_change < 0} + {$sales_change|number_format:2}% + {else} + +{$sales_change|number_format:2}% + {/if} +
                    {t}Forcast{/t}{$period_forcast}{$list->format_currency_num($forcast_current,'')}-{$forcast_change}
                    {t}Forcast{/t}{$period_forcast}{$list->format_currency_num($forcast_current)}- + {if $forcast_change < 0} + {$forcast_change|number_format:2}% + {else} + +{$forcast_change|number_format:2}% + {/if} +
                    {t}Quota{/t}{t}Today{/t}{$list->format_currency_num($quota_current,'')}--
                    {t}Quota{/t}{t}Today{/t}{$list->format_currency_num($quota_current)}--
                    {t}A/R Credits{/t}{$period_compare}{$list->format_currency_num($ar_credits_current,'')}{$list->format_currency_num($ar_credits_previous,'')}{$ar_credit_change}
                    {t}A/R Credits{/t}{$period_compare}{$list->format_currency_num($ar_credits_current)}{$list->format_currency_num($ar_credits_previous)} + {if $ar_credit_change < 0} + {$ar_credit_change|number_format:2}% + {else} + +{$ar_credit_change|number_format:2}% + {/if} +
                    {t}A/R Balance{/t}{$period_compare}{$list->format_currency_num($ar_balance_current,'')}{$list->format_currency_num($ar_balance_last,'')}-
                    {t}A/R Balance{/t}{$period_compare}{$list->format_currency_num($ar_balance_current)}{$list->format_currency_num($ar_balance_last)}-
                    {t}Users{/t}{$period_compare}{$users_current}{$users_previous}{$users_change}
                    {t}Users{/t}{$period_compare}{$users_current}{$users_previous} + {if $users_change < 0} + {$users_change|number_format:2}% + {else} + +{$users_change|number_format:2}% + {/if} +
                    {t module=invoice}affiliatesales{/t}{$period_compare}{$list->format_currency_num($affiliate_sales_current,'')}{$list->format_currency_num($affiliate_sales_previous,'')}{$affiliate_sales_change}
                    {t module=invoice}affiliatesales{/t}{$period_compare}{$list->format_currency_num($affiliate_sales_current)}{$list->format_currency_num($affiliate_sales_previous)} + {if $affiliate_sales_change < 0} + {$affiliate_sales_change|number_format:2}% + {else} + +{$affiliate_sales_change|number_format:2}% + {/if} +
                    diff --git a/themes/default_admin/blocks/core/invalid_page.tpl b/themes/default_admin/blocks/core/invalid_page.tpl deleted file mode 100644 index 95e39688..00000000 --- a/themes/default_admin/blocks/core/invalid_page.tpl +++ /dev/null @@ -1 +0,0 @@ -

                    Sorry, the page you specified does not exist on our server!
                    diff --git a/themes/default_admin/blocks/core/leftFrameBlue.tpl b/themes/default_admin/blocks/core/leftFrameBlue.tpl index 3b52bf76..2175feb8 100644 --- a/themes/default_admin/blocks/core/leftFrameBlue.tpl +++ b/themes/default_admin/blocks/core/leftFrameBlue.tpl @@ -49,6 +49,7 @@
                    all
                    Show ALL accounts
                    fn:XXX
                    Show accounts where FIRST NAME is XXX
                    ln:XXX
                    Show accounts where LAST NAME is XXX
                    +
                    un:XXX
                    Show accounts where USERNAME is XXX
                    co:XXX
                    Show accounts where COMPANY NAME is XXX
                    em:XXX
                    Show accounts where EMAIL is XXX
                    id:XXX
                    Show accounts where ID is XXX
                    @@ -136,11 +137,11 @@ All Rights Reserved. } else if(s.match(/em:/)) { var str = s.replace(/em:/, ""); st += '&account_email='+str; - } else if(s.match(/id:/)) { + } else if(s.match(/un:/)) { var str = s.replace(/id:/, ""); - st += '&account_id='+str; + st += '&account_username='+str; } else { - st += '&account_username=' +s; + st += '&account_id=' +s; } } else { var array=input.split(" "); @@ -163,6 +164,9 @@ All Rights Reserved. } else if(s.match(/ln:/)) { var str = s.replace(/ln:/, ""); st += '&account_last_name='+str; + } else if(s.match(/un:/)) { + var str = s.replace(/un:/, ""); + st += '&account_username='+str; } else if(s.match(/co:/)) { var str = s.replace(/co:/, ""); st += '&account_company='+str; @@ -170,7 +174,7 @@ All Rights Reserved. var str = s.replace(/em:/, ""); st += '&account_email='+str; } else { - st += '&account_username=' +s; + st += '&account_id=' +s; } num+=1; } diff --git a/themes/default_admin/blocks/core/top_frame.tpl b/themes/default_admin/blocks/core/top_frame.tpl index d0942802..0f6ee6b3 100644 --- a/themes/default_admin/blocks/core/top_frame.tpl +++ b/themes/default_admin/blocks/core/top_frame.tpl @@ -23,6 +23,7 @@ {/literal} //--> + diff --git a/themes/default_admin/search.js b/themes/default_admin/search.js index 3960af6e..59702f80 100644 --- a/themes/default_admin/search.js +++ b/themes/default_admin/search.js @@ -12,10 +12,6 @@ function search_nav_jump(jmp_to) { } } -function search_nav_jump1(jmp_to) { - search_nav_jump(jmp_to); -} - function search_nav_top() { var iPages = (new Number(pages)) + 0; var iPage = (new Number(page)) + 0; @@ -96,7 +92,7 @@ function search_heading(title,field) { newimg = ''; } - var url = '?_page='+module+':search_show&search_id='+search_id+'&page='+page+'&'+newsort+'=&order_by='+field+''+p+pgescape; + var url = '?_page='+module+':'+method+'&search_id='+search_id+'&page='+page+'&'+newsort+'=&order_by='+field+''+p+pgescape; if (newimg) var returns = ''+title+' '; @@ -206,12 +202,13 @@ function mass_do(doit, page, limit, module) { var checked = document.getElementById("record"+record_arr[i]).checked; var this_id = document.getElementById("record"+record_arr[i]).value; - if(checked != '') { + if (checked != '') { count++; id = id + this_id + ','; } } } + id = id.replace(/,$/,''); if(count == 0) { alert('You must first select some records for this action!'); @@ -275,7 +272,7 @@ function key_handler(e) { } if(pressed == 'x' || pressed == 'X') { - mass_do('delete', module+ ":search_show&search_id=" +search_id+ "&page=" +page+ "&order_by=" +order+ "&" +sort1, limit, module); + mass_do('delete', module+':'+method+'&search_id='+search_id+'&page='+page+'&order_by='+order+'&'+sort1,limit,module); } if(pressed == 'v' || pressed == 'V') { diff --git a/themes/default_admin/view-advanced.js b/themes/default_admin/view-advanced.js index 2d65dbc1..17ed3514 100644 --- a/themes/default_admin/view-advanced.js +++ b/themes/default_admin/view-advanced.js @@ -26,7 +26,7 @@ function view_Jump(account_id) { if (module != 'invoice') break; - approveInvoice(id,1,ids) + pApproveVoid(id,1) break; case 'become': @@ -58,7 +58,7 @@ function view_Jump(account_id) { if (module != 'account') break; - document.location = URL+'admin.php?_page='+module+':view&do[]=invoice:generateinvoice_account&account_id='+account_id+'&id='+account_id; + document.location = URL+'admin.php?_page='+module+':view&do[]=invoice:generateinvoice_account&account_id='+account_id+'&id='+account_id+'&_page_current='+module+':view'; break; case 'merge': @@ -142,7 +142,7 @@ function view_Jump(account_id) { if (module != 'invoice') break; - approveInvoice(id,0,ids) + pApproveVoid(id,0) break; default: diff --git a/themes/default_admin/view.js b/themes/default_admin/view.js index 5d4dc1eb..6b2d63be 100644 --- a/themes/default_admin/view.js +++ b/themes/default_admin/view.js @@ -20,7 +20,7 @@ function view_nav_top(array,id,ids) { var ff = ''; var jmp= ''; - var t=array.length-1; + var t=array.length; var last = false; var next = false;