From 04c392136e09a4c310375b04221a77583c1c8a82 Mon Sep 17 00:00:00 2001 From: Jeramy Simpson Date: Tue, 17 Mar 2015 07:45:25 +1000 Subject: [PATCH] Add Files --- app/Console/Commands/CheckData.php | 266 + app/Console/Commands/CreateRandomData.php | 88 + app/Console/Commands/ImportTimesheetData.php | 335 + app/Console/Commands/ResetData.php | 24 + .../Commands/SendRecurringInvoices.php | 113 + app/Handlers/InvoiceEventHandler.php | 51 + app/Handlers/UserEventHandler.php | 30 + app/Http/Controllers/.gitkeep | 0 app/Http/Controllers/AccountController.php | 715 + .../Controllers/AccountGatewayController.php | 292 + app/Http/Controllers/ActivityController.php | 20 + app/Http/Controllers/AppController.php | 171 + app/Http/Controllers/BaseController.php | 21 + app/Http/Controllers/ClientApiController.php | 51 + app/Http/Controllers/ClientController.php | 278 + app/Http/Controllers/Controller.php | 11 + app/Http/Controllers/CreditController.php | 149 + app/Http/Controllers/DashboardController.php | 79 + app/Http/Controllers/HomeController.php | 3 +- .../Controllers/IntegrationController.php | 26 + app/Http/Controllers/InvoiceApiController.php | 192 + app/Http/Controllers/InvoiceController.php | 542 + app/Http/Controllers/PaymentApiController.php | 36 + app/Http/Controllers/PaymentController.php | 748 + app/Http/Controllers/ProductController.php | 96 + app/Http/Controllers/QuoteApiController.php | 36 + app/Http/Controllers/QuoteController.php | 187 + app/Http/Controllers/ReportController.php | 127 + app/Http/Controllers/TimesheetController.php | 93 + app/Http/Controllers/TokenController.php | 161 + app/Http/Controllers/UserController.php | 507 + .../Controllers/old/Auth/AuthController.php | 38 + .../old/Auth/PasswordController.php | 38 + app/Http/Controllers/old/HomeController.php | 36 + .../Controllers/old/WelcomeController.php | 36 + app/Http/routes.php | 2 +- app/Libraries/Utils.php | 605 + app/Libraries/entity.php | 8 + app/Libraries/timesheet_utils.php | 119 + app/Models/Account.php | 363 + app/Models/AccountGateway.php | 28 + app/Models/AccountGatewayToken.php | 7 + app/Models/AccountToken.php | 9 + app/Models/Activity.php | 470 + app/Models/Affiliate.php | 7 + app/Models/Client.php | 268 + app/Models/Contact.php | 74 + app/Models/Country.php | 9 + app/Models/Credit.php | 55 + app/Models/Currency.php | 7 + app/Models/DateFormat.php | 7 + app/Models/DatetimeFormat.php | 7 + app/Models/EntityModel.php | 78 + app/Models/Frequency.php | 7 + app/Models/Gateway.php | 52 + app/Models/Industry.php | 7 + app/Models/Invitation.php | 29 + app/Models/Invoice.php | 230 + app/Models/InvoiceDesign.php | 7 + app/Models/InvoiceItem.php | 14 + app/Models/InvoiceStatus.php | 7 + app/Models/Language.php | 7 + app/Models/License.php | 7 + app/Models/Payment.php | 60 + app/Models/PaymentLibrary.php | 12 + app/Models/PaymentTerm.php | 7 + app/Models/PaymentType.php | 7 + app/Models/Product.php | 9 + app/Models/Project.php | 45 + app/Models/ProjectCode.php | 45 + app/Models/Size.php | 7 + app/Models/Subscription.php | 7 + app/Models/TaxRate.php | 5 + app/Models/Theme.php | 7 + app/Models/Timesheet.php | 22 + app/Models/TimesheetEvent.php | 122 + app/Models/TimesheetEventSource.php | 40 + app/Models/Timezone.php | 7 + app/Models/User.php | 170 + app/Providers/RouteServiceProvider.php.bak | 303 + app/includes/parsecsv.lib.php | 695 + app/libraries/Utils.php | 604 + app/ninja/mailers/ContactMailer.php | 104 + app/ninja/mailers/Mailer.php | 27 + app/ninja/mailers/UserMailer.php | 62 + app/ninja/repositories/AccountRepository.php | 234 + app/ninja/repositories/ClientRepository.php | 202 + app/ninja/repositories/CreditRepository.php | 77 + app/ninja/repositories/InvoiceRepository.php | 490 + app/ninja/repositories/PaymentRepository.php | 154 + app/ninja/repositories/TaxRateRepository.php | 42 + composer.json | 2 +- composer.lock | 6220 +++ config/app.php | 41 +- ...11_05_180133_confide_setup_users_table.php | 550 + ...013_11_28_195703_setup_countries_table.php | 47 + .../2014_02_13_151500_add_cascase_drops.php | 32 + ...151817_add_support_for_invoice_designs.php | 72 + ...2014_03_03_155556_add_phone_to_account.php | 36 + ...2014_03_19_201454_add_language_support.php | 60 + ..._03_20_200300_create_payment_libraries.php | 58 + ...2014_03_23_051736_enable_forcing_jspdf.php | 34 + ...0_add_sort_and_recommended_to_gateways.php | 49 + .../2014_04_03_191105_add_pro_plan.php | 34 + .../2014_04_17_100523_add_remember_token.php | 34 + .../2014_04_17_145108_add_custom_fields.php | 60 + ...014_04_23_170909_add_products_settings.php | 39 + ...014_04_29_174315_add_advanced_settings.php | 42 + .../2014_05_17_175626_add_quotes.php | 38 + ...epted_credit_cards_to_account_gateways.php | 34 + .../2014_07_13_142654_one_click_install.php | 58 + ...4_07_17_205900_support_hiding_quantity.php | 66 + .../2014_07_24_171214_add_zapier_support.php | 42 + ...14_10_01_141248_add_company_vat_number.php | 43 + ...4_10_05_141856_track_last_seen_message.php | 46 + .../2014_10_06_103529_add_timesheets.php | 152 + ..._10_06_195330_add_invoice_design_table.php | 519 + ..._13_054100_add_invoice_number_settings.php | 63 + ...14_10_14_225227_add_danish_translation.php | 29 + .../2014_10_22_174452_add_affiliate_price.php | 44 + ...014_10_30_184126_add_company_id_number.php | 43 + ...1_04_200406_allow_null_client_currency.php | 31 + .../2014_12_03_154119_add_discount_type.php | 34 + .../2015_02_12_102940_add_email_templates.php | 38 + ...015_02_17_131714_support_token_billing.php | 56 + .../2015_02_27_081836_add_invoice_footer.php | 44 + .../2015_03_03_140259_add_tokens.php | 54 + .../2015_03_09_151011_add_ip_to_activity.php | 34 + database/seeds/ConstantsSeeder.php | 327 + database/seeds/CountriesSeeder.php | 37 + database/seeds/PaymentLibrariesSeeder.php | 35 + database/seeds/SecurePaymentFormSeeder.php | 187 + database/seeds/UserTableSeeder.php | 11 + error_log | 9 + public/apple-touch-icon-precomposed.png | Bin 0 -> 2207 bytes public/apple-touch-icon.png | Bin 0 -> 2207 bytes ...e.min-6140190bf67c53b87b24ba70ca9fc9ee.css | 9 + ...p.min-6140190bf67c53b87b24ba70ca9fc9ee.css | 9 + ...ap.min-6140190bf67c53b87b24ba70ca9fc9ee.js | 9 + ....2.min-590935b89a583963aad9f1d779d81729.js | 6 + public/built.css | 2910 ++ public/built.js | 33045 +++++++++++++ public/built.public.css | 708 + public/css/bootstrap-combobox.css | 70 + public/css/bootstrap.min.css | 7 + public/css/bootstrap.splash.css | 11 + public/css/customCss.css | 29 + public/css/lightbox.css | 210 + public/css/splash.css | 1378 + public/css/style.css | 802 + public/css/themes/amelia.min.css | 1 + public/css/themes/cerulean.min.css | 1 + public/css/themes/cosmo.min.css | 1 + public/css/themes/cyborg.min.css | 1 + public/css/themes/flatly.min.css | 1 + public/css/themes/journal.min.css | 1 + public/css/themes/readable.min.css | 1 + public/css/themes/simplex.min.css | 1 + public/css/themes/slate.min.css | 1 + public/css/themes/spacelab.min.css | 1 + public/css/themes/united.min.css | 1 + public/css/themes/yeti.min.css | 1 + public/css/typeahead.js-bootstrap.css | 84 + public/error_log | 305 + public/favicon.gif | Bin 0 -> 298 bytes public/fonts/.empty | 1 + public/fonts/FontAwesome.otf | Bin 0 -> 62856 bytes public/fonts/fontawesome-webfont.eot | Bin 0 -> 38205 bytes public/fonts/fontawesome-webfont.svg | 414 + public/fonts/fontawesome-webfont.ttf | Bin 0 -> 80652 bytes public/fonts/fontawesome-webfont.woff | Bin 0 -> 44432 bytes public/fonts/socicon-webfont.eot | Bin 0 -> 18826 bytes public/fonts/socicon-webfont.svg | 90 + public/fonts/socicon-webfont.ttf | Bin 0 -> 27720 bytes public/fonts/socicon-webfont.woff | Bin 0 -> 20972 bytes public/images/AcceptPaymentsOnline.png | Bin 0 -> 1203 bytes public/images/AdjustablePaymentTerms.png | Bin 0 -> 1451 bytes public/images/AlertsWhenInvoicesViewed.png | Bin 0 -> 1392 bytes public/images/BeautifulTemplates.png | Bin 0 -> 1172 bytes public/images/BestInClassSecurity.png | Bin 0 -> 1405 bytes public/images/CloneInvoices.png | Bin 0 -> 1115 bytes public/images/CloudBasedApp.png | Bin 0 -> 1283 bytes public/images/CustomizeInvoices.png | Bin 0 -> 1276 bytes public/images/EstimatesProForma.png | Bin 0 -> 1551 bytes public/images/FreeInvoicing.png | Bin 0 -> 1340 bytes public/images/GitHub.png | Bin 0 -> 2625 bytes public/images/ImportExportRecords.png | Bin 0 -> 1271 bytes public/images/InTuitiveEditingInterface.png | Bin 0 -> 1323 bytes .../images/IntegrateWithPaymentGateways.png | Bin 0 -> 1268 bytes public/images/InvoiceClientsViaEmail.png | Bin 0 -> 1372 bytes public/images/LivePDFCreation.png | Bin 0 -> 1117 bytes .../images/ManualAutomaticInvoiceNumbers.png | Bin 0 -> 1180 bytes public/images/MultilingualSupport.png | Bin 0 -> 1158 bytes public/images/MultipleCurrencySupport.png | Bin 0 -> 1241 bytes public/images/MultipleTaxSettings.png | Bin 0 -> 1184 bytes public/images/OpenSource.png | Bin 0 -> 1242 bytes public/images/PaymentTracking.png | Bin 0 -> 1462 bytes public/images/PersonalizeInvoiceColor.png | Bin 0 -> 1427 bytes public/images/PrintablePDFInvoices.png | Bin 0 -> 1273 bytes public/images/RecurringInvoiceProfiles.png | Bin 0 -> 1232 bytes public/images/SelfHostedAvailable.png | Bin 0 -> 1195 bytes public/images/Thumbs.db | Bin 0 -> 444928 bytes public/images/about1.jpg | Bin 0 -> 30861 bytes public/images/about1@2x.jpg | Bin 0 -> 30861 bytes public/images/about2.jpg | Bin 0 -> 47959 bytes public/images/about2@2x.jpg | Bin 0 -> 47959 bytes public/images/activeclients.png | Bin 0 -> 3827 bytes public/images/activeclients@2x.png | Bin 0 -> 7112 bytes .../apple-touch-icon-114x114-precomposed.png | Bin 0 -> 3613 bytes .../apple-touch-icon-144x144-precomposed.png | Bin 0 -> 4369 bytes .../apple-touch-icon-57x57-precomposed.png | Bin 0 -> 2207 bytes .../apple-touch-icon-72x72-precomposed.png | Bin 0 -> 2588 bytes public/images/apple-touch-icon.png | Bin 0 -> 2207 bytes public/images/benjacobson.jpg | Bin 0 -> 27563 bytes public/images/bg-blue.jpg | Bin 0 -> 22543 bytes public/images/clients.png | Bin 0 -> 3788 bytes public/images/clients@2x.png | Bin 0 -> 6894 bytes .../Test-AmericanExpress-Icon.png | Bin 0 -> 32399 bytes .../images/credit_cards/Test-Diners-Icon.png | Bin 0 -> 9415 bytes .../credit_cards/Test-Discover-Icon.png | Bin 0 -> 7611 bytes .../credit_cards/Test-MasterCard-Icon.png | Bin 0 -> 50662 bytes public/images/credit_cards/Test-Visa-Icon.png | Bin 0 -> 33235 bytes public/images/designs/business.png | Bin 0 -> 43569 bytes public/images/designs/business_thumb.png | Bin 0 -> 7938 bytes public/images/designs/creative.png | Bin 0 -> 48193 bytes public/images/designs/creative_thumb.png | Bin 0 -> 9688 bytes public/images/designs/elegant.png | Bin 0 -> 37810 bytes public/images/designs/elegant_thumb.png | Bin 0 -> 7623 bytes public/images/designs/hipster.png | Bin 0 -> 41702 bytes public/images/designs/hipster_thumb.png | Bin 0 -> 8597 bytes public/images/designs/photo.png | Bin 0 -> 243068 bytes public/images/designs/photo_thumb.png | Bin 0 -> 22300 bytes public/images/designs/playful.png | Bin 0 -> 38996 bytes public/images/designs/playful_thumb.png | Bin 0 -> 10006 bytes public/images/devices-2.png | Bin 0 -> 90359 bytes public/images/devices.png | Bin 0 -> 90169 bytes public/images/devices3.png | Bin 0 -> 73775 bytes public/images/facebook.jpg | Bin 0 -> 14974 bytes public/images/features1.jpg | Bin 0 -> 248116 bytes public/images/features2.jpg | Bin 0 -> 9334 bytes public/images/features3.jpg | Bin 0 -> 28589 bytes public/images/features4.jpg | Bin 0 -> 84076 bytes public/images/features5.jpg | Bin 0 -> 33678 bytes public/images/footer-logo.png | Bin 0 -> 4838 bytes public/images/gateways/Thumbs.db | Bin 0 -> 8192 bytes .../images/gateways/logo_AuthorizeNet_AIM.png | Bin 0 -> 6799 bytes public/images/gateways/logo_BeanStream.png | Bin 0 -> 3228 bytes .../gateways/logo_FirstData_Connect.png | Bin 0 -> 2501 bytes public/images/gateways/logo_PayPal_Pro.png | Bin 0 -> 4375 bytes public/images/gateways/logo_TwoCheckout.png | Bin 0 -> 2550 bytes public/images/gateways/logo_iTransact.png | Bin 0 -> 5902 bytes public/images/hero-bg-1.jpg | Bin 0 -> 189586 bytes public/images/hero-bg-2.jpg | Bin 0 -> 142317 bytes public/images/hero-bg-3.jpg | Bin 0 -> 40898 bytes public/images/hero-bg-4.jpg | Bin 0 -> 86024 bytes public/images/hero-bg-contact.jpg | Bin 0 -> 55707 bytes public/images/hero-bg-faq.jpg | Bin 0 -> 24206 bytes public/images/hero-bg-plans.jpg | Bin 0 -> 26159 bytes public/images/hero-bg-secure-pay.jpg | Bin 0 -> 18459 bytes public/images/hero-bg-testi.jpg | Bin 0 -> 24501 bytes public/images/hero-faq@2x.png | Bin 0 -> 2753 bytes public/images/hex-facebook.png | Bin 0 -> 1600 bytes public/images/hex-github.png | Bin 0 -> 1804 bytes public/images/hex-gplus.png | Bin 0 -> 1848 bytes public/images/hex-linkedin.png | Bin 0 -> 1701 bytes public/images/hex-pinterest.png | Bin 0 -> 1892 bytes public/images/hex-rss.png | Bin 0 -> 1870 bytes public/images/hex-twitter.png | Bin 0 -> 1743 bytes public/images/hillelcoren.jpg | Bin 0 -> 16418 bytes public/images/icon-about.png | Bin 0 -> 1787 bytes public/images/icon-about@2x.png | Bin 0 -> 2554 bytes public/images/icon-contact.png | Bin 0 -> 1854 bytes public/images/icon-contact@2x.png | Bin 0 -> 2845 bytes public/images/icon-faq.png | Bin 0 -> 1807 bytes public/images/icon-features.png | Bin 0 -> 1882 bytes public/images/icon-features@2x.png | Bin 0 -> 2974 bytes public/images/icon-free.png | Bin 0 -> 1412 bytes public/images/icon-free2.png | Bin 0 -> 1542 bytes public/images/icon-free@2x.png | Bin 0 -> 2699 bytes public/images/icon-login.png | Bin 0 -> 1561 bytes public/images/icon-login@2x.png | Bin 0 -> 2313 bytes public/images/icon-opensource.png | Bin 0 -> 1411 bytes public/images/icon-opensource@2x.png | Bin 0 -> 1848 bytes public/images/icon-payment.png | Bin 0 -> 1465 bytes public/images/icon-payment@2x.png | Bin 0 -> 1970 bytes public/images/icon-pdf.png | Bin 0 -> 1564 bytes public/images/icon-pdf@2x.png | Bin 0 -> 3084 bytes public/images/icon-plans.png | Bin 0 -> 1199 bytes public/images/icon-plans@2x.png | Bin 0 -> 1297 bytes public/images/icon-secure-footer.png | Bin 0 -> 1240 bytes public/images/icon-secure-footer@2x.png | Bin 0 -> 1559 bytes public/images/icon-secure-pay.png | Bin 0 -> 1163 bytes public/images/icon-secure-pay@2x.png | Bin 0 -> 1288 bytes public/images/icon-secure.png | Bin 0 -> 1194 bytes public/images/icon-secure@2x.png | Bin 0 -> 1420 bytes public/images/icon-shield.png | Bin 0 -> 2017 bytes public/images/icon-testi.png | Bin 0 -> 1999 bytes public/images/icon-testi@2x.png | Bin 0 -> 3175 bytes public/images/instagram.svg | 24 + public/images/invoiceninja-logo.png | Bin 0 -> 3952 bytes public/images/invoiceninja-logo@2x.png | Bin 0 -> 3952 bytes public/images/laptopwicon.jpg | Bin 0 -> 30152 bytes public/images/lightbox/close.png | Bin 0 -> 280 bytes public/images/lightbox/loading.gif | Bin 0 -> 8476 bytes public/images/lightbox/next.png | Bin 0 -> 1350 bytes public/images/lightbox/prev.png | Bin 0 -> 1360 bytes public/images/linkedin.svg | 14 + public/images/me.svg | 26 + public/images/opensource-footer.png | Bin 0 -> 6990 bytes public/images/pro-plan-chart.png | Bin 0 -> 164763 bytes public/images/providers.png | Bin 0 -> 8990 bytes public/images/razikantorp.jpg | Bin 0 -> 47455 bytes public/images/report_logo1.jpg | Bin 0 -> 5234 bytes public/images/report_logo2.jpg | Bin 0 -> 13504 bytes public/images/report_logo3.jpg | Bin 0 -> 31804 bytes public/images/shalomstark.jpg | Bin 0 -> 62164 bytes public/images/social.jpg | Bin 0 -> 14974 bytes public/images/social/facebook.png | Bin 0 -> 229 bytes public/images/social/facebook.svg | 6 + public/images/social/github.png | Bin 0 -> 457 bytes public/images/social/twitter.png | Bin 0 -> 307 bytes public/images/social/twitter.svg | 6 + public/images/sort_asc.png | Bin 0 -> 1028 bytes public/images/sort_asc_disabled.png | Bin 0 -> 1050 bytes public/images/sort_both.png | Bin 0 -> 1136 bytes public/images/sort_desc.png | Bin 0 -> 1037 bytes public/images/sort_desc_disabled.png | Bin 0 -> 1045 bytes public/images/ssl-footer.png | Bin 0 -> 7519 bytes public/images/totalincome.png | Bin 0 -> 3395 bytes public/images/totalincome@2x.png | Bin 0 -> 6026 bytes public/images/totalinvoices.png | Bin 0 -> 3294 bytes public/images/totalinvoices@2x.png | Bin 0 -> 5651 bytes public/images/twitter.svg | 13 + public/images/website.svg | 11 + public/js/Chart.js | 1426 + public/js/bootstrap-combobox.js | 419 + public/js/bootstrap.js | 219 + public/js/bootstrap.min.js | 7 + public/js/built.public.js | 7 + public/js/compatibility.js | 483 + public/js/d3.min.js | 5 + public/js/jspdf.min.js | 140 + public/js/jspdf.plugin.split_text_to_size.js | 297 + public/js/jspdf.source.js | 6663 +++ public/js/lightbox.min.js | 9 + public/js/pdf.js | 49 + public/js/pdf_viewer.js | 7420 +++ public/js/pdf_viewer.worker.js | 39769 ++++++++++++++++ public/js/retina-1.1.0.min.js | 10 + public/js/script.js | 1522 + public/js/simpleexpand.js | 4 + public/js/stacktrace.js | 485 + public/js/typedarray.js | 1030 + public/js/valign.js | 12 + public/logo/.gitkeep | 0 .../logo/zg4ylmzDkdkPOT8yoKQw9LTWaoZJx79h.jpg | Bin 0 -> 1822 bytes resources/lang/da/pagination.php | 20 + resources/lang/da/public.php | 209 + resources/lang/da/reminders.php | 26 + resources/lang/da/texts.php | 582 + resources/lang/da/validation.php | 106 + resources/lang/de/pagination.php | 20 + resources/lang/de/public.php | 209 + resources/lang/de/reminders.php | 24 + resources/lang/de/texts.php | 574 + resources/lang/de/validation.php | 108 + resources/lang/en/public.php | 209 + resources/lang/en/reminders.php | 24 + resources/lang/en/texts.php | 581 + resources/lang/es/pagination.php | 20 + resources/lang/es/public.php | 209 + resources/lang/es/reminders.php | 24 + resources/lang/es/texts.php | 554 + resources/lang/es/validation.php | 111 + resources/lang/fr/pagination.php | 20 + resources/lang/fr/public.php | 209 + resources/lang/fr/reminders.php | 24 + resources/lang/fr/texts.php | 574 + resources/lang/fr/validation.php | 138 + resources/lang/it/pagination.php | 20 + resources/lang/it/public.php | 209 + resources/lang/it/reminders.php | 24 + resources/lang/it/texts.php | 576 + resources/lang/it/validation.php | 107 + resources/lang/lt/pagination.php | 20 + resources/lang/lt/public.php | 209 + resources/lang/lt/reminders.php | 24 + resources/lang/lt/texts.php | 586 + resources/lang/lt/validation.php | 102 + resources/lang/nb_NO/pagination.php | 20 + resources/lang/nb_NO/public.php | 209 + resources/lang/nb_NO/reminders.php | 24 + resources/lang/nb_NO/texts.php | 582 + resources/lang/nb_NO/validation.php | 102 + resources/lang/nl/pagination.php | 20 + resources/lang/nl/public.php | 209 + resources/lang/nl/reminders.php | 24 + resources/lang/nl/texts.php | 578 + resources/lang/nl/validation.php | 111 + resources/lang/pt_BR/pagination.php | 20 + resources/lang/pt_BR/public.php | 209 + resources/lang/pt_BR/reminders.php | 24 + resources/lang/pt_BR/texts.php | 565 + resources/lang/pt_BR/validation.php | 106 + .../views/accounts/account_gateway.blade.php | 153 + resources/views/accounts/details.blade.php | 252 + .../views/accounts/email_templates.blade.php | 109 + resources/views/accounts/export.blade.php | 11 + .../views/accounts/import_export.blade.php | 61 + resources/views/accounts/import_map.blade.php | 73 + .../views/accounts/invoice_design.blade.php | 116 + .../views/accounts/invoice_settings.blade.php | 73 + resources/views/accounts/nav.blade.php | 16 + .../views/accounts/nav_advanced.blade.php | 17 + .../views/accounts/notifications.blade.php | 47 + resources/views/accounts/payments.blade.php | 60 + resources/views/accounts/product.blade.php | 56 + resources/views/accounts/products.blade.php | 48 + resources/views/accounts/token.blade.php | 30 + .../views/accounts/token_management.blade.php | 67 + .../views/accounts/user_management.blade.php | 71 + resources/views/client.blade.php | 99 + resources/views/clients/edit.blade.php | 168 + resources/views/clients/show.blade.php | 233 + resources/views/coming_soon.blade.php | 35 + resources/views/credits/edit.blade.php | 64 + resources/views/dashboard.blade.php | 159 + resources/views/datatable.blade.php | 68 + .../views/emails/auth/reminder.blade.php | 13 + resources/views/emails/confirm_html.blade.php | 41 + resources/views/emails/confirm_text.blade.php | 7 + resources/views/emails/contact_html.blade.php | 1 + resources/views/emails/contact_text.blade.php | 1 + resources/views/emails/error.blade.php | 0 resources/views/emails/invoice_html.blade.php | 10 + .../views/emails/invoice_paid_html.blade.php | 21 + .../views/emails/invoice_paid_text.blade.php | 11 + .../views/emails/invoice_sent_html.blade.php | 18 + .../views/emails/invoice_sent_text.blade.php | 8 + resources/views/emails/invoice_text.blade.php | 1 + .../emails/invoice_viewed_html.blade.php | 18 + .../emails/invoice_viewed_text.blade.php | 8 + .../license_confirmation_html.blade.php | 18 + .../license_confirmation_text.blade.php | 8 + .../views/emails/passwordreset_html.blade.php | 9 + .../payment_confirmation_html.blade.php | 7 + .../payment_confirmation_text.blade.php | 1 + resources/views/emails/view_action.blade.php | 17 + resources/views/error.blade.php | 20 + resources/views/header.blade.php | 605 + resources/views/invoices/deleted.blade.php | 1 + resources/views/invoices/edit.blade.php | 1671 + resources/views/invoices/history.blade.php | 61 + resources/views/invoices/pdf.blade.php | 126 + resources/views/invoices/view.blade.php | 84 + resources/views/list.blade.php | 164 + resources/views/master.blade.php | 139 + resources/views/payments/edit.blade.php | 70 + resources/views/payments/payment.blade.php | 323 + resources/views/plans.blade.php | 62 + resources/views/public/header.blade.php | 276 + resources/views/public/license.blade.php | 101 + resources/views/public/terms.blade.php | 177 + resources/views/public_list.blade.php | 110 + resources/views/reports/d3.blade.php | 309 + .../views/reports/report_builder.blade.php | 106 + resources/views/script.blade.php | 26 + resources/views/secure_payment.blade.php | 130 + resources/views/setup.blade.php | 139 + resources/views/timesheets/edit.blade.php | 76 + resources/views/users/edit.blade.php | 30 + .../views/users/forgot_password.blade.php | 86 + resources/views/users/login.blade.php | 119 + .../views/users/reset_password.blade.php | 95 + tests/TimesheetUtilsTest.php | 26 + tests/data/Demo/demo.response.json | 5 + 476 files changed, 138012 insertions(+), 5 deletions(-) create mode 100644 app/Console/Commands/CheckData.php create mode 100644 app/Console/Commands/CreateRandomData.php create mode 100644 app/Console/Commands/ImportTimesheetData.php create mode 100644 app/Console/Commands/ResetData.php create mode 100644 app/Console/Commands/SendRecurringInvoices.php create mode 100644 app/Handlers/InvoiceEventHandler.php create mode 100644 app/Handlers/UserEventHandler.php create mode 100644 app/Http/Controllers/.gitkeep create mode 100644 app/Http/Controllers/AccountController.php create mode 100644 app/Http/Controllers/AccountGatewayController.php create mode 100644 app/Http/Controllers/ActivityController.php create mode 100644 app/Http/Controllers/AppController.php create mode 100644 app/Http/Controllers/BaseController.php create mode 100644 app/Http/Controllers/ClientApiController.php create mode 100644 app/Http/Controllers/ClientController.php create mode 100644 app/Http/Controllers/Controller.php create mode 100644 app/Http/Controllers/CreditController.php create mode 100644 app/Http/Controllers/DashboardController.php create mode 100644 app/Http/Controllers/IntegrationController.php create mode 100644 app/Http/Controllers/InvoiceApiController.php create mode 100644 app/Http/Controllers/InvoiceController.php create mode 100644 app/Http/Controllers/PaymentApiController.php create mode 100644 app/Http/Controllers/PaymentController.php create mode 100644 app/Http/Controllers/ProductController.php create mode 100644 app/Http/Controllers/QuoteApiController.php create mode 100644 app/Http/Controllers/QuoteController.php create mode 100644 app/Http/Controllers/ReportController.php create mode 100644 app/Http/Controllers/TimesheetController.php create mode 100644 app/Http/Controllers/TokenController.php create mode 100644 app/Http/Controllers/UserController.php create mode 100644 app/Http/Controllers/old/Auth/AuthController.php create mode 100644 app/Http/Controllers/old/Auth/PasswordController.php create mode 100644 app/Http/Controllers/old/HomeController.php create mode 100644 app/Http/Controllers/old/WelcomeController.php create mode 100644 app/Libraries/Utils.php create mode 100644 app/Libraries/entity.php create mode 100644 app/Libraries/timesheet_utils.php create mode 100644 app/Models/Account.php create mode 100644 app/Models/AccountGateway.php create mode 100644 app/Models/AccountGatewayToken.php create mode 100644 app/Models/AccountToken.php create mode 100644 app/Models/Activity.php create mode 100644 app/Models/Affiliate.php create mode 100644 app/Models/Client.php create mode 100644 app/Models/Contact.php create mode 100644 app/Models/Country.php create mode 100644 app/Models/Credit.php create mode 100644 app/Models/Currency.php create mode 100644 app/Models/DateFormat.php create mode 100644 app/Models/DatetimeFormat.php create mode 100644 app/Models/EntityModel.php create mode 100644 app/Models/Frequency.php create mode 100644 app/Models/Gateway.php create mode 100644 app/Models/Industry.php create mode 100644 app/Models/Invitation.php create mode 100644 app/Models/Invoice.php create mode 100644 app/Models/InvoiceDesign.php create mode 100644 app/Models/InvoiceItem.php create mode 100644 app/Models/InvoiceStatus.php create mode 100644 app/Models/Language.php create mode 100644 app/Models/License.php create mode 100644 app/Models/Payment.php create mode 100644 app/Models/PaymentLibrary.php create mode 100644 app/Models/PaymentTerm.php create mode 100644 app/Models/PaymentType.php create mode 100644 app/Models/Product.php create mode 100644 app/Models/Project.php create mode 100644 app/Models/ProjectCode.php create mode 100644 app/Models/Size.php create mode 100644 app/Models/Subscription.php create mode 100644 app/Models/TaxRate.php create mode 100644 app/Models/Theme.php create mode 100644 app/Models/Timesheet.php create mode 100644 app/Models/TimesheetEvent.php create mode 100644 app/Models/TimesheetEventSource.php create mode 100644 app/Models/Timezone.php create mode 100644 app/Models/User.php create mode 100644 app/Providers/RouteServiceProvider.php.bak create mode 100644 app/includes/parsecsv.lib.php create mode 100644 app/libraries/Utils.php create mode 100644 app/ninja/mailers/ContactMailer.php create mode 100644 app/ninja/mailers/Mailer.php create mode 100644 app/ninja/mailers/UserMailer.php create mode 100644 app/ninja/repositories/AccountRepository.php create mode 100644 app/ninja/repositories/ClientRepository.php create mode 100644 app/ninja/repositories/CreditRepository.php create mode 100644 app/ninja/repositories/InvoiceRepository.php create mode 100644 app/ninja/repositories/PaymentRepository.php create mode 100644 app/ninja/repositories/TaxRateRepository.php create mode 100644 composer.lock create mode 100644 database/migrations/2013_11_05_180133_confide_setup_users_table.php create mode 100644 database/migrations/2013_11_28_195703_setup_countries_table.php create mode 100644 database/migrations/2014_02_13_151500_add_cascase_drops.php create mode 100644 database/migrations/2014_02_19_151817_add_support_for_invoice_designs.php create mode 100644 database/migrations/2014_03_03_155556_add_phone_to_account.php create mode 100644 database/migrations/2014_03_19_201454_add_language_support.php create mode 100644 database/migrations/2014_03_20_200300_create_payment_libraries.php create mode 100644 database/migrations/2014_03_23_051736_enable_forcing_jspdf.php create mode 100644 database/migrations/2014_03_25_102200_add_sort_and_recommended_to_gateways.php create mode 100644 database/migrations/2014_04_03_191105_add_pro_plan.php create mode 100644 database/migrations/2014_04_17_100523_add_remember_token.php create mode 100644 database/migrations/2014_04_17_145108_add_custom_fields.php create mode 100644 database/migrations/2014_04_23_170909_add_products_settings.php create mode 100644 database/migrations/2014_04_29_174315_add_advanced_settings.php create mode 100644 database/migrations/2014_05_17_175626_add_quotes.php create mode 100644 database/migrations/2014_06_17_131940_add_accepted_credit_cards_to_account_gateways.php create mode 100644 database/migrations/2014_07_13_142654_one_click_install.php create mode 100644 database/migrations/2014_07_17_205900_support_hiding_quantity.php create mode 100644 database/migrations/2014_07_24_171214_add_zapier_support.php create mode 100644 database/migrations/2014_10_01_141248_add_company_vat_number.php create mode 100644 database/migrations/2014_10_05_141856_track_last_seen_message.php create mode 100644 database/migrations/2014_10_06_103529_add_timesheets.php create mode 100644 database/migrations/2014_10_06_195330_add_invoice_design_table.php create mode 100644 database/migrations/2014_10_13_054100_add_invoice_number_settings.php create mode 100644 database/migrations/2014_10_14_225227_add_danish_translation.php create mode 100644 database/migrations/2014_10_22_174452_add_affiliate_price.php create mode 100644 database/migrations/2014_10_30_184126_add_company_id_number.php create mode 100644 database/migrations/2014_11_04_200406_allow_null_client_currency.php create mode 100644 database/migrations/2014_12_03_154119_add_discount_type.php create mode 100644 database/migrations/2015_02_12_102940_add_email_templates.php create mode 100644 database/migrations/2015_02_17_131714_support_token_billing.php create mode 100644 database/migrations/2015_02_27_081836_add_invoice_footer.php create mode 100644 database/migrations/2015_03_03_140259_add_tokens.php create mode 100644 database/migrations/2015_03_09_151011_add_ip_to_activity.php create mode 100644 database/seeds/ConstantsSeeder.php create mode 100644 database/seeds/CountriesSeeder.php create mode 100644 database/seeds/PaymentLibrariesSeeder.php create mode 100644 database/seeds/SecurePaymentFormSeeder.php create mode 100644 database/seeds/UserTableSeeder.php create mode 100644 error_log create mode 100644 public/apple-touch-icon-precomposed.png create mode 100644 public/apple-touch-icon.png create mode 100644 public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/css/bootstrap-theme.min-6140190bf67c53b87b24ba70ca9fc9ee.css create mode 100644 public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/css/bootstrap.min-6140190bf67c53b87b24ba70ca9fc9ee.css create mode 100644 public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/js/bootstrap.min-6140190bf67c53b87b24ba70ca9fc9ee.js create mode 100644 public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/js/jquery-1.10.2.min-590935b89a583963aad9f1d779d81729.js create mode 100644 public/built.css create mode 100644 public/built.js create mode 100644 public/built.public.css create mode 100644 public/css/bootstrap-combobox.css create mode 100644 public/css/bootstrap.min.css create mode 100644 public/css/bootstrap.splash.css create mode 100644 public/css/customCss.css create mode 100644 public/css/lightbox.css create mode 100644 public/css/splash.css create mode 100644 public/css/style.css create mode 100644 public/css/themes/amelia.min.css create mode 100644 public/css/themes/cerulean.min.css create mode 100644 public/css/themes/cosmo.min.css create mode 100644 public/css/themes/cyborg.min.css create mode 100644 public/css/themes/flatly.min.css create mode 100644 public/css/themes/journal.min.css create mode 100644 public/css/themes/readable.min.css create mode 100644 public/css/themes/simplex.min.css create mode 100644 public/css/themes/slate.min.css create mode 100644 public/css/themes/spacelab.min.css create mode 100644 public/css/themes/united.min.css create mode 100644 public/css/themes/yeti.min.css create mode 100644 public/css/typeahead.js-bootstrap.css create mode 100644 public/error_log create mode 100644 public/favicon.gif create mode 100644 public/fonts/.empty create mode 100644 public/fonts/FontAwesome.otf create mode 100644 public/fonts/fontawesome-webfont.eot create mode 100644 public/fonts/fontawesome-webfont.svg create mode 100644 public/fonts/fontawesome-webfont.ttf create mode 100644 public/fonts/fontawesome-webfont.woff create mode 100644 public/fonts/socicon-webfont.eot create mode 100644 public/fonts/socicon-webfont.svg create mode 100644 public/fonts/socicon-webfont.ttf create mode 100644 public/fonts/socicon-webfont.woff create mode 100644 public/images/AcceptPaymentsOnline.png create mode 100644 public/images/AdjustablePaymentTerms.png create mode 100644 public/images/AlertsWhenInvoicesViewed.png create mode 100644 public/images/BeautifulTemplates.png create mode 100644 public/images/BestInClassSecurity.png create mode 100644 public/images/CloneInvoices.png create mode 100644 public/images/CloudBasedApp.png create mode 100644 public/images/CustomizeInvoices.png create mode 100644 public/images/EstimatesProForma.png create mode 100644 public/images/FreeInvoicing.png create mode 100644 public/images/GitHub.png create mode 100644 public/images/ImportExportRecords.png create mode 100644 public/images/InTuitiveEditingInterface.png create mode 100644 public/images/IntegrateWithPaymentGateways.png create mode 100644 public/images/InvoiceClientsViaEmail.png create mode 100644 public/images/LivePDFCreation.png create mode 100644 public/images/ManualAutomaticInvoiceNumbers.png create mode 100644 public/images/MultilingualSupport.png create mode 100644 public/images/MultipleCurrencySupport.png create mode 100644 public/images/MultipleTaxSettings.png create mode 100644 public/images/OpenSource.png create mode 100644 public/images/PaymentTracking.png create mode 100644 public/images/PersonalizeInvoiceColor.png create mode 100644 public/images/PrintablePDFInvoices.png create mode 100644 public/images/RecurringInvoiceProfiles.png create mode 100644 public/images/SelfHostedAvailable.png create mode 100644 public/images/Thumbs.db create mode 100644 public/images/about1.jpg create mode 100644 public/images/about1@2x.jpg create mode 100644 public/images/about2.jpg create mode 100644 public/images/about2@2x.jpg create mode 100644 public/images/activeclients.png create mode 100644 public/images/activeclients@2x.png create mode 100644 public/images/apple-touch-icon-114x114-precomposed.png create mode 100644 public/images/apple-touch-icon-144x144-precomposed.png create mode 100644 public/images/apple-touch-icon-57x57-precomposed.png create mode 100644 public/images/apple-touch-icon-72x72-precomposed.png create mode 100644 public/images/apple-touch-icon.png create mode 100644 public/images/benjacobson.jpg create mode 100644 public/images/bg-blue.jpg create mode 100644 public/images/clients.png create mode 100644 public/images/clients@2x.png create mode 100644 public/images/credit_cards/Test-AmericanExpress-Icon.png create mode 100644 public/images/credit_cards/Test-Diners-Icon.png create mode 100644 public/images/credit_cards/Test-Discover-Icon.png create mode 100644 public/images/credit_cards/Test-MasterCard-Icon.png create mode 100644 public/images/credit_cards/Test-Visa-Icon.png create mode 100644 public/images/designs/business.png create mode 100644 public/images/designs/business_thumb.png create mode 100644 public/images/designs/creative.png create mode 100644 public/images/designs/creative_thumb.png create mode 100644 public/images/designs/elegant.png create mode 100644 public/images/designs/elegant_thumb.png create mode 100644 public/images/designs/hipster.png create mode 100644 public/images/designs/hipster_thumb.png create mode 100644 public/images/designs/photo.png create mode 100644 public/images/designs/photo_thumb.png create mode 100644 public/images/designs/playful.png create mode 100644 public/images/designs/playful_thumb.png create mode 100644 public/images/devices-2.png create mode 100644 public/images/devices.png create mode 100644 public/images/devices3.png create mode 100644 public/images/facebook.jpg create mode 100644 public/images/features1.jpg create mode 100644 public/images/features2.jpg create mode 100644 public/images/features3.jpg create mode 100644 public/images/features4.jpg create mode 100644 public/images/features5.jpg create mode 100644 public/images/footer-logo.png create mode 100644 public/images/gateways/Thumbs.db create mode 100644 public/images/gateways/logo_AuthorizeNet_AIM.png create mode 100644 public/images/gateways/logo_BeanStream.png create mode 100644 public/images/gateways/logo_FirstData_Connect.png create mode 100644 public/images/gateways/logo_PayPal_Pro.png create mode 100644 public/images/gateways/logo_TwoCheckout.png create mode 100644 public/images/gateways/logo_iTransact.png create mode 100644 public/images/hero-bg-1.jpg create mode 100644 public/images/hero-bg-2.jpg create mode 100644 public/images/hero-bg-3.jpg create mode 100644 public/images/hero-bg-4.jpg create mode 100644 public/images/hero-bg-contact.jpg create mode 100644 public/images/hero-bg-faq.jpg create mode 100644 public/images/hero-bg-plans.jpg create mode 100644 public/images/hero-bg-secure-pay.jpg create mode 100644 public/images/hero-bg-testi.jpg create mode 100644 public/images/hero-faq@2x.png create mode 100644 public/images/hex-facebook.png create mode 100644 public/images/hex-github.png create mode 100644 public/images/hex-gplus.png create mode 100644 public/images/hex-linkedin.png create mode 100644 public/images/hex-pinterest.png create mode 100644 public/images/hex-rss.png create mode 100644 public/images/hex-twitter.png create mode 100644 public/images/hillelcoren.jpg create mode 100644 public/images/icon-about.png create mode 100644 public/images/icon-about@2x.png create mode 100644 public/images/icon-contact.png create mode 100644 public/images/icon-contact@2x.png create mode 100644 public/images/icon-faq.png create mode 100644 public/images/icon-features.png create mode 100644 public/images/icon-features@2x.png create mode 100644 public/images/icon-free.png create mode 100644 public/images/icon-free2.png create mode 100644 public/images/icon-free@2x.png create mode 100644 public/images/icon-login.png create mode 100644 public/images/icon-login@2x.png create mode 100644 public/images/icon-opensource.png create mode 100644 public/images/icon-opensource@2x.png create mode 100644 public/images/icon-payment.png create mode 100644 public/images/icon-payment@2x.png create mode 100644 public/images/icon-pdf.png create mode 100644 public/images/icon-pdf@2x.png create mode 100644 public/images/icon-plans.png create mode 100644 public/images/icon-plans@2x.png create mode 100644 public/images/icon-secure-footer.png create mode 100644 public/images/icon-secure-footer@2x.png create mode 100644 public/images/icon-secure-pay.png create mode 100644 public/images/icon-secure-pay@2x.png create mode 100644 public/images/icon-secure.png create mode 100644 public/images/icon-secure@2x.png create mode 100644 public/images/icon-shield.png create mode 100644 public/images/icon-testi.png create mode 100644 public/images/icon-testi@2x.png create mode 100644 public/images/instagram.svg create mode 100644 public/images/invoiceninja-logo.png create mode 100644 public/images/invoiceninja-logo@2x.png create mode 100644 public/images/laptopwicon.jpg create mode 100644 public/images/lightbox/close.png create mode 100644 public/images/lightbox/loading.gif create mode 100644 public/images/lightbox/next.png create mode 100644 public/images/lightbox/prev.png create mode 100644 public/images/linkedin.svg create mode 100644 public/images/me.svg create mode 100644 public/images/opensource-footer.png create mode 100644 public/images/pro-plan-chart.png create mode 100644 public/images/providers.png create mode 100644 public/images/razikantorp.jpg create mode 100644 public/images/report_logo1.jpg create mode 100644 public/images/report_logo2.jpg create mode 100644 public/images/report_logo3.jpg create mode 100644 public/images/shalomstark.jpg create mode 100644 public/images/social.jpg create mode 100644 public/images/social/facebook.png create mode 100644 public/images/social/facebook.svg create mode 100644 public/images/social/github.png create mode 100644 public/images/social/twitter.png create mode 100644 public/images/social/twitter.svg create mode 100644 public/images/sort_asc.png create mode 100644 public/images/sort_asc_disabled.png create mode 100644 public/images/sort_both.png create mode 100644 public/images/sort_desc.png create mode 100644 public/images/sort_desc_disabled.png create mode 100644 public/images/ssl-footer.png create mode 100644 public/images/totalincome.png create mode 100644 public/images/totalincome@2x.png create mode 100644 public/images/totalinvoices.png create mode 100644 public/images/totalinvoices@2x.png create mode 100644 public/images/twitter.svg create mode 100644 public/images/website.svg create mode 100644 public/js/Chart.js create mode 100644 public/js/bootstrap-combobox.js create mode 100644 public/js/bootstrap.js create mode 100644 public/js/bootstrap.min.js create mode 100644 public/js/built.public.js create mode 100644 public/js/compatibility.js create mode 100644 public/js/d3.min.js create mode 100644 public/js/jspdf.min.js create mode 100644 public/js/jspdf.plugin.split_text_to_size.js create mode 100644 public/js/jspdf.source.js create mode 100644 public/js/lightbox.min.js create mode 100644 public/js/pdf.js create mode 100644 public/js/pdf_viewer.js create mode 100644 public/js/pdf_viewer.worker.js create mode 100644 public/js/retina-1.1.0.min.js create mode 100644 public/js/script.js create mode 100644 public/js/simpleexpand.js create mode 100644 public/js/stacktrace.js create mode 100644 public/js/typedarray.js create mode 100644 public/js/valign.js create mode 100644 public/logo/.gitkeep create mode 100644 public/logo/zg4ylmzDkdkPOT8yoKQw9LTWaoZJx79h.jpg create mode 100644 resources/lang/da/pagination.php create mode 100644 resources/lang/da/public.php create mode 100644 resources/lang/da/reminders.php create mode 100644 resources/lang/da/texts.php create mode 100644 resources/lang/da/validation.php create mode 100644 resources/lang/de/pagination.php create mode 100644 resources/lang/de/public.php create mode 100644 resources/lang/de/reminders.php create mode 100644 resources/lang/de/texts.php create mode 100644 resources/lang/de/validation.php create mode 100644 resources/lang/en/public.php create mode 100644 resources/lang/en/reminders.php create mode 100644 resources/lang/en/texts.php create mode 100644 resources/lang/es/pagination.php create mode 100644 resources/lang/es/public.php create mode 100644 resources/lang/es/reminders.php create mode 100644 resources/lang/es/texts.php create mode 100644 resources/lang/es/validation.php create mode 100644 resources/lang/fr/pagination.php create mode 100644 resources/lang/fr/public.php create mode 100644 resources/lang/fr/reminders.php create mode 100644 resources/lang/fr/texts.php create mode 100644 resources/lang/fr/validation.php create mode 100644 resources/lang/it/pagination.php create mode 100644 resources/lang/it/public.php create mode 100644 resources/lang/it/reminders.php create mode 100644 resources/lang/it/texts.php create mode 100644 resources/lang/it/validation.php create mode 100644 resources/lang/lt/pagination.php create mode 100644 resources/lang/lt/public.php create mode 100644 resources/lang/lt/reminders.php create mode 100644 resources/lang/lt/texts.php create mode 100644 resources/lang/lt/validation.php create mode 100644 resources/lang/nb_NO/pagination.php create mode 100644 resources/lang/nb_NO/public.php create mode 100644 resources/lang/nb_NO/reminders.php create mode 100644 resources/lang/nb_NO/texts.php create mode 100644 resources/lang/nb_NO/validation.php create mode 100644 resources/lang/nl/pagination.php create mode 100644 resources/lang/nl/public.php create mode 100644 resources/lang/nl/reminders.php create mode 100644 resources/lang/nl/texts.php create mode 100644 resources/lang/nl/validation.php create mode 100644 resources/lang/pt_BR/pagination.php create mode 100644 resources/lang/pt_BR/public.php create mode 100644 resources/lang/pt_BR/reminders.php create mode 100644 resources/lang/pt_BR/texts.php create mode 100644 resources/lang/pt_BR/validation.php create mode 100644 resources/views/accounts/account_gateway.blade.php create mode 100644 resources/views/accounts/details.blade.php create mode 100644 resources/views/accounts/email_templates.blade.php create mode 100644 resources/views/accounts/export.blade.php create mode 100644 resources/views/accounts/import_export.blade.php create mode 100644 resources/views/accounts/import_map.blade.php create mode 100644 resources/views/accounts/invoice_design.blade.php create mode 100644 resources/views/accounts/invoice_settings.blade.php create mode 100644 resources/views/accounts/nav.blade.php create mode 100644 resources/views/accounts/nav_advanced.blade.php create mode 100644 resources/views/accounts/notifications.blade.php create mode 100644 resources/views/accounts/payments.blade.php create mode 100644 resources/views/accounts/product.blade.php create mode 100644 resources/views/accounts/products.blade.php create mode 100644 resources/views/accounts/token.blade.php create mode 100644 resources/views/accounts/token_management.blade.php create mode 100644 resources/views/accounts/user_management.blade.php create mode 100644 resources/views/client.blade.php create mode 100644 resources/views/clients/edit.blade.php create mode 100644 resources/views/clients/show.blade.php create mode 100644 resources/views/coming_soon.blade.php create mode 100644 resources/views/credits/edit.blade.php create mode 100644 resources/views/dashboard.blade.php create mode 100644 resources/views/datatable.blade.php create mode 100644 resources/views/emails/auth/reminder.blade.php create mode 100644 resources/views/emails/confirm_html.blade.php create mode 100644 resources/views/emails/confirm_text.blade.php create mode 100644 resources/views/emails/contact_html.blade.php create mode 100644 resources/views/emails/contact_text.blade.php create mode 100644 resources/views/emails/error.blade.php create mode 100644 resources/views/emails/invoice_html.blade.php create mode 100644 resources/views/emails/invoice_paid_html.blade.php create mode 100644 resources/views/emails/invoice_paid_text.blade.php create mode 100644 resources/views/emails/invoice_sent_html.blade.php create mode 100644 resources/views/emails/invoice_sent_text.blade.php create mode 100644 resources/views/emails/invoice_text.blade.php create mode 100644 resources/views/emails/invoice_viewed_html.blade.php create mode 100644 resources/views/emails/invoice_viewed_text.blade.php create mode 100644 resources/views/emails/license_confirmation_html.blade.php create mode 100644 resources/views/emails/license_confirmation_text.blade.php create mode 100644 resources/views/emails/passwordreset_html.blade.php create mode 100644 resources/views/emails/payment_confirmation_html.blade.php create mode 100644 resources/views/emails/payment_confirmation_text.blade.php create mode 100644 resources/views/emails/view_action.blade.php create mode 100644 resources/views/error.blade.php create mode 100644 resources/views/header.blade.php create mode 100644 resources/views/invoices/deleted.blade.php create mode 100644 resources/views/invoices/edit.blade.php create mode 100644 resources/views/invoices/history.blade.php create mode 100644 resources/views/invoices/pdf.blade.php create mode 100644 resources/views/invoices/view.blade.php create mode 100644 resources/views/list.blade.php create mode 100644 resources/views/master.blade.php create mode 100644 resources/views/payments/edit.blade.php create mode 100644 resources/views/payments/payment.blade.php create mode 100644 resources/views/plans.blade.php create mode 100644 resources/views/public/header.blade.php create mode 100644 resources/views/public/license.blade.php create mode 100644 resources/views/public/terms.blade.php create mode 100644 resources/views/public_list.blade.php create mode 100644 resources/views/reports/d3.blade.php create mode 100644 resources/views/reports/report_builder.blade.php create mode 100644 resources/views/script.blade.php create mode 100644 resources/views/secure_payment.blade.php create mode 100644 resources/views/setup.blade.php create mode 100644 resources/views/timesheets/edit.blade.php create mode 100644 resources/views/users/edit.blade.php create mode 100644 resources/views/users/forgot_password.blade.php create mode 100644 resources/views/users/login.blade.php create mode 100644 resources/views/users/reset_password.blade.php create mode 100644 tests/TimesheetUtilsTest.php create mode 100644 tests/data/Demo/demo.response.json diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php new file mode 100644 index 000000000000..501f95b43e4f --- /dev/null +++ b/app/Console/Commands/CheckData.php @@ -0,0 +1,266 @@ + + + Limits the script to a single client + +--fix=true + + By default the script only checks for errors, adding this option + makes the script apply the fixes. + +*/ + + +class CheckData extends Command { + + protected $name = 'ninja:check-data'; + protected $description = 'Check/fix data'; + + public function fire() + { + $this->info(date('Y-m-d') . ' Running CheckData...'); + $today = new DateTime(); + + if (!$this->option('client_id')) { + // update client deletion activities with the client's current balance + $activities = DB::table('activities') + ->join('clients', 'clients.id', '=', 'activities.client_id') + ->where('activities.activity_type_id', '=', ACTIVITY_TYPE_DELETE_CLIENT) + ->where('activities.balance', '=', 0) + ->where('clients.balance', '!=', 0) + ->get(['activities.id', 'clients.balance']); + + $this->info(count($activities) . ' delete client activities with zero balance'); + + if ($this->option('fix') == 'true') { + foreach ($activities as $activity) { + DB::table('activities') + ->where('id', $activity->id) + ->update(['balance' => $activity->balance]); + } + } + + // update client paid_to_date value + $clients = DB::table('clients') + ->join('payments', 'payments.client_id', '=', 'clients.id') + ->join('invoices', 'invoices.id', '=', 'payments.invoice_id') + ->where('payments.is_deleted', '=', 0) + ->where('invoices.is_deleted', '=', 0) + ->groupBy('clients.id') + ->havingRaw('clients.paid_to_date != sum(payments.amount) and clients.paid_to_date != 999999999.9999') + ->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(payments.amount) as amount')]); + $this->info(count($clients) . ' clients with incorrect paid to date'); + + if ($this->option('fix') == 'true') { + foreach ($clients as $client) { + DB::table('clients') + ->where('id', $client->id) + ->update(['paid_to_date' => $client->amount]); + } + } + } + + // find all clients where the balance doesn't equal the sum of the outstanding invoices + $clients = DB::table('clients') + ->join('invoices', 'invoices.client_id', '=', 'clients.id') + ->join('accounts', 'accounts.id', '=', 'clients.account_id'); + + if ($this->option('client_id')) { + $clients->where('clients.id', '=', $this->option('client_id')); + } else { + $clients->where('invoices.is_deleted', '=', 0) + ->where('invoices.is_quote', '=', 0) + ->where('invoices.is_recurring', '=', 0) + ->havingRaw('abs(clients.balance - sum(invoices.balance)) > .01 and clients.balance != 999999999.9999'); + } + + $clients = $clients->groupBy('clients.id', 'clients.balance', 'clients.created_at') + ->orderBy('clients.id', 'DESC') + ->get(['clients.id', 'clients.balance', 'clients.paid_to_date']); + $this->info(count($clients) . ' clients with incorrect balance/activities'); + + foreach ($clients as $client) { + $this->info("=== Client:{$client->id} Balance:{$client->balance} ==="); + $foundProblem = false; + $lastBalance = 0; + $clientFix = false; + $activities = DB::table('activities') + ->where('client_id', '=', $client->id) + ->orderBy('activities.id') + ->get(['activities.id', 'activities.created_at', 'activities.activity_type_id', 'activities.message', 'activities.adjustment', 'activities.balance', 'activities.invoice_id']); + //$this->info(var_dump($activities)); + + foreach ($activities as $activity) { + + $activityFix = false; + + if ($activity->invoice_id) { + $invoice = DB::table('invoices') + ->where('id', '=', $activity->invoice_id) + ->first(['invoices.amount', 'invoices.is_recurring', 'invoices.is_quote', 'invoices.deleted_at', 'invoices.id', 'invoices.is_deleted']); + + // Check if this invoice was once set as recurring invoice + if (!$invoice->is_recurring && DB::table('invoices') + ->where('recurring_invoice_id', '=', $activity->invoice_id) + ->first(['invoices.id'])) { + $invoice->is_recurring = 1; + + // **Fix for enabling a recurring invoice to be set as non-recurring** + if ($this->option('fix') == 'true') { + DB::table('invoices') + ->where('id', $invoice->id) + ->update(['is_recurring' => 1]); + } + } + } + + + if ($activity->activity_type_id == ACTIVITY_TYPE_CREATE_INVOICE + || $activity->activity_type_id == ACTIVITY_TYPE_CREATE_QUOTE) { + + // Get original invoice amount + $update = DB::table('activities') + ->where('invoice_id', '=', $activity->invoice_id) + ->where('activity_type_id', '=', ACTIVITY_TYPE_UPDATE_INVOICE) + ->orderBy('id') + ->first(['json_backup']); + if ($update) { + $backup = json_decode($update->json_backup); + $invoice->amount = floatval($backup->amount); + } + + $noAdjustment = $activity->activity_type_id == ACTIVITY_TYPE_CREATE_INVOICE + && $activity->adjustment == 0 + && $invoice->amount > 0; + + // **Fix for allowing converting a recurring invoice to a normal one without updating the balance** + if ($noAdjustment && !$invoice->is_quote && !$invoice->is_recurring) { + $this->info("No adjustment for new invoice:{$activity->invoice_id} amount:{$invoice->amount} isQuote:{$invoice->is_quote} isRecurring:{$invoice->is_recurring}"); + $foundProblem = true; + $clientFix += $invoice->amount; + $activityFix = $invoice->amount; + // **Fix for updating balance when creating a quote or recurring invoice** + } elseif ($activity->adjustment != 0 && ($invoice->is_quote || $invoice->is_recurring)) { + $this->info("Incorrect adjustment for new invoice:{$activity->invoice_id} adjustment:{$activity->adjustment} isQuote:{$invoice->is_quote} isRecurring:{$invoice->is_recurring}"); + $foundProblem = true; + $clientFix -= $activity->adjustment; + $activityFix = 0; + } + } elseif ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_INVOICE) { + // **Fix for updating balance when deleting a recurring invoice** + if ($activity->adjustment != 0 && $invoice->is_recurring) { + $this->info("Incorrect adjustment for deleted invoice adjustment:{$activity->adjustment}"); + $foundProblem = true; + if ($activity->balance != $lastBalance) { + $clientFix -= $activity->adjustment; + } + $activityFix = 0; + } + } elseif ($activity->activity_type_id == ACTIVITY_TYPE_ARCHIVE_INVOICE) { + // **Fix for updating balance when archiving an invoice** + if ($activity->adjustment != 0 && !$invoice->is_recurring) { + $this->info("Incorrect adjustment for archiving invoice adjustment:{$activity->adjustment}"); + $foundProblem = true; + $activityFix = 0; + $clientFix += $activity->adjustment; + } + } elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_INVOICE) { + // **Fix for updating balance when updating recurring invoice** + if ($activity->adjustment != 0 && $invoice->is_recurring) { + $this->info("Incorrect adjustment for updated recurring invoice adjustment:{$activity->adjustment}"); + $foundProblem = true; + $clientFix -= $activity->adjustment; + $activityFix = 0; + } + } elseif ($activity->activity_type_id == ACTIVITY_TYPE_UPDATE_QUOTE) { + // **Fix for updating balance when updating a quote** + if ($activity->balance != $lastBalance) { + $this->info("Incorrect adjustment for updated quote adjustment:{$activity->adjustment}"); + $foundProblem = true; + $clientFix += $lastBalance - $activity->balance; + $activityFix = 0; + } + } else if ($activity->activity_type_id == ACTIVITY_TYPE_DELETE_PAYMENT) { + // **Fix for delting payment after deleting invoice** + if ($activity->adjustment != 0 && $invoice->is_deleted && $activity->created_at > $invoice->deleted_at) { + $this->info("Incorrect adjustment for deleted payment adjustment:{$activity->adjustment}"); + $foundProblem = true; + $activityFix = 0; + $clientFix -= $activity->adjustment; + } + } + + if ($activityFix !== false || $clientFix !== false) { + $data = [ + 'balance' => $activity->balance + $clientFix + ]; + + if ($activityFix !== false) { + $data['adjustment'] = $activityFix; + } + + if ($this->option('fix') == 'true') { + DB::table('activities') + ->where('id', $activity->id) + ->update($data); + } + } + + $lastBalance = $activity->balance; + } + + if ($clientFix !== false) { + $balance = $activity->balance + $clientFix; + $data = ['balance' => $balance]; + $this->info("Corrected balance:{$balance}"); + if ($this->option('fix') == 'true') { + DB::table('clients') + ->where('id', $client->id) + ->update($data); + } + } + } + + $this->info('Done'); + } + + protected function getArguments() + { + return array( + //array('example', InputArgument::REQUIRED, 'An example argument.'), + ); + } + + protected function getOptions() + { + return array( + array('fix', null, InputOption::VALUE_OPTIONAL, 'Fix data', null), + array('client_id', null, InputOption::VALUE_OPTIONAL, 'Client id', null), + ); + } + +} \ No newline at end of file diff --git a/app/Console/Commands/CreateRandomData.php b/app/Console/Commands/CreateRandomData.php new file mode 100644 index 000000000000..9fe826cc9b5b --- /dev/null +++ b/app/Console/Commands/CreateRandomData.php @@ -0,0 +1,88 @@ +info(date('Y-m-d') . ' Running CreateRandomData...'); + + $user = User::first(); + + if (!$user) { + $this->error("Error: please create user account by logging in"); + return; + } + + $productNames = ['Arkansas', 'New York', 'Arizona', 'California', 'Colorado', 'Alabama', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'Alaska', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming']; + $clientNames = ['IBM', 'Nestle', 'Mitsubishi UFJ Financial', 'Vodafone', 'Eni', 'Procter & Gamble', 'Johnson & Johnson', 'American International Group', 'Banco Santander', 'BHP Billiton', 'Pfizer', 'Itaú Unibanco Holding', 'Ford Motor', 'BMW Group', 'Commonwealth Bank', 'EDF', 'Statoil', 'Google', 'Siemens', 'Novartis', 'Royal Bank of Canada', 'Sumitomo Mitsui Financial', 'Comcast', 'Sberbank', 'Goldman Sachs Group', 'Westpac Banking Group', 'Nippon Telegraph & Tel', 'Ping An Insurance Group', 'Banco Bradesco', 'Anheuser-Busch InBev', 'Bank of Communications', 'China Life Insurance', 'General Motors', 'Telefónica', 'MetLife', 'Honda Motor', 'Enel', 'BASF', 'Softbank', 'National Australia Bank', 'ANZ', 'ConocoPhillips', 'TD Bank Group', 'Intel', 'UBS', 'Hewlett-Packard', 'Coca-Cola', 'Cisco Systems', 'UnitedHealth Group', 'Boeing', 'Zurich Insurance Group', 'Hyundai Motor', 'Sanofi', 'Credit Agricole', 'United Technologies', 'Roche Holding', 'Munich Re', 'PepsiCo', 'Oracle', 'Bank of Nova Scotia']; + + foreach ($productNames as $i => $value) { + $product = Product::createNew($user); + $product->id = $i+1; + $product->product_key = $value; + $product->save(); + } + + foreach ($clientNames as $i => $value) { + $client = Client::createNew($user); + $client->name = $value; + $client->save(); + + $contact = Contact::createNew($user); + $contact->email = "client@aol.com"; + $contact->is_primary = 1; + $client->contacts()->save($contact); + + $numInvoices = rand(1, 25); + if ($numInvoices == 4 || $numInvoices == 10 || $numInvoices == 25) { + // leave these + } else if ($numInvoices % 3 == 0) { + $numInvoices = 1; + } else if ($numInvoices > 10) { + $numInvoices = $numInvoices % 2; + } + + $paidUp = rand(0, 1) == 1; + + for ($j=1; $j<=$numInvoices; $j++) { + + $price = rand(10, 1000); + if ($price < 900) { + $price = rand(10, 150); + } + + $invoice = Invoice::createNew($user); + $invoice->invoice_number = $user->account->getNextInvoiceNumber(); + $invoice->amount = $invoice->balance = $price; + $invoice->created_at = date('Y-m-d', strtotime(date("Y-m-d") . ' - ' . rand(1, 100) . ' days')); + $client->invoices()->save($invoice); + + $productId = rand(0, 40); + if ($productId > 20) { + $productId = ($productId % 2) + rand(0, 2); + } + + $invoiceItem = InvoiceItem::createNew($user); + $invoiceItem->product_id = $productId+1; + $invoiceItem->product_key = $productNames[$invoiceItem->product_id]; + $invoiceItem->cost = $invoice->amount; + $invoiceItem->qty = 1; + $invoice->invoice_items()->save($invoiceItem); + + if ($paidUp || rand(0,2) > 1) { + $payment = Payment::createNew($user); + $payment->invoice_id = $invoice->id; + $payment->amount = $invoice->amount; + $client->payments()->save($payment); + } + } + } + } +} \ No newline at end of file diff --git a/app/Console/Commands/ImportTimesheetData.php b/app/Console/Commands/ImportTimesheetData.php new file mode 100644 index 000000000000..450b02b1f4c8 --- /dev/null +++ b/app/Console/Commands/ImportTimesheetData.php @@ -0,0 +1,335 @@ +info(date('Y-m-d') . ' Running ImportTimesheetData...'); + + // Seems we are using the console timezone + DB::statement("SET SESSION time_zone = '+00:00'"); + + // Get the Unix epoch + $unix_epoch = new DateTime('1970-01-01T00:00:01', new DateTimeZone("UTC")); + + // Create some initial sources we can test with + $user = User::first(); + if (!$user) { + $this->error("Error: please create user account by logging in"); + return; + } + + // TODO: Populate with own test data until test data has been created + // Truncate the tables + /*$this->info("Truncate tables"); + DB::statement('SET FOREIGN_KEY_CHECKS=0;'); + DB::table('projects')->truncate(); + DB::table('project_codes')->truncate(); + DB::table('timesheet_event_sources')->truncate(); + DB::table('timesheet_events')->truncate(); + DB::statement('SET FOREIGN_KEY_CHECKS=1;'); */ + + if (!Project::find(1)) { + $this->info("Import old project codes"); + $oldcodes = json_decode(file_get_contents("/home/tlb/git/itktime/codes.json"), true); + foreach ($oldcodes as $name => $options) { + $project = Project::createNew($user); + $project->name = $options['description']; + $project->save(); + + $code = ProjectCode::createNew($user); + $code->name = $name; + $project->codes()->save($code); + } + } + + if (!TimesheetEventSource::find(1)) { + $this->info("Import old event sources"); + + $oldevent_sources = json_decode(file_get_contents("/home/tlb/git/itktime/employes.json"), true); + + foreach ($oldevent_sources as $source) { + $event_source = TimesheetEventSource::createNew($user); + $event_source->name = $source['name']; + $event_source->url = $source['url']; + $event_source->owner = $source['owner']; + $event_source->type = 'ical'; + //$event_source->from_date = new DateTime("2009-01-01"); + $event_source->save(); + } + } + + // Add all URL's to Curl + $this->info("Download ICAL feeds"); + $T = new Timer; + $T->start(); + + $T->lap("Get Event Sources"); + $event_sources = TimesheetEventSource::all(); // TODO: Filter based on ical feeds + + $T->lap("Get ICAL responses"); + $urls = []; + $event_sources->map(function($item) use(&$urls) { + $urls[] = $item->url; + }); + $icalresponses = TimesheetUtils::curlGetUrls($urls); + + $T->lap("Fetch all codes so we can do a quick lookup"); + $codes = array(); + ProjectCode::all()->map(function($item) use(&$codes) { + $codes[$item->name] = $item; + }); + + $this->info("Start parsing ICAL files"); + foreach ($event_sources as $i => $event_source) { + if (!is_array($icalresponses[$i])) { + $this->info("Find events in " . $event_source->name); + file_put_contents("/tmp/" . $event_source->name . ".ical", $icalresponses[$i]); // FIXME: Remove + $T->lap("Split on events for ".$event_source->name); + + // Check if the file is complete + if(!preg_match("/^\s*BEGIN:VCALENDAR/", $icalresponses[$i]) || !preg_match("/END:VCALENDAR\s*$/", $icalresponses[$i])) { + $this->error("Missing start or end of ical file"); + continue; + } + + // Extract all events from ical file + if (preg_match_all('/BEGIN:VEVENT\r?\n(.+?)\r?\nEND:VEVENT/s', $icalresponses[$i], $icalmatches)) { + $this->info("Found ".(count($icalmatches[1])-1)." events"); + $T->lap("Fetch all uids and last updated at so we can do a quick lookup to find out if the event needs to be updated in the database".$event_source->name); + $uids = []; + $org_deleted = []; // Create list of events we know are deleted on the source, but still have in the db + $event_source->events()->withTrashed()->get(['uid', 'org_updated_at', 'updated_data_at', 'org_deleted_at'])->map(function($item) use(&$uids, &$org_deleted) { + if($item->org_updated_at > $item->updated_data_at) { + $uids[$item->uid] = $item->org_updated_at; + } else { + $uids[$item->uid] = $item->updated_data_at; + } + if($item->org_deleted_at > '0000-00-00 00:00:00') { + $org_deleted[$item->uid] = $item->updated_data_at; + } + }); + $deleted = $uids; + + // Loop over all the found events + $T->lap("Parse events for ".$event_source->name); + foreach ($icalmatches[1] as $eventstr) { + //print "---\n"; + //print $eventstr."\n"; + //print "---\n"; + //$this->info("Match event"); + # Fix lines broken by 76 char limit + $eventstr = preg_replace('/\r?\n\s/s', '', $eventstr); + //$this->info("Parse data"); + $data = TimesheetUtils::parseICALEvent($eventstr); + if ($data) { + // Extract code for summary so we only import events we use + list($codename, $tags, $title) = TimesheetUtils::parseEventSummary($data['summary']); + if ($codename != null) { + $event = TimesheetEvent::createNew($user); + + // Copy data to new object + $event->uid = $data['uid']; + $event->summary = $title; + $event->org_data = $eventstr; + $event->org_code = $codename; + if(isset($data['description'])) { + $event->description = $data['description']; + } + $event->owner = $event_source->owner; + $event->timesheet_event_source_id = $event_source->id; + if (isset($codes[$codename])) { + $event->project_id = $codes[$codename]->project_id; + $event->project_code_id = $codes[$codename]->id; + } + if (isset($data['location'])) { + $event->location = $data['location']; + } + + + # Add RECURRENCE-ID to the UID to make sure the event is unique + if (isset($data['recurrence-id'])) { + $event->uid .= "::".$data['recurrence-id']; + } + + //TODO: Add support for recurring event, make limit on number of events created : https://github.com/tplaner/When + // Bail on RRULE as we don't support that + if(isset($event['rrule'])) { + die("Recurring event not supported: {$event['summary']} - {$event['dtstart']}"); + } + + // Convert to DateTime objects + foreach (['dtstart', 'dtend', 'created', 'last-modified'] as $key) { + // Parse and create DataTime object from ICAL format + list($dt, $timezone) = TimesheetUtils::parseICALDate($data[$key]); + + // Handle bad dates in created and last-modified + if ($dt == null || $dt < $unix_epoch) { + if ($key == 'created' || $key == 'last-modified') { + $dt = $unix_epoch; // Default to UNIX epoch + $event->import_warning = "Could not parse date for $key: '" . $data[$key] . "' so default to UNIX Epoc\n"; + } else { + $event->import_error = "Could not parse date for $key: '" . $data[$key] . "' so default to UNIX Epoc\n"; + // TODO: Bail on this event or write to error table + die("Could not parse date for $key: '" . $data[$key] . "'\n"); + } + } + + // Assign DateTime object to + switch ($key) { + case 'dtstart': + $event->start_date = $dt; + if($timezone) { + $event->org_start_date_timezone = $timezone; + } + break; + case 'dtend': + $event->end_date = $dt; + if($timezone) { + $event->org_end_date_timezone = $timezone; + } + break; + case 'created': + $event->org_created_at = $dt; + break; + case 'last-modified': + $event->org_updated_at = $dt; + break; + } + } + + // Check that we are witin the range + if ($event_source->from_date != null) { + $from_date = new DateTime($event_source->from_date, new DateTimeZone('UTC')); + if ($from_date > $event->end_date) { + // Skip this event + echo "Skiped: $codename: $title\n"; + continue; + } + } + + // Calculate number of hours + $di = $event->end_date->diff($event->start_date); + $event->hours = $di->h + $di->i / 60; + + // Check for events we already have + if (isset($uids[$event->uid])) { + // Remove from deleted list + unset($deleted[$event->uid]); + + // See if the event has been updated compared to the one in the database + $db_event_org_updated_at = new DateTime($uids[$event->uid], new DateTimeZone('UTC')); + + // Check if same or older version of new event then skip + if($event->org_updated_at <= $db_event_org_updated_at) { + // SKIP + + // Updated version of the event + } else { + // Get the old event from the database + /* @var $db_event TimesheetEvent */ + $db_event = $event_source->events()->where('uid', $event->uid)->firstOrFail(); + $changes = $db_event->toChangesArray($event); + + // Make sure it's more than the org_updated_at that has been changed + if (count($changes) > 1) { + // Check if we have manually changed the event in the database or used it in a timesheet + if ($db_event->manualedit || $db_event->timesheet) { + $this->info("Updated Data"); + $db_event->updated_data = $event->org_data; + $db_event->updated_data_at = $event->org_updated_at; + + // Update the db_event with the changes + } else { + $this->info("Updated Event"); + foreach ($changes as $key => $value) { + if($value == null) { + unset($db_event->$key); + } else { + $db_event->$key = $value; + } + } + } + + } else { + $this->info("Nothing Changed"); + // Nothing has been changed so update the org_updated_at + $db_event->org_updated_at = $changes['org_updated_at']; + } + $db_event->save(); + } + + } else { + try { + $this->info("New event: " . $event->summary); + $event->save(); + + } catch (Exception $ex) { + echo "'" . $event->summary . "'\n"; + var_dump($data); + echo $ex->getMessage(); + echo $ex->getTraceAsString(); + exit(0); + } + } + // Add new uid to know uids + $uids[$event->uid] = $event->org_updated_at; + } + } + } + // Delete events in database that no longer exists in the source + foreach($deleted as $uid => $lastupdated_date) { + // Skip we already marked this a deleted + if(isset($org_deleted[$uid])) { + unset($deleted[$uid]); + continue; + } + // Delete or update event in db + $db_event = $event_source->events()->where('uid', $uid)->firstOrFail(); + if($db_event->timesheet_id === null && !$db_event->manualedit) { + // Hard delete if this event has not been assigned to a timesheet or have been manually edited + $db_event->forceDelete(); + + } else { + // Mark as deleted in source + $db_event->org_deleted_at = new DateTime('now', new DateTimeZone('UTC')); + $db_event->save(); + + } + } + $this->info("Deleted ".count($deleted). " events"); + + } else { + // TODO: Parse error + } + + } else { + // TODO: Curl Error + } + } + + foreach($T->end()['laps'] as $lap) { + echo number_format($lap['total'], 3)." : {$lap['name']}\n"; + } + + $this->info('Done'); + } + + protected function getArguments() { + return array( + ); + } + + protected function getOptions() { + return array( + ); + } + +} diff --git a/app/Console/Commands/ResetData.php b/app/Console/Commands/ResetData.php new file mode 100644 index 000000000000..a02760034726 --- /dev/null +++ b/app/Console/Commands/ResetData.php @@ -0,0 +1,24 @@ +info(date('Y-m-d') . ' Running ResetData...'); + + if (!Utils::isNinjaDev()) { + return; + } + + Artisan::call('migrate:reset'); + Artisan::call('migrate'); + Artisan::call('db:seed'); + } +} \ No newline at end of file diff --git a/app/Console/Commands/SendRecurringInvoices.php b/app/Console/Commands/SendRecurringInvoices.php new file mode 100644 index 000000000000..389950c8291a --- /dev/null +++ b/app/Console/Commands/SendRecurringInvoices.php @@ -0,0 +1,113 @@ +mailer = $mailer; + } + + public function fire() + { + $this->info(date('Y-m-d').' Running SendRecurringInvoices...'); + $today = new DateTime(); + + $invoices = Invoice::with('account.timezone', 'invoice_items', 'client', 'user') + ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', array($today, $today))->get(); + $this->info(count($invoices).' recurring invoice(s) found'); + + foreach ($invoices as $recurInvoice) { + if ($recurInvoice->client->deleted_at) { + continue; + } + + if (!$recurInvoice->user->confirmed) { + continue; + } + + $this->info('Processing Invoice '.$recurInvoice->id.' - Should send '.($recurInvoice->shouldSendToday() ? 'YES' : 'NO')); + + if (!$recurInvoice->shouldSendToday()) { + continue; + } + + $invoice = Invoice::createNew($recurInvoice); + $invoice->client_id = $recurInvoice->client_id; + $invoice->recurring_invoice_id = $recurInvoice->id; + $invoice->invoice_number = 'R'.$recurInvoice->account->getNextInvoiceNumber(); + $invoice->amount = $recurInvoice->amount; + $invoice->balance = $recurInvoice->amount; + $invoice->invoice_date = date_create()->format('Y-m-d'); + $invoice->discount = $recurInvoice->discount; + $invoice->po_number = $recurInvoice->po_number; + $invoice->public_notes = $recurInvoice->public_notes; + $invoice->terms = $recurInvoice->terms; + $invoice->invoice_footer = $recurInvoice->invoice_footer; + $invoice->tax_name = $recurInvoice->tax_name; + $invoice->tax_rate = $recurInvoice->tax_rate; + $invoice->invoice_design_id = $recurInvoice->invoice_design_id; + $invoice->custom_value1 = $recurInvoice->custom_value1; + $invoice->custom_value2 = $recurInvoice->custom_value2; + $invoice->custom_taxes1 = $recurInvoice->custom_taxes1; + $invoice->custom_taxes2 = $recurInvoice->custom_taxes2; + $invoice->is_amount_discount = $recurInvoice->is_amount_discount; + + if ($invoice->client->payment_terms) { + $invoice->due_date = date_create()->modify($invoice->client->payment_terms.' day')->format('Y-m-d'); + } + + $invoice->save(); + + foreach ($recurInvoice->invoice_items as $recurItem) { + $item = InvoiceItem::createNew($recurItem); + $item->product_id = $recurItem->product_id; + $item->qty = $recurItem->qty; + $item->cost = $recurItem->cost; + $item->notes = Utils::processVariables($recurItem->notes); + $item->product_key = Utils::processVariables($recurItem->product_key); + $item->tax_name = $recurItem->tax_name; + $item->tax_rate = $recurItem->tax_rate; + $invoice->invoice_items()->save($item); + } + + foreach ($recurInvoice->invitations as $recurInvitation) { + $invitation = Invitation::createNew($recurInvitation); + $invitation->contact_id = $recurInvitation->contact_id; + $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); + $invoice->invitations()->save($invitation); + } + + $this->mailer->sendInvoice($invoice); + + $recurInvoice->last_sent_date = Carbon::now()->toDateTimeString(); + $recurInvoice->save(); + } + + $this->info('Done'); + } + + protected function getArguments() + { + return array( + //array('example', InputArgument::REQUIRED, 'An example argument.'), + ); + } + + protected function getOptions() + { + return array( + //array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null), + ); + } +} diff --git a/app/Handlers/InvoiceEventHandler.php b/app/Handlers/InvoiceEventHandler.php new file mode 100644 index 000000000000..7b6f4e9cc52b --- /dev/null +++ b/app/Handlers/InvoiceEventHandler.php @@ -0,0 +1,51 @@ +userMailer = $userMailer; + $this->contactMailer = $contactMailer; + } + + public function subscribe($events) + { + $events->listen('invoice.sent', 'InvoiceEventHandler@onSent'); + $events->listen('invoice.viewed', 'InvoiceEventHandler@onViewed'); + $events->listen('invoice.paid', 'InvoiceEventHandler@onPaid'); + } + + public function onSent($invoice) + { + $this->sendNotifications($invoice, 'sent'); + } + + public function onViewed($invoice) + { + $this->sendNotifications($invoice, 'viewed'); + } + + public function onPaid($payment) + { + $this->contactMailer->sendPaymentConfirmation($payment); + + $this->sendNotifications($payment->invoice, 'paid', $payment); + } + + private function sendNotifications($invoice, $type, $payment = null) + { + foreach ($invoice->account->users as $user) + { + if ($user->{'notify_' . $type}) + { + $this->userMailer->sendNotification($user, $invoice, $type, $payment); + } + } + } +} \ No newline at end of file diff --git a/app/Handlers/UserEventHandler.php b/app/Handlers/UserEventHandler.php new file mode 100644 index 000000000000..19ee6f5de936 --- /dev/null +++ b/app/Handlers/UserEventHandler.php @@ -0,0 +1,30 @@ +listen('user.signup', 'UserEventHandler@onSignup'); + $events->listen('user.login', 'UserEventHandler@onLogin'); + + $events->listen('user.refresh', 'UserEventHandler@onRefresh'); + } + + public function onSignup() + { + } + + public function onLogin() + { + $account = Auth::user()->account; + $account->last_login = Carbon::now()->toDateTimeString(); + $account->save(); + + Event::fire('user.refresh'); + } + + public function onRefresh() + { + Auth::user()->account->loadLocalizationSettings(); + } +} diff --git a/app/Http/Controllers/.gitkeep b/app/Http/Controllers/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php new file mode 100644 index 000000000000..6036a93b3753 --- /dev/null +++ b/app/Http/Controllers/AccountController.php @@ -0,0 +1,715 @@ +accountRepo = $accountRepo; + $this->userMailer = $userMailer; + $this->contactMailer = $contactMailer; + } + + public function demo() + { + $demoAccountId = Utils::getDemoAccountId(); + + if (!$demoAccountId) { + return Redirect::to('/'); + } + + $account = Account::find($demoAccountId); + $user = $account->users()->first(); + + Auth::login($user, true); + + return Redirect::to('invoices/create'); + } + + public function getStarted() + { + if (Auth::check()) { + return Redirect::to('invoices/create'); + } elseif (!Utils::isNinja() && Account::count() > 0) { + return Redirect::to('/login'); + } + + $user = false; + $guestKey = Input::get('guest_key'); + + if ($guestKey) { + $user = User::where('password', '=', $guestKey)->first(); + + if ($user && $user->registered) { + return Redirect::to('/'); + } + } + + if (!$user) { + $account = $this->accountRepo->create(); + $user = $account->users()->first(); + + Session::forget(RECENTLY_VIEWED); + } + + Auth::login($user, true); + Event::fire('user.login'); + + return Redirect::to('invoices/create')->with('sign_up', Input::get('sign_up')); + } + + public function enableProPlan() + { + $invitation = $this->accountRepo->enableProPlan(); + + /* + if ($invoice) + { + $this->contactMailer->sendInvoice($invoice); + } + */ + + return $invitation->invitation_key; + } + + public function setTrashVisible($entityType, $visible) + { + Session::put("show_trash:{$entityType}", $visible == 'true'); + + if ($entityType == 'user') { + return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_USER_MANAGEMENT); + } elseif ($entityType == 'token') { + return Redirect::to('company/'.ACCOUNT_ADVANCED_SETTINGS.'/'.ACCOUNT_TOKEN_MANAGEMENT); + } else { + return Redirect::to("{$entityType}s"); + } + } + + public function getSearchData() + { + $data = $this->accountRepo->getSearchData(); + return Response::json($data); + } + + public function showSection($section = ACCOUNT_DETAILS, $subSection = false) + { + if ($section == ACCOUNT_DETAILS) { + $data = [ + 'account' => Account::with('users')->findOrFail(Auth::user()->account_id), + 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), + 'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'timezones' => Timezone::remember(DEFAULT_QUERY_CACHE)->orderBy('location')->get(), + 'dateFormats' => DateFormat::remember(DEFAULT_QUERY_CACHE)->get(), + 'datetimeFormats' => DatetimeFormat::remember(DEFAULT_QUERY_CACHE)->get(), + 'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'languages' => Language::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'showUser' => Auth::user()->id === Auth::user()->account->users()->first()->id, + ]; + + return View::make('accounts.details', $data); + } elseif ($section == ACCOUNT_PAYMENTS) { + + $account = Auth::user()->account; + $account->load('account_gateways'); + $count = count($account->account_gateways); + + if ($count == 0) { + return Redirect::to('gateways/create'); + } else { + return View::make('accounts.payments', ['showAdd' => $count < 2]); + } + } elseif ($section == ACCOUNT_NOTIFICATIONS) { + $data = [ + 'account' => Account::with('users')->findOrFail(Auth::user()->account_id), + ]; + + return View::make('accounts.notifications', $data); + } elseif ($section == ACCOUNT_IMPORT_EXPORT) { + return View::make('accounts.import_export'); + } elseif ($section == ACCOUNT_ADVANCED_SETTINGS) { + $account = Auth::user()->account; + $data = [ + 'account' => $account, + 'feature' => $subSection, + ]; + + if ($subSection == ACCOUNT_INVOICE_DESIGN) { + $invoice = new stdClass(); + $client = new stdClass(); + $invoiceItem = new stdClass(); + + $client->name = 'Sample Client'; + $client->address1 = ''; + $client->city = ''; + $client->state = ''; + $client->postal_code = ''; + $client->work_phone = ''; + $client->work_email = ''; + + $invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber(); + $invoice->invoice_date = date_create()->format('Y-m-d'); + $invoice->account = json_decode(Auth::user()->account->toJson()); + $invoice->amount = $invoice->balance = 100; + + $invoiceItem->cost = 100; + $invoiceItem->qty = 1; + $invoiceItem->notes = 'Notes'; + $invoiceItem->product_key = 'Item'; + + $invoice->client = $client; + $invoice->invoice_items = [$invoiceItem]; + + $data['invoice'] = $invoice; + $data['invoiceDesigns'] = InvoiceDesign::remember(DEFAULT_QUERY_CACHE, 'invoice_designs_cache_'.Auth::user()->maxInvoiceDesignId()) + ->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get(); + } else if ($subSection == ACCOUNT_EMAIL_TEMPLATES) { + $data['invoiceEmail'] = $account->getEmailTemplate(ENTITY_INVOICE); + $data['quoteEmail'] = $account->getEmailTemplate(ENTITY_QUOTE); + $data['paymentEmail'] = $account->getEmailTemplate(ENTITY_PAYMENT); + $data['emailFooter'] = $account->getEmailFooter(); + } + + return View::make("accounts.{$subSection}", $data); + } elseif ($section == ACCOUNT_PRODUCTS) { + $data = [ + 'account' => Auth::user()->account, + ]; + + return View::make('accounts.products', $data); + } + } + + public function doSection($section = ACCOUNT_DETAILS, $subSection = false) + { + if ($section == ACCOUNT_DETAILS) { + return AccountController::saveDetails(); + } elseif ($section == ACCOUNT_IMPORT_EXPORT) { + return AccountController::importFile(); + } elseif ($section == ACCOUNT_MAP) { + return AccountController::mapFile(); + } elseif ($section == ACCOUNT_NOTIFICATIONS) { + return AccountController::saveNotifications(); + } elseif ($section == ACCOUNT_EXPORT) { + return AccountController::export(); + } elseif ($section == ACCOUNT_ADVANCED_SETTINGS) { + if ($subSection == ACCOUNT_INVOICE_SETTINGS) { + return AccountController::saveInvoiceSettings(); + } elseif ($subSection == ACCOUNT_INVOICE_DESIGN) { + return AccountController::saveInvoiceDesign(); + } elseif ($subSection == ACCOUNT_EMAIL_TEMPLATES) { + return AccountController::saveEmailTemplates(); + } + } elseif ($section == ACCOUNT_PRODUCTS) { + return AccountController::saveProducts(); + } + } + + private function saveEmailTemplates() + { + if (Auth::user()->account->isPro()) { + $account = Auth::user()->account; + + $account->email_template_invoice = Input::get('email_template_invoice', $account->getEmailTemplate(ENTITY_INVOICE)); + $account->email_template_quote = Input::get('email_template_quote', $account->getEmailTemplate(ENTITY_QUOTE)); + $account->email_template_payment = Input::get('email_template_payment', $account->getEmailTemplate(ENTITY_PAYMENT)); + + $account->save(); + + Session::flash('message', trans('texts.updated_settings')); + } + + return Redirect::to('company/advanced_settings/email_templates'); + } + + private function saveProducts() + { + $account = Auth::user()->account; + + $account->fill_products = Input::get('fill_products') ? true : false; + $account->update_products = Input::get('update_products') ? true : false; + $account->save(); + + Session::flash('message', trans('texts.updated_settings')); + return Redirect::to('company/products'); + } + + private function saveInvoiceSettings() + { + if (Auth::user()->account->isPro()) { + $account = Auth::user()->account; + + $account->custom_label1 = trim(Input::get('custom_label1')); + $account->custom_value1 = trim(Input::get('custom_value1')); + $account->custom_label2 = trim(Input::get('custom_label2')); + $account->custom_value2 = trim(Input::get('custom_value2')); + $account->custom_client_label1 = trim(Input::get('custom_client_label1')); + $account->custom_client_label2 = trim(Input::get('custom_client_label2')); + $account->custom_invoice_label1 = trim(Input::get('custom_invoice_label1')); + $account->custom_invoice_label2 = trim(Input::get('custom_invoice_label2')); + $account->custom_invoice_taxes1 = Input::get('custom_invoice_taxes1') ? true : false; + $account->custom_invoice_taxes2 = Input::get('custom_invoice_taxes2') ? true : false; + + $account->invoice_number_prefix = Input::get('invoice_number_prefix'); + $account->invoice_number_counter = Input::get('invoice_number_counter'); + $account->quote_number_prefix = Input::get('quote_number_prefix'); + $account->share_counter = Input::get('share_counter') ? true : false; + + if (!$account->share_counter) { + $account->quote_number_counter = Input::get('quote_number_counter'); + } + + if (!$account->share_counter && $account->invoice_number_prefix == $account->quote_number_prefix) { + Session::flash('error', trans('texts.invalid_counter')); + + return Redirect::to('company/advanced_settings/invoice_settings')->withInput(); + } else { + $account->save(); + Session::flash('message', trans('texts.updated_settings')); + } + } + + return Redirect::to('company/advanced_settings/invoice_settings'); + } + + private function saveInvoiceDesign() + { + if (Auth::user()->account->isPro()) { + $account = Auth::user()->account; + $account->hide_quantity = Input::get('hide_quantity') ? true : false; + $account->hide_paid_to_date = Input::get('hide_paid_to_date') ? true : false; + $account->primary_color = Input::get('primary_color'); + $account->secondary_color = Input::get('secondary_color'); + $account->invoice_design_id = Input::get('invoice_design_id'); + $account->save(); + + Session::flash('message', trans('texts.updated_settings')); + } + + return Redirect::to('company/advanced_settings/invoice_design'); + } + + private function export() + { + $output = fopen('php://output', 'w') or Utils::fatalError(); + header('Content-Type:application/csv'); + header('Content-Disposition:attachment;filename=export.csv'); + + $clients = Client::scope()->get(); + AccountController::exportData($output, $clients->toArray()); + + $contacts = Contact::scope()->get(); + AccountController::exportData($output, $contacts->toArray()); + + $invoices = Invoice::scope()->get(); + AccountController::exportData($output, $invoices->toArray()); + + $invoiceItems = InvoiceItem::scope()->get(); + AccountController::exportData($output, $invoiceItems->toArray()); + + $payments = Payment::scope()->get(); + AccountController::exportData($output, $payments->toArray()); + + $credits = Credit::scope()->get(); + AccountController::exportData($output, $credits->toArray()); + + fclose($output); + exit; + } + + private function exportData($output, $data) + { + if (count($data) > 0) { + fputcsv($output, array_keys($data[0])); + } + + foreach ($data as $record) { + fputcsv($output, $record); + } + + fwrite($output, "\n"); + } + + private function importFile() + { + $data = Session::get('data'); + Session::forget('data'); + + $map = Input::get('map'); + $count = 0; + $hasHeaders = Input::get('header_checkbox'); + + $countries = Country::remember(DEFAULT_QUERY_CACHE)->get(); + $countryMap = []; + + foreach ($countries as $country) { + $countryMap[strtolower($country->name)] = $country->id; + } + + foreach ($data as $row) { + if ($hasHeaders) { + $hasHeaders = false; + continue; + } + + $client = Client::createNew(); + $contact = Contact::createNew(); + $contact->is_primary = true; + $contact->send_invoice = true; + $count++; + + foreach ($row as $index => $value) { + $field = $map[$index]; + $value = trim($value); + + if ($field == Client::$fieldName && !$client->name) { + $client->name = $value; + } elseif ($field == Client::$fieldPhone && !$client->work_phone) { + $client->work_phone = $value; + } elseif ($field == Client::$fieldAddress1 && !$client->address1) { + $client->address1 = $value; + } elseif ($field == Client::$fieldAddress2 && !$client->address2) { + $client->address2 = $value; + } elseif ($field == Client::$fieldCity && !$client->city) { + $client->city = $value; + } elseif ($field == Client::$fieldState && !$client->state) { + $client->state = $value; + } elseif ($field == Client::$fieldPostalCode && !$client->postal_code) { + $client->postal_code = $value; + } elseif ($field == Client::$fieldCountry && !$client->country_id) { + $value = strtolower($value); + $client->country_id = isset($countryMap[$value]) ? $countryMap[$value] : null; + } elseif ($field == Client::$fieldNotes && !$client->private_notes) { + $client->private_notes = $value; + } elseif ($field == Contact::$fieldFirstName && !$contact->first_name) { + $contact->first_name = $value; + } elseif ($field == Contact::$fieldLastName && !$contact->last_name) { + $contact->last_name = $value; + } elseif ($field == Contact::$fieldPhone && !$contact->phone) { + $contact->phone = $value; + } elseif ($field == Contact::$fieldEmail && !$contact->email) { + $contact->email = strtolower($value); + } + } + + $client->save(); + $client->contacts()->save($contact); + Activity::createClient($client, false); + } + + $message = Utils::pluralize('created_client', $count); + Session::flash('message', $message); + + return Redirect::to('clients'); + } + + private function mapFile() + { + $file = Input::file('file'); + + if ($file == null) { + Session::flash('error', trans('texts.select_file')); + + return Redirect::to('company/import_export'); + } + + $name = $file->getRealPath(); + + require_once app_path().'/includes/parsecsv.lib.php'; + $csv = new parseCSV(); + $csv->heading = false; + $csv->auto($name); + + if (count($csv->data) + Client::scope()->count() > Auth::user()->getMaxNumClients()) { + $message = trans('texts.limit_clients', ['count' => Auth::user()->getMaxNumClients()]); + Session::flash('error', $message); + + return Redirect::to('company/import_export'); + } + + Session::put('data', $csv->data); + + $headers = false; + $hasHeaders = false; + $mapped = array(); + $columns = array('', + Client::$fieldName, + Client::$fieldPhone, + Client::$fieldAddress1, + Client::$fieldAddress2, + Client::$fieldCity, + Client::$fieldState, + Client::$fieldPostalCode, + Client::$fieldCountry, + Client::$fieldNotes, + Contact::$fieldFirstName, + Contact::$fieldLastName, + Contact::$fieldPhone, + Contact::$fieldEmail, + ); + + if (count($csv->data) > 0) { + $headers = $csv->data[0]; + foreach ($headers as $title) { + if (strpos(strtolower($title), 'name') > 0) { + $hasHeaders = true; + break; + } + } + + for ($i = 0; $i Contact::$fieldFirstName, + 'last' => Contact::$fieldLastName, + 'email' => Contact::$fieldEmail, + 'mobile' => Contact::$fieldPhone, + 'phone' => Client::$fieldPhone, + 'name|organization' => Client::$fieldName, + 'street|address|address1' => Client::$fieldAddress1, + 'street2|address2' => Client::$fieldAddress2, + 'city' => Client::$fieldCity, + 'state|province' => Client::$fieldState, + 'zip|postal|code' => Client::$fieldPostalCode, + 'country' => Client::$fieldCountry, + 'note' => Client::$fieldNotes, + ); + + foreach ($map as $search => $column) { + foreach (explode("|", $search) as $string) { + if (strpos($title, 'sec') === 0) { + continue; + } + + if (strpos($title, $string) !== false) { + $mapped[$i] = $column; + break(2); + } + } + } + } + } + } + + $data = array( + 'data' => $csv->data, + 'headers' => $headers, + 'hasHeaders' => $hasHeaders, + 'columns' => $columns, + 'mapped' => $mapped, + ); + + return View::make('accounts.import_map', $data); + } + + private function saveNotifications() + { + $account = Auth::user()->account; + $account->invoice_terms = Input::get('invoice_terms'); + $account->invoice_footer = Input::get('invoice_footer'); + $account->email_footer = Input::get('email_footer'); + $account->save(); + + $user = Auth::user(); + $user->notify_sent = Input::get('notify_sent'); + $user->notify_viewed = Input::get('notify_viewed'); + $user->notify_paid = Input::get('notify_paid'); + $user->save(); + + Session::flash('message', trans('texts.updated_settings')); + + return Redirect::to('company/notifications'); + } + + private function saveDetails() + { + $rules = array( + 'name' => 'required', + ); + + $user = Auth::user()->account->users()->first(); + + if (Auth::user()->id === $user->id) { + $rules['email'] = 'email|required|unique:users,email,'.$user->id.',id'; + } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to('company/details') + ->withErrors($validator) + ->withInput(); + } else { + $account = Auth::user()->account; + $account->name = trim(Input::get('name')); + $account->id_number = trim(Input::get('id_number')); + $account->vat_number = trim(Input::get('vat_number')); + $account->work_email = trim(Input::get('work_email')); + $account->work_phone = trim(Input::get('work_phone')); + $account->address1 = trim(Input::get('address1')); + $account->address2 = trim(Input::get('address2')); + $account->city = trim(Input::get('city')); + $account->state = trim(Input::get('state')); + $account->postal_code = trim(Input::get('postal_code')); + $account->country_id = Input::get('country_id') ? Input::get('country_id') : null; + $account->size_id = Input::get('size_id') ? Input::get('size_id') : null; + $account->industry_id = Input::get('industry_id') ? Input::get('industry_id') : null; + $account->timezone_id = Input::get('timezone_id') ? Input::get('timezone_id') : null; + $account->date_format_id = Input::get('date_format_id') ? Input::get('date_format_id') : null; + $account->datetime_format_id = Input::get('datetime_format_id') ? Input::get('datetime_format_id') : null; + $account->currency_id = Input::get('currency_id') ? Input::get('currency_id') : 1; // US Dollar + $account->language_id = Input::get('language_id') ? Input::get('language_id') : 1; // English + $account->save(); + + if (Auth::user()->id === $user->id) { + $user->first_name = trim(Input::get('first_name')); + $user->last_name = trim(Input::get('last_name')); + $user->username = trim(Input::get('email')); + $user->email = trim(strtolower(Input::get('email'))); + $user->phone = trim(Input::get('phone')); + $user->save(); + } + + /* Logo image file */ + if ($file = Input::file('logo')) { + $path = Input::file('logo')->getRealPath(); + File::delete('logo/'.$account->account_key.'.jpg'); + + $image = Image::make($path); + $mimeType = $file->getMimeType(); + + if ($image->width == 200 && $mimeType == 'image/jpeg') { + $file->move('logo/', $account->account_key . '.jpg'); + } else { + $image->resize(200, 120, true, false); + Image::canvas($image->width, $image->height, '#FFFFFF')->insert($image)->save($account->getLogoPath()); + } + + //$image = Image::make($path)->resize(200, 120, true, false); + //Image::canvas($image->width, $image->height, '#FFFFFF')->insert($image)->save($account->getLogoPath()); + } + + Event::fire('user.refresh'); + Session::flash('message', trans('texts.updated_settings')); + + return Redirect::to('company/details'); + } + } + + public function removeLogo() + { + File::delete('logo/'.Auth::user()->account->account_key.'.jpg'); + + Session::flash('message', trans('texts.removed_logo')); + + return Redirect::to('company/details'); + } + + public function checkEmail() + { + $email = User::withTrashed()->where('email', '=', Input::get('email'))->where('id', '<>', Auth::user()->id)->first(); + + if ($email) { + return "taken"; + } else { + return "available"; + } + } + + public function submitSignup() + { + $rules = array( + 'new_first_name' => 'required', + 'new_last_name' => 'required', + 'new_password' => 'required|min:6', + 'new_email' => 'email|required|unique:users,email,'.Auth::user()->id.',id', + ); + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return ''; + } + + $user = Auth::user(); + $user->first_name = trim(Input::get('new_first_name')); + $user->last_name = trim(Input::get('new_last_name')); + $user->email = trim(strtolower(Input::get('new_email'))); + $user->username = $user->email; + $user->password = trim(Input::get('new_password')); + $user->password_confirmation = trim(Input::get('new_password')); + $user->registered = true; + $user->amend(); + + if (Utils::isNinja()) { + $this->userMailer->sendConfirmation($user); + } else { + $this->accountRepo->registerUser($user); + } + + $activities = Activity::scope()->get(); + foreach ($activities as $activity) { + $activity->message = str_replace('Guest', $user->getFullName(), $activity->message); + $activity->save(); + } + + if (Input::get('go_pro') == 'true') { + Session::set(REQUESTED_PRO_PLAN, true); + } + + Session::set(SESSION_COUNTER, -1); + + return "{$user->first_name} {$user->last_name}"; + } + + public function doRegister() + { + $affiliate = Affiliate::where('affiliate_key', '=', SELF_HOST_AFFILIATE_KEY)->first(); + + $license = new License(); + $license->first_name = Input::get('first_name'); + $license->last_name = Input::get('last_name'); + $license->email = Input::get('email'); + $license->transaction_reference = Request::getClientIp(); + $license->license_key = Utils::generateLicense(); + $license->affiliate_id = $affiliate->id; + $license->product_id = PRODUCT_SELF_HOST; + $license->is_claimed = 1; + $license->save(); + + return ''; + } + + public function cancelAccount() + { + if ($reason = trim(Input::get('reason'))) { + $email = Auth::user()->email; + $name = Auth::user()->getDisplayName(); + + $data = [ + 'text' => $reason, + ]; + + $this->userMailer->sendTo(CONTACT_EMAIL, $email, $name, 'Invoice Ninja Feedback [Canceled Account]', 'contact', $data); + } + + $account = Auth::user()->account; + $account->forceDelete(); + + Confide::logout(); + + return Redirect::to('/')->with('clearGuestKey', true); + } +} diff --git a/app/Http/Controllers/AccountGatewayController.php b/app/Http/Controllers/AccountGatewayController.php new file mode 100644 index 000000000000..e6f646e4e70a --- /dev/null +++ b/app/Http/Controllers/AccountGatewayController.php @@ -0,0 +1,292 @@ +join('gateways', 'gateways.id', '=', 'account_gateways.gateway_id') + ->where('account_gateways.deleted_at', '=', null) + ->where('account_gateways.account_id', '=', \Auth::user()->account_id) + ->select('account_gateways.public_id', 'gateways.name', 'account_gateways.deleted_at'); + + return Datatable::query($query) + ->addColumn('name', function ($model) { return link_to('gateways/'.$model->public_id.'/edit', $model->name); }) + ->addColumn('dropdown', function ($model) { + $actions = ''; + + return $actions; + }) + ->orderColumns(['name']) + ->make(); + } + + public function edit($publicId) + { + $accountGateway = AccountGateway::scope($publicId)->firstOrFail(); + $config = $accountGateway->config; + $selectedCards = $accountGateway->accepted_credit_cards; + + $configFields = json_decode($config); + + foreach ($configFields as $configField => $value) { + $configFields->$configField = str_repeat('*', strlen($value)); + } + + $data = self::getViewModel($accountGateway); + $data['url'] = 'gateways/'.$publicId; + $data['method'] = 'PUT'; + $data['title'] = trans('texts.edit_gateway') . ' - ' . $accountGateway->gateway->name; + $data['config'] = $configFields; + + return View::make('accounts.account_gateway', $data); + } + + public function update($publicId) + { + return $this->save($publicId); + } + + public function store() + { + return $this->save(); + } + + /** + * Displays the form for account creation + * + */ + public function create() + { + $data = self::getViewModel(); + $data['url'] = 'gateways'; + $data['method'] = 'POST'; + $data['title'] = trans('texts.add_gateway'); + + return View::make('accounts.account_gateway', $data); + } + + private function getViewModel($accountGateway = false) + { + $selectedCards = $accountGateway ? $accountGateway->accepted_credit_cards : 0; + $account = Auth::user()->account; + + $recommendedGateways = Gateway::remember(DEFAULT_QUERY_CACHE) + ->where('recommended', '=', '1') + ->orderBy('sort_order') + ->get(); + $recommendedGatewayArray = array(); + + foreach ($recommendedGateways as $recommendedGateway) { + $arrayItem = array( + 'value' => $recommendedGateway->id, + 'other' => 'false', + 'data-imageUrl' => asset($recommendedGateway->getLogoUrl()), + 'data-siteUrl' => $recommendedGateway->site_url, + ); + $recommendedGatewayArray[$recommendedGateway->name] = $arrayItem; + } + + $creditCardsArray = unserialize(CREDIT_CARDS); + $creditCards = []; + foreach ($creditCardsArray as $card => $name) { + if ($selectedCards > 0 && ($selectedCards & $card) == $card) { + $creditCards[$name['text']] = ['value' => $card, 'data-imageUrl' => asset($name['card']), 'checked' => 'checked']; + } else { + $creditCards[$name['text']] = ['value' => $card, 'data-imageUrl' => asset($name['card'])]; + } + } + + $otherItem = array( + 'value' => 1000000, + 'other' => 'true', + 'data-imageUrl' => '', + 'data-siteUrl' => '', + ); + $recommendedGatewayArray['Other Options'] = $otherItem; + + $account->load('account_gateways'); + $currentGateways = $account->account_gateways; + $gateways = Gateway::where('payment_library_id', '=', 1)->orderBy('name'); + $onlyPayPal = false; + if (!$accountGateway) { + if (count($currentGateways) > 0) { + $currentGateway = $currentGateways[0]; + if ($currentGateway->isPayPal()) { + $gateways->where('id', '!=', GATEWAY_PAYPAL_EXPRESS); + } else { + $gateways->where('id', '=', GATEWAY_PAYPAL_EXPRESS); + $onlyPayPal = true; + } + } + } + $gateways = $gateways->get(); + + foreach ($gateways as $gateway) { + $paymentLibrary = $gateway->paymentlibrary; + $gateway->fields = $gateway->getFields(); + + if ($accountGateway && $accountGateway->gateway_id == $gateway->id) { + $accountGateway->fields = $gateway->fields; + } + } + + $tokenBillingOptions = []; + for ($i=1; $i<=4; $i++) { + $tokenBillingOptions[$i] = trans("texts.token_billing_{$i}"); + } + + return [ + 'account' => $account, + 'accountGateway' => $accountGateway, + 'config' => false, + 'gateways' => $gateways, + 'recommendedGateways' => $recommendedGatewayArray, + 'creditCardTypes' => $creditCards, + 'tokenBillingOptions' => $tokenBillingOptions, + 'showBreadcrumbs' => false, + 'onlyPayPal' => $onlyPayPal, + 'countGateways' => count($currentGateways) + ]; + } + + public function delete() + { + $accountGatewayPublicId = Input::get('accountGatewayPublicId'); + $gateway = AccountGateway::scope($accountGatewayPublicId)->firstOrFail(); + + $gateway->delete(); + + Session::flash('message', trans('texts.deleted_gateway')); + + return Redirect::to('company/payments'); + } + + /** + * Stores new account + * + */ + public function save($accountGatewayPublicId = false) + { + $rules = array(); + $recommendedId = Input::get('recommendedGateway_id'); + + $gatewayId = ($recommendedId == 1000000 ? Input::get('gateway_id') : $recommendedId); + + if (!$gatewayId) { + Session::flash('error', trans('validation.required', ['attribute' => 'gateway'])); + return Redirect::to('gateways/create') + ->withInput(); + } + + $gateway = Gateway::findOrFail($gatewayId); + $paymentLibrary = $gateway->paymentlibrary; + $fields = $gateway->getFields(); + + foreach ($fields as $field => $details) { + if (!in_array($field, ['testMode', 'developerMode', 'headerImageUrl', 'solutionType', 'landingPage', 'brandName', 'logoImageUrl', 'borderColor'])) { + if (strtolower($gateway->name) == 'beanstream') { + if (in_array($field, ['merchant_id', 'passCode'])) { + $rules[$gateway->id.'_'.$field] = 'required'; + } + } else { + $rules[$gateway->id.'_'.$field] = 'required'; + } + } + } + + $creditcards = Input::get('creditCardTypes'); + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to('gateways/create') + ->withErrors($validator) + ->withInput(); + } else { + $account = Account::with('account_gateways')->findOrFail(Auth::user()->account_id); + + if ($accountGatewayPublicId) { + $accountGateway = AccountGateway::scope($accountGatewayPublicId)->firstOrFail(); + } else { + $accountGateway = AccountGateway::createNew(); + $accountGateway->gateway_id = $gatewayId; + } + + $isMasked = false; + + $config = new stdClass(); + foreach ($fields as $field => $details) { + $value = trim(Input::get($gateway->id.'_'.$field)); + + if ($value && $value === str_repeat('*', strlen($value))) { + $isMasked = true; + } + + $config->$field = $value; + } + + $cardCount = 0; + if ($creditcards) { + foreach ($creditcards as $card => $value) { + $cardCount += intval($value); + } + } + + // if the values haven't changed don't update the config + if ($isMasked && $accountGatewayPublicId) { + $accountGateway->accepted_credit_cards = $cardCount; + $accountGateway->save(); + // if there's an existing config for this gateway update it + } elseif (!$isMasked && $accountGatewayPublicId && $accountGateway->gateway_id == $gatewayId) { + $accountGateway->accepted_credit_cards = $cardCount; + $accountGateway->config = json_encode($config); + $accountGateway->save(); + // otherwise, create a new gateway config + } else { + $accountGateway->config = json_encode($config); + $accountGateway->accepted_credit_cards = $cardCount; + $account->account_gateways()->save($accountGateway); + } + + if (Input::get('token_billing_type_id')) { + $account->token_billing_type_id = Input::get('token_billing_type_id'); + $account->save(); + } + + if ($accountGatewayPublicId) { + $message = trans('texts.updated_gateway'); + } else { + $message = trans('texts.created_gateway'); + } + + Session::flash('message', $message); + + return Redirect::to('company/payments'); + } + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php new file mode 100644 index 000000000000..ba8797bb1d00 --- /dev/null +++ b/app/Http/Controllers/ActivityController.php @@ -0,0 +1,20 @@ +join('clients', 'clients.id', '=', 'activities.client_id') + ->where('clients.public_id', '=', $clientPublicId) + ->where('activities.account_id', '=', Auth::user()->account_id) + ->select('activities.id', 'activities.message', 'activities.created_at', 'clients.currency_id', 'activities.balance', 'activities.adjustment'); + + return Datatable::query($query) + ->addColumn('id', function ($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); }) + ->addColumn('message', function ($model) { return Utils::decodeActivity($model->message); }) + ->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); }) + ->addColumn('adjustment', function ($model) { return $model->adjustment != 0 ? Utils::formatMoney($model->adjustment, $model->currency_id) : ''; }) + ->make(); + } +} diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php new file mode 100644 index 000000000000..1378c43c9c95 --- /dev/null +++ b/app/Http/Controllers/AppController.php @@ -0,0 +1,171 @@ +accountRepo = $accountRepo; + $this->mailer = $mailer; + } + + public function showSetup() + { + if (Utils::isNinja() || Utils::isDatabaseSetup()) { + return Redirect::to('/'); + } + + return View::make('setup'); + } + + public function doSetup() + { + if (Utils::isNinja() || Utils::isDatabaseSetup()) { + return Redirect::to('/'); + } + + $valid = false; + $test = Input::get('test'); + + $app = Input::get('app'); + $app['key'] = str_random(RANDOM_KEY_LENGTH); + $app['debug'] = false; + + $database = Input::get('database'); + $dbType = $database['default']; + $database['connections'] = [$dbType => $database['type']]; + unset($database['type']); + + $mail = Input::get('mail'); + $email = $mail['username']; + $mail['from']['address'] = $email; + + if ($test == 'mail') { + return self::testMail($mail); + } + + $valid = self::testDatabase($database); + + if ($test == 'db') { + return $valid === true ? 'Success' : $valid; + } elseif (!$valid) { + return Redirect::to('/setup')->withInput(); + } + + $content = " $app, 'database' => $database, 'mail' => $mail] as $key => $config) { + $content = 'accountRepo->create(); + $user = $account->users()->first(); + + $user->first_name = trim(Input::get('first_name')); + $user->last_name = trim(Input::get('last_name')); + $user->email = trim(strtolower(Input::get('email'))); + $user->username = $user->email; + $user->password = trim(Input::get('password')); + $user->password_confirmation = trim(Input::get('password')); + $user->registered = true; + $user->amend(); + + //Auth::login($user, true); + $this->accountRepo->registerUser($user); + + return Redirect::to('/invoices/create'); + } + + private function testDatabase($database) + { + $dbType = $database['default']; + + Config::set('database.default', $dbType); + + foreach ($database['connections'][$dbType] as $key => $val) { + Config::set("database.connections.{$dbType}.{$key}", $val); + } + + try { + $valid = DB::connection()->getDatabaseName() ? true : false; + } catch (Exception $e) { + return $e->getMessage(); + } + + return $valid; + } + + private function testMail($mail) + { + $email = $mail['username']; + $fromName = $mail['from']['name']; + + foreach ($mail as $key => $val) { + Config::set("mail.{$key}", $val); + } + + Config::set('mail.from.address', $email); + Config::set('mail.from.name', $fromName); + + $data = [ + 'text' => 'Test email', + ]; + + try { + $this->mailer->sendTo($email, $email, $fromName, 'Test email', 'contact', $data); + + return 'Sent'; + } catch (Exception $e) { + return $e->getMessage(); + } + } + + public function install() + { + if (!Utils::isNinja() && !Utils::isDatabaseSetup()) { + try { + Artisan::call('migrate'); + Artisan::call('db:seed'); + } catch (Exception $e) { + Response::make($e->getMessage(), 500); + } + } + + return Redirect::to('/'); + } + + public function update() + { + if (!Utils::isNinja()) { + try { + Artisan::call('migrate'); + Cache::flush(); + } catch (Exception $e) { + Response::make($e->getMessage(), 500); + } + } + + return Redirect::to('/'); + } +} diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php new file mode 100644 index 000000000000..0cc63c7c5a1a --- /dev/null +++ b/app/Http/Controllers/BaseController.php @@ -0,0 +1,21 @@ +layout)) { + $this->layout = View::make($this->layout); + } + } + + public function __construct() + { + $this->beforeFilter('csrf', array('on' => array('post', 'delete', 'put'))); + } +} diff --git a/app/Http/Controllers/ClientApiController.php b/app/Http/Controllers/ClientApiController.php new file mode 100644 index 000000000000..138a92aabcdb --- /dev/null +++ b/app/Http/Controllers/ClientApiController.php @@ -0,0 +1,51 @@ +clientRepo = $clientRepo; + } + + public function ping() + { + $headers = Utils::getApiHeaders(); + + return Response::make('', 200, $headers); + } + + public function index() + { + $clients = Client::scope()->with('contacts')->orderBy('created_at', 'desc')->get(); + $clients = Utils::remapPublicIds($clients->toArray()); + + $response = json_encode($clients, JSON_PRETTY_PRINT); + $headers = Utils::getApiHeaders(count($clients)); + + return Response::make($response, 200, $headers); + } + + public function store() + { + $data = Input::all(); + $error = $this->clientRepo->getErrors($data); + + if ($error) { + $headers = Utils::getApiHeaders(); + + return Response::make($error, 500, $headers); + } else { + $client = $this->clientRepo->save(false, $data, false); + $client->load('contacts'); + $client = Utils::remapPublicIds($client->toArray()); + $response = json_encode($client, JSON_PRETTY_PRINT); + $headers = Utils::getApiHeaders(); + + return Response::make($response, 200, $headers); + } + } +} diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php new file mode 100644 index 000000000000..a06b6c5bdc8e --- /dev/null +++ b/app/Http/Controllers/ClientController.php @@ -0,0 +1,278 @@ +clientRepo = $clientRepo; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list', array( + 'entityType' => ENTITY_CLIENT, + 'title' => trans('texts.clients'), + 'columns' => Utils::trans(['checkbox', 'client', 'contact', 'email', 'date_created', 'last_login', 'balance', 'action']), + )); + } + + public function getDatatable() + { + $clients = $this->clientRepo->find(Input::get('sSearch')); + + return Datatable::query($clients) + ->addColumn('checkbox', function ($model) { return ''; }) + ->addColumn('name', function ($model) { return link_to('clients/'.$model->public_id, $model->name); }) + ->addColumn('first_name', function ($model) { return link_to('clients/'.$model->public_id, $model->first_name.' '.$model->last_name); }) + ->addColumn('email', function ($model) { return link_to('clients/'.$model->public_id, $model->email); }) + ->addColumn('created_at', function ($model) { return Utils::timestampToDateString(strtotime($model->created_at)); }) + ->addColumn('last_login', function ($model) { return Utils::timestampToDateString(strtotime($model->last_login)); }) + ->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); }) + ->addColumn('dropdown', function ($model) { + if ($model->is_deleted) { + return '
'; + } + + $str = ''; + }) + ->make(); + } + + /** + * Store a newly created resource in storage. + * + * @return Response + */ + public function store() + { + return $this->save(); + } + + /** + * Display the specified resource. + * + * @param int $id + * @return Response + */ + public function show($publicId) + { + $client = Client::withTrashed()->scope($publicId)->with('contacts', 'size', 'industry')->firstOrFail(); + Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT); + + $actionLinks = [ + [trans('texts.create_invoice'), URL::to('invoices/create/'.$client->public_id)], + [trans('texts.enter_payment'), URL::to('payments/create/'.$client->public_id)], + [trans('texts.enter_credit'), URL::to('credits/create/'.$client->public_id)], + ]; + + if (Utils::isPro()) { + array_unshift($actionLinks, [trans('texts.create_quote'), URL::to('quotes/create/'.$client->public_id)]); + } + + $data = array( + 'actionLinks' => $actionLinks, + 'showBreadcrumbs' => false, + 'client' => $client, + 'credit' => $client->getTotalCredit(), + 'title' => trans('texts.view_client'), + 'hasRecurringInvoices' => Invoice::scope()->where('is_recurring', '=', true)->whereClientId($client->id)->count() > 0, + 'gatewayLink' => $client->getGatewayLink(), + ); + + return View::make('clients.show', $data); + } + + /** + * Show the form for creating a new resource. + * + * @return Response + */ + public function create() + { + if (Client::scope()->count() > Auth::user()->getMaxNumClients()) { + return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients()." clients"]); + } + + $data = [ + 'client' => null, + 'method' => 'POST', + 'url' => 'clients', + 'title' => trans('texts.new_client'), + ]; + + $data = array_merge($data, self::getViewModel()); + + return View::make('clients.edit', $data); + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return Response + */ + public function edit($publicId) + { + $client = Client::scope($publicId)->with('contacts')->firstOrFail(); + $data = [ + 'client' => $client, + 'method' => 'PUT', + 'url' => 'clients/'.$publicId, + 'title' => trans('texts.edit_client'), + ]; + + $data = array_merge($data, self::getViewModel()); + + return View::make('clients.edit', $data); + } + + private static function getViewModel() + { + return [ + 'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), + 'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']), + 'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'customLabel1' => Auth::user()->account->custom_client_label1, + 'customLabel2' => Auth::user()->account->custom_client_label2, + ]; + } + + /** + * Update the specified resource in storage. + * + * @param int $id + * @return Response + */ + public function update($publicId) + { + return $this->save($publicId); + } + + private function save($publicId = null) + { + $rules = array( + 'email' => 'required', + ); + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + $url = $publicId ? 'clients/'.$publicId.'/edit' : 'clients/create'; + + return Redirect::to($url) + ->withErrors($validator) + ->withInput(Input::except('password')); + } else { + if ($publicId) { + $client = Client::scope($publicId)->firstOrFail(); + } else { + $client = Client::createNew(); + } + + $client->name = trim(Input::get('name')); + $client->id_number = trim(Input::get('id_number')); + $client->vat_number = trim(Input::get('vat_number')); + $client->work_phone = trim(Input::get('work_phone')); + $client->custom_value1 = trim(Input::get('custom_value1')); + $client->custom_value2 = trim(Input::get('custom_value2')); + $client->address1 = trim(Input::get('address1')); + $client->address2 = trim(Input::get('address2')); + $client->city = trim(Input::get('city')); + $client->state = trim(Input::get('state')); + $client->postal_code = trim(Input::get('postal_code')); + $client->country_id = Input::get('country_id') ?: null; + $client->private_notes = trim(Input::get('private_notes')); + $client->size_id = Input::get('size_id') ?: null; + $client->industry_id = Input::get('industry_id') ?: null; + $client->currency_id = Input::get('currency_id') ?: null; + $client->payment_terms = Input::get('payment_terms') ?: 0; + $client->website = trim(Input::get('website')); + + $client->save(); + + $data = json_decode(Input::get('data')); + $contactIds = []; + $isPrimary = true; + + foreach ($data->contacts as $contact) { + if (isset($contact->public_id) && $contact->public_id) { + $record = Contact::scope($contact->public_id)->firstOrFail(); + } else { + $record = Contact::createNew(); + } + + $record->email = trim(strtolower($contact->email)); + $record->first_name = trim($contact->first_name); + $record->last_name = trim($contact->last_name); + $record->phone = trim($contact->phone); + $record->is_primary = $isPrimary; + $isPrimary = false; + + $client->contacts()->save($record); + $contactIds[] = $record->public_id; + } + + foreach ($client->contacts as $contact) { + if (!in_array($contact->public_id, $contactIds)) { + $contact->delete(); + } + } + + if ($publicId) { + Session::flash('message', trans('texts.updated_client')); + } else { + Activity::createClient($client); + Session::flash('message', trans('texts.created_client')); + } + + return Redirect::to('clients/'.$client->public_id); + } + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('id') ? Input::get('id') : Input::get('ids'); + $count = $this->clientRepo->bulk($ids, $action); + + $message = Utils::pluralize($action.'d_client', $count); + Session::flash('message', $message); + + if ($action == 'restore' && $count == 1) { + return Redirect::to('clients/'.$ids[0]); + } else { + return Redirect::to('clients'); + } + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100644 index 000000000000..27b3f45272fd --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,11 @@ +creditRepo = $creditRepo; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list', array( + 'entityType' => ENTITY_CREDIT, + 'title' => trans('texts.credits'), + 'columns' => Utils::trans(['checkbox', 'client', 'credit_amount', 'credit_balance', 'credit_date', 'private_notes', 'action']), + )); + } + + public function getDatatable($clientPublicId = null) + { + $credits = $this->creditRepo->find($clientPublicId, Input::get('sSearch')); + + $table = Datatable::query($credits); + + if (!$clientPublicId) { + $table->addColumn('checkbox', function ($model) { return ''; }) + ->addColumn('client_name', function ($model) { return link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)); }); + } + + return $table->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id).''; }) + ->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); }) + ->addColumn('credit_date', function ($model) { return Utils::fromSqlDate($model->credit_date); }) + ->addColumn('private_notes', function ($model) { return $model->private_notes; }) + ->addColumn('dropdown', function ($model) { + if ($model->is_deleted) { + return '
'; + } + + $str = ''; + }) + ->make(); + } + + public function create($clientPublicId = 0) + { + $data = array( + 'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId, + //'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId, + 'credit' => null, + 'method' => 'POST', + 'url' => 'credits', + 'title' => trans('texts.new_credit'), + //'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + //'invoices' => Invoice::scope()->with('client', 'invoice_status')->orderBy('invoice_number')->get(), + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ); + + return View::make('credits.edit', $data); + } + + public function edit($publicId) + { + $credit = Credit::scope($publicId)->firstOrFail(); + $credit->credit_date = Utils::fromSqlDate($credit->credit_date); + + $data = array( + 'client' => null, + 'credit' => $credit, + 'method' => 'PUT', + 'url' => 'credits/'.$publicId, + 'title' => 'Edit Credit', + //'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ); + + return View::make('credit.edit', $data); + } + + public function store() + { + return $this->save(); + } + + public function update($publicId) + { + return $this->save($publicId); + } + + private function save($publicId = null) + { + $rules = array( + 'client' => 'required', + 'amount' => 'required|positive', + ); + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + $url = $publicId ? 'credits/'.$publicId.'/edit' : 'credits/create'; + + return Redirect::to($url) + ->withErrors($validator) + ->withInput(); + } else { + $this->creditRepo->save($publicId, Input::all()); + + $message = trans('texts.created_credit'); + Session::flash('message', $message); + + return Redirect::to('clients/'.Input::get('client')); + } + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('id') ? Input::get('id') : Input::get('ids'); + $count = $this->creditRepo->bulk($ids, $action); + + if ($count > 0) { + $message = Utils::pluralize($action.'d_credit', $count); + Session::flash('message', $message); + } + + return Redirect::to('credits'); + } +} diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php new file mode 100644 index 000000000000..6038c812da7c --- /dev/null +++ b/app/Http/Controllers/DashboardController.php @@ -0,0 +1,79 @@ += '.INVOICE_STATUS_SENT.' THEN 1 ELSE 0 END) invoices_sent, + COUNT(DISTINCT clients.id) active_clients'); + $metrics = DB::table('accounts') + ->select($select) + ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') + ->leftJoin('invoices', 'clients.id', '=', 'invoices.client_id') + ->where('accounts.id', '=', Auth::user()->account_id) + ->where('clients.is_deleted', '=', false) + ->where('invoices.is_deleted', '=', false) + ->where('invoices.is_recurring', '=', false) + ->where('invoices.is_quote', '=', false) + ->groupBy('accounts.id') + ->first(); + + $select = DB::raw('SUM(clients.paid_to_date) as value, clients.currency_id as currency_id'); + $paidToDate = DB::table('accounts') + ->select($select) + ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') + ->where('accounts.id', '=', Auth::user()->account_id) + ->where('clients.is_deleted', '=', false) + ->groupBy('accounts.id') + ->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')) + ->get(); + + $select = DB::raw('AVG(invoices.amount) as invoice_avg, clients.currency_id as currency_id'); + $averageInvoice = DB::table('accounts') + ->select($select) + ->leftJoin('clients', 'accounts.id', '=', 'clients.account_id') + ->leftJoin('invoices', 'clients.id', '=', 'invoices.client_id') + ->where('accounts.id', '=', Auth::user()->account_id) + ->where('clients.is_deleted', '=', false) + ->where('invoices.is_deleted', '=', false) + ->groupBy('accounts.id') + ->groupBy(DB::raw('CASE WHEN clients.currency_id IS NULL THEN CASE WHEN accounts.currency_id IS NULL THEN 1 ELSE accounts.currency_id END ELSE clients.currency_id END')) + ->get(); + + + + $activities = Activity::where('activities.account_id', '=', Auth::user()->account_id) + ->orderBy('created_at', 'desc')->take(6)->get(); + + $pastDue = Invoice::scope() + ->where('due_date', '<', date('Y-m-d')) + ->where('balance', '>', 0) + ->where('is_recurring', '=', false) + ->where('is_quote', '=', false) + ->where('is_deleted', '=', false) + ->orderBy('due_date', 'asc')->take(6)->get(); + + $upcoming = Invoice::scope() + ->where('due_date', '>=', date('Y-m-d')) + ->where('balance', '>', 0) + ->where('is_recurring', '=', false) + ->where('is_quote', '=', false) + ->where('is_deleted', '=', false) + ->orderBy('due_date', 'asc')->take(6)->get(); + + $data = [ + 'paidToDate' => $paidToDate, + 'averageInvoice' => $averageInvoice, + 'billedClients' => $metrics ? $metrics->billed_clients : 0, + 'invoicesSent' => $metrics ? $metrics->invoices_sent : 0, + 'activeClients' => $metrics ? $metrics->active_clients : 0, + 'activities' => $activities, + 'pastDue' => $pastDue, + 'upcoming' => $upcoming, + ]; + + return View::make('dashboard', $data); + } +} diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 27e8a9983fd7..4c10565ebf29 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -1,5 +1,6 @@ -account_id)->where('event_id', '=', $eventId)->first(); + + if (!$subscription) { + $subscription = new Subscription(); + $subscription->account_id = Auth::user()->account_id; + $subscription->event_id = $eventId; + } + + $subscription->target_url = trim(Input::get('target_url')); + $subscription->save(); + + return Response::json('{"id":'.$subscription->id.'}', 201); + } +} diff --git a/app/Http/Controllers/InvoiceApiController.php b/app/Http/Controllers/InvoiceApiController.php new file mode 100644 index 000000000000..40c63ea30d9c --- /dev/null +++ b/app/Http/Controllers/InvoiceApiController.php @@ -0,0 +1,192 @@ +invoiceRepo = $invoiceRepo; + $this->mailer = $mailer; + } + + public function index() + { + $invoices = Invoice::scope()->where('invoices.is_quote', '=', false)->orderBy('created_at', 'desc')->get(); + $invoices = Utils::remapPublicIds($invoices->toArray()); + + $response = json_encode($invoices, JSON_PRETTY_PRINT); + $headers = Utils::getApiHeaders(count($invoices)); + + return Response::make($response, 200, $headers); + } + + public function store() + { + $data = Input::all(); + $error = null; + + // check if the invoice number is set and unique + if (!isset($data['invoice_number'])) { + $data['invoice_number'] = Auth::user()->account->getNextInvoiceNumber(); + } else { + $invoice = Invoice::scope()->where('invoice_number', '=', $data['invoice_number'])->first(); + if ($invoice) { + $error = trans('validation.unique', ['attribute' => 'texts.invoice_number']); + } + } + + // check the client id is set and exists + if (!isset($data['client_id'])) { + $error = trans('validation.required', ['attribute' => 'client_id']); + } else { + $client = Client::scope($data['client_id'])->first(); + if (!$client) { + $error = trans('validation.not_in', ['attribute' => 'client_id']); + } + } + + if ($error) { + $response = json_encode($error, JSON_PRETTY_PRINT); + } else { + $data = self::prepareData($data); + $invoice = $this->invoiceRepo->save(false, $data, false); + + $invitation = Invitation::createNew(); + $invitation->invoice_id = $invoice->id; + $invitation->contact_id = $client->contacts[0]->id; + $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); + $invitation->save(); + + // prepare the return data + $invoice->load('invoice_items'); + $invoice = $invoice->toArray(); + $invoice['link'] = $invitation->getLink(); + unset($invoice['account']); + unset($invoice['client']); + $invoice = Utils::remapPublicIds($invoice); + $invoice['client_id'] = $client->public_id; + + $response = json_encode($invoice, JSON_PRETTY_PRINT); + } + + $headers = Utils::getApiHeaders(); + + return Response::make($response, $error ? 400 : 200, $headers); + } + + private function prepareData($data) + { + $account = Auth::user()->account; + $account->loadLocalizationSettings(); + + // set defaults for optional fields + $fields = [ + 'discount' => 0, + 'is_amount_discount' => false, + 'terms' => '', + 'invoice_footer' => '', + 'public_notes' => '', + 'po_number' => '', + 'invoice_design_id' => $account->invoice_design_id, + 'invoice_items' => [], + 'custom_value1' => 0, + 'custom_value2' => 0, + 'custom_taxes1' => false, + 'custom_taxes2' => false, + ]; + + if (!isset($data['invoice_date'])) { + $fields['invoice_date_sql'] = date_create()->format('Y-m-d'); + } + if (!isset($data['due_date'])) { + $fields['due_date_sql'] = false; + } + + foreach ($fields as $key => $val) { + if (!isset($data[$key])) { + $data[$key] = $val; + } + } + + // hardcode some fields + $fields = [ + 'is_recurring' => false + ]; + + foreach ($fields as $key => $val) { + $data[$key] = $val; + } + + // initialize the line items + if (isset($data['product_key']) || isset($data['cost']) || isset($data['notes']) || isset($data['qty'])) { + $data['invoice_items'] = [self::prepareItem($data)]; + } else { + foreach ($data['invoice_items'] as $index => $item) { + $data['invoice_items'][$index] = self::prepareItem($item); + } + } + + return $data; + } + + private function prepareItem($item) + { + $fields = [ + 'cost' => 0, + 'product_key' => '', + 'notes' => '', + 'qty' => 1 + ]; + + foreach ($fields as $key => $val) { + if (!isset($item[$key])) { + $item[$key] = $val; + } + } + + // if only the product key is set we'll load the cost and notes + if ($item['product_key'] && (!$item['cost'] || !$item['notes'])) { + $product = Product::findProductByKey($item['product_key']); + if ($product) { + if (!$item['cost']) { + $item['cost'] = $product->cost; + } + if (!$item['notes']) { + $item['notes'] = $product->notes; + } + } + } + + return $item; + } + + public function emailInvoice() + { + $data = Input::all(); + $error = null; + + if (!isset($data['id'])) { + $error = trans('validation.required', ['attribute' => 'id']); + } else { + $invoice = Invoice::scope($data['id'])->first(); + if (!$invoice) { + $error = trans('validation.not_in', ['attribute' => 'id']); + } else { + $this->mailer->sendInvoice($invoice); + } + } + + if ($error) { + $response = json_encode($error, JSON_PRETTY_PRINT); + } else { + $response = json_encode(RESULT_SUCCESS, JSON_PRETTY_PRINT); + } + + $headers = Utils::getApiHeaders(); + return Response::make($response, $error ? 400 : 200, $headers); + } +} diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php new file mode 100644 index 000000000000..28a04b3cbaf9 --- /dev/null +++ b/app/Http/Controllers/InvoiceController.php @@ -0,0 +1,542 @@ +mailer = $mailer; + $this->invoiceRepo = $invoiceRepo; + $this->clientRepo = $clientRepo; + $this->taxRateRepo = $taxRateRepo; + } + + public function index() + { + $data = [ + 'title' => trans('texts.invoices'), + 'entityType' => ENTITY_INVOICE, + 'columns' => Utils::trans(['checkbox', 'invoice_number', 'client', 'invoice_date', 'invoice_total', 'balance_due', 'due_date', 'status', 'action']), + ]; + + $recurringInvoices = Invoice::scope()->where('is_recurring', '=', true); + + if (Session::get('show_trash:invoice')) { + $recurringInvoices->withTrashed(); + } + + if ($recurringInvoices->count() > 0) { + $data['secEntityType'] = ENTITY_RECURRING_INVOICE; + $data['secColumns'] = Utils::trans(['checkbox', 'frequency', 'client', 'start_date', 'end_date', 'invoice_total', 'action']); + } + + return View::make('list', $data); + } + + public function clientIndex() + { + $invitationKey = Session::get('invitation_key'); + if (!$invitationKey) { + return Redirect::to('/setup'); + } + + $invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first(); + $color = $invitation->account->primary_color ? $invitation->account->primary_color : '#0b4d78'; + + $data = [ + 'color' => $color, + 'hideLogo' => Session::get('white_label'), + 'title' => trans('texts.invoices'), + 'entityType' => ENTITY_INVOICE, + 'columns' => Utils::trans(['invoice_number', 'invoice_date', 'invoice_total', 'balance_due', 'due_date']), + ]; + + return View::make('public_list', $data); + } + + public function getDatatable($clientPublicId = null) + { + $accountId = Auth::user()->account_id; + $search = Input::get('sSearch'); + + return $this->invoiceRepo->getDatatable($accountId, $clientPublicId, ENTITY_INVOICE, $search); + } + + public function getClientDatatable() + { + //$accountId = Auth::user()->account_id; + $search = Input::get('sSearch'); + $invitationKey = Session::get('invitation_key'); + $invitation = Invitation::where('invitation_key', '=', $invitationKey)->first(); + + if (!$invitation || $invitation->is_deleted) { + return []; + } + + $invoice = $invitation->invoice; + + if (!$invoice || $invoice->is_deleted) { + return []; + } + + return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_INVOICE, $search); + } + + public function getRecurringDatatable($clientPublicId = null) + { + $query = $this->invoiceRepo->getRecurringInvoices(Auth::user()->account_id, $clientPublicId, Input::get('sSearch')); + $table = Datatable::query($query); + + if (!$clientPublicId) { + $table->addColumn('checkbox', function ($model) { return ''; }); + } + + $table->addColumn('frequency', function ($model) { return link_to('invoices/'.$model->public_id, $model->frequency); }); + + if (!$clientPublicId) { + $table->addColumn('client_name', function ($model) { return link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)); }); + } + + return $table->addColumn('start_date', function ($model) { return Utils::fromSqlDate($model->start_date); }) + ->addColumn('end_date', function ($model) { return Utils::fromSqlDate($model->end_date); }) + ->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); }) + ->addColumn('dropdown', function ($model) { + if ($model->is_deleted) { + return '
'; + } + + $str = ''; + + }) + ->make(); + } + + public function view($invitationKey) + { + $invitation = Invitation::where('invitation_key', '=', $invitationKey)->firstOrFail(); + $invoice = $invitation->invoice; + + if (!$invoice || $invoice->is_deleted) { + return View::make('invoices.deleted'); + } + + $invoice->load('user', 'invoice_items', 'invoice_design', 'account.country', 'client.contacts', 'client.country'); + $client = $invoice->client; + + if (!$client || $client->is_deleted) { + return View::make('invoices.deleted'); + } + + if (!Session::has($invitationKey) && (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) { + Activity::viewInvoice($invitation); + Event::fire('invoice.viewed', $invoice); + } + + Session::set($invitationKey, true); + Session::set('invitation_key', $invitationKey); + Session::set('white_label', $client->account->isWhiteLabel()); + + $client->account->loadLocalizationSettings(); + + $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); + $invoice->due_date = Utils::fromSqlDate($invoice->due_date); + $invoice->is_pro = $client->account->isPro(); + + $contact = $invitation->contact; + $contact->setVisible([ + 'first_name', + 'last_name', + 'email', + 'phone', ]); + + $data = array( + 'isConverted' => $invoice->quote_invoice_id ? true : false, + 'showBreadcrumbs' => false, + 'hideLogo' => $client->account->isWhiteLabel(), + 'invoice' => $invoice->hidePrivateFields(), + 'invitation' => $invitation, + 'invoiceLabels' => $client->account->getInvoiceLabels(), + 'contact' => $contact, + 'hasToken' => $client->getGatewayToken(), + 'countGateways' => AccountGateway::scope(false, $client->account->id)->count(), + ); + + return View::make('invoices.view', $data); + } + + public function edit($publicId, $clone = false) + { + $invoice = Invoice::scope($publicId)->withTrashed()->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items')->firstOrFail(); + $entityType = $invoice->getEntityType(); + + $contactIds = DB::table('invitations') + ->join('contacts', 'contacts.id', '=', 'invitations.contact_id') + ->where('invitations.invoice_id', '=', $invoice->id) + ->where('invitations.account_id', '=', Auth::user()->account_id) + ->where('invitations.deleted_at', '=', null) + ->select('contacts.public_id')->lists('public_id'); + + if ($clone) { + $invoice->id = null; + $invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber($invoice->is_quote); + $invoice->balance = $invoice->amount; + $invoice->invoice_status_id = 0; + $invoice->invoice_date = date_create()->format('Y-m-d'); + $method = 'POST'; + $url = "{$entityType}s"; + } else { + Utils::trackViewed($invoice->invoice_number.' - '.$invoice->client->getDisplayName(), $invoice->getEntityType()); + $method = 'PUT'; + $url = "{$entityType}s/{$publicId}"; + } + + $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); + $invoice->due_date = Utils::fromSqlDate($invoice->due_date); + $invoice->start_date = Utils::fromSqlDate($invoice->start_date); + $invoice->end_date = Utils::fromSqlDate($invoice->end_date); + $invoice->is_pro = Auth::user()->isPro(); + + $data = array( + 'entityType' => $entityType, + 'showBreadcrumbs' => $clone, + 'account' => $invoice->account, + 'invoice' => $invoice, + 'data' => false, + 'method' => $method, + 'invitationContactIds' => $contactIds, + 'url' => $url, + 'title' => trans("texts.edit_{$entityType}"), + 'client' => $invoice->client, ); + $data = array_merge($data, self::getViewModel()); + + // Set the invitation link on the client's contacts + if (!$clone) { + $clients = $data['clients']; + foreach ($clients as $client) { + if ($client->id == $invoice->client->id) { + foreach ($invoice->invitations as $invitation) { + foreach ($client->contacts as $contact) { + if ($invitation->contact_id == $contact->id) { + $contact->invitation_link = $invitation->getLink(); + } + } + } + break; + } + } + } + + return View::make('invoices.edit', $data); + } + + public function create($clientPublicId = 0) + { + $client = null; + $invoiceNumber = Auth::user()->account->getNextInvoiceNumber(); + $account = Account::with('country')->findOrFail(Auth::user()->account_id); + + if ($clientPublicId) { + $client = Client::scope($clientPublicId)->firstOrFail(); + } + + $data = array( + 'entityType' => ENTITY_INVOICE, + 'account' => $account, + 'invoice' => null, + 'data' => Input::old('data'), + 'invoiceNumber' => $invoiceNumber, + 'method' => 'POST', + 'url' => 'invoices', + 'title' => trans('texts.new_invoice'), + 'client' => $client, ); + $data = array_merge($data, self::getViewModel()); + + return View::make('invoices.edit', $data); + } + + private static function getViewModel() + { + $recurringHelp = ''; + foreach (preg_split("/((\r?\n)|(\r\n?))/", trans('texts.recurring_help')) as $line) { + $parts = explode("=>", $line); + if (count($parts) > 1) { + $line = $parts[0].' => '.Utils::processVariables($parts[0]); + $recurringHelp .= '
  • '.strip_tags($line).'
  • '; + } else { + $recurringHelp .= $line; + } + } + + return [ + 'account' => Auth::user()->account, + 'products' => Product::scope()->orderBy('id')->get(array('product_key', 'notes', 'cost', 'qty')), + 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(), + 'taxRates' => TaxRate::scope()->orderBy('name')->get(), + 'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), + 'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']), + 'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE, 'invoice_designs_cache_'.Auth::user()->maxInvoiceDesignId()) + ->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get(), + 'frequencies' => array( + 1 => 'Weekly', + 2 => 'Two weeks', + 3 => 'Four weeks', + 4 => 'Monthly', + 5 => 'Three months', + 6 => 'Six months', + 7 => 'Annually', + ), + 'recurringHelp' => $recurringHelp + ]; + } + + /** + * Store a newly created resource in storage. + * + * @return Response + */ + public function store() + { + return InvoiceController::save(); + } + + private function save($publicId = null) + { + $action = Input::get('action'); + $entityType = Input::get('entityType'); + + if (in_array($action, ['archive', 'delete', 'mark', 'restore'])) { + return InvoiceController::bulk($entityType); + } + + $input = json_decode(Input::get('data')); + $invoice = $input->invoice; + + if ($errors = $this->invoiceRepo->getErrors($invoice)) { + Session::flash('error', trans('texts.invoice_error')); + + return Redirect::to("{$entityType}s/create") + ->withInput()->withErrors($errors); + } else { + $this->taxRateRepo->save($input->tax_rates); + + $clientData = (array) $invoice->client; + $client = $this->clientRepo->save($invoice->client->public_id, $clientData); + + $invoiceData = (array) $invoice; + $invoiceData['client_id'] = $client->id; + $invoice = $this->invoiceRepo->save($publicId, $invoiceData, $entityType); + + $account = Auth::user()->account; + if ($account->invoice_taxes != $input->invoice_taxes + || $account->invoice_item_taxes != $input->invoice_item_taxes + || $account->invoice_design_id != $input->invoice->invoice_design_id) { + $account->invoice_taxes = $input->invoice_taxes; + $account->invoice_item_taxes = $input->invoice_item_taxes; + $account->invoice_design_id = $input->invoice->invoice_design_id; + $account->save(); + } + + $client->load('contacts'); + $sendInvoiceIds = []; + + foreach ($client->contacts as $contact) { + if ($contact->send_invoice || count($client->contacts) == 1) { + $sendInvoiceIds[] = $contact->id; + } + } + + foreach ($client->contacts as $contact) { + $invitation = Invitation::scope()->whereContactId($contact->id)->whereInvoiceId($invoice->id)->first(); + + if (in_array($contact->id, $sendInvoiceIds) && !$invitation) { + $invitation = Invitation::createNew(); + $invitation->invoice_id = $invoice->id; + $invitation->contact_id = $contact->id; + $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); + $invitation->save(); + } elseif (!in_array($contact->id, $sendInvoiceIds) && $invitation) { + $invitation->delete(); + } + } + + $message = trans($publicId ? "texts.updated_{$entityType}" : "texts.created_{$entityType}"); + if ($input->invoice->client->public_id == '-1') { + $message = $message.' '.trans('texts.and_created_client'); + + $url = URL::to('clients/'.$client->public_id); + Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT, $url); + } + + if ($action == 'clone') { + return $this->cloneInvoice($publicId); + } elseif ($action == 'convert') { + return $this->convertQuote($publicId); + } elseif ($action == 'email') { + if (Auth::user()->confirmed && !Auth::user()->isDemo()) { + $message = trans("texts.emailed_{$entityType}"); + $this->mailer->sendInvoice($invoice); + Session::flash('message', $message); + } else { + $errorMessage = trans(Auth::user()->registered ? 'texts.confirmation_required' : 'texts.registration_required'); + Session::flash('error', $errorMessage); + Session::flash('message', $message); + } + } else { + Session::flash('message', $message); + } + + $url = "{$entityType}s/".$invoice->public_id.'/edit'; + + return Redirect::to($url); + } + } + + /** + * Display the specified resource. + * + * @param int $id + * @return Response + */ + public function show($publicId) + { + Session::reflash(); + + return Redirect::to('invoices/'.$publicId.'/edit'); + } + + /** + * Update the specified resource in storage. + * + * @param int $id + * @return Response + */ + public function update($publicId) + { + return InvoiceController::save($publicId); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return Response + */ + public function bulk($entityType = ENTITY_INVOICE) + { + $action = Input::get('action'); + $statusId = Input::get('statusId', INVOICE_STATUS_SENT); + $ids = Input::get('id') ? Input::get('id') : Input::get('ids'); + $count = $this->invoiceRepo->bulk($ids, $action, $statusId); + + if ($count > 0) { + $key = $action == 'mark' ? "updated_{$entityType}" : "{$action}d_{$entityType}"; + $message = Utils::pluralize($key, $count); + Session::flash('message', $message); + } + + if ($action == 'restore' && $count == 1) { + return Redirect::to("{$entityType}s/".$ids[0]); + } else { + return Redirect::to("{$entityType}s"); + } + } + + public function convertQuote($publicId) + { + $invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail(); + $clone = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id); + + Session::flash('message', trans('texts.converted_to_invoice')); + return Redirect::to('invoices/'.$clone->public_id); + } + + public function cloneInvoice($publicId) + { + /* + $invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail(); + $clone = $this->invoiceRepo->cloneInvoice($invoice); + $entityType = $invoice->getEntityType(); + + Session::flash('message', trans('texts.cloned_invoice')); + return Redirect::to("{$entityType}s/" . $clone->public_id); + */ + + return self::edit($publicId, true); + } + + public function invoiceHistory($publicId) + { + $invoice = Invoice::withTrashed()->scope($publicId)->firstOrFail(); + $invoice->load('user', 'invoice_items', 'account.country', 'client.contacts', 'client.country'); + $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); + $invoice->due_date = Utils::fromSqlDate($invoice->due_date); + $invoice->is_pro = Auth::user()->isPro(); + $invoice->is_quote = intval($invoice->is_quote); + + $activityTypeId = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE; + $activities = Activity::scope(false, $invoice->account_id) + ->where('activity_type_id', '=', $activityTypeId) + ->where('invoice_id', '=', $invoice->id) + ->orderBy('id', 'desc') + ->get(['id', 'created_at', 'user_id', 'json_backup', 'message']); + + $versionsJson = []; + $versionsSelect = []; + $lastId = false; + + foreach ($activities as $activity) { + $backup = json_decode($activity->json_backup); + $backup->invoice_date = Utils::fromSqlDate($backup->invoice_date); + $backup->due_date = Utils::fromSqlDate($backup->due_date); + $backup->is_pro = Auth::user()->isPro(); + $backup->is_quote = isset($backup->is_quote) && intval($backup->is_quote); + $backup->account = $invoice->account->toArray(); + + $versionsJson[$activity->id] = $backup; + $key = Utils::timestampToDateTimeString(strtotime($activity->created_at)) . ' - ' . Utils::decodeActivity($activity->message); + $versionsSelect[$lastId ? $lastId : 0] = $key; + $lastId = $activity->id; + } + + $versionsSelect[$lastId] = Utils::timestampToDateTimeString(strtotime($invoice->created_at)) . ' - ' . $invoice->user->getDisplayName(); + + $data = [ + 'invoice' => $invoice, + 'versionsJson' => json_encode($versionsJson), + 'versionsSelect' => $versionsSelect, + 'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE, 'invoice_designs_cache_'.Auth::user()->maxInvoiceDesignId())->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get(), + ]; + + return View::make('invoices.history', $data); + } +} diff --git a/app/Http/Controllers/PaymentApiController.php b/app/Http/Controllers/PaymentApiController.php new file mode 100644 index 000000000000..46db0d353d2b --- /dev/null +++ b/app/Http/Controllers/PaymentApiController.php @@ -0,0 +1,36 @@ +paymentRepo = $paymentRepo; + } + + public function index() + { + $payments = Payment::scope()->orderBy('created_at', 'desc')->get(); + $payments = Utils::remapPublicIds($payments->toArray()); + + $response = json_encode($payments, JSON_PRETTY_PRINT); + $headers = Utils::getApiHeaders(count($payments)); + + return Response::make($response, 200, $headers); + } + + /* + public function store() + { + $data = Input::all(); + $invoice = $this->invoiceRepo->save(false, $data, false); + + $response = json_encode($invoice, JSON_PRETTY_PRINT); + $headers = Utils::getApiHeaders(); + return Response::make($response, 200, $headers); + } + */ +} diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php new file mode 100644 index 000000000000..c0241a8979fe --- /dev/null +++ b/app/Http/Controllers/PaymentController.php @@ -0,0 +1,748 @@ +paymentRepo = $paymentRepo; + $this->invoiceRepo = $invoiceRepo; + $this->accountRepo = $accountRepo; + $this->contactMailer = $contactMailer; + } + + public function index() + { + return View::make('list', array( + 'entityType' => ENTITY_PAYMENT, + 'title' => trans('texts.payments'), + 'columns' => Utils::trans(['checkbox', 'invoice', 'client', 'transaction_reference', 'method', 'payment_amount', 'payment_date', 'action']), + )); + } + + public function clientIndex() + { + $invitationKey = Session::get('invitation_key'); + if (!$invitationKey) { + return Redirect::to('/setup'); + } + + $invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first(); + $color = $invitation->account->primary_color ? $invitation->account->primary_color : '#0b4d78'; + + $data = [ + 'color' => $color, + 'hideLogo' => Session::get('white_label'), + 'entityType' => ENTITY_PAYMENT, + 'title' => trans('texts.payments'), + 'columns' => Utils::trans(['invoice', 'transaction_reference', 'method', 'payment_amount', 'payment_date']) + ]; + + return View::make('public_list', $data); + } + + public function getDatatable($clientPublicId = null) + { + $payments = $this->paymentRepo->find($clientPublicId, Input::get('sSearch')); + $table = Datatable::query($payments); + + if (!$clientPublicId) { + $table->addColumn('checkbox', function ($model) { return ''; }); + } + + $table->addColumn('invoice_number', function ($model) { return $model->invoice_public_id ? link_to('invoices/'.$model->invoice_public_id.'/edit', $model->invoice_number, ['class' => Utils::getEntityRowClass($model)]) : ''; }); + + if (!$clientPublicId) { + $table->addColumn('client_name', function ($model) { return link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)); }); + } + + $table->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : 'Manual entry'; }) + ->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? 'Online payment' : ''); }); + + return $table->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); }) + ->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); }) + ->addColumn('dropdown', function ($model) { + if ($model->is_deleted || $model->invoice_is_deleted) { + return '
    '; + } + + $str = ''; + }) + ->make(); + } + + public function getClientDatatable() + { + $search = Input::get('sSearch'); + $invitationKey = Session::get('invitation_key'); + $invitation = Invitation::where('invitation_key', '=', $invitationKey)->with('contact.client')->first(); + + if (!$invitation) { + return []; + } + + $invoice = $invitation->invoice; + + if (!$invoice || $invoice->is_deleted) { + return []; + } + + $payments = $this->paymentRepo->findForContact($invitation->contact->id, Input::get('sSearch')); + + return Datatable::query($payments) + ->addColumn('invoice_number', function ($model) { return $model->invitation_key ? link_to('/view/'.$model->invitation_key, $model->invoice_number) : $model->invoice_number; }) + ->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : 'Manual entry'; }) + ->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? 'Online payment' : ''); }) + ->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); }) + ->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); }) + ->make(); + } + + public function create($clientPublicId = 0, $invoicePublicId = 0) + { + $data = array( + 'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId, + 'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId, + 'invoice' => null, + 'invoices' => Invoice::scope()->where('is_recurring', '=', false)->where('is_quote', '=', false) + ->with('client', 'invoice_status')->orderBy('invoice_number')->get(), + 'payment' => null, + 'method' => 'POST', + 'url' => "payments", + 'title' => trans('texts.new_payment'), + //'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'paymentTypes' => PaymentType::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ); + + return View::make('payments.edit', $data); + } + + public function edit($publicId) + { + $payment = Payment::scope($publicId)->firstOrFail(); + $payment->payment_date = Utils::fromSqlDate($payment->payment_date); + + $data = array( + 'client' => null, + 'invoice' => null, + 'invoices' => Invoice::scope()->where('is_recurring', '=', false)->where('is_quote', '=', false) + ->with('client', 'invoice_status')->orderBy('invoice_number')->get(), + 'payment' => $payment, + 'method' => 'PUT', + 'url' => 'payments/'.$publicId, + 'title' => trans('texts.edit_payment'), + //'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'paymentTypes' => PaymentType::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ); + + return View::make('payments.edit', $data); + } + + private function createGateway($accountGateway) + { + $gateway = Omnipay::create($accountGateway->gateway->provider); + $config = json_decode($accountGateway->config); + + /* + $gateway->setSolutionType("Sole"); + $gateway->setLandingPage("Billing"); + */ + + foreach ($config as $key => $val) { + if (!$val) { + continue; + } + + $function = "set".ucfirst($key); + $gateway->$function($val); + } + + if (Utils::isNinjaDev()) { + $gateway->setTestMode(true); + } + + return $gateway; + } + + private function getLicensePaymentDetails($input, $affiliate) + { + $data = self::convertInputForOmnipay($input); + $card = new CreditCard($data); + + return [ + 'amount' => $affiliate->price, + 'card' => $card, + 'currency' => 'USD', + 'returnUrl' => URL::to('license_complete'), + 'cancelUrl' => URL::to('/') + ]; + } + + private function convertInputForOmnipay($input) + { + return [ + 'firstName' => $input['first_name'], + 'lastName' => $input['last_name'], + 'number' => $input['card_number'], + 'expiryMonth' => $input['expiration_month'], + 'expiryYear' => $input['expiration_year'], + 'cvv' => $input['cvv'], + 'billingAddress1' => $input['address1'], + 'billingAddress2' => $input['address2'], + 'billingCity' => $input['city'], + 'billingState' => $input['state'], + 'billingPostcode' => $input['postal_code'], + 'shippingAddress1' => $input['address1'], + 'shippingAddress2' => $input['address2'], + 'shippingCity' => $input['city'], + 'shippingState' => $input['state'], + 'shippingPostcode' => $input['postal_code'] + ]; + } + + private function getPaymentDetails($invitation, $input = null) + { + $invoice = $invitation->invoice; + $key = $invoice->invoice_number.'_details'; + $gateway = $invoice->client->account->getGatewayByType(Session::get('payment_type'))->gateway; + $paymentLibrary = $gateway->paymentlibrary; + $currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD'); + + if ($input && $paymentLibrary->id == PAYMENT_LIBRARY_OMNIPAY) { + $data = self::convertInputForOmnipay($input); + + Session::put($key, $data); + } elseif ($input && $paymentLibrary->id == PAYMENT_LIBRARY_PHP_PAYMENTS) { + $input = Input::all(); + $data = [ + 'first_name' => $input['first_name'], + 'last_name' => $input['last_name'], + 'cc_number' => $input['card_number'], + 'cc_exp' => $input['expiration_month'].$input['expiration_year'], + 'cc_code' => $input['cvv'], + 'street' => $input['address1'], + 'street2' => $input['address2'], + 'city' => $input['city'], + 'state' => $input['state'], + 'postal_code' => $input['postal_code'], + 'amt' => $invoice->balance, + 'ship_to_street' => $input['address1'], + 'ship_to_city' => $input['city'], + 'ship_to_state' => $input['state'], + 'ship_to_postal_code' => $input['postal_code'], + 'currency_code' => $currencyCode, + ]; + + switch ($gateway->id) { + case GATEWAY_BEANSTREAM: + $data['phone'] = $input['phone']; + $data['email'] = $input['email']; + $data['country'] = $input['country']; + $data['ship_to_country'] = $input['country']; + break; + case GATEWAY_BRAINTREE: + $data['ship_to_state'] = 'Ohio'; //$input['state']; + break; + } + + if (strlen($data['cc_exp']) == 5) { + $data['cc_exp'] = '0'.$data['cc_exp']; + } + + Session::put($key, $data); + + return $data; + } elseif (Session::get($key)) { + $data = Session::get($key); + } else { + $data = []; + } + + if ($paymentLibrary->id == PAYMENT_LIBRARY_OMNIPAY) { + $card = new CreditCard($data); + + return [ + 'amount' => $invoice->balance, + 'card' => $card, + 'currency' => $currencyCode, + 'returnUrl' => URL::to('complete'), + 'cancelUrl' => $invitation->getLink(), + 'description' => trans('texts.' . $invoice->getEntityType()) . " {$invoice->invoice_number}", + ]; + } else { + return $data; + } + } + + public function show_payment($invitationKey) + { + // Handle token billing + if (Input::get('use_token') == 'true') { + return self::do_payment($invitationKey, false, true); + } + + if (Input::has('use_paypal')) { + Session::put('payment_type', Input::get('use_paypal') == 'true' ? PAYMENT_TYPE_PAYPAL : PAYMENT_TYPE_CREDIT_CARD); + } elseif (!Session::has('payment_type')) { + Session::put('payment_type', PAYMENT_TYPE_ANY); + } + + // For PayPal we redirect straight to their site + $usePayPal = false; + if ($usePayPal = Input::get('use_paypal')) { + $usePayPal = $usePayPal == 'true'; + } else { + $invitation = Invitation::with('invoice.client.account', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); + $account = $invitation->invoice->client->account; + if (count($account->account_gateways) == 1 && $account->getGatewayByType(PAYMENT_TYPE_PAYPAL)) { + $usePayPal = true; + } + } + if ($usePayPal) { + if (Session::has('error')) { + Session::reflash(); + return Redirect::to('view/'.$invitationKey); + } else { + return self::do_payment($invitationKey, false); + } + } + + $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); + $invoice = $invitation->invoice; + $client = $invoice->client; + $accountGateway = $invoice->client->account->getGatewayByType(Session::get('payment_type')); + $gateway = $invoice->client->account->getGatewayByType(Session::get('payment_type'))->gateway; + $paymentLibrary = $gateway->paymentlibrary; + $acceptedCreditCardTypes = $accountGateway->getCreditcardTypes(); + + $data = [ + 'showBreadcrumbs' => false, + 'url' => 'payment/'.$invitationKey, + 'amount' => $invoice->balance, + 'invoiceNumber' => $invoice->invoice_number, + 'client' => $client, + 'contact' => $invitation->contact, + 'paymentLibrary' => $paymentLibrary, + 'gateway' => $gateway, + 'acceptedCreditCardTypes' => $acceptedCreditCardTypes, + 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'currencyId' => $client->currency_id, + 'account' => $client->account + ]; + + return View::make('payments.payment', $data); + } + + public function show_license_payment() + { + if (Input::has('return_url')) { + Session::set('return_url', Input::get('return_url')); + } + + if (Input::has('affiliate_key')) { + if ($affiliate = Affiliate::where('affiliate_key', '=', Input::get('affiliate_key'))->first()) { + Session::set('affiliate_id', $affiliate->id); + } + } + + Session::set('product_id', Input::get('product_id', PRODUCT_ONE_CLICK_INSTALL)); + + if (!Session::get('affiliate_id')) { + return Utils::fatalError(); + } + + if (Utils::isNinjaDev() && Input::has('test_mode')) { + Session::set('test_mode', Input::get('test_mode')); + } + + $account = $this->accountRepo->getNinjaAccount(); + $account->load('account_gateways.gateway'); + $accountGateway = $account->getGatewayByType(Session::get('payment_type')); + $gateway = $accountGateway->gateway; + $paymentLibrary = $gateway->paymentlibrary; + $acceptedCreditCardTypes = $accountGateway->getCreditcardTypes(); + + $affiliate = Affiliate::find(Session::get('affiliate_id')); + + $data = [ + 'showBreadcrumbs' => false, + 'hideHeader' => true, + 'url' => 'license', + 'amount' => $affiliate->price, + 'client' => false, + 'contact' => false, + 'paymentLibrary' => $paymentLibrary, + 'gateway' => $gateway, + 'acceptedCreditCardTypes' => $acceptedCreditCardTypes, + 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'currencyId' => 1, + 'paymentTitle' => $affiliate->payment_title, + 'paymentSubtitle' => $affiliate->payment_subtitle, + ]; + + return View::make('payments.payment', $data); + } + + public function do_license_payment() + { + $testMode = Session::get('test_mode') === 'true'; + + $rules = array( + 'first_name' => 'required', + 'last_name' => 'required', + 'card_number' => 'required', + 'expiration_month' => 'required', + 'expiration_year' => 'required', + 'cvv' => 'required', + 'address1' => 'required', + 'city' => 'required', + 'state' => 'required', + 'postal_code' => 'required', + ); + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to('license') + ->withErrors($validator); + } + + $account = $this->accountRepo->getNinjaAccount(); + $account->load('account_gateways.gateway'); + $accountGateway = $account->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD); + + try { + $affiliate = Affiliate::find(Session::get('affiliate_id')); + + if ($testMode) { + $ref = 'TEST_MODE'; + } else { + $gateway = self::createGateway($accountGateway); + $details = self::getLicensePaymentDetails(Input::all(), $affiliate); + $response = $gateway->purchase($details)->send(); + $ref = $response->getTransactionReference(); + + if (!$ref) { + Session::flash('error', $response->getMessage()); + + return Redirect::to('license')->withInput(); + } + + if (!$response->isSuccessful()) { + Session::flash('error', $response->getMessage()); + Utils::logError($response->getMessage()); + + return Redirect::to('license')->withInput(); + } + } + + $licenseKey = Utils::generateLicense(); + + $license = new License(); + $license->first_name = Input::get('first_name'); + $license->last_name = Input::get('last_name'); + $license->email = Input::get('email'); + $license->transaction_reference = $ref; + $license->license_key = $licenseKey; + $license->affiliate_id = Session::get('affiliate_id'); + $license->product_id = Session::get('product_id'); + $license->save(); + + $data = [ + 'message' => $affiliate->payment_subtitle, + 'license' => $licenseKey, + 'hideHeader' => true, + ]; + + $name = "{$license->first_name} {$license->last_name}"; + $this->contactMailer->sendLicensePaymentConfirmation($name, $license->email, $affiliate->price, $license->license_key, $license->product_id); + + if (Session::has('return_url')) { + return Redirect::away(Session::get('return_url')."?license_key={$license->license_key}&product_id=".Session::get('product_id')); + } else { + return View::make('public.license', $data); + } + } catch (\Exception $e) { + $errorMessage = trans('texts.payment_error'); + Session::flash('error', $errorMessage); + Utils::logError(Utils::getErrorString($e)); + + return Redirect::to('license')->withInput(); + } + } + + public function claim_license() + { + $licenseKey = Input::get('license_key'); + $productId = Input::get('product_id', PRODUCT_ONE_CLICK_INSTALL); + + $license = License::where('license_key', '=', $licenseKey) + ->where('is_claimed', '=', false) + ->where('product_id', '=', $productId) + ->first(); + + if ($license) { + if ($license->transaction_reference != 'TEST_MODE') { + $license->is_claimed = true; + $license->save(); + } + + return $productId == PRODUCT_INVOICE_DESIGNS ? $_ENV['INVOICE_DESIGNS'] : 'valid'; + } else { + return 'invalid'; + } + } + + public function do_payment($invitationKey, $onSite = true, $useToken = false) + { + $rules = array( + 'first_name' => 'required', + 'last_name' => 'required', + 'card_number' => 'required', + 'expiration_month' => 'required', + 'expiration_year' => 'required', + 'cvv' => 'required', + 'address1' => 'required', + 'city' => 'required', + 'state' => 'required', + 'postal_code' => 'required', + ); + + if ($onSite) { + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to('payment/'.$invitationKey) + ->withErrors($validator); + } + } + + $invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail(); + $invoice = $invitation->invoice; + $client = $invoice->client; + $account = $client->account; + $accountGateway = $account->getGatewayByType(Session::get('payment_type')); + $paymentLibrary = $accountGateway->gateway->paymentlibrary; + + if ($onSite) { + $client->address1 = trim(Input::get('address1')); + $client->address2 = trim(Input::get('address2')); + $client->city = trim(Input::get('city')); + $client->state = trim(Input::get('state')); + $client->postal_code = trim(Input::get('postal_code')); + $client->save(); + } + + try { + if ($paymentLibrary->id == PAYMENT_LIBRARY_OMNIPAY) { + $gateway = self::createGateway($accountGateway); + $details = self::getPaymentDetails($invitation, $useToken || !$onSite ? false : Input::all()); + + if ($accountGateway->gateway_id == GATEWAY_STRIPE) { + if ($useToken) { + $details['cardReference'] = $client->getGatewayToken(); + } elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing')) { + $tokenResponse = $gateway->createCard($details)->send(); + $cardReference = $tokenResponse->getCardReference(); + $details['cardReference'] = $cardReference; + + $token = AccountGatewayToken::where('client_id', '=', $client->id) + ->where('account_gateway_id', '=', $accountGateway->id)->first(); + + if (!$token) { + $token = new AccountGatewayToken(); + $token->account_id = $account->id; + $token->contact_id = $invitation->contact_id; + $token->account_gateway_id = $accountGateway->id; + $token->client_id = $client->id; + } + + $token->token = $cardReference; + $token->save(); + } + } + + $response = $gateway->purchase($details)->send(); + $ref = $response->getTransactionReference(); + + if (!$ref) { + + Session::flash('error', $response->getMessage()); + + if ($onSite) { + return Redirect::to('payment/'.$invitationKey)->withInput(); + } else { + return Redirect::to('view/'.$invitationKey); + } + } + + if ($response->isSuccessful()) { + $payment = self::createPayment($invitation, $ref); + Session::flash('message', trans('texts.applied_payment')); + + return Redirect::to('view/'.$payment->invitation->invitation_key); + } elseif ($response->isRedirect()) { + $invitation->transaction_reference = $ref; + $invitation->save(); + + Session::save(); + $response->redirect(); + } else { + Session::flash('error', $response->getMessage()); + + return Utils::fatalError('Sorry, there was an error processing your payment. Please try again later.

    ', $response->getMessage()); + } + } + } catch (\Exception $e) { + $errorMessage = trans('texts.payment_error'); + Session::flash('error', $errorMessage."

    ".$e->getMessage()); + Utils::logError(Utils::getErrorString($e)); + + if ($onSite) { + return Redirect::to('payment/'.$invitationKey)->withInput(); + } else { + return Redirect::to('view/'.$invitationKey); + } + } + } + + private function createPayment($invitation, $ref, $payerId = null) + { + $invoice = $invitation->invoice; + $accountGateway = $invoice->client->account->getGatewayByType(Session::get('payment_type')); + + if ($invoice->account->account_key == NINJA_ACCOUNT_KEY) { + $account = Account::find($invoice->client->public_id); + $account->pro_plan_paid = date_create()->format('Y-m-d'); + $account->save(); + } + + $payment = Payment::createNew($invitation); + $payment->invitation_id = $invitation->id; + $payment->account_gateway_id = $accountGateway->id; + $payment->invoice_id = $invoice->id; + $payment->amount = $invoice->balance; + $payment->client_id = $invoice->client_id; + $payment->contact_id = $invitation->contact_id; + $payment->transaction_reference = $ref; + $payment->payment_date = date_create()->format('Y-m-d'); + + if ($payerId) { + $payment->payer_id = $payerId; + } + + $payment->save(); + + Event::fire('invoice.paid', $payment); + + return $payment; + } + + public function offsite_payment() + { + $payerId = Request::query('PayerID'); + $token = Request::query('token'); + + $invitation = Invitation::with('invoice.client.currency', 'invoice.client.account.account_gateways.gateway')->where('transaction_reference', '=', $token)->firstOrFail(); + $invoice = $invitation->invoice; + + $accountGateway = $invoice->client->account->getGatewayByType(Session::get('payment_type')); + $gateway = self::createGateway($accountGateway); + + try { + $details = self::getPaymentDetails($invitation); + $response = $gateway->completePurchase($details)->send(); + $ref = $response->getTransactionReference(); + + if ($response->isSuccessful()) { + $payment = self::createPayment($invitation, $ref, $payerId); + + Session::flash('message', trans('texts.applied_payment')); + + return Redirect::to('view/'.$invitation->invitation_key); + } else { + $errorMessage = trans('texts.payment_error')."\n\n".$response->getMessage(); + Session::flash('error', $errorMessage); + Utils::logError($errorMessage); + + return Redirect::to('view/'.$invitation->invitation_key); + } + } catch (\Exception $e) { + $errorMessage = trans('texts.payment_error'); + Session::flash('error', $errorMessage); + Utils::logError($errorMessage."\n\n".$e->getMessage()); + + return Redirect::to('view/'.$invitation->invitation_key); + } + } + + public function store() + { + return $this->save(); + } + + public function update($publicId) + { + return $this->save($publicId); + } + + private function save($publicId = null) + { + if (!$publicId && $errors = $this->paymentRepo->getErrors(Input::all())) { + $url = $publicId ? 'payments/'.$publicId.'/edit' : 'payments/create'; + + return Redirect::to($url) + ->withErrors($errors) + ->withInput(); + } else { + $this->paymentRepo->save($publicId, Input::all()); + + if ($publicId) { + Session::flash('message', trans('texts.updated_payment')); + + return Redirect::to('payments/'); + } else { + Session::flash('message', trans('texts.created_payment')); + + return Redirect::to('clients/'.Input::get('client')); + } + } + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('id') ? Input::get('id') : Input::get('ids'); + $count = $this->paymentRepo->bulk($ids, $action); + + if ($count > 0) { + $message = Utils::pluralize($action.'d_payment', $count); + Session::flash('message', $message); + } + + return Redirect::to('payments'); + } +} diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php new file mode 100644 index 000000000000..5be7ab1339fa --- /dev/null +++ b/app/Http/Controllers/ProductController.php @@ -0,0 +1,96 @@ +where('products.account_id', '=', Auth::user()->account_id) + ->where('products.deleted_at', '=', null) + ->select('products.public_id', 'products.product_key', 'products.notes', 'products.cost'); + + return Datatable::query($query) + ->addColumn('product_key', function ($model) { return link_to('products/'.$model->public_id.'/edit', $model->product_key); }) + ->addColumn('notes', function ($model) { return nl2br(Str::limit($model->notes, 100)); }) + ->addColumn('cost', function ($model) { return Utils::formatMoney($model->cost); }) + ->addColumn('dropdown', function ($model) { + return '

    '; + }) + ->orderColumns(['cost', 'product_key', 'cost']) + ->make(); + } + + public function edit($publicId) + { + $data = [ + 'showBreadcrumbs' => false, + 'product' => Product::scope($publicId)->firstOrFail(), + 'method' => 'PUT', + 'url' => 'products/'.$publicId, + 'title' => trans('texts.edit_product'), + ]; + + return View::make('accounts.product', $data); + } + + public function create() + { + $data = [ + 'showBreadcrumbs' => false, + 'product' => null, + 'method' => 'POST', + 'url' => 'products', + 'title' => trans('texts.create_product'), + ]; + + return View::make('accounts.product', $data); + } + + public function store() + { + return $this->save(); + } + + public function update($publicId) + { + return $this->save($publicId); + } + + private function save($productPublicId = false) + { + if ($productPublicId) { + $product = Product::scope($productPublicId)->firstOrFail(); + } else { + $product = Product::createNew(); + } + + $product->product_key = trim(Input::get('product_key')); + $product->notes = trim(Input::get('notes')); + $product->cost = trim(Input::get('cost')); + $product->save(); + + $message = $productPublicId ? trans('texts.updated_product') : trans('texts.created_product'); + Session::flash('message', $message); + + return Redirect::to('company/products'); + } + + public function archive($publicId) + { + $product = Product::scope($publicId)->firstOrFail(); + $product->delete(); + + Session::flash('message', trans('texts.archived_product')); + + return Redirect::to('company/products'); + } +} diff --git a/app/Http/Controllers/QuoteApiController.php b/app/Http/Controllers/QuoteApiController.php new file mode 100644 index 000000000000..713f92997cb6 --- /dev/null +++ b/app/Http/Controllers/QuoteApiController.php @@ -0,0 +1,36 @@ +invoiceRepo = $invoiceRepo; + } + + public function index() + { + $invoices = Invoice::scope()->where('invoices.is_quote', '=', true)->orderBy('created_at', 'desc')->get(); + $invoices = Utils::remapPublicIds($invoices->toArray()); + + $response = json_encode($invoices, JSON_PRETTY_PRINT); + $headers = Utils::getApiHeaders(count($invoices)); + + return Response::make($response, 200, $headers); + } + + /* + public function store() + { + $data = Input::all(); + $invoice = $this->invoiceRepo->save(false, $data, false); + + $response = json_encode($invoice, JSON_PRETTY_PRINT); + $headers = Utils::getApiHeaders(); + return Response::make($response, 200, $headers); + } + */ +} diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php new file mode 100644 index 000000000000..199d6b1130a9 --- /dev/null +++ b/app/Http/Controllers/QuoteController.php @@ -0,0 +1,187 @@ +mailer = $mailer; + $this->invoiceRepo = $invoiceRepo; + $this->clientRepo = $clientRepo; + $this->taxRateRepo = $taxRateRepo; + } + + public function index() + { + if (!Utils::isPro()) { + return Redirect::to('/invoices/create'); + } + + $data = [ + 'title' => trans('texts.quotes'), + 'entityType' => ENTITY_QUOTE, + 'columns' => Utils::trans(['checkbox', 'quote_number', 'client', 'quote_date', 'quote_total', 'due_date', 'status', 'action']), + ]; + + /* + if (Invoice::scope()->where('is_recurring', '=', true)->count() > 0) + { + $data['secEntityType'] = ENTITY_RECURRING_INVOICE; + $data['secColumns'] = Utils::trans(['checkbox', 'frequency', 'client', 'start_date', 'end_date', 'quote_total', 'action']); + } + */ + + return View::make('list', $data); + } + + public function clientIndex() + { + $invitationKey = Session::get('invitation_key'); + if (!$invitationKey) { + return Redirect::to('/setup'); + } + + $invitation = Invitation::with('account')->where('invitation_key', '=', $invitationKey)->first(); + $color = $invitation->account->primary_color ? $invitation->account->primary_color : '#0b4d78'; + + $data = [ + 'color' => $color, + 'hideLogo' => Session::get('white_label'), + 'title' => trans('texts.quotes'), + 'entityType' => ENTITY_QUOTE, + 'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date']), + ]; + + return View::make('public_list', $data); + } + + public function getDatatable($clientPublicId = null) + { + $accountId = Auth::user()->account_id; + $search = Input::get('sSearch'); + + return $this->invoiceRepo->getDatatable($accountId, $clientPublicId, ENTITY_QUOTE, $search); + } + + public function getClientDatatable() + { + $search = Input::get('sSearch'); + $invitationKey = Session::get('invitation_key'); + $invitation = Invitation::where('invitation_key', '=', $invitationKey)->first(); + + if (!$invitation || $invitation->is_deleted) { + return []; + } + + $invoice = $invitation->invoice; + + if (!$invoice || $invoice->is_deleted) { + return []; + } + + return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, $search); + } + + public function create($clientPublicId = 0) + { + if (!Utils::isPro()) { + return Redirect::to('/invoices/create'); + } + + $client = null; + $invoiceNumber = Auth::user()->account->getNextInvoiceNumber(true); + $account = Account::with('country')->findOrFail(Auth::user()->account_id); + + if ($clientPublicId) { + $client = Client::scope($clientPublicId)->firstOrFail(); + } + + $data = array( + 'account' => $account, + 'invoice' => null, + 'data' => Input::old('data'), + 'invoiceNumber' => $invoiceNumber, + 'method' => 'POST', + 'url' => 'invoices', + 'title' => trans('texts.new_quote'), + 'client' => $client, ); + $data = array_merge($data, self::getViewModel()); + + return View::make('invoices.edit', $data); + } + + private static function getViewModel() + { + return [ + 'entityType' => ENTITY_QUOTE, + 'account' => Auth::user()->account, + 'products' => Product::scope()->orderBy('id')->get(array('product_key', 'notes', 'cost', 'qty')), + 'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(), + 'taxRates' => TaxRate::scope()->orderBy('name')->get(), + 'currencies' => Currency::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'sizes' => Size::remember(DEFAULT_QUERY_CACHE)->orderBy('id')->get(), + 'paymentTerms' => PaymentTerm::remember(DEFAULT_QUERY_CACHE)->orderBy('num_days')->get(['name', 'num_days']), + 'industries' => Industry::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(), + 'invoiceDesigns' => InvoiceDesign::remember(DEFAULT_QUERY_CACHE, 'invoice_designs_cache_'.Auth::user()->maxInvoiceDesignId()) + ->where('id', '<=', Auth::user()->maxInvoiceDesignId())->orderBy('id')->get(), + 'invoiceLabels' => Auth::user()->account->getInvoiceLabels() + ]; + } + + public function bulk() + { + $action = Input::get('action'); + + if ($action == 'convert') { + $invoice = Invoice::with('invoice_items')->scope(Input::get('id'))->firstOrFail(); + $clone = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id); + + Session::flash('message', trans('texts.converted_to_invoice')); + return Redirect::to('invoices/'.$clone->public_id); + } + + $statusId = Input::get('statusId'); + $ids = Input::get('id') ? Input::get('id') : Input::get('ids'); + $count = $this->invoiceRepo->bulk($ids, $action, $statusId); + + if ($count > 0) { + $key = $action == 'mark' ? "updated_quote" : "{$action}d_quote"; + $message = Utils::pluralize($key, $count); + Session::flash('message', $message); + } + + return Redirect::to('quotes'); + } + + public function approve($invitationKey) + { + $invitation = Invitation::with('invoice.invoice_items', 'invoice.invitations')->where('invitation_key', '=', $invitationKey)->firstOrFail(); + $invoice = $invitation->invoice; + + if ($invoice->is_quote && !$invoice->quote_invoice_id) { + Activity::approveQuote($invitation); + $invoice = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id); + Session::flash('message', trans('texts.converted_to_invoice')); + + foreach ($invoice->invitations as $invitationClone) { + if ($invitation->contact_id == $invitationClone->contact_id) { + $invitationKey = $invitationClone->invitation_key; + } + } + } + + return Redirect::to("view/{$invitationKey}"); + } +} diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php new file mode 100644 index 000000000000..9000b8165444 --- /dev/null +++ b/app/Http/Controllers/ReportController.php @@ -0,0 +1,127 @@ +account->isPro()) { + $account = Account::where('id', '=', Auth::user()->account->id)->with(['clients.invoices.invoice_items', 'clients.contacts'])->first(); + $account = $account->hideFieldsForViz(); + $clients = $account->clients->toJson(); + } elseif (isset($_ENV['DATA_VIZ_SAMPLE'])) { + $clients = $_ENV['DATA_VIZ_SAMPLE']; + $message = trans('texts.sample_data'); + } else { + $clients = '[]'; + } + + $data = [ + 'feature' => ACCOUNT_DATA_VISUALIZATIONS, + 'clients' => $clients, + 'message' => $message, + ]; + + return View::make('reports.d3', $data); + } + + public function report() + { + if (Input::all()) { + $groupBy = Input::get('group_by'); + $chartType = Input::get('chart_type'); + $startDate = Utils::toSqlDate(Input::get('start_date'), false); + $endDate = Utils::toSqlDate(Input::get('end_date'), false); + } else { + $groupBy = 'MONTH'; + $chartType = 'Bar'; + $startDate = Utils::today(false)->modify('-3 month'); + $endDate = Utils::today(false); + } + + $padding = $groupBy == 'DAYOFYEAR' ? 'day' : ($groupBy == 'WEEK' ? 'week' : 'month'); + $endDate->modify('+1 '.$padding); + $datasets = []; + $labels = []; + $maxTotals = 0; + $width = 10; + + if (Auth::user()->account->isPro()) { + foreach ([ENTITY_INVOICE, ENTITY_PAYMENT, ENTITY_CREDIT] as $entityType) { + $records = DB::table($entityType.'s') + ->select(DB::raw('sum(amount) as total, '.$groupBy.'('.$entityType.'_date) as '.$groupBy)) + ->where('account_id', '=', Auth::user()->account_id) + ->where($entityType.'s.is_deleted', '=', false) + ->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d')) + ->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d')) + ->groupBy($groupBy); + + if ($entityType == ENTITY_INVOICE) { + $records->where('is_quote', '=', false) + ->where('is_recurring', '=', false); + } + + $totals = $records->lists('total'); + $dates = $records->lists($groupBy); + $data = array_combine($dates, $totals); + + $interval = new DateInterval('P1'.substr($groupBy, 0, 1)); + $period = new DatePeriod($startDate, $interval, $endDate); + + $totals = []; + + foreach ($period as $d) { + $dateFormat = $groupBy == 'DAYOFYEAR' ? 'z' : ($groupBy == 'WEEK' ? 'W' : 'n'); + $date = $d->format($dateFormat); + $totals[] = isset($data[$date]) ? $data[$date] : 0; + + if ($entityType == ENTITY_INVOICE) { + $labelFormat = $groupBy == 'DAYOFYEAR' ? 'j' : ($groupBy == 'WEEK' ? 'W' : 'F'); + $label = $d->format($labelFormat); + $labels[] = $label; + } + } + + $max = max($totals); + + if ($max > 0) { + $datasets[] = [ + 'totals' => $totals, + 'colors' => $entityType == ENTITY_INVOICE ? '78,205,196' : ($entityType == ENTITY_CREDIT ? '199,244,100' : '255,107,107'), + ]; + $maxTotals = max($max, $maxTotals); + } + } + + $width = (ceil($maxTotals / 100) * 100) / 10; + $width = max($width, 10); + } + + $dateTypes = [ + 'DAYOFYEAR' => 'Daily', + 'WEEK' => 'Weekly', + 'MONTH' => 'Monthly', + ]; + + $chartTypes = [ + 'Bar' => 'Bar', + 'Line' => 'Line', + ]; + + $params = [ + 'labels' => $labels, + 'datasets' => $datasets, + 'scaleStepWidth' => $width, + 'dateTypes' => $dateTypes, + 'chartTypes' => $chartTypes, + 'chartType' => $chartType, + 'startDate' => $startDate->format(Session::get(SESSION_DATE_FORMAT)), + 'endDate' => $endDate->modify('-1'.$padding)->format(Session::get(SESSION_DATE_FORMAT)), + 'groupBy' => $groupBy, + 'feature' => ACCOUNT_CHART_BUILDER, + ]; + + return View::make('reports.report_builder', $params); + } +} diff --git a/app/Http/Controllers/TimesheetController.php b/app/Http/Controllers/TimesheetController.php new file mode 100644 index 000000000000..afc6982a5d5e --- /dev/null +++ b/app/Http/Controllers/TimesheetController.php @@ -0,0 +1,93 @@ + false, + 'timesheet' => [ + 'timesheet_number' => 1 + ] + ]; + + return View::make('timesheets.edit', $data); + } + + + /** + * Show the form for creating a new resource. + * + * @return Response + */ + public function create() + { + // + } + + + /** + * Store a newly created resource in storage. + * + * @return Response + */ + public function store() + { + // + } + + + /** + * Display the specified resource. + * + * @param int $id + * @return Response + */ + public function show($id) + { + // + } + + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return Response + */ + public function edit($id) + { + // + } + + + /** + * Update the specified resource in storage. + * + * @param int $id + * @return Response + */ + public function update($id) + { + // + } + + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return Response + */ + public function destroy($id) + { + // + } + + +} diff --git a/app/Http/Controllers/TokenController.php b/app/Http/Controllers/TokenController.php new file mode 100644 index 000000000000..ba7924d49479 --- /dev/null +++ b/app/Http/Controllers/TokenController.php @@ -0,0 +1,161 @@ +where('account_tokens.account_id', '=', Auth::user()->account_id); + + if (!Session::get('show_trash:token')) { + $query->where('account_tokens.deleted_at', '=', null); + } + + $query->select('account_tokens.public_id', 'account_tokens.name', 'account_tokens.token', 'account_tokens.public_id', 'account_tokens.deleted_at'); + + return Datatable::query($query) + ->addColumn('name', function ($model) { return link_to('tokens/'.$model->public_id.'/edit', $model->name); }) + ->addColumn('token', function ($model) { return $model->token; }) + ->addColumn('dropdown', function ($model) { + $actions = ''; + + return $actions; + }) + ->orderColumns(['name', 'token']) + ->make(); + } + + public function edit($publicId) + { + $token = AccountToken::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $publicId)->firstOrFail(); + + $data = [ + 'showBreadcrumbs' => false, + 'token' => $token, + 'method' => 'PUT', + 'url' => 'tokens/'.$publicId, + 'title' => trans('texts.edit_token'), + ]; + + return View::make('accounts.token', $data); + } + + public function update($publicId) + { + return $this->save($publicId); + } + + public function store() + { + return $this->save(); + } + + /** + * Displays the form for account creation + * + */ + public function create() + { + if (!Auth::user()->confirmed) { + Session::flash('error', trans('texts.register_to_add_user')); + return Redirect::to('company/advanced_settings/user_management'); + } + + $data = [ + 'showBreadcrumbs' => false, + 'token' => null, + 'method' => 'POST', + 'url' => 'tokens', + 'title' => trans('texts.add_token'), + ]; + + return View::make('accounts.token', $data); + } + + public function delete() + { + $tokenPublicId = Input::get('tokenPublicId'); + $token = AccountToken::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $tokenPublicId)->firstOrFail(); + + $token->delete(); + + Session::flash('message', trans('texts.deleted_token')); + + return Redirect::to('company/advanced_settings/token_management'); + } + + /** + * Stores new account + * + */ + public function save($tokenPublicId = false) + { + if (Auth::user()->account->isPro()) { + $rules = [ + 'name' => 'required', + ]; + + if ($tokenPublicId) { + $token = AccountToken::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $tokenPublicId)->firstOrFail(); + } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to($tokenPublicId ? 'tokens/edit' : 'tokens/create')->withInput()->withErrors($validator); + } + + if ($tokenPublicId) { + $token->name = trim(Input::get('name')); + } else { + $lastToken = AccountToken::withTrashed()->where('account_id', '=', Auth::user()->account_id) + ->orderBy('public_id', 'DESC')->first(); + + $token = AccountToken::createNew(); + $token->name = trim(Input::get('name')); + $token->token = str_random(RANDOM_KEY_LENGTH); + $token->public_id = $lastToken ? $lastToken->public_id + 1 : 1; + } + + $token->save(); + + if ($tokenPublicId) { + $message = trans('texts.updated_token'); + } else { + $message = trans('texts.created_token'); + } + + Session::flash('message', $message); + } + + return Redirect::to('company/advanced_settings/token_management'); + } + +} diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php new file mode 100644 index 000000000000..85fff4f86da3 --- /dev/null +++ b/app/Http/Controllers/UserController.php @@ -0,0 +1,507 @@ +accountRepo = $accountRepo; + $this->contactMailer = $contactMailer; + $this->userMailer = $userMailer; + } + + public function getDatatable() + { + $query = DB::table('users') + ->where('users.account_id', '=', Auth::user()->account_id); + + if (!Session::get('show_trash:user')) { + $query->where('users.deleted_at', '=', null); + } + + $query->where('users.public_id', '>', 0) + ->select('users.public_id', 'users.first_name', 'users.last_name', 'users.email', 'users.confirmed', 'users.public_id', 'users.deleted_at'); + + return Datatable::query($query) + ->addColumn('first_name', function ($model) { return link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name); }) + ->addColumn('email', function ($model) { return $model->email; }) + ->addColumn('confirmed', function ($model) { return $model->deleted_at ? trans('texts.deleted') : ($model->confirmed ? trans('texts.active') : trans('texts.pending')); }) + ->addColumn('dropdown', function ($model) { + $actions = ''; + + return $actions; + }) + ->orderColumns(['first_name', 'email', 'confirmed']) + ->make(); + } + + public function setTheme() + { + $user = User::find(Auth::user()->id); + $user->theme_id = Input::get('theme_id'); + $user->save(); + + return Redirect::to(Input::get('path')); + } + + public function forcePDFJS() + { + $user = Auth::user(); + $user->force_pdfjs = true; + $user->save(); + + Session::flash('message', trans('texts.confide.updated_settings')); + + return Redirect::to('/dashboard'); + } + + public function edit($publicId) + { + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $publicId)->firstOrFail(); + + $data = [ + 'showBreadcrumbs' => false, + 'user' => $user, + 'method' => 'PUT', + 'url' => 'users/'.$publicId, + 'title' => trans('texts.edit_user'), + ]; + + return View::make('users.edit', $data); + } + + public function update($publicId) + { + return $this->save($publicId); + } + + public function store() + { + return $this->save(); + } + + /** + * Displays the form for account creation + * + */ + public function create() + { + if (!Auth::user()->confirmed) { + Session::flash('error', trans('texts.register_to_add_user')); + + return Redirect::to('company/advanced_settings/user_management'); + } + + if (Utils::isNinja()) { + $count = User::where('account_id', '=', Auth::user()->account_id)->count(); + if ($count >= MAX_NUM_USERS) { + Session::flash('error', trans('texts.limit_users')); + + return Redirect::to('company/advanced_settings/user_management'); + } + } + + $data = [ + 'showBreadcrumbs' => false, + 'user' => null, + 'method' => 'POST', + 'url' => 'users', + 'title' => trans('texts.add_user'), + ]; + + return View::make('users.edit', $data); + } + + public function delete() + { + $userPublicId = Input::get('userPublicId'); + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $userPublicId)->firstOrFail(); + + $user->delete(); + + Session::flash('message', trans('texts.deleted_user')); + + return Redirect::to('company/advanced_settings/user_management'); + } + + public function restoreUser($userPublicId) + { + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $userPublicId) + ->withTrashed()->firstOrFail(); + + $user->restore(); + + Session::flash('message', trans('texts.restored_user')); + + return Redirect::to('company/advanced_settings/user_management'); + } + + /** + * Stores new account + * + */ + public function save($userPublicId = false) + { + if (Auth::user()->account->isPro()) { + $rules = [ + 'first_name' => 'required', + 'last_name' => 'required', + ]; + + if ($userPublicId) { + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $userPublicId)->firstOrFail(); + + $rules['email'] = 'required|email|unique:users,email,'.$user->id.',id'; + } else { + $rules['email'] = 'required|email|unique:users'; + } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to($userPublicId ? 'users/edit' : 'users/create')->withInput()->withErrors($validator); + } + + if ($userPublicId) { + $user->first_name = trim(Input::get('first_name')); + $user->last_name = trim(Input::get('last_name')); + $user->username = trim(Input::get('email')); + $user->email = trim(Input::get('email')); + } else { + $lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id) + ->orderBy('public_id', 'DESC')->first(); + + $user = new User(); + $user->account_id = Auth::user()->account_id; + $user->first_name = trim(Input::get('first_name')); + $user->last_name = trim(Input::get('last_name')); + $user->username = trim(Input::get('email')); + $user->email = trim(Input::get('email')); + $user->registered = true; + $user->password = str_random(RANDOM_KEY_LENGTH); + $user->password_confirmation = $user->password; + $user->public_id = $lastUser->public_id + 1; + } + + $user->save(); + + if (!$user->confirmed) { + $this->userMailer->sendConfirmation($user, Auth::user()); + $message = trans('texts.sent_invite'); + } else { + $message = trans('texts.updated_user'); + } + + Session::flash('message', $message); + } + + return Redirect::to('company/advanced_settings/user_management'); + } + + public function sendConfirmation($userPublicId) + { + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $userPublicId)->firstOrFail(); + + $this->userMailer->sendConfirmation($user, Auth::user()); + Session::flash('message', trans('texts.sent_invite')); + + return Redirect::to('company/advanced_settings/user_management'); + } + + /** + * Displays the login form + * + */ + public function login() + { + if (Confide::user()) { + Event::fire('user.login'); + Session::reflash(); + + return Redirect::to('/dashboard'); + + /* + $invoice = Invoice::scope()->orderBy('id', 'desc')->first(); + + if ($invoice) + { + return Redirect::to('/invoices/' . $invoice->public_id); + } + else + { + return Redirect::to('/dashboard'); + } + */ + } else { + return View::make(Config::get('confide::login_form')); + } + } + + /** + * Attempt to do login + * + */ + public function do_login() + { + $input = array( + 'email' => Input::get('login_email'), // May be the username too + 'username' => Input::get('login_email'), // so we have to pass both + 'password' => Input::get('login_password'), + 'remember' => true, + ); + + // If you wish to only allow login from confirmed users, call logAttempt + // with the second parameter as true. + // logAttempt will check if the 'email' perhaps is the username. + // Get the value from the config file instead of changing the controller + if (Input::get('login_email') && Confide::logAttempt($input, false)) { + Event::fire('user.login'); + // Redirect the user to the URL they were trying to access before + // caught by the authentication filter IE Redirect::guest('user/login'). + // Otherwise fallback to '/' + // Fix pull #145 + return Redirect::intended('/dashboard'); // change it to '/admin', '/dashboard' or something + } else { + //$user = new User; + + // Check if there was too many login attempts + if (Confide::isThrottled($input)) { + $err_msg = trans('texts.confide.too_many_attempts'); + } + /* + elseif( $user->checkUserExists( $input ) and ! $user->isConfirmed( $input ) ) + { + $err_msg = Lang::get('confide::confide.alerts.not_confirmed'); + } + */ + else { + $err_msg = trans('texts.confide.wrong_credentials'); + } + + return Redirect::action('UserController@login') + ->withInput(Input::except('login_password')) + ->with('error', $err_msg); + } + } + + /** + * Attempt to confirm account with code + * + * @param string $code + */ + public function confirm($code) + { + if (Confide::confirm($code)) { + $notice_msg = trans('texts.confide.confirmation'); + + $user = User::where('confirmation_code', '=', $code)->get()->first(); + $user->confirmation_code = ''; + $user->save(); + + if ($user->public_id) { + Auth::login($user); + + return Redirect::to('user/reset'); + } else { + if (Session::has(REQUESTED_PRO_PLAN)) { + Session::forget(REQUESTED_PRO_PLAN); + $invitation = $this->accountRepo->enableProPlan(); + + return Redirect::to($invitation->getLink()); + } else { + return Redirect::action('UserController@login')->with('message', $notice_msg); + } + } + } else { + $error_msg = trans('texts.confide.wrong_confirmation'); + + return Redirect::action('UserController@login')->with('error', $error_msg); + } + } + + /** + * Displays the forgot password form + * + */ + public function forgot_password() + { + return View::make(Config::get('confide::forgot_password_form')); + } + + /** + * Attempt to send change password link to the given email + * + */ + public function do_forgot_password() + { + Confide::forgotPassword(Input::get('email')); + + $notice_msg = trans('texts.confide.password_forgot'); + + return Redirect::action('UserController@login') + ->with('notice', $notice_msg); + + /* + if( Confide::forgotPassword( Input::get( 'email' ) ) ) + { + $notice_msg = Lang::get('confide::confide.alerts.password_forgot'); + return Redirect::action('UserController@login') + ->with( 'notice', $notice_msg ); + } + else + { + $error_msg = Lang::get('confide::confide.alerts.wrong_password_forgot'); + return Redirect::action('UserController@forgot_password') + ->withInput() + ->with( 'error', $error_msg ); + } + */ + } + + /** + * Shows the change password form with the given token + * + */ + public function reset_password($token = false) + { + return View::make(Config::get('confide::reset_password_form')) + ->with('token', $token); + } + + /** + * Attempt change password of the user + * + */ + public function do_reset_password() + { + if (Auth::check()) { + $rules = [ + 'password' => 'required|between:4,11|confirmed', + 'password_confirmation' => 'between:4,11', + ]; + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to('user/reset')->withInput()->withErrors($validator); + } + + $user = Auth::user(); + $user->password = Input::get('password'); + $user->save(); + + Session::flash('message', trans('texts.confide.password_reset')); + + return Redirect::to('/dashboard'); + } else { + $input = array( + 'token' => Input::get('token'), + 'password' => Input::get('password'), + 'password_confirmation' => Input::get('password_confirmation'), + ); + + // By passing an array with the token, password and confirmation + if (Confide::resetPassword($input)) { + $notice_msg = trans('texts.confide.password_reset'); + + return Redirect::action('UserController@login') + ->with('notice', $notice_msg); + } else { + $error_msg = trans('texts.confide.wrong_password_reset'); + + return Redirect::action('UserController@reset_password', array('token' => $input['token'])) + ->withInput() + ->with('error', $error_msg); + } + } + } + + /** + * Log the user out of the application. + * + */ + public function logout() + { + if (Auth::check()) { + if (!Auth::user()->registered) { + $account = Auth::user()->account; + $account->forceDelete(); + } + } + + Session::forget('news_feed_id'); + Session::forget('news_feed_message'); + + Confide::logout(); + + return Redirect::to('/')->with('clearGuestKey', true); + } + + public function changePassword() + { + // check the current password is correct + if (!Auth::validate([ + 'email' => Auth::user()->email, + 'password' => Input::get('current_password') + ])) { + return trans('texts.password_error_incorrect'); + } + + // validate the new password + $password = Input::get('new_password'); + $confirm = Input::get('confirm_password'); + + if (strlen($password) < 6 || $password != $confirm) { + return trans('texts.password_error_invalid'); + } + + // save the new password + $user = Auth::user(); + $user->password = $password; + $user->save(); + + return RESULT_SUCCESS; + } +} diff --git a/app/Http/Controllers/old/Auth/AuthController.php b/app/Http/Controllers/old/Auth/AuthController.php new file mode 100644 index 000000000000..32f55302e5b3 --- /dev/null +++ b/app/Http/Controllers/old/Auth/AuthController.php @@ -0,0 +1,38 @@ +auth = $auth; + $this->registrar = $registrar; + + $this->middleware('guest', ['except' => 'getLogout']); + } + +} diff --git a/app/Http/Controllers/old/Auth/PasswordController.php b/app/Http/Controllers/old/Auth/PasswordController.php new file mode 100644 index 000000000000..1b12cfa4f9ce --- /dev/null +++ b/app/Http/Controllers/old/Auth/PasswordController.php @@ -0,0 +1,38 @@ +auth = $auth; + $this->passwords = $passwords; + + $this->middleware('guest'); + } + +} diff --git a/app/Http/Controllers/old/HomeController.php b/app/Http/Controllers/old/HomeController.php new file mode 100644 index 000000000000..2050070ab5ef --- /dev/null +++ b/app/Http/Controllers/old/HomeController.php @@ -0,0 +1,36 @@ +middleware('auth'); + } + + /** + * Show the application dashboard to the user. + * + * @return Response + */ + public function index() + { + return view('home'); + } + +} diff --git a/app/Http/Controllers/old/WelcomeController.php b/app/Http/Controllers/old/WelcomeController.php new file mode 100644 index 000000000000..c7da91c94522 --- /dev/null +++ b/app/Http/Controllers/old/WelcomeController.php @@ -0,0 +1,36 @@ +middleware('guest'); + } + + /** + * Show the application welcome screen to the user. + * + * @return Response + */ + public function index() + { + return view('welcome'); + } + +} diff --git a/app/Http/routes.php b/app/Http/routes.php index fc436e177b86..9fbaa5ad9c25 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -64,7 +64,7 @@ Route::get('user/reset/{token?}', 'UserController@reset_password'); Route::post('user/reset', 'UserController@do_reset_password'); Route::get('logout', 'UserController@logout'); -if (Utils::isNinja()) { +if (\App\libraries\Utils::isNinja()) { Route::post('/signup/register', 'AccountController@doRegister'); Route::get('/news_feed/{user_type}/{version}/', 'HomeController@newsFeed'); Route::get('/demo', 'AccountController@demo'); diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php new file mode 100644 index 000000000000..609ae864cd35 --- /dev/null +++ b/app/Libraries/Utils.php @@ -0,0 +1,605 @@ +registered; + } + + public static function isConfirmed() + { + return Auth::check() && Auth::user()->confirmed; + } + + public static function isDatabaseSetup() + { + try { + if (Schema::hasTable('accounts')) { + return true; + } + } catch (Exception $e) { + return false; + } + } + + public static function isProd() + { + return App::environment() == ENV_PRODUCTION; + } + + public static function isNinja() + { + return self::isNinjaProd() || self::isNinjaDev(); + } + + public static function isNinjaProd() + { + return isset($_ENV['NINJA_PROD']) && $_ENV['NINJA_PROD']; + } + + public static function isNinjaDev() + { + return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV']; + } + + public static function isPro() + { + return Auth::check() && Auth::user()->isPro(); + } + + public static function getUserType() + { + if (Utils::isNinja()) { + return USER_TYPE_CLOUD_HOST; + } else { + return USER_TYPE_SELF_HOST; + } + } + + public static function getDemoAccountId() + { + return isset($_ENV[DEMO_ACCOUNT_ID]) ? $_ENV[DEMO_ACCOUNT_ID] : false; + } + + public static function isDemo() + { + return Auth::check() && Auth::user()->isDemo(); + } + + public static function getNewsFeedResponse($userType = false) + { + if (!$userType) { + $userType = Utils::getUserType(); + } + + $response = new stdClass(); + $response->message = isset($_ENV["{$userType}_MESSAGE"]) ? $_ENV["{$userType}_MESSAGE"] : ''; + $response->id = isset($_ENV["{$userType}_ID"]) ? $_ENV["{$userType}_ID"] : ''; + $response->version = NINJA_VERSION; + + return $response; + } + + public static function getProLabel($feature) + { + if (Auth::check() + && !Auth::user()->isPro() + && $feature == ACCOUNT_ADVANCED_SETTINGS) { + return ' PRO'; + } else { + return ''; + } + } + + public static function basePath() + { + return substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/') + 1); + } + + public static function trans($input) + { + $data = []; + + foreach ($input as $field) { + if ($field == "checkbox") { + $data[] = $field; + } else { + $data[] = trans("texts.$field"); + } + } + + return $data; + } + + public static function fatalError($message = false, $exception = false) + { + if (!$message) { + $message = "An error occurred, please try again later."; + } + + static::logError($message.' '.$exception); + + $data = [ + 'showBreadcrumbs' => false, + 'hideHeader' => true, + ]; + + return View::make('error', $data)->with('error', $message); + } + + public static function getErrorString($exception) + { + return "{$exception->getFile()} [Line {$exception->getLine()}] => {$exception->getMessage()}"; + } + + public static function logError($error, $context = 'PHP') + { + $count = Session::get('error_count', 0); + Session::put('error_count', ++$count); + if ($count > 100) { + return 'logged'; + } + + $data = [ + 'context' => $context, + 'user_id' => Auth::check() ? Auth::user()->id : 0, + 'user_name' => Auth::check() ? Auth::user()->getDisplayName() : '', + 'url' => Input::get('url', Request::url()), + 'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '', + 'ip' => Request::getClientIp(), + 'count' => Session::get('error_count', 0), + ]; + + Log::error($error."\n", $data); + + /* + Mail::queue('emails.error', ['message'=>$error.' '.json_encode($data)], function($message) + { + $message->to($email)->subject($subject); + }); + */ + } + + public static function parseFloat($value) + { + $value = preg_replace('/[^0-9\.\-]/', '', $value); + + return floatval($value); + } + + public static function formatPhoneNumber($phoneNumber) + { + $phoneNumber = preg_replace('/[^0-9a-zA-Z]/', '', $phoneNumber); + + if (!$phoneNumber) { + return ''; + } + + if (strlen($phoneNumber) > 10) { + $countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10); + $areaCode = substr($phoneNumber, -10, 3); + $nextThree = substr($phoneNumber, -7, 3); + $lastFour = substr($phoneNumber, -4, 4); + + $phoneNumber = '+'.$countryCode.' ('.$areaCode.') '.$nextThree.'-'.$lastFour; + } elseif (strlen($phoneNumber) == 10 && in_array(substr($phoneNumber, 0, 3), array(653, 656, 658, 659))) { + /** + * SG country code are 653, 656, 658, 659 + * US area code consist of 650, 651 and 657 + * @see http://en.wikipedia.org/wiki/Telephone_numbers_in_Singapore#Numbering_plan + * @see http://www.bennetyee.org/ucsd-pages/area.html + */ + $countryCode = substr($phoneNumber, 0, 2); + $nextFour = substr($phoneNumber, 2, 4); + $lastFour = substr($phoneNumber, 6, 4); + + $phoneNumber = '+'.$countryCode.' '.$nextFour.' '.$lastFour; + } elseif (strlen($phoneNumber) == 10) { + $areaCode = substr($phoneNumber, 0, 3); + $nextThree = substr($phoneNumber, 3, 3); + $lastFour = substr($phoneNumber, 6, 4); + + $phoneNumber = '('.$areaCode.') '.$nextThree.'-'.$lastFour; + } elseif (strlen($phoneNumber) == 7) { + $nextThree = substr($phoneNumber, 0, 3); + $lastFour = substr($phoneNumber, 3, 4); + + $phoneNumber = $nextThree.'-'.$lastFour; + } + + return $phoneNumber; + } + + public static function formatMoney($value, $currencyId = false) + { + if (!$currencyId) { + $currencyId = Session::get(SESSION_CURRENCY); + } + + $currency = Currency::remember(DEFAULT_QUERY_CACHE)->find($currencyId); + + if (!$currency) { + $currency = Currency::remember(DEFAULT_QUERY_CACHE)->find(1); + } + + return $currency->symbol.number_format($value, $currency->precision, $currency->decimal_separator, $currency->thousand_separator); + } + + public static function pluralize($string, $count) + { + $field = $count == 1 ? $string : $string.'s'; + $string = trans("texts.$field", ['count' => $count]); + + return $string; + } + + public static function toArray($data) + { + return json_decode(json_encode((array) $data), true); + } + + public static function toSpaceCase($camelStr) + { + return preg_replace('/([a-z])([A-Z])/s', '$1 $2', $camelStr); + } + + public static function timestampToDateTimeString($timestamp) + { + $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + $format = Session::get(SESSION_DATETIME_FORMAT, DEFAULT_DATETIME_FORMAT); + + return Utils::timestampToString($timestamp, $timezone, $format); + } + + public static function timestampToDateString($timestamp) + { + $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); + + return Utils::timestampToString($timestamp, $timezone, $format); + } + + public static function dateToString($date) + { + $dateTime = new DateTime($date); + $timestamp = $dateTime->getTimestamp(); + $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); + + return Utils::timestampToString($timestamp, false, $format); + } + + public static function timestampToString($timestamp, $timezone = false, $format) + { + if (!$timestamp) { + return ''; + } + $date = Carbon::createFromTimeStamp($timestamp); + if ($timezone) { + $date->tz = $timezone; + } + if ($date->year < 1900) { + return ''; + } + + return $date->format($format); + } + + public static function toSqlDate($date, $formatResult = true) + { + if (!$date) { + return; + } + + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + + $dateTime = DateTime::createFromFormat($format, $date, new DateTimeZone($timezone)); + + return $formatResult ? $dateTime->format('Y-m-d') : $dateTime; + } + + public static function fromSqlDate($date, $formatResult = true) + { + if (!$date || $date == '0000-00-00') { + return ''; + } + + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + + $dateTime = DateTime::createFromFormat('Y-m-d', $date, new DateTimeZone($timezone)); + + return $formatResult ? $dateTime->format($format) : $dateTime; + } + + public static function today($formatResult = true) + { + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + $date = date_create(null, new DateTimeZone($timezone)); + + if ($formatResult) { + return $date->format($format); + } else { + return $date; + } + } + + public static function trackViewed($name, $type, $url = false) + { + if (!$url) { + $url = Request::url(); + } + + $viewed = Session::get(RECENTLY_VIEWED); + + if (!$viewed) { + $viewed = []; + } + + $object = new stdClass(); + $object->url = $url; + $object->name = ucwords($type).': '.$name; + + $data = []; + + for ($i = 0; $iurl == $item->url || $object->name == $item->name) { + continue; + } + + array_unshift($data, $item); + } + + array_unshift($data, $object); + + if (count($data) > RECENTLY_VIEWED_LIMIT) { + array_pop($data); + } + + Session::put(RECENTLY_VIEWED, $data); + } + + public static function processVariables($str) + { + if (!$str) { + return ''; + } + + $variables = ['MONTH', 'QUARTER', 'YEAR']; + for ($i = 0; $i 1) { + $offset = intval($addArray[1]); + } elseif (count($minArray) > 1) { + $offset = intval($minArray[1]) * -1; + } + + $val = Utils::getDatePart($variable, $offset); + $str = str_replace($match, $val, $str); + } + } + + return $str; + } + + private static function getDatePart($part, $offset) + { + $offset = intval($offset); + if ($part == 'MONTH') { + return Utils::getMonth($offset); + } elseif ($part == 'QUARTER') { + return Utils::getQuarter($offset); + } elseif ($part == 'YEAR') { + return Utils::getYear($offset); + } + } + + private static function getMonth($offset) + { + $months = [ "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", ]; + + $month = intval(date('n')) - 1; + + $month += $offset; + $month = $month % 12; + + if ($month < 0) { + $month += 12; + } + + return $months[$month]; + } + + private static function getQuarter($offset) + { + $month = intval(date('n')) - 1; + $quarter = floor(($month + 3) / 3); + $quarter += $offset; + $quarter = $quarter % 4; + if ($quarter == 0) { + $quarter = 4; + } + + return 'Q'.$quarter; + } + + private static function getYear($offset) + { + $year = intval(date('Y')); + + return $year + $offset; + } + + public static function getEntityName($entityType) + { + return ucwords(str_replace('_', ' ', $entityType)); + } + + public static function getClientDisplayName($model) + { + if ($model->client_name) { + return $model->client_name; + } elseif ($model->first_name || $model->last_name) { + return $model->first_name.' '.$model->last_name; + } else { + return $model->email; + } + } + + public static function encodeActivity($person = null, $action, $entity = null, $otherPerson = null) + { + $person = $person ? $person->getDisplayName() : 'System'; + $entity = $entity ? '['.$entity->getActivityKey().']' : ''; + $otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : ''; + $token = Session::get('token_id') ? ' ('.trans('texts.token').')' : ''; + + return trim("$person $token $action $entity $otherPerson"); + } + + public static function decodeActivity($message) + { + $pattern = '/\[([\w]*):([\d]*):(.*)\]/i'; + preg_match($pattern, $message, $matches); + + if (count($matches) > 0) { + $match = $matches[0]; + $type = $matches[1]; + $publicId = $matches[2]; + $name = $matches[3]; + + $link = link_to($type.'s/'.$publicId, $name); + $message = str_replace($match, "$type $link", $message); + } + + return $message; + } + + public static function generateLicense() + { + $parts = []; + for ($i = 0; $i<5; $i++) { + $parts[] = strtoupper(str_random(4)); + } + + return implode('-', $parts); + } + + public static function lookupEventId($eventName) + { + if ($eventName == 'create_client') { + return EVENT_CREATE_CLIENT; + } elseif ($eventName == 'create_invoice') { + return EVENT_CREATE_INVOICE; + } elseif ($eventName == 'create_quote') { + return EVENT_CREATE_QUOTE; + } elseif ($eventName == 'create_payment') { + return EVENT_CREATE_PAYMENT; + } else { + return false; + } + } + + public static function notifyZapier($subscription, $data) + { + $curl = curl_init(); + + $jsonEncodedData = json_encode($data->toJson()); + $opts = [ + CURLOPT_URL => $subscription->target_url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => $jsonEncodedData, + CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: '.strlen($jsonEncodedData)], + ]; + + curl_setopt_array($curl, $opts); + + $result = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + curl_close($curl); + + if ($status == 410) { + $subscription->delete(); + } + } + + + public static function remapPublicIds(array $data) + { + $return = []; + + foreach ($data as $key => $val) { + if ($key === 'public_id') { + $key = 'id'; + } elseif (strpos($key, '_id')) { + continue; + } + + if (is_array($val)) { + $val = Utils::remapPublicIds($val); + } + + $return[$key] = $val; + } + + return $return; + } + + public static function getApiHeaders($count = 0) + { + return [ + 'Content-Type' => 'application/json', + //'Access-Control-Allow-Origin' => '*', + //'Access-Control-Allow-Methods' => 'GET', + //'Access-Control-Allow-Headers' => 'Origin, Content-Type, Accept, Authorization, X-Requested-With', + //'Access-Control-Allow-Credentials' => 'true', + 'X-Total-Count' => $count, + //'X-Rate-Limit-Limit' - The number of allowed requests in the current period + //'X-Rate-Limit-Remaining' - The number of remaining requests in the current period + //'X-Rate-Limit-Reset' - The number of seconds left in the current period, + ]; + } + + public static function startsWith($haystack, $needle) + { + return $needle === "" || strpos($haystack, $needle) === 0; + } + + public static function endsWith($haystack, $needle) + { + return $needle === "" || substr($haystack, -strlen($needle)) === $needle; + } + + public static function getEntityRowClass($model) + { + $str = $model->is_deleted || ($model->deleted_at && $model->deleted_at != '0000-00-00') ? 'DISABLED ' : ''; + + if ($model->is_deleted) { + $str .= 'ENTITY_DELETED '; + } + + if ($model->deleted_at && $model->deleted_at != '0000-00-00') { + $str .= 'ENTITY_ARCHIVED '; + } + + return $str; + } +} diff --git a/app/Libraries/entity.php b/app/Libraries/entity.php new file mode 100644 index 000000000000..57e447e2e271 --- /dev/null +++ b/app/Libraries/entity.php @@ -0,0 +1,8 @@ + '']; + foreach ($matches[1] as $i => $key) { + # Convert escaped linebreakes to linebreak + $value = preg_replace("/\r?\n\s/", "", $matches[2][$i]); + # Unescape , and ; + $value = preg_replace('/\\\\([,;])/s', '$1', $value); + $data[strtolower($key)] = $value; + } + return $data; + } else { + return false; + } + } + + + public static function parseICALDate($datestr) { + $dt = null; + $timezone = null; + if (preg_match('/^TZID=(.+?):([12]\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)$/', $datestr, $m)) { + $timezone = $m[1]; + $dt = new DateTime("{$m[2]}-{$m[3]}-{$m[4]}T{$m[5]}:{$m[6]}:{$m[7]}", new DateTimeZone($m[1])); + + } else if (preg_match('/^VALUE=DATE:([12]\d\d\d)(\d\d)(\d\d)$/', $datestr, $m)) { + $dt = new DateTime("{$m[1]}-{$m[2]}-{$m[3]}T00:00:00", new DateTimeZone("UTC")); + + } else if (preg_match('/^([12]\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)Z$/', $datestr, $m)) { + $dt = new DateTime("{$m[1]}-{$m[2]}-{$m[3]}T{$m[4]}:{$m[5]}:{$m[6]}", new DateTimeZone("UTC")); + + } else { + return false; + } + + // Convert all to UTC + if($dt->getTimezone()->getName() != 'UTC') { + $dt->setTimezone(new DateTimeZone('UTC')); + } + + return [$dt, $timezone]; + } + + public static function curlGetUrls($urls = [], $timeout = 30) { + // Create muxer + $results = []; + $multi = curl_multi_init(); + $handles = []; + $ch2idx = []; + try { + foreach ($urls as $i => $url) { + // Create new handle and add to muxer + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_ENCODING, "gzip"); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); //timeout in seconds + + curl_multi_add_handle($multi, $ch); + $handles[(int) $ch] = $ch; + $ch2idx[(int) $ch] = $i; + } + + // Do initial connect + $still_running = true; + while ($still_running) { + // Do curl stuff + while (($mrc = curl_multi_exec($multi, $still_running)) === CURLM_CALL_MULTI_PERFORM); + if ($mrc !== CURLM_OK) { + break; + } + + // Try to read from handles that are ready + while ($info = curl_multi_info_read($multi)) { + if ($info["result"] == CURLE_OK) { + $results[$ch2idx[(int) $info["handle"]]] = curl_multi_getcontent($info["handle"]); + } else { + if (CURLE_UNSUPPORTED_PROTOCOL == $info["result"]) { + $results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Unsupported protocol"]; + } else if (CURLE_URL_MALFORMAT == $info["result"]) { + $results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Malform url"]; + } else if (CURLE_COULDNT_RESOLVE_HOST == $info["result"]) { + $results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Could not resolve host"]; + } else if (CURLE_OPERATION_TIMEDOUT == $info["result"]) { + $results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Timed out waiting for operations to finish"]; + } else { + $results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Unknown curl error code"]; + } + } + } + + // Sleep until + if (($rs = curl_multi_select($multi)) === -1) { + usleep(20); // select failed for some reason, so we sleep for 20ms and run some more curl stuff + } + } + } finally { + foreach ($handles as $chi => $ch) { + curl_multi_remove_handle($multi, $ch); + } + + curl_multi_close($multi); + } + + return $results; + } +} diff --git a/app/Models/Account.php b/app/Models/Account.php new file mode 100644 index 000000000000..bbe026266a64 --- /dev/null +++ b/app/Models/Account.php @@ -0,0 +1,363 @@ +hasMany('User'); + } + + public function clients() + { + return $this->hasMany('Client'); + } + + public function invoices() + { + return $this->hasMany('Invoice'); + } + + public function account_gateways() + { + return $this->hasMany('AccountGateway'); + } + + public function tax_rates() + { + return $this->hasMany('TaxRate'); + } + + public function country() + { + return $this->belongsTo('Country'); + } + + public function timezone() + { + return $this->belongsTo('Timezone'); + } + + public function language() + { + return $this->belongsTo('Language'); + } + + public function date_format() + { + return $this->belongsTo('DateFormat'); + } + + public function datetime_format() + { + return $this->belongsTo('DatetimeFormat'); + } + + public function size() + { + return $this->belongsTo('Size'); + } + + public function industry() + { + return $this->belongsTo('Industry'); + } + + public function isGatewayConfigured($gatewayId = 0) + { + $this->load('account_gateways'); + + if ($gatewayId) { + return $this->getGatewayConfig($gatewayId) != false; + } else { + return count($this->account_gateways) > 0; + } + } + + public function getDisplayName() + { + if ($this->name) { + return $this->name; + } + + $this->load('users'); + $user = $this->users()->first(); + + return $user->getDisplayName(); + } + + public function getTimezone() + { + if ($this->timezone) { + return $this->timezone->name; + } else { + return 'US/Eastern'; + } + } + + public function getGatewayByType($type = PAYMENT_TYPE_ANY) + { + foreach ($this->account_gateways as $gateway) { + if ($type == PAYMENT_TYPE_ANY) { + return $gateway; + } elseif ($gateway->isPayPal() && $type == PAYMENT_TYPE_PAYPAL) { + return $gateway; + } elseif (!$gateway->isPayPal() && $type == PAYMENT_TYPE_CREDIT_CARD) { + return $gateway; + } + } + + return false; + } + + public function getGatewayConfig($gatewayId) + { + foreach ($this->account_gateways as $gateway) { + if ($gateway->gateway_id == $gatewayId) { + return $gateway; + } + } + + return false; + } + + public function getLogoPath() + { + return 'logo/'.$this->account_key.'.jpg'; + } + + public function getLogoWidth() + { + $path = $this->getLogoPath(); + if (!file_exists($path)) { + return 0; + } + list($width, $height) = getimagesize($path); + + return $width; + } + + public function getLogoHeight() + { + $path = $this->getLogoPath(); + if (!file_exists($path)) { + return 0; + } + list($width, $height) = getimagesize($path); + + return $height; + } + + public function getNextInvoiceNumber($isQuote = false) + { + $counter = $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter; + $prefix = $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix; + + return $prefix.str_pad($counter, 4, "0", STR_PAD_LEFT); + } + + public function incrementCounter($invoiceNumber, $isQuote = false, $isRecurring) + { + // check if the user modified the invoice number + if (!$isRecurring && $invoiceNumber != $this->getNextInvoiceNumber($isQuote)) { + $number = intval(preg_replace('/[^0-9]/', '', $invoiceNumber)); + if ($isQuote && !$this->share_counter) { + $this->quote_number_counter = $number + 1; + } else { + $this->invoice_number_counter = $number + 1; + } + // otherwise, just increment the counter + } else { + if ($isQuote && !$this->share_counter) { + $this->quote_number_counter += 1; + } else { + $this->invoice_number_counter += 1; + } + } + + $this->save(); + } + + public function getLocale() + { + $language = Language::remember(DEFAULT_QUERY_CACHE)->where('id', '=', $this->account->language_id)->first(); + + return $language->locale; + } + + public function loadLocalizationSettings() + { + $this->load('timezone', 'date_format', 'datetime_format', 'language'); + + Session::put(SESSION_TIMEZONE, $this->timezone ? $this->timezone->name : DEFAULT_TIMEZONE); + Session::put(SESSION_DATE_FORMAT, $this->date_format ? $this->date_format->format : DEFAULT_DATE_FORMAT); + Session::put(SESSION_DATE_PICKER_FORMAT, $this->date_format ? $this->date_format->picker_format : DEFAULT_DATE_PICKER_FORMAT); + Session::put(SESSION_DATETIME_FORMAT, $this->datetime_format ? $this->datetime_format->format : DEFAULT_DATETIME_FORMAT); + Session::put(SESSION_CURRENCY, $this->currency_id ? $this->currency_id : DEFAULT_CURRENCY); + Session::put(SESSION_LOCALE, $this->language_id ? $this->language->locale : DEFAULT_LOCALE); + } + + public function getInvoiceLabels() + { + $data = []; + $fields = [ + 'invoice', + 'invoice_date', + 'due_date', + 'invoice_number', + 'po_number', + 'discount', + 'taxes', + 'tax', + 'item', + 'description', + 'unit_cost', + 'quantity', + 'line_total', + 'subtotal', + 'paid_to_date', + 'balance_due', + 'terms', + 'your_invoice', + 'quote', + 'your_quote', + 'quote_date', + 'quote_number', + 'total', + 'invoice_issued_to', + ]; + + foreach ($fields as $field) { + $data[$field] = trans("texts.$field"); + } + + return $data; + } + + public function isPro() + { + if (!Utils::isNinjaProd()) { + return true; + } + + if ($this->account_key == NINJA_ACCOUNT_KEY) { + return true; + } + + $datePaid = $this->pro_plan_paid; + + if (!$datePaid || $datePaid == '0000-00-00') { + return false; + } elseif ($datePaid == NINJA_DATE) { + return true; + } + + $today = new DateTime('now'); + $datePaid = DateTime::createFromFormat('Y-m-d', $datePaid); + $interval = $today->diff($datePaid); + + return $interval->y == 0; + } + + public function isWhiteLabel() + { + if (Utils::isNinjaProd()) { + return false; + } + + return $this->pro_plan_paid == NINJA_DATE; + } + + public function getSubscription($eventId) + { + return Subscription::where('account_id', '=', $this->id)->where('event_id', '=', $eventId)->first(); + } + + public function hideFieldsForViz() + { + foreach ($this->clients as $client) { + $client->setVisible([ + 'public_id', + 'name', + 'balance', + 'paid_to_date', + 'invoices', + 'contacts', + ]); + + foreach ($client->invoices as $invoice) { + $invoice->setVisible([ + 'public_id', + 'invoice_number', + 'amount', + 'balance', + 'invoice_status_id', + 'invoice_items', + 'created_at', + ]); + + foreach ($invoice->invoice_items as $invoiceItem) { + $invoiceItem->setVisible([ + 'product_key', + 'cost', + 'qty', + ]); + } + } + + foreach ($client->contacts as $contact) { + $contact->setVisible([ + 'public_id', + 'first_name', + 'last_name', + 'email', ]); + } + } + + return $this; + } + + public function getEmailTemplate($entityType, $message = false) + { + $field = "email_template_$entityType"; + $template = $this->$field; + + if ($template) { + return $template; + } + + $template = "\$client,

    \r\n\r\n" . + trans("texts.{$entityType}_message", ['amount' => '$amount']) . "

    \r\n\r\n"; + + if ($entityType != ENTITY_PAYMENT) { + $template .= "\$link

    \r\n\r\n"; + } + + if ($message) { + $template .= "$message

    \r\n\r\n"; + } + + return $template . "\$footer"; + } + + public function getEmailFooter() + { + if ($this->email_footer) { + return $this->email_footer; + } else { + return "

    " . trans('texts.email_signature') . "
    \$account

    "; + } + } + + public function showTokenCheckbox() + { + return $this->token_billing_type_id == TOKEN_BILLING_OPT_IN + || $this->token_billing_type_id == TOKEN_BILLING_OPT_OUT; + } + + public function selectTokenCheckbox() + { + return $this->token_billing_type_id == TOKEN_BILLING_OPT_OUT; + } +} diff --git a/app/Models/AccountGateway.php b/app/Models/AccountGateway.php new file mode 100644 index 000000000000..002bc830795e --- /dev/null +++ b/app/Models/AccountGateway.php @@ -0,0 +1,28 @@ +belongsTo('Gateway'); + } + + public function getCreditcardTypes() + { + $flags = unserialize(CREDIT_CARDS); + $arrayOfImages = []; + + foreach ($flags as $card => $name) { + if (($this->accepted_credit_cards & $card) == $card) { + $arrayOfImages[] = ['source' => asset($name['card']), 'alt' => $name['text']]; + } + } + + return $arrayOfImages; + } + + public function isPayPal() { + return $this->gateway_id == GATEWAY_PAYPAL_EXPRESS; + } +} + diff --git a/app/Models/AccountGatewayToken.php b/app/Models/AccountGatewayToken.php new file mode 100644 index 000000000000..ae63d6c2d2cd --- /dev/null +++ b/app/Models/AccountGatewayToken.php @@ -0,0 +1,7 @@ +belongsTo('Account'); + } +} diff --git a/app/Models/Activity.php b/app/Models/Activity.php new file mode 100644 index 000000000000..9fe82178c612 --- /dev/null +++ b/app/Models/Activity.php @@ -0,0 +1,470 @@ +whereAccountId(Auth::user()->account_id); + } + + public function account() + { + return $this->belongsTo('Account'); + } + + public function user() + { + return $this->belongsTo('User'); + } + + private static function getBlank($entity = false) + { + $activity = new Activity(); + + if ($entity) { + $activity->user_id = $entity instanceof User ? $entity->id : $entity->user_id; + $activity->account_id = $entity->account_id; + } elseif (Auth::check()) { + $activity->user_id = Auth::user()->id; + $activity->account_id = Auth::user()->account_id; + } else { + Utils::fatalError(); + } + + $activity->token_id = Session::get('token_id', null); + $activity->ip = Request::getClientIp(); + + return $activity; + } + + public static function createClient($client, $notify = true) + { + $activity = Activity::getBlank(); + $activity->client_id = $client->id; + $activity->activity_type_id = ACTIVITY_TYPE_CREATE_CLIENT; + $activity->message = Utils::encodeActivity(Auth::user(), 'created', $client); + $activity->save(); + + if ($notify) { + Activity::checkSubscriptions(EVENT_CREATE_CLIENT, $client); + } + } + + public static function updateClient($client) + { + if ($client->is_deleted && !$client->getOriginal('is_deleted')) { + $activity = Activity::getBlank(); + $activity->client_id = $client->id; + $activity->activity_type_id = ACTIVITY_TYPE_DELETE_CLIENT; + $activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $client); + $activity->balance = $client->balance; + $activity->save(); + } + } + + public static function archiveClient($client) + { + if (!$client->is_deleted) { + $activity = Activity::getBlank(); + $activity->client_id = $client->id; + $activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CLIENT; + $activity->message = Utils::encodeActivity(Auth::user(), 'archived', $client); + $activity->balance = $client->balance; + $activity->save(); + } + } + + public static function restoreClient($client) + { + $activity = Activity::getBlank(); + $activity->client_id = $client->id; + $activity->activity_type_id = ACTIVITY_TYPE_RESTORE_CLIENT; + $activity->message = Utils::encodeActivity(Auth::user(), 'restored', $client); + $activity->balance = $client->balance; + $activity->save(); + } + + public static function createInvoice($invoice) + { + if (Auth::check()) { + $message = Utils::encodeActivity(Auth::user(), 'created', $invoice); + } else { + $message = Utils::encodeActivity(null, 'created', $invoice); + } + + $adjustment = 0; + $client = $invoice->client; + if (!$invoice->is_quote && !$invoice->is_recurring) { + $adjustment = $invoice->amount; + $client->balance = $client->balance + $adjustment; + $client->save(); + } + + $activity = Activity::getBlank($invoice); + $activity->invoice_id = $invoice->id; + $activity->client_id = $invoice->client_id; + $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_CREATE_QUOTE : ACTIVITY_TYPE_CREATE_INVOICE; + $activity->message = $message; + $activity->balance = $client->balance; + $activity->adjustment = $adjustment; + $activity->save(); + + Activity::checkSubscriptions($invoice->is_quote ? EVENT_CREATE_QUOTE : EVENT_CREATE_INVOICE, $invoice); + } + + public static function archiveInvoice($invoice) + { + if (!$invoice->is_deleted) { + $activity = Activity::getBlank(); + $activity->invoice_id = $invoice->id; + $activity->client_id = $invoice->client_id; + $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_ARCHIVE_QUOTE : ACTIVITY_TYPE_ARCHIVE_INVOICE; + $activity->message = Utils::encodeActivity(Auth::user(), 'archived', $invoice); + $activity->balance = $invoice->client->balance; + + $activity->save(); + } + } + + public static function restoreInvoice($invoice) + { + $activity = Activity::getBlank(); + $activity->invoice_id = $invoice->id; + $activity->client_id = $invoice->client_id; + $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_RESTORE_QUOTE : ACTIVITY_TYPE_RESTORE_INVOICE; + $activity->message = Utils::encodeActivity(Auth::user(), 'restored', $invoice); + $activity->balance = $invoice->client->balance; + + $activity->save(); + } + + public static function emailInvoice($invitation) + { + $adjustment = 0; + $client = $invitation->invoice->client; + + $activity = Activity::getBlank($invitation); + $activity->client_id = $invitation->invoice->client_id; + $activity->invoice_id = $invitation->invoice_id; + $activity->contact_id = $invitation->contact_id; + $activity->activity_type_id = $invitation->invoice ? ACTIVITY_TYPE_EMAIL_QUOTE : ACTIVITY_TYPE_EMAIL_INVOICE; + $activity->message = Utils::encodeActivity(Auth::check() ? Auth::user() : null, 'emailed', $invitation->invoice, $invitation->contact); + $activity->balance = $client->balance; + $activity->save(); + } + + public static function updateInvoice($invoice) + { + $client = $invoice->client; + + if ($invoice->is_deleted && !$invoice->getOriginal('is_deleted')) { + $adjustment = 0; + if (!$invoice->is_quote && !$invoice->is_recurring) { + $adjustment = $invoice->balance * -1; + $client->balance = $client->balance - $invoice->balance; + $client->paid_to_date = $client->paid_to_date - ($invoice->amount - $invoice->balance); + $client->save(); + } + + $activity = Activity::getBlank(); + $activity->client_id = $invoice->client_id; + $activity->invoice_id = $invoice->id; + $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_DELETE_QUOTE : ACTIVITY_TYPE_DELETE_INVOICE; + $activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $invoice); + $activity->balance = $invoice->client->balance; + $activity->adjustment = $adjustment; + $activity->save(); + } else { + $diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount')); + + $fieldChanged = false; + foreach (['invoice_number', 'po_number', 'invoice_date', 'due_date', 'terms', 'public_notes', 'invoice_footer'] as $field) { + if ($invoice->$field != $invoice->getOriginal($field)) { + $fieldChanged = true; + break; + } + } + + if ($diff > 0 || $fieldChanged) { + $backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($invoice->id); + + if ($diff > 0 && !$invoice->is_quote && !$invoice->is_recurring) { + $client->balance = $client->balance + $diff; + $client->save(); + } + + $activity = Activity::getBlank($invoice); + $activity->client_id = $invoice->client_id; + $activity->invoice_id = $invoice->id; + $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE; + $activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice); + $activity->balance = $client->balance; + $activity->adjustment = $invoice->is_quote || $invoice->is_recurring ? 0 : $diff; + $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON(); + $activity->save(); + + if ($invoice->isPaid() && $invoice->balance > 0) { + $invoice->invoice_status_id = INVOICE_STATUS_PARTIAL; + $invoice->save(); + } + } + } + } + + public static function viewInvoice($invitation) + { + if (Session::get($invitation->invitation_key)) { + return; + } + + Session::put($invitation->invitation_key, true); + $invoice = $invitation->invoice; + + if (!$invoice->isViewed()) { + $invoice->invoice_status_id = INVOICE_STATUS_VIEWED; + $invoice->save(); + } + + $now = Carbon::now()->toDateTimeString(); + + $invitation->viewed_date = $now; + $invitation->save(); + + $client = $invoice->client; + $client->last_login = $now; + $client->save(); + + $activity = Activity::getBlank($invitation); + $activity->client_id = $invitation->invoice->client_id; + $activity->invitation_id = $invitation->id; + $activity->contact_id = $invitation->contact_id; + $activity->invoice_id = $invitation->invoice_id; + $activity->activity_type_id = $invitation->invoice->is_quote ? ACTIVITY_TYPE_VIEW_QUOTE : ACTIVITY_TYPE_VIEW_INVOICE; + $activity->message = Utils::encodeActivity($invitation->contact, 'viewed', $invitation->invoice); + $activity->balance = $invitation->invoice->client->balance; + $activity->save(); + } + + public static function approveQuote($invitation) { + + $activity = Activity::getBlank($invitation); + $activity->client_id = $invitation->invoice->client_id; + $activity->invitation_id = $invitation->id; + $activity->contact_id = $invitation->contact_id; + $activity->invoice_id = $invitation->invoice_id; + $activity->activity_type_id = ACTIVITY_TYPE_APPROVE_QUOTE; + $activity->message = Utils::encodeActivity($invitation->contact, 'approved', $invitation->invoice); + $activity->balance = $invitation->invoice->client->balance; + $activity->save(); + } + + public static function createPayment($payment) + { + $client = $payment->client; + $client->balance = $client->balance - $payment->amount; + $client->paid_to_date = $client->paid_to_date + $payment->amount; + $client->save(); + + if ($payment->contact_id) { + $activity = Activity::getBlank($client); + $activity->contact_id = $payment->contact_id; + $activity->message = Utils::encodeActivity($payment->invitation->contact, 'entered '.$payment->getName().' for ', $payment->invoice); + } else { + $activity = Activity::getBlank($client); + $message = $payment->payment_type_id == PAYMENT_TYPE_CREDIT ? 'applied credit for ' : 'entered '.$payment->getName().' for '; + $activity->message = Utils::encodeActivity(Auth::user(), $message, $payment->invoice); + } + + $activity->payment_id = $payment->id; + + if ($payment->invoice_id) { + $activity->invoice_id = $payment->invoice_id; + + $invoice = $payment->invoice; + $invoice->balance = $invoice->balance - $payment->amount; + $invoice->invoice_status_id = ($invoice->balance > 0) ? INVOICE_STATUS_PARTIAL : INVOICE_STATUS_PAID; + $invoice->save(); + } + + $activity->payment_id = $payment->id; + $activity->client_id = $payment->client_id; + $activity->activity_type_id = ACTIVITY_TYPE_CREATE_PAYMENT; + $activity->balance = $client->balance; + $activity->adjustment = $payment->amount * -1; + $activity->save(); + + Activity::checkSubscriptions(EVENT_CREATE_PAYMENT, $payment); + } + + public static function updatePayment($payment) + { + if ($payment->is_deleted && !$payment->getOriginal('is_deleted')) { + $client = $payment->client; + $client->balance = $client->balance + $payment->amount; + $client->paid_to_date = $client->paid_to_date - $payment->amount; + $client->save(); + + $invoice = $payment->invoice; + $invoice->balance = $invoice->balance + $payment->amount; + $invoice->save(); + + $activity = Activity::getBlank(); + $activity->payment_id = $payment->id; + $activity->client_id = $invoice->client_id; + $activity->invoice_id = $invoice->id; + $activity->activity_type_id = ACTIVITY_TYPE_DELETE_PAYMENT; + $activity->message = Utils::encodeActivity(Auth::user(), 'deleted '.$payment->getName()); + $activity->balance = $client->balance; + $activity->adjustment = $payment->amount; + $activity->save(); + } else { + /* + $diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount')); + + if ($diff == 0) + { + return; + } + + $client = $invoice->client; + $client->balance = $client->balance + $diff; + $client->save(); + + $activity = Activity::getBlank($invoice); + $activity->client_id = $invoice->client_id; + $activity->invoice_id = $invoice->id; + $activity->activity_type_id = ACTIVITY_TYPE_UPDATE_INVOICE; + $activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice); + $activity->balance = $client->balance; + $activity->adjustment = $diff; + $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON(); + $activity->save(); + */ + } + } + + public static function archivePayment($payment) + { + if ($payment->is_deleted) { + return; + } + + $client = $payment->client; + $invoice = $payment->invoice; + + $activity = Activity::getBlank(); + $activity->payment_id = $payment->id; + $activity->invoice_id = $invoice->id; + $activity->client_id = $client->id; + $activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_PAYMENT; + $activity->message = Utils::encodeActivity(Auth::user(), 'archived '.$payment->getName()); + $activity->balance = $client->balance; + $activity->adjustment = 0; + $activity->save(); + } + + public static function restorePayment($payment) + { + $client = $payment->client; + $invoice = $payment->invoice; + + $activity = Activity::getBlank(); + $activity->payment_id = $payment->id; + $activity->invoice_id = $invoice->id; + $activity->client_id = $client->id; + $activity->activity_type_id = ACTIVITY_TYPE_RESTORE_PAYMENT; + $activity->message = Utils::encodeActivity(Auth::user(), 'restored '.$payment->getName()); + $activity->balance = $client->balance; + $activity->adjustment = 0; + $activity->save(); + } + + public static function createCredit($credit) + { + $activity = Activity::getBlank(); + $activity->message = Utils::encodeActivity(Auth::user(), 'entered '.Utils::formatMoney($credit->amount, $credit->client->currency_id).' credit'); + $activity->credit_id = $credit->id; + $activity->client_id = $credit->client_id; + $activity->activity_type_id = ACTIVITY_TYPE_CREATE_CREDIT; + $activity->balance = $credit->client->balance; + $activity->save(); + } + + public static function updateCredit($credit) + { + if ($credit->is_deleted && !$credit->getOriginal('is_deleted')) { + $activity = Activity::getBlank(); + $activity->credit_id = $credit->id; + $activity->client_id = $credit->client_id; + $activity->activity_type_id = ACTIVITY_TYPE_DELETE_CREDIT; + $activity->message = Utils::encodeActivity(Auth::user(), 'deleted '.Utils::formatMoney($credit->balance, $credit->client->currency_id).' credit'); + $activity->balance = $credit->client->balance; + $activity->save(); + } else { + /* + $diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount')); + + if ($diff == 0) + { + return; + } + + $client = $invoice->client; + $client->balance = $client->balance + $diff; + $client->save(); + + $activity = Activity::getBlank($invoice); + $activity->client_id = $invoice->client_id; + $activity->invoice_id = $invoice->id; + $activity->activity_type_id = ACTIVITY_TYPE_UPDATE_INVOICE; + $activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice); + $activity->balance = $client->balance; + $activity->adjustment = $diff; + $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON(); + $activity->save(); + */ + } + } + + public static function archiveCredit($credit) + { + if ($credit->is_deleted) { + return; + } + + $activity = Activity::getBlank(); + $activity->client_id = $credit->client_id; + $activity->credit_id = $credit->id; + $activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CREDIT; + $activity->message = Utils::encodeActivity(Auth::user(), 'archived '.Utils::formatMoney($credit->balance, $credit->client->currency_id).' credit'); + $activity->balance = $credit->client->balance; + $activity->save(); + } + + public static function restoreCredit($credit) + { + $activity = Activity::getBlank(); + $activity->client_id = $credit->client_id; + $activity->credit_id = $credit->id; + $activity->activity_type_id = ACTIVITY_TYPE_RESTORE_CREDIT; + $activity->message = Utils::encodeActivity(Auth::user(), 'restored '.Utils::formatMoney($credit->balance, $credit->client->currency_id).' credit'); + $activity->balance = $credit->client->balance; + $activity->save(); + } + + private static function checkSubscriptions($event, $data) + { + if (!Auth::check()) { + return; + } + + $subscription = Auth::user()->account->getSubscription($event); + + if ($subscription) { + Utils::notifyZapier($subscription, $data); + } + } +} diff --git a/app/Models/Affiliate.php b/app/Models/Affiliate.php new file mode 100644 index 000000000000..3efccbd1ada0 --- /dev/null +++ b/app/Models/Affiliate.php @@ -0,0 +1,7 @@ +belongsTo('Account'); + } + + public function invoices() + { + return $this->hasMany('Invoice'); + } + + public function payments() + { + return $this->hasMany('Payment'); + } + + public function contacts() + { + return $this->hasMany('Contact'); + } + + public function projects() + { + return $this->hasMany('Project'); + } + + public function country() + { + return $this->belongsTo('Country'); + } + + public function currency() + { + return $this->belongsTo('Currency'); + } + + public function size() + { + return $this->belongsTo('Size'); + } + + public function industry() + { + return $this->belongsTo('Industry'); + } + + public function getTotalCredit() + { + return DB::table('credits') + ->where('client_id', '=', $this->id) + ->whereNull('deleted_at') + ->sum('balance'); + } + + public function getName() + { + return $this->getDisplayName(); + } + + public function getDisplayName() + { + if ($this->name) { + return $this->name; + } + + $this->load('contacts'); + $contact = $this->contacts()->first(); + + return $contact->getDisplayName(); + } + + public function getEntityType() + { + return ENTITY_CLIENT; + } + + public function getAddress() + { + $str = ''; + + if ($this->address1) { + $str .= $this->address1.'
    '; + } + if ($this->address2) { + $str .= $this->address2.'
    '; + } + if ($this->city) { + $str .= $this->city.', '; + } + if ($this->state) { + $str .= $this->state.' '; + } + if ($this->postal_code) { + $str .= $this->postal_code; + } + if ($this->country) { + $str .= '
    '.$this->country->name; + } + + if ($str) { + $str = '

    '.$str.'

    '; + } + + return $str; + } + + public function getPhone() + { + $str = ''; + + if ($this->work_phone) { + $str .= ''.Utils::formatPhoneNumber($this->work_phone); + } + + return $str; + } + + public function getIdNumber() + { + $str = ''; + + if ($this->id_number) { + $str .= ''.trans('texts.id_number').': '.$this->id_number; + } + + return $str; + } + + public function getVatNumber() + { + $str = ''; + + if ($this->vat_number) { + $str .= ''.trans('texts.vat_number').': '.$this->vat_number; + } + + return $str; + } + + public function getNotes() + { + $str = ''; + + if ($this->private_notes) { + $str .= ''.$this->private_notes.''; + } + + return $str; + } + + public function getIndustry() + { + $str = ''; + + if ($this->client_industry) { + $str .= $this->client_industry->name.' '; + } + + if ($this->client_size) { + $str .= $this->client_size->name; + } + + return $str; + } + + public function getCustomFields() + { + $str = ''; + $account = $this->account; + + if ($account->custom_client_label1 && $this->custom_value1) { + $str .= "{$account->custom_client_label1}: {$this->custom_value1}
    "; + } + + if ($account->custom_client_label2 && $this->custom_value2) { + $str .= "{$account->custom_client_label2}: {$this->custom_value2}
    "; + } + + return $str; + } + + public function getWebsite() + { + if (!$this->website) { + return ''; + } + + $link = $this->website; + $title = $this->website; + $prefix = 'http://'; + + if (strlen($link) > 7 && substr($link, 0, 7) === $prefix) { + $title = substr($title, 7); + } else { + $link = $prefix.$link; + } + + return link_to($link, $title, array('target' => '_blank')); + } + + public function getDateCreated() + { + if ($this->created_at == '0000-00-00 00:00:00') { + return '---'; + } else { + return $this->created_at->format('m/d/y h:i a'); + } + } + + + public function getGatewayToken() + { + $this->account->load('account_gateways'); + + if (!count($this->account->account_gateways)) { + return false; + } + + $accountGateway = $this->account->getGatewayConfig(GATEWAY_STRIPE); + + if (!$accountGateway) { + return false; + } + + $token = AccountGatewayToken::where('client_id', '=', $this->id) + ->where('account_gateway_id', '=', $accountGateway->id)->first(); + + return $token ? $token->token : false; + } + + public function getGatewayLink() + { + $token = $this->getGatewayToken(); + return $token ? "https://dashboard.stripe.com/customers/{$token}" : false; + } +} + +/* +Client::created(function($client) +{ + Activity::createClient($client); +}); +*/ + +Client::updating(function ($client) { + Activity::updateClient($client); +}); + +Client::deleting(function ($client) { + Activity::archiveClient($client); +}); + +Client::restoring(function ($client) { + Activity::restoreClient($client); +}); diff --git a/app/Models/Contact.php b/app/Models/Contact.php new file mode 100644 index 000000000000..ca29ce31b9f5 --- /dev/null +++ b/app/Models/Contact.php @@ -0,0 +1,74 @@ +belongsTo('Client'); + } + + public function getPersonType() + { + return PERSON_CONTACT; + } + + /* + public function getLastLogin() + { + if ($this->last_login == '0000-00-00 00:00:00') + { + return '---'; + } + else + { + return $this->last_login->format('m/d/y h:i a'); + } + } + */ + + public function getDisplayName() + { + if ($this->getFullName()) { + return $this->getFullName(); + } else { + return $this->email; + } + } + + public function getFullName() + { + if ($this->first_name || $this->last_name) { + return $this->first_name.' '.$this->last_name; + } else { + return ''; + } + } + + public function getDetails() + { + $str = ''; + + if ($this->first_name || $this->last_name) { + $str .= ''.$this->first_name.' '.$this->last_name.'
    '; + } + + if ($this->email) { + $str .= ''.HTML::mailto($this->email, $this->email).'
    '; + } + + if ($this->phone) { + $str .= ''.Utils::formatPhoneNumber($this->phone); + } + + if ($str) { + $str = '

    '.$str.'

    '; + } + + return $str; + } +} diff --git a/app/Models/Country.php b/app/Models/Country.php new file mode 100644 index 000000000000..05364b4e3529 --- /dev/null +++ b/app/Models/Country.php @@ -0,0 +1,9 @@ +belongsTo('Invoice')->withTrashed(); + } + + public function client() + { + return $this->belongsTo('Client')->withTrashed(); + } + + public function getName() + { + return ''; + } + + public function getEntityType() + { + return ENTITY_CREDIT; + } + + public function apply($amount) + { + if ($amount > $this->balance) { + $applied = $this->balance; + $this->balance = 0; + } else { + $applied = $amount; + $this->balance = $this->balance - $amount; + } + + $this->save(); + + return $applied; + } +} + +Credit::created(function ($credit) { + Activity::createCredit($credit); +}); + +Credit::updating(function ($credit) { + Activity::updateCredit($credit); +}); + +Credit::deleting(function ($credit) { + Activity::archiveCredit($credit); +}); + +Credit::restoring(function ($credit) { + Activity::restoreCredit($credit); +}); diff --git a/app/Models/Currency.php b/app/Models/Currency.php new file mode 100644 index 000000000000..943816064607 --- /dev/null +++ b/app/Models/Currency.php @@ -0,0 +1,7 @@ +user_id = $parent instanceof User ? $parent->id : $parent->user_id; + $entity->account_id = $parent->account_id; + } elseif (Auth::check()) { + $entity->user_id = Auth::user()->id; + $entity->account_id = Auth::user()->account_id; + } else { + Utils::fatalError(); + } + + $lastEntity = $className::withTrashed()->scope(false, $entity->account_id)->orderBy('public_id', 'DESC')->first(); + + if ($lastEntity) { + $entity->public_id = $lastEntity->public_id + 1; + } else { + $entity->public_id = 1; + } + + return $entity; + } + + public static function getPrivateId($publicId) + { + $className = get_called_class(); + + return $className::scope($publicId)->pluck('id'); + } + + public function getActivityKey() + { + return $this->getEntityType().':'.$this->public_id.':'.$this->getName(); + } + + /* + public function getEntityType() + { + return ''; + } + + public function getNmae() + { + return ''; + } + */ + + public function scopeScope($query, $publicId = false, $accountId = false) + { + if (!$accountId) { + $accountId = Auth::user()->account_id; + } + + $query->whereAccountId($accountId); + + if ($publicId) { + if (is_array($publicId)) { + $query->whereIn('public_id', $publicId); + } else { + $query->wherePublicId($publicId); + } + } + + return $query; + } +} diff --git a/app/Models/Frequency.php b/app/Models/Frequency.php new file mode 100644 index 000000000000..84373222ae62 --- /dev/null +++ b/app/Models/Frequency.php @@ -0,0 +1,7 @@ +belongsTo('PaymentLibrary', 'payment_library_id'); + } + + public function getLogoUrl() + { + return '/images/gateways/logo_'.$this->provider.'.png'; + } + + public function getHelp() + { + $link = ''; + + if ($this->id == GATEWAY_AUTHORIZE_NET || $this->id == GATEWAY_AUTHORIZE_NET_SIM) { + $link = 'http://reseller.authorize.net/application/?id=5560364'; + } elseif ($this->id == GATEWAY_PAYPAL_EXPRESS) { + $link = 'https://www.paypal.com/us/cgi-bin/webscr?cmd=_login-api-run'; + } elseif ($this->id == GATEWAY_TWO_CHECKOUT) { + $link = 'https://www.2checkout.com/referral?r=2c37ac2298'; + } + + $key = 'texts.gateway_help_'.$this->id; + $str = trans($key, ['link' => "Click here"]); + + return $key != $str ? $str : ''; + } + + public function getFields() + { + $paymentLibrary = $this->paymentlibrary; + + if ($paymentLibrary->id == PAYMENT_LIBRARY_OMNIPAY) { + $fields = Omnipay::create($this->provider)->getDefaultParameters(); + } else { + $fields = Payment_Utility::load('config', 'drivers/'.strtolower($this->provider)); + } + + if ($fields == null) { + $fields = array(); + } + + return $fields; + } +} diff --git a/app/Models/Industry.php b/app/Models/Industry.php new file mode 100644 index 000000000000..4c931a520d8f --- /dev/null +++ b/app/Models/Industry.php @@ -0,0 +1,7 @@ +belongsTo('Invoice'); + } + + public function contact() + { + return $this->belongsTo('Contact')->withTrashed(); + } + + public function user() + { + return $this->belongsTo('User')->withTrashed(); + } + + public function account() + { + return $this->belongsTo('Account'); + } + + public function getLink() + { + return SITE_URL.'/view/'.$this->invitation_key; + } +} diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php new file mode 100644 index 000000000000..09e1f887d34d --- /dev/null +++ b/app/Models/Invoice.php @@ -0,0 +1,230 @@ +belongsTo('Account'); + } + + public function user() + { + return $this->belongsTo('User'); + } + + public function client() + { + return $this->belongsTo('Client')->withTrashed(); + } + + public function invoice_items() + { + return $this->hasMany('InvoiceItem')->orderBy('id'); + } + + public function invoice_status() + { + return $this->belongsTo('InvoiceStatus'); + } + + public function invoice_design() + { + return $this->belongsTo('InvoiceDesign'); + } + + public function invitations() + { + return $this->hasMany('Invitation')->orderBy('invitations.contact_id'); + } + + public function getName() + { + return $this->invoice_number; + } + + public function getLink() + { + return link_to('invoices/'.$this->public_id, $this->invoice_number); + } + + public function getEntityType() + { + return $this->is_quote ? ENTITY_QUOTE : ENTITY_INVOICE; + } + + public function isSent() + { + return $this->invoice_status_id >= INVOICE_STATUS_SENT; + } + + public function isViewed() + { + return $this->invoice_status_id >= INVOICE_STATUS_VIEWED; + } + + public function isPaid() + { + return $this->invoice_status_id >= INVOICE_STATUS_PAID; + } + + public function hidePrivateFields() + { + $this->setVisible([ + 'invoice_number', + 'discount', + 'is_amount_discount', + 'po_number', + 'invoice_date', + 'due_date', + 'terms', + 'invoice_footer', + 'public_notes', + 'amount', + 'balance', + 'invoice_items', + 'client', + 'tax_name', + 'tax_rate', + 'account', + 'invoice_design', + 'invoice_design_id', + 'is_pro', + 'is_quote', + 'custom_value1', + 'custom_value2', + 'custom_taxes1', + 'custom_taxes2', ]); + + $this->client->setVisible([ + 'name', + 'id_number', + 'vat_number', + 'address1', + 'address2', + 'city', + 'state', + 'postal_code', + 'work_phone', + 'payment_terms', + 'contacts', + 'country', + 'currency_id', + 'custom_value1', + 'custom_value2', ]); + + $this->account->setVisible([ + 'name', + 'id_number', + 'vat_number', + 'address1', + 'address2', + 'city', + 'state', + 'postal_code', + 'work_phone', + 'work_email', + 'country', + 'currency_id', + 'custom_label1', + 'custom_value1', + 'custom_label2', + 'custom_value2', + 'custom_client_label1', + 'custom_client_label2', + 'primary_color', + 'secondary_color', + 'hide_quantity', + 'hide_paid_to_date', + 'custom_invoice_label1', + 'custom_invoice_label2', ]); + + foreach ($this->invoice_items as $invoiceItem) { + $invoiceItem->setVisible([ + 'product_key', + 'notes', + 'cost', + 'qty', + 'tax_name', + 'tax_rate', ]); + } + + foreach ($this->client->contacts as $contact) { + $contact->setVisible([ + 'first_name', + 'last_name', + 'email', + 'phone', ]); + } + + return $this; + } + + public function shouldSendToday() + { + if (!$this->start_date || strtotime($this->start_date) > strtotime('now')) { + return false; + } + + if ($this->end_date && strtotime($this->end_date) < strtotime('now')) { + return false; + } + + $dayOfWeekToday = date('w'); + $dayOfWeekStart = date('w', strtotime($this->start_date)); + + $dayOfMonthToday = date('j'); + $dayOfMonthStart = date('j', strtotime($this->start_date)); + + if (!$this->last_sent_date) { + return true; + } else { + $date1 = new DateTime($this->last_sent_date); + $date2 = new DateTime(); + $diff = $date2->diff($date1); + $daysSinceLastSent = $diff->format("%a"); + $monthsSinceLastSent = ($diff->format('%y') * 12) + $diff->format('%m'); + + if ($daysSinceLastSent == 0) { + return false; + } + } + + switch ($this->frequency_id) { + case FREQUENCY_WEEKLY: + return $daysSinceLastSent >= 7; + case FREQUENCY_TWO_WEEKS: + return $daysSinceLastSent >= 14; + case FREQUENCY_FOUR_WEEKS: + return $daysSinceLastSent >= 28; + case FREQUENCY_MONTHLY: + return $monthsSinceLastSent >= 1; + case FREQUENCY_THREE_MONTHS: + return $monthsSinceLastSent >= 3; + case FREQUENCY_SIX_MONTHS: + return $monthsSinceLastSent >= 6; + case FREQUENCY_ANNUALLY: + return $monthsSinceLastSent >= 12; + default: + return false; + } + + return false; + } +} + +Invoice::created(function ($invoice) { + $invoice->account->incrementCounter($invoice->invoice_number, $invoice->is_quote, $invoice->recurring_invoice_id); + Activity::createInvoice($invoice); +}); + +Invoice::updating(function ($invoice) { + Activity::updateInvoice($invoice); +}); + +Invoice::deleting(function ($invoice) { + Activity::archiveInvoice($invoice); +}); + +Invoice::restoring(function ($invoice) { + Activity::restoreInvoice($invoice); +}); diff --git a/app/Models/InvoiceDesign.php b/app/Models/InvoiceDesign.php new file mode 100644 index 000000000000..6dfd823dae02 --- /dev/null +++ b/app/Models/InvoiceDesign.php @@ -0,0 +1,7 @@ +belongsTo('Invoice'); + } + + public function product() + { + return $this->belongsTo('Product'); + } +} diff --git a/app/Models/InvoiceStatus.php b/app/Models/InvoiceStatus.php new file mode 100644 index 000000000000..faca90e50bcf --- /dev/null +++ b/app/Models/InvoiceStatus.php @@ -0,0 +1,7 @@ +belongsTo('Invoice')->withTrashed(); + } + + public function invitation() + { + return $this->belongsTo('Invitation'); + } + + public function client() + { + return $this->belongsTo('Client')->withTrashed(); + } + + public function account() + { + return $this->belongsTo('Account'); + } + + public function contact() + { + return $this->belongsTo('Contact'); + } + + public function getAmount() + { + return Utils::formatMoney($this->amount, $this->client->currency_id); + } + + public function getName() + { + return trim("payment {$this->transaction_reference}"); + } + + public function getEntityType() + { + return ENTITY_PAYMENT; + } +} + +Payment::created(function ($payment) { + Activity::createPayment($payment); +}); + +Payment::updating(function ($payment) { + Activity::updatePayment($payment); +}); + +Payment::deleting(function ($payment) { + Activity::archivePayment($payment); +}); + +Payment::restoring(function ($payment) { + Activity::restorePayment($payment); +}); diff --git a/app/Models/PaymentLibrary.php b/app/Models/PaymentLibrary.php new file mode 100644 index 000000000000..c6eff7009159 --- /dev/null +++ b/app/Models/PaymentLibrary.php @@ -0,0 +1,12 @@ +hasMany('Gateway', 'payment_library_id'); + } +} diff --git a/app/Models/PaymentTerm.php b/app/Models/PaymentTerm.php new file mode 100644 index 000000000000..15669d6535d3 --- /dev/null +++ b/app/Models/PaymentTerm.php @@ -0,0 +1,7 @@ +where('product_key', '=', $key)->first(); + } +} diff --git a/app/Models/Project.php b/app/Models/Project.php new file mode 100644 index 000000000000..6a2042e87ab9 --- /dev/null +++ b/app/Models/Project.php @@ -0,0 +1,45 @@ +belongsTo('Account'); + } + + public function user() + { + return $this->belongsTo('User'); + } + + public function client() + { + return $this->belongsTo('Client'); + } + + public function codes() + { + return $this->hasMany('ProjectCode'); + } + + public static function createNew($parent = false) + { + $className = get_called_class(); + $entity = new $className(); + + if ($parent) { + $entity->user_id = $parent instanceof User ? $parent->id : $parent->user_id; + $entity->account_id = $parent->account_id; + } elseif (Auth::check()) { + $entity->user_id = Auth::user()->id; + $entity->account_id = Auth::user()->account_id; + } else { + Utils::fatalError(); + } + + return $entity; + } +} diff --git a/app/Models/ProjectCode.php b/app/Models/ProjectCode.php new file mode 100644 index 000000000000..3f3f344a5e0b --- /dev/null +++ b/app/Models/ProjectCode.php @@ -0,0 +1,45 @@ +belongsTo('Account'); + } + + public function user() + { + return $this->belongsTo('User'); + } + + public function project() + { + return $this->belongsTo('Project'); + } + + public function events() + { + return $this->hasMany('TimesheetEvent'); + } + + public static function createNew($parent = false) + { + $className = get_called_class(); + $entity = new $className(); + + if ($parent) { + $entity->user_id = $parent instanceof User ? $parent->id : $parent->user_id; + $entity->account_id = $parent->account_id; + } elseif (Auth::check()) { + $entity->user_id = Auth::user()->id; + $entity->account_id = Auth::user()->account_id; + } else { + Utils::fatalError(); + } + + return $entity; + } +} diff --git a/app/Models/Size.php b/app/Models/Size.php new file mode 100644 index 000000000000..a598c7732d01 --- /dev/null +++ b/app/Models/Size.php @@ -0,0 +1,7 @@ +belongsTo('Account'); + } + + public function user() + { + return $this->belongsTo('User'); + } + + public function timesheet_events() + { + return $this->hasMany('TimeSheetEvent'); + } +} diff --git a/app/Models/TimesheetEvent.php b/app/Models/TimesheetEvent.php new file mode 100644 index 000000000000..448ac40c9b5a --- /dev/null +++ b/app/Models/TimesheetEvent.php @@ -0,0 +1,122 @@ +attributes['org_updated_at'] = $value->getTimestamp(); + }*/ + + public function account() + { + return $this->belongsTo('Account'); + } + + public function user() + { + return $this->belongsTo('User'); + } + + public function source() + { + return $this->belongsTo('TimesheetEventSource'); + } + + public function timesheet() + { + return $this->belongsTo('Timesheet'); + } + + public function project() + { + return $this->belongsTo('Project'); + } + + public function project_code() + { + return $this->belongsTo('ProjectCode'); + } + + /** + * @return TimesheetEvent + */ + public static function createNew($parent = false) + { + $className = get_called_class(); + $entity = new $className(); + + if ($parent) { + $entity->user_id = $parent instanceof User ? $parent->id : $parent->user_id; + $entity->account_id = $parent->account_id; + } elseif (Auth::check()) { + $entity->user_id = Auth::user()->id; + $entity->account_id = Auth::user()->account_id; + } else { + Utils::fatalError(); + } + + return $entity; + } + + public function toChangesArray(TimesheetEvent $other) + { + $attributes_old = parent::toArray(); + $attributes_new = $other->toArray(); + + $skip_keys = ['id' => 1, 'created_at' => 1, 'updated_at' => 1, 'deleted_at' => 1, 'org_data' => 1, 'update_data' => 1]; + $zeroisempty_keys = ['discount' => 1]; + + $result = []; + // Find all the values that where changed or deleted + foreach ($attributes_old as $key => $value) { + // Skip null values, keys we don't care about and 0 value keys that means they are not used + if (empty($value) || isset($skip_keys[$key]) || (isset($zeroisempty_keys[$key]) && $value)) { + continue; + } + + // Compare values if it exists in the new array + if (isset($attributes_new[$key]) || array_key_exists($key, $attributes_new)) { + if ($value instanceof \DateTime && $attributes_new[$key] instanceof \DateTime) { + if ($value != $attributes_new[$key]) { + $result[$key] = $attributes_new[$key]->format("Y-m-d H:i:s"); + } + } elseif ($value instanceof \DateTime && is_string($attributes_new[$key])) { + if ($value->format("Y-m-d H:i:s") != $attributes_new[$key]) { + $result[$key] = $attributes_new[$key]; + } + } elseif (is_string($value) && $attributes_new[$key] instanceof \DateTime) { + if ($attributes_new[$key]->format("Y-m-d H:i:s") != $value) { + $result[$key] = $attributes_new[$key]->format("Y-m-d H:i:s"); + } + } elseif ($value != $attributes_new[$key]) { + $result[$key] = $attributes_new[$key]; + } + } else { + $result[$key] = null; + } + } + + // Find all the values that where deleted + foreach ($attributes_new as $key => $value) { + if (isset($skip_keys[$key])) { + continue; + } + + if (!isset($attributes_old[$key])) { + $result[$key] = $value; + } + } + + return $result; + } +} diff --git a/app/Models/TimesheetEventSource.php b/app/Models/TimesheetEventSource.php new file mode 100644 index 000000000000..fcca52c61f79 --- /dev/null +++ b/app/Models/TimesheetEventSource.php @@ -0,0 +1,40 @@ +belongsTo('Account'); + } + + public function user() + { + return $this->belongsTo('User'); + } + + public function events() + { + return $this->hasMany('TimesheetEvent'); + } + + public static function createNew($parent = false) + { + $className = get_called_class(); + $entity = new $className(); + + if ($parent) { + $entity->user_id = $parent instanceof User ? $parent->id : $parent->user_id; + $entity->account_id = $parent->account_id; + } elseif (Auth::check()) { + $entity->user_id = Auth::user()->id; + $entity->account_id = Auth::user()->account_id; + } else { + Utils::fatalError(); + } + + return $entity; + } +} diff --git a/app/Models/Timezone.php b/app/Models/Timezone.php new file mode 100644 index 000000000000..09b91108a4b4 --- /dev/null +++ b/app/Models/Timezone.php @@ -0,0 +1,7 @@ + 'required|unique:users', + 'password' => 'required|between:6,32|confirmed', + 'password_confirmation' => 'between:6,32', + */ + ); + + protected $updateRules = array( + /* + 'email' => 'required|unique:users', + 'username' => 'required|unique:users', + */ + ); + + /** + * The database table used by the model. + * + * @var string + */ + protected $table = 'users'; + + public function account() + { + return $this->belongsTo('Account'); + } + + public function theme() + { + return $this->belongsTo('Theme'); + } + + public function getPersonType() + { + return PERSON_USER; + } + + /** + * Get the unique identifier for the user. + * + * @return mixed + */ + public function getAuthIdentifier() + { + return $this->getKey(); + } + + /** + * Get the password for the user. + * + * @return string + */ + public function getAuthPassword() + { + return $this->password; + } + + /** + * Get the e-mail address where password reminders are sent. + * + * @return string + */ + public function getReminderEmail() + { + return $this->email; + } + + public function isPro() + { + return $this->account->isPro(); + } + + public function isDemo() + { + return $this->account->id == Utils::getDemoAccountId(); + } + + public function maxInvoiceDesignId() + { + return $this->isPro() ? 10 : COUNT_FREE_DESIGNS; + } + + public function getDisplayName() + { + if ($this->getFullName()) { + return $this->getFullName(); + } elseif ($this->email) { + return $this->email; + } else { + return 'Guest'; + } + } + + public function getFullName() + { + if ($this->first_name || $this->last_name) { + return $this->first_name.' '.$this->last_name; + } else { + return ''; + } + } + + public function showGreyBackground() + { + return !$this->theme_id || in_array($this->theme_id, [2, 3, 5, 6, 7, 8, 10, 11, 12]); + } + + public function getRequestsCount() + { + return Session::get(SESSION_COUNTER, 0); + } + + public function getPopOverText() + { + if (!Utils::isNinja() || !Auth::check() || Session::has('error')) { + return false; + } + + $count = self::getRequestsCount(); + + if ($count == 1 || $count % 5 == 0) { + if (!Utils::isRegistered()) { + return trans('texts.sign_up_to_save'); + } elseif (!Auth::user()->account->name) { + return trans('texts.set_name'); + } + } + + return false; + } + + public function afterSave($success = true, $forced = false) + { + if ($this->email) { + return parent::afterSave($success = true, $forced = false); + } else { + return true; + } + } + + public function getMaxNumClients() + { + return $this->isPro() ? MAX_NUM_CLIENTS_PRO : MAX_NUM_CLIENTS; + } + + public function getRememberToken() + { + return $this->remember_token; + } + + public function setRememberToken($value) + { + $this->remember_token = $value; + } + + public function getRememberTokenName() + { + return 'remember_token'; + } +} diff --git a/app/Providers/RouteServiceProvider.php.bak b/app/Providers/RouteServiceProvider.php.bak new file mode 100644 index 000000000000..07963a09dc70 --- /dev/null +++ b/app/Providers/RouteServiceProvider.php.bak @@ -0,0 +1,303 @@ +version != NINJA_VERSION) { + $params = [ + 'user_version' => NINJA_VERSION, + 'latest_version'=> $data->version, + 'releases_link' => link_to(RELEASES_URL, 'Invoice Ninja', ['target' => '_blank']) + ]; + Session::put('news_feed_id', NEW_VERSION_AVAILABLE); + Session::put('news_feed_message', trans('texts.new_version_available', $params)); + } else { + Session::put('news_feed_id', $data->id); + if ($data->message && $data->id > Auth::user()->news_feed_id) { + Session::put('news_feed_message', $data->message); + } + } + } else { + Session::put('news_feed_id', true); + } + } + } + + // Check if we're requesting to change the account's language + if (Input::has('lang')) + { + $locale = Input::get('lang'); + App::setLocale($locale); + Session::set(SESSION_LOCALE, $locale); + + if (Auth::check()) + { + if ($language = Language::whereLocale($locale)->first()) + { + $account = Auth::user()->account; + $account->language_id = $language->id; + $account->save(); + } + } + } + else if (Auth::check()) + { + $locale = Session::get(SESSION_LOCALE, DEFAULT_LOCALE); + App::setLocale($locale); + } + + // Make sure the account/user localization settings are in the session + if (Auth::check() && !Session::has(SESSION_TIMEZONE)) + { + Event::fire('user.refresh'); + } + + // Check if the user is claiming a license (ie, additional invoices, white label, etc.) + $claimingLicense = Utils::startsWith($_SERVER['REQUEST_URI'], '/claim_license'); + if (!$claimingLicense && Input::has('license_key') && Input::has('product_id')) + { + $licenseKey = Input::get('license_key'); + $productId = Input::get('product_id'); + + $data = trim(file_get_contents((Utils::isNinjaDev() ? 'http://ninja.dev' : NINJA_APP_URL) . "/claim_license?license_key={$licenseKey}&product_id={$productId}")); + + if ($productId == PRODUCT_INVOICE_DESIGNS) + { + if ($data = json_decode($data)) + { + foreach ($data as $item) + { + $design = new InvoiceDesign(); + $design->id = $item->id; + $design->name = $item->name; + $design->javascript = $item->javascript; + $design->save(); + } + + if (!Utils::isNinjaProd()) { + Cache::forget('invoice_designs_cache_' . Auth::user()->maxInvoiceDesignId()); + } + + Session::flash('message', trans('texts.bought_designs')); + } + } + else if ($productId == PRODUCT_WHITE_LABEL) + { + if ($data == 'valid') + { + $account = Auth::user()->account; + $account->pro_plan_paid = NINJA_DATE; + $account->save(); + + Session::flash('message', trans('texts.bought_white_label')); + } + } + } + }); + + /* + |-------------------------------------------------------------------------- + | Authentication Filters + |-------------------------------------------------------------------------- + | + | The following filters are used to verify that the user of the current + | session is logged into this application. The "basic" filter easily + | integrates HTTP Basic authentication for quick, simple checking. + | + */ + + $router->filter('auth', function() + { + if (Auth::guest()) + { + if (Utils::isNinja() || Account::count() == 0) + { + return Redirect::guest('/'); + } + else + { + return Redirect::guest('/login'); + } + } + }); + + + $router->filter('auth.basic', function() + { + return Auth::basic(); + }); + + $router->filter('api.access', function() + { + $headers = Utils::getApiHeaders(); + + // check for a valid token + $token = AccountToken::where('token', '=', Request::header('X-Ninja-Token'))->first(['id', 'user_id']); + + if ($token) { + Auth::loginUsingId($token->user_id); + Session::set('token_id', $token->id); + } else { + sleep(3); + return Response::make('Invalid token', 403, $headers); + } + + if (!Utils::isNinja()) { + return null; + } + + if (!Utils::isPro()) { + return Response::make('API requires pro plan', 403, $headers); + } else { + $accountId = Auth::user()->account->id; + + // http://stackoverflow.com/questions/1375501/how-do-i-throttle-my-sites-api-users + $hour = 60 * 60; + $hour_limit = 100; # users are limited to 100 requests/hour + $hour_throttle = Cache::get("hour_throttle:{$accountId}", null); + $last_api_request = Cache::get("last_api_request:{$accountId}", 0); + $last_api_diff = time() - $last_api_request; + + if (is_null($hour_throttle)) { + $new_hour_throttle = 0; + } else { + $new_hour_throttle = $hour_throttle - $last_api_diff; + $new_hour_throttle = $new_hour_throttle < 0 ? 0 : $new_hour_throttle; + $new_hour_throttle += $hour / $hour_limit; + $hour_hits_remaining = floor(( $hour - $new_hour_throttle ) * $hour_limit / $hour); + $hour_hits_remaining = $hour_hits_remaining >= 0 ? $hour_hits_remaining : 0; + } + + if ($new_hour_throttle > $hour) { + $wait = ceil($new_hour_throttle - $hour); + sleep(1); + return Response::make("Please wait {$wait} second(s)", 403, $headers); + } + + Cache::put("hour_throttle:{$accountId}", $new_hour_throttle, 10); + Cache::put("last_api_request:{$accountId}", time(), 10); + } + + return null; + }); + + + + /* + |-------------------------------------------------------------------------- + | Guest Filter + |-------------------------------------------------------------------------- + | + | The "guest" filter is the counterpart of the authentication filters as + | it simply checks that the current user is not logged in. A redirect + | response will be issued if they are, which you may freely change. + | + */ + + $router->filter('guest', function() + { + if (Auth::check()) return Redirect::to('/'); + }); + + /* + |-------------------------------------------------------------------------- + | CSRF Protection Filter + |-------------------------------------------------------------------------- + | + | The CSRF filter is responsible for protecting your application against + | cross-site request forgery attacks. If this special token in a user + | session does not match the one given in this request, we'll bail. + | + */ + + $router->filter('csrf', function() + { + if ($_SERVER['REQUEST_URI'] != '/signup/register') + { + $token = Request::ajax() ? Request::header('X-CSRF-Token') : Input::get('_token'); + + if (Session::token() != $token) + { + Session::flash('warning', trans('texts.session_expired')); + + return Redirect::to('/'); + //throw new Illuminate\Session\TokenMismatchException; + } + } + }); + + + + } + + /** + * Define the routes for the application. + * + * @param \Illuminate\Routing\Router $router + * @return void + */ + public function map(Router $router) + { + $router->group(['namespace' => $this->namespace], function($router) + { + require app_path('Http/routes.php'); + }); + } + +} diff --git a/app/includes/parsecsv.lib.php b/app/includes/parsecsv.lib.php new file mode 100644 index 000000000000..c5941b9dbcbd --- /dev/null +++ b/app/includes/parsecsv.lib.php @@ -0,0 +1,695 @@ +data); + ---------------- + # tab delimited, and encoding conversion + $csv = new parseCSV(); + $csv->encoding('UTF-16', 'UTF-8'); + $csv->delimiter = "\t"; + $csv->parse('data.tsv'); + print_r($csv->data); + ---------------- + # auto-detect delimiter character + $csv = new parseCSV(); + $csv->auto('data.csv'); + print_r($csv->data); + ---------------- + # modify data in a csv file + $csv = new parseCSV(); + $csv->sort_by = 'id'; + $csv->parse('data.csv'); + # "4" is the value of the "id" column of the CSV row + $csv->data[4] = array('firstname' => 'John', 'lastname' => 'Doe', 'email' => 'john@doe.com'); + $csv->save(); + ---------------- + # add row/entry to end of CSV file + # - only recommended when you know the extact sctructure of the file + $csv = new parseCSV(); + $csv->save('data.csv', array('1986', 'Home', 'Nowhere', ''), true); + ---------------- + # convert 2D array to csv data and send headers + # to browser to treat output as a file and download it + $csv = new parseCSV(); + $csv->output (true, 'movies.csv', $array); + ---------------- + + +*/ + + + /** + * Configuration + * - set these options with $object->var_name = 'value'; + */ + + # use first line/entry as field names + var $heading = true; + + # override field names + var $fields = array(); + + # sort entries by this field + var $sort_by = null; + var $sort_reverse = false; + + # delimiter (comma) and enclosure (double quote) + var $delimiter = ','; + var $enclosure = '"'; + + # basic SQL-like conditions for row matching + var $conditions = null; + + # number of rows to ignore from beginning of data + var $offset = null; + + # limits the number of returned rows to specified amount + var $limit = null; + + # number of rows to analyze when attempting to auto-detect delimiter + var $auto_depth = 15; + + # characters to ignore when attempting to auto-detect delimiter + var $auto_non_chars = "a-zA-Z0-9\n\r"; + + # preferred delimiter characters, only used when all filtering method + # returns multiple possible delimiters (happens very rarely) + var $auto_preferred = ",;\t.:|"; + + # character encoding options + var $convert_encoding = false; + var $input_encoding = 'ISO-8859-1'; + var $output_encoding = 'ISO-8859-1'; + + # used by unparse(), save(), and output() functions + var $linefeed = "\r\n"; + + # only used by output() function + var $output_delimiter = ','; + var $output_filename = 'data.csv'; + + + /** + * Internal variables + */ + + # current file + var $file; + + # loaded file contents + var $file_data; + + # array of field values in data parsed + var $titles = array(); + + # two dimentional array of CSV data + var $data = array(); + + + /** + * Constructor + * @param input CSV file or string + * @return nothing + */ + function parseCSV ($input = null, $offset = null, $limit = null, $conditions = null) { + if ( $offset !== null ) $this->offset = $offset; + if ( $limit !== null ) $this->limit = $limit; + if ( count($conditions) > 0 ) $this->conditions = $conditions; + if ( !empty($input) ) $this->parse($input); + } + + + // ============================================== + // ----- [ Main Functions ] --------------------- + // ============================================== + + /** + * Parse CSV file or string + * @param input CSV file or string + * @return nothing + */ + function parse ($input = null, $offset = null, $limit = null, $conditions = null) { + if ( !empty($input) ) { + if ( $offset !== null ) $this->offset = $offset; + if ( $limit !== null ) $this->limit = $limit; + if ( count($conditions) > 0 ) $this->conditions = $conditions; + if ( is_readable($input) ) { + $this->data = $this->parse_file($input); + } else { + $this->file_data = &$input; + $this->data = $this->parse_string(); + } + if ( $this->data === false ) return false; + } + return true; + } + + /** + * Save changes, or new file and/or data + * @param file file to save to + * @param data 2D array with data + * @param append append current data to end of target CSV if exists + * @param fields field names + * @return true or false + */ + function save ($file = null, $data = array(), $append = false, $fields = array()) { + if ( empty($file) ) $file = &$this->file; + $mode = ( $append ) ? 'at' : 'wt' ; + $is_php = ( preg_match('/\.php$/i', $file) ) ? true : false ; + return $this->_wfile($file, $this->unparse($data, $fields, $append, $is_php), $mode); + } + + /** + * Generate CSV based string for output + * @param output if true, prints headers and strings to browser + * @param filename filename sent to browser in headers if output is true + * @param data 2D array with data + * @param fields field names + * @param delimiter delimiter used to separate data + * @return CSV data using delimiter of choice, or default + */ + function output ($output = true, $filename = null, $data = array(), $fields = array(), $delimiter = null) { + if ( empty($filename) ) $filename = $this->output_filename; + if ( $delimiter === null ) $delimiter = $this->output_delimiter; + $data = $this->unparse($data, $fields, null, null, $delimiter); + if ( $output ) { + header('Content-type: application/csv'); + header('Content-Disposition: inline; filename="'.$filename.'"'); + echo $data; + } + return $data; + } + + /** + * Convert character encoding + * @param input input character encoding, uses default if left blank + * @param output output character encoding, uses default if left blank + * @return nothing + */ + function encoding ($input = null, $output = null) { + $this->convert_encoding = true; + if ( $input !== null ) $this->input_encoding = $input; + if ( $output !== null ) $this->output_encoding = $output; + } + + /** + * Auto-Detect Delimiter: Find delimiter by analyzing a specific number of + * rows to determine most probable delimiter character + * @param file local CSV file + * @param parse true/false parse file directly + * @param search_depth number of rows to analyze + * @param preferred preferred delimiter characters + * @param enclosure enclosure character, default is double quote ("). + * @return delimiter character + */ + function auto ($file = null, $parse = true, $search_depth = null, $preferred = null, $enclosure = null) { + + if ( $file === null ) $file = $this->file; + if ( empty($search_depth) ) $search_depth = $this->auto_depth; + if ( $enclosure === null ) $enclosure = $this->enclosure; + + if ( $preferred === null ) $preferred = $this->auto_preferred; + + if ( empty($this->file_data) ) { + if ( $this->_check_data($file) ) { + $data = &$this->file_data; + } else return false; + } else { + $data = &$this->file_data; + } + + $chars = array(); + $strlen = strlen($data); + $enclosed = false; + $n = 1; + $to_end = true; + + // walk specific depth finding posssible delimiter characters + for ( $i=0; $i < $strlen; $i++ ) { + $ch = $data{$i}; + $nch = ( isset($data{$i+1}) ) ? $data{$i+1} : false ; + $pch = ( isset($data{$i-1}) ) ? $data{$i-1} : false ; + + // open and closing quotes + if ( $ch == $enclosure && (!$enclosed || $nch != $enclosure) ) { + $enclosed = ( $enclosed ) ? false : true ; + + // inline quotes + } elseif ( $ch == $enclosure && $enclosed ) { + $i++; + + // end of row + } elseif ( ($ch == "\n" && $pch != "\r" || $ch == "\r") && !$enclosed ) { + if ( $n >= $search_depth ) { + $strlen = 0; + $to_end = false; + } else { + $n++; + } + + // count character + } elseif (!$enclosed) { + if ( !preg_match('/['.preg_quote($this->auto_non_chars, '/').']/i', $ch) ) { + if ( !isset($chars[$ch][$n]) ) { + $chars[$ch][$n] = 1; + } else { + $chars[$ch][$n]++; + } + } + } + } + + // filtering + $depth = ( $to_end ) ? $n-1 : $n ; + $filtered = array(); + foreach( $chars as $char => $value ) { + if ( $match = $this->_check_count($char, $value, $depth, $preferred) ) { + $filtered[$match] = $char; + } + } + + // capture most probable delimiter + ksort($filtered); + $delimiter = reset($filtered); + $this->delimiter = $delimiter; + + // parse data + if ( $parse ) $this->data = $this->parse_string(); + + return $delimiter; + + } + + + // ============================================== + // ----- [ Core Functions ] --------------------- + // ============================================== + + /** + * Read file to string and call parse_string() + * @param file local CSV file + * @return 2D array with CSV data, or false on failure + */ + function parse_file ($file = null) { + if ( $file === null ) $file = $this->file; + if ( empty($this->file_data) ) $this->load_data($file); + return ( !empty($this->file_data) ) ? $this->parse_string() : false ; + } + + /** + * Parse CSV strings to arrays + * @param data CSV string + * @return 2D array with CSV data, or false on failure + */ + function parse_string ($data = null) { + if ( empty($data) ) { + if ( $this->_check_data() ) { + $data = &$this->file_data; + } else return false; + } + + $rows = array(); + $row = array(); + $row_count = 0; + $current = ''; + $head = ( !empty($this->fields) ) ? $this->fields : array() ; + $col = 0; + $enclosed = false; + $was_enclosed = false; + $strlen = strlen($data); + + // walk through each character + for ( $i=0; $i < $strlen; $i++ ) { + $ch = $data{$i}; + $nch = ( isset($data{$i+1}) ) ? $data{$i+1} : false ; + $pch = ( isset($data{$i-1}) ) ? $data{$i-1} : false ; + + // open and closing quotes + if ( $ch == $this->enclosure && (!$enclosed || $nch != $this->enclosure) ) { + $enclosed = ( $enclosed ) ? false : true ; + if ( $enclosed ) $was_enclosed = true; + + // inline quotes + } elseif ( $ch == $this->enclosure && $enclosed ) { + $current .= $ch; + $i++; + + // end of field/row + } elseif ( ($ch == $this->delimiter || ($ch == "\n" && $pch != "\r") || $ch == "\r") && !$enclosed ) { + if ( !$was_enclosed ) $current = trim($current); + $key = ( !empty($head[$col]) ) ? $head[$col] : $col ; + $row[$key] = $current; + $current = ''; + $col++; + + // end of row + if ( $ch == "\n" || $ch == "\r" ) { + if ( $this->_validate_offset($row_count) && $this->_validate_row_conditions($row, $this->conditions) ) { + if ( $this->heading && empty($head) ) { + $head = $row; + } elseif ( empty($this->fields) || (!empty($this->fields) && (($this->heading && $row_count > 0) || !$this->heading)) ) { + if ( !empty($this->sort_by) && !empty($row[$this->sort_by]) ) { + if ( isset($rows[$row[$this->sort_by]]) ) { + $rows[$row[$this->sort_by].'_0'] = &$rows[$row[$this->sort_by]]; + unset($rows[$row[$this->sort_by]]); + for ( $sn=1; isset($rows[$row[$this->sort_by].'_'.$sn]); $sn++ ) {} + $rows[$row[$this->sort_by].'_'.$sn] = $row; + } else $rows[$row[$this->sort_by]] = $row; + } else $rows[] = $row; + } + } + $row = array(); + $col = 0; + $row_count++; + if ( $this->sort_by === null && $this->limit !== null && count($rows) == $this->limit ) { + $i = $strlen; + } + } + + // append character to current field + } else { + $current .= $ch; + } + } + $this->titles = $head; + if ( !empty($this->sort_by) ) { + ( $this->sort_reverse ) ? krsort($rows) : ksort($rows) ; + if ( $this->offset !== null || $this->limit !== null ) { + $rows = array_slice($rows, ($this->offset === null ? 0 : $this->offset) , $this->limit, true); + } + } + return $rows; + } + + /** + * Create CSV data from array + * @param data 2D array with data + * @param fields field names + * @param append if true, field names will not be output + * @param is_php if a php die() call should be put on the first + * line of the file, this is later ignored when read. + * @param delimiter field delimiter to use + * @return CSV data (text string) + */ + function unparse ( $data = array(), $fields = array(), $append = false , $is_php = false, $delimiter = null) { + if ( !is_array($data) || empty($data) ) $data = &$this->data; + if ( !is_array($fields) || empty($fields) ) $fields = &$this->titles; + if ( $delimiter === null ) $delimiter = $this->delimiter; + + $string = ( $is_php ) ? "".$this->linefeed : '' ; + $entry = array(); + + // create heading + if ( $this->heading && !$append ) { + foreach( $fields as $key => $value ) { + $entry[] = $this->_enclose_value($value); + } + $string .= implode($delimiter, $entry).$this->linefeed; + $entry = array(); + } + + // create data + foreach( $data as $key => $row ) { + foreach( $row as $field => $value ) { + $entry[] = $this->_enclose_value($value); + } + $string .= implode($delimiter, $entry).$this->linefeed; + $entry = array(); + } + + return $string; + } + + /** + * Load local file or string + * @param input local CSV file + * @return true or false + */ + function load_data ($input = null) { + $data = null; + $file = null; + if ( $input === null ) { + $file = $this->file; + } elseif ( file_exists($input) ) { + $file = $input; + } else { + $data = $input; + } + if ( !empty($data) || $data = $this->_rfile($file) ) { + if ( $this->file != $file ) $this->file = $file; + if ( preg_match('/\.php$/i', $file) && preg_match('/<\?.*?\?>(.*)/ims', $data, $strip) ) { + $data = ltrim($strip[1]); + } + if ( $this->convert_encoding ) $data = iconv($this->input_encoding, $this->output_encoding, $data); + if ( substr($data, -1) != "\n" ) $data .= "\n"; + $this->file_data = &$data; + return true; + } + return false; + } + + + // ============================================== + // ----- [ Internal Functions ] ----------------- + // ============================================== + + /** + * Validate a row against specified conditions + * @param row array with values from a row + * @param conditions specified conditions that the row must match + * @return true of false + */ + function _validate_row_conditions ($row = array(), $conditions = null) { + if ( !empty($row) ) { + if ( !empty($conditions) ) { + $conditions = (strpos($conditions, ' OR ') !== false) ? explode(' OR ', $conditions) : array($conditions) ; + $or = ''; + foreach( $conditions as $key => $value ) { + if ( strpos($value, ' AND ') !== false ) { + $value = explode(' AND ', $value); + $and = ''; + foreach( $value as $k => $v ) { + $and .= $this->_validate_row_condition($row, $v); + } + $or .= (strpos($and, '0') !== false) ? '0' : '1' ; + } else { + $or .= $this->_validate_row_condition($row, $value); + } + } + return (strpos($or, '1') !== false) ? true : false ; + } + return true; + } + return false; + } + + /** + * Validate a row against a single condition + * @param row array with values from a row + * @param condition specified condition that the row must match + * @return true of false + */ + function _validate_row_condition ($row, $condition) { + $operators = array( + '=', 'equals', 'is', + '!=', 'is not', + '<', 'is less than', + '>', 'is greater than', + '<=', 'is less than or equals', + '>=', 'is greater than or equals', + 'contains', + 'does not contain', + ); + $operators_regex = array(); + foreach( $operators as $value ) { + $operators_regex[] = preg_quote($value, '/'); + } + $operators_regex = implode('|', $operators_regex); + if ( preg_match('/^(.+) ('.$operators_regex.') (.+)$/i', trim($condition), $capture) ) { + $field = $capture[1]; + $op = $capture[2]; + $value = $capture[3]; + if ( preg_match('/^([\'\"]{1})(.*)([\'\"]{1})$/i', $value, $capture) ) { + if ( $capture[1] == $capture[3] ) { + $value = $capture[2]; + $value = str_replace("\\n", "\n", $value); + $value = str_replace("\\r", "\r", $value); + $value = str_replace("\\t", "\t", $value); + $value = stripslashes($value); + } + } + if ( array_key_exists($field, $row) ) { + if ( ($op == '=' || $op == 'equals' || $op == 'is') && $row[$field] == $value ) { + return '1'; + } elseif ( ($op == '!=' || $op == 'is not') && $row[$field] != $value ) { + return '1'; + } elseif ( ($op == '<' || $op == 'is less than' ) && $row[$field] < $value ) { + return '1'; + } elseif ( ($op == '>' || $op == 'is greater than') && $row[$field] > $value ) { + return '1'; + } elseif ( ($op == '<=' || $op == 'is less than or equals' ) && $row[$field] <= $value ) { + return '1'; + } elseif ( ($op == '>=' || $op == 'is greater than or equals') && $row[$field] >= $value ) { + return '1'; + } elseif ( $op == 'contains' && preg_match('/'.preg_quote($value, '/').'/i', $row[$field]) ) { + return '1'; + } elseif ( $op == 'does not contain' && !preg_match('/'.preg_quote($value, '/').'/i', $row[$field]) ) { + return '1'; + } else { + return '0'; + } + } + } + return '1'; + } + + /** + * Validates if the row is within the offset or not if sorting is disabled + * @param current_row the current row number being processed + * @return true of false + */ + function _validate_offset ($current_row) { + if ( $this->sort_by === null && $this->offset !== null && $current_row < $this->offset ) return false; + return true; + } + + /** + * Enclose values if needed + * - only used by unparse() + * @param value string to process + * @return Processed value + */ + function _enclose_value ($value = null) { + if ( $value !== null && $value != '' ) { + $delimiter = preg_quote($this->delimiter, '/'); + $enclosure = preg_quote($this->enclosure, '/'); + if ( preg_match("/".$delimiter."|".$enclosure."|\n|\r/i", $value) || ($value{0} == ' ' || substr($value, -1) == ' ') ) { + $value = str_replace($this->enclosure, $this->enclosure.$this->enclosure, $value); + $value = $this->enclosure.$value.$this->enclosure; + } + } + return $value; + } + + /** + * Check file data + * @param file local filename + * @return true or false + */ + function _check_data ($file = null) { + if ( empty($this->file_data) ) { + if ( $file === null ) $file = $this->file; + return $this->load_data($file); + } + return true; + } + + + /** + * Check if passed info might be delimiter + * - only used by find_delimiter() + * @return special string used for delimiter selection, or false + */ + function _check_count ($char, $array, $depth, $preferred) { + if ( $depth == count($array) ) { + $first = null; + $equal = null; + $almost = false; + foreach( $array as $key => $value ) { + if ( $first == null ) { + $first = $value; + } elseif ( $value == $first && $equal !== false) { + $equal = true; + } elseif ( $value == $first+1 && $equal !== false ) { + $equal = true; + $almost = true; + } else { + $equal = false; + } + } + if ( $equal ) { + $match = ( $almost ) ? 2 : 1 ; + $pref = strpos($preferred, $char); + $pref = ( $pref !== false ) ? str_pad($pref, 3, '0', STR_PAD_LEFT) : '999' ; + return $pref.$match.'.'.(99999 - str_pad($first, 5, '0', STR_PAD_LEFT)); + } else return false; + } + } + + /** + * Read local file + * @param file local filename + * @return Data from file, or false on failure + */ + function _rfile ($file = null) { + if ( is_readable($file) ) { + if ( !($fh = fopen($file, 'r')) ) return false; + $data = fread($fh, filesize($file)); + fclose($fh); + return $data; + } + return false; + } + + /** + * Write to local file + * @param file local filename + * @param string data to write to file + * @param mode fopen() mode + * @param lock flock() mode + * @return true or false + */ + function _wfile ($file, $string = '', $mode = 'wb', $lock = 2) { + if ( $fp = fopen($file, $mode) ) { + flock($fp, $lock); + $re = fwrite($fp, $string); + $re2 = fclose($fp); + if ( $re != false && $re2 != false ) return true; + } + return false; + } + +} + +?> \ No newline at end of file diff --git a/app/libraries/Utils.php b/app/libraries/Utils.php new file mode 100644 index 000000000000..9d405f202dc8 --- /dev/null +++ b/app/libraries/Utils.php @@ -0,0 +1,604 @@ +registered; + } + + public static function isConfirmed() + { + return Auth::check() && Auth::user()->confirmed; + } + + public static function isDatabaseSetup() + { + try { + if (Schema::hasTable('accounts')) { + return true; + } + } catch (Exception $e) { + return false; + } + } + + public static function isProd() + { + return App::environment() == ENV_PRODUCTION; + } + + public static function isNinja() + { + return self::isNinjaProd() || self::isNinjaDev(); + } + + public static function isNinjaProd() + { + return isset($_ENV['NINJA_PROD']) && $_ENV['NINJA_PROD']; + } + + public static function isNinjaDev() + { + return isset($_ENV['NINJA_DEV']) && $_ENV['NINJA_DEV']; + } + + public static function isPro() + { + return Auth::check() && Auth::user()->isPro(); + } + + public static function getUserType() + { + if (Utils::isNinja()) { + return USER_TYPE_CLOUD_HOST; + } else { + return USER_TYPE_SELF_HOST; + } + } + + public static function getDemoAccountId() + { + return isset($_ENV[DEMO_ACCOUNT_ID]) ? $_ENV[DEMO_ACCOUNT_ID] : false; + } + + public static function isDemo() + { + return Auth::check() && Auth::user()->isDemo(); + } + + public static function getNewsFeedResponse($userType = false) + { + if (!$userType) { + $userType = Utils::getUserType(); + } + + $response = new stdClass(); + $response->message = isset($_ENV["{$userType}_MESSAGE"]) ? $_ENV["{$userType}_MESSAGE"] : ''; + $response->id = isset($_ENV["{$userType}_ID"]) ? $_ENV["{$userType}_ID"] : ''; + $response->version = NINJA_VERSION; + + return $response; + } + + public static function getProLabel($feature) + { + if (Auth::check() + && !Auth::user()->isPro() + && $feature == ACCOUNT_ADVANCED_SETTINGS) { + return ' PRO'; + } else { + return ''; + } + } + + public static function basePath() + { + return substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/') + 1); + } + + public static function trans($input) + { + $data = []; + + foreach ($input as $field) { + if ($field == "checkbox") { + $data[] = $field; + } else { + $data[] = trans("texts.$field"); + } + } + + return $data; + } + + public static function fatalError($message = false, $exception = false) + { + if (!$message) { + $message = "An error occurred, please try again later."; + } + + static::logError($message.' '.$exception); + + $data = [ + 'showBreadcrumbs' => false, + 'hideHeader' => true, + ]; + + return View::make('error', $data)->with('error', $message); + } + + public static function getErrorString($exception) + { + return "{$exception->getFile()} [Line {$exception->getLine()}] => {$exception->getMessage()}"; + } + + public static function logError($error, $context = 'PHP') + { + $count = Session::get('error_count', 0); + Session::put('error_count', ++$count); + if ($count > 100) { + return 'logged'; + } + + $data = [ + 'context' => $context, + 'user_id' => Auth::check() ? Auth::user()->id : 0, + 'user_name' => Auth::check() ? Auth::user()->getDisplayName() : '', + 'url' => Input::get('url', Request::url()), + 'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '', + 'ip' => Request::getClientIp(), + 'count' => Session::get('error_count', 0), + ]; + + Log::error($error."\n", $data); + + /* + Mail::queue('emails.error', ['message'=>$error.' '.json_encode($data)], function($message) + { + $message->to($email)->subject($subject); + }); + */ + } + + public static function parseFloat($value) + { + $value = preg_replace('/[^0-9\.\-]/', '', $value); + + return floatval($value); + } + + public static function formatPhoneNumber($phoneNumber) + { + $phoneNumber = preg_replace('/[^0-9a-zA-Z]/', '', $phoneNumber); + + if (!$phoneNumber) { + return ''; + } + + if (strlen($phoneNumber) > 10) { + $countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10); + $areaCode = substr($phoneNumber, -10, 3); + $nextThree = substr($phoneNumber, -7, 3); + $lastFour = substr($phoneNumber, -4, 4); + + $phoneNumber = '+'.$countryCode.' ('.$areaCode.') '.$nextThree.'-'.$lastFour; + } elseif (strlen($phoneNumber) == 10 && in_array(substr($phoneNumber, 0, 3), array(653, 656, 658, 659))) { + /** + * SG country code are 653, 656, 658, 659 + * US area code consist of 650, 651 and 657 + * @see http://en.wikipedia.org/wiki/Telephone_numbers_in_Singapore#Numbering_plan + * @see http://www.bennetyee.org/ucsd-pages/area.html + */ + $countryCode = substr($phoneNumber, 0, 2); + $nextFour = substr($phoneNumber, 2, 4); + $lastFour = substr($phoneNumber, 6, 4); + + $phoneNumber = '+'.$countryCode.' '.$nextFour.' '.$lastFour; + } elseif (strlen($phoneNumber) == 10) { + $areaCode = substr($phoneNumber, 0, 3); + $nextThree = substr($phoneNumber, 3, 3); + $lastFour = substr($phoneNumber, 6, 4); + + $phoneNumber = '('.$areaCode.') '.$nextThree.'-'.$lastFour; + } elseif (strlen($phoneNumber) == 7) { + $nextThree = substr($phoneNumber, 0, 3); + $lastFour = substr($phoneNumber, 3, 4); + + $phoneNumber = $nextThree.'-'.$lastFour; + } + + return $phoneNumber; + } + + public static function formatMoney($value, $currencyId = false) + { + if (!$currencyId) { + $currencyId = Session::get(SESSION_CURRENCY); + } + + $currency = Currency::remember(DEFAULT_QUERY_CACHE)->find($currencyId); + + if (!$currency) { + $currency = Currency::remember(DEFAULT_QUERY_CACHE)->find(1); + } + + return $currency->symbol.number_format($value, $currency->precision, $currency->decimal_separator, $currency->thousand_separator); + } + + public static function pluralize($string, $count) + { + $field = $count == 1 ? $string : $string.'s'; + $string = trans("texts.$field", ['count' => $count]); + + return $string; + } + + public static function toArray($data) + { + return json_decode(json_encode((array) $data), true); + } + + public static function toSpaceCase($camelStr) + { + return preg_replace('/([a-z])([A-Z])/s', '$1 $2', $camelStr); + } + + public static function timestampToDateTimeString($timestamp) + { + $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + $format = Session::get(SESSION_DATETIME_FORMAT, DEFAULT_DATETIME_FORMAT); + + return Utils::timestampToString($timestamp, $timezone, $format); + } + + public static function timestampToDateString($timestamp) + { + $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); + + return Utils::timestampToString($timestamp, $timezone, $format); + } + + public static function dateToString($date) + { + $dateTime = new DateTime($date); + $timestamp = $dateTime->getTimestamp(); + $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); + + return Utils::timestampToString($timestamp, false, $format); + } + + public static function timestampToString($timestamp, $timezone = false, $format) + { + if (!$timestamp) { + return ''; + } + $date = Carbon::createFromTimeStamp($timestamp); + if ($timezone) { + $date->tz = $timezone; + } + if ($date->year < 1900) { + return ''; + } + + return $date->format($format); + } + + public static function toSqlDate($date, $formatResult = true) + { + if (!$date) { + return; + } + + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + + $dateTime = DateTime::createFromFormat($format, $date, new DateTimeZone($timezone)); + + return $formatResult ? $dateTime->format('Y-m-d') : $dateTime; + } + + public static function fromSqlDate($date, $formatResult = true) + { + if (!$date || $date == '0000-00-00') { + return ''; + } + + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + + $dateTime = DateTime::createFromFormat('Y-m-d', $date, new DateTimeZone($timezone)); + + return $formatResult ? $dateTime->format($format) : $dateTime; + } + + public static function today($formatResult = true) + { + $timezone = Session::get(SESSION_TIMEZONE); + $format = Session::get(SESSION_DATE_FORMAT); + $date = date_create(null, new DateTimeZone($timezone)); + + if ($formatResult) { + return $date->format($format); + } else { + return $date; + } + } + + public static function trackViewed($name, $type, $url = false) + { + if (!$url) { + $url = Request::url(); + } + + $viewed = Session::get(RECENTLY_VIEWED); + + if (!$viewed) { + $viewed = []; + } + + $object = new stdClass(); + $object->url = $url; + $object->name = ucwords($type).': '.$name; + + $data = []; + + for ($i = 0; $iurl == $item->url || $object->name == $item->name) { + continue; + } + + array_unshift($data, $item); + } + + array_unshift($data, $object); + + if (count($data) > RECENTLY_VIEWED_LIMIT) { + array_pop($data); + } + + Session::put(RECENTLY_VIEWED, $data); + } + + public static function processVariables($str) + { + if (!$str) { + return ''; + } + + $variables = ['MONTH', 'QUARTER', 'YEAR']; + for ($i = 0; $i 1) { + $offset = intval($addArray[1]); + } elseif (count($minArray) > 1) { + $offset = intval($minArray[1]) * -1; + } + + $val = Utils::getDatePart($variable, $offset); + $str = str_replace($match, $val, $str); + } + } + + return $str; + } + + private static function getDatePart($part, $offset) + { + $offset = intval($offset); + if ($part == 'MONTH') { + return Utils::getMonth($offset); + } elseif ($part == 'QUARTER') { + return Utils::getQuarter($offset); + } elseif ($part == 'YEAR') { + return Utils::getYear($offset); + } + } + + private static function getMonth($offset) + { + $months = [ "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", ]; + + $month = intval(date('n')) - 1; + + $month += $offset; + $month = $month % 12; + + if ($month < 0) { + $month += 12; + } + + return $months[$month]; + } + + private static function getQuarter($offset) + { + $month = intval(date('n')) - 1; + $quarter = floor(($month + 3) / 3); + $quarter += $offset; + $quarter = $quarter % 4; + if ($quarter == 0) { + $quarter = 4; + } + + return 'Q'.$quarter; + } + + private static function getYear($offset) + { + $year = intval(date('Y')); + + return $year + $offset; + } + + public static function getEntityName($entityType) + { + return ucwords(str_replace('_', ' ', $entityType)); + } + + public static function getClientDisplayName($model) + { + if ($model->client_name) { + return $model->client_name; + } elseif ($model->first_name || $model->last_name) { + return $model->first_name.' '.$model->last_name; + } else { + return $model->email; + } + } + + public static function encodeActivity($person = null, $action, $entity = null, $otherPerson = null) + { + $person = $person ? $person->getDisplayName() : 'System'; + $entity = $entity ? '['.$entity->getActivityKey().']' : ''; + $otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : ''; + $token = Session::get('token_id') ? ' ('.trans('texts.token').')' : ''; + + return trim("$person $token $action $entity $otherPerson"); + } + + public static function decodeActivity($message) + { + $pattern = '/\[([\w]*):([\d]*):(.*)\]/i'; + preg_match($pattern, $message, $matches); + + if (count($matches) > 0) { + $match = $matches[0]; + $type = $matches[1]; + $publicId = $matches[2]; + $name = $matches[3]; + + $link = link_to($type.'s/'.$publicId, $name); + $message = str_replace($match, "$type $link", $message); + } + + return $message; + } + + public static function generateLicense() + { + $parts = []; + for ($i = 0; $i<5; $i++) { + $parts[] = strtoupper(str_random(4)); + } + + return implode('-', $parts); + } + + public static function lookupEventId($eventName) + { + if ($eventName == 'create_client') { + return EVENT_CREATE_CLIENT; + } elseif ($eventName == 'create_invoice') { + return EVENT_CREATE_INVOICE; + } elseif ($eventName == 'create_quote') { + return EVENT_CREATE_QUOTE; + } elseif ($eventName == 'create_payment') { + return EVENT_CREATE_PAYMENT; + } else { + return false; + } + } + + public static function notifyZapier($subscription, $data) + { + $curl = curl_init(); + + $jsonEncodedData = json_encode($data->toJson()); + $opts = [ + CURLOPT_URL => $subscription->target_url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => $jsonEncodedData, + CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Content-Length: '.strlen($jsonEncodedData)], + ]; + + curl_setopt_array($curl, $opts); + + $result = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + curl_close($curl); + + if ($status == 410) { + $subscription->delete(); + } + } + + + public static function remapPublicIds(array $data) + { + $return = []; + + foreach ($data as $key => $val) { + if ($key === 'public_id') { + $key = 'id'; + } elseif (strpos($key, '_id')) { + continue; + } + + if (is_array($val)) { + $val = Utils::remapPublicIds($val); + } + + $return[$key] = $val; + } + + return $return; + } + + public static function getApiHeaders($count = 0) + { + return [ + 'Content-Type' => 'application/json', + //'Access-Control-Allow-Origin' => '*', + //'Access-Control-Allow-Methods' => 'GET', + //'Access-Control-Allow-Headers' => 'Origin, Content-Type, Accept, Authorization, X-Requested-With', + //'Access-Control-Allow-Credentials' => 'true', + 'X-Total-Count' => $count, + //'X-Rate-Limit-Limit' - The number of allowed requests in the current period + //'X-Rate-Limit-Remaining' - The number of remaining requests in the current period + //'X-Rate-Limit-Reset' - The number of seconds left in the current period, + ]; + } + + public static function startsWith($haystack, $needle) + { + return $needle === "" || strpos($haystack, $needle) === 0; + } + + public static function endsWith($haystack, $needle) + { + return $needle === "" || substr($haystack, -strlen($needle)) === $needle; + } + + public static function getEntityRowClass($model) + { + $str = $model->is_deleted || ($model->deleted_at && $model->deleted_at != '0000-00-00') ? 'DISABLED ' : ''; + + if ($model->is_deleted) { + $str .= 'ENTITY_DELETED '; + } + + if ($model->deleted_at && $model->deleted_at != '0000-00-00') { + $str .= 'ENTITY_ARCHIVED '; + } + + return $str; + } +} diff --git a/app/ninja/mailers/ContactMailer.php b/app/ninja/mailers/ContactMailer.php new file mode 100644 index 000000000000..0a262aecba08 --- /dev/null +++ b/app/ninja/mailers/ContactMailer.php @@ -0,0 +1,104 @@ +load('invitations', 'client', 'account'); + $entityType = $invoice->getEntityType(); + + $view = 'invoice'; + $subject = trans("texts.{$entityType}_subject", ['invoice' => $invoice->invoice_number, 'account' => $invoice->account->getDisplayName()]); + $accountName = $invoice->account->getDisplayName(); + $emailTemplate = $invoice->account->getEmailTemplate($entityType); + $invoiceAmount = Utils::formatMoney($invoice->amount, $invoice->client->currency_id); + + foreach ($invoice->invitations as $invitation) { + if (!$invitation->user || !$invitation->user->email) { + return false; + } + if (!$invitation->contact || !$invitation->contact->email) { + return false; + } + + $invitation->sent_date = \Carbon::now()->toDateTimeString(); + $invitation->save(); + + $variables = [ + '$footer' => $invoice->account->getEmailFooter(), + '$link' => $invitation->getLink(), + '$client' => $invoice->client->getDisplayName(), + '$account' => $accountName, + '$contact' => $invitation->contact->getDisplayName(), + '$amount' => $invoiceAmount + ]; + + $data['body'] = str_replace(array_keys($variables), array_values($variables), $emailTemplate); + $data['link'] = $invitation->getLink(); + $data['entityType'] = $entityType; + + $fromEmail = $invitation->user->email; + $this->sendTo($invitation->contact->email, $fromEmail, $accountName, $subject, $view, $data); + + Activity::emailInvoice($invitation); + } + + if (!$invoice->isSent()) { + $invoice->invoice_status_id = INVOICE_STATUS_SENT; + $invoice->save(); + } + + \Event::fire('invoice.sent', $invoice); + } + + public function sendPaymentConfirmation(Payment $payment) + { + $invoice = $payment->invoice; + $view = 'payment_confirmation'; + $subject = trans('texts.payment_subject', ['invoice' => $invoice->invoice_number]); + $accountName = $payment->account->getDisplayName(); + $emailTemplate = $invoice->account->getEmailTemplate(ENTITY_PAYMENT); + + $variables = [ + '$footer' => $payment->account->getEmailFooter(), + '$client' => $payment->client->getDisplayName(), + '$account' => $accountName, + '$amount' => Utils::formatMoney($payment->amount, $payment->client->currency_id) + ]; + + $data = ['body' => str_replace(array_keys($variables), array_values($variables), $emailTemplate)]; + + $user = $payment->invitation->user; + $this->sendTo($payment->contact->email, $user->email, $accountName, $subject, $view, $data); + } + + public function sendLicensePaymentConfirmation($name, $email, $amount, $license, $productId) + { + $view = 'license_confirmation'; + $subject = trans('texts.payment_subject'); + + if ($productId == PRODUCT_ONE_CLICK_INSTALL) { + $license = "Softaculous install license: $license"; + } elseif ($productId == PRODUCT_INVOICE_DESIGNS) { + $license = "Invoice designs license: $license"; + } elseif ($productId == PRODUCT_WHITE_LABEL) { + $license = "White label license: $license"; + } + + $data = [ + 'account' => trans('texts.email_from'), + 'client' => $name, + 'amount' => Utils::formatMoney($amount, 1), + 'license' => $license + ]; + + $this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); + } +} diff --git a/app/ninja/mailers/Mailer.php b/app/ninja/mailers/Mailer.php new file mode 100644 index 000000000000..16264d91cc55 --- /dev/null +++ b/app/ninja/mailers/Mailer.php @@ -0,0 +1,27 @@ +setEncoder(\Swift_Encoding::get8BitEncoding()); + $message->to($toEmail)->from($fromEmail, $fromName)->replyTo($replyEmail, $fromName)->subject($subject); + }); + } +} diff --git a/app/ninja/mailers/UserMailer.php b/app/ninja/mailers/UserMailer.php new file mode 100644 index 000000000000..12e7bedd60eb --- /dev/null +++ b/app/ninja/mailers/UserMailer.php @@ -0,0 +1,62 @@ +email) { + return; + } + + $view = 'confirm'; + $subject = trans('texts.confirmation_subject'); + + $data = [ + 'user' => $user, + 'invitationMessage' => $invitor ? trans('texts.invitation_message', ['invitor' => $invitor->getDisplayName()]) : '', + ]; + + if ($invitor) { + $fromEmail = $invitor->email; + $fromName = $invitor->getDisplayName(); + } else { + $fromEmail = CONTACT_EMAIL; + $fromName = CONTACT_NAME; + } + + $this->sendTo($user->email, $fromEmail, $fromName, $subject, $view, $data); + } + + public function sendNotification(User $user, Invoice $invoice, $notificationType, Payment $payment = null) + { + if (!$user->email) { + return; + } + + $view = 'invoice_'.$notificationType; + $entityType = $invoice->getEntityType(); + + $data = [ + 'entityType' => $entityType, + 'clientName' => $invoice->client->getDisplayName(), + 'accountName' => $invoice->account->getDisplayName(), + 'userName' => $user->getDisplayName(), + 'invoiceAmount' => Utils::formatMoney($invoice->amount, $invoice->client->currency_id), + 'invoiceNumber' => $invoice->invoice_number, + 'invoiceLink' => SITE_URL."/{$entityType}s/{$invoice->public_id}", + ]; + + if ($payment) { + $data['paymentAmount'] = Utils::formatMoney($payment->amount, $invoice->client->currency_id); + } + + $subject = trans("texts.notification_{$entityType}_{$notificationType}_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->getDisplayName()]); + + $this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); + } +} diff --git a/app/ninja/repositories/AccountRepository.php b/app/ninja/repositories/AccountRepository.php new file mode 100644 index 000000000000..fa1b3e41410b --- /dev/null +++ b/app/ninja/repositories/AccountRepository.php @@ -0,0 +1,234 @@ +ip = Request::getClientIp(); + $account->account_key = str_random(RANDOM_KEY_LENGTH); + + if (Session::has(SESSION_LOCALE)) { + $locale = Session::get(SESSION_LOCALE); + if ($language = Language::whereLocale($locale)->first()) { + $account->language_id = $language->id; + } + } + + $account->save(); + + $random = str_random(RANDOM_KEY_LENGTH); + + $user = new User(); + $user->password = $random; + $user->password_confirmation = $random; + $user->username = $random; + $user->confirmed = !Utils::isNinja(); + $account->users()->save($user, []); + + return $account; + } + + public function getSearchData() + { + $clients = \DB::table('clients') + ->where('clients.deleted_at', '=', null) + ->where('clients.account_id', '=', \Auth::user()->account_id) + ->whereRaw("clients.name <> ''") + ->select(\DB::raw("'Clients' as type, clients.public_id, clients.name, '' as token")); + + $contacts = \DB::table('clients') + ->join('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('clients.deleted_at', '=', null) + ->where('clients.account_id', '=', \Auth::user()->account_id) + ->whereRaw("CONCAT(contacts.first_name, contacts.last_name, contacts.email) <> ''") + ->select(\DB::raw("'Contacts' as type, clients.public_id, CONCAT(contacts.first_name, ' ', contacts.last_name, ' ', contacts.email) as name, '' as token")); + + $invoices = \DB::table('clients') + ->join('invoices', 'invoices.client_id', '=', 'clients.id') + ->where('clients.account_id', '=', \Auth::user()->account_id) + ->where('clients.deleted_at', '=', null) + ->where('invoices.deleted_at', '=', null) + ->select(\DB::raw("'Invoices' as type, invoices.public_id, CONCAT(invoices.invoice_number, ': ', clients.name) as name, invoices.invoice_number as token")); + + $data = []; + + foreach ($clients->union($contacts)->union($invoices)->get() as $row) { + $type = $row->type; + + if (!isset($data[$type])) { + $data[$type] = []; + } + + $tokens = explode(' ', $row->name); + $tokens[] = $type; + + if ($type == 'Invoices') { + $tokens[] = intVal($row->token).''; + } + + $data[$type][] = [ + 'value' => $row->name, + 'public_id' => $row->public_id, + 'tokens' => $tokens, + ]; + } + + return $data; + } + + public function enableProPlan() + { + if (Auth::user()->isPro()) { + return false; + } + + $ninjaAccount = $this->getNinjaAccount(); + $lastInvoice = Invoice::withTrashed()->whereAccountId($ninjaAccount->id)->orderBy('public_id', 'DESC')->first(); + $publicId = $lastInvoice ? ($lastInvoice->public_id + 1) : 1; + + $ninjaClient = $this->getNinjaClient($ninjaAccount); + $invitation = $this->createNinjaInvoice($publicId, $ninjaAccount, $ninjaClient); + + return $invitation; + } + + private function createNinjaInvoice($publicId, $account, $client) + { + $invoice = new Invoice(); + $invoice->account_id = $account->id; + $invoice->user_id = $account->users()->first()->id; + $invoice->public_id = $publicId; + $invoice->client_id = $client->id; + $invoice->invoice_number = $account->getNextInvoiceNumber(); + $invoice->invoice_date = date_create()->format('Y-m-d'); + $invoice->amount = PRO_PLAN_PRICE; + $invoice->balance = PRO_PLAN_PRICE; + $invoice->save(); + + $item = new InvoiceItem(); + $item->account_id = $account->id; + $item->user_id = $account->users()->first()->id; + $item->public_id = $publicId; + $item->qty = 1; + $item->cost = PRO_PLAN_PRICE; + $item->notes = trans('texts.pro_plan_description'); + $item->product_key = trans('texts.pro_plan_product'); + $invoice->invoice_items()->save($item); + + $invitation = new Invitation(); + $invitation->account_id = $account->id; + $invitation->user_id = $account->users()->first()->id; + $invitation->public_id = $publicId; + $invitation->invoice_id = $invoice->id; + $invitation->contact_id = $client->contacts()->first()->id; + $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH); + $invitation->save(); + + return $invitation; + } + + public function getNinjaAccount() + { + $account = Account::whereAccountKey(NINJA_ACCOUNT_KEY)->first(); + + if ($account) { + return $account; + } else { + $account = new Account(); + $account->name = 'Invoice Ninja'; + $account->work_email = 'contact@invoiceninja.com'; + $account->work_phone = '(800) 763-1948'; + $account->account_key = NINJA_ACCOUNT_KEY; + $account->save(); + + $random = str_random(RANDOM_KEY_LENGTH); + $user = new User(); + $user->registered = true; + $user->confirmed = true; + $user->email = 'contact@invoiceninja.com'; + $user->password = $random; + $user->password_confirmation = $random; + $user->username = $random; + $user->first_name = 'Invoice'; + $user->last_name = 'Ninja'; + $user->notify_sent = true; + $user->notify_paid = true; + $account->users()->save($user); + + $accountGateway = new AccountGateway(); + $accountGateway->user_id = $user->id; + $accountGateway->gateway_id = NINJA_GATEWAY_ID; + $accountGateway->public_id = 1; + $accountGateway->config = NINJA_GATEWAY_CONFIG; + $account->account_gateways()->save($accountGateway); + } + + return $account; + } + + private function getNinjaClient($ninjaAccount) + { + $client = Client::whereAccountId($ninjaAccount->id)->wherePublicId(Auth::user()->account_id)->first(); + + if (!$client) { + $client = new Client(); + $client->public_id = Auth::user()->account_id; + $client->user_id = $ninjaAccount->users()->first()->id; + $client->currency_id = 1; + foreach (['name', 'address1', 'address2', 'city', 'state', 'postal_code', 'country_id', 'work_phone'] as $field) { + $client->$field = Auth::user()->account->$field; + } + $ninjaAccount->clients()->save($client); + + $contact = new Contact(); + $contact->user_id = $ninjaAccount->users()->first()->id; + $contact->account_id = $ninjaAccount->id; + $contact->public_id = Auth::user()->account_id; + $contact->is_primary = true; + foreach (['first_name', 'last_name', 'email', 'phone'] as $field) { + $contact->$field = Auth::user()->$field; + } + $client->contacts()->save($contact); + } + + return $client; + } + + public function registerUser($user) + { + $url = NINJA_APP_URL.'/signup/register'; + $data = ''; + $fields = [ + 'first_name' => urlencode($user->first_name), + 'last_name' => urlencode($user->last_name), + 'email' => urlencode($user->email), + ]; + + foreach ($fields as $key => $value) { + $data .= $key.'='.$value.'&'; + } + rtrim($data, '&'); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, count($fields)); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_exec($ch); + curl_close($ch); + } +} diff --git a/app/ninja/repositories/ClientRepository.php b/app/ninja/repositories/ClientRepository.php new file mode 100644 index 000000000000..f1308b84c609 --- /dev/null +++ b/app/ninja/repositories/ClientRepository.php @@ -0,0 +1,202 @@ +join('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('clients.account_id', '=', \Auth::user()->account_id) + ->where('contacts.is_primary', '=', true) + ->where('contacts.deleted_at', '=', null) + ->select('clients.public_id', 'clients.name', 'contacts.first_name', 'contacts.last_name', 'clients.balance', 'clients.last_login', 'clients.created_at', 'clients.work_phone', 'contacts.email', 'clients.currency_id', 'clients.deleted_at', 'clients.is_deleted'); + + if (!\Session::get('show_trash:client')) { + $query->where('clients.deleted_at', '=', null); + } + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function getErrors($data) + { + $contact = isset($data['contacts']) ? (array) $data['contacts'][0] : (isset($data['contact']) ? $data['contact'] : []); + $validator = \Validator::make($contact, ['email' => 'required|email']); + if ($validator->fails()) { + return $validator->messages(); + } + + return false; + } + + public function save($publicId, $data, $notify = true) + { + if (!$publicId || $publicId == "-1") { + $client = Client::createNew(); + $client->currency_id = 1; + $contact = Contact::createNew(); + $contact->is_primary = true; + $contact->send_invoice = true; + } else { + $client = Client::scope($publicId)->with('contacts')->firstOrFail(); + $contact = $client->contacts()->where('is_primary', '=', true)->firstOrFail(); + } + + if (isset($data['name'])) { + $client->name = trim($data['name']); + } + if (isset($data['id_number'])) { + $client->id_number = trim($data['id_number']); + } + if (isset($data['vat_number'])) { + $client->vat_number = trim($data['vat_number']); + } + if (isset($data['work_phone'])) { + $client->work_phone = trim($data['work_phone']); + } + if (isset($data['custom_value1'])) { + $client->custom_value1 = trim($data['custom_value1']); + } + if (isset($data['custom_value2'])) { + $client->custom_value2 = trim($data['custom_value2']); + } + if (isset($data['address1'])) { + $client->address1 = trim($data['address1']); + } + if (isset($data['address2'])) { + $client->address2 = trim($data['address2']); + } + if (isset($data['city'])) { + $client->city = trim($data['city']); + } + if (isset($data['state'])) { + $client->state = trim($data['state']); + } + if (isset($data['postal_code'])) { + $client->postal_code = trim($data['postal_code']); + } + if (isset($data['country_id'])) { + $client->country_id = $data['country_id'] ? $data['country_id'] : null; + } + if (isset($data['private_notes'])) { + $client->private_notes = trim($data['private_notes']); + } + if (isset($data['size_id'])) { + $client->size_id = $data['size_id'] ? $data['size_id'] : null; + } + if (isset($data['industry_id'])) { + $client->industry_id = $data['industry_id'] ? $data['industry_id'] : null; + } + if (isset($data['currency_id'])) { + $client->currency_id = $data['currency_id'] ? $data['currency_id'] : null; + } + if (isset($data['payment_terms'])) { + $client->payment_terms = $data['payment_terms']; + } + if (isset($data['website'])) { + $client->website = trim($data['website']); + } + + $client->save(); + + $isPrimary = true; + $contactIds = []; + + if (isset($data['contact'])) { + $info = $data['contact']; + if (isset($info['email'])) { + $contact->email = trim(strtolower($info['email'])); + } + if (isset($info['first_name'])) { + $contact->first_name = trim($info['first_name']); + } + if (isset($info['last_name'])) { + $contact->last_name = trim($info['last_name']); + } + if (isset($info['phone'])) { + $contact->phone = trim($info['phone']); + } + $contact->is_primary = true; + $contact->send_invoice = true; + $client->contacts()->save($contact); + } else { + foreach ($data['contacts'] as $record) { + $record = (array) $record; + + if ($publicId != "-1" && isset($record['public_id']) && $record['public_id']) { + $contact = Contact::scope($record['public_id'])->firstOrFail(); + } else { + $contact = Contact::createNew(); + } + + if (isset($record['email'])) { + $contact->email = trim(strtolower($record['email'])); + } + if (isset($record['first_name'])) { + $contact->first_name = trim($record['first_name']); + } + if (isset($record['last_name'])) { + $contact->last_name = trim($record['last_name']); + } + if (isset($record['phone'])) { + $contact->phone = trim($record['phone']); + } + $contact->is_primary = $isPrimary; + $contact->send_invoice = isset($record['send_invoice']) ? $record['send_invoice'] : true; + $isPrimary = false; + + $client->contacts()->save($contact); + $contactIds[] = $contact->public_id; + } + + foreach ($client->contacts as $contact) { + if (!in_array($contact->public_id, $contactIds)) { + $contact->delete(); + } + } + } + + $client->save(); + + if (!$publicId || $publicId == "-1") { + \Activity::createClient($client, $notify); + } + + return $client; + } + + public function bulk($ids, $action) + { + $clients = Client::withTrashed()->scope($ids)->get(); + + foreach ($clients as $client) { + if ($action == 'restore') { + $client->restore(); + + $client->is_deleted = false; + $client->save(); + } else { + if ($action == 'delete') { + $client->is_deleted = true; + $client->save(); + } + + $client->delete(); + } + } + + return count($clients); + } +} diff --git a/app/ninja/repositories/CreditRepository.php b/app/ninja/repositories/CreditRepository.php new file mode 100644 index 000000000000..3bbdae5c8e10 --- /dev/null +++ b/app/ninja/repositories/CreditRepository.php @@ -0,0 +1,77 @@ +join('clients', 'clients.id', '=', 'credits.client_id') + ->join('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('clients.account_id', '=', \Auth::user()->account_id) + ->where('clients.deleted_at', '=', null) + ->where('contacts.is_primary', '=', true) + ->select('credits.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'credits.amount', 'credits.balance', 'credits.credit_date', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'credits.private_notes', 'credits.deleted_at', 'credits.is_deleted'); + + if ($clientPublicId) { + $query->where('clients.public_id', '=', $clientPublicId); + } + + if (!\Session::get('show_trash:credit')) { + $query->where('credits.deleted_at', '=', null); + } + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function save($publicId = null, $input) + { + if ($publicId) { + $credit = Credit::scope($publicId)->firstOrFail(); + } else { + $credit = Credit::createNew(); + } + + $credit->client_id = Client::getPrivateId($input['client']); + $credit->credit_date = Utils::toSqlDate($input['credit_date']); + $credit->amount = Utils::parseFloat($input['amount']); + $credit->balance = Utils::parseFloat($input['amount']); + $credit->private_notes = trim($input['private_notes']); + $credit->save(); + + return $credit; + } + + public function bulk($ids, $action) + { + if (!$ids) { + return 0; + } + + $credits = Credit::withTrashed()->scope($ids)->get(); + + foreach ($credits as $credit) { + if ($action == 'restore') { + $credit->restore(); + } else { + if ($action == 'delete') { + $credit->is_deleted = true; + $credit->save(); + } + + $credit->delete(); + } + } + + return count($credits); + } +} diff --git a/app/ninja/repositories/InvoiceRepository.php b/app/ninja/repositories/InvoiceRepository.php new file mode 100644 index 000000000000..c364cb569b9c --- /dev/null +++ b/app/ninja/repositories/InvoiceRepository.php @@ -0,0 +1,490 @@ +join('clients', 'clients.id', '=', 'invoices.client_id') + ->join('invoice_statuses', 'invoice_statuses.id', '=', 'invoices.invoice_status_id') + ->join('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('invoices.account_id', '=', $accountId) + ->where('clients.deleted_at', '=', null) + ->where('contacts.deleted_at', '=', null) + ->where('invoices.is_recurring', '=', false) + ->where('contacts.is_primary', '=', true) + ->select('clients.public_id as client_public_id', 'invoice_number', 'invoice_status_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'invoices.balance', 'invoice_date', 'due_date', 'invoice_statuses.name as invoice_status_name', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'quote_id', 'quote_invoice_id', 'invoices.deleted_at', 'invoices.is_deleted'); + + if (!\Session::get('show_trash:'.$entityType)) { + $query->where('invoices.deleted_at', '=', null); + } + + if ($clientPublicId) { + $query->where('clients.public_id', '=', $clientPublicId); + } + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('invoices.invoice_number', 'like', '%'.$filter.'%') + ->orWhere('invoice_statuses.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function getRecurringInvoices($accountId, $clientPublicId = false, $filter = false) + { + $query = \DB::table('invoices') + ->join('clients', 'clients.id', '=', 'invoices.client_id') + ->join('frequencies', 'frequencies.id', '=', 'invoices.frequency_id') + ->join('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('invoices.account_id', '=', $accountId) + ->where('invoices.is_quote', '=', false) + ->where('clients.deleted_at', '=', null) + ->where('contacts.deleted_at', '=', null) + ->where('invoices.is_recurring', '=', true) + ->where('contacts.is_primary', '=', true) + ->select('clients.public_id as client_public_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'frequencies.name as frequency', 'start_date', 'end_date', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'invoices.deleted_at', 'invoices.is_deleted'); + + if ($clientPublicId) { + $query->where('clients.public_id', '=', $clientPublicId); + } + + if (!\Session::get('show_trash:invoice')) { + $query->where('invoices.deleted_at', '=', null); + } + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('invoices.invoice_number', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function getClientDatatable($contactId, $entityType, $search) + { + $query = \DB::table('invitations') + ->join('invoices', 'invoices.id', '=', 'invitations.invoice_id') + ->join('clients', 'clients.id', '=', 'invoices.client_id') + ->where('invitations.contact_id', '=', $contactId) + ->where('invitations.deleted_at', '=', null) + ->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE) + ->where('invoices.is_deleted', '=', false) + ->where('clients.deleted_at', '=', null) + ->where('invoices.is_recurring', '=', false) + ->select('invitation_key', 'invoice_number', 'invoice_date', 'invoices.balance as balance', 'due_date', 'clients.public_id as client_public_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'start_date', 'end_date', 'clients.currency_id'); + + $table = \Datatable::query($query) + ->addColumn('invoice_number', function ($model) use ($entityType) { return link_to('/view/'.$model->invitation_key, $model->invoice_number); }) + ->addColumn('invoice_date', function ($model) { return Utils::fromSqlDate($model->invoice_date); }) + ->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); }); + + if ($entityType == ENTITY_INVOICE) { + $table->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); }); + } + + return $table->addColumn('due_date', function ($model) { return Utils::fromSqlDate($model->due_date); }) + ->make(); + } + + public function getDatatable($accountId, $clientPublicId = null, $entityType, $search) + { + $query = $this->getInvoices($accountId, $clientPublicId, $entityType, $search) + ->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE ? true : false); + + $table = \Datatable::query($query); + + if (!$clientPublicId) { + $table->addColumn('checkbox', function ($model) { return ''; }); + } + + $table->addColumn("invoice_number", function ($model) use ($entityType) { return link_to("{$entityType}s/".$model->public_id.'/edit', $model->invoice_number, ['class' => Utils::getEntityRowClass($model)]); }); + + if (!$clientPublicId) { + $table->addColumn('client_name', function ($model) { return link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)); }); + } + + $table->addColumn("invoice_date", function ($model) { return Utils::fromSqlDate($model->invoice_date); }) + ->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); }); + + if ($entityType == ENTITY_INVOICE) { + $table->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); }); + } + + return $table->addColumn('due_date', function ($model) { return Utils::fromSqlDate($model->due_date); }) + ->addColumn('invoice_status_name', function ($model) { return $model->quote_invoice_id ? link_to("invoices/{$model->quote_invoice_id}/edit", trans('texts.converted')) : $model->invoice_status_name; }) + ->addColumn('dropdown', function ($model) use ($entityType) { + + if ($model->is_deleted) { + return '
    '; + } + + $str = ''; + }) + ->make(); + } + + public function getErrors($input) + { + $contact = (array) $input->client->contacts[0]; + $rules = ['email' => 'required|email']; + $validator = \Validator::make($contact, $rules); + + if ($validator->fails()) { + return $validator; + } + + $invoice = (array) $input; + $invoiceId = isset($invoice['public_id']) && $invoice['public_id'] ? Invoice::getPrivateId($invoice['public_id']) : null; + $rules = [ + 'invoice_number' => 'required|unique:invoices,invoice_number,'.$invoiceId.',id,account_id,'.\Auth::user()->account_id, + 'discount' => 'positive', + ]; + + if ($invoice['is_recurring'] && $invoice['start_date'] && $invoice['end_date']) { + $rules['end_date'] = 'after:'.$invoice['start_date']; + } + + $validator = \Validator::make($invoice, $rules); + + if ($validator->fails()) { + return $validator; + } + + return false; + } + + public function save($publicId, $data, $entityType) + { + if ($publicId) { + $invoice = Invoice::scope($publicId)->firstOrFail(); + } else { + $invoice = Invoice::createNew(); + + if ($entityType == ENTITY_QUOTE) { + $invoice->is_quote = true; + } + } + + $account = \Auth::user()->account; + + $invoice->client_id = $data['client_id']; + $invoice->discount = round(Utils::parseFloat($data['discount']), 2); + $invoice->is_amount_discount = $data['is_amount_discount'] ? true : false; + $invoice->invoice_number = trim($data['invoice_number']); + $invoice->is_recurring = $data['is_recurring'] && !Utils::isDemo() ? true : false; + $invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']); + + if ($invoice->is_recurring) { + $invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0; + $invoice->start_date = Utils::toSqlDate($data['start_date']); + $invoice->end_date = Utils::toSqlDate($data['end_date']); + $invoice->due_date = null; + } else { + $invoice->due_date = isset($data['due_date_sql']) ? $data['due_date_sql'] : Utils::toSqlDate($data['due_date']); + $invoice->frequency_id = 0; + $invoice->start_date = null; + $invoice->end_date = null; + } + + $invoice->terms = trim($data['terms']) ? trim($data['terms']) : ($account->invoice_terms ? $account->invoice_terms : ''); + $invoice->invoice_footer = trim($data['invoice_footer']) ? trim($data['invoice_footer']) : $account->invoice_footer; + $invoice->public_notes = trim($data['public_notes']); + $invoice->po_number = trim($data['po_number']); + $invoice->invoice_design_id = $data['invoice_design_id']; + + if (isset($data['tax_name']) && isset($data['tax_rate']) && $data['tax_name']) { + $invoice->tax_rate = Utils::parseFloat($data['tax_rate']); + $invoice->tax_name = trim($data['tax_name']); + } else { + $invoice->tax_rate = 0; + $invoice->tax_name = ''; + } + + $total = 0; + + foreach ($data['invoice_items'] as $item) { + $item = (array) $item; + if (!$item['cost'] && !$item['product_key'] && !$item['notes']) { + continue; + } + + $invoiceItemCost = round(Utils::parseFloat($item['cost']), 2); + $invoiceItemQty = round(Utils::parseFloat($item['qty']), 2); + $invoiceItemTaxRate = 0; + + if (isset($item['tax_rate']) && Utils::parseFloat($item['tax_rate']) > 0) { + $invoiceItemTaxRate = Utils::parseFloat($item['tax_rate']); + } + + $lineTotal = $invoiceItemCost * $invoiceItemQty; + + $total += round($lineTotal + ($lineTotal * $invoiceItemTaxRate / 100), 2); + } + + if ($invoice->discount > 0) { + if ($invoice->is_amount_discount) { + $total -= $invoice->discount; + } else { + $total *= (100 - $invoice->discount) / 100; + } + } + + $invoice->custom_value1 = round($data['custom_value1'], 2); + $invoice->custom_value2 = round($data['custom_value2'], 2); + $invoice->custom_taxes1 = $data['custom_taxes1'] ? true : false; + $invoice->custom_taxes2 = $data['custom_taxes2'] ? true : false; + + // custom fields charged taxes + if ($invoice->custom_value1 && $invoice->custom_taxes1) { + $total += $invoice->custom_value1; + } + if ($invoice->custom_value2 && $invoice->custom_taxes2) { + $total += $invoice->custom_value2; + } + + $total += $total * $invoice->tax_rate / 100; + $total = round($total, 2); + + // custom fields not charged taxes + if ($invoice->custom_value1 && !$invoice->custom_taxes1) { + $total += $invoice->custom_value1; + } + if ($invoice->custom_value2 && !$invoice->custom_taxes2) { + $total += $invoice->custom_value2; + } + + if ($publicId) { + $invoice->balance = $total - ($invoice->amount - $invoice->balance); + } else { + $invoice->balance = $total; + } + + $invoice->amount = $total; + $invoice->save(); + + if ($publicId) { + $invoice->invoice_items()->forceDelete(); + } + + foreach ($data['invoice_items'] as $item) { + $item = (array) $item; + if (!$item['cost'] && !$item['product_key'] && !$item['notes']) { + continue; + } + + if ($item['product_key']) { + $product = Product::findProductByKey(trim($item['product_key'])); + + if (!$product) { + $product = Product::createNew(); + $product->product_key = trim($item['product_key']); + } + + if (\Auth::user()->account->update_products) { + $product->notes = $item['notes']; + $product->cost = $item['cost']; + } + + $product->save(); + } + + $invoiceItem = InvoiceItem::createNew(); + $invoiceItem->product_id = isset($product) ? $product->id : null; + $invoiceItem->product_key = trim($invoice->is_recurring ? $item->product_key : Utils::processVariables($item['product_key'])); + $invoiceItem->notes = trim($invoice->is_recurring ? $item['notes'] : Utils::processVariables($item['notes'])); + $invoiceItem->cost = Utils::parseFloat($item['cost']); + $invoiceItem->qty = Utils::parseFloat($item['qty']); + $invoiceItem->tax_rate = 0; + + if (isset($item['tax_rate']) && isset($item['tax_name']) && $item['tax_name']) { + $invoiceItem['tax_rate'] = Utils::parseFloat($item['tax_rate']); + $invoiceItem['tax_name'] = trim($item['tax_name']); + } + + $invoice->invoice_items()->save($invoiceItem); + } + + if ((isset($data['set_default_terms']) && $data['set_default_terms']) + || (isset($data['set_default_footer']) && $data['set_default_footer'])) { + if (isset($data['set_default_terms']) && $data['set_default_terms']) { + $account->invoice_terms = trim($data['terms']); + } + if (isset($data['set_default_footer']) && $data['set_default_footer']) { + $account->invoice_footer = trim($data['invoice_footer']); + } + $account->save(); + } + + return $invoice; + } + + public function cloneInvoice($invoice, $quotePublicId = null) + { + $invoice->load('invitations', 'invoice_items'); + $account = $invoice->account; + + $clone = Invoice::createNew($invoice); + $clone->balance = $invoice->amount; + + // if the invoice prefix is diff than quote prefix, use the same number for the invoice + if (($account->invoice_number_prefix || $account->quote_number_prefix) + && $account->invoice_number_prefix != $account->quote_number_prefix + && $account->share_counter) { + + $invoiceNumber = $invoice->invoice_number; + if (strpos($invoiceNumber, $account->quote_number_prefix) === 0) { + $invoiceNumber = substr($invoiceNumber, strlen($account->quote_number_prefix)); + } + $clone->invoice_number = $account->invoice_number_prefix.$invoiceNumber; + } else { + $clone->invoice_number = $account->getNextInvoiceNumber(); + } + + foreach ([ + 'client_id', + 'discount', + 'is_amount_discount', + 'invoice_date', + 'po_number', + 'due_date', + 'is_recurring', + 'frequency_id', + 'start_date', + 'end_date', + 'terms', + 'invoice_footer', + 'public_notes', + 'invoice_design_id', + 'tax_name', + 'tax_rate', + 'amount', + 'is_quote', + 'custom_value1', + 'custom_value2', + 'custom_taxes1', + 'custom_taxes2', ] as $field) { + $clone->$field = $invoice->$field; + } + + if ($quotePublicId) { + $clone->is_quote = false; + $clone->quote_id = $quotePublicId; + } + + $clone->save(); + + if ($quotePublicId) { + $invoice->quote_invoice_id = $clone->public_id; + $invoice->save(); + } + + foreach ($invoice->invoice_items as $item) { + $cloneItem = InvoiceItem::createNew($invoice); + + foreach ([ + 'product_id', + 'product_key', + 'notes', + 'cost', + 'qty', + 'tax_name', + 'tax_rate', ] as $field) { + $cloneItem->$field = $item->$field; + } + + $clone->invoice_items()->save($cloneItem); + } + + foreach ($invoice->invitations as $invitation) { + $cloneInvitation = Invitation::createNew($invoice); + $cloneInvitation->contact_id = $invitation->contact_id; + $cloneInvitation->invitation_key = str_random(RANDOM_KEY_LENGTH); + $clone->invitations()->save($cloneInvitation); + } + + return $clone; + } + + public function bulk($ids, $action, $statusId = false) + { + if (!$ids) { + return 0; + } + + $invoices = Invoice::withTrashed()->scope($ids)->get(); + + foreach ($invoices as $invoice) { + if ($action == 'mark') { + $invoice->invoice_status_id = $statusId; + $invoice->save(); + } elseif ($action == 'restore') { + $invoice->restore(); + } else { + if ($action == 'delete') { + $invoice->is_deleted = true; + $invoice->save(); + } + + $invoice->delete(); + } + } + + return count($invoices); + } +} diff --git a/app/ninja/repositories/PaymentRepository.php b/app/ninja/repositories/PaymentRepository.php new file mode 100644 index 000000000000..e7e986db374b --- /dev/null +++ b/app/ninja/repositories/PaymentRepository.php @@ -0,0 +1,154 @@ +join('clients', 'clients.id', '=', 'payments.client_id') + ->join('invoices', 'invoices.id', '=', 'payments.invoice_id') + ->join('contacts', 'contacts.client_id', '=', 'clients.id') + ->leftJoin('payment_types', 'payment_types.id', '=', 'payments.payment_type_id') + ->where('payments.account_id', '=', \Auth::user()->account_id) + ->where('clients.deleted_at', '=', null) + ->where('contacts.is_primary', '=', true) + ->where('contacts.deleted_at', '=', null) + ->select('payments.public_id', 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'payment_types.name as payment_type', 'payments.account_gateway_id', 'payments.deleted_at', 'payments.is_deleted', 'invoices.is_deleted as invoice_is_deleted'); + + if (!\Session::get('show_trash:payment')) { + $query->where('payments.deleted_at', '=', null) + ->where('invoices.deleted_at', '=', null); + } + + if ($clientPublicId) { + $query->where('clients.public_id', '=', $clientPublicId); + } + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function findForContact($contactId = null, $filter = null) + { + $query = \DB::table('payments') + ->join('clients', 'clients.id', '=', 'payments.client_id') + ->join('invoices', 'invoices.id', '=', 'payments.invoice_id') + ->join('contacts', 'contacts.client_id', '=', 'clients.id') + ->leftJoin('invitations', function ($join) { + $join->on('invitations.invoice_id', '=', 'invoices.id') + ->on('invitations.contact_id', '=', 'contacts.id'); + }) + ->leftJoin('payment_types', 'payment_types.id', '=', 'payments.payment_type_id') + ->where('clients.is_deleted', '=', false) + ->where('payments.is_deleted', '=', false) + ->where('invitations.deleted_at', '=', null) + ->where('invoices.deleted_at', '=', null) + ->where('invitations.contact_id', '=', $contactId) + ->select('invitations.invitation_key', 'payments.public_id', 'payments.transaction_reference', 'clients.name as client_name', 'clients.public_id as client_public_id', 'payments.amount', 'payments.payment_date', 'invoices.public_id as invoice_public_id', 'invoices.invoice_number', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'payment_types.name as payment_type', 'payments.account_gateway_id'); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function getErrors($input) + { + $rules = array( + 'client' => 'required', + 'invoice' => 'required', + 'amount' => 'required', + ); + + if ($input['payment_type_id'] == PAYMENT_TYPE_CREDIT) { + $rules['payment_type_id'] = 'has_credit:'.$input['client'].','.$input['amount']; + } + + $validator = \Validator::make($input, $rules); + + if ($validator->fails()) { + return $validator; + } + + return false; + } + + public function save($publicId = null, $input) + { + if ($publicId) { + $payment = Payment::scope($publicId)->firstOrFail(); + } else { + $payment = Payment::createNew(); + } + + $paymentTypeId = $input['payment_type_id'] ? $input['payment_type_id'] : null; + $payment->payment_type_id = $paymentTypeId; + $payment->payment_date = Utils::toSqlDate($input['payment_date']); + $payment->transaction_reference = trim($input['transaction_reference']); + + if (!$publicId) { + $clientId = Client::getPrivateId($input['client']); + $amount = Utils::parseFloat($input['amount']); + + if ($paymentTypeId == PAYMENT_TYPE_CREDIT) { + $credits = Credit::scope()->where('client_id', '=', $clientId) + ->where('balance', '>', 0)->orderBy('created_at')->get(); + $applied = 0; + + foreach ($credits as $credit) { + $applied += $credit->apply($amount); + + if ($applied >= $amount) { + break; + } + } + } + + $payment->client_id = $clientId; + $payment->invoice_id = isset($input['invoice']) && $input['invoice'] != "-1" ? Invoice::getPrivateId($input['invoice']) : null; + $payment->amount = $amount; + } + + $payment->save(); + + return $payment; + } + + public function bulk($ids, $action) + { + if (!$ids) { + return 0; + } + + $payments = Payment::withTrashed()->scope($ids)->get(); + + foreach ($payments as $payment) { + if ($action == 'restore') { + $payment->restore(); + } else { + if ($action == 'delete') { + $payment->is_deleted = true; + $payment->save(); + } + + $payment->delete(); + } + } + + return count($payments); + } +} diff --git a/app/ninja/repositories/TaxRateRepository.php b/app/ninja/repositories/TaxRateRepository.php new file mode 100644 index 000000000000..9fe1c854411e --- /dev/null +++ b/app/ninja/repositories/TaxRateRepository.php @@ -0,0 +1,42 @@ +rate) || (isset($record->is_deleted) && $record->is_deleted)) { + continue; + } + + if (!isset($record->name) || !trim($record->name)) { + continue; + } + + if ($record->public_id) { + $taxRate = TaxRate::scope($record->public_id)->firstOrFail(); + } else { + $taxRate = TaxRate::createNew(); + } + + $taxRate->rate = Utils::parseFloat($record->rate); + $taxRate->name = trim($record->name); + $taxRate->save(); + + $taxRateIds[] = $taxRate->public_id; + } + + $taxRates = TaxRate::scope()->get(); + + foreach ($taxRates as $taxRate) { + if (!in_array($taxRate->public_id, $taxRateIds)) { + $taxRate->delete(); + } + } + } +} diff --git a/composer.json b/composer.json index 1e8dd85a0b08..7fe73e950558 100644 --- a/composer.json +++ b/composer.json @@ -57,9 +57,9 @@ "autoload": { "classmap": [ "app/Console/Commands", + "app/libraries", "app/Http/Controllers", "app/Models", - "app/libraries", "app/ninja", "vendor/calvinfroedge/PHP-Payments/lib", "database" diff --git a/composer.lock b/composer.lock new file mode 100644 index 000000000000..08952bebc96f --- /dev/null +++ b/composer.lock @@ -0,0 +1,6220 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "1411d18a1a61e0241540bd59173b3c1b", + "packages": [ + { + "name": "alfaproject/omnipay-neteller", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/alfaproject/omnipay-neteller.git", + "reference": "e2b9129936cf45bf10e0dd406f897d2852e3d567" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alfaproject/omnipay-neteller/zipball/e2b9129936cf45bf10e0dd406f897d2852e3d567", + "reference": "e2b9129936cf45bf10e0dd406f897d2852e3d567", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0", + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Omnipay\\Neteller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joao Dias", + "email": "joao.dias@cherrygroup.com" + } + ], + "description": "Neteller driver for the Omnipay payment processing library", + "homepage": "https://github.com/alfaproject/omnipay-neteller", + "keywords": [ + "gateway", + "merchant", + "neteller", + "omnipay", + "pay", + "payment" + ], + "time": "2014-02-25 10:03:25" + }, + { + "name": "alfaproject/omnipay-skrill", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/alfaproject/omnipay-skrill.git", + "reference": "2fa2ba8083fd5289366660f8de1b46b5f49ac052" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alfaproject/omnipay-skrill/zipball/2fa2ba8083fd5289366660f8de1b46b5f49ac052", + "reference": "2fa2ba8083fd5289366660f8de1b46b5f49ac052", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0", + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Omnipay\\Skrill\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joao Dias", + "email": "joao.dias@cherrygroup.com" + } + ], + "description": "Skrill driver for the Omnipay payment processing library", + "homepage": "https://github.com/alfaproject/omnipay-skrill", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "skrill" + ], + "time": "2014-02-25 13:40:07" + }, + { + "name": "anahkiasen/former", + "version": "4.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/formers/former.git", + "reference": "ed7d00c2b11578a4db31531e1fee97f6ccd85030" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/formers/former/zipball/ed7d00c2b11578a4db31531e1fee97f6ccd85030", + "reference": "ed7d00c2b11578a4db31531e1fee97f6ccd85030", + "shasum": "" + }, + "require": { + "anahkiasen/html-object": "~1.4", + "illuminate/config": "5.0.*", + "illuminate/container": "5.0.*", + "illuminate/http": "5.0.*", + "illuminate/routing": "5.0.*", + "illuminate/session": "5.0.*", + "illuminate/translation": "5.0.*", + "php": ">=5.4.0" + }, + "require-dev": { + "illuminate/database": "5.0.*", + "mockery/mockery": "~0.9.1", + "phpunit/phpunit": "~4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Former\\": [ + "src/Former", + "tests" + ], + "Laravel\\": "src/Laravel" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Fabre", + "email": "ehtnam6@gmail.com" + } + ], + "description": "A powerful form builder", + "homepage": "http://anahkiasen.github.com/former/", + "keywords": [ + "bootstrap", + "form", + "foundation", + "laravel" + ], + "time": "2015-03-06 17:50:05" + }, + { + "name": "anahkiasen/html-object", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/Anahkiasen/html-object.git", + "reference": "7890eb43636b1cd5ae7c4aab0d27c6890065c9ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Anahkiasen/html-object/zipball/7890eb43636b1cd5ae7c4aab0d27c6890065c9ad", + "reference": "7890eb43636b1cd5ae7c4aab0d27c6890065c9ad", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "HtmlObject\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anahkiasen", + "email": "ehtnam6@gmail.com" + } + ], + "description": "A set of classes to create and manipulate HTML objects abstractions", + "time": "2015-03-04 17:12:08" + }, + { + "name": "barryvdh/laravel-debugbar", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-debugbar.git", + "reference": "7bdf8acf3b955f4fcf922e74abdfdec370369196" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/7bdf8acf3b955f4fcf922e74abdfdec370369196", + "reference": "7bdf8acf3b955f4fcf922e74abdfdec370369196", + "shasum": "" + }, + "require": { + "illuminate/support": "5.0.x", + "maximebf/debugbar": "~1.10.2", + "php": ">=5.4.0", + "symfony/finder": "~2.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\Debugbar\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "PHP Debugbar integration for Laravel", + "keywords": [ + "debug", + "debugbar", + "laravel", + "profiler", + "webprofiler" + ], + "time": "2015-02-19 10:26:39" + }, + { + "name": "barryvdh/laravel-ide-helper", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/barryvdh/laravel-ide-helper.git", + "reference": "81b7febfc64168ea1af57261aa4dfc9acefd5429" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/81b7febfc64168ea1af57261aa4dfc9acefd5429", + "reference": "81b7febfc64168ea1af57261aa4dfc9acefd5429", + "shasum": "" + }, + "require": { + "illuminate/console": "5.0.x", + "illuminate/filesystem": "5.0.x", + "illuminate/support": "5.0.x", + "php": ">=5.4.0", + "phpdocumentor/reflection-docblock": "2.0.x", + "symfony/class-loader": "~2.3" + }, + "require-dev": { + "doctrine/dbal": "~2.3" + }, + "suggest": { + "doctrine/dbal": "Load information from the database about models for phpdocs (~2.3)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Barryvdh\\LaravelIdeHelper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.", + "keywords": [ + "autocomplete", + "codeintel", + "helper", + "ide", + "laravel", + "netbeans", + "phpdoc", + "phpstorm", + "sublime" + ], + "time": "2015-02-23 15:55:54" + }, + { + "name": "calvinfroedge/PHP-Payments", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/calvinfroedge/PHP-Payments", + "reference": "origin/master" + }, + "type": "library", + "time": "2015-02-28 14:18:28" + }, + { + "name": "chumper/datatable", + "version": "dev-develop", + "source": { + "type": "git", + "url": "https://github.com/Chumper/Datatable.git", + "reference": "3b251b9c6d7d266d6af37d3096034cf69c6b50a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Chumper/Datatable/zipball/3b251b9c6d7d266d6af37d3096034cf69c6b50a8", + "reference": "3b251b9c6d7d266d6af37d3096034cf69c6b50a8", + "shasum": "" + }, + "require": { + "illuminate/config": "~5.0", + "illuminate/support": "~5.0", + "illuminate/view": "~5.0", + "php": ">=5.3.0" + }, + "require-dev": { + "mockery/mockery": "dev-master", + "orchestra/testbench": "2.1.*", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "Chumper\\Datatable": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Plaschke", + "email": "github@nilsplaschke.de", + "homepage": "http://nilsplaschke.de", + "role": "Developer" + } + ], + "description": "This is a laravel 4 package for the server and client side of datatablaes at http://datatables.net/", + "homepage": "http://github.com/Chumper/datatable", + "keywords": [ + "ajax", + "datatables", + "jquery", + "laravel" + ], + "time": "2015-03-08 23:17:58" + }, + { + "name": "classpreloader/classpreloader", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/ClassPreloader/ClassPreloader.git", + "reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/f0bfbf71fb3335c9473f695d4d966ba2fb879a9f", + "reference": "f0bfbf71fb3335c9473f695d4d966ba2fb879a9f", + "shasum": "" + }, + "require": { + "nikic/php-parser": "~1.0", + "php": ">=5.3.3", + "symfony/console": "~2.1", + "symfony/filesystem": "~2.1", + "symfony/finder": "~2.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "classpreloader.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "ClassPreloader\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "graham@mineuk.com" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com" + } + ], + "description": "Helps class loading performance by generating a single PHP file containing all of the autoloaded files for a specific use case", + "keywords": [ + "autoload", + "class", + "preload" + ], + "time": "2015-01-26 22:06:19" + }, + { + "name": "coatesap/omnipay-datacash", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/coatesap/omnipay-datacash.git", + "reference": "77915db87635c514576550dd15355987cadefc78" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/coatesap/omnipay-datacash/zipball/77915db87635c514576550dd15355987cadefc78", + "reference": "77915db87635c514576550dd15355987cadefc78", + "shasum": "" + }, + "require": { + "omnipay/common": "2.*" + }, + "require-dev": { + "guzzle/plugin-mock": "~3.1", + "mockery/mockery": "~0.8", + "omnipay/tests": "2.*", + "phpunit/phpunit": "~3.7.16", + "squizlabs/php_codesniffer": "~1.4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Omnipay\\DataCash\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrew Coates", + "email": "andycoatz@gmail.com" + } + ], + "description": "DataCash driver for the Omnipay payment processing library", + "homepage": "https://github.com/coatesap/omnipay-datacash", + "keywords": [ + "datacash", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2015-01-08 11:19:06" + }, + { + "name": "coatesap/omnipay-paymentsense", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/coatesap/omnipay-paymentsense.git", + "reference": "4a5a87ef140abf8e09ff27cd0e6502ac1e79e434" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/coatesap/omnipay-paymentsense/zipball/4a5a87ef140abf8e09ff27cd0e6502ac1e79e434", + "reference": "4a5a87ef140abf8e09ff27cd0e6502ac1e79e434", + "shasum": "" + }, + "require": { + "omnipay/common": "2.*" + }, + "require-dev": { + "guzzle/plugin-mock": "~3.1", + "mockery/mockery": "~0.8", + "omnipay/tests": "2.*", + "phpunit/phpunit": "~3.7.16", + "squizlabs/php_codesniffer": "~1.4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Omnipay\\PaymentSense\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrew Coates", + "email": "andycoatz@gmail.com" + } + ], + "description": "PaymentSense driver for the Omnipay payment processing library", + "homepage": "https://github.com/coatesap/paymentsense", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "payment sense", + "paymentsense" + ], + "time": "2014-03-18 17:17:57" + }, + { + "name": "coatesap/omnipay-realex", + "version": "v2.1.3", + "source": { + "type": "git", + "url": "https://github.com/coatesap/omnipay-realex.git", + "reference": "9a751a66c7fdd610a7c41493a57587d59944bbfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/coatesap/omnipay-realex/zipball/9a751a66c7fdd610a7c41493a57587d59944bbfa", + "reference": "9a751a66c7fdd610a7c41493a57587d59944bbfa", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "squizlabs/php_codesniffer": "~1.4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Omnipay\\Realex\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrew Coates", + "email": "andycoatz@gmail.com" + } + ], + "description": "Realex driver with 3D Secure support for Omnipay payment processing library", + "homepage": "https://github.com/coatesap/omnipay-realex", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "purchase", + "realex" + ], + "time": "2015-01-08 10:05:58" + }, + { + "name": "danielstjules/stringy", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/danielstjules/Stringy.git", + "reference": "3cf18e9e424a6dedc38b7eb7ef580edb0929461b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/3cf18e9e424a6dedc38b7eb7ef580edb0929461b", + "reference": "3cf18e9e424a6dedc38b7eb7ef580edb0929461b", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Stringy\\": "src/" + }, + "files": [ + "src/Create.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel St. Jules", + "email": "danielst.jules@gmail.com", + "homepage": "http://www.danielstjules.com" + } + ], + "description": "A string manipulation library with multibyte support", + "homepage": "https://github.com/danielstjules/Stringy", + "keywords": [ + "UTF", + "helpers", + "manipulation", + "methods", + "multibyte", + "string", + "utf-8", + "utility", + "utils" + ], + "time": "2015-02-10 06:19:18" + }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "type": "project", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "time": "2014-10-24 07:27:01" + }, + { + "name": "doctrine/annotations", + "version": "v1.2.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "eeda578cbe24a170331a1cfdf78be723412df7a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/eeda578cbe24a170331a1cfdf78be723412df7a4", + "reference": "eeda578cbe24a170331a1cfdf78be723412df7a4", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Annotations\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2014-12-20 20:49:38" + }, + { + "name": "doctrine/cache", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "2346085d2b027b233ae1d5de59b07440b9f288c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8", + "reference": "2346085d2b027b233ae1d5de59b07440b9f288c8", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": ">=3.7", + "predis/predis": "~0.8", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Cache\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2015-01-15 20:38:55" + }, + { + "name": "doctrine/collections", + "version": "v1.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2", + "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2014-02-03 23:07:43" + }, + { + "name": "doctrine/common", + "version": "v2.4.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/5db6ab40e4c531f14dad4ca96a394dfce5d4255b", + "reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b", + "shasum": "" + }, + "require": { + "doctrine/annotations": "1.*", + "doctrine/cache": "1.*", + "doctrine/collections": "1.*", + "doctrine/inflector": "1.*", + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~3.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/", + "role": "Creator" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Common Library for Doctrine projects", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "collections", + "eventmanager", + "persistence", + "spl" + ], + "time": "2014-05-21 19:28:51" + }, + { + "name": "doctrine/dbal", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "628c2256b646ae2417d44e063bce8aec5199d48d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/628c2256b646ae2417d44e063bce8aec5199d48d", + "reference": "628c2256b646ae2417d44e063bce8aec5199d48d", + "shasum": "" + }, + "require": { + "doctrine/common": ">=2.4,<2.6-dev", + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "symfony/console": "2.*" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\DBAL\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Database Abstraction Layer", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "persistence", + "queryobject" + ], + "time": "2015-01-12 21:52:47" + }, + { + "name": "doctrine/inflector", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "0bcb2e79d8571787f18b7eb036ed3d004908e604" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/0bcb2e79d8571787f18b7eb036ed3d004908e604", + "reference": "0bcb2e79d8571787f18b7eb036ed3d004908e604", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Inflector\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2014-12-20 21:24:13" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09 13:34:57" + }, + { + "name": "fruitcakestudio/omnipay-sisow", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/fruitcakestudio/omnipay-sisow.git", + "reference": "0ae3ae13da86c087e22717f051bc86d2057a0309" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcakestudio/omnipay-sisow/zipball/0ae3ae13da86c087e22717f051bc86d2057a0309", + "reference": "0ae3ae13da86c087e22717f051bc86d2057a0309", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.2" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Sisow\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + }, + { + "name": "Fruitcake Studio", + "homepage": "http://fruitcakestudio.nl" + } + ], + "description": "Sisow gateway for the Omnipay payment processing library", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "sisow" + ], + "time": "2015-01-16 08:41:13" + }, + { + "name": "guzzle/common", + "version": "v3.9.2", + "target-dir": "Guzzle/Common", + "source": { + "type": "git", + "url": "https://github.com/Guzzle3/common.git", + "reference": "2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Guzzle3/common/zipball/2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc", + "reference": "2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc", + "shasum": "" + }, + "require": { + "php": ">=5.3.2", + "symfony/event-dispatcher": ">=2.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle\\Common": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Common libraries used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "collection", + "common", + "event", + "exception" + ], + "abandoned": "guzzle/guzzle", + "time": "2014-08-11 04:32:36" + }, + { + "name": "guzzle/http", + "version": "v3.9.2", + "target-dir": "Guzzle/Http", + "source": { + "type": "git", + "url": "https://github.com/Guzzle3/http.git", + "reference": "1e8dd1e2ba9dc42332396f39fbfab950b2301dc5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Guzzle3/http/zipball/1e8dd1e2ba9dc42332396f39fbfab950b2301dc5", + "reference": "1e8dd1e2ba9dc42332396f39fbfab950b2301dc5", + "shasum": "" + }, + "require": { + "guzzle/common": "self.version", + "guzzle/parser": "self.version", + "guzzle/stream": "self.version", + "php": ">=5.3.2" + }, + "suggest": { + "ext-curl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle\\Http": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "HTTP libraries used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "client", + "curl", + "http", + "http client" + ], + "abandoned": "guzzle/guzzle", + "time": "2014-08-11 04:32:36" + }, + { + "name": "guzzle/parser", + "version": "v3.9.2", + "target-dir": "Guzzle/Parser", + "source": { + "type": "git", + "url": "https://github.com/Guzzle3/parser.git", + "reference": "6874d171318a8e93eb6d224cf85e4678490b625c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Guzzle3/parser/zipball/6874d171318a8e93eb6d224cf85e4678490b625c", + "reference": "6874d171318a8e93eb6d224cf85e4678490b625c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle\\Parser": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Interchangeable parsers used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "URI Template", + "cookie", + "http", + "message", + "url" + ], + "abandoned": "guzzle/guzzle", + "time": "2014-02-05 18:29:46" + }, + { + "name": "guzzle/stream", + "version": "v3.9.2", + "target-dir": "Guzzle/Stream", + "source": { + "type": "git", + "url": "https://github.com/Guzzle3/stream.git", + "reference": "60c7fed02e98d2c518dae8f97874c8f4622100f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Guzzle3/stream/zipball/60c7fed02e98d2c518dae8f97874c8f4622100f0", + "reference": "60c7fed02e98d2c518dae8f97874c8f4622100f0", + "shasum": "" + }, + "require": { + "guzzle/common": "self.version", + "php": ">=5.3.2" + }, + "suggest": { + "guzzle/http": "To convert Guzzle request objects to PHP streams" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle\\Stream": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle stream wrapper component", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "component", + "stream" + ], + "abandoned": "guzzle/guzzle", + "time": "2014-05-01 21:36:02" + }, + { + "name": "illuminate/html", + "version": "v5.0.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/html.git", + "reference": "3d1009bb8e0f25720c914af5c1f4015dd373c9ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/html/zipball/3d1009bb8e0f25720c914af5c1f4015dd373c9ef", + "reference": "3d1009bb8e0f25720c914af5c1f4015dd373c9ef", + "shasum": "" + }, + "require": { + "illuminate/http": "~5.0", + "illuminate/session": "~5.0", + "illuminate/support": "~5.0", + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Html\\": "" + }, + "files": [ + "helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "time": "2015-01-01 16:31:18" + }, + { + "name": "intervention/image", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Intervention/image.git", + "reference": "e58192bb1efd7dc26c2bac9ab8ab49b0cbb4552a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Intervention/image/zipball/e58192bb1efd7dc26c2bac9ab8ab49b0cbb4552a", + "reference": "e58192bb1efd7dc26c2bac9ab8ab49b0cbb4552a", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.2", + "phpunit/phpunit": "3.*" + }, + "suggest": { + "ext-gd": "to use GD library based image processing.", + "ext-imagick": "to use Imagick based image processing.", + "intervention/imagecache": "Caching extension for the Intervention Image library" + }, + "type": "library", + "autoload": { + "psr-4": { + "Intervention\\Image\\": "src/Intervention/Image" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oliver Vogel", + "email": "oliver@olivervogel.net", + "homepage": "http://olivervogel.net/" + } + ], + "description": "Image handling and manipulation library with support for Laravel integration", + "homepage": "http://image.intervention.io/", + "keywords": [ + "gd", + "image", + "imagick", + "laravel", + "thumbnail", + "watermark" + ], + "time": "2015-03-11 22:03:31" + }, + { + "name": "ircmaxell/password-compat", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/ircmaxell/password_compat.git", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "autoload": { + "files": [ + "lib/password.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthony Ferrara", + "email": "ircmaxell@php.net", + "homepage": "http://blog.ircmaxell.com" + } + ], + "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash", + "homepage": "https://github.com/ircmaxell/password_compat", + "keywords": [ + "hashing", + "password" + ], + "time": "2014-11-20 16:49:30" + }, + { + "name": "jakub-onderka/php-console-color", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1", + "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "jakub-onderka/php-code-style": "1.0", + "jakub-onderka/php-parallel-lint": "0.*", + "jakub-onderka/php-var-dump-check": "0.*", + "phpunit/phpunit": "3.7.*", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "JakubOnderka\\PhpConsoleColor": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com", + "homepage": "http://www.acci.cz" + } + ], + "time": "2014-04-08 15:00:19" + }, + { + "name": "jakub-onderka/php-console-highlighter", + "version": "v0.3.1", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", + "reference": "05bce997da20acf873e6bf396276798f3cd2c76a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/05bce997da20acf873e6bf396276798f3cd2c76a", + "reference": "05bce997da20acf873e6bf396276798f3cd2c76a", + "shasum": "" + }, + "require": { + "jakub-onderka/php-console-color": "~0.1", + "php": ">=5.3.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "~1.0", + "jakub-onderka/php-parallel-lint": "~0.5", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JakubOnderka\\PhpConsoleHighlighter": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" + } + ], + "time": "2014-07-14 20:59:35" + }, + { + "name": "jeremeamia/SuperClosure", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/jeremeamia/super_closure.git", + "reference": "b712f39c671e5ead60c7ebfe662545456aade833" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/b712f39c671e5ead60c7ebfe662545456aade833", + "reference": "b712f39c671e5ead60c7ebfe662545456aade833", + "shasum": "" + }, + "require": { + "nikic/php-parser": "~1.0", + "php": ">=5.4" + }, + "require-dev": { + "codeclimate/php-test-reporter": "~0.1.2", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "SuperClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia", + "role": "Developer" + } + ], + "description": "Serialize Closure objects, including their context and binding", + "homepage": "https://github.com/jeremeamia/super_closure", + "keywords": [ + "closure", + "function", + "lambda", + "parser", + "serializable", + "serialize", + "tokenizer" + ], + "time": "2015-03-11 20:06:43" + }, + { + "name": "jsanc623/phpbenchtime", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/jsanc623/PHPBenchTime.git", + "reference": "e8cba5217fe5998ae1926c2cb2202d8d973db1f1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jsanc623/PHPBenchTime/zipball/e8cba5217fe5998ae1926c2cb2202d8d973db1f1", + "reference": "e8cba5217fe5998ae1926c2cb2202d8d973db1f1", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Juan Sanchez", + "email": "juan.sanchez@juanleonardosanchez.com" + } + ], + "description": "A light benchmark timer class for PHP.", + "keywords": [ + "benchmark", + "benchtime", + "profiler", + "stopwatch", + "timer" + ], + "time": "2014-07-23 20:52:24" + }, + { + "name": "laravel/framework", + "version": "v5.0.15", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "ec3a166c504acedffd8ed878b08481f9cb1497fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/ec3a166c504acedffd8ed878b08481f9cb1497fb", + "reference": "ec3a166c504acedffd8ed878b08481f9cb1497fb", + "shasum": "" + }, + "require": { + "classpreloader/classpreloader": "~1.2", + "danielstjules/stringy": "~1.8", + "doctrine/inflector": "~1.0", + "ext-mbstring": "*", + "ext-mcrypt": "*", + "ext-openssl": "*", + "ircmaxell/password-compat": "~1.0", + "jeremeamia/superclosure": "~2.0", + "league/flysystem": "~1.0", + "monolog/monolog": "~1.11", + "mtdowling/cron-expression": "~1.0", + "nesbot/carbon": "~1.0", + "php": ">=5.4.0", + "psy/psysh": "0.4.*", + "swiftmailer/swiftmailer": "~5.1", + "symfony/console": "2.6.*", + "symfony/debug": "2.6.*", + "symfony/finder": "2.6.*", + "symfony/http-foundation": "2.6.*", + "symfony/http-kernel": "2.6.*", + "symfony/process": "2.6.*", + "symfony/routing": "2.6.*", + "symfony/security-core": "2.6.*", + "symfony/translation": "2.6.*", + "symfony/var-dumper": "2.6.*", + "vlucas/phpdotenv": "~1.0" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/exception": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/foundation": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/mail": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version" + }, + "require-dev": { + "aws/aws-sdk-php": "~2.4", + "iron-io/iron_mq": "~1.5", + "mockery/mockery": "~0.9", + "pda/pheanstalk": "~3.0", + "phpunit/phpunit": "~4.0", + "predis/predis": "~1.0" + }, + "suggest": { + "aws/aws-sdk-php": "Required to use the SQS queue driver (~2.4).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).", + "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers (~5.0).", + "iron-io/iron_mq": "Required to use the iron queue driver (~1.5).", + "league/flysystem-aws-s3-v2": "Required to use the Flysystem S3 driver (~1.0).", + "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", + "predis/predis": "Required to use the redis cache and queue drivers (~1.0)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/Illuminate/Queue/IlluminateQueueClosure.php" + ], + "files": [ + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "http://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "time": "2015-03-12 14:09:40" + }, + { + "name": "league/flysystem", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "51cd7cd7ee0defbaafc6ec0d3620110a5d71e11a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/51cd7cd7ee0defbaafc6ec0d3620110a5d71e11a", + "reference": "51cd7cd7ee0defbaafc6ec0d3620110a5d71e11a", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "ext-fileinfo": "*", + "league/phpunit-coverage-listener": "~1.1", + "mockery/mockery": "~0.9", + "phpspec/phpspec": "~2.0.0", + "phpspec/prophecy-phpunit": "~1.0", + "phpunit/phpunit": "~4.1", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12.0" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-copy": "Allows you to use Copy.com storage", + "league/flysystem-dropbox": "Allows you to use Dropbox storage", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "predis/predis": "Allows you to use Predis for caching" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "time": "2015-03-10 11:04:14" + }, + { + "name": "lokielse/omnipay-alipay", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/lokielse/omnipay-alipay.git", + "reference": "d7ed96d785b980ddf159709431fe3c25e4503612" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lokielse/omnipay-alipay/zipball/d7ed96d785b980ddf159709431fe3c25e4503612", + "reference": "d7ed96d785b980ddf159709431fe3c25e4503612", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Omnipay\\Alipay\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Loki Else", + "email": "lokielse@gmail.com" + } + ], + "description": "Alipay gateway for Omnipay payment processing library", + "homepage": "https://github.com/lokielse/omnipay-alipay", + "keywords": [ + "alipay", + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "purchase" + ], + "time": "2015-02-03 05:58:34" + }, + { + "name": "maximebf/debugbar", + "version": "v1.10.4", + "source": { + "type": "git", + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "7b2006e6e095126b5a061ec33fca3d90ea8a8219" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/7b2006e6e095126b5a061ec33fca3d90ea8a8219", + "reference": "7b2006e6e095126b5a061ec33fca3d90ea8a8219", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0", + "symfony/var-dumper": "~2.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-0": { + "DebugBar": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + } + ], + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", + "keywords": [ + "debug" + ], + "time": "2015-02-05 07:51:20" + }, + { + "name": "mfauveau/omnipay-pacnet", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/mfauveau/omnipay-pacnet.git", + "reference": "84201b2d216c8327f1cba379e123abb5e09b0f74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mfauveau/omnipay-pacnet/zipball/84201b2d216c8327f1cba379e123abb5e09b0f74", + "reference": "84201b2d216c8327f1cba379e123abb5e09b0f74", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Omnipay\\Pacnet\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthieu Fauveau", + "email": "mfauveau@gmail.com" + } + ], + "description": "Pacnet (Raven) driver for the Omnipay PHP payment processing library", + "homepage": "https://github.com/mfauveau/omnipay-pacnet", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pacnet", + "pay", + "payment", + "purchase", + "raven" + ], + "time": "2014-08-19 18:50:39" + }, + { + "name": "monolog/monolog", + "version": "1.13.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "c31a2c4e8db5da8b46c74cf275d7f109c0f249ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c31a2c4e8db5da8b46c74cf275d7f109c0f249ac", + "reference": "c31a2c4e8db5da8b46c74cf275d7f109c0f249ac", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "~2.4, >2.4.8", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "phpunit/phpunit": "~4.0", + "raven/raven": "~0.5", + "ruflin/elastica": "0.90.*", + "swiftmailer/swiftmailer": "~5.3", + "videlalvaro/php-amqplib": "~2.4" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2015-03-09 09:58:04" + }, + { + "name": "mtdowling/cron-expression", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/mtdowling/cron-expression.git", + "reference": "fd92e883195e5dfa77720b1868cf084b08be4412" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/fd92e883195e5dfa77720b1868cf084b08be4412", + "reference": "fd92e883195e5dfa77720b1868cf084b08be4412", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "autoload": { + "psr-0": { + "Cron": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "time": "2015-01-11 23:07:46" + }, + { + "name": "nesbot/carbon", + "version": "1.17.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "a1dd1ad9abfc8b3c4d8768068e6c71d293424e86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/a1dd1ad9abfc8b3c4d8768068e6c71d293424e86", + "reference": "a1dd1ad9abfc8b3c4d8768068e6c71d293424e86", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Carbon": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "http://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "time": "2015-03-08 14:05:44" + }, + { + "name": "nikic/php-parser", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "ac05ef6f95bf8361549604b6031c115f92f39528" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ac05ef6f95bf8361549604b6031c115f92f39528", + "reference": "ac05ef6f95bf8361549604b6031c115f92f39528", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "files": [ + "lib/bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2015-01-18 11:29:59" + }, + { + "name": "omnipay/2checkout", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-2checkout.git", + "reference": "31394ce58d5999b6f49b321cb3547747837c1297" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-2checkout/zipball/31394ce58d5999b6f49b321cb3547747837c1297", + "reference": "31394ce58d5999b6f49b321cb3547747837c1297", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\TwoCheckout\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-2checkout/contributors" + } + ], + "description": "2Checkout driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-2checkout", + "keywords": [ + "2checkout", + "2co", + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "twocheckout" + ], + "time": "2014-09-17 00:35:37" + }, + { + "name": "omnipay/authorizenet", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-authorizenet.git", + "reference": "233b9c6378e3c65833e972e67b8e699208c04803" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-authorizenet/zipball/233b9c6378e3c65833e972e67b8e699208c04803", + "reference": "233b9c6378e3c65833e972e67b8e699208c04803", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\AuthorizeNet\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-authorizenet/contributors" + } + ], + "description": "Authorize.Net gateway for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-authorizenet", + "keywords": [ + "authorize", + "authorize net", + "authorize.net", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2014-10-24 17:32:06" + }, + { + "name": "omnipay/buckaroo", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-buckaroo.git", + "reference": "76a4fdc4af46a2eeff58036bcb16af7d077363b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-buckaroo/zipball/76a4fdc4af46a2eeff58036bcb16af7d077363b9", + "reference": "76a4fdc4af46a2eeff58036bcb16af7d077363b9", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Buckaroo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-buckaroo/contributors" + } + ], + "description": "Buckaroo driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-buckaroo", + "keywords": [ + "buckaroo", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-17 00:35:28" + }, + { + "name": "omnipay/cardsave", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-cardsave.git", + "reference": "368fb2f56adb5be2ffcb3c29a7ddcd585cb41a04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-cardsave/zipball/368fb2f56adb5be2ffcb3c29a7ddcd585cb41a04", + "reference": "368fb2f56adb5be2ffcb3c29a7ddcd585cb41a04", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\CardSave\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-cardsave/contributors" + } + ], + "description": "CardSave driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-cardsave", + "keywords": [ + "card save", + "cardsave", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-21 02:27:16" + }, + { + "name": "omnipay/coinbase", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-coinbase.git", + "reference": "69c4f07d88ef3bdb2b42cd90234b358b641dfa29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-coinbase/zipball/69c4f07d88ef3bdb2b42cd90234b358b641dfa29", + "reference": "69c4f07d88ef3bdb2b42cd90234b358b641dfa29", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Coinbase\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-coinbase/contributors" + } + ], + "description": "Coinbase driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-coinbase", + "keywords": [ + "coinbase", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2015-03-06 05:35:39" + }, + { + "name": "omnipay/common", + "version": "v2.3.3", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-common.git", + "reference": "e4c54a314a2529c1008ad3f77e9eef26ed1f311b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-common/zipball/e4c54a314a2529c1008ad3f77e9eef26ed1f311b", + "reference": "e4c54a314a2529c1008ad3f77e9eef26ed1f311b", + "shasum": "" + }, + "require": { + "guzzle/http": "~3.1", + "php": ">=5.3.2", + "symfony/http-foundation": "~2.1" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + }, + "gateways": [ + "AuthorizeNet_AIM", + "AuthorizeNet_SIM", + "Buckaroo", + "Buckaroo_Ideal", + "Buckaroo_PayPal", + "CardSave", + "Coinbase", + "Dummy", + "Eway_Rapid", + "FirstData_Connect", + "GoCardless", + "Manual", + "Migs_ThreeParty", + "Migs_TwoParty", + "Mollie", + "MultiSafepay", + "Netaxept", + "NetBanx", + "PayFast", + "Payflow_Pro", + "PaymentExpress_PxPay", + "PaymentExpress_PxPost", + "PayPal_Express", + "PayPal_Pro", + "Pin", + "SagePay_Direct", + "SagePay_Server", + "SecurePay_DirectPost", + "Stripe", + "TargetPay_Directebanking", + "TargetPay_Ideal", + "TargetPay_Mrcash", + "TwoCheckout", + "WorldPay", + "Alipay Bank", + "AliPay Dual Func", + "Alipay Express", + "Alipay Mobile Express", + "Alipay Secured", + "Alipay Wap Express", + "Cybersource", + "DataCash", + "Ecopayz", + "Neteller", + "Pacnet", + "PaymentSense", + "Realex Remote", + "SecPay (PayPoint.net)", + "Sisow", + "Skrill", + "YandexMoney", + "YandexMoneyIndividual" + ] + }, + "autoload": { + "psr-0": { + "Omnipay\\Common\\": "src/" + }, + "classmap": [ + "src/Omnipay/Omnipay.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-common/contributors" + } + ], + "description": "Common components for Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-common", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "purchase" + ], + "time": "2015-01-11 04:54:29" + }, + { + "name": "omnipay/dummy", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-dummy.git", + "reference": "2e4d4b37114917b7b843bed3cd19bafdf22ad420" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-dummy/zipball/2e4d4b37114917b7b843bed3cd19bafdf22ad420", + "reference": "2e4d4b37114917b7b843bed3cd19bafdf22ad420", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Dummy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-dummy/contributors" + } + ], + "description": "Dummy driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-dummy", + "keywords": [ + "Dummy", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-17 00:39:36" + }, + { + "name": "omnipay/eway", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-eway.git", + "reference": "031236cf5653b5a021a5eb5565aceb923f64d964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-eway/zipball/031236cf5653b5a021a5eb5565aceb923f64d964", + "reference": "031236cf5653b5a021a5eb5565aceb923f64d964", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Eway\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-eway/contributors" + } + ], + "description": "eWay driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-eway", + "keywords": [ + "eway", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-17 00:39:29" + }, + { + "name": "omnipay/firstdata", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-firstdata.git", + "reference": "3c198a29ab36c0d2fa17495444e5ab6e1d79e212" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-firstdata/zipball/3c198a29ab36c0d2fa17495444e5ab6e1d79e212", + "reference": "3c198a29ab36c0d2fa17495444e5ab6e1d79e212", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\FirstData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-firstdata/contributors" + } + ], + "description": "First Data driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-firstdata", + "keywords": [ + "first data", + "firstdata", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-17 00:39:22" + }, + { + "name": "omnipay/gocardless", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-gocardless.git", + "reference": "106c2cc2f992813319c86f45863347c238771548" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-gocardless/zipball/106c2cc2f992813319c86f45863347c238771548", + "reference": "106c2cc2f992813319c86f45863347c238771548", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\GoCardless\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-gocardless/contributors" + } + ], + "description": "GoCardless driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-gocardless", + "keywords": [ + "gateway", + "go cardless", + "gocardless", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-17 00:39:16" + }, + { + "name": "omnipay/manual", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-manual.git", + "reference": "ddbe7e8cfdb03b102219185aeb7dd91823275c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-manual/zipball/ddbe7e8cfdb03b102219185aeb7dd91823275c71", + "reference": "ddbe7e8cfdb03b102219185aeb7dd91823275c71", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Manual\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-manual/contributors" + } + ], + "description": "Manual driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-manual", + "keywords": [ + "gateway", + "manual", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-17 00:37:01" + }, + { + "name": "omnipay/migs", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-migs.git", + "reference": "b49e9f2816a5cdd3c1ba2bcb46a0c73dc43c0b3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-migs/zipball/b49e9f2816a5cdd3c1ba2bcb46a0c73dc43c0b3b", + "reference": "b49e9f2816a5cdd3c1ba2bcb46a0c73dc43c0b3b", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Migs\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-migs/contributors" + } + ], + "description": "MIGS driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-migs", + "keywords": [ + "gateway", + "mastercard internet gateway service", + "merchant", + "migs", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-17 00:38:25" + }, + { + "name": "omnipay/mollie", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-mollie.git", + "reference": "ea3830b0aaa845430387e5afc1f638be18a152ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-mollie/zipball/ea3830b0aaa845430387e5afc1f638be18a152ec", + "reference": "ea3830b0aaa845430387e5afc1f638be18a152ec", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.2" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Mollie\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-mollie/contributors" + } + ], + "description": "Mollie driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-mollie", + "keywords": [ + "gateway", + "merchant", + "mollie", + "omnipay", + "pay", + "payment" + ], + "time": "2014-10-15 14:25:03" + }, + { + "name": "omnipay/multisafepay", + "version": "V2.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-multisafepay.git", + "reference": "a0f09abf404ca0dd21b553578d7f95df2bfa5318" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-multisafepay/zipball/a0f09abf404ca0dd21b553578d7f95df2bfa5318", + "reference": "a0f09abf404ca0dd21b553578d7f95df2bfa5318", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\MultiSafepay\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-multisafepay/contributors" + } + ], + "description": "MultiSafepay driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-multisafepay", + "keywords": [ + "gateway", + "merchant", + "multi safepay", + "multisafepay", + "omnipay", + "pay", + "payment" + ], + "time": "2015-01-14 04:01:43" + }, + { + "name": "omnipay/netaxept", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-netaxept.git", + "reference": "a661c212428703175f17e3f8f0a32f24b06fe9f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-netaxept/zipball/a661c212428703175f17e3f8f0a32f24b06fe9f8", + "reference": "a661c212428703175f17e3f8f0a32f24b06fe9f8", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Netaxept\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-netaxept/contributors" + } + ], + "description": "Netaxept driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-netaxept", + "keywords": [ + "gateway", + "merchant", + "netaxept", + "omnipay", + "pay", + "payment" + ], + "time": "2015-01-12 16:10:59" + }, + { + "name": "omnipay/netbanx", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-netbanx.git", + "reference": "a56900120e676385cc42d67c82985fcaaa752140" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-netbanx/zipball/a56900120e676385cc42d67c82985fcaaa752140", + "reference": "a56900120e676385cc42d67c82985fcaaa752140", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\NetBanx\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-netbanx/contributors" + } + ], + "description": "NetBanx driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-netbanx", + "keywords": [ + "gateway", + "merchant", + "netbanx", + "omnipay", + "pay", + "payment" + ], + "time": "2014-09-17 00:38:46" + }, + { + "name": "omnipay/omnipay", + "version": "2.3.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay.git", + "reference": "e9e6d95a2e7c3641ba31c985334d82e39dbd6078" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay/zipball/e9e6d95a2e7c3641ba31c985334d82e39dbd6078", + "reference": "e9e6d95a2e7c3641ba31c985334d82e39dbd6078", + "shasum": "" + }, + "require": { + "omnipay/2checkout": "~2.0", + "omnipay/authorizenet": "~2.0", + "omnipay/buckaroo": "~2.0", + "omnipay/cardsave": "~2.0", + "omnipay/coinbase": "~2.0", + "omnipay/common": "~2.3.0", + "omnipay/dummy": "~2.0", + "omnipay/eway": "~2.0", + "omnipay/firstdata": "~2.0", + "omnipay/gocardless": "~2.0", + "omnipay/manual": "~2.0", + "omnipay/migs": "~2.0", + "omnipay/mollie": "~3.0", + "omnipay/multisafepay": "~2.0", + "omnipay/netaxept": "~2.0", + "omnipay/netbanx": "~2.0", + "omnipay/payfast": "~2.0", + "omnipay/payflow": "~2.0", + "omnipay/paymentexpress": "~2.0", + "omnipay/paypal": "~2.0", + "omnipay/pin": "~2.0", + "omnipay/sagepay": "~2.0", + "omnipay/securepay": "~2.0", + "omnipay/stripe": "~2.0", + "omnipay/targetpay": "~2.0", + "omnipay/worldpay": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "metapackage", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Community", + "homepage": "https://github.com/thephpleague/omnipay/graphs/contributors" + } + ], + "description": "Includes Omnipay payment processing library and all officially supported gateways", + "homepage": "https://github.com/thephpleague/omnipay", + "keywords": [ + "2checkout", + "2co", + "auth.net", + "authorize", + "authorize.net", + "buckaroo", + "cardsave", + "coinbase", + "commweb", + "dps", + "egate", + "eway", + "express", + "first data", + "firstdata", + "gateway", + "gocardless", + "ideal", + "merchant", + "migs", + "mollie", + "multisafepay", + "netaxept", + "netbanx", + "pay", + "payfast", + "payflow", + "payment", + "paymentexpress", + "paypal", + "pin", + "purchase", + "rapid", + "sagepay", + "securepay", + "stripe", + "tala", + "tala-payments", + "targetpay", + "twocheckout", + "worldpay" + ], + "time": "2014-12-10 13:55:00" + }, + { + "name": "omnipay/payfast", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-payfast.git", + "reference": "b5b0a0ce86a6471871e2b149643fc8cb836c465f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-payfast/zipball/b5b0a0ce86a6471871e2b149643fc8cb836c465f", + "reference": "b5b0a0ce86a6471871e2b149643fc8cb836c465f", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\PayFast\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-payfast/contributors" + } + ], + "description": "PayFast driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-payfast", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payfast", + "payment" + ], + "time": "2014-09-17 00:39:04" + }, + { + "name": "omnipay/payflow", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-payflow.git", + "reference": "9d86e3478dd42cbe40ab9466a7505c4f99c70ee7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-payflow/zipball/9d86e3478dd42cbe40ab9466a7505c4f99c70ee7", + "reference": "9d86e3478dd42cbe40ab9466a7505c4f99c70ee7", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Payflow\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-payflow/contributors" + } + ], + "description": "Payflow driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-payflow", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payflow", + "payment" + ], + "time": "2014-09-17 00:38:58" + }, + { + "name": "omnipay/paymentexpress", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-paymentexpress.git", + "reference": "a6309569a4a4372fe1c9cb464ff2ef57101df46d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-paymentexpress/zipball/a6309569a4a4372fe1c9cb464ff2ef57101df46d", + "reference": "a6309569a4a4372fe1c9cb464ff2ef57101df46d", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\PaymentExpress\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-paymentexpress/contributors" + } + ], + "description": "Payment Express (DPS) driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-paymentexpress", + "keywords": [ + "direct payment solutions", + "dps", + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "payment express", + "paymentexpress", + "pxaccess", + "pxpay", + "pxpost" + ], + "time": "2014-09-17 00:37:09" + }, + { + "name": "omnipay/paypal", + "version": "v2.4.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-paypal.git", + "reference": "feacf47b52f599c8271625c44abc869178840ce4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-paypal/zipball/feacf47b52f599c8271625c44abc869178840ce4", + "reference": "feacf47b52f599c8271625c44abc869178840ce4", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\PayPal\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-paypal/contributors" + } + ], + "description": "PayPal gateway for Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-paypal", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "paypal", + "purchase" + ], + "time": "2015-03-10 23:39:59" + }, + { + "name": "omnipay/pin", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/omnipay/pin.git", + "reference": "04e778e9689882d4c40419263014068b69b93168" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/omnipay/pin/zipball/04e778e9689882d4c40419263014068b69b93168", + "reference": "04e778e9689882d4c40419263014068b69b93168", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Pin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/omnipay/pin/contributors" + } + ], + "description": "Pin Payments driver for the Omnipay payment processing library", + "homepage": "https://github.com/omnipay/pin", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "pin" + ], + "time": "2014-04-14 11:26:15" + }, + { + "name": "omnipay/sagepay", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-sagepay.git", + "reference": "2d24d15c7a78e2fe1ffb7af705948a60a6492dc6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-sagepay/zipball/2d24d15c7a78e2fe1ffb7af705948a60a6492dc6", + "reference": "2d24d15c7a78e2fe1ffb7af705948a60a6492dc6", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\SagePay\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-sagepay/contributors" + } + ], + "description": "Sage Pay driver for the Omnipay PHP payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-sagepay", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "purchase", + "sage pay", + "sagepay" + ], + "time": "2014-09-17 00:40:02" + }, + { + "name": "omnipay/securepay", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/omnipay/securepay.git", + "reference": "09503288fdb1efcd81bd0ac3c1800ce0ce13cc6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/omnipay/securepay/zipball/09503288fdb1efcd81bd0ac3c1800ce0ce13cc6e", + "reference": "09503288fdb1efcd81bd0ac3c1800ce0ce13cc6e", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\SecurePay\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/omnipay/securepay/contributors" + } + ], + "description": "SecurePay driver for the Omnipay payment processing library", + "homepage": "https://github.com/omnipay/securepay", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "securepay" + ], + "time": "2014-04-14 11:26:20" + }, + { + "name": "omnipay/stripe", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-stripe.git", + "reference": "23a5f77ed5345356c458355419395cbbf0106049" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-stripe/zipball/23a5f77ed5345356c458355419395cbbf0106049", + "reference": "23a5f77ed5345356c458355419395cbbf0106049", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Stripe\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-stripe/contributors" + } + ], + "description": "Stripe driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-stripe", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "stripe" + ], + "time": "2015-01-27 17:58:03" + }, + { + "name": "omnipay/targetpay", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/omnipay/targetpay.git", + "reference": "7274721c97f6f8ad3d2a8b4dea474ac548c45bac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/omnipay/targetpay/zipball/7274721c97f6f8ad3d2a8b4dea474ac548c45bac", + "reference": "7274721c97f6f8ad3d2a8b4dea474ac548c45bac", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\TargetPay\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/omnipay/targetpay/contributors" + } + ], + "description": "TargetPay driver for the Omnipay payment processing library", + "homepage": "https://github.com/omnipay/targetpay", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "targetpay" + ], + "time": "2014-04-14 12:23:56" + }, + { + "name": "omnipay/worldpay", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/omnipay-worldpay.git", + "reference": "5353f02b7f800b93d8aeae606d6df09afa538457" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/omnipay-worldpay/zipball/5353f02b7f800b93d8aeae606d6df09afa538457", + "reference": "5353f02b7f800b93d8aeae606d6df09afa538457", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\WorldPay\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "Omnipay Contributors", + "homepage": "https://github.com/thephpleague/omnipay-worldpay/contributors" + } + ], + "description": "WorldPay driver for the Omnipay payment processing library", + "homepage": "https://github.com/thephpleague/omnipay-worldpay", + "keywords": [ + "gateway", + "merchant", + "omnipay", + "pay", + "payment", + "worldpay" + ], + "time": "2014-09-17 00:37:18" + }, + { + "name": "patricktalmadge/bootstrapper", + "version": "5.5.3", + "source": { + "type": "git", + "url": "https://github.com/patricktalmadge/bootstrapper.git", + "reference": "0c5d5199c887f8a730899963be37a055d1d5ba29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/patricktalmadge/bootstrapper/zipball/0c5d5199c887f8a730899963be37a055d1d5ba29", + "reference": "0c5d5199c887f8a730899963be37a055d1d5ba29", + "shasum": "" + }, + "require": { + "illuminate/config": "~4.2||~5", + "illuminate/html": "~4.2||~5", + "illuminate/routing": "~4.2||~5", + "illuminate/support": "~4.2||~5", + "php": ">=5.4.0", + "twbs/bootstrap": "~3" + }, + "require-dev": { + "akeneo/phpspec-skip-example-extension": "~1.1", + "mockery/mockery": "~0.9", + "phpspec/phpspec": "~2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Bootstrapper\\": "src\\Bootstrapper", + "DummyClasses\\": "tests\\DummyClasses" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maxime Fabre", + "email": "ehtnam6@gmail.com" + }, + { + "name": "Patrick Talmadge", + "email": "ptalmadge@gmail.com" + }, + { + "name": "Patrick Rose", + "email": "pjr0911025@gmail.com" + } + ], + "description": "Twitter Bootstrap markup generator", + "keywords": [ + "bootstrap", + "laravel" + ], + "time": "2015-02-28 17:09:35" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03 12:10:50" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "psy/psysh", + "version": "v0.4.1", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "3787f3436f4fd898e0ac1eb6f5abd2ab6b24085b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/3787f3436f4fd898e0ac1eb6f5abd2ab6b24085b", + "reference": "3787f3436f4fd898e0ac1eb6f5abd2ab6b24085b", + "shasum": "" + }, + "require": { + "dnoegel/php-xdg-base-dir": "0.1", + "jakub-onderka/php-console-highlighter": "0.3.*", + "nikic/php-parser": "~1.0", + "php": ">=5.3.0", + "symfony/console": "~2.3.10|~2.4.2|~2.5" + }, + "require-dev": { + "fabpot/php-cs-fixer": "~1.3", + "phpunit/phpunit": "~3.7|~4.0", + "squizlabs/php_codesniffer": "~2.0", + "symfony/finder": "~2.1" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.3.x-dev" + } + }, + "autoload": { + "files": [ + "src/Psy/functions.php" + ], + "psr-0": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "time": "2015-02-25 20:35:54" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v5.3.1", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "c5f963e7f9d6f6438fda4f22d5cc2db296ec621a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/c5f963e7f9d6f6438fda4f22d5cc2db296ec621a", + "reference": "c5f963e7f9d6f6438fda4f22d5cc2db296ec621a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "mockery/mockery": "~0.9.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.3-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.org", + "keywords": [ + "mail", + "mailer" + ], + "time": "2014-12-05 14:17:14" + }, + { + "name": "symfony/class-loader", + "version": "v2.6.4", + "target-dir": "Symfony/Component/ClassLoader", + "source": { + "type": "git", + "url": "https://github.com/symfony/ClassLoader.git", + "reference": "deac802f76910708ab50d039806cfd1866895b52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/ClassLoader/zipball/deac802f76910708ab50d039806cfd1866895b52", + "reference": "deac802f76910708ab50d039806cfd1866895b52", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/finder": "~2.0,>=2.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\ClassLoader\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony ClassLoader Component", + "homepage": "http://symfony.com", + "time": "2015-01-05 14:28:40" + }, + { + "name": "symfony/console", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Console", + "source": { + "type": "git", + "url": "https://github.com/symfony/Console.git", + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Console/zipball/e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.1" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Console Component", + "homepage": "http://symfony.com", + "time": "2015-01-25 04:39:26" + }, + { + "name": "symfony/debug", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Debug", + "source": { + "type": "git", + "url": "https://github.com/symfony/Debug.git", + "reference": "150c80059c3ccf68f96a4fceb513eb6b41f23300" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Debug/zipball/150c80059c3ccf68f96a4fceb513eb6b41f23300", + "reference": "150c80059c3ccf68f96a4fceb513eb6b41f23300", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.2", + "symfony/http-foundation": "~2.1", + "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2" + }, + "suggest": { + "symfony/http-foundation": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Debug\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Debug Component", + "homepage": "http://symfony.com", + "time": "2015-01-21 20:57:55" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.6.4", + "target-dir": "Symfony/Component/EventDispatcher", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "f75989f3ab2743a82fe0b03ded2598a2b1546813" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/f75989f3ab2743a82fe0b03ded2598a2b1546813", + "reference": "f75989f3ab2743a82fe0b03ded2598a2b1546813", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "http://symfony.com", + "time": "2015-02-01 16:10:57" + }, + { + "name": "symfony/filesystem", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Filesystem", + "source": { + "type": "git", + "url": "https://github.com/symfony/Filesystem.git", + "reference": "a1f566d1f92e142fa1593f4555d6d89e3044a9b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/a1f566d1f92e142fa1593f4555d6d89e3044a9b7", + "reference": "a1f566d1f92e142fa1593f4555d6d89e3044a9b7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Filesystem\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 21:13:09" + }, + { + "name": "symfony/finder", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Finder", + "source": { + "type": "git", + "url": "https://github.com/symfony/Finder.git", + "reference": "16513333bca64186c01609961a2bb1b95b5e1355" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Finder/zipball/16513333bca64186c01609961a2bb1b95b5e1355", + "reference": "16513333bca64186c01609961a2bb1b95b5e1355", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Finder\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Finder Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 08:01:59" + }, + { + "name": "symfony/http-foundation", + "version": "v2.6.4", + "target-dir": "Symfony/Component/HttpFoundation", + "source": { + "type": "git", + "url": "https://github.com/symfony/HttpFoundation.git", + "reference": "8fa63d614d56ccfe033e30411d90913cfc483ff6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/8fa63d614d56ccfe033e30411d90913cfc483ff6", + "reference": "8fa63d614d56ccfe033e30411d90913cfc483ff6", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/expression-language": "~2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "classmap": [ + "Symfony/Component/HttpFoundation/Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "http://symfony.com", + "time": "2015-02-01 16:10:57" + }, + { + "name": "symfony/http-kernel", + "version": "v2.6.4", + "target-dir": "Symfony/Component/HttpKernel", + "source": { + "type": "git", + "url": "https://github.com/symfony/HttpKernel.git", + "reference": "27abf3106d8bd08562070dd4e2438c279792c434" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/27abf3106d8bd08562070dd4e2438c279792c434", + "reference": "27abf3106d8bd08562070dd4e2438c279792c434", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "psr/log": "~1.0", + "symfony/debug": "~2.6,>=2.6.2", + "symfony/event-dispatcher": "~2.5.9|~2.6,>=2.6.2", + "symfony/http-foundation": "~2.5,>=2.5.4" + }, + "require-dev": { + "symfony/browser-kit": "~2.3", + "symfony/class-loader": "~2.1", + "symfony/config": "~2.0,>=2.0.5", + "symfony/console": "~2.3", + "symfony/css-selector": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.2", + "symfony/dom-crawler": "~2.0,>=2.0.5", + "symfony/expression-language": "~2.4", + "symfony/finder": "~2.0,>=2.0.5", + "symfony/process": "~2.0,>=2.0.5", + "symfony/routing": "~2.2", + "symfony/stopwatch": "~2.3", + "symfony/templating": "~2.2", + "symfony/translation": "~2.0,>=2.0.5", + "symfony/var-dumper": "~2.6" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/class-loader": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "", + "symfony/finder": "", + "symfony/var-dumper": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\HttpKernel\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony HttpKernel Component", + "homepage": "http://symfony.com", + "time": "2015-02-02 18:02:30" + }, + { + "name": "symfony/process", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Process", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process.git", + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Process/zipball/ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Process\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Process Component", + "homepage": "http://symfony.com", + "time": "2015-01-25 04:39:26" + }, + { + "name": "symfony/routing", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Routing", + "source": { + "type": "git", + "url": "https://github.com/symfony/Routing.git", + "reference": "bda1c3c67f2a33bbeabb1d321feaf626a0ca5698" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Routing/zipball/bda1c3c67f2a33bbeabb1d321feaf626a0ca5698", + "reference": "bda1c3c67f2a33bbeabb1d321feaf626a0ca5698", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "doctrine/annotations": "~1.0", + "doctrine/common": "~2.2", + "psr/log": "~1.0", + "symfony/config": "~2.2", + "symfony/expression-language": "~2.4", + "symfony/http-foundation": "~2.3", + "symfony/yaml": "~2.0,>=2.0.5" + }, + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/yaml": "For using the YAML loader" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Routing\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Routing Component", + "homepage": "http://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "time": "2015-01-15 12:15:12" + }, + { + "name": "symfony/security-core", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Security/Core", + "source": { + "type": "git", + "url": "https://github.com/symfony/security-core.git", + "reference": "4603bcc66e20e23f018c67f7f9f3f8146a100c11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/security-core/zipball/4603bcc66e20e23f018c67f7f9f3f8146a100c11", + "reference": "4603bcc66e20e23f018c67f7f9f3f8146a100c11", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "ircmaxell/password-compat": "1.0.*", + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/expression-language": "~2.6", + "symfony/http-foundation": "~2.4", + "symfony/translation": "~2.0,>=2.0.5", + "symfony/validator": "~2.5,>=2.5.5" + }, + "suggest": { + "ircmaxell/password-compat": "For using the BCrypt password encoder in PHP <5.5", + "symfony/event-dispatcher": "", + "symfony/expression-language": "For using the expression voter", + "symfony/http-foundation": "", + "symfony/validator": "For using the user password constraint" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Security\\Core\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Security Component - Core Library", + "homepage": "http://symfony.com", + "time": "2015-01-25 04:39:26" + }, + { + "name": "symfony/translation", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Translation", + "source": { + "type": "git", + "url": "https://github.com/symfony/Translation.git", + "reference": "f289cdf8179d32058c1e1cbac723106a5ff6fa39" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Translation/zipball/f289cdf8179d32058c1e1cbac723106a5ff6fa39", + "reference": "f289cdf8179d32058c1e1cbac723106a5ff6fa39", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.3,>=2.3.12", + "symfony/intl": "~2.3", + "symfony/yaml": "~2.2" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Translation Component", + "homepage": "http://symfony.com", + "time": "2015-01-03 15:33:07" + }, + { + "name": "symfony/var-dumper", + "version": "v2.6.4", + "target-dir": "Symfony/Component/VarDumper", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "c3d5a36c3e3298bd8b070488fba5537174647353" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/c3d5a36c3e3298bd8b070488fba5537174647353", + "reference": "c3d5a36c3e3298bd8b070488fba5537174647353", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-symfony_debug": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-0": { + "Symfony\\Component\\VarDumper\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "http://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2015-02-02 16:32:08" + }, + { + "name": "twbs/bootstrap", + "version": "v3.3.2", + "source": { + "type": "git", + "url": "https://github.com/twbs/bootstrap.git", + "reference": "bcf7dd38b5ab180256e2e4fb5da0369551b3f082" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/bcf7dd38b5ab180256e2e4fb5da0369551b3f082", + "reference": "bcf7dd38b5ab180256e2e4fb5da0369551b3f082", + "shasum": "" + }, + "replace": { + "twitter/bootstrap": "self.version" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jacob Thornton", + "email": "jacobthornton@gmail.com" + }, + { + "name": "Mark Otto", + "email": "markdotto@gmail.com" + } + ], + "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", + "homepage": "http://getbootstrap.com", + "keywords": [ + "JS", + "css", + "framework", + "front-end", + "less", + "mobile-first", + "responsive", + "web" + ], + "time": "2015-01-19 17:03:09" + }, + { + "name": "vlucas/phpdotenv", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "732d2adb7d916c9593b9d58c3b0d9ebefead07aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/732d2adb7d916c9593b9d58c3b0d9ebefead07aa", + "reference": "732d2adb7d916c9593b9d58c3b0d9ebefead07aa", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Dotenv": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "authors": [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "homepage": "http://github.com/vlucas/phpdotenv", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "time": "2014-12-05 15:19:21" + }, + { + "name": "webpatser/laravel-countries", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/webpatser/laravel-countries.git", + "reference": "5714176d7acb008f4b6ac3a1ac9e139243c921fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webpatser/laravel-countries/zipball/5714176d7acb008f4b6ac3a1ac9e139243c921fc", + "reference": "5714176d7acb008f4b6ac3a1ac9e139243c921fc", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "laravel-library", + "autoload": { + "psr-0": { + "Webpatser\\Countries": "src/" + }, + "classmap": [ + "src/commands" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christoph Kempen", + "email": "christoph@downsized.nl", + "homepage": "http://downsized.nl/", + "role": "developer" + }, + { + "name": "Paul Kievits", + "role": "developer" + } + ], + "description": "Laravel Countries is a bundle for Laravel, providing Almost ISO 3166_2, 3166_3, currency, Capital and more for all countries.", + "homepage": "https://github.com/webpatser/laravel-countries", + "keywords": [ + "countries", + "iso_3166_2", + "iso_3166_3", + "laravel" + ], + "time": "2014-12-12 12:17:07" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "2.0.*@ALPHA" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Instantiator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2014-10-13 12:58:55" + }, + { + "name": "phpspec/php-diff", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/phpspec/php-diff.git", + "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/php-diff/zipball/30e103d19519fe678ae64a60d77884ef3d71b28a", + "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Diff": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Chris Boulton", + "homepage": "http://github.com/chrisboulton", + "role": "Original developer" + } + ], + "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", + "time": "2013-11-01 13:02:21" + }, + { + "name": "phpspec/phpspec", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/phpspec.git", + "reference": "66a1df93099282b1514e9e001fcf6e9393f7783d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/phpspec/zipball/66a1df93099282b1514e9e001fcf6e9393f7783d", + "reference": "66a1df93099282b1514e9e001fcf6e9393f7783d", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.1", + "php": ">=5.3.3", + "phpspec/php-diff": "~1.0.0", + "phpspec/prophecy": "~1.1", + "sebastian/exporter": "~1.0", + "symfony/console": "~2.3", + "symfony/event-dispatcher": "~2.1", + "symfony/finder": "~2.1", + "symfony/process": "~2.1", + "symfony/yaml": "~2.1" + }, + "require-dev": { + "behat/behat": "~3.0,>=3.0.11", + "bossa/phpspec2-expect": "~1.0", + "symfony/filesystem": "~2.1" + }, + "suggest": { + "phpspec/nyan-formatters": "~1.0 – Adds Nyan formatters" + }, + "bin": [ + "bin/phpspec" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "PhpSpec": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "homepage": "http://marcelloduarte.net/" + } + ], + "description": "Specification-oriented BDD framework for PHP 5.3+", + "homepage": "http://phpspec.net/", + "keywords": [ + "BDD", + "SpecBDD", + "TDD", + "spec", + "specification", + "testing", + "tests" + ], + "time": "2015-01-09 13:21:45" + }, + { + "name": "phpspec/prophecy", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "reference": "9ca52329bcdd1500de24427542577ebf3fc2f1c9", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.2", + "phpdocumentor/reflection-docblock": "~2.0" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "http://phpspec.org", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2014-11-17 16:23:49" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.0.15", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "34cc484af1ca149188d0d9e91412191e398e0b67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/34cc484af1ca149188d0d9e91412191e398e0b67", + "reference": "34cc484af1ca149188d0d9e91412191e398e0b67", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "~1.0", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-01-24 10:06:35" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2013-08-02 07:42:54" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/db32c18eba00b121c145575fcbcd4d4d24e6db74", + "reference": "db32c18eba00b121c145575fcbcd4d4d24e6db74", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-01-17 09:51:32" + }, + { + "name": "phpunit/phpunit", + "version": "4.5.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "5b578d3865a9128b9c209b011fda6539ec06e7a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5b578d3865a9128b9c209b011fda6539ec06e7a5", + "reference": "5b578d3865a9128b9c209b011fda6539ec06e7a5", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "~1.3.1", + "phpunit/php-code-coverage": "~2.0", + "phpunit/php-file-iterator": "~1.3.2", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0.2", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.1", + "sebastian/environment": "~1.2", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.5.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-02-05 15:51:19" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "c63d2367247365f688544f0d500af90a11a44c65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/c63d2367247365f688544f0d500af90a11a44c65", + "reference": "c63d2367247365f688544f0d500af90a11a44c65", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.1", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2014-10-03 05:12:11" + }, + { + "name": "sebastian/comparator", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-01-29 16:28:08" + }, + { + "name": "sebastian/diff", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/5843509fed39dee4b356a306401e9dd1a931fec7", + "reference": "5843509fed39dee4b356a306401e9dd1a931fec7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2014-08-15 10:29:00" + }, + { + "name": "sebastian/environment", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6e6c71d918088c251b181ba8b3088af4ac336dd7", + "reference": "6e6c71d918088c251b181ba8b3088af4ac336dd7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2014-10-25 08:00:45" + }, + { + "name": "sebastian/exporter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "84839970d05254c73cde183a721c7af13aede943" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-01-27 07:23:06" + }, + { + "name": "sebastian/global-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2014-10-06 09:23:50" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-01-24 09:48:32" + }, + { + "name": "sebastian/version", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/a77d9123f8e809db3fbdea15038c27a95da4058b", + "reference": "a77d9123f8e809db3fbdea15038c27a95da4058b", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2014-12-15 14:25:24" + }, + { + "name": "symfony/yaml", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/60ed7751671113cf1ee7d7778e691642c2e9acd8", + "reference": "60ed7751671113cf1ee7d7778e691642c2e9acd8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2015-01-25 04:39:26" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "anahkiasen/former": 20, + "chumper/datatable": 20, + "intervention/image": 20, + "webpatser/laravel-countries": 20, + "lokielse/omnipay-alipay": 20, + "alfaproject/omnipay-neteller": 20, + "alfaproject/omnipay-skrill": 20, + "calvinfroedge/php-payments": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/config/app.php b/config/app.php index aa6fe72399c7..fcd96369f830 100644 --- a/config/app.php +++ b/config/app.php @@ -171,7 +171,44 @@ return [ 'aliases' => [ - 'App' => 'Illuminate\Support\Facades\App', + 'App' => 'Illuminate\Support\Facades\App', + 'Artisan' => 'Illuminate\Support\Facades\Artisan', + 'Auth' => 'Illuminate\Support\Facades\Auth', + 'Blade' => 'Illuminate\Support\Facades\Blade', + 'Cache' => 'Illuminate\Support\Facades\Cache', + 'ClassLoader' => 'Illuminate\Support\ClassLoader', + 'Config' => 'Illuminate\Support\Facades\Config', + 'Controller' => 'Illuminate\Routing\Controller', + 'Cookie' => 'Illuminate\Support\Facades\Cookie', + 'Crypt' => 'Illuminate\Support\Facades\Crypt', + 'DB' => 'Illuminate\Support\Facades\DB', + 'Eloquent' => 'Illuminate\Database\Eloquent\Model', + 'Event' => 'Illuminate\Support\Facades\Event', + 'File' => 'Illuminate\Support\Facades\File', + //'Form' => 'Illuminate\Support\Facades\Form', + 'Hash' => 'Illuminate\Support\Facades\Hash', + 'HTML' => 'Illuminate\Support\Facades\HTML', + 'Input' => 'Illuminate\Support\Facades\Input', + 'Lang' => 'Illuminate\Support\Facades\Lang', + 'Log' => 'Illuminate\Support\Facades\Log', + 'Mail' => 'Illuminate\Support\Facades\Mail', + //'Paginator' => 'Illuminate\Support\Facades\Paginator', + 'Password' => 'Illuminate\Support\Facades\Password', + 'Queue' => 'Illuminate\Support\Facades\Queue', + 'Redirect' => 'Illuminate\Support\Facades\Redirect', + 'Redis' => 'Illuminate\Support\Facades\Redis', + 'Request' => 'Illuminate\Support\Facades\Request', + 'Response' => 'Illuminate\Support\Facades\Response', + 'Route' => 'Illuminate\Support\Facades\Route', + 'Schema' => 'Illuminate\Support\Facades\Schema', + 'Seeder' => 'Illuminate\Database\Seeder', + 'Session' => 'Illuminate\Support\Facades\Session', + 'Str' => 'Illuminate\Support\Str', + 'URL' => 'Illuminate\Support\Facades\URL', + 'Validator' => 'Illuminate\Support\Facades\Validator', + 'View' => 'Illuminate\Support\Facades\View', + + /*'App' => 'Illuminate\Support\Facades\App', 'Artisan' => 'Illuminate\Support\Facades\Artisan', 'Auth' => 'Illuminate\Support\Facades\Auth', 'Blade' => 'Illuminate\Support\Facades\Blade', @@ -202,7 +239,7 @@ return [ 'Storage' => 'Illuminate\Support\Facades\Storage', 'URL' => 'Illuminate\Support\Facades\URL', 'Validator' => 'Illuminate\Support\Facades\Validator', - 'View' => 'Illuminate\Support\Facades\View', + 'View' => 'Illuminate\Support\Facades\View',*/ // Added Class Aliases diff --git a/database/migrations/2013_11_05_180133_confide_setup_users_table.php b/database/migrations/2013_11_05_180133_confide_setup_users_table.php new file mode 100644 index 000000000000..cb2594770923 --- /dev/null +++ b/database/migrations/2013_11_05_180133_confide_setup_users_table.php @@ -0,0 +1,550 @@ +increments('id'); + $table->string('capital', 255)->nullable(); + $table->string('citizenship', 255)->nullable(); + $table->string('country_code', 3)->default(''); + $table->string('currency', 255)->nullable(); + $table->string('currency_code', 255)->nullable(); + $table->string('currency_sub_unit', 255)->nullable(); + $table->string('full_name', 255)->nullable(); + $table->string('iso_3166_2', 2)->default(''); + $table->string('iso_3166_3', 3)->default(''); + $table->string('name', 255)->default(''); + $table->string('region_code', 3)->default(''); + $table->string('sub_region_code', 3)->default(''); + $table->boolean('eea')->default(0); + }); + + Schema::create('themes', function($t) + { + $t->increments('id'); + $t->string('name'); + }); + + Schema::create('payment_types', function($t) + { + $t->increments('id'); + $t->string('name'); + }); + + Schema::create('payment_terms', function($t) + { + $t->increments('id'); + $t->integer('num_days'); + $t->string('name'); + }); + + Schema::create('timezones', function($t) + { + $t->increments('id'); + $t->string('name'); + $t->string('location'); + }); + + Schema::create('date_formats', function($t) + { + $t->increments('id'); + $t->string('format'); + $t->string('picker_format'); + $t->string('label'); + }); + + Schema::create('datetime_formats', function($t) + { + $t->increments('id'); + $t->string('format'); + $t->string('label'); + }); + + Schema::create('currencies', function($t) + { + $t->increments('id'); + + $t->string('name'); + $t->string('symbol'); + $t->string('precision'); + $t->string('thousand_separator'); + $t->string('decimal_separator'); + $t->string('code'); + }); + + Schema::create('sizes', function($t) + { + $t->increments('id'); + $t->string('name'); + }); + + Schema::create('industries', function($t) + { + $t->increments('id'); + $t->string('name'); + }); + + Schema::create('accounts', function($t) + { + $t->increments('id'); + $t->unsignedInteger('timezone_id')->nullable(); + $t->unsignedInteger('date_format_id')->nullable(); + $t->unsignedInteger('datetime_format_id')->nullable(); + $t->unsignedInteger('currency_id')->nullable(); + + $t->timestamps(); + $t->softDeletes(); + + $t->string('name')->nullable(); + $t->string('ip'); + $t->string('account_key')->unique(); + $t->timestamp('last_login')->nullable(); + + $t->string('address1')->nullable(); + $t->string('address2')->nullable(); + $t->string('city')->nullable(); + $t->string('state')->nullable(); + $t->string('postal_code')->nullable(); + $t->unsignedInteger('country_id')->nullable(); + $t->text('invoice_terms')->nullable(); + $t->text('email_footer')->nullable(); + $t->unsignedInteger('industry_id')->nullable(); + $t->unsignedInteger('size_id')->nullable(); + + $t->boolean('invoice_taxes')->default(true); + $t->boolean('invoice_item_taxes')->default(false); + + $t->foreign('timezone_id')->references('id')->on('timezones'); + $t->foreign('date_format_id')->references('id')->on('date_formats'); + $t->foreign('datetime_format_id')->references('id')->on('datetime_formats'); + $t->foreign('country_id')->references('id')->on('countries'); + $t->foreign('currency_id')->references('id')->on('currencies'); + $t->foreign('industry_id')->references('id')->on('industries'); + $t->foreign('size_id')->references('id')->on('sizes'); + }); + + Schema::create('gateways', function($t) + { + $t->increments('id'); + $t->timestamps(); + + $t->string('name'); + $t->string('provider'); + $t->boolean('visible')->default(true); + }); + + Schema::create('users', function($t) + { + $t->increments('id'); + $t->unsignedInteger('account_id')->index(); + $t->timestamps(); + $t->softDeletes(); + + $t->string('first_name')->nullable(); + $t->string('last_name')->nullable(); + $t->string('phone')->nullable(); + $t->string('username')->unique(); + $t->string('email')->nullable(); + $t->string('password'); + $t->string('confirmation_code'); + $t->boolean('registered')->default(false); + $t->boolean('confirmed')->default(false); + $t->integer('theme_id')->nullable(); + + $t->boolean('notify_sent')->default(true); + $t->boolean('notify_viewed')->default(false); + $t->boolean('notify_paid')->default(true); + + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + + $t->unsignedInteger('public_id')->nullable(); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('account_gateways', function($t) + { + $t->increments('id'); + $t->unsignedInteger('account_id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('gateway_id'); + $t->timestamps(); + $t->softDeletes(); + + $t->text('config'); + + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('gateway_id')->references('id')->on('gateways'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + $t->unsignedInteger('public_id')->index(); + $t->unique( array('account_id','public_id') ); + }); + + + Schema::create('password_reminders', function($t) + { + $t->string('email'); + $t->timestamps(); + + $t->string('token'); + }); + + Schema::create('clients', function($t) + { + $t->increments('id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('currency_id')->nullable(); + $t->timestamps(); + $t->softDeletes(); + + $t->string('name')->nullable(); + $t->string('address1')->nullable(); + $t->string('address2')->nullable(); + $t->string('city')->nullable(); + $t->string('state')->nullable(); + $t->string('postal_code')->nullable(); + $t->unsignedInteger('country_id')->nullable(); + $t->string('work_phone')->nullable(); + $t->text('private_notes')->nullable(); + $t->decimal('balance', 13, 2)->nullable(); + $t->decimal('paid_to_date', 13, 2)->nullable(); + $t->timestamp('last_login')->nullable(); + $t->string('website')->nullable(); + $t->unsignedInteger('industry_id')->nullable(); + $t->unsignedInteger('size_id')->nullable(); + $t->boolean('is_deleted')->default(false); + $t->integer('payment_terms')->nullable(); + + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $t->foreign('country_id')->references('id')->on('countries'); + $t->foreign('industry_id')->references('id')->on('industries'); + $t->foreign('size_id')->references('id')->on('sizes'); + $t->foreign('currency_id')->references('id')->on('currencies'); + + $t->unsignedInteger('public_id')->index(); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('contacts', function($t) + { + $t->increments('id'); + $t->unsignedInteger('account_id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('client_id')->index(); + $t->timestamps(); + $t->softDeletes(); + + $t->boolean('is_primary')->default(0); + $t->boolean('send_invoice')->default(0); + $t->string('first_name')->nullable(); + $t->string('last_name')->nullable(); + $t->string('email')->nullable(); + $t->string('phone')->nullable(); + $t->timestamp('last_login')->nullable(); + + $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');; + + $t->unsignedInteger('public_id')->nullable(); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('invoice_statuses', function($t) + { + $t->increments('id'); + $t->string('name'); + }); + + Schema::create('frequencies', function($t) + { + $t->increments('id'); + $t->string('name'); + }); + + Schema::create('invoices', function($t) + { + $t->increments('id'); + $t->unsignedInteger('client_id')->index(); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('invoice_status_id')->default(1); + $t->timestamps(); + $t->softDeletes(); + + $t->string('invoice_number'); + $t->float('discount'); + $t->string('po_number'); + $t->date('invoice_date')->nullable(); + $t->date('due_date')->nullable(); + $t->text('terms'); + $t->text('public_notes'); + $t->boolean('is_deleted')->default(false); + $t->boolean('is_recurring'); + $t->unsignedInteger('frequency_id'); + $t->date('start_date')->nullable(); + $t->date('end_date')->nullable(); + $t->timestamp('last_sent_date')->nullable(); + $t->unsignedInteger('recurring_invoice_id')->index()->nullable(); + + $t->string('tax_name'); + $t->decimal('tax_rate', 13, 2); + + $t->decimal('amount', 13, 2); + $t->decimal('balance', 13, 2); + + $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $t->foreign('invoice_status_id')->references('id')->on('invoice_statuses'); + $t->foreign('recurring_invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + + $t->unsignedInteger('public_id')->index(); + $t->unique( array('account_id','public_id') ); + $t->unique( array('account_id','invoice_number') ); + }); + + + Schema::create('invitations', function($t) + { + $t->increments('id'); + $t->unsignedInteger('account_id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('contact_id'); + $t->unsignedInteger('invoice_id')->index(); + $t->string('invitation_key')->index()->unique(); + $t->timestamps(); + $t->softDeletes(); + + $t->string('transaction_reference')->nullable(); + $t->timestamp('sent_date'); + $t->timestamp('viewed_date'); + + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');; + $t->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + $t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + + $t->unsignedInteger('public_id')->index(); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('tax_rates', function($t) + { + $t->increments('id'); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('user_id'); + $t->timestamps(); + $t->softDeletes(); + + $t->string('name'); + $t->decimal('rate', 13, 2); + + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');; + + $t->unsignedInteger('public_id'); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('products', function($t) + { + $t->increments('id'); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('user_id'); + $t->timestamps(); + $t->softDeletes(); + + $t->string('product_key'); + $t->text('notes'); + $t->decimal('cost', 13, 2); + $t->decimal('qty', 13, 2)->nullable(); + + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');; + + $t->unsignedInteger('public_id'); + $t->unique( array('account_id','public_id') ); + }); + + + Schema::create('invoice_items', function($t) + { + $t->increments('id'); + $t->unsignedInteger('account_id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('invoice_id')->index(); + $t->unsignedInteger('product_id')->nullable(); + $t->timestamps(); + $t->softDeletes(); + + $t->string('product_key'); + $t->text('notes'); + $t->decimal('cost', 13, 2); + $t->decimal('qty', 13, 2)->nullable(); + + $t->string('tax_name')->nullable(); + $t->decimal('tax_rate', 13, 2)->nullable(); + + $t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + $t->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');; + + $t->unsignedInteger('public_id'); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('payments', function($t) + { + $t->increments('id'); + $t->unsignedInteger('invoice_id')->nullable(); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('client_id')->index(); + $t->unsignedInteger('contact_id')->nullable(); + $t->unsignedInteger('invitation_id')->nullable(); + $t->unsignedInteger('user_id')->nullable(); + $t->unsignedInteger('account_gateway_id')->nullable(); + $t->unsignedInteger('payment_type_id')->nullable(); + $t->timestamps(); + $t->softDeletes(); + + $t->boolean('is_deleted')->default(false); + $t->decimal('amount', 13, 2); + $t->date('payment_date')->nullable(); + $t->string('transaction_reference')->nullable(); + $t->string('payer_id')->nullable(); + + $t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + $t->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + $t->foreign('account_gateway_id')->references('id')->on('account_gateways')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');; + $t->foreign('payment_type_id')->references('id')->on('payment_types'); + + $t->unsignedInteger('public_id')->index(); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('credits', function($t) + { + $t->increments('id'); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('client_id')->index(); + $t->unsignedInteger('user_id'); + $t->timestamps(); + $t->softDeletes(); + + $t->boolean('is_deleted')->default(false); + $t->decimal('amount', 13, 2); + $t->decimal('balance', 13, 2); + $t->date('credit_date')->nullable(); + $t->string('credit_number')->nullable(); + $t->text('private_notes'); + + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');; + + $t->unsignedInteger('public_id')->index(); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('activities', function($t) + { + $t->increments('id'); + $t->timestamps(); + + $t->unsignedInteger('account_id'); + $t->unsignedInteger('client_id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('contact_id')->nullable(); + $t->unsignedInteger('payment_id')->nullable(); + $t->unsignedInteger('invoice_id')->nullable(); + $t->unsignedInteger('credit_id')->nullable(); + $t->unsignedInteger('invitation_id')->nullable(); + + $t->text('message')->nullable(); + $t->text('json_backup')->nullable(); + $t->integer('activity_type_id'); + $t->decimal('adjustment', 13, 2)->nullable(); + $t->decimal('balance', 13, 2)->nullable(); + + $t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('payment_terms'); + Schema::dropIfExists('themes'); + Schema::dropIfExists('credits'); + Schema::dropIfExists('activities'); + Schema::dropIfExists('invitations'); + Schema::dropIfExists('payments'); + Schema::dropIfExists('account_gateways'); + Schema::dropIfExists('invoice_items'); + Schema::dropIfExists('products'); + Schema::dropIfExists('tax_rates'); + Schema::dropIfExists('contacts'); + Schema::dropIfExists('invoices'); + Schema::dropIfExists('password_reminders'); + Schema::dropIfExists('clients'); + Schema::dropIfExists('users'); + Schema::dropIfExists('accounts'); + Schema::dropIfExists('currencies'); + Schema::dropIfExists('invoice_statuses'); + Schema::dropIfExists('countries'); + Schema::dropIfExists('timezones'); + Schema::dropIfExists('frequencies'); + Schema::dropIfExists('date_formats'); + Schema::dropIfExists('datetime_formats'); + Schema::dropIfExists('sizes'); + Schema::dropIfExists('industries'); + Schema::dropIfExists('gateways'); + Schema::dropIfExists('payment_types'); + } +} diff --git a/database/migrations/2013_11_28_195703_setup_countries_table.php b/database/migrations/2013_11_28_195703_setup_countries_table.php new file mode 100644 index 000000000000..09e8c8eca2e0 --- /dev/null +++ b/database/migrations/2013_11_28_195703_setup_countries_table.php @@ -0,0 +1,47 @@ +integer('id')->index(); + $table->string('capital', 255)->nullable(); + $table->string('citizenship', 255)->nullable(); + $table->string('country_code', 3)->default(''); + $table->string('currency', 255)->nullable(); + $table->string('currency_code', 255)->nullable(); + $table->string('currency_sub_unit', 255)->nullable(); + $table->string('full_name', 255)->nullable(); + $table->string('iso_3166_2', 2)->default(''); + $table->string('iso_3166_3', 3)->default(''); + $table->string('name', 255)->default(''); + $table->string('region_code', 3)->default(''); + $table->string('sub_region_code', 3)->default(''); + $table->boolean('eea')->default(0); + + $table->primary('id'); + }); + */ + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + //Schema::drop('countries'); + } + +} \ No newline at end of file diff --git a/database/migrations/2014_02_13_151500_add_cascase_drops.php b/database/migrations/2014_02_13_151500_add_cascase_drops.php new file mode 100644 index 000000000000..66d362317dfd --- /dev/null +++ b/database/migrations/2014_02_13_151500_add_cascase_drops.php @@ -0,0 +1,32 @@ +dropForeign('invoices_account_id_foreign'); + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + } + +} diff --git a/database/migrations/2014_02_19_151817_add_support_for_invoice_designs.php b/database/migrations/2014_02_19_151817_add_support_for_invoice_designs.php new file mode 100644 index 000000000000..4bd8daf912df --- /dev/null +++ b/database/migrations/2014_02_19_151817_add_support_for_invoice_designs.php @@ -0,0 +1,72 @@ +increments('id'); + $table->string('name'); + }); + + DB::table('invoice_designs')->insert(['name' => 'Clean']); + DB::table('invoice_designs')->insert(['name' => 'Bold']); + DB::table('invoice_designs')->insert(['name' => 'Modern']); + DB::table('invoice_designs')->insert(['name' => 'Plain']); + + Schema::table('invoices', function($table) + { + $table->unsignedInteger('invoice_design_id')->default(1); + }); + + Schema::table('accounts', function($table) + { + $table->unsignedInteger('invoice_design_id')->default(1); + }); + + DB::table('invoices')->update(['invoice_design_id' => 1]); + DB::table('accounts')->update(['invoice_design_id' => 1]); + + Schema::table('invoices', function($table) + { + $table->foreign('invoice_design_id')->references('id')->on('invoice_designs'); + }); + + Schema::table('accounts', function($table) + { + $table->foreign('invoice_design_id')->references('id')->on('invoice_designs'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('invoices', function($table) + { + $table->dropForeign('invoices_invoice_design_id_foreign'); + $table->dropColumn('invoice_design_id'); + }); + + Schema::table('accounts', function($table) + { + $table->dropForeign('accounts_invoice_design_id_foreign'); + $table->dropColumn('invoice_design_id'); + }); + + Schema::dropIfExists('invoice_designs'); + } + +} diff --git a/database/migrations/2014_03_03_155556_add_phone_to_account.php b/database/migrations/2014_03_03_155556_add_phone_to_account.php new file mode 100644 index 000000000000..79e03e9d183a --- /dev/null +++ b/database/migrations/2014_03_03_155556_add_phone_to_account.php @@ -0,0 +1,36 @@ +string('work_phone')->nullable(); + $table->string('work_email')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('work_phone'); + $table->dropColumn('work_email'); + }); + } + +} \ No newline at end of file diff --git a/database/migrations/2014_03_19_201454_add_language_support.php b/database/migrations/2014_03_19_201454_add_language_support.php new file mode 100644 index 000000000000..cdb092a9a498 --- /dev/null +++ b/database/migrations/2014_03_19_201454_add_language_support.php @@ -0,0 +1,60 @@ +increments('id'); + $table->string('name'); + $table->string('locale'); + }); + + DB::table('languages')->insert(['name' => 'English', 'locale' => 'en']); + DB::table('languages')->insert(['name' => 'Italian', 'locale' => 'it']); + DB::table('languages')->insert(['name' => 'German', 'locale' => 'de']); + DB::table('languages')->insert(['name' => 'French', 'locale' => 'fr']); + DB::table('languages')->insert(['name' => 'Brazilian Portuguese', 'locale' => 'pt_BR']); + DB::table('languages')->insert(['name' => 'Dutch', 'locale' => 'nl']); + DB::table('languages')->insert(['name' => 'Spanish', 'locale' => 'es']); + DB::table('languages')->insert(['name' => 'Norwegian', 'locale' => 'nb_NO']); + + Schema::table('accounts', function($table) + { + $table->unsignedInteger('language_id')->default(1); + }); + + DB::table('accounts')->update(['language_id' => 1]); + + Schema::table('accounts', function($table) + { + $table->foreign('language_id')->references('id')->on('languages'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropForeign('accounts_language_id_foreign'); + $table->dropColumn('language_id'); + }); + + Schema::drop('languages'); + } + +} diff --git a/database/migrations/2014_03_20_200300_create_payment_libraries.php b/database/migrations/2014_03_20_200300_create_payment_libraries.php new file mode 100644 index 000000000000..dc8074c913bd --- /dev/null +++ b/database/migrations/2014_03_20_200300_create_payment_libraries.php @@ -0,0 +1,58 @@ +increments('id'); + $t->timestamps(); + + $t->string('name'); + $t->boolean('visible')->default(true); + }); + + Schema::table('gateways', function($table) + { + $table->unsignedInteger('payment_library_id')->default(1); + }); + + DB::table('gateways')->update(['payment_library_id' => 1]); + + Schema::table('gateways', function($table) + { + $table->foreign('payment_library_id')->references('id')->on('payment_libraries')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + if (Schema::hasColumn('gateways', 'payment_library_id')) + { + Schema::table('gateways', function($table) + { + $table->dropForeign('gateways_payment_library_id_foreign'); + $table->dropColumn('payment_library_id'); + }); + } + + Schema::dropIfExists('payment_libraries'); + } + +} \ No newline at end of file diff --git a/database/migrations/2014_03_23_051736_enable_forcing_jspdf.php b/database/migrations/2014_03_23_051736_enable_forcing_jspdf.php new file mode 100644 index 000000000000..30d7c664e451 --- /dev/null +++ b/database/migrations/2014_03_23_051736_enable_forcing_jspdf.php @@ -0,0 +1,34 @@ +boolean('force_pdfjs')->default(false); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function($table) + { + $table->dropColumn('force_pdfjs'); + }); + } + +} diff --git a/database/migrations/2014_03_25_102200_add_sort_and_recommended_to_gateways.php b/database/migrations/2014_03_25_102200_add_sort_and_recommended_to_gateways.php new file mode 100644 index 000000000000..a49fe8f855ef --- /dev/null +++ b/database/migrations/2014_03_25_102200_add_sort_and_recommended_to_gateways.php @@ -0,0 +1,49 @@ +unsignedInteger('sort_order')->default(10000); + $table->boolean('recommended')->default(0); + $table->string('site_url', 200)->nullable(); + }); + } + + public function down() + { + if (Schema::hasColumn('gateways', 'sort_order')) + { + Schema::table('gateways', function($table) + { + $table->dropColumn('sort_order'); + }); + } + + if (Schema::hasColumn('gateways', 'recommended')) + { + Schema::table('gateways', function($table) + { + $table->dropColumn('recommended'); + }); + } + + if (Schema::hasColumn('gateways', 'site_url')) + { + Schema::table('gateways', function($table) + { + $table->dropColumn('site_url'); + }); + } + } +} diff --git a/database/migrations/2014_04_03_191105_add_pro_plan.php b/database/migrations/2014_04_03_191105_add_pro_plan.php new file mode 100644 index 000000000000..cbc714971f1d --- /dev/null +++ b/database/migrations/2014_04_03_191105_add_pro_plan.php @@ -0,0 +1,34 @@ +date('pro_plan_paid')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('pro_plan_paid'); + }); + } + +} diff --git a/database/migrations/2014_04_17_100523_add_remember_token.php b/database/migrations/2014_04_17_100523_add_remember_token.php new file mode 100644 index 000000000000..6a436001075a --- /dev/null +++ b/database/migrations/2014_04_17_100523_add_remember_token.php @@ -0,0 +1,34 @@ +string('remember_token', 100)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function($table) + { + $table->dropColumn('remember_token'); + }); + } + +} diff --git a/database/migrations/2014_04_17_145108_add_custom_fields.php b/database/migrations/2014_04_17_145108_add_custom_fields.php new file mode 100644 index 000000000000..f6ff7c8f45a1 --- /dev/null +++ b/database/migrations/2014_04_17_145108_add_custom_fields.php @@ -0,0 +1,60 @@ +string('custom_label1')->nullable(); + $table->string('custom_value1')->nullable(); + + $table->string('custom_label2')->nullable(); + $table->string('custom_value2')->nullable(); + + $table->string('custom_client_label1')->nullable(); + $table->string('custom_client_label2')->nullable(); + }); + + Schema::table('clients', function($table) + { + $table->string('custom_value1')->nullable(); + $table->string('custom_value2')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('custom_label1'); + $table->dropColumn('custom_value1'); + + $table->dropColumn('custom_label2'); + $table->dropColumn('custom_value2'); + + $table->dropColumn('custom_client_label1'); + $table->dropColumn('custom_client_label2'); + }); + + Schema::table('clients', function($table) + { + $table->dropColumn('custom_value1'); + $table->dropColumn('custom_value2'); + }); + } + +} diff --git a/database/migrations/2014_04_23_170909_add_products_settings.php b/database/migrations/2014_04_23_170909_add_products_settings.php new file mode 100644 index 000000000000..a5e5541177b5 --- /dev/null +++ b/database/migrations/2014_04_23_170909_add_products_settings.php @@ -0,0 +1,39 @@ +boolean('fill_products')->default(true); + $table->boolean('update_products')->default(true); + }); + + DB::table('accounts')->update(['fill_products' => true]); + DB::table('accounts')->update(['update_products' => true]); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('fill_products'); + $table->dropColumn('update_products'); + }); + } + +} diff --git a/database/migrations/2014_04_29_174315_add_advanced_settings.php b/database/migrations/2014_04_29_174315_add_advanced_settings.php new file mode 100644 index 000000000000..ae91740d21f3 --- /dev/null +++ b/database/migrations/2014_04_29_174315_add_advanced_settings.php @@ -0,0 +1,42 @@ +string('primary_color')->nullable(); + $table->string('secondary_color')->nullable(); + }); + + Schema::table('payments', function($table) + { + $table->dropForeign('payments_invoice_id_foreign'); + $table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('primary_color'); + $table->dropColumn('secondary_color'); + }); + } + +} diff --git a/database/migrations/2014_05_17_175626_add_quotes.php b/database/migrations/2014_05_17_175626_add_quotes.php new file mode 100644 index 000000000000..6299ad124dc0 --- /dev/null +++ b/database/migrations/2014_05_17_175626_add_quotes.php @@ -0,0 +1,38 @@ +boolean('is_quote')->default(0); + $table->unsignedInteger('quote_id')->nullable(); + $table->unsignedInteger('quote_invoice_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('invoices', function($table) + { + $table->dropColumn('is_quote'); + $table->dropColumn('quote_id'); + $table->dropColumn('quote_invoice_id'); + }); + } + +} diff --git a/database/migrations/2014_06_17_131940_add_accepted_credit_cards_to_account_gateways.php b/database/migrations/2014_06_17_131940_add_accepted_credit_cards_to_account_gateways.php new file mode 100644 index 000000000000..dfcbdc90559a --- /dev/null +++ b/database/migrations/2014_06_17_131940_add_accepted_credit_cards_to_account_gateways.php @@ -0,0 +1,34 @@ +unsignedInteger('accepted_credit_cards')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('account_gateways', function($table) + { + $table->dropColumn('accepted_credit_cards'); + }); + } + +} diff --git a/database/migrations/2014_07_13_142654_one_click_install.php b/database/migrations/2014_07_13_142654_one_click_install.php new file mode 100644 index 000000000000..943117bed3a7 --- /dev/null +++ b/database/migrations/2014_07_13_142654_one_click_install.php @@ -0,0 +1,58 @@ +increments('id'); + $table->timestamps(); + $table->softDeletes(); + + $table->string('name'); + $table->string('affiliate_key')->unique(); + + $table->text('payment_title'); + $table->text('payment_subtitle'); + }); + + Schema::create('licenses', function($table) + { + $table->increments('id'); + $table->timestamps(); + $table->softDeletes(); + $table->unsignedInteger('affiliate_id'); + + $table->string('first_name'); + $table->string('last_name'); + $table->string('email'); + + $table->string('license_key')->unique(); + $table->boolean('is_claimed'); + $table->string('transaction_reference'); + + $table->foreign('affiliate_id')->references('id')->on('affiliates'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('licenses'); + Schema::dropIfExists('affiliates'); + } + +} diff --git a/database/migrations/2014_07_17_205900_support_hiding_quantity.php b/database/migrations/2014_07_17_205900_support_hiding_quantity.php new file mode 100644 index 000000000000..c7104ef88c8d --- /dev/null +++ b/database/migrations/2014_07_17_205900_support_hiding_quantity.php @@ -0,0 +1,66 @@ +boolean('hide_quantity')->default(0); + $table->boolean('hide_paid_to_date')->default(0); + + $table->string('custom_invoice_label1')->nullable(); + $table->string('custom_invoice_label2')->nullable(); + + $table->boolean('custom_invoice_taxes1')->nullable(); + $table->boolean('custom_invoice_taxes2')->nullable(); + }); + + Schema::table('invoices', function($table) + { + $table->decimal('custom_value1', 13, 2)->default(0); + $table->decimal('custom_value2', 13, 2)->default(0); + + $table->boolean('custom_taxes1')->default(0); + $table->boolean('custom_taxes2')->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('hide_quantity'); + $table->dropColumn('hide_paid_to_date'); + + $table->dropColumn('custom_invoice_label1'); + $table->dropColumn('custom_invoice_label2'); + + $table->dropColumn('custom_invoice_taxes1'); + $table->dropColumn('custom_invoice_taxes2'); + }); + + Schema::table('invoices', function($table) + { + $table->dropColumn('custom_value1'); + $table->dropColumn('custom_value2'); + + $table->dropColumn('custom_taxes1'); + $table->dropColumn('custom_taxes2'); + }); + } + +} diff --git a/database/migrations/2014_07_24_171214_add_zapier_support.php b/database/migrations/2014_07_24_171214_add_zapier_support.php new file mode 100644 index 000000000000..b7bfc0a5bae3 --- /dev/null +++ b/database/migrations/2014_07_24_171214_add_zapier_support.php @@ -0,0 +1,42 @@ +increments('id'); + $table->unsignedInteger('account_id')->nullable(); + + $table->timestamps(); + $table->softDeletes(); + + $table->unsignedInteger('event_id')->nullable(); + $table->string('target_url'); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->unique( ['account_id', 'event_id'] ); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('subscriptions'); + } + +} diff --git a/database/migrations/2014_10_01_141248_add_company_vat_number.php b/database/migrations/2014_10_01_141248_add_company_vat_number.php new file mode 100644 index 000000000000..b93a217712ed --- /dev/null +++ b/database/migrations/2014_10_01_141248_add_company_vat_number.php @@ -0,0 +1,43 @@ +string('vat_number')->nullable(); + }); + + Schema::table('clients', function($table) + { + $table->string('vat_number')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('vat_number'); + }); + Schema::table('clients', function($table) + { + $table->dropColumn('vat_number'); + }); + } + +} diff --git a/database/migrations/2014_10_05_141856_track_last_seen_message.php b/database/migrations/2014_10_05_141856_track_last_seen_message.php new file mode 100644 index 000000000000..7446782a6ac3 --- /dev/null +++ b/database/migrations/2014_10_05_141856_track_last_seen_message.php @@ -0,0 +1,46 @@ +unsignedInteger('news_feed_id')->nullable(); + }); + + if (DB::table('payment_libraries')->count() > 0) { + DB::table('gateways')->update(['recommended' => 0]); + DB::table('gateways')->insert([ + 'name' => 'moolah', + 'provider' => 'AuthorizeNet_AIM', + 'sort_order' => 1, + 'recommended' => 1, + 'site_url' => 'https://invoiceninja.mymoolah.com/', + 'payment_library_id' => 1 + ]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function($table) + { + $table->dropColumn('news_feed_id'); + }); + } + +} diff --git a/database/migrations/2014_10_06_103529_add_timesheets.php b/database/migrations/2014_10_06_103529_add_timesheets.php new file mode 100644 index 000000000000..879cd450402d --- /dev/null +++ b/database/migrations/2014_10_06_103529_add_timesheets.php @@ -0,0 +1,152 @@ +increments('id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('client_id')->nullable(); + $t->timestamps(); + $t->softDeletes(); + + $t->string('name'); + $t->string('description'); + + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $t->foreign('account_id')->references('id')->on('accounts'); + + $t->unique( array('account_id','name') ); + }); + + Schema::create('project_codes', function($t) { + $t->increments('id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('project_id'); + $t->timestamps(); + $t->softDeletes(); + + $t->string('name'); + $t->string('description'); + + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $t->foreign('account_id')->references('id')->on('accounts'); + $t->foreign('project_id')->references('id')->on('projects')->onDelete('cascade'); + + $t->unique( array('account_id','name') ); + }); + + + Schema::create('timesheets', function($t) { + $t->increments('id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('account_id')->index(); + $t->timestamps(); + $t->softDeletes(); + + $t->dateTime('start_date'); + $t->dateTime('end_date'); + $t->float('discount'); + + $t->decimal('hours'); + + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $t->foreign('account_id')->references('id')->on('accounts'); + + $t->unsignedInteger('public_id'); + $t->unique( array('account_id','public_id') ); + }); + + Schema::create('timesheet_event_sources', function($t) { + $t->increments('id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('account_id')->index(); + $t->timestamps(); + $t->softDeletes(); + + $t->string('owner'); + $t->string('name'); + $t->string('url'); + $t->enum('type', array('ical', 'googlejson')); + + $t->dateTime('from_date')->nullable(); + $t->dateTime('to_date')->nullable(); + + $t->foreign('account_id')->references('id')->on('accounts'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + }); + + Schema::create('timesheet_events', function($t) { + $t->increments('id'); + $t->unsignedInteger('user_id'); + $t->unsignedInteger('account_id')->index(); + $t->unsignedInteger('timesheet_event_source_id'); + $t->unsignedInteger('timesheet_id')->nullable()->index(); + $t->unsignedInteger('project_id')->nullable()->index(); + $t->unsignedInteger('project_code_id')->nullable()->index(); + $t->timestamps(); + $t->softDeletes(); + + // Basic fields + $t->string('uid'); + $t->string('summary'); + $t->text('description'); + $t->string('location'); + $t->string('owner'); + $t->dateTime('start_date'); + $t->dateTime('end_date'); + + # Calculated values + $t->decimal('hours'); + $t->float('discount'); + $t->boolean('manualedit'); + + // Original data + $t->string('org_code'); + $t->timeStamp('org_created_at'); + $t->timeStamp('org_updated_at'); + $t->timeStamp('org_deleted_at')->default('0000-00-00T00:00:00'); + $t->string('org_start_date_timezone')->nullable(); + $t->string('org_end_date_timezone')->nullable(); + $t->text('org_data'); + + // Error and merge handling + $t->string('import_error')->nullable(); + $t->string('import_warning')->nullable(); + $t->text('updated_data')->nullable(); + $t->timeStamp('updated_data_at')->default('0000-00-00T00:00:00'); + + $t->foreign('account_id')->references('id')->on('accounts'); + $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $t->foreign('timesheet_event_source_id')->references('id')->on('timesheet_event_sources')->onDelete('cascade'); + + $t->unique( array('timesheet_event_source_id', 'uid') ); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('timesheet_events'); + Schema::drop('timesheet_event_sources'); + Schema::drop('timesheets'); + Schema::drop('project_codes'); + Schema::drop('projects'); + } + +} diff --git a/database/migrations/2014_10_06_195330_add_invoice_design_table.php b/database/migrations/2014_10_06_195330_add_invoice_design_table.php new file mode 100644 index 000000000000..81442b001b3f --- /dev/null +++ b/database/migrations/2014_10_06_195330_add_invoice_design_table.php @@ -0,0 +1,519 @@ +text('javascript')->nullable(); + }); + + Schema::table('accounts', function($table) + { + $table->text('invoice_design')->nullable(); + }); + + DB::table('invoice_designs')->where('id', 1)->update([ + 'javascript' => "var GlobalY=0;//Y position of line at current page + + var client = invoice.client; + var account = invoice.account; + var currencyId = client.currency_id; + + layout.headerRight = 550; + layout.rowHeight = 15; + + doc.setFontSize(9); + + if (invoice.image) + { + var left = layout.headerRight - invoice.imageWidth; + doc.addImage(invoice.image, 'JPEG', layout.marginLeft, 30); + } + + if (!invoice.is_pro && logoImages.imageLogo1) + { + pageHeight=820; + y=pageHeight-logoImages.imageLogoHeight1; + doc.addImage(logoImages.imageLogo1, 'JPEG', layout.marginLeft, y, logoImages.imageLogoWidth1, logoImages.imageLogoHeight1); + } + + doc.setFontSize(9); + SetPdfColor('LightBlue', doc, 'primary'); + displayAccount(doc, invoice, 220, layout.accountTop, layout); + + SetPdfColor('LightBlue', doc, 'primary'); + doc.setFontSize('11'); + doc.text(50, layout.headerTop, (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase()); + + + SetPdfColor('Black',doc); //set black color + doc.setFontSize(9); + + var invoiceHeight = displayInvoice(doc, invoice, 50, 170, layout); + var clientHeight = displayClient(doc, invoice, 220, 170, layout); + var detailsHeight = Math.max(invoiceHeight, clientHeight); + layout.tableTop = Math.max(layout.tableTop, layout.headerTop + detailsHeight + (3 * layout.rowHeight)); + + doc.setLineWidth(0.3); + doc.setDrawColor(200,200,200); + doc.line(layout.marginLeft - layout.tablePadding, layout.headerTop + 6, layout.marginRight + layout.tablePadding, layout.headerTop + 6); + doc.line(layout.marginLeft - layout.tablePadding, layout.headerTop + detailsHeight + 14, layout.marginRight + layout.tablePadding, layout.headerTop + detailsHeight + 14); + + doc.setFontSize(10); + doc.setFontType('bold'); + displayInvoiceHeader(doc, invoice, layout); + var y = displayInvoiceItems(doc, invoice, layout); + + doc.setFontSize(9); + doc.setFontType('bold'); + + GlobalY=GlobalY+25; + + + doc.setLineWidth(0.3); + doc.setDrawColor(241,241,241); + doc.setFillColor(241,241,241); + var x1 = layout.marginLeft - 12; + var y1 = GlobalY-layout.tablePadding; + + var w2 = 510 + 24; + var h2 = doc.internal.getFontSize()*3+layout.tablePadding*2; + + if (invoice.discount) { + h2 += doc.internal.getFontSize()*2; + } + if (invoice.tax_amount) { + h2 += doc.internal.getFontSize()*2; + } + + //doc.rect(x1, y1, w2, h2, 'FD'); + + doc.setFontSize(9); + displayNotesAndTerms(doc, layout, invoice, y); + y += displaySubtotals(doc, layout, invoice, y, layout.unitCostRight); + + + doc.setFontSize(10); + Msg = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due; + var TmpMsgX = layout.unitCostRight-(doc.getStringUnitWidth(Msg) * doc.internal.getFontSize()); + + doc.text(TmpMsgX, y, Msg); + + SetPdfColor('LightBlue', doc, 'primary'); + AmountText = formatMoney(invoice.balance_amount, currencyId); + headerLeft=layout.headerRight+400; + var AmountX = layout.lineTotalRight - (doc.getStringUnitWidth(AmountText) * doc.internal.getFontSize()); + doc.text(AmountX, y, AmountText);" + ]); + + DB::table('invoice_designs')->where('id', 2)->update([ + 'javascript' => " var GlobalY=0;//Y position of line at current page + + var client = invoice.client; + var account = invoice.account; + var currencyId = client.currency_id; + + layout.headerRight = 150; + layout.rowHeight = 15; + layout.headerTop = 125; + layout.tableTop = 300; + + doc.setLineWidth(0.5); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setFillColor(46,43,43); + } + + var x1 =0; + var y1 = 0; + var w2 = 595; + var h2 = 100; + doc.rect(x1, y1, w2, h2, 'FD'); + + if (invoice.image) + { + var left = layout.headerRight - invoice.imageWidth; + doc.addImage(invoice.image, 'JPEG', layout.marginLeft, 30); + } + + doc.setLineWidth(0.5); + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setFillColor(46,43,43); + doc.setDrawColor(46,43,43); + } + + // return doc.setTextColor(240,240,240);//select color Custom Report GRAY Colour + var x1 = 0;//tableLeft-tablePadding ; + var y1 = 750; + var w2 = 596; + var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; + + doc.rect(x1, y1, w2, h2, 'FD'); + if (!invoice.is_pro && logoImages.imageLogo2) + { + pageHeight=820; + var left = 250;//headerRight ; + y=pageHeight-logoImages.imageLogoHeight2; + var headerRight=370; + + var left = headerRight - logoImages.imageLogoWidth2; + doc.addImage(logoImages.imageLogo2, 'JPEG', left, y, logoImages.imageLogoWidth2, logoImages.imageLogoHeight2); + } + + doc.setFontSize(7); + doc.setFontType('bold'); + SetPdfColor('White',doc); + + displayAccount(doc, invoice, 300, layout.accountTop, layout); + + + var y = layout.accountTop; + var left = layout.marginLeft; + var headerY = layout.headerTop; + + SetPdfColor('GrayLogo',doc); //set black color + doc.setFontSize(7); + + //show left column + SetPdfColor('Black',doc); //set black color + doc.setFontType('normal'); + + //publish filled box + doc.setDrawColor(200,200,200); + + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + } else { + doc.setFillColor(54,164,152); + } + + GlobalY=190; + doc.setLineWidth(0.5); + + var BlockLenght=220; + var x1 =595-BlockLenght; + var y1 = GlobalY-12; + var w2 = BlockLenght; + var h2 = getInvoiceDetailsHeight(invoice, layout) + layout.tablePadding + 2; + + doc.rect(x1, y1, w2, h2, 'FD'); + + SetPdfColor('SomeGreen', doc, 'secondary'); + doc.setFontSize('14'); + doc.setFontType('bold'); + doc.text(50, GlobalY, (invoice.is_quote ? invoiceLabels.your_quote : invoiceLabels.your_invoice).toUpperCase()); + + + var z=GlobalY; + z=z+30; + + doc.setFontSize('8'); + SetPdfColor('Black',doc); + var clientHeight = displayClient(doc, invoice, layout.marginLeft, z, layout); + layout.tableTop += Math.max(0, clientHeight - 75); + marginLeft2=395; + + //publish left side information + SetPdfColor('White',doc); + doc.setFontSize('8'); + var detailsHeight = displayInvoice(doc, invoice, marginLeft2, z-25, layout) + 75; + layout.tableTop = Math.max(layout.tableTop, layout.headerTop + detailsHeight + (2 * layout.tablePadding)); + + y=z+60; + x = GlobalY + 100; + doc.setFontType('bold'); + + doc.setFontSize(12); + doc.setFontType('bold'); + SetPdfColor('Black',doc); + displayInvoiceHeader(doc, invoice, layout); + + var y = displayInvoiceItems(doc, invoice, layout); + doc.setLineWidth(0.3); + displayNotesAndTerms(doc, layout, invoice, y); + y += displaySubtotals(doc, layout, invoice, y, layout.unitCostRight); + + doc.setFontType('bold'); + + doc.setFontSize(12); + x += doc.internal.getFontSize()*4; + Msg = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due; + var TmpMsgX = layout.unitCostRight-(doc.getStringUnitWidth(Msg) * doc.internal.getFontSize()); + + doc.text(TmpMsgX, y, Msg); + + //SetPdfColor('LightBlue',doc); + AmountText = formatMoney(invoice.balance_amount , currencyId); + headerLeft=layout.headerRight+400; + var AmountX = headerLeft - (doc.getStringUnitWidth(AmountText) * doc.internal.getFontSize()); + SetPdfColor('SomeGreen', doc, 'secondary'); + doc.text(AmountX, y, AmountText);" + ]); + + DB::table('invoice_designs')->where('id', 3)->update([ + 'javascript' => " var client = invoice.client; + var account = invoice.account; + var currencyId = client.currency_id; + + layout.headerRight = 400; + layout.rowHeight = 15; + + + doc.setFontSize(7); + + // add header + doc.setLineWidth(0.5); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setDrawColor(242,101,34); + doc.setFillColor(242,101,34); + } + + var x1 =0; + var y1 = 0; + var w2 = 595; + var h2 = Math.max(110, getInvoiceDetailsHeight(invoice, layout) + 30); + doc.rect(x1, y1, w2, h2, 'FD'); + + SetPdfColor('White',doc); + + //second column + doc.setFontType('bold'); + var name = invoice.account.name; + if (name) { + doc.setFontSize('30'); + doc.setFontType('bold'); + doc.text(40, 50, name); + } + + if (invoice.image) + { + y=130; + var left = layout.headerRight - invoice.imageWidth; + doc.addImage(invoice.image, 'JPEG', layout.marginLeft, y); + } + + // add footer + doc.setLineWidth(0.5); + + if (NINJA.primaryColor) { + setDocHexFill(doc, NINJA.primaryColor); + setDocHexDraw(doc, NINJA.primaryColor); + } else { + doc.setDrawColor(242,101,34); + doc.setFillColor(242,101,34); + } + + var x1 = 0;//tableLeft-tablePadding ; + var y1 = 750; + var w2 = 596; + var h2 = 94;//doc.internal.getFontSize()*length+length*1.1;//+h;//+tablePadding; + + doc.rect(x1, y1, w2, h2, 'FD'); + + if (!invoice.is_pro && logoImages.imageLogo3) + { + pageHeight=820; + // var left = 25;//250;//headerRight ; + y=pageHeight-logoImages.imageLogoHeight3; + //var headerRight=370; + + //var left = headerRight - invoice.imageLogoWidth3; + doc.addImage(logoImages.imageLogo3, 'JPEG', 40, y, logoImages.imageLogoWidth3, logoImages.imageLogoHeight3); + } + + doc.setFontSize(10); + var marginLeft = 340; + displayAccount(doc, invoice, marginLeft, 780, layout); + + + SetPdfColor('White',doc); + doc.setFontSize('8'); + var detailsHeight = displayInvoice(doc, invoice, layout.headerRight, layout.accountTop-10, layout); + layout.headerTop = Math.max(layout.headerTop, detailsHeight + 50); + layout.tableTop = Math.max(layout.tableTop, detailsHeight + 150); + + SetPdfColor('Black',doc); //set black color + doc.setFontSize(7); + doc.setFontType('normal'); + displayClient(doc, invoice, layout.headerRight, layout.headerTop, layout); + + + + SetPdfColor('White',doc); + doc.setFontType('bold'); + + doc.setLineWidth(0.3); + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + setDocHexDraw(doc, NINJA.secondaryColor); + } else { + doc.setDrawColor(63,60,60); + doc.setFillColor(63,60,60); + } + + var left = layout.marginLeft - layout.tablePadding; + var top = layout.tableTop - layout.tablePadding; + var width = layout.marginRight - (2 * layout.tablePadding); + var height = 20; + doc.rect(left, top, width, height, 'FD'); + + + displayInvoiceHeader(doc, invoice, layout); + SetPdfColor('Black',doc); + var y = displayInvoiceItems(doc, invoice, layout); + + + var height1 = displayNotesAndTerms(doc, layout, invoice, y); + var height2 = displaySubtotals(doc, layout, invoice, y, layout.unitCostRight); + y += Math.max(height1, height2); + + + var left = layout.marginLeft - layout.tablePadding; + var top = y - layout.tablePadding; + var width = layout.marginRight - (2 * layout.tablePadding); + var height = 20; + if (NINJA.secondaryColor) { + setDocHexFill(doc, NINJA.secondaryColor); + setDocHexDraw(doc, NINJA.secondaryColor); + } else { + doc.setDrawColor(63,60,60); + doc.setFillColor(63,60,60); + } + doc.rect(left, top, width, height, 'FD'); + + doc.setFontType('bold'); + SetPdfColor('White', doc); + doc.setFontSize(12); + + var label = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due; + var labelX = layout.unitCostRight-(doc.getStringUnitWidth(label) * doc.internal.getFontSize()); + doc.text(labelX, y+2, label); + + + doc.setFontType('normal'); + var amount = formatMoney(invoice.balance_amount , currencyId); + headerLeft=layout.headerRight+400; + var amountX = layout.lineTotalRight - (doc.getStringUnitWidth(amount) * doc.internal.getFontSize()); + doc.text(amountX, y+2, amount);" + ]); + + DB::table('invoice_designs')->where('id', 4)->update([ + 'javascript' => " var client = invoice.client; + var account = invoice.account; + var currencyId = client.currency_id; + + layout.accountTop += 25; + layout.headerTop += 25; + layout.tableTop += 25; + + if (invoice.image) + { + var left = layout.headerRight - invoice.imageWidth; + doc.addImage(invoice.image, 'JPEG', left, 50); + } + + /* table header */ + doc.setDrawColor(200,200,200); + doc.setFillColor(230,230,230); + + var detailsHeight = getInvoiceDetailsHeight(invoice, layout); + var left = layout.headerLeft - layout.tablePadding; + var top = layout.headerTop + detailsHeight - layout.rowHeight - layout.tablePadding; + var width = layout.headerRight - layout.headerLeft + (2 * layout.tablePadding); + var height = layout.rowHeight + 1; + doc.rect(left, top, width, height, 'FD'); + + doc.setFontSize(10); + doc.setFontType('normal'); + + displayAccount(doc, invoice, layout.marginLeft, layout.accountTop, layout); + displayClient(doc, invoice, layout.marginLeft, layout.headerTop, layout); + + displayInvoice(doc, invoice, layout.headerLeft, layout.headerTop, layout, layout.headerRight); + layout.tableTop = Math.max(layout.tableTop, layout.headerTop + detailsHeight + (2 * layout.tablePadding)); + + var headerY = layout.headerTop; + var total = 0; + + doc.setDrawColor(200,200,200); + doc.setFillColor(230,230,230); + var left = layout.marginLeft - layout.tablePadding; + var top = layout.tableTop - layout.tablePadding; + var width = layout.headerRight - layout.marginLeft + (2 * layout.tablePadding); + var height = layout.rowHeight + 2; + doc.rect(left, top, width, height, 'FD'); + + displayInvoiceHeader(doc, invoice, layout); + var y = displayInvoiceItems(doc, invoice, layout); + + doc.setFontSize(10); + + displayNotesAndTerms(doc, layout, invoice, y+20); + + y += displaySubtotals(doc, layout, invoice, y+20, 480) + 20; + + doc.setDrawColor(200,200,200); + doc.setFillColor(230,230,230); + + var left = layout.footerLeft - layout.tablePadding; + var top = y - layout.tablePadding; + var width = layout.headerRight - layout.footerLeft + (2 * layout.tablePadding); + var height = layout.rowHeight + 2; + doc.rect(left, top, width, height, 'FD'); + + doc.setFontType('bold'); + doc.text(layout.footerLeft, y, invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due); + + total = formatMoney(invoice.balance_amount, currencyId); + var totalX = layout.headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize()); + doc.text(totalX, y, total); + + if (!invoice.is_pro) { + doc.setFontType('normal'); + doc.text(layout.marginLeft, 790, 'Created by InvoiceNinja.com'); + }" + + ]); + + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('invoice_designs', function($table) + { + $table->dropColumn('javascript'); + }); + + Schema::table('accounts', function($table) + { + $table->dropColumn('invoice_design'); + }); + } + +} diff --git a/database/migrations/2014_10_13_054100_add_invoice_number_settings.php b/database/migrations/2014_10_13_054100_add_invoice_number_settings.php new file mode 100644 index 000000000000..377e9e013fa3 --- /dev/null +++ b/database/migrations/2014_10_13_054100_add_invoice_number_settings.php @@ -0,0 +1,63 @@ +text('invoice_number_prefix')->nullable(); + $table->integer('invoice_number_counter')->default(1)->nullable(); + + $table->text('quote_number_prefix')->nullable(); + $table->integer('quote_number_counter')->default(1)->nullable(); + + $table->boolean('share_counter')->default(true); + }); + + // set initial counter value for accounts with invoices + $accounts = DB::table('accounts')->lists('id'); + + foreach ($accounts as $accountId) { + + $invoiceNumbers = DB::table('invoices')->where('account_id', $accountId)->lists('invoice_number'); + $max = 0; + + foreach ($invoiceNumbers as $invoiceNumber) { + $number = intval(preg_replace('/[^0-9]/', '', $invoiceNumber)); + $max = max($max, $number); + } + + DB::table('accounts')->where('id', $accountId)->update(['invoice_number_counter' => ++$max]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('invoice_number_prefix'); + $table->dropColumn('invoice_number_counter'); + + $table->dropColumn('quote_number_prefix'); + $table->dropColumn('quote_number_counter'); + + $table->dropColumn('share_counter'); + }); + + } + +} diff --git a/database/migrations/2014_10_14_225227_add_danish_translation.php b/database/migrations/2014_10_14_225227_add_danish_translation.php new file mode 100644 index 000000000000..b7f8b42d5b42 --- /dev/null +++ b/database/migrations/2014_10_14_225227_add_danish_translation.php @@ -0,0 +1,29 @@ +insert(['name' => 'Danish', 'locale' => 'da']); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $language = Language::whereLocale('da')->first(); + $language->delete(); + } + +} diff --git a/database/migrations/2014_10_22_174452_add_affiliate_price.php b/database/migrations/2014_10_22_174452_add_affiliate_price.php new file mode 100644 index 000000000000..305ad1f42135 --- /dev/null +++ b/database/migrations/2014_10_22_174452_add_affiliate_price.php @@ -0,0 +1,44 @@ +decimal('price', 7, 2)->nullable(); + }); + + Schema::table('licenses', function($table) + { + $table->unsignedInteger('product_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('affiliates', function($table) + { + $table->dropColumn('price'); + }); + + Schema::table('licenses', function($table) + { + $table->dropColumn('product_id'); + }); + } + +} diff --git a/database/migrations/2014_10_30_184126_add_company_id_number.php b/database/migrations/2014_10_30_184126_add_company_id_number.php new file mode 100644 index 000000000000..9e0fcb75b494 --- /dev/null +++ b/database/migrations/2014_10_30_184126_add_company_id_number.php @@ -0,0 +1,43 @@ +string('id_number')->nullable(); + }); + + Schema::table('clients', function($table) + { + $table->string('id_number')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('id_number'); + }); + Schema::table('clients', function($table) + { + $table->dropColumn('id_number'); + }); + } + +} diff --git a/database/migrations/2014_11_04_200406_allow_null_client_currency.php b/database/migrations/2014_11_04_200406_allow_null_client_currency.php new file mode 100644 index 000000000000..8007e8cb65c4 --- /dev/null +++ b/database/migrations/2014_11_04_200406_allow_null_client_currency.php @@ -0,0 +1,31 @@ +boolean('is_amount_discount')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('invoices', function($table) + { + $table->dropColumn('is_amount_discount'); + }); + } + +} diff --git a/database/migrations/2015_02_12_102940_add_email_templates.php b/database/migrations/2015_02_12_102940_add_email_templates.php new file mode 100644 index 000000000000..756466a79113 --- /dev/null +++ b/database/migrations/2015_02_12_102940_add_email_templates.php @@ -0,0 +1,38 @@ +text('email_template_invoice')->nullable(); + $table->text('email_template_quote')->nullable(); + $table->text('email_template_payment')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('email_template_invoice'); + $table->dropColumn('email_template_quote'); + $table->dropColumn('email_template_payment'); + }); + } + +} diff --git a/database/migrations/2015_02_17_131714_support_token_billing.php b/database/migrations/2015_02_17_131714_support_token_billing.php new file mode 100644 index 000000000000..0022d44cf2ef --- /dev/null +++ b/database/migrations/2015_02_17_131714_support_token_billing.php @@ -0,0 +1,56 @@ +smallInteger('token_billing_type_id')->default(TOKEN_BILLING_OPT_IN); + }); + + Schema::create('account_gateway_tokens', function($table) + { + $table->increments('id'); + $table->unsignedInteger('account_id'); + $table->unsignedInteger('contact_id'); + $table->unsignedInteger('account_gateway_id'); + $table->unsignedInteger('client_id'); + $table->string('token'); + + $table->timestamps(); + $table->softDeletes(); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + $table->foreign('account_gateway_id')->references('id')->on('account_gateways')->onDelete('cascade'); + $table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + }); + + DB::table('accounts')->update(['token_billing_type_id' => TOKEN_BILLING_OPT_IN]); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('token_billing_type_id'); + }); + + Schema::drop('account_gateway_tokens'); + } + +} \ No newline at end of file diff --git a/database/migrations/2015_02_27_081836_add_invoice_footer.php b/database/migrations/2015_02_27_081836_add_invoice_footer.php new file mode 100644 index 000000000000..6d1cfb7a9efa --- /dev/null +++ b/database/migrations/2015_02_27_081836_add_invoice_footer.php @@ -0,0 +1,44 @@ +text('invoice_footer')->nullable(); + }); + + Schema::table('invoices', function($table) + { + $table->text('invoice_footer')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('invoice_footer'); + }); + + Schema::table('invoices', function($table) + { + $table->dropColumn('invoice_footer'); + }); + } + +} diff --git a/database/migrations/2015_03_03_140259_add_tokens.php b/database/migrations/2015_03_03_140259_add_tokens.php new file mode 100644 index 000000000000..45b54e3ca4f8 --- /dev/null +++ b/database/migrations/2015_03_03_140259_add_tokens.php @@ -0,0 +1,54 @@ +increments('id'); + $table->unsignedInteger('account_id')->index(); + $table->unsignedInteger('user_id'); + $table->timestamps(); + $table->softDeletes(); + + $table->string('name')->nullable(); + $table->string('token')->unique(); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + $table->unsignedInteger('public_id')->nullable(); + $table->unique(['account_id', 'public_id']); + }); + + Schema::table('activities', function($table) + { + $table->unsignedInteger('token_id')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('account_tokens'); + + Schema::table('activities', function($table) + { + $table->dropColumn('token_id'); + }); + } + +} diff --git a/database/migrations/2015_03_09_151011_add_ip_to_activity.php b/database/migrations/2015_03_09_151011_add_ip_to_activity.php new file mode 100644 index 000000000000..552f75dfa808 --- /dev/null +++ b/database/migrations/2015_03_09_151011_add_ip_to_activity.php @@ -0,0 +1,34 @@ +string('ip')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('activities', function($table) + { + $table->dropColumn('ip'); + }); + } + +} diff --git a/database/seeds/ConstantsSeeder.php b/database/seeds/ConstantsSeeder.php new file mode 100644 index 000000000000..53e3a26cf6d8 --- /dev/null +++ b/database/seeds/ConstantsSeeder.php @@ -0,0 +1,327 @@ +first_name = 'Hillel'; + $contact->last_name = 'Hillel'; + $contact->email = 'hillelcoren@gmail.com'; + $contact->last_name = '2125551234'; + $client->contacts()->save($contact); + + $invoice = new Invoice; + $invoice->invoice_number = '0001'; + $client->invoices()->save($invoice); + + $invoice = new Invoice; + $invoice->invoice_number = '0002'; + $client->invoices()->save($invoice); + + $invoice = new Invoice; + $invoice->invoice_number = '0003'; + $client->invoices()->save($invoice); + + $invoice = new Invoice; + $invoice->invoice_number = '0004'; + $client->invoices()->save($invoice); + */ + + PaymentType::create(array('name' => 'Apply Credit')); + PaymentType::create(array('name' => 'Bank Transfer')); + PaymentType::create(array('name' => 'Cash')); + PaymentType::create(array('name' => 'Debit')); + PaymentType::create(array('name' => 'ACH')); + PaymentType::create(array('name' => 'Visa Card')); + PaymentType::create(array('name' => 'MasterCard')); + PaymentType::create(array('name' => 'American Express')); + PaymentType::create(array('name' => 'Discover Card')); + PaymentType::create(array('name' => 'Diners Card')); + PaymentType::create(array('name' => 'EuroCard')); + PaymentType::create(array('name' => 'Nova')); + PaymentType::create(array('name' => 'Credit Card Other')); + PaymentType::create(array('name' => 'PayPal')); + PaymentType::create(array('name' => 'Google Wallet')); + PaymentType::create(array('name' => 'Check')); + + Theme::create(array('name' => 'amelia')); + Theme::create(array('name' => 'cerulean')); + Theme::create(array('name' => 'cosmo')); + Theme::create(array('name' => 'cyborg')); + Theme::create(array('name' => 'flatly')); + Theme::create(array('name' => 'journal')); + Theme::create(array('name' => 'readable')); + Theme::create(array('name' => 'simplex')); + Theme::create(array('name' => 'slate')); + Theme::create(array('name' => 'spacelab')); + Theme::create(array('name' => 'united')); + Theme::create(array('name' => 'yeti')); + + InvoiceStatus::create(array('name' => 'Draft')); + InvoiceStatus::create(array('name' => 'Sent')); + InvoiceStatus::create(array('name' => 'Viewed')); + InvoiceStatus::create(array('name' => 'Partial')); + InvoiceStatus::create(array('name' => 'Paid')); + + Frequency::create(array('name' => 'Weekly')); + Frequency::create(array('name' => 'Two weeks')); + Frequency::create(array('name' => 'Four weeks')); + Frequency::create(array('name' => 'Monthly')); + Frequency::create(array('name' => 'Three months')); + Frequency::create(array('name' => 'Six months')); + Frequency::create(array('name' => 'Annually')); + + Industry::create(array('name' => 'Accounting & Legal')); + Industry::create(array('name' => 'Advertising')); + Industry::create(array('name' => 'Aerospace')); + Industry::create(array('name' => 'Agriculture')); + Industry::create(array('name' => 'Automotive')); + Industry::create(array('name' => 'Banking & Finance')); + Industry::create(array('name' => 'Biotechnology')); + Industry::create(array('name' => 'Broadcasting')); + Industry::create(array('name' => 'Business Services')); + Industry::create(array('name' => 'Commodities & Chemicals')); + Industry::create(array('name' => 'Communications')); + Industry::create(array('name' => 'Computers & Hightech')); + Industry::create(array('name' => 'Defense')); + Industry::create(array('name' => 'Energy')); + Industry::create(array('name' => 'Entertainment')); + Industry::create(array('name' => 'Government')); + Industry::create(array('name' => 'Healthcare & Life Sciences')); + Industry::create(array('name' => 'Insurance')); + Industry::create(array('name' => 'Manufacturing')); + Industry::create(array('name' => 'Marketing')); + Industry::create(array('name' => 'Media')); + Industry::create(array('name' => 'Nonprofit & Higher Ed')); + Industry::create(array('name' => 'Pharmaceuticals')); + Industry::create(array('name' => 'Professional Services & Consulting')); + Industry::create(array('name' => 'Real Estate')); + Industry::create(array('name' => 'Retail & Wholesale')); + Industry::create(array('name' => 'Sports')); + Industry::create(array('name' => 'Transportation')); + Industry::create(array('name' => 'Travel & Luxury')); + Industry::create(array('name' => 'Other')); + Industry::create(array('name' => 'Photography')); + + Size::create(array('name' => '1 - 3')); + Size::create(array('name' => '4 - 10')); + Size::create(array('name' => '11 - 50')); + Size::create(array('name' => '51 - 100')); + Size::create(array('name' => '101 - 500')); + Size::create(array('name' => '500+')); + + PaymentTerm::create(array('num_days' => 7, 'name' => 'Net 7')); + PaymentTerm::create(array('num_days' => 10, 'name' => 'Net 10')); + PaymentTerm::create(array('num_days' => 14, 'name' => 'Net 14')); + PaymentTerm::create(array('num_days' => 15, 'name' => 'Net 15')); + PaymentTerm::create(array('num_days' => 30, 'name' => 'Net 30')); + PaymentTerm::create(array('num_days' => 60, 'name' => 'Net 60')); + PaymentTerm::create(array('num_days' => 90, 'name' => 'Net 90')); + + Currency::create(array('name' => 'US Dollar', 'code' => 'USD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Pound Sterling', 'code' => 'GBP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Euro', 'code' => 'EUR', 'symbol' => '€', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Rand', 'code' => 'ZAR', 'symbol' => 'R', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Danish Krone', 'code' => 'DKK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Israeli Shekel', 'code' => 'ILS', 'symbol' => 'NIS ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Swedish Krona', 'code' => 'SEK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Kenyan Shilling', 'code' => 'KES', 'symbol' => 'KSh ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Canadian Dollar', 'code' => 'CAD', 'symbol' => 'C$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Philippine Peso', 'code' => 'PHP', 'symbol' => 'P ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Indian Rupee', 'code' => 'INR', 'symbol' => 'Rs. ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Australian Dollar', 'code' => 'AUD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Singapore Dollar', 'code' => 'SGD', 'symbol' => 'SGD ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Norske Kroner', 'code' => 'NOK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'New Zealand Dollar', 'code' => 'NZD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Vietnamese Dong', 'code' => 'VND', 'symbol' => 'VND ', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.')); + Currency::create(array('name' => 'Swiss Franc', 'code' => 'CHF', 'symbol' => 'CHF ', 'precision' => '2', 'thousand_separator' => '\'', 'decimal_separator' => '.')); + + + DatetimeFormat::create(array('format' => 'd/M/Y g:i a', 'label' => '10/Mar/2013')); + DatetimeFormat::create(array('format' => 'd-M-Yk g:i a', 'label' => '10-Mar-2013')); + DatetimeFormat::create(array('format' => 'd/F/Y g:i a', 'label' => '10/March/2013')); + DatetimeFormat::create(array('format' => 'd-F-Y g:i a', 'label' => '10-March-2013')); + DatetimeFormat::create(array('format' => 'M j, Y g:i a', 'label' => 'Mar 10, 2013 6:15 pm')); + DatetimeFormat::create(array('format' => 'F j, Y g:i a', 'label' => 'March 10, 2013 6:15 pm')); + DatetimeFormat::create(array('format' => 'D M jS, Y g:ia', 'label' => 'Mon March 10th, 2013 6:15 pm')); + + DateFormat::create(array('format' => 'd/M/Y', 'picker_format' => 'dd/M/yyyy', 'label' => '10/Mar/2013')); + DateFormat::create(array('format' => 'd-M-Y', 'picker_format' => 'dd-M-yyyy', 'label' => '10-Mar-2013')); + DateFormat::create(array('format' => 'd/F/Y', 'picker_format' => 'dd/MM/yyyy', 'label' => '10/March/2013')); + DateFormat::create(array('format' => 'd-F-Y', 'picker_format' => 'dd-MM-yyyy', 'label' => '10-March-2013')); + DateFormat::create(array('format' => 'M j, Y', 'picker_format' => 'M d, yyyy', 'label' => 'Mar 10, 2013')); + DateFormat::create(array('format' => 'F j, Y', 'picker_format' => 'MM d, yyyy', 'label' => 'March 10, 2013')); + DateFormat::create(array('format' => 'D M j, Y', 'picker_format' => 'D MM d, yyyy', 'label' => 'Mon March 10, 2013')); + + PaymentLibrary::create(['name' => 'Omnipay']); + PaymentLibrary::create(['name' => 'PHP-Payments']); + + /* + d, dd: Numeric date, no leading zero and leading zero, respectively. Eg, 5, 05. + D, DD: Abbreviated and full weekday names, respectively. Eg, Mon, Monday. + m, mm: Numeric month, no leading zero and leading zero, respectively. Eg, 7, 07. + M, MM: Abbreviated and full month names, respectively. Eg, Jan, January + yy, yyyy: 2- and 4-digit years, respectively. Eg, 12, 2012.) + */ + + $gateways = [ + array('name'=>'Authorize.Net AIM', 'provider'=>'AuthorizeNet_AIM'), + array('name'=>'Authorize.Net SIM', 'provider'=>'AuthorizeNet_SIM'), + array('name'=>'CardSave', 'provider'=>'CardSave'), + array('name'=>'Eway Rapid', 'provider'=>'Eway_Rapid'), + array('name'=>'FirstData Connect', 'provider'=>'FirstData_Connect'), + array('name'=>'GoCardless', 'provider'=>'GoCardless'), + array('name'=>'Migs ThreeParty', 'provider'=>'Migs_ThreeParty'), + array('name'=>'Migs TwoParty', 'provider'=>'Migs_TwoParty'), + array('name'=>'Mollie', 'provider'=>'Mollie'), + array('name'=>'MultiSafepay', 'provider'=>'MultiSafepay'), + array('name'=>'Netaxept', 'provider'=>'Netaxept'), + array('name'=>'NetBanx', 'provider'=>'NetBanx'), + array('name'=>'PayFast', 'provider'=>'PayFast'), + array('name'=>'Payflow Pro', 'provider'=>'Payflow_Pro'), + array('name'=>'PaymentExpress PxPay', 'provider'=>'PaymentExpress_PxPay'), + array('name'=>'PaymentExpress PxPost', 'provider'=>'PaymentExpress_PxPost'), + array('name'=>'PayPal Express', 'provider'=>'PayPal_Express'), + array('name'=>'PayPal Pro', 'provider'=>'PayPal_Pro'), + array('name'=>'Pin', 'provider'=>'Pin'), + array('name'=>'SagePay Direct', 'provider'=>'SagePay_Direct'), + array('name'=>'SagePay Server', 'provider'=>'SagePay_Server'), + array('name'=>'SecurePay DirectPost', 'provider'=>'SecurePay_DirectPost'), + array('name'=>'Stripe', 'provider'=>'Stripe'), + array('name'=>'TargetPay Direct eBanking', 'provider'=>'TargetPay_Directebanking'), + array('name'=>'TargetPay Ideal', 'provider'=>'TargetPay_Ideal'), + array('name'=>'TargetPay Mr Cash', 'provider'=>'TargetPay_Mrcash'), + array('name'=>'TwoCheckout', 'provider'=>'TwoCheckout'), + array('name'=>'WorldPay', 'provider'=>'WorldPay'), + ]; + + foreach ($gateways as $gateway) + { + Gateway::create($gateway); + } + + $timezones = array( + 'Pacific/Midway' => "(GMT-11:00) Midway Island", + 'US/Samoa' => "(GMT-11:00) Samoa", + 'US/Hawaii' => "(GMT-10:00) Hawaii", + 'US/Alaska' => "(GMT-09:00) Alaska", + 'US/Pacific' => "(GMT-08:00) Pacific Time (US & Canada)", + 'America/Tijuana' => "(GMT-08:00) Tijuana", + 'US/Arizona' => "(GMT-07:00) Arizona", + 'US/Mountain' => "(GMT-07:00) Mountain Time (US & Canada)", + 'America/Chihuahua' => "(GMT-07:00) Chihuahua", + 'America/Mazatlan' => "(GMT-07:00) Mazatlan", + 'America/Mexico_City' => "(GMT-06:00) Mexico City", + 'America/Monterrey' => "(GMT-06:00) Monterrey", + 'Canada/Saskatchewan' => "(GMT-06:00) Saskatchewan", + 'US/Central' => "(GMT-06:00) Central Time (US & Canada)", + 'US/Eastern' => "(GMT-05:00) Eastern Time (US & Canada)", + 'US/East-Indiana' => "(GMT-05:00) Indiana (East)", + 'America/Bogota' => "(GMT-05:00) Bogota", + 'America/Lima' => "(GMT-05:00) Lima", + 'America/Caracas' => "(GMT-04:30) Caracas", + 'Canada/Atlantic' => "(GMT-04:00) Atlantic Time (Canada)", + 'America/La_Paz' => "(GMT-04:00) La Paz", + 'America/Santiago' => "(GMT-04:00) Santiago", + 'Canada/Newfoundland' => "(GMT-03:30) Newfoundland", + 'America/Buenos_Aires' => "(GMT-03:00) Buenos Aires", + 'Greenland' => "(GMT-03:00) Greenland", + 'Atlantic/Stanley' => "(GMT-02:00) Stanley", + 'Atlantic/Azores' => "(GMT-01:00) Azores", + 'Atlantic/Cape_Verde' => "(GMT-01:00) Cape Verde Is.", + 'Africa/Casablanca' => "(GMT) Casablanca", + 'Europe/Dublin' => "(GMT) Dublin", + 'Europe/Lisbon' => "(GMT) Lisbon", + 'Europe/London' => "(GMT) London", + 'Africa/Monrovia' => "(GMT) Monrovia", + 'Europe/Amsterdam' => "(GMT+01:00) Amsterdam", + 'Europe/Belgrade' => "(GMT+01:00) Belgrade", + 'Europe/Berlin' => "(GMT+01:00) Berlin", + 'Europe/Bratislava' => "(GMT+01:00) Bratislava", + 'Europe/Brussels' => "(GMT+01:00) Brussels", + 'Europe/Budapest' => "(GMT+01:00) Budapest", + 'Europe/Copenhagen' => "(GMT+01:00) Copenhagen", + 'Europe/Ljubljana' => "(GMT+01:00) Ljubljana", + 'Europe/Madrid' => "(GMT+01:00) Madrid", + 'Europe/Paris' => "(GMT+01:00) Paris", + 'Europe/Prague' => "(GMT+01:00) Prague", + 'Europe/Rome' => "(GMT+01:00) Rome", + 'Europe/Sarajevo' => "(GMT+01:00) Sarajevo", + 'Europe/Skopje' => "(GMT+01:00) Skopje", + 'Europe/Stockholm' => "(GMT+01:00) Stockholm", + 'Europe/Vienna' => "(GMT+01:00) Vienna", + 'Europe/Warsaw' => "(GMT+01:00) Warsaw", + 'Europe/Zagreb' => "(GMT+01:00) Zagreb", + 'Europe/Athens' => "(GMT+02:00) Athens", + 'Europe/Bucharest' => "(GMT+02:00) Bucharest", + 'Africa/Cairo' => "(GMT+02:00) Cairo", + 'Africa/Harare' => "(GMT+02:00) Harare", + 'Europe/Helsinki' => "(GMT+02:00) Helsinki", + 'Europe/Istanbul' => "(GMT+02:00) Istanbul", + 'Asia/Jerusalem' => "(GMT+02:00) Jerusalem", + 'Europe/Kiev' => "(GMT+02:00) Kyiv", + 'Europe/Minsk' => "(GMT+02:00) Minsk", + 'Europe/Riga' => "(GMT+02:00) Riga", + 'Europe/Sofia' => "(GMT+02:00) Sofia", + 'Europe/Tallinn' => "(GMT+02:00) Tallinn", + 'Europe/Vilnius' => "(GMT+02:00) Vilnius", + 'Asia/Baghdad' => "(GMT+03:00) Baghdad", + 'Asia/Kuwait' => "(GMT+03:00) Kuwait", + 'Africa/Nairobi' => "(GMT+03:00) Nairobi", + 'Asia/Riyadh' => "(GMT+03:00) Riyadh", + 'Asia/Tehran' => "(GMT+03:30) Tehran", + 'Europe/Moscow' => "(GMT+04:00) Moscow", + 'Asia/Baku' => "(GMT+04:00) Baku", + 'Europe/Volgograd' => "(GMT+04:00) Volgograd", + 'Asia/Muscat' => "(GMT+04:00) Muscat", + 'Asia/Tbilisi' => "(GMT+04:00) Tbilisi", + 'Asia/Yerevan' => "(GMT+04:00) Yerevan", + 'Asia/Kabul' => "(GMT+04:30) Kabul", + 'Asia/Karachi' => "(GMT+05:00) Karachi", + 'Asia/Tashkent' => "(GMT+05:00) Tashkent", + 'Asia/Kolkata' => "(GMT+05:30) Kolkata", + 'Asia/Kathmandu' => "(GMT+05:45) Kathmandu", + 'Asia/Yekaterinburg' => "(GMT+06:00) Ekaterinburg", + 'Asia/Almaty' => "(GMT+06:00) Almaty", + 'Asia/Dhaka' => "(GMT+06:00) Dhaka", + 'Asia/Novosibirsk' => "(GMT+07:00) Novosibirsk", + 'Asia/Bangkok' => "(GMT+07:00) Bangkok", + 'Asia/Ho_Chi_Minh' => "(GMT+07.00) Ho Chi Minh", + 'Asia/Jakarta' => "(GMT+07:00) Jakarta", + 'Asia/Krasnoyarsk' => "(GMT+08:00) Krasnoyarsk", + 'Asia/Chongqing' => "(GMT+08:00) Chongqing", + 'Asia/Hong_Kong' => "(GMT+08:00) Hong Kong", + 'Asia/Kuala_Lumpur' => "(GMT+08:00) Kuala Lumpur", + 'Australia/Perth' => "(GMT+08:00) Perth", + 'Asia/Singapore' => "(GMT+08:00) Singapore", + 'Asia/Taipei' => "(GMT+08:00) Taipei", + 'Asia/Ulaanbaatar' => "(GMT+08:00) Ulaan Bataar", + 'Asia/Urumqi' => "(GMT+08:00) Urumqi", + 'Asia/Irkutsk' => "(GMT+09:00) Irkutsk", + 'Asia/Seoul' => "(GMT+09:00) Seoul", + 'Asia/Tokyo' => "(GMT+09:00) Tokyo", + 'Australia/Adelaide' => "(GMT+09:30) Adelaide", + 'Australia/Darwin' => "(GMT+09:30) Darwin", + 'Asia/Yakutsk' => "(GMT+10:00) Yakutsk", + 'Australia/Brisbane' => "(GMT+10:00) Brisbane", + 'Australia/Canberra' => "(GMT+10:00) Canberra", + 'Pacific/Guam' => "(GMT+10:00) Guam", + 'Australia/Hobart' => "(GMT+10:00) Hobart", + 'Australia/Melbourne' => "(GMT+10:00) Melbourne", + 'Pacific/Port_Moresby' => "(GMT+10:00) Port Moresby", + 'Australia/Sydney' => "(GMT+10:00) Sydney", + 'Asia/Vladivostok' => "(GMT+11:00) Vladivostok", + 'Asia/Magadan' => "(GMT+12:00) Magadan", + 'Pacific/Auckland' => "(GMT+12:00) Auckland", + 'Pacific/Fiji' => "(GMT+12:00) Fiji", + ); + + foreach ($timezones as $name => $location) { + Timezone::create(array('name'=>$name, 'location'=>$location)); + } + } +} diff --git a/database/seeds/CountriesSeeder.php b/database/seeds/CountriesSeeder.php new file mode 100644 index 000000000000..7fe9c9e3fb05 --- /dev/null +++ b/database/seeds/CountriesSeeder.php @@ -0,0 +1,37 @@ +delete(); + + //Get all of the countries + $countries = Countries::getList(); + foreach ($countries as $countryId => $country){ + DB::table('countries')->insert(array( + 'id' => $countryId, + 'capital' => ((isset($country['capital'])) ? $country['capital'] : null), + 'citizenship' => ((isset($country['citizenship'])) ? $country['citizenship'] : null), + 'country_code' => $country['country-code'], + 'currency' => ((isset($country['currency'])) ? $country['currency'] : null), + 'currency_code' => ((isset($country['currency_code'])) ? $country['currency_code'] : null), + 'currency_sub_unit' => ((isset($country['currency_sub_unit'])) ? $country['currency_sub_unit'] : null), + 'full_name' => ((isset($country['full_name'])) ? $country['full_name'] : null), + 'iso_3166_2' => $country['iso_3166_2'], + 'iso_3166_3' => $country['iso_3166_3'], + 'name' => $country['name'], + 'region_code' => $country['region-code'], + 'sub_region_code' => $country['sub-region-code'], + 'eea' => (bool)$country['eea'] + )); + } + } +} \ No newline at end of file diff --git a/database/seeds/PaymentLibrariesSeeder.php b/database/seeds/PaymentLibrariesSeeder.php new file mode 100644 index 000000000000..186b656f769f --- /dev/null +++ b/database/seeds/PaymentLibrariesSeeder.php @@ -0,0 +1,35 @@ + 'BeanStream', 'provider' => 'BeanStream', 'payment_library_id' => 2], + ['name' => 'Psigate', 'provider' => 'Psigate', 'payment_library_id' => 2], + ['name' => 'moolah', 'provider' => 'AuthorizeNet_AIM', 'sort_order' => 1, 'recommended' => 1, 'site_url' => 'https://invoiceninja.mymoolah.com/', 'payment_library_id' => 1], + ['name' => 'Alipay', 'provider' => 'Alipay_Express', 'payment_library_id' => 1], + ['name' => 'Buckaroo', 'provider' => 'Buckaroo_CreditCard', 'payment_library_id' => 1], + ['name' => 'Coinbase', 'provider' => 'Coinbase', 'payment_library_id' => 1], + ['name' => 'DataCash', 'provider' => 'DataCash', 'payment_library_id' => 1], + ['name' => 'Neteller', 'provider' => 'Neteller', 'payment_library_id' => 1], + ['name' => 'Pacnet', 'provider' => 'Pacnet', 'payment_library_id' => 1], + ['name' => 'PaymentSense', 'provider' => 'PaymentSense', 'payment_library_id' => 1], + ['name' => 'Realex', 'provider' => 'Realex_Remote', 'payment_library_id' => 1], + ['name' => 'Sisow', 'provider' => 'Sisow', 'payment_library_id' => 1], + ['name' => 'Skrill', 'provider' => 'Skrill', 'payment_library_id' => 1] + ]; + + foreach ($gateways as $gateway) + { + if (!DB::table('gateways')->where('name', '=', $gateway['name'])->get()) + { + Gateway::create($gateway); + } + } + + } +} \ No newline at end of file diff --git a/database/seeds/SecurePaymentFormSeeder.php b/database/seeds/SecurePaymentFormSeeder.php new file mode 100644 index 000000000000..77bbe1ba6cf2 --- /dev/null +++ b/database/seeds/SecurePaymentFormSeeder.php @@ -0,0 +1,187 @@ +delete(); + DB::table('invoices')->delete(); + DB::table('contacts')->delete(); + DB::table('clients')->delete(); + DB::table('account_gateways')->delete(); + //To reset the auto increment + $statement = " + ALTER TABLE invitations AUTO_INCREMENT = 1; + ALTER TABLE invoices AUTO_INCREMENT = 1; + ALTER TABLE contacts AUTO_INCREMENT = 1; + ALTER TABLE clients AUTO_INCREMENT = 1; + ALTER TABLE account_gateways AUTO_INCREMENT = 1; + "; + + DB::unprepared($statement); + + //$firstName = 'Oscar'; +// $lastName = 'Thompson'; +// $firstName_2 = 'Philip'; +// $lastName_2 = 'Jonsson'; +// +// $user = AccountGateway::create(array( +// 'account_id' => 1, +// 'user_id' => 1, +// 'gateway_id' => 4, +// 'config' => '{"bla":"vla","bli":"cla"}', +// 'public_id' => 1, +// 'accepted_credit_cards' => 8 +// )); +// +// $user2 = AccountGateway::create(array( +// 'account_id' => 2, +// 'user_id' => 2, +// 'gateway_id' => 5, +// 'config' => '{"bla":"vla","bli":"cla"}', +// 'public_id' => 2, +// 'accepted_credit_cards' => 7 +// )); +// +// $client = Client::create(array( +// 'user_id' => 1, +// 'account_id' => 1, +// 'currency_id' => 1, +// 'name' => $firstName.' '.$lastName, +// 'address1' => '2119 Howe Course', +// 'address2' => '2118 Howe Course', +// 'city' => 'West Chazport', +// 'state' => 'Utah', +// 'postal_code' => '31572', +// 'country_id' => 752, +// 'work_phone' => '012-345678', +// 'private_notes' => 'bla bla bla bla bla bla bla', +// 'balance' => 10.4, +// 'paid_to_date' => 10.2, +// 'website' => 'awebsite.com', +// 'industry_id' => 8, +// 'is_deleted' => 0, +// 'payment_terms' => 2, +// 'public_id' => 1, +// 'custom_value1' => $firstName, +// 'custom_value2' => $firstName +// )); +// +// $client2 = Client::create(array( +// 'user_id' => 2, +// 'account_id' => 2, +// 'currency_id' => 1, +// 'name' => $firstName_2.' '.$lastName_2, +// 'address1' => '1118 Muma Road', +// 'address2' => '1118 Muma Road', +// 'city' => 'New Orleans', +// 'state' => 'Arizona', +// 'postal_code' => '31572', +// 'country_id' => 752, +// 'work_phone' => '012-345678', +// 'private_notes' => 'bla bla bla bla bla bla bla', +// 'balance' => 10.4, +// 'paid_to_date' => 10.2, +// 'website' => 'bodosite.com', +// 'industry_id' => 8, +// 'is_deleted' => 0, +// 'payment_terms' => 2, +// 'public_id' => 1, +// 'custom_value1' => $firstName_2, +// 'custom_value2' => $firstName_2 +// )); +// +// $contact = Contact::create(array( +// 'account_id' => 1, +// 'user_id' => 1, +// 'client_id' => 1, +// 'is_primary' => 0, +// 'send_invoice' => 0, +// 'first_name' => $firstName, +// 'last_name' => $lastName, +// 'email' => 'an@email.com', +// 'phone' => '012-345678', +// 'public_id' => 1 +// )); +// +// $contact2 = Contact::create(array( +// 'account_id' => 2, +// 'user_id' => 2, +// 'client_id' => 2, +// 'is_primary' => 0, +// 'send_invoice' => 0, +// 'first_name' => $firstName_2, +// 'last_name' => $lastName_2, +// 'email' => 'the@email.com', +// 'phone' => '012-345678', +// 'public_id' => 2 +// )); +// +// $invoice = Invoice::create(array( +// 'client_id' => 1, +// 'user_id' => 1, +// 'account_id' => 1, +// 'invoice_number' => 1, +// 'discount' => 0.4, +// 'po_number' => $firstName, +// 'terms' => 'bla bla bla bla bla bla bla', +// 'public_notes' => 'bla bla bla bla bla bla bla', +// 'is_deleted' => 0, +// 'is_recurring' => 0, +// 'frequency_id' => 1, +// 'tax_name' => 'moms', +// 'tax_rate' => 33.0, +// 'amount' => 10.0, +// 'balance' => 8.0, +// 'public_id' => 1, +// 'is_quote' => 0 +// )); +// +// $invoice2 = Invoice::create(array( +// 'client_id' => 2, +// 'user_id' => 2, +// 'account_id' => 2, +// 'invoice_number' => 2, +// 'discount' => 0.4, +// 'po_number' => $firstName_2, +// 'terms' => 'bla bla bla bla bla bla bla', +// 'public_notes' => 'bla bla bla bla bla bla bla', +// 'is_deleted' => 0, +// 'is_recurring' => 0, +// 'frequency_id' => 1, +// 'tax_name' => 'moms', +// 'tax_rate' => 33.0, +// 'amount' => 10.0, +// 'balance' => 8.0, +// 'public_id' => 2, +// 'is_quote' => 0 +// )); +// +// $invitation = Invitation::create(array( +// 'account_id' => 1, +// 'user_id' => 1, +// 'contact_id' => 1, +// 'invoice_id' => 1, +// 'invitation_key' => 'aaabbb', +// 'transaction_reference' => 'bla bla bla bla bla bla bla', +// 'public_id' => 1 +// )); +// +// $invitation2 = Invitation::create(array( +// 'account_id' => 2, +// 'user_id' => 2, +// 'contact_id' => 2, +// 'invoice_id' => 2, +// 'invitation_key' => 'cccddd', +// 'transaction_reference' => 'bla bla bla bla bla bla bla', +// 'public_id' => 2 +// )); + } +} \ No newline at end of file diff --git a/database/seeds/UserTableSeeder.php b/database/seeds/UserTableSeeder.php new file mode 100644 index 000000000000..4250450755d8 --- /dev/null +++ b/database/seeds/UserTableSeeder.php @@ -0,0 +1,11 @@ +p4%hQ9#0fiX03WJdg#V{Lzuy>S;*&G1?A;W-hzKD)`d%FpResB4~wKUIUV&$mj=&O+gKFx69f{_ zQGc0Yd3qxmpaejYFa&Fk4GxDSlQB3ViA=^>A@MdiJk|z&$ksR_jYOv5Dag+Q1!t3R z57B&?uAg(kD>{k?L1G#fE0f7EG6Dvagky13DpjR{$6Lb)YiYCyV#}>XQp+U;CLrZV z_+p3;ijXQrb{H55(NVC|zm6ajFUyLgpRWnNFsz&{#^NwGsv|7{Jw5+FR480VOCew2 zi{Jk#EcK5T16W@`3PwseaN!PFs#1w*3<1K2TpEewYRe?xoNO5kJPzkVu*H#a&QyvM$(f30 zz{@2r6XZk+0THys<$mEhugF!kf=~=+W&#p^6u@TbpUI{JEbpr7>XOTso1>yc z0^!BtVu}rMSn@;v=sUSWp@M`!2Q$0U#}^v7-`Bv33YY&$yqgQk=3WpjaJ7m6GR zgrT9=3;dA6{QRKVnX%fciHXtC(UB3r_}oa#0K)8#pVGzm6R*3vy56ZvWF2&TH>f$) zKQQ0hd(`2ZX*H1#n>}$IcH@^640(8n-L%VVUf#?g+uG)36n@;ZFI%A)J+lGpT4bkn zsjRH*2Kegy!TBoO~zu>eZ{sq)}tz@;dOY@XCdzb>{%Q zDcL9?@j&v~t|w3YuK6cs*A%1CO}pLID5>sl9@i==K42^v)8kq`K0B-eJR@s=EalMi zPo6wEcGeJ_o-e0>`fJx_Qj|*NxlQ(M>2B3{f`KXd!p7pP;o;$$0p>^$+q;Fr=XV!c zR6FbxC#NwD3~v5hIiTm<^W+JEOiR8(Bv2eB!`kXPrgIB(*ZOoe7hJrk`M&HG&x!Rs zX9U<2VBFfiQ~#KSxw(l^LZM)B_Ac_S5q_uS@LWlHdU{HVUXjxgt$n9;X%IOk%dK{ibo_x)Xca z^k1BQ_s`(I>B*k0fj3gq(kvqf2Zy9HGvAWui%NW+z0OI@SO6sWT8a)d>iy5&U;ISE@O1}2T(s-!yIuEEJ&ELQ z<$9wxd(CWCaIjfLb6RWb_W@VPo%mjAq|QbYzP{F?w?C0ceA?G{5L#@kC@_nC9Ot%U zJn-oY`*I^nk9?J%Xvn;CKeM8uLhFheR8TlM z`5;+m*if+xg&KrH`#VZ4V^$@{1@X5ljI*jbtEy}+cRqhEZ(?-?#_d3B0I{)lrc+66 zZWNhp!hpH`&RjrVaoQ$DNy*^ru`@B%FZFjuXg3+WFdQmZzh?juJKFA_m6Y&Ks4=*5rG-)%Q1LWsoj zZFcB2EtmEm9ADJp1r%f-DhuK-2W8w(ALDne_bUa5W=++DnwmCm83{sfT` BoDKj0 literal 0 HcmV?d00001 diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2a5a5d1f069d56ae9a746137d0935e098f12bd07 GIT binary patch literal 2207 zcmaJ@eLR%u8XhE8D6#TYJB@St8fMJ58HSi43i*l=TgJ?r8Pm)=&AiN@Qjw%ZzCRL0 z<}8&Y4*P2n9h*u*bvEth`y-N8nngNm-)W=s$8nzD`@Z+{JiqI@?(2E(`;Ygmx7RK` z9WxyS0-@*b#`J|FRrPAC!(WXUqi#5uLM|-G4?G0P*b)HY#0A3uq`QzE4)_9WZuF7+ zfISRF@%>p4%hQ9#0fiX03WJdg#V{Lzuy>S;*&G1?A;W-hzKD)`d%FpResB4~wKUIUV&$mj=&O+gKFx69f{_ zQGc0Yd3qxmpaejYFa&Fk4GxDSlQB3ViA=^>A@MdiJk|z&$ksR_jYOv5Dag+Q1!t3R z57B&?uAg(kD>{k?L1G#fE0f7EG6Dvagky13DpjR{$6Lb)YiYCyV#}>XQp+U;CLrZV z_+p3;ijXQrb{H55(NVC|zm6ajFUyLgpRWnNFsz&{#^NwGsv|7{Jw5+FR480VOCew2 zi{Jk#EcK5T16W@`3PwseaN!PFs#1w*3<1K2TpEewYRe?xoNO5kJPzkVu*H#a&QyvM$(f30 zz{@2r6XZk+0THys<$mEhugF!kf=~=+W&#p^6u@TbpUI{JEbpr7>XOTso1>yc z0^!BtVu}rMSn@;v=sUSWp@M`!2Q$0U#}^v7-`Bv33YY&$yqgQk=3WpjaJ7m6GR zgrT9=3;dA6{QRKVnX%fciHXtC(UB3r_}oa#0K)8#pVGzm6R*3vy56ZvWF2&TH>f$) zKQQ0hd(`2ZX*H1#n>}$IcH@^640(8n-L%VVUf#?g+uG)36n@;ZFI%A)J+lGpT4bkn zsjRH*2Kegy!TBoO~zu>eZ{sq)}tz@;dOY@XCdzb>{%Q zDcL9?@j&v~t|w3YuK6cs*A%1CO}pLID5>sl9@i==K42^v)8kq`K0B-eJR@s=EalMi zPo6wEcGeJ_o-e0>`fJx_Qj|*NxlQ(M>2B3{f`KXd!p7pP;o;$$0p>^$+q;Fr=XV!c zR6FbxC#NwD3~v5hIiTm<^W+JEOiR8(Bv2eB!`kXPrgIB(*ZOoe7hJrk`M&HG&x!Rs zX9U<2VBFfiQ~#KSxw(l^LZM)B_Ac_S5q_uS@LWlHdU{HVUXjxgt$n9;X%IOk%dK{ibo_x)Xca z^k1BQ_s`(I>B*k0fj3gq(kvqf2Zy9HGvAWui%NW+z0OI@SO6sWT8a)d>iy5&U;ISE@O1}2T(s-!yIuEEJ&ELQ z<$9wxd(CWCaIjfLb6RWb_W@VPo%mjAq|QbYzP{F?w?C0ceA?G{5L#@kC@_nC9Ot%U zJn-oY`*I^nk9?J%Xvn;CKeM8uLhFheR8TlM z`5;+m*if+xg&KrH`#VZ4V^$@{1@X5ljI*jbtEy}+cRqhEZ(?-?#_d3B0I{)lrc+66 zZWNhp!hpH`&RjrVaoQ$DNy*^ru`@B%FZFjuXg3+WFdQmZzh?juJKFA_m6Y&Ks4=*5rG-)%Q1LWsoj zZFcB2EtmEm9ADJp1r%f-DhuK-2W8w(ALDne_bUa5W=++DnwmCm83{sfT` BoDKj0 literal 0 HcmV?d00001 diff --git a/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/css/bootstrap-theme.min-6140190bf67c53b87b24ba70ca9fc9ee.css b/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/css/bootstrap-theme.min-6140190bf67c53b87b24ba70ca9fc9ee.css new file mode 100644 index 000000000000..221d31831b01 --- /dev/null +++ b/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/css/bootstrap-theme.min-6140190bf67c53b87b24ba70ca9fc9ee.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v3.0.1 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#2d6ca2));background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-moz-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#419641));background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#eb9316));background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c12e2a));background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#2aabd2));background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#f8f8f8));background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-moz-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f3f3f3));background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-gradient(linear,left 0,left 100%,from(#3c3c3c),to(#222));background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-moz-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-gradient(linear,left 0,left 100%,from(#222),to(#282828));background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-moz-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#c8e5bc));background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#b9def0));background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#f8efc0));background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#e7c3c3));background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-moz-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3278b3));background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-moz-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#d0e9c6));background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#c4e3f3));background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#faf2cc));background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#ebcccc));background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-moz-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-gradient(linear,left 0,left 100%,from(#e8e8e8),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-moz-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} \ No newline at end of file diff --git a/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/css/bootstrap.min-6140190bf67c53b87b24ba70ca9fc9ee.css b/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/css/bootstrap.min-6140190bf67c53b87b24ba70ca9fc9ee.css new file mode 100644 index 000000000000..871123f9567b --- /dev/null +++ b/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/css/bootstrap.min-6140190bf67c53b87b24ba70ca9fc9ee.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v3.0.1 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#428bca}.text-primary:hover{color:#3071a9}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}@media(min-width:768px){.container{width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}}@media(min-width:992px){.container{width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}}@media(min-width:1200px){.container{width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:45px;line-height:45px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:7px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-link{font-weight:normal;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #000;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#333}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#333}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:45px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:45px;line-height:45px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .open>a .caret,.nav .open>a:hover .caret,.nav .open>a:focus .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-pills>li.active>a .caret,.nav-pills>li.active>a:hover .caret,.nav-pills>li.active>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#428bca;border-bottom-color:#428bca}.nav a:hover .caret{border-top-color:#2a6496;border-bottom-color:#2a6496}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:auto}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#555;border-bottom-color:#555}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#777;border-bottom-color:#777}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-heading>.dropdown .caret{border-color:#333 transparent}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-heading>.dropdown .caret{border-color:#fff transparent}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading>.dropdown .caret{border-color:#468847 transparent}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#c09853;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading>.dropdown .caret{border-color:#c09853 transparent}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#b94a48;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading>.dropdown .caret{border-color:#b94a48 transparent}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading>.dropdown .caret{border-color:#3a87ad transparent}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} \ No newline at end of file diff --git a/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/js/bootstrap.min-6140190bf67c53b87b24ba70ca9fc9ee.js b/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/js/bootstrap.min-6140190bf67c53b87b24ba70ca9fc9ee.js new file mode 100644 index 000000000000..e64572519d5d --- /dev/null +++ b/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/js/bootstrap.min-6140190bf67c53b87b24ba70ca9fc9ee.js @@ -0,0 +1,9 @@ +/*! + * Bootstrap v3.0.1 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +if("undefined"==typeof jQuery)throw new Error("Bootstrap requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]}}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(window.jQuery),+function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function c(){f.trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one(a.support.transition.end,c).emulateTransitionEnd(150):c())};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("bs.alert");e||d.data("bs.alert",e=new c(this)),"string"==typeof b&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.bs.alert.data-api",b,c.prototype.close)}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d)};b.DEFAULTS={loadingText:"loading..."},b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.is("input")?"val":"html",e=c.data();a+="Text",e.resetText||c.data("resetText",c[d]()),c[d](e[a]||this.options[a]),setTimeout(function(){"loadingText"==a?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons"]');if(a.length){var b=this.$element.find("input").prop("checked",!this.$element.hasClass("active")).trigger("change");"radio"===b.prop("type")&&a.find(".active").removeClass("active")}this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof c&&c;e||d.data("bs.button",e=new b(this,f)),"toggle"==c?e.toggle():c&&e.setState(c)})},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.bs.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle"),b.preventDefault()})}(window.jQuery),+function(a){"use strict";var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},b.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},b.prototype.getActiveIndex=function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},b.prototype.to=function(b){var c=this,d=this.getActiveIndex();return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},b.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},b.prototype.next=function(){return this.sliding?void 0:this.slide("next")},b.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},b.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}this.sliding=!0,f&&this.pause();var j=a.Event("slide.bs.carousel",{relatedTarget:e[0],direction:g});if(!e.hasClass("active")){if(this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")})),a.support.transition&&this.$element.hasClass("slide")){if(this.$element.trigger(j),j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)}).emulateTransitionEnd(600)}else{if(this.$element.trigger(j),j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c),g="string"==typeof c?c:f.slide;e||d.data("bs.carousel",e=new b(this,f)),"number"==typeof c?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c,d=a(this),e=a(d.attr("data-target")||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),d.data()),g=d.attr("data-slide-to");g&&(f.interval=!1),e.carousel(f),(g=d.attr("data-slide-to"))&&e.data("bs.carousel").to(g),b.preventDefault()}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var b=a(this);b.carousel(b.data())})})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.DEFAULTS={toggle:!0},b.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},b.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b=a.Event("show.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.$parent&&this.$parent.find("> .panel > .in");if(c&&c.length){var d=c.data("bs.collapse");if(d&&d.transitioning)return;c.collapse("hide"),d||c.data("bs.collapse",null)}var e=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[e](0),this.transitioning=1;var f=function(){this.$element.removeClass("collapsing").addClass("in")[e]("auto"),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return f.call(this);var g=a.camelCase(["scroll",e].join("-"));this.$element.one(a.support.transition.end,a.proxy(f,this)).emulateTransitionEnd(350)[e](this.$element[0][g])}}},b.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?(this.$element[c](0).one(a.support.transition.end,a.proxy(d,this)).emulateTransitionEnd(350),void 0):d.call(this)}}},b.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.collapse",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.bs.collapse.data-api","[data-toggle=collapse]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.collapse"),h=g?"toggle":d.data(),i=d.attr("data-parent"),j=i&&a(i);g&&g.transitioning||(j&&j.find('[data-toggle=collapse][data-parent="'+i+'"]').not(d).addClass("collapsed"),d[f.hasClass("in")?"addClass":"removeClass"]("collapsed")),f.collapse(h)})}(window.jQuery),+function(a){"use strict";function b(){a(d).remove(),a(e).each(function(b){var d=c(a(this));d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown")),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown"))})}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}var d=".dropdown-backdrop",e="[data-toggle=dropdown]",f=function(b){a(b).on("click.bs.dropdown",this.toggle)};f.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){if("ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(''}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery),+function(a){"use strict";function b(c,d){var e,f=a.proxy(this.process,this);this.$element=a(c).is("body")?a(window):a(c),this.$body=a("body"),this.$scrollElement=this.$element.on("scroll.bs.scroll-spy.data-api",f),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||(e=a(c).attr("href"))&&e.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.offsets=a([]),this.targets=a([]),this.activeTarget=null,this.refresh(),this.process()}b.DEFAULTS={offset:10},b.prototype.refresh=function(){var b=this.$element[0]==window?"offset":"position";this.offsets=a([]),this.targets=a([]);var c=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#\w/.test(e)&&a(e);return f&&f.length&&[[f[b]().top+(!a.isWindow(c.$scrollElement.get(0))&&c.$scrollElement.scrollTop()),e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){c.offsets.push(this[0]),c.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,d=c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(b>=d)return g!=(a=f.last()[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parents(".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate")};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),+function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.parent("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},b.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e).emulateTransitionEnd(150):e(),f.removeClass("in")};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new b(this)),"string"==typeof c&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.options=a.extend({},b.DEFAULTS,d),this.$window=a(window).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(c),this.affixed=this.unpin=null,this.checkPosition()};b.RESET="affix affix-top affix-bottom",b.DEFAULTS={offset:0},b.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},b.prototype.checkPosition=function(){if(this.$element.is(":visible")){var c=a(document).height(),d=this.$window.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top()),"function"==typeof h&&(h=f.bottom());var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=c-h?"bottom":null!=g&&g>=d?"top":!1;this.affixed!==i&&(this.unpin&&this.$element.css("top",""),this.affixed=i,this.unpin="bottom"==i?e.top-d:null,this.$element.removeClass(b.RESET).addClass("affix"+(i?"-"+i:"")),"bottom"==i&&this.$element.offset({top:document.body.offsetHeight-h-this.$element.height()}))}};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof c&&c;e||d.data("bs.affix",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery); \ No newline at end of file diff --git a/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/js/jquery-1.10.2.min-590935b89a583963aad9f1d779d81729.js b/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/js/jquery-1.10.2.min-590935b89a583963aad9f1d779d81729.js new file mode 100644 index 000000000000..76d21a4651e4 --- /dev/null +++ b/public/builds/bootstrapper/packages/patricktalmadge/bootstrapper/js/jquery-1.10.2.min-590935b89a583963aad9f1d779d81729.js @@ -0,0 +1,6 @@ +/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery-1.10.2.min.map +*/ +(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="
    ",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
    a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
    t
    ",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
    ",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t +}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); +u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x(" + + + + + + + \ No newline at end of file diff --git a/resources/views/invoices/view.blade.php b/resources/views/invoices/view.blade.php new file mode 100644 index 000000000000..6f53dba4a4c8 --- /dev/null +++ b/resources/views/invoices/view.blade.php @@ -0,0 +1,84 @@ +@extends('public.header') + +@section('head') + @parent + + @include('script') + + + + + +@stop + +@section('content') + +
    + +

     

    +
    + @if ($invoice->is_quote) + {{ Button::normal(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }}   + @if (!$isConverted) + {{ Button::success_link(URL::to('approve/' . $invitation->invitation_key), trans('texts.approve'), array('class' => 'btn-lg')) }} + @endif + @elseif ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_recurring) + {{ Button::normal(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }}   + @if ($hasToken) + {{ DropdownButton::success_lg(trans('texts.pay_now'), [ + ['url' => URL::to("payment/{$invitation->invitation_key}?use_token=true&use_paypal=false"), 'label' => trans('texts.use_card_on_file')], + ['url' => URL::to("payment/{$invitation->invitation_key}?use_paypal=false"), 'label' => trans('texts.edit_payment_details')] + ])->addClass('btn-lg') }} + @elseif ($countGateways == 2) + {{ DropdownButton::success_lg(trans('texts.pay_now'), [ + ['url' => URL::to("payment/{$invitation->invitation_key}?use_paypal=true"), 'label' => trans('texts.pay_with_paypal')], + ['url' => URL::to("payment/{$invitation->invitation_key}?use_paypal=false"), 'label' => trans('texts.pay_with_card')] + ])->addClass('btn-lg') }} + @else + {{ Button::success_link(URL::to('payment/' . $invitation->invitation_key), trans('texts.pay_now'), array('class' => 'btn-lg')) }} + @endif + @else + {{ Button::success('Download PDF', array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }} + @endif +
    + +

     

    + + + + @include('invoices.pdf', ['account' => $invoice->client->account]) + +

     

    +

     

    + +
    + +@stop \ No newline at end of file diff --git a/resources/views/list.blade.php b/resources/views/list.blade.php new file mode 100644 index 000000000000..4cc501c55d16 --- /dev/null +++ b/resources/views/list.blade.php @@ -0,0 +1,164 @@ +@extends('header') + +@section('content') + + {{ Former::open($entityType . 's/bulk')->addClass('listForm') }} +
    + {{ Former::text('action') }} + {{ Former::text('statusId') }} + {{ Former::text('id') }} +
    + + {{ DropdownButton::normal(trans('texts.archive'), + Navigation::links( + array( + array(trans('texts.archive_'.$entityType), "javascript:submitForm('archive')"), + array(trans('texts.delete_'.$entityType), "javascript:submitForm('delete')"), + ) + ) + , array('id'=>'archive'))->split(); }} + +   + +
    + + {{ Button::success_link(URL::to($entityType . 's/create'), trans("texts.new_$entityType"), array('class' => 'pull-right'))->append_with_icon('plus-sign'); }} + +
    + + @if (isset($secEntityType)) + {{ Datatable::table() + ->addColumn($secColumns) + ->setUrl(route('api.' . $secEntityType . 's')) + ->setOptions('sPaginationType', 'bootstrap') + ->render('datatable') }} + @endif + + {{ Datatable::table() + ->addColumn($columns) + ->setUrl(route('api.' . $entityType . 's')) + ->setOptions('sPaginationType', 'bootstrap') + ->render('datatable') }} + + {{ Former::close() }} + + + +@stop + +@section('onReady') + + var tableFilter = ''; + var searchTimeout = false; + + var oTable0 = $('#DataTables_Table_0').dataTable(); + var oTable1 = $('#DataTables_Table_1').dataTable(); + function filterTable(val) { + if (val == tableFilter) { + return; + } + tableFilter = val; + oTable0.fnFilter(val); + @if (isset($secEntityType)) + oTable1.fnFilter(val); + @endif + } + + $('#tableFilter').on('keyup', function(){ + if (searchTimeout) { + window.clearTimeout(searchTimeout); + } + + searchTimeout = setTimeout(function() { + filterTable($('#tableFilter').val()); + }, 1000); + }) + + window.onDatatableReady = function() { + $(':checkbox').click(function() { + setArchiveEnabled(); + }); + + $('tbody tr').click(function(event) { + if (event.target.type !== 'checkbox' && event.target.type !== 'button' && event.target.tagName.toLowerCase() !== 'a') { + $checkbox = $(this).closest('tr').find(':checkbox:not(:disabled)'); + var checked = $checkbox.prop('checked'); + $checkbox.prop('checked', !checked); + setArchiveEnabled(); + } + }); + + $('tbody tr').mouseover(function() { + $(this).closest('tr').find('.tr-action').css('visibility','visible'); + }).mouseout(function() { + $dropdown = $(this).closest('tr').find('.tr-action'); + if (!$dropdown.hasClass('open')) { + $dropdown.css('visibility','hidden'); + } + }); + + } + + $('#archive > button').prop('disabled', true); + $('#archive > button:first').click(function() { + submitForm('archive'); + }); + + $('.selectAll').click(function() { + $(this).closest('table').find(':checkbox:not(:disabled)').prop('checked', this.checked); + }); + + function setArchiveEnabled() { + var checked = $('tbody :checkbox:checked').length > 0; + $('#archive > button').prop('disabled', !checked); + } + + + +@stop \ No newline at end of file diff --git a/resources/views/master.blade.php b/resources/views/master.blade.php new file mode 100644 index 000000000000..d174c873917f --- /dev/null +++ b/resources/views/master.blade.php @@ -0,0 +1,139 @@ + + + + Invoice Ninja | {{ isset($title) ? $title : ' ' . trans('public.title') }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@yield('head') + + + + + + @if (isset($_ENV['TAG_MANAGER_KEY']) && $_ENV['TAG_MANAGER_KEY']) + + + + + + + @elseif (isset($_ENV['ANALYTICS_KEY']) && $_ENV['ANALYTICS_KEY']) + + @else + + @endif + +@yield('body') + + + + + + \ No newline at end of file diff --git a/resources/views/payments/edit.blade.php b/resources/views/payments/edit.blade.php new file mode 100644 index 000000000000..024676fdd9bb --- /dev/null +++ b/resources/views/payments/edit.blade.php @@ -0,0 +1,70 @@ +@extends('header') + + +@section('onReady') + $('input#name').focus(); +@stop + +@section('content') + + + {{ Former::open($url)->addClass('col-md-10 col-md-offset-1 warn-on-exit')->method($method)->rules(array( + 'client' => 'required', + 'invoice' => 'required', + 'amount' => 'required', + )); }} + + @if ($payment) + {{ Former::populate($payment) }} + @endif + +
    +
    + + @if (!$payment) + {{ Former::select('client')->addOption('', '')->addGroupClass('client-select') }} + {{ Former::select('invoice')->addOption('', '')->addGroupClass('invoice-select') }} + {{ Former::text('amount') }} + @endif + + {{ Former::select('payment_type_id')->addOption('','') + ->fromQuery($paymentTypes, 'name', 'id') }} + {{ Former::text('payment_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('') }} + {{ Former::text('transaction_reference') }} + {{-- Former::select('currency_id')->addOption('','') + ->fromQuery($currencies, 'name', 'id')->select(Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY)) --}} + +
    +
    + +
    +
    + +
    + {{ Button::lg_primary_submit_success(trans('texts.save'))->append_with_icon('floppy-disk') }} + {{ Button::lg_default_link('payments/', trans('texts.cancel'))->append_with_icon('remove-circle'); }} +
    + + {{ Former::close() }} + + + +@stop diff --git a/resources/views/payments/payment.blade.php b/resources/views/payments/payment.blade.php new file mode 100644 index 000000000000..e1019c19d358 --- /dev/null +++ b/resources/views/payments/payment.blade.php @@ -0,0 +1,323 @@ +@extends('public.header') + +@section('content') + + + +{{ Former::vertical_open($url)->rules(array( +'first_name' => 'required', +'last_name' => 'required', +'card_number' => 'required', +'expiration_month' => 'required', +'expiration_year' => 'required', +'cvv' => 'required', +'address1' => 'required', +'city' => 'required', +'state' => 'required', +'postal_code' => 'required', +'country' => 'required', +'phone' => 'required', +'email' => 'required|email' +)) }} + +@if ($client) + {{ Former::populate($client) }} + {{ Former::populateField('first_name', $contact->first_name) }} + {{ Former::populateField('last_name', $contact->last_name) }} +@endif + +
    +

     

    + +
    +
    + +
    +
    +
    + @if ($client) +

    {{{ $client->getDisplayName() }}}

    +

    {{{ trans('texts.invoice') . ' ' . $invoiceNumber }}}|  {{ trans('texts.amount_due') }}: {{ Utils::formatMoney($amount, $currencyId) }}

    + @elseif ($paymentTitle) +

    {{ $paymentTitle }}
    {{ $paymentSubtitle }}

    + @endif +
    +
    +
    + @if (Request::secure() || Utils::isNinjaDev()) +
    +

    {{ trans('texts.secure_payment') }}

    +
    {{ trans('texts.256_encryption') }}
    +
    + @endif +
    +
    + +

     
     

    + +
    +

    {{ trans('texts.contact_information') }}

    +
    +
    + {{ Former::text('first_name')->placeholder(trans('texts.first_name'))->raw() }} +
    +
    + {{ Former::text('last_name')->placeholder(trans('texts.last_name'))->raw() }} +
    +
    + @if (isset($paymentTitle)) +
    +
    + {{ Former::text('email')->placeholder(trans('texts.email'))->raw() }} +
    +
    + @endif + +

     
     

    + +

    {{ trans('texts.billing_address') }}  {{ trans('texts.payment_footer1') }}

    +
    +
    + {{ Former::text('address1')->placeholder(trans('texts.address1'))->raw() }} +
    +
    +
    +
    + {{ Former::text('address2')->placeholder(trans('texts.address2'))->raw() }} +
    +
    + {{ Former::text('city')->placeholder(trans('texts.city'))->raw() }} +
    +
    +
    +
    + {{ Former::text('state')->placeholder(trans('texts.state'))->raw() }} +
    +
    + {{ Former::text('postal_code')->placeholder(trans('texts.postal_code'))->raw() }} +
    +
    + +

     
     

    + +

    {{ trans('texts.billing_method') }}

    +
    +
    + {{ Former::text('card_number')->placeholder(trans('texts.card_number'))->raw() }} +
    +
    + {{ Former::text('cvv')->placeholder(trans('texts.cvv'))->raw() }} +
    +
    +
    +
    + {{ Former::select('expiration_month')->placeholder(trans('texts.expiration_month')) + ->addOption('01 - January', '1') + ->addOption('02 - February', '2') + ->addOption('03 - March', '3') + ->addOption('04 - April', '4') + ->addOption('05 - May', '5') + ->addOption('06 - June', '6') + ->addOption('07 - July', '7') + ->addOption('08 - August', '8') + ->addOption('09 - September', '9') + ->addOption('10 - October', '10') + ->addOption('11 - November', '11') + ->addOption('12 - December', '12')->raw(); + }} +
    +
    + {{ Former::select('expiration_year')->placeholder(trans('texts.expiration_year')) + ->addOption('2015', '2015') + ->addOption('2016', '2016') + ->addOption('2017', '2017') + ->addOption('2018', '2018') + ->addOption('2019', '2019') + ->addOption('2020', '2020') + ->addOption('2021', '2021') + ->addOption('2022', '2022') + ->addOption('2023', '2023') + ->addOption('2024', '2024') + ->addOption('2025', '2025')->raw(); + }} +
    +
    + + +
    +
    + @if ($client && $account->showTokenCheckbox()) + selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:top"> + + {{ trans('texts.token_billing_secure', ['stripe_link' => link_to('https://stripe.com/', 'Stripe.com', ['target' => '_blank'])]) }} + @endif +
    + +
    + @if (isset($acceptedCreditCardTypes)) +
    + @foreach ($acceptedCreditCardTypes as $card) + {{ $card['alt'] }} + @endforeach +
    + @endif +
    +
    + + +

     
     

    + +
    +
    + {{ Button::block_success_submit_lg(strtoupper(trans('texts.pay_now') . ' - ' . Utils::formatMoney($amount, $currencyId) )) }} +
    +
    + + +
    + +
    +
    + + +

     

    +

     

    + +
    + + + +{{ Former::close() }} + + + +@stop \ No newline at end of file diff --git a/resources/views/plans.blade.php b/resources/views/plans.blade.php new file mode 100644 index 000000000000..ef9da93391eb --- /dev/null +++ b/resources/views/plans.blade.php @@ -0,0 +1,62 @@ +
    +
    +
    +
    +
    {{ trans('public.plans.number_clients') }}
    +
    {{ trans('public.plans.unlimited_invoices') }}
    +
    {{ trans('public.plans.company_logo') }}
    +
    {{ trans('public.plans.live_pdf') }}
    +
    {{ trans('public.plans.four_templates') }}
    +
    {{ trans('public.plans.payments') }}
    +
    {{ trans('public.plans.additional_templates') }}
    +
    {{ trans('public.plans.multi_user') }}
    +
    {{ trans('public.plans.quotes') }}
    +
    {{ trans('public.plans.advanced_settings') }}
    +
    {{ trans('public.plans.data_vizualizations') }}
    +
    {{ trans('public.plans.email_support') }}
    +
    {{ trans('public.plans.remove_created_by') }}
    +
    {{ trans('public.plans.latest_features') }}
    +
    {{ trans('public.plans.pricing') }}
    + +
    +
    +
    {{ trans('public.plans.free') }}
    +
    {{ trans('public.plans.number_clients') }}
    500
    +
    {{ trans('public.plans.unlimited_invoices') }}
    +
    {{ trans('public.plans.company_logo') }}
    +
    {{ trans('public.plans.live_pdf') }}
    +
    {{ trans('public.plans.four_templates') }}
    +
    {{ trans('public.plans.payments') }}
    +
    {{ trans('public.plans.additional_templates') }}
    +
    {{ trans('public.plans.multi_user') }}
    +
    {{ trans('public.plans.quotes') }}
    +
    {{ trans('public.plans.advanced_settings') }}
    +
    {{ trans('public.plans.data_vizualizations') }}
    +
    {{ trans('public.plans.email_support') }}
    +
    {{ trans('public.plans.remove_created_by') }}
    +
    {{ trans('public.plans.latest_features') }}
    +
    {{ trans('public.plans.pricing') }}

    {{ trans('public.plans.free_always') }}

    +
    +
    + +
    {{ trans('public.plans.pro_plan') }}
    +
    {{ trans('public.plans.number_clients') }}
    {{ trans('public.plans.unlimited') }}
    +
    {{ trans('public.plans.unlimited_invoices') }}
    +
    {{ trans('public.plans.company_logo') }}
    +
    {{ trans('public.plans.live_pdf') }}
    +
    {{ trans('public.plans.four_templates') }}
    +
    {{ trans('public.plans.payments') }}
    +
    {{ trans('public.plans.additional_templates') }}
    +
    {{ trans('public.plans.multi_user') }}
    +
    {{ trans('public.plans.quotes') }}
    +
    {{ trans('public.plans.advanced_settings') }}
    +
    {{ trans('public.plans.data_vizualizations') }}
    +
    {{ trans('public.plans.email_support') }}
    +
    {{ trans('public.plans.remove_created_by') }}
    +
    {{ trans('public.plans.latest_features') }}
    +
    {{ trans('public.plans.pricing') }}

    {{ trans('public.plans.year_price') }}

    + + +
    +
    +
    \ No newline at end of file diff --git a/resources/views/public/header.blade.php b/resources/views/public/header.blade.php new file mode 100644 index 000000000000..32d0dffbfc5a --- /dev/null +++ b/resources/views/public/header.blade.php @@ -0,0 +1,276 @@ +@extends('master') + +@section('head') + + + + +@stop + +@section('body') + + + +{{ Form::open(array('url' => 'get_started', 'id' => 'startForm')) }} +{{ Form::hidden('guest_key') }} +{{ Form::hidden('sign_up', Input::get('sign_up')) }} +{{ Form::close() }} + + + + + + + +
    + @if (Session::has('warning')) +
    {{ Session::get('warning') }}
    + @endif + + @if (Session::has('message')) +
    {{ Session::get('message') }}
    + @endif + + @if (Session::has('error')) +
    {{ Session::get('error') }}
    + @endif +
    + +@yield('content') + +
    +
    +
    + @if (!isset($hideLogo) || !$hideLogo) + + @endif +
    +
    + +
    +
    +
    Copyright ©2015 InvoiceNinja. All rights reserved.
    +
    +
    +
    + + + + + + + + + + + + + + + @stop diff --git a/resources/views/public/license.blade.php b/resources/views/public/license.blade.php new file mode 100644 index 000000000000..92844a2a3123 --- /dev/null +++ b/resources/views/public/license.blade.php @@ -0,0 +1,101 @@ +@extends('public.header') + +@section('content') + + + + +
    +

     

    + +
    +
    + +
    +
    +
    +

    License Key
    {{ $message }}

    +
    +
    +
    + +

     

    +

     

    + +
    +
    +

    {{ $license }}

    +
    +
    +
    +
    + +
    + +
    + + +@stop \ No newline at end of file diff --git a/resources/views/public/terms.blade.php b/resources/views/public/terms.blade.php new file mode 100644 index 000000000000..c509ddde5716 --- /dev/null +++ b/resources/views/public/terms.blade.php @@ -0,0 +1,177 @@ +@extends('public.header') + +@section('content') + + + + +
    +

     

    + +
    +
    + + +
    +
    +
    +
    +

    Terms of Service & Conditions of Use

    +
    +
    +
    +
    + +
    +
    +
    +
    +

    Invoice Ninja LLC provides this website and services under the following terms of service and conditions of use. By utilizing the invoiceNinja.com website you are agreeing to the following terms of service & conditions of use. You must be of legal age of majority to enter into a binding agreement to use invoiceninja.com. If you do not agree to the below terms & conditions, do not use invoiceninja.com.

    +
    +
    +
    +
    + + + + +
    +
    +
    +
    +

    Definitions

    +

    Invoiceninja.com users who access invoiceninja.com services are defined as “User Accountsâ€. User Account clients who use invoiceninja.com services to view and/or pay invoices are defined as “Clients.†The wording “data†and “content†are used interchangeably.

    +
    +
    +
    + +
    +
    +
    +
    +

    Responsibility

    +

    User Accounts must ensure the confidentiality of usernames and passwords used to access their account. User Accounts are responsible for all activity occurring under their account including all laws relating to data, privacy, personal information, international copyright and trademark laws.

    +
    +
    +
    +
    + +
    +
    +
    +
    +

    Data Ownership

    +

    The User Accounts owns all data generated in their invoiceninja.com account. Invoiceninja.com will not modify or distribute User Account data. Invoiceninja.com will store and access data solely for the purpose of providing services to User Accounts.

    +

    User Accounts are responsible for their data. Invoiceninja.com has no responsibility or liability for User Account data or Client experience. User Accounts are responsible for any loss or damage a User Account may cause to their Clients or other people. Although we have no obligation to do so, if deemed legally necessary invoiceninja.com has absolute discretion to remove or edit User Account data without notice or penalty.

    +

    Invoiceninja.com does not own User Account data, but we do reserve the right to use User Account data as necessary to operate invoiceninja.com and improve User Account services.

    +
    +
    +
    +
    + + +
    +
    +
    +
    +

    Copyright & Trademarks

    +

    User Accounts are responsible that company logos, graphics, and content uploaded to invoiceninja.com do not infringe on international copyright & trademark law.

    +
    +
    +
    +
    + + +
    +
    +
    +
    +

    Open Source License

    +

    Invoiceninja.com is an open source application and invoiceninja.com source code is governed by international attribution assurances licensing: https://github.com/hillelcoren/invoice-ninja/blob/master/LICENSE.

    +
    +
    +
    +
    + + +
    +
    +
    +
    +

    User Account Limited License

    +

    Invoiceninja.com grants User Accounts & Clients a limited license to access the invoiceninja.com services such as User Account creation and all invoiceninja.om services, and Client services such as viewing invoices, downloading invoices, and printing invoices. This limited license may be revoked if deemed legally necessary without notice or penalty.

    +
    +
    +
    +
    + + +
    +
    +
    +
    +

    Use of Emailing Services

    +

    Keep it legal and clean. Any User Account emailing invoices data, hyper-links, or other material that is unlawful, libelous, defamatory, pornographic, harassing, invasive, fraudulent or otherwise objectionable will be deactivated.

    +

    Content that would constitute criminal offence or create legal liability, violate copyright, trademark, or intellectual property will be deleted or provided to legal authorities.

    +
    +
    +
    +
    + + +
    +
    +
    +
    +

    Security

    +

    Invoiceninja.com does not store or obtain credit card or sensitive financial data in any form. Responsibility for Third-Party Material User Account may utilize hyper-linking to third-party web sites. Invoiceninja.com takes no responsibility for third party content.

    +
    +
    +
    +
    + + +
    +
    +
    +
    +

    Limited Liability

    +

    User Accounts and Clients agree to indemnify, defend, and hold invoiceninja.com, its directors or employees harmless against any and all liability and cost as a result of using invoiceninja.com. User Accounts and Clients shall not assert any claim or allegation of any nature whatsoever against invoiceninja.com, its directors or employees.

    +

    Invoiceninja.com shall not be liable for damages of any kind, including but not limited to loss of site use, loss of profits or loss of data, tort or otherwise, arising out of or in any way connected with the use of or inability to use invoiceninja.com.

    +

    You shall defend, indemnify and hold harmless invoiceninja.com from any loss, damages, liabilities, expenses, claims and proceedings arising out of your use of invoiceninja.com.

    +
    +
    +
    +
    + +
    +
    +
    +
    +

    Availability

    +

    Invoiceninja.com uses third party hosting that strives to ensure maximum uptime. However, invoiceninja.com cannot guarantee uninterrupted access invoiceninja.com. Invoiceninja.com reserves the right to interrupt access to invoiceninja.com for the sake of forming maintenance, updates, and security requirements.

    +
    +
    +
    +
    + +

     

    +

     

    + +
    +
    +
    + +@stop \ No newline at end of file diff --git a/resources/views/public_list.blade.php b/resources/views/public_list.blade.php new file mode 100644 index 000000000000..a517539ab74b --- /dev/null +++ b/resources/views/public_list.blade.php @@ -0,0 +1,110 @@ +@extends('public.header') + +@section('content') + + + +
    + +

     

    + + + +

    {{ $title }}

    + + {{ Datatable::table() + ->addColumn($columns) + ->setUrl(route('api.client.' . $entityType . 's')) + ->setOptions('sPaginationType', 'bootstrap') + ->render('datatable') }} + +
    + + + +@stop + diff --git a/resources/views/reports/d3.blade.php b/resources/views/reports/d3.blade.php new file mode 100644 index 000000000000..003cc95972f8 --- /dev/null +++ b/resources/views/reports/d3.blade.php @@ -0,0 +1,309 @@ +@extends('accounts.nav') + +@section('head') + @parent + + + + +@stop + +@section('content') + @parent + @include('accounts.nav_advanced') + + {{ Former::open() }} + {{ Former::legend('data_visualizations') }} + {{ Former::close() }} + + + + + Group By    + +    {{ $message }} + + +

     

    + +
    + + + +@stop \ No newline at end of file diff --git a/resources/views/reports/report_builder.blade.php b/resources/views/reports/report_builder.blade.php new file mode 100644 index 000000000000..e45e96063b03 --- /dev/null +++ b/resources/views/reports/report_builder.blade.php @@ -0,0 +1,106 @@ +@extends('accounts.nav') + +@section('head') + @parent + + +@stop + +@section('content') + @parent + @include('accounts.nav_advanced') + + + + {{ trans('texts.chart_builder') }} +
    + {{ Button::default_link(URL::to('company/advanced_settings/data_visualizations'), trans("texts.data_visualizations"))->append_with_icon('globe') }} +
    +
    + +
    +
    + + {{ Former::open()->addClass('warn-on-exit') }} + {{ Former::populateField('start_date', $startDate) }} + {{ Former::populateField('end_date', $endDate) }} + {{ Former::select('chart_type')->options($chartTypes, $chartType) }} + {{ Former::select('group_by')->options($dateTypes, $groupBy) }} + {{ Former::text('start_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT)) + ->append('') }} + {{ Former::text('end_date')->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT)) + ->append('') }} + + @if (Auth::user()->isPro()) + {{ Former::actions( Button::primary_submit('Generate') ) }} + @else + + @endif + + {{ Former::close() }} + +

     

    +
    +
    +
     Invoices
    +
    +
    +
    +
     Payments
    +
    +
    +
    +
     Credits
    +
    + +
    +
    + +
    + +
    + + + +@stop + + +@section('onReady') + + $('#start_date, #end_date').datepicker({ + autoclose: true, + todayHighlight: true, + keyboardNavigation: false + }); + +@stop \ No newline at end of file diff --git a/resources/views/script.blade.php b/resources/views/script.blade.php new file mode 100644 index 000000000000..f1a5c1a29f05 --- /dev/null +++ b/resources/views/script.blade.php @@ -0,0 +1,26 @@ + \ No newline at end of file diff --git a/resources/views/secure_payment.blade.php b/resources/views/secure_payment.blade.php new file mode 100644 index 000000000000..30f10c5fc50d --- /dev/null +++ b/resources/views/secure_payment.blade.php @@ -0,0 +1,130 @@ +@extends('public.header') + +@section('content') + +
    +
    +
    +

    Secure Payment

    +

    256-BiT Encryption

    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + + + +
    +
    + + + +
    +
    + +
    +
    + + + + +
    +
    + +
    +
    + + + +
    + +
    + + + +
    + +
    + + + +
    + +
    + + + +
    +
    + +
    +
    +
    +
    +
    + + + + + +
    +
    +
    +
    + + + + +
    +
    + + + + +
    +
    + + +
    +
    + + + +
    + + +
    +
    + + +
    +
    +
    +
    + +
    + +
    +
    +
    + + + + + +@stop \ No newline at end of file diff --git a/resources/views/setup.blade.php b/resources/views/setup.blade.php new file mode 100644 index 000000000000..4a0ffa52ea6e --- /dev/null +++ b/resources/views/setup.blade.php @@ -0,0 +1,139 @@ + + + + Invoice Ninja | Setup + + + + + + + +
    + +   +
    +
    + +
    +

    Invoice Ninja Setup

    + @if (version_compare(phpversion(), '5.4.0', '<')) +
    Warning: The application requires PHP >= 5.4.0
    + @endif + @if (!extension_loaded('fileinfo')) +
    Warning: The fileinfo extension needs to be installed and enabled.
    + @endif + If you need help you can either post to our Google Group + or email us at contact@invoiceninja.com. +

    +

    -- Commands to create a MySQL database and user
    +CREATE SCHEMA `ninja` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
    +CREATE USER 'ninja'@'localhost' IDENTIFIED BY 'ninja';
    +GRANT ALL PRIVILEGES ON `ninja`.* TO 'ninja'@'localhost';
    +FLUSH PRIVILEGES;
    +

    +
    + + {{ Former::open()->rules([ + 'app[url]' => 'required', + 'database[type][host]' => 'required', + 'database[type][database]' => 'required', + 'database[type][username]' => 'required', + 'database[type][password]' => 'required', + 'first_name' => 'required', + 'last_name' => 'required', + 'email' => 'required|email', + 'password' => 'required', + 'terms_checkbox' => 'required' + ]) }} + +
    +
    +

    Application Settings

    +
    +
    + {{ Former::text('app[url]')->label('URL')->value(Request::root()) }} +
    +
    + +
    +
    +

    Database Connection

    +
    +
    + {{ Former::select('database[default]')->label('Driver')->options(['mysql' => 'MySQL', 'pgsql' => 'PostgreSQL', 'sqlite' => 'SQLite']) }} + {{ Former::text('database[type][host]')->label('Host')->value('localhost') }} + {{ Former::text('database[type][database]')->label('Database')->value('ninja') }} + {{ Former::text('database[type][username]')->label('Username')->value('ninja') }} + {{ Former::password('database[type][password]')->label('Password')->value('ninja') }} + {{ Former::actions( Button::normal('Test connection', ['onclick' => 'testDatabase()']), '  ' ) }} +
    +
    + + +
    +
    +

    Email Settings

    +
    +
    + {{ Former::select('mail[driver]')->label('Driver')->options(['smtp' => 'SMTP', 'mail' => 'Mail', 'sendmail' => 'Sendmail']) }} + {{ Former::text('mail[host]')->label('Host')->value('localhost') }} + {{ Former::text('mail[port]')->label('Port')->value('587') }} + {{ Former::select('mail[encryption]')->label('Encryption')->options(['tls' => 'TLS', 'ssl' => 'SSL']) }} + {{ Former::text('mail[from][name]')->label('From Name') }} + {{ Former::text('mail[username]')->label('Email') }} + {{ Former::password('mail[password]')->label('Password') }} + {{ Former::actions( Button::normal('Send test email', ['onclick' => 'testMail()']), '  ' ) }} +
    +
    + + +
    +
    +

    User Details

    +
    +
    + {{ Former::text('first_name') }} + {{ Former::text('last_name') }} + {{ Former::text('email') }} + {{ Former::password('password') }} +
    +
    + + {{ Former::checkbox('terms_checkbox')->label(' ')->text(trans('texts.agree_to_terms', ['terms' => ''.trans('texts.terms_of_service').''])) }} + {{ Former::actions( Button::submit_lg('Submit') ) }} + {{ Former::close() }} + +
    + + + + + \ No newline at end of file diff --git a/resources/views/timesheets/edit.blade.php b/resources/views/timesheets/edit.blade.php new file mode 100644 index 000000000000..34755559fee0 --- /dev/null +++ b/resources/views/timesheets/edit.blade.php @@ -0,0 +1,76 @@ +@extends('header') + +@section('head') + @parent +@stop + +@section('content') + + +
    +
    + +@stop diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php new file mode 100644 index 000000000000..c88f4b43370f --- /dev/null +++ b/resources/views/users/edit.blade.php @@ -0,0 +1,30 @@ +@extends('accounts.nav') + +@section('content') + @parent + @include('accounts.nav_advanced') + + {{ Former::open($url)->method($method)->addClass('col-md-8 col-md-offset-2 warn-on-exit')->rules(array( + 'first_name' => 'required', + 'last_name' => 'required', + 'email' => 'required|email', + )); }} + + {{ Former::legend($title) }} + + @if ($user) + {{ Former::populate($user) }} + @endif + + {{ Former::text('first_name') }} + {{ Former::text('last_name') }} + {{ Former::text('email') }} + + {{ Former::actions( + Button::lg_success_submit(trans($user && $user->confirmed ? 'texts.save' : 'texts.send_invite'))->append_with_icon($user && $user->confirmed ? 'floppy-disk' : 'send'), + Button::lg_default_link('company/advanced_settings/user_management', trans('texts.cancel'))->append_with_icon('remove-circle') + )}} + + {{ Former::close() }} + +@stop \ No newline at end of file diff --git a/resources/views/users/forgot_password.blade.php b/resources/views/users/forgot_password.blade.php new file mode 100644 index 000000000000..c40dae6a9cd0 --- /dev/null +++ b/resources/views/users/forgot_password.blade.php @@ -0,0 +1,86 @@ +@extends('master') + +@section('head') + + + + + + +@stop + +@section('body') +
    + +{{ Former::open('forgot_password')->rules(['email' => 'required|email'])->addClass('form-signin') }} + +
    + +

    + {{ Former::text('email')->placeholder(trans('texts.email_address'))->raw() }} +

    + +

    {{ Button::success_submit(trans('texts.send_email'), array('class' => 'btn-lg'))->block() }}

    + + + @if (Session::has('warning')) +
    {{ Session::get('warning') }}
    + @endif + + @if (Session::has('message')) +
    {{ Session::get('message') }}
    + @endif + + @if (Session::has('error')) +
    {{ Session::get('error') }}
    + @endif + + {{ Former::close() }} + +
    +
    + +@stop \ No newline at end of file diff --git a/resources/views/users/login.blade.php b/resources/views/users/login.blade.php new file mode 100644 index 000000000000..085575fd4350 --- /dev/null +++ b/resources/views/users/login.blade.php @@ -0,0 +1,119 @@ +@extends('master') + +@section('head') + + + + + + +@stop + +@section('body') +
    + + + {{ Former::open('login')->rules(['login_email' => 'required|email', 'login_password' => 'required'])->addClass('form-signin') }} + +
    +

    + {{ $errors->first('login_email') }} + {{ $errors->first('login_password') }} +

    + +

    + {{ Former::text('login_email')->placeholder(trans('texts.email_address'))->raw() }} + {{ Former::password('login_password')->placeholder(trans('texts.password'))->raw() }} +

    + +

    {{ Button::success_submit(trans('texts.lets_go'), array('class' => 'btn-lg'))->block() }}

    + + + + + @if (Session::has('warning')) +
    {{ Session::get('warning') }}
    + @endif + + @if (Session::has('message')) +
    {{ Session::get('message') }}
    + @endif + + @if (Session::has('error')) +
    {{ Session::get('error') }}
    + @endif + +
    + + {{ Former::close() }} + + @if (!Utils::isNinja()) +

    +

    +
    + + +
       + + + + + +
    + @endif + +
    + + @stop \ No newline at end of file diff --git a/resources/views/users/reset_password.blade.php b/resources/views/users/reset_password.blade.php new file mode 100644 index 000000000000..1c4e7750b503 --- /dev/null +++ b/resources/views/users/reset_password.blade.php @@ -0,0 +1,95 @@ +@extends('master') + +@section('head') + + + + + + +@stop + +@section('body') +
    + + {{ Former::open('user/reset')->addClass('form-signin')->rules(array( + 'password' => 'required', + 'password_confirmation' => 'required', + )); }} + + +
    + + + +

    + {{ Former::password('password')->placeholder(trans('texts.password'))->raw() }} + {{ Former::password('password_confirmation')->placeholder(trans('texts.confirm_password'))->raw() }} + +

    + +

    {{ Button::success_submit(trans('texts.save'), array('class' => 'btn-lg'))->block() }}

    + + + @if (Session::has('warning')) +
    {{ Session::get('warning') }}
    + @endif + + @if (Session::has('message')) +
    {{ Session::get('message') }}
    + @endif + + @if (Session::has('error')) +
    {{ Session::get('error') }}
    + @endif + + + {{ Former::close() }} +
    + +
    + +@stop \ No newline at end of file diff --git a/tests/TimesheetUtilsTest.php b/tests/TimesheetUtilsTest.php new file mode 100644 index 000000000000..ccfefef42849 --- /dev/null +++ b/tests/TimesheetUtilsTest.php @@ -0,0 +1,26 @@ +assertSame(null, $code); + + list($code, $tags, $title) = TimesheetUtils::parseEventSummary('Test:'); + $this->assertSame("TEST", $code); + + list($code, $tags, $title) = TimesheetUtils::parseEventSummary('Test: '); + $this->assertSame("TEST", $code); + + list($code, $tags, $title) = TimesheetUtils::parseEventSummary('Test::'); + $this->assertSame("TEST", $code); + + list($code, $tags, $title) = TimesheetUtils::parseEventSummary('TEST: Hello :)'); + $this->assertSame("TEST", $code); + + list($code, $tags, $title) = TimesheetUtils::parseEventSummary('Test/tags: '); + $this->assertSame('TEST', $code); + $this->assertSame('tags', $tags); + } + +} diff --git a/tests/data/Demo/demo.response.json b/tests/data/Demo/demo.response.json new file mode 100644 index 000000000000..21ff1e1c096b --- /dev/null +++ b/tests/data/Demo/demo.response.json @@ -0,0 +1,5 @@ +{ + "clients":[{"name":"IBM","balance":"0.00","paid_to_date":"13.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-18 00:00:00","invoice_number":"0001","amount":"13.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"13.00","qty":"1.00"}],"displayName":"0001","displayTotal":13,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"1"}],"displayName":"IBM","displayTotal":13,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Nestle","balance":null,"paid_to_date":null,"invoices":[],"contacts":[{"public_id":"2"}],"displayName":"Nestle","displayTotal":0,"displayBalance":0,"displayPercent":"NaN","displayAge":null},{"name":"Mitsubishi UFJ Financial","balance":"0.00","paid_to_date":"1701.00","invoices":[{"invoice_status_id":"5","created_at":"2014-06-29 00:00:00","invoice_number":"0002","amount":"85.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"85.00","qty":"1.00"}],"displayName":"0002","displayTotal":85,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-11 00:00:00","invoice_number":"0003","amount":"142.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"142.00","qty":"1.00"}],"displayName":"0003","displayTotal":142,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-19 00:00:00","invoice_number":"0004","amount":"936.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"936.00","qty":"1.00"}],"displayName":"0004","displayTotal":936,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-19 00:00:00","invoice_number":"0005","amount":"74.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"74.00","qty":"1.00"}],"displayName":"0005","displayTotal":74,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-25 00:00:00","invoice_number":"0006","amount":"101.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"101.00","qty":"1.00"}],"displayName":"0006","displayTotal":101,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-21 00:00:00","invoice_number":"0007","amount":"116.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"116.00","qty":"1.00"}],"displayName":"0007","displayTotal":116,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-17 00:00:00","invoice_number":"0008","amount":"42.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"42.00","qty":"1.00"}],"displayName":"0008","displayTotal":42,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-24 00:00:00","invoice_number":"0009","amount":"66.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"66.00","qty":"1.00"}],"displayName":"0009","displayTotal":66,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-21 00:00:00","invoice_number":"0010","amount":"40.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"40.00","qty":"1.00"}],"displayName":"0010","displayTotal":40,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-25 00:00:00","invoice_number":"0011","amount":"99.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"99.00","qty":"1.00"}],"displayName":"0011","displayTotal":99,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"3"}],"displayName":"Mitsubishi UFJ Financial","displayTotal":1701,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Vodafone","balance":"0.00","paid_to_date":"106.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-26 00:00:00","invoice_number":"0012","amount":"106.00","balance":"0.00","invoice_items":[{"product_key":"Louisiana","cost":"106.00","qty":"1.00"}],"displayName":"0012","displayTotal":106,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"4"}],"displayName":"Vodafone","displayTotal":106,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Eni","balance":"0.00","paid_to_date":"402.00","invoices":[{"invoice_status_id":"5","created_at":"2014-06-29 00:00:00","invoice_number":"0013","amount":"18.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"18.00","qty":"1.00"}],"displayName":"0013","displayTotal":18,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-04 00:00:00","invoice_number":"0014","amount":"70.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"70.00","qty":"1.00"}],"displayName":"0014","displayTotal":70,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-08 00:00:00","invoice_number":"0015","amount":"59.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"59.00","qty":"1.00"}],"displayName":"0015","displayTotal":59,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-25 00:00:00","invoice_number":"0016","amount":"18.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"18.00","qty":"1.00"}],"displayName":"0016","displayTotal":18,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-04 00:00:00","invoice_number":"0017","amount":"61.00","balance":"0.00","invoice_items":[{"product_key":"Maine","cost":"61.00","qty":"1.00"}],"displayName":"0017","displayTotal":61,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-16 00:00:00","invoice_number":"0018","amount":"65.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"65.00","qty":"1.00"}],"displayName":"0018","displayTotal":65,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-24 00:00:00","invoice_number":"0019","amount":"39.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"39.00","qty":"1.00"}],"displayName":"0019","displayTotal":39,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-31 00:00:00","invoice_number":"0020","amount":"72.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"72.00","qty":"1.00"}],"displayName":"0020","displayTotal":72,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"5"}],"displayName":"Eni","displayTotal":402,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Procter & Gamble","balance":"0.00","paid_to_date":"251.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-12 00:00:00","invoice_number":"0021","amount":"48.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"48.00","qty":"1.00"}],"displayName":"0021","displayTotal":48,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-24 00:00:00","invoice_number":"0022","amount":"90.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"90.00","qty":"1.00"}],"displayName":"0022","displayTotal":90,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-31 00:00:00","invoice_number":"0023","amount":"70.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"70.00","qty":"1.00"}],"displayName":"0023","displayTotal":70,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-07 00:00:00","invoice_number":"0024","amount":"43.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"43.00","qty":"1.00"}],"displayName":"0024","displayTotal":43,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"6"}],"displayName":"Procter & Gamble","displayTotal":251,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Johnson & Johnson","balance":"485.00","paid_to_date":"2188.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-06 00:00:00","invoice_number":"0025","amount":"137.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"137.00","qty":"1.00"}],"displayName":"0025","displayTotal":137,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-30 00:00:00","invoice_number":"0026","amount":"92.00","balance":"92.00","invoice_items":[{"product_key":"Iowa","cost":"92.00","qty":"1.00"}],"displayName":"0026","displayTotal":92,"displayBalance":92,"displayPercent":0,"displayAge":3},{"invoice_status_id":"1","created_at":"2014-08-11 00:00:00","invoice_number":"0027","amount":"95.00","balance":"95.00","invoice_items":[{"product_key":"Arizona","cost":"95.00","qty":"1.00"}],"displayName":"0027","displayTotal":95,"displayBalance":95,"displayPercent":0,"displayAge":53},{"invoice_status_id":"1","created_at":"2014-07-28 00:00:00","invoice_number":"0028","amount":"25.00","balance":"25.00","invoice_items":[{"product_key":"Massachusetts","cost":"25.00","qty":"1.00"}],"displayName":"0028","displayTotal":25,"displayBalance":25,"displayPercent":0,"displayAge":67},{"invoice_status_id":"5","created_at":"2014-09-04 00:00:00","invoice_number":"0029","amount":"966.00","balance":"0.00","invoice_items":[{"product_key":"Iowa","cost":"966.00","qty":"1.00"}],"displayName":"0029","displayTotal":966,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-16 00:00:00","invoice_number":"0030","amount":"91.00","balance":"91.00","invoice_items":[{"product_key":"Arizona","cost":"91.00","qty":"1.00"}],"displayName":"0030","displayTotal":91,"displayBalance":91,"displayPercent":0,"displayAge":17},{"invoice_status_id":"5","created_at":"2014-09-03 00:00:00","invoice_number":"0031","amount":"134.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"134.00","qty":"1.00"}],"displayName":"0031","displayTotal":134,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-08 00:00:00","invoice_number":"0032","amount":"102.00","balance":"102.00","invoice_items":[{"product_key":"Colorado","cost":"102.00","qty":"1.00"}],"displayName":"0032","displayTotal":102,"displayBalance":102,"displayPercent":0,"displayAge":87},{"invoice_status_id":"1","created_at":"2014-09-17 00:00:00","invoice_number":"0033","amount":"80.00","balance":"80.00","invoice_items":[{"product_key":"New York","cost":"80.00","qty":"1.00"}],"displayName":"0033","displayTotal":80,"displayBalance":80,"displayPercent":0,"displayAge":16},{"invoice_status_id":"5","created_at":"2014-07-23 00:00:00","invoice_number":"0034","amount":"951.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"951.00","qty":"1.00"}],"displayName":"0034","displayTotal":951,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"7"}],"displayName":"Johnson & Johnson","displayTotal":2673,"displayBalance":485,"displayPercent":"0.82","displayAge":87},{"name":"American International Group","balance":"0.00","paid_to_date":"94.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-23 00:00:00","invoice_number":"0035","amount":"94.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"94.00","qty":"1.00"}],"displayName":"0035","displayTotal":94,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"8"}],"displayName":"American International Group","displayTotal":94,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Banco Santander","balance":"0.00","paid_to_date":"137.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-13 00:00:00","invoice_number":"0036","amount":"137.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"137.00","qty":"1.00"}],"displayName":"0036","displayTotal":137,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"9"}],"displayName":"Banco Santander","displayTotal":137,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"BHP Billiton","balance":"2584.00","paid_to_date":"284.00","invoices":[{"invoice_status_id":"1","created_at":"2014-06-24 00:00:00","invoice_number":"0037","amount":"122.00","balance":"122.00","invoice_items":[{"product_key":"Alabama","cost":"122.00","qty":"1.00"}],"displayName":"0037","displayTotal":122,"displayBalance":122,"displayPercent":0,"displayAge":101},{"invoice_status_id":"1","created_at":"2014-09-25 00:00:00","invoice_number":"0038","amount":"44.00","balance":"44.00","invoice_items":[{"product_key":"Arizona","cost":"44.00","qty":"1.00"}],"displayName":"0038","displayTotal":44,"displayBalance":44,"displayPercent":0,"displayAge":8},{"invoice_status_id":"1","created_at":"2014-08-13 00:00:00","invoice_number":"0039","amount":"68.00","balance":"68.00","invoice_items":[{"product_key":"Arizona","cost":"68.00","qty":"1.00"}],"displayName":"0039","displayTotal":68,"displayBalance":68,"displayPercent":0,"displayAge":51},{"invoice_status_id":"1","created_at":"2014-07-23 00:00:00","invoice_number":"0040","amount":"23.00","balance":"23.00","invoice_items":[{"product_key":"Delaware","cost":"23.00","qty":"1.00"}],"displayName":"0040","displayTotal":23,"displayBalance":23,"displayPercent":0,"displayAge":72},{"invoice_status_id":"1","created_at":"2014-07-06 00:00:00","invoice_number":"0041","amount":"61.00","balance":"61.00","invoice_items":[{"product_key":"Colorado","cost":"61.00","qty":"1.00"}],"displayName":"0041","displayTotal":61,"displayBalance":61,"displayPercent":0,"displayAge":89},{"invoice_status_id":"1","created_at":"2014-09-05 00:00:00","invoice_number":"0042","amount":"128.00","balance":"128.00","invoice_items":[{"product_key":"Arizona","cost":"128.00","qty":"1.00"}],"displayName":"0042","displayTotal":128,"displayBalance":128,"displayPercent":0,"displayAge":28},{"invoice_status_id":"5","created_at":"2014-07-17 00:00:00","invoice_number":"0043","amount":"130.00","balance":"0.00","invoice_items":[{"product_key":"Iowa","cost":"130.00","qty":"1.00"}],"displayName":"0043","displayTotal":130,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-01 00:00:00","invoice_number":"0044","amount":"139.00","balance":"139.00","invoice_items":[{"product_key":"Arizona","cost":"139.00","qty":"1.00"}],"displayName":"0044","displayTotal":139,"displayBalance":139,"displayPercent":0,"displayAge":94},{"invoice_status_id":"1","created_at":"2014-07-20 00:00:00","invoice_number":"0045","amount":"127.00","balance":"127.00","invoice_items":[{"product_key":"California","cost":"127.00","qty":"1.00"}],"displayName":"0045","displayTotal":127,"displayBalance":127,"displayPercent":0,"displayAge":75},{"invoice_status_id":"1","created_at":"2014-09-15 00:00:00","invoice_number":"0046","amount":"83.00","balance":"83.00","invoice_items":[{"product_key":"Michigan","cost":"83.00","qty":"1.00"}],"displayName":"0046","displayTotal":83,"displayBalance":83,"displayPercent":0,"displayAge":18},{"invoice_status_id":"1","created_at":"2014-07-30 00:00:00","invoice_number":"0047","amount":"62.00","balance":"62.00","invoice_items":[{"product_key":"Florida","cost":"62.00","qty":"1.00"}],"displayName":"0047","displayTotal":62,"displayBalance":62,"displayPercent":0,"displayAge":65},{"invoice_status_id":"1","created_at":"2014-09-16 00:00:00","invoice_number":"0048","amount":"902.00","balance":"902.00","invoice_items":[{"product_key":"New York","cost":"902.00","qty":"1.00"}],"displayName":"0048","displayTotal":902,"displayBalance":902,"displayPercent":0,"displayAge":17},{"invoice_status_id":"1","created_at":"2014-08-07 00:00:00","invoice_number":"0049","amount":"139.00","balance":"139.00","invoice_items":[{"product_key":"Arizona","cost":"139.00","qty":"1.00"}],"displayName":"0049","displayTotal":139,"displayBalance":139,"displayPercent":0,"displayAge":57},{"invoice_status_id":"1","created_at":"2014-07-12 00:00:00","invoice_number":"0050","amount":"124.00","balance":"124.00","invoice_items":[{"product_key":"Arizona","cost":"124.00","qty":"1.00"}],"displayName":"0050","displayTotal":124,"displayBalance":124,"displayPercent":0,"displayAge":83},{"invoice_status_id":"1","created_at":"2014-08-05 00:00:00","invoice_number":"0051","amount":"53.00","balance":"53.00","invoice_items":[{"product_key":"Connecticut","cost":"53.00","qty":"1.00"}],"displayName":"0051","displayTotal":53,"displayBalance":53,"displayPercent":0,"displayAge":59},{"invoice_status_id":"1","created_at":"2014-06-27 00:00:00","invoice_number":"0052","amount":"52.00","balance":"52.00","invoice_items":[{"product_key":"Michigan","cost":"52.00","qty":"1.00"}],"displayName":"0052","displayTotal":52,"displayBalance":52,"displayPercent":0,"displayAge":98},{"invoice_status_id":"1","created_at":"2014-09-04 00:00:00","invoice_number":"0053","amount":"28.00","balance":"28.00","invoice_items":[{"product_key":"New York","cost":"28.00","qty":"1.00"}],"displayName":"0053","displayTotal":28,"displayBalance":28,"displayPercent":0,"displayAge":29},{"invoice_status_id":"1","created_at":"2014-07-28 00:00:00","invoice_number":"0054","amount":"36.00","balance":"36.00","invoice_items":[{"product_key":"Alabama","cost":"36.00","qty":"1.00"}],"displayName":"0054","displayTotal":36,"displayBalance":36,"displayPercent":0,"displayAge":67},{"invoice_status_id":"1","created_at":"2014-08-28 00:00:00","invoice_number":"0055","amount":"111.00","balance":"111.00","invoice_items":[{"product_key":"New York","cost":"111.00","qty":"1.00"}],"displayName":"0055","displayTotal":111,"displayBalance":111,"displayPercent":0,"displayAge":36},{"invoice_status_id":"5","created_at":"2014-08-14 00:00:00","invoice_number":"0056","amount":"43.00","balance":"0.00","invoice_items":[{"product_key":"Delaware","cost":"43.00","qty":"1.00"}],"displayName":"0056","displayTotal":43,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-23 00:00:00","invoice_number":"0057","amount":"111.00","balance":"0.00","invoice_items":[{"product_key":"Idaho","cost":"111.00","qty":"1.00"}],"displayName":"0057","displayTotal":111,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-01 00:00:00","invoice_number":"0058","amount":"40.00","balance":"40.00","invoice_items":[{"product_key":"Massachusetts","cost":"40.00","qty":"1.00"}],"displayName":"0058","displayTotal":40,"displayBalance":40,"displayPercent":0,"displayAge":32},{"invoice_status_id":"1","created_at":"2014-09-21 00:00:00","invoice_number":"0059","amount":"116.00","balance":"116.00","invoice_items":[{"product_key":"Maryland","cost":"116.00","qty":"1.00"}],"displayName":"0059","displayTotal":116,"displayBalance":116,"displayPercent":0,"displayAge":12},{"invoice_status_id":"1","created_at":"2014-07-10 00:00:00","invoice_number":"0060","amount":"101.00","balance":"101.00","invoice_items":[{"product_key":"California","cost":"101.00","qty":"1.00"}],"displayName":"0060","displayTotal":101,"displayBalance":101,"displayPercent":0,"displayAge":85},{"invoice_status_id":"1","created_at":"2014-07-19 00:00:00","invoice_number":"0061","amount":"25.00","balance":"25.00","invoice_items":[{"product_key":"New York","cost":"25.00","qty":"1.00"}],"displayName":"0061","displayTotal":25,"displayBalance":25,"displayPercent":0,"displayAge":76}],"contacts":[{"public_id":"10"}],"displayName":"BHP Billiton","displayTotal":2868,"displayBalance":2584,"displayPercent":"0.10","displayAge":101},{"name":"Pfizer","balance":"0.00","paid_to_date":"119.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-08 00:00:00","invoice_number":"0062","amount":"119.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"119.00","qty":"1.00"}],"displayName":"0062","displayTotal":119,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"11"}],"displayName":"Pfizer","displayTotal":119,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Itaú Unibanco Holding","balance":null,"paid_to_date":null,"invoices":[],"contacts":[{"public_id":"12"}],"displayName":"Itaú Unibanco Holding","displayTotal":0,"displayBalance":0,"displayPercent":"NaN","displayAge":null},{"name":"Ford Motor","balance":"42.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-07-21 00:00:00","invoice_number":"0063","amount":"42.00","balance":"42.00","invoice_items":[{"product_key":"California","cost":"42.00","qty":"1.00"}],"displayName":"0063","displayTotal":42,"displayBalance":42,"displayPercent":0,"displayAge":74}],"contacts":[{"public_id":"13"}],"displayName":"Ford Motor","displayTotal":42,"displayBalance":42,"displayPercent":"0.00","displayAge":74},{"name":"BMW Group","balance":"0.00","paid_to_date":"34.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-17 00:00:00","invoice_number":"0064","amount":"34.00","balance":"0.00","invoice_items":[{"product_key":"Michigan","cost":"34.00","qty":"1.00"}],"displayName":"0064","displayTotal":34,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"14"}],"displayName":"BMW Group","displayTotal":34,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Commonwealth Bank","balance":null,"paid_to_date":null,"invoices":[],"contacts":[{"public_id":"15"}],"displayName":"Commonwealth Bank","displayTotal":0,"displayBalance":0,"displayPercent":"NaN","displayAge":null},{"name":"EDF","balance":"0.00","paid_to_date":"108.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-03 00:00:00","invoice_number":"0065","amount":"108.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"108.00","qty":"1.00"}],"displayName":"0065","displayTotal":108,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"16"}],"displayName":"EDF","displayTotal":108,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Statoil","balance":"0.00","paid_to_date":"38.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-29 00:00:00","invoice_number":"0066","amount":"38.00","balance":"0.00","invoice_items":[{"product_key":"Delaware","cost":"38.00","qty":"1.00"}],"displayName":"0066","displayTotal":38,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"17"}],"displayName":"Statoil","displayTotal":38,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Google","balance":"0.00","paid_to_date":"5537.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0067","amount":"11.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"11.00","qty":"1.00"}],"displayName":"0067","displayTotal":11,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-02 00:00:00","invoice_number":"0068","amount":"128.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"128.00","qty":"1.00"}],"displayName":"0068","displayTotal":128,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-05 00:00:00","invoice_number":"0069","amount":"959.00","balance":"0.00","invoice_items":[{"product_key":"Louisiana","cost":"959.00","qty":"1.00"}],"displayName":"0069","displayTotal":959,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0070","amount":"116.00","balance":"0.00","invoice_items":[{"product_key":"Idaho","cost":"116.00","qty":"1.00"}],"displayName":"0070","displayTotal":116,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-04 00:00:00","invoice_number":"0071","amount":"50.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"50.00","qty":"1.00"}],"displayName":"0071","displayTotal":50,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-11 00:00:00","invoice_number":"0072","amount":"23.00","balance":"0.00","invoice_items":[{"product_key":"Maryland","cost":"23.00","qty":"1.00"}],"displayName":"0072","displayTotal":23,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-28 00:00:00","invoice_number":"0073","amount":"125.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"125.00","qty":"1.00"}],"displayName":"0073","displayTotal":125,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-28 00:00:00","invoice_number":"0074","amount":"981.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"981.00","qty":"1.00"}],"displayName":"0074","displayTotal":981,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-12 00:00:00","invoice_number":"0075","amount":"34.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"34.00","qty":"1.00"}],"displayName":"0075","displayTotal":34,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-15 00:00:00","invoice_number":"0076","amount":"24.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"24.00","qty":"1.00"}],"displayName":"0076","displayTotal":24,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-19 00:00:00","invoice_number":"0077","amount":"107.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"107.00","qty":"1.00"}],"displayName":"0077","displayTotal":107,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-21 00:00:00","invoice_number":"0078","amount":"950.00","balance":"0.00","invoice_items":[{"product_key":"Kentucky","cost":"950.00","qty":"1.00"}],"displayName":"0078","displayTotal":950,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-27 00:00:00","invoice_number":"0079","amount":"148.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"148.00","qty":"1.00"}],"displayName":"0079","displayTotal":148,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-22 00:00:00","invoice_number":"0080","amount":"22.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"22.00","qty":"1.00"}],"displayName":"0080","displayTotal":22,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-22 00:00:00","invoice_number":"0081","amount":"105.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"105.00","qty":"1.00"}],"displayName":"0081","displayTotal":105,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-02 00:00:00","invoice_number":"0082","amount":"19.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"19.00","qty":"1.00"}],"displayName":"0082","displayTotal":19,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-15 00:00:00","invoice_number":"0083","amount":"102.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"102.00","qty":"1.00"}],"displayName":"0083","displayTotal":102,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-06-27 00:00:00","invoice_number":"0084","amount":"105.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"105.00","qty":"1.00"}],"displayName":"0084","displayTotal":105,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-07 00:00:00","invoice_number":"0085","amount":"138.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"138.00","qty":"1.00"}],"displayName":"0085","displayTotal":138,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-15 00:00:00","invoice_number":"0086","amount":"86.00","balance":"0.00","invoice_items":[{"product_key":"Louisiana","cost":"86.00","qty":"1.00"}],"displayName":"0086","displayTotal":86,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-14 00:00:00","invoice_number":"0087","amount":"59.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"59.00","qty":"1.00"}],"displayName":"0087","displayTotal":59,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-22 00:00:00","invoice_number":"0088","amount":"129.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"129.00","qty":"1.00"}],"displayName":"0088","displayTotal":129,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-06 00:00:00","invoice_number":"0089","amount":"107.00","balance":"0.00","invoice_items":[{"product_key":"Iowa","cost":"107.00","qty":"1.00"}],"displayName":"0089","displayTotal":107,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-07 00:00:00","invoice_number":"0090","amount":"998.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"998.00","qty":"1.00"}],"displayName":"0090","displayTotal":998,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-17 00:00:00","invoice_number":"0091","amount":"11.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"11.00","qty":"1.00"}],"displayName":"0091","displayTotal":11,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"18"}],"displayName":"Google","displayTotal":5537,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Siemens","balance":"0.00","paid_to_date":"57.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-16 00:00:00","invoice_number":"0092","amount":"57.00","balance":"0.00","invoice_items":[{"product_key":"Idaho","cost":"57.00","qty":"1.00"}],"displayName":"0092","displayTotal":57,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"19"}],"displayName":"Siemens","displayTotal":57,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Novartis","balance":"0.00","paid_to_date":"32.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-29 00:00:00","invoice_number":"0093","amount":"32.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"32.00","qty":"1.00"}],"displayName":"0093","displayTotal":32,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"20"}],"displayName":"Novartis","displayTotal":32,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Royal Bank of Canada","balance":null,"paid_to_date":null,"invoices":[],"contacts":[{"public_id":"21"}],"displayName":"Royal Bank of Canada","displayTotal":0,"displayBalance":0,"displayPercent":"NaN","displayAge":null},{"name":"Sumitomo Mitsui Financial","balance":"0.00","paid_to_date":"108.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-06 00:00:00","invoice_number":"0094","amount":"108.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"108.00","qty":"1.00"}],"displayName":"0094","displayTotal":108,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"22"}],"displayName":"Sumitomo Mitsui Financial","displayTotal":108,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Comcast","balance":"0.00","paid_to_date":"18.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-30 00:00:00","invoice_number":"0095","amount":"18.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"18.00","qty":"1.00"}],"displayName":"0095","displayTotal":18,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"23"}],"displayName":"Comcast","displayTotal":18,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Sberbank","balance":"466.00","paid_to_date":"127.00","invoices":[{"invoice_status_id":"1","created_at":"2014-07-27 00:00:00","invoice_number":"0096","amount":"135.00","balance":"135.00","invoice_items":[{"product_key":"New York","cost":"135.00","qty":"1.00"}],"displayName":"0096","displayTotal":135,"displayBalance":135,"displayPercent":0,"displayAge":68},{"invoice_status_id":"1","created_at":"2014-09-29 00:00:00","invoice_number":"0097","amount":"133.00","balance":"133.00","invoice_items":[{"product_key":"New York","cost":"133.00","qty":"1.00"}],"displayName":"0097","displayTotal":133,"displayBalance":133,"displayPercent":0,"displayAge":4},{"invoice_status_id":"1","created_at":"2014-09-24 00:00:00","invoice_number":"0098","amount":"118.00","balance":"118.00","invoice_items":[{"product_key":"Colorado","cost":"118.00","qty":"1.00"}],"displayName":"0098","displayTotal":118,"displayBalance":118,"displayPercent":0,"displayAge":9},{"invoice_status_id":"5","created_at":"2014-09-15 00:00:00","invoice_number":"0099","amount":"127.00","balance":"0.00","invoice_items":[{"product_key":"Michigan","cost":"127.00","qty":"1.00"}],"displayName":"0099","displayTotal":127,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-08-26 00:00:00","invoice_number":"0100","amount":"80.00","balance":"80.00","invoice_items":[{"product_key":"Maryland","cost":"80.00","qty":"1.00"}],"displayName":"0100","displayTotal":80,"displayBalance":80,"displayPercent":0,"displayAge":38}],"contacts":[{"public_id":"24"}],"displayName":"Sberbank","displayTotal":593,"displayBalance":466,"displayPercent":"0.21","displayAge":68},{"name":"Goldman Sachs Group","balance":"0.00","paid_to_date":"123.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-07 00:00:00","invoice_number":"0101","amount":"123.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"123.00","qty":"1.00"}],"displayName":"0101","displayTotal":123,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"25"}],"displayName":"Goldman Sachs Group","displayTotal":123,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Westpac Banking Group","balance":"0.00","paid_to_date":"116.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-05 00:00:00","invoice_number":"0102","amount":"116.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"116.00","qty":"1.00"}],"displayName":"0102","displayTotal":116,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"26"}],"displayName":"Westpac Banking Group","displayTotal":116,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Nippon Telegraph & Tel","balance":"0.00","paid_to_date":"36.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-24 00:00:00","invoice_number":"0103","amount":"36.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"36.00","qty":"1.00"}],"displayName":"0103","displayTotal":36,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"27"}],"displayName":"Nippon Telegraph & Tel","displayTotal":36,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Ping An Insurance Group","balance":null,"paid_to_date":null,"invoices":[],"contacts":[{"public_id":"28"}],"displayName":"Ping An Insurance Group","displayTotal":0,"displayBalance":0,"displayPercent":"NaN","displayAge":null},{"name":"Banco Bradesco","balance":"1175.00","paid_to_date":"13.00","invoices":[{"invoice_status_id":"1","created_at":"2014-08-03 00:00:00","invoice_number":"0104","amount":"101.00","balance":"101.00","invoice_items":[{"product_key":"Arizona","cost":"101.00","qty":"1.00"}],"displayName":"0104","displayTotal":101,"displayBalance":101,"displayPercent":0,"displayAge":61},{"invoice_status_id":"1","created_at":"2014-07-06 00:00:00","invoice_number":"0105","amount":"132.00","balance":"132.00","invoice_items":[{"product_key":"Connecticut","cost":"132.00","qty":"1.00"}],"displayName":"0105","displayTotal":132,"displayBalance":132,"displayPercent":0,"displayAge":89},{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0106","amount":"13.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"13.00","qty":"1.00"}],"displayName":"0106","displayTotal":13,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-08 00:00:00","invoice_number":"0107","amount":"942.00","balance":"942.00","invoice_items":[{"product_key":"Arizona","cost":"942.00","qty":"1.00"}],"displayName":"0107","displayTotal":942,"displayBalance":942,"displayPercent":0,"displayAge":87}],"contacts":[{"public_id":"29"}],"displayName":"Banco Bradesco","displayTotal":1188,"displayBalance":1175,"displayPercent":"0.01","displayAge":89},{"name":"Anheuser-Busch InBev","balance":"0.00","paid_to_date":"38.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-20 00:00:00","invoice_number":"0108","amount":"38.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"38.00","qty":"1.00"}],"displayName":"0108","displayTotal":38,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"30"}],"displayName":"Anheuser-Busch InBev","displayTotal":38,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Bank of Communications","balance":"0.00","paid_to_date":"145.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-27 00:00:00","invoice_number":"0109","amount":"145.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"145.00","qty":"1.00"}],"displayName":"0109","displayTotal":145,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"31"}],"displayName":"Bank of Communications","displayTotal":145,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"China Life Insurance","balance":"0.00","paid_to_date":"93.00","invoices":[{"invoice_status_id":"5","created_at":"2014-06-27 00:00:00","invoice_number":"0110","amount":"93.00","balance":"0.00","invoice_items":[{"product_key":"Michigan","cost":"93.00","qty":"1.00"}],"displayName":"0110","displayTotal":93,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"32"}],"displayName":"China Life Insurance","displayTotal":93,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"General Motors","balance":"0.00","paid_to_date":"94.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-21 00:00:00","invoice_number":"0111","amount":"94.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"94.00","qty":"1.00"}],"displayName":"0111","displayTotal":94,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"33"}],"displayName":"General Motors","displayTotal":94,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Telefónica","balance":"41.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-07-10 00:00:00","invoice_number":"0112","amount":"41.00","balance":"41.00","invoice_items":[{"product_key":"California","cost":"41.00","qty":"1.00"}],"displayName":"0112","displayTotal":41,"displayBalance":41,"displayPercent":0,"displayAge":85}],"contacts":[{"public_id":"34"}],"displayName":"Telefónica","displayTotal":41,"displayBalance":41,"displayPercent":"0.00","displayAge":85},{"name":"MetLife","balance":"0.00","paid_to_date":"3253.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-25 00:00:00","invoice_number":"0113","amount":"43.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"43.00","qty":"1.00"}],"displayName":"0113","displayTotal":43,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-03 00:00:00","invoice_number":"0114","amount":"980.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"980.00","qty":"1.00"}],"displayName":"0114","displayTotal":980,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-11 00:00:00","invoice_number":"0115","amount":"903.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"903.00","qty":"1.00"}],"displayName":"0115","displayTotal":903,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-18 00:00:00","invoice_number":"0116","amount":"44.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"44.00","qty":"1.00"}],"displayName":"0116","displayTotal":44,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-30 00:00:00","invoice_number":"0117","amount":"17.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"17.00","qty":"1.00"}],"displayName":"0117","displayTotal":17,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-17 00:00:00","invoice_number":"0118","amount":"133.00","balance":"0.00","invoice_items":[{"product_key":"Michigan","cost":"133.00","qty":"1.00"}],"displayName":"0118","displayTotal":133,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0119","amount":"25.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"25.00","qty":"1.00"}],"displayName":"0119","displayTotal":25,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-12 00:00:00","invoice_number":"0120","amount":"982.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"982.00","qty":"1.00"}],"displayName":"0120","displayTotal":982,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-29 00:00:00","invoice_number":"0121","amount":"57.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"57.00","qty":"1.00"}],"displayName":"0121","displayTotal":57,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-16 00:00:00","invoice_number":"0122","amount":"69.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"69.00","qty":"1.00"}],"displayName":"0122","displayTotal":69,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"35"}],"displayName":"MetLife","displayTotal":3253,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Honda Motor","balance":"14.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-09-30 00:00:00","invoice_number":"0123","amount":"14.00","balance":"14.00","invoice_items":[{"product_key":"California","cost":"14.00","qty":"1.00"}],"displayName":"0123","displayTotal":14,"displayBalance":14,"displayPercent":0,"displayAge":3}],"contacts":[{"public_id":"36"}],"displayName":"Honda Motor","displayTotal":14,"displayBalance":14,"displayPercent":"0.00","displayAge":3},{"name":"Enel","balance":"0.00","paid_to_date":"105.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-19 00:00:00","invoice_number":"0124","amount":"105.00","balance":"0.00","invoice_items":[{"product_key":"Delaware","cost":"105.00","qty":"1.00"}],"displayName":"0124","displayTotal":105,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"37"}],"displayName":"Enel","displayTotal":105,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"BASF","balance":null,"paid_to_date":null,"invoices":[],"contacts":[{"public_id":"38"}],"displayName":"BASF","displayTotal":0,"displayBalance":0,"displayPercent":"NaN","displayAge":null},{"name":"Softbank","balance":"68.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-09-28 00:00:00","invoice_number":"0125","amount":"68.00","balance":"68.00","invoice_items":[{"product_key":"Iowa","cost":"68.00","qty":"1.00"}],"displayName":"0125","displayTotal":68,"displayBalance":68,"displayPercent":0,"displayAge":5}],"contacts":[{"public_id":"39"}],"displayName":"Softbank","displayTotal":68,"displayBalance":68,"displayPercent":"0.00","displayAge":5},{"name":"National Australia Bank","balance":"573.00","paid_to_date":"201.00","invoices":[{"invoice_status_id":"1","created_at":"2014-08-17 00:00:00","invoice_number":"0126","amount":"98.00","balance":"98.00","invoice_items":[{"product_key":"Arizona","cost":"98.00","qty":"1.00"}],"displayName":"0126","displayTotal":98,"displayBalance":98,"displayPercent":0,"displayAge":47},{"invoice_status_id":"1","created_at":"2014-09-16 00:00:00","invoice_number":"0127","amount":"68.00","balance":"68.00","invoice_items":[{"product_key":"Maine","cost":"68.00","qty":"1.00"}],"displayName":"0127","displayTotal":68,"displayBalance":68,"displayPercent":0,"displayAge":17},{"invoice_status_id":"1","created_at":"2014-09-30 00:00:00","invoice_number":"0128","amount":"120.00","balance":"120.00","invoice_items":[{"product_key":"New York","cost":"120.00","qty":"1.00"}],"displayName":"0128","displayTotal":120,"displayBalance":120,"displayPercent":0,"displayAge":3},{"invoice_status_id":"5","created_at":"2014-08-08 00:00:00","invoice_number":"0129","amount":"105.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"105.00","qty":"1.00"}],"displayName":"0129","displayTotal":105,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-16 00:00:00","invoice_number":"0130","amount":"117.00","balance":"117.00","invoice_items":[{"product_key":"California","cost":"117.00","qty":"1.00"}],"displayName":"0130","displayTotal":117,"displayBalance":117,"displayPercent":0,"displayAge":17},{"invoice_status_id":"1","created_at":"2014-07-08 00:00:00","invoice_number":"0131","amount":"32.00","balance":"32.00","invoice_items":[{"product_key":"Colorado","cost":"32.00","qty":"1.00"}],"displayName":"0131","displayTotal":32,"displayBalance":32,"displayPercent":0,"displayAge":87},{"invoice_status_id":"1","created_at":"2014-07-05 00:00:00","invoice_number":"0132","amount":"35.00","balance":"35.00","invoice_items":[{"product_key":"Arizona","cost":"35.00","qty":"1.00"}],"displayName":"0132","displayTotal":35,"displayBalance":35,"displayPercent":0,"displayAge":90},{"invoice_status_id":"5","created_at":"2014-07-10 00:00:00","invoice_number":"0133","amount":"14.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"14.00","qty":"1.00"}],"displayName":"0133","displayTotal":14,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-12 00:00:00","invoice_number":"0134","amount":"82.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"82.00","qty":"1.00"}],"displayName":"0134","displayTotal":82,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-20 00:00:00","invoice_number":"0135","amount":"103.00","balance":"103.00","invoice_items":[{"product_key":"Arizona","cost":"103.00","qty":"1.00"}],"displayName":"0135","displayTotal":103,"displayBalance":103,"displayPercent":0,"displayAge":75}],"contacts":[{"public_id":"40"}],"displayName":"National Australia Bank","displayTotal":774,"displayBalance":573,"displayPercent":"0.26","displayAge":90},{"name":"ANZ","balance":"49.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-06-26 00:00:00","invoice_number":"0136","amount":"49.00","balance":"49.00","invoice_items":[{"product_key":"Massachusetts","cost":"49.00","qty":"1.00"}],"displayName":"0136","displayTotal":49,"displayBalance":49,"displayPercent":0,"displayAge":99}],"contacts":[{"public_id":"41"}],"displayName":"ANZ","displayTotal":49,"displayBalance":49,"displayPercent":"0.00","displayAge":99},{"name":"ConocoPhillips","balance":"0.00","paid_to_date":"20.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-07 00:00:00","invoice_number":"0137","amount":"20.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"20.00","qty":"1.00"}],"displayName":"0137","displayTotal":20,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"42"}],"displayName":"ConocoPhillips","displayTotal":20,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"TD Bank Group","balance":"756.00","paid_to_date":"56.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0138","amount":"56.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"56.00","qty":"1.00"}],"displayName":"0138","displayTotal":56,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-26 00:00:00","invoice_number":"0139","amount":"147.00","balance":"147.00","invoice_items":[{"product_key":"Iowa","cost":"147.00","qty":"1.00"}],"displayName":"0139","displayTotal":147,"displayBalance":147,"displayPercent":0,"displayAge":69},{"invoice_status_id":"1","created_at":"2014-09-06 00:00:00","invoice_number":"0140","amount":"47.00","balance":"47.00","invoice_items":[{"product_key":"California","cost":"47.00","qty":"1.00"}],"displayName":"0140","displayTotal":47,"displayBalance":47,"displayPercent":0,"displayAge":27},{"invoice_status_id":"1","created_at":"2014-08-19 00:00:00","invoice_number":"0141","amount":"147.00","balance":"147.00","invoice_items":[{"product_key":"Colorado","cost":"147.00","qty":"1.00"}],"displayName":"0141","displayTotal":147,"displayBalance":147,"displayPercent":0,"displayAge":45},{"invoice_status_id":"1","created_at":"2014-09-27 00:00:00","invoice_number":"0142","amount":"113.00","balance":"113.00","invoice_items":[{"product_key":"Colorado","cost":"113.00","qty":"1.00"}],"displayName":"0142","displayTotal":113,"displayBalance":113,"displayPercent":0,"displayAge":6},{"invoice_status_id":"1","created_at":"2014-07-01 00:00:00","invoice_number":"0143","amount":"48.00","balance":"48.00","invoice_items":[{"product_key":"Indiana","cost":"48.00","qty":"1.00"}],"displayName":"0143","displayTotal":48,"displayBalance":48,"displayPercent":0,"displayAge":94},{"invoice_status_id":"1","created_at":"2014-08-18 00:00:00","invoice_number":"0144","amount":"137.00","balance":"137.00","invoice_items":[{"product_key":"Arizona","cost":"137.00","qty":"1.00"}],"displayName":"0144","displayTotal":137,"displayBalance":137,"displayPercent":0,"displayAge":46},{"invoice_status_id":"1","created_at":"2014-09-25 00:00:00","invoice_number":"0145","amount":"117.00","balance":"117.00","invoice_items":[{"product_key":"New York","cost":"117.00","qty":"1.00"}],"displayName":"0145","displayTotal":117,"displayBalance":117,"displayPercent":0,"displayAge":8}],"contacts":[{"public_id":"43"}],"displayName":"TD Bank Group","displayTotal":812,"displayBalance":756,"displayPercent":"0.07","displayAge":94},{"name":"Intel","balance":"0.00","paid_to_date":"71.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-24 00:00:00","invoice_number":"0146","amount":"71.00","balance":"0.00","invoice_items":[{"product_key":"Georgia","cost":"71.00","qty":"1.00"}],"displayName":"0146","displayTotal":71,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"44"}],"displayName":"Intel","displayTotal":71,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"UBS","balance":"0.00","paid_to_date":"976.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-06 00:00:00","invoice_number":"0147","amount":"976.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"976.00","qty":"1.00"}],"displayName":"0147","displayTotal":976,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"45"}],"displayName":"UBS","displayTotal":976,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Hewlett-Packard","balance":"0.00","paid_to_date":"501.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-16 00:00:00","invoice_number":"0148","amount":"82.00","balance":"0.00","invoice_items":[{"product_key":"Florida","cost":"82.00","qty":"1.00"}],"displayName":"0148","displayTotal":82,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-22 00:00:00","invoice_number":"0149","amount":"134.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"134.00","qty":"1.00"}],"displayName":"0149","displayTotal":134,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-15 00:00:00","invoice_number":"0150","amount":"147.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"147.00","qty":"1.00"}],"displayName":"0150","displayTotal":147,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-31 00:00:00","invoice_number":"0151","amount":"16.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"16.00","qty":"1.00"}],"displayName":"0151","displayTotal":16,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-17 00:00:00","invoice_number":"0152","amount":"14.00","balance":"0.00","invoice_items":[{"product_key":"Indiana","cost":"14.00","qty":"1.00"}],"displayName":"0152","displayTotal":14,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-12 00:00:00","invoice_number":"0153","amount":"61.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"61.00","qty":"1.00"}],"displayName":"0153","displayTotal":61,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-17 00:00:00","invoice_number":"0154","amount":"47.00","balance":"0.00","invoice_items":[{"product_key":"Indiana","cost":"47.00","qty":"1.00"}],"displayName":"0154","displayTotal":47,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"46"}],"displayName":"Hewlett-Packard","displayTotal":501,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Coca-Cola","balance":"289.00","paid_to_date":"82.00","invoices":[{"invoice_status_id":"1","created_at":"2014-09-10 00:00:00","invoice_number":"0155","amount":"137.00","balance":"137.00","invoice_items":[{"product_key":"California","cost":"137.00","qty":"1.00"}],"displayName":"0155","displayTotal":137,"displayBalance":137,"displayPercent":0,"displayAge":23},{"invoice_status_id":"1","created_at":"2014-07-10 00:00:00","invoice_number":"0156","amount":"76.00","balance":"76.00","invoice_items":[{"product_key":"Massachusetts","cost":"76.00","qty":"1.00"}],"displayName":"0156","displayTotal":76,"displayBalance":76,"displayPercent":0,"displayAge":85},{"invoice_status_id":"5","created_at":"2014-07-26 00:00:00","invoice_number":"0157","amount":"82.00","balance":"0.00","invoice_items":[{"product_key":"Maine","cost":"82.00","qty":"1.00"}],"displayName":"0157","displayTotal":82,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-29 00:00:00","invoice_number":"0158","amount":"76.00","balance":"76.00","invoice_items":[{"product_key":"New York","cost":"76.00","qty":"1.00"}],"displayName":"0158","displayTotal":76,"displayBalance":76,"displayPercent":0,"displayAge":4}],"contacts":[{"public_id":"47"}],"displayName":"Coca-Cola","displayTotal":371,"displayBalance":289,"displayPercent":"0.22","displayAge":85},{"name":"Cisco Systems","balance":"111.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-08-20 00:00:00","invoice_number":"0159","amount":"111.00","balance":"111.00","invoice_items":[{"product_key":"Arizona","cost":"111.00","qty":"1.00"}],"displayName":"0159","displayTotal":111,"displayBalance":111,"displayPercent":0,"displayAge":44}],"contacts":[{"public_id":"48"}],"displayName":"Cisco Systems","displayTotal":111,"displayBalance":111,"displayPercent":"0.00","displayAge":44},{"name":"UnitedHealth Group","balance":"0.00","paid_to_date":"27.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-14 00:00:00","invoice_number":"0160","amount":"27.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"27.00","qty":"1.00"}],"displayName":"0160","displayTotal":27,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"49"}],"displayName":"UnitedHealth Group","displayTotal":27,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Boeing","balance":"47.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-07-17 00:00:00","invoice_number":"0161","amount":"47.00","balance":"47.00","invoice_items":[{"product_key":"Kansas","cost":"47.00","qty":"1.00"}],"displayName":"0161","displayTotal":47,"displayBalance":47,"displayPercent":0,"displayAge":78}],"contacts":[{"public_id":"50"}],"displayName":"Boeing","displayTotal":47,"displayBalance":47,"displayPercent":"0.00","displayAge":78},{"name":"Zurich Insurance Group","balance":"1134.00","paid_to_date":"172.00","invoices":[{"invoice_status_id":"1","created_at":"2014-08-06 00:00:00","invoice_number":"0162","amount":"31.00","balance":"31.00","invoice_items":[{"product_key":"Indiana","cost":"31.00","qty":"1.00"}],"displayName":"0162","displayTotal":31,"displayBalance":31,"displayPercent":0,"displayAge":58},{"invoice_status_id":"1","created_at":"2014-08-06 00:00:00","invoice_number":"0163","amount":"78.00","balance":"78.00","invoice_items":[{"product_key":"California","cost":"78.00","qty":"1.00"}],"displayName":"0163","displayTotal":78,"displayBalance":78,"displayPercent":0,"displayAge":58},{"invoice_status_id":"5","created_at":"2014-09-24 00:00:00","invoice_number":"0164","amount":"118.00","balance":"0.00","invoice_items":[{"product_key":"Florida","cost":"118.00","qty":"1.00"}],"displayName":"0164","displayTotal":118,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-27 00:00:00","invoice_number":"0165","amount":"21.00","balance":"21.00","invoice_items":[{"product_key":"Colorado","cost":"21.00","qty":"1.00"}],"displayName":"0165","displayTotal":21,"displayBalance":21,"displayPercent":0,"displayAge":68},{"invoice_status_id":"5","created_at":"2014-07-30 00:00:00","invoice_number":"0166","amount":"54.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"54.00","qty":"1.00"}],"displayName":"0166","displayTotal":54,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-03 00:00:00","invoice_number":"0167","amount":"63.00","balance":"63.00","invoice_items":[{"product_key":"Arizona","cost":"63.00","qty":"1.00"}],"displayName":"0167","displayTotal":63,"displayBalance":63,"displayPercent":0,"displayAge":30},{"invoice_status_id":"1","created_at":"2014-06-26 00:00:00","invoice_number":"0168","amount":"941.00","balance":"941.00","invoice_items":[{"product_key":"Louisiana","cost":"941.00","qty":"1.00"}],"displayName":"0168","displayTotal":941,"displayBalance":941,"displayPercent":0,"displayAge":99}],"contacts":[{"public_id":"51"}],"displayName":"Zurich Insurance Group","displayTotal":1306,"displayBalance":1134,"displayPercent":"0.13","displayAge":99},{"name":"Hyundai Motor","balance":"0.00","paid_to_date":"1643.00","invoices":[{"invoice_status_id":"5","created_at":"2014-08-08 00:00:00","invoice_number":"0169","amount":"69.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"69.00","qty":"1.00"}],"displayName":"0169","displayTotal":69,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-06-24 00:00:00","invoice_number":"0170","amount":"31.00","balance":"0.00","invoice_items":[{"product_key":"Idaho","cost":"31.00","qty":"1.00"}],"displayName":"0170","displayTotal":31,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-30 00:00:00","invoice_number":"0171","amount":"102.00","balance":"0.00","invoice_items":[{"product_key":"Maryland","cost":"102.00","qty":"1.00"}],"displayName":"0171","displayTotal":102,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-24 00:00:00","invoice_number":"0172","amount":"101.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"101.00","qty":"1.00"}],"displayName":"0172","displayTotal":101,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-24 00:00:00","invoice_number":"0173","amount":"971.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"971.00","qty":"1.00"}],"displayName":"0173","displayTotal":971,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-16 00:00:00","invoice_number":"0174","amount":"34.00","balance":"0.00","invoice_items":[{"product_key":"Kentucky","cost":"34.00","qty":"1.00"}],"displayName":"0174","displayTotal":34,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-15 00:00:00","invoice_number":"0175","amount":"71.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"71.00","qty":"1.00"}],"displayName":"0175","displayTotal":71,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-03 00:00:00","invoice_number":"0176","amount":"106.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"106.00","qty":"1.00"}],"displayName":"0176","displayTotal":106,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-21 00:00:00","invoice_number":"0177","amount":"134.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"134.00","qty":"1.00"}],"displayName":"0177","displayTotal":134,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-04 00:00:00","invoice_number":"0178","amount":"24.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"24.00","qty":"1.00"}],"displayName":"0178","displayTotal":24,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"52"}],"displayName":"Hyundai Motor","displayTotal":1643,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Sanofi","balance":"0.00","paid_to_date":"20.00","invoices":[{"invoice_status_id":"5","created_at":"2014-07-15 00:00:00","invoice_number":"0179","amount":"20.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"20.00","qty":"1.00"}],"displayName":"0179","displayTotal":20,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"53"}],"displayName":"Sanofi","displayTotal":20,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Credit Agricole","balance":"0.00","paid_to_date":"124.00","invoices":[{"invoice_status_id":"5","created_at":"2014-09-30 00:00:00","invoice_number":"0180","amount":"124.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"124.00","qty":"1.00"}],"displayName":"0180","displayTotal":124,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"54"}],"displayName":"Credit Agricole","displayTotal":124,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"United Technologies","balance":"0.00","paid_to_date":"2598.00","invoices":[{"invoice_status_id":"5","created_at":"2014-06-28 00:00:00","invoice_number":"0181","amount":"33.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"33.00","qty":"1.00"}],"displayName":"0181","displayTotal":33,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-23 00:00:00","invoice_number":"0182","amount":"114.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"114.00","qty":"1.00"}],"displayName":"0182","displayTotal":114,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-16 00:00:00","invoice_number":"0183","amount":"938.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"938.00","qty":"1.00"}],"displayName":"0183","displayTotal":938,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-15 00:00:00","invoice_number":"0184","amount":"101.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"101.00","qty":"1.00"}],"displayName":"0184","displayTotal":101,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-03 00:00:00","invoice_number":"0185","amount":"87.00","balance":"0.00","invoice_items":[{"product_key":"Indiana","cost":"87.00","qty":"1.00"}],"displayName":"0185","displayTotal":87,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-20 00:00:00","invoice_number":"0186","amount":"58.00","balance":"0.00","invoice_items":[{"product_key":"Iowa","cost":"58.00","qty":"1.00"}],"displayName":"0186","displayTotal":58,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-24 00:00:00","invoice_number":"0187","amount":"961.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"961.00","qty":"1.00"}],"displayName":"0187","displayTotal":961,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-30 00:00:00","invoice_number":"0188","amount":"132.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"132.00","qty":"1.00"}],"displayName":"0188","displayTotal":132,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-13 00:00:00","invoice_number":"0189","amount":"60.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"60.00","qty":"1.00"}],"displayName":"0189","displayTotal":60,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-30 00:00:00","invoice_number":"0190","amount":"114.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"114.00","qty":"1.00"}],"displayName":"0190","displayTotal":114,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"55"}],"displayName":"United Technologies","displayTotal":2598,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Roche Holding","balance":null,"paid_to_date":null,"invoices":[],"contacts":[{"public_id":"56"}],"displayName":"Roche Holding","displayTotal":0,"displayBalance":0,"displayPercent":"NaN","displayAge":null},{"name":"Munich Re","balance":"93.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-07-13 00:00:00","invoice_number":"0191","amount":"93.00","balance":"93.00","invoice_items":[{"product_key":"Kentucky","cost":"93.00","qty":"1.00"}],"displayName":"0191","displayTotal":93,"displayBalance":93,"displayPercent":0,"displayAge":82}],"contacts":[{"public_id":"57"}],"displayName":"Munich Re","displayTotal":93,"displayBalance":93,"displayPercent":"0.00","displayAge":82},{"name":"PepsiCo","balance":"0.00","paid_to_date":"41.00","invoices":[{"invoice_status_id":"5","created_at":"2014-10-01 00:00:00","invoice_number":"0192","amount":"41.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"41.00","qty":"1.00"}],"displayName":"0192","displayTotal":41,"displayBalance":0,"displayPercent":1,"displayAge":0}],"contacts":[{"public_id":"58"}],"displayName":"PepsiCo","displayTotal":41,"displayBalance":0,"displayPercent":"1.00","displayAge":0},{"name":"Oracle","balance":"91.00","paid_to_date":null,"invoices":[{"invoice_status_id":"1","created_at":"2014-09-19 00:00:00","invoice_number":"0193","amount":"91.00","balance":"91.00","invoice_items":[{"product_key":"Iowa","cost":"91.00","qty":"1.00"}],"displayName":"0193","displayTotal":91,"displayBalance":91,"displayPercent":0,"displayAge":14}],"contacts":[{"public_id":"59"}],"displayName":"Oracle","displayTotal":91,"displayBalance":91,"displayPercent":"0.00","displayAge":14},{"name":"Bank of Nova Scotia","balance":null,"paid_to_date":null,"invoices":[],"contacts":[{"public_id":"60"}],"displayName":"Bank of Nova Scotia","displayTotal":0,"displayBalance":0,"displayPercent":"NaN","displayAge":null}], + "invoices":[{"invoice_status_id":"5","created_at":"2014-09-18 00:00:00","invoice_number":"0001","amount":"13.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"13.00","qty":"1.00"}],"displayName":"0001","displayTotal":13,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-06-29 00:00:00","invoice_number":"0002","amount":"85.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"85.00","qty":"1.00"}],"displayName":"0002","displayTotal":85,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-11 00:00:00","invoice_number":"0003","amount":"142.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"142.00","qty":"1.00"}],"displayName":"0003","displayTotal":142,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-19 00:00:00","invoice_number":"0004","amount":"936.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"936.00","qty":"1.00"}],"displayName":"0004","displayTotal":936,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-19 00:00:00","invoice_number":"0005","amount":"74.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"74.00","qty":"1.00"}],"displayName":"0005","displayTotal":74,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-25 00:00:00","invoice_number":"0006","amount":"101.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"101.00","qty":"1.00"}],"displayName":"0006","displayTotal":101,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-21 00:00:00","invoice_number":"0007","amount":"116.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"116.00","qty":"1.00"}],"displayName":"0007","displayTotal":116,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-17 00:00:00","invoice_number":"0008","amount":"42.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"42.00","qty":"1.00"}],"displayName":"0008","displayTotal":42,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-24 00:00:00","invoice_number":"0009","amount":"66.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"66.00","qty":"1.00"}],"displayName":"0009","displayTotal":66,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-21 00:00:00","invoice_number":"0010","amount":"40.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"40.00","qty":"1.00"}],"displayName":"0010","displayTotal":40,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-25 00:00:00","invoice_number":"0011","amount":"99.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"99.00","qty":"1.00"}],"displayName":"0011","displayTotal":99,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-26 00:00:00","invoice_number":"0012","amount":"106.00","balance":"0.00","invoice_items":[{"product_key":"Louisiana","cost":"106.00","qty":"1.00"}],"displayName":"0012","displayTotal":106,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-06-29 00:00:00","invoice_number":"0013","amount":"18.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"18.00","qty":"1.00"}],"displayName":"0013","displayTotal":18,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-04 00:00:00","invoice_number":"0014","amount":"70.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"70.00","qty":"1.00"}],"displayName":"0014","displayTotal":70,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-08 00:00:00","invoice_number":"0015","amount":"59.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"59.00","qty":"1.00"}],"displayName":"0015","displayTotal":59,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-25 00:00:00","invoice_number":"0016","amount":"18.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"18.00","qty":"1.00"}],"displayName":"0016","displayTotal":18,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-04 00:00:00","invoice_number":"0017","amount":"61.00","balance":"0.00","invoice_items":[{"product_key":"Maine","cost":"61.00","qty":"1.00"}],"displayName":"0017","displayTotal":61,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-16 00:00:00","invoice_number":"0018","amount":"65.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"65.00","qty":"1.00"}],"displayName":"0018","displayTotal":65,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-24 00:00:00","invoice_number":"0019","amount":"39.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"39.00","qty":"1.00"}],"displayName":"0019","displayTotal":39,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-31 00:00:00","invoice_number":"0020","amount":"72.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"72.00","qty":"1.00"}],"displayName":"0020","displayTotal":72,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-12 00:00:00","invoice_number":"0021","amount":"48.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"48.00","qty":"1.00"}],"displayName":"0021","displayTotal":48,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-24 00:00:00","invoice_number":"0022","amount":"90.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"90.00","qty":"1.00"}],"displayName":"0022","displayTotal":90,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-31 00:00:00","invoice_number":"0023","amount":"70.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"70.00","qty":"1.00"}],"displayName":"0023","displayTotal":70,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-07 00:00:00","invoice_number":"0024","amount":"43.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"43.00","qty":"1.00"}],"displayName":"0024","displayTotal":43,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-06 00:00:00","invoice_number":"0025","amount":"137.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"137.00","qty":"1.00"}],"displayName":"0025","displayTotal":137,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-30 00:00:00","invoice_number":"0026","amount":"92.00","balance":"92.00","invoice_items":[{"product_key":"Iowa","cost":"92.00","qty":"1.00"}],"displayName":"0026","displayTotal":92,"displayBalance":92,"displayPercent":0,"displayAge":3},{"invoice_status_id":"1","created_at":"2014-08-11 00:00:00","invoice_number":"0027","amount":"95.00","balance":"95.00","invoice_items":[{"product_key":"Arizona","cost":"95.00","qty":"1.00"}],"displayName":"0027","displayTotal":95,"displayBalance":95,"displayPercent":0,"displayAge":53},{"invoice_status_id":"1","created_at":"2014-07-28 00:00:00","invoice_number":"0028","amount":"25.00","balance":"25.00","invoice_items":[{"product_key":"Massachusetts","cost":"25.00","qty":"1.00"}],"displayName":"0028","displayTotal":25,"displayBalance":25,"displayPercent":0,"displayAge":67},{"invoice_status_id":"5","created_at":"2014-09-04 00:00:00","invoice_number":"0029","amount":"966.00","balance":"0.00","invoice_items":[{"product_key":"Iowa","cost":"966.00","qty":"1.00"}],"displayName":"0029","displayTotal":966,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-16 00:00:00","invoice_number":"0030","amount":"91.00","balance":"91.00","invoice_items":[{"product_key":"Arizona","cost":"91.00","qty":"1.00"}],"displayName":"0030","displayTotal":91,"displayBalance":91,"displayPercent":0,"displayAge":17},{"invoice_status_id":"5","created_at":"2014-09-03 00:00:00","invoice_number":"0031","amount":"134.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"134.00","qty":"1.00"}],"displayName":"0031","displayTotal":134,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-08 00:00:00","invoice_number":"0032","amount":"102.00","balance":"102.00","invoice_items":[{"product_key":"Colorado","cost":"102.00","qty":"1.00"}],"displayName":"0032","displayTotal":102,"displayBalance":102,"displayPercent":0,"displayAge":87},{"invoice_status_id":"1","created_at":"2014-09-17 00:00:00","invoice_number":"0033","amount":"80.00","balance":"80.00","invoice_items":[{"product_key":"New York","cost":"80.00","qty":"1.00"}],"displayName":"0033","displayTotal":80,"displayBalance":80,"displayPercent":0,"displayAge":16},{"invoice_status_id":"5","created_at":"2014-07-23 00:00:00","invoice_number":"0034","amount":"951.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"951.00","qty":"1.00"}],"displayName":"0034","displayTotal":951,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-23 00:00:00","invoice_number":"0035","amount":"94.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"94.00","qty":"1.00"}],"displayName":"0035","displayTotal":94,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-13 00:00:00","invoice_number":"0036","amount":"137.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"137.00","qty":"1.00"}],"displayName":"0036","displayTotal":137,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-06-24 00:00:00","invoice_number":"0037","amount":"122.00","balance":"122.00","invoice_items":[{"product_key":"Alabama","cost":"122.00","qty":"1.00"}],"displayName":"0037","displayTotal":122,"displayBalance":122,"displayPercent":0,"displayAge":101},{"invoice_status_id":"1","created_at":"2014-09-25 00:00:00","invoice_number":"0038","amount":"44.00","balance":"44.00","invoice_items":[{"product_key":"Arizona","cost":"44.00","qty":"1.00"}],"displayName":"0038","displayTotal":44,"displayBalance":44,"displayPercent":0,"displayAge":8},{"invoice_status_id":"1","created_at":"2014-08-13 00:00:00","invoice_number":"0039","amount":"68.00","balance":"68.00","invoice_items":[{"product_key":"Arizona","cost":"68.00","qty":"1.00"}],"displayName":"0039","displayTotal":68,"displayBalance":68,"displayPercent":0,"displayAge":51},{"invoice_status_id":"1","created_at":"2014-07-23 00:00:00","invoice_number":"0040","amount":"23.00","balance":"23.00","invoice_items":[{"product_key":"Delaware","cost":"23.00","qty":"1.00"}],"displayName":"0040","displayTotal":23,"displayBalance":23,"displayPercent":0,"displayAge":72},{"invoice_status_id":"1","created_at":"2014-07-06 00:00:00","invoice_number":"0041","amount":"61.00","balance":"61.00","invoice_items":[{"product_key":"Colorado","cost":"61.00","qty":"1.00"}],"displayName":"0041","displayTotal":61,"displayBalance":61,"displayPercent":0,"displayAge":89},{"invoice_status_id":"1","created_at":"2014-09-05 00:00:00","invoice_number":"0042","amount":"128.00","balance":"128.00","invoice_items":[{"product_key":"Arizona","cost":"128.00","qty":"1.00"}],"displayName":"0042","displayTotal":128,"displayBalance":128,"displayPercent":0,"displayAge":28},{"invoice_status_id":"5","created_at":"2014-07-17 00:00:00","invoice_number":"0043","amount":"130.00","balance":"0.00","invoice_items":[{"product_key":"Iowa","cost":"130.00","qty":"1.00"}],"displayName":"0043","displayTotal":130,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-01 00:00:00","invoice_number":"0044","amount":"139.00","balance":"139.00","invoice_items":[{"product_key":"Arizona","cost":"139.00","qty":"1.00"}],"displayName":"0044","displayTotal":139,"displayBalance":139,"displayPercent":0,"displayAge":94},{"invoice_status_id":"1","created_at":"2014-07-20 00:00:00","invoice_number":"0045","amount":"127.00","balance":"127.00","invoice_items":[{"product_key":"California","cost":"127.00","qty":"1.00"}],"displayName":"0045","displayTotal":127,"displayBalance":127,"displayPercent":0,"displayAge":75},{"invoice_status_id":"1","created_at":"2014-09-15 00:00:00","invoice_number":"0046","amount":"83.00","balance":"83.00","invoice_items":[{"product_key":"Michigan","cost":"83.00","qty":"1.00"}],"displayName":"0046","displayTotal":83,"displayBalance":83,"displayPercent":0,"displayAge":18},{"invoice_status_id":"1","created_at":"2014-07-30 00:00:00","invoice_number":"0047","amount":"62.00","balance":"62.00","invoice_items":[{"product_key":"Florida","cost":"62.00","qty":"1.00"}],"displayName":"0047","displayTotal":62,"displayBalance":62,"displayPercent":0,"displayAge":65},{"invoice_status_id":"1","created_at":"2014-09-16 00:00:00","invoice_number":"0048","amount":"902.00","balance":"902.00","invoice_items":[{"product_key":"New York","cost":"902.00","qty":"1.00"}],"displayName":"0048","displayTotal":902,"displayBalance":902,"displayPercent":0,"displayAge":17},{"invoice_status_id":"1","created_at":"2014-08-07 00:00:00","invoice_number":"0049","amount":"139.00","balance":"139.00","invoice_items":[{"product_key":"Arizona","cost":"139.00","qty":"1.00"}],"displayName":"0049","displayTotal":139,"displayBalance":139,"displayPercent":0,"displayAge":57},{"invoice_status_id":"1","created_at":"2014-07-12 00:00:00","invoice_number":"0050","amount":"124.00","balance":"124.00","invoice_items":[{"product_key":"Arizona","cost":"124.00","qty":"1.00"}],"displayName":"0050","displayTotal":124,"displayBalance":124,"displayPercent":0,"displayAge":83},{"invoice_status_id":"1","created_at":"2014-08-05 00:00:00","invoice_number":"0051","amount":"53.00","balance":"53.00","invoice_items":[{"product_key":"Connecticut","cost":"53.00","qty":"1.00"}],"displayName":"0051","displayTotal":53,"displayBalance":53,"displayPercent":0,"displayAge":59},{"invoice_status_id":"1","created_at":"2014-06-27 00:00:00","invoice_number":"0052","amount":"52.00","balance":"52.00","invoice_items":[{"product_key":"Michigan","cost":"52.00","qty":"1.00"}],"displayName":"0052","displayTotal":52,"displayBalance":52,"displayPercent":0,"displayAge":98},{"invoice_status_id":"1","created_at":"2014-09-04 00:00:00","invoice_number":"0053","amount":"28.00","balance":"28.00","invoice_items":[{"product_key":"New York","cost":"28.00","qty":"1.00"}],"displayName":"0053","displayTotal":28,"displayBalance":28,"displayPercent":0,"displayAge":29},{"invoice_status_id":"1","created_at":"2014-07-28 00:00:00","invoice_number":"0054","amount":"36.00","balance":"36.00","invoice_items":[{"product_key":"Alabama","cost":"36.00","qty":"1.00"}],"displayName":"0054","displayTotal":36,"displayBalance":36,"displayPercent":0,"displayAge":67},{"invoice_status_id":"1","created_at":"2014-08-28 00:00:00","invoice_number":"0055","amount":"111.00","balance":"111.00","invoice_items":[{"product_key":"New York","cost":"111.00","qty":"1.00"}],"displayName":"0055","displayTotal":111,"displayBalance":111,"displayPercent":0,"displayAge":36},{"invoice_status_id":"5","created_at":"2014-08-14 00:00:00","invoice_number":"0056","amount":"43.00","balance":"0.00","invoice_items":[{"product_key":"Delaware","cost":"43.00","qty":"1.00"}],"displayName":"0056","displayTotal":43,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-23 00:00:00","invoice_number":"0057","amount":"111.00","balance":"0.00","invoice_items":[{"product_key":"Idaho","cost":"111.00","qty":"1.00"}],"displayName":"0057","displayTotal":111,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-01 00:00:00","invoice_number":"0058","amount":"40.00","balance":"40.00","invoice_items":[{"product_key":"Massachusetts","cost":"40.00","qty":"1.00"}],"displayName":"0058","displayTotal":40,"displayBalance":40,"displayPercent":0,"displayAge":32},{"invoice_status_id":"1","created_at":"2014-09-21 00:00:00","invoice_number":"0059","amount":"116.00","balance":"116.00","invoice_items":[{"product_key":"Maryland","cost":"116.00","qty":"1.00"}],"displayName":"0059","displayTotal":116,"displayBalance":116,"displayPercent":0,"displayAge":12},{"invoice_status_id":"1","created_at":"2014-07-10 00:00:00","invoice_number":"0060","amount":"101.00","balance":"101.00","invoice_items":[{"product_key":"California","cost":"101.00","qty":"1.00"}],"displayName":"0060","displayTotal":101,"displayBalance":101,"displayPercent":0,"displayAge":85},{"invoice_status_id":"1","created_at":"2014-07-19 00:00:00","invoice_number":"0061","amount":"25.00","balance":"25.00","invoice_items":[{"product_key":"New York","cost":"25.00","qty":"1.00"}],"displayName":"0061","displayTotal":25,"displayBalance":25,"displayPercent":0,"displayAge":76},{"invoice_status_id":"5","created_at":"2014-08-08 00:00:00","invoice_number":"0062","amount":"119.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"119.00","qty":"1.00"}],"displayName":"0062","displayTotal":119,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-21 00:00:00","invoice_number":"0063","amount":"42.00","balance":"42.00","invoice_items":[{"product_key":"California","cost":"42.00","qty":"1.00"}],"displayName":"0063","displayTotal":42,"displayBalance":42,"displayPercent":0,"displayAge":74},{"invoice_status_id":"5","created_at":"2014-07-17 00:00:00","invoice_number":"0064","amount":"34.00","balance":"0.00","invoice_items":[{"product_key":"Michigan","cost":"34.00","qty":"1.00"}],"displayName":"0064","displayTotal":34,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-03 00:00:00","invoice_number":"0065","amount":"108.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"108.00","qty":"1.00"}],"displayName":"0065","displayTotal":108,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-29 00:00:00","invoice_number":"0066","amount":"38.00","balance":"0.00","invoice_items":[{"product_key":"Delaware","cost":"38.00","qty":"1.00"}],"displayName":"0066","displayTotal":38,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0067","amount":"11.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"11.00","qty":"1.00"}],"displayName":"0067","displayTotal":11,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-02 00:00:00","invoice_number":"0068","amount":"128.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"128.00","qty":"1.00"}],"displayName":"0068","displayTotal":128,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-05 00:00:00","invoice_number":"0069","amount":"959.00","balance":"0.00","invoice_items":[{"product_key":"Louisiana","cost":"959.00","qty":"1.00"}],"displayName":"0069","displayTotal":959,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0070","amount":"116.00","balance":"0.00","invoice_items":[{"product_key":"Idaho","cost":"116.00","qty":"1.00"}],"displayName":"0070","displayTotal":116,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-04 00:00:00","invoice_number":"0071","amount":"50.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"50.00","qty":"1.00"}],"displayName":"0071","displayTotal":50,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-11 00:00:00","invoice_number":"0072","amount":"23.00","balance":"0.00","invoice_items":[{"product_key":"Maryland","cost":"23.00","qty":"1.00"}],"displayName":"0072","displayTotal":23,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-28 00:00:00","invoice_number":"0073","amount":"125.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"125.00","qty":"1.00"}],"displayName":"0073","displayTotal":125,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-28 00:00:00","invoice_number":"0074","amount":"981.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"981.00","qty":"1.00"}],"displayName":"0074","displayTotal":981,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-12 00:00:00","invoice_number":"0075","amount":"34.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"34.00","qty":"1.00"}],"displayName":"0075","displayTotal":34,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-15 00:00:00","invoice_number":"0076","amount":"24.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"24.00","qty":"1.00"}],"displayName":"0076","displayTotal":24,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-19 00:00:00","invoice_number":"0077","amount":"107.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"107.00","qty":"1.00"}],"displayName":"0077","displayTotal":107,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-21 00:00:00","invoice_number":"0078","amount":"950.00","balance":"0.00","invoice_items":[{"product_key":"Kentucky","cost":"950.00","qty":"1.00"}],"displayName":"0078","displayTotal":950,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-27 00:00:00","invoice_number":"0079","amount":"148.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"148.00","qty":"1.00"}],"displayName":"0079","displayTotal":148,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-22 00:00:00","invoice_number":"0080","amount":"22.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"22.00","qty":"1.00"}],"displayName":"0080","displayTotal":22,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-22 00:00:00","invoice_number":"0081","amount":"105.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"105.00","qty":"1.00"}],"displayName":"0081","displayTotal":105,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-02 00:00:00","invoice_number":"0082","amount":"19.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"19.00","qty":"1.00"}],"displayName":"0082","displayTotal":19,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-15 00:00:00","invoice_number":"0083","amount":"102.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"102.00","qty":"1.00"}],"displayName":"0083","displayTotal":102,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-06-27 00:00:00","invoice_number":"0084","amount":"105.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"105.00","qty":"1.00"}],"displayName":"0084","displayTotal":105,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-07 00:00:00","invoice_number":"0085","amount":"138.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"138.00","qty":"1.00"}],"displayName":"0085","displayTotal":138,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-15 00:00:00","invoice_number":"0086","amount":"86.00","balance":"0.00","invoice_items":[{"product_key":"Louisiana","cost":"86.00","qty":"1.00"}],"displayName":"0086","displayTotal":86,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-14 00:00:00","invoice_number":"0087","amount":"59.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"59.00","qty":"1.00"}],"displayName":"0087","displayTotal":59,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-22 00:00:00","invoice_number":"0088","amount":"129.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"129.00","qty":"1.00"}],"displayName":"0088","displayTotal":129,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-06 00:00:00","invoice_number":"0089","amount":"107.00","balance":"0.00","invoice_items":[{"product_key":"Iowa","cost":"107.00","qty":"1.00"}],"displayName":"0089","displayTotal":107,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-07 00:00:00","invoice_number":"0090","amount":"998.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"998.00","qty":"1.00"}],"displayName":"0090","displayTotal":998,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-17 00:00:00","invoice_number":"0091","amount":"11.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"11.00","qty":"1.00"}],"displayName":"0091","displayTotal":11,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-16 00:00:00","invoice_number":"0092","amount":"57.00","balance":"0.00","invoice_items":[{"product_key":"Idaho","cost":"57.00","qty":"1.00"}],"displayName":"0092","displayTotal":57,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-29 00:00:00","invoice_number":"0093","amount":"32.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"32.00","qty":"1.00"}],"displayName":"0093","displayTotal":32,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-06 00:00:00","invoice_number":"0094","amount":"108.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"108.00","qty":"1.00"}],"displayName":"0094","displayTotal":108,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-30 00:00:00","invoice_number":"0095","amount":"18.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"18.00","qty":"1.00"}],"displayName":"0095","displayTotal":18,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-27 00:00:00","invoice_number":"0096","amount":"135.00","balance":"135.00","invoice_items":[{"product_key":"New York","cost":"135.00","qty":"1.00"}],"displayName":"0096","displayTotal":135,"displayBalance":135,"displayPercent":0,"displayAge":68},{"invoice_status_id":"1","created_at":"2014-09-29 00:00:00","invoice_number":"0097","amount":"133.00","balance":"133.00","invoice_items":[{"product_key":"New York","cost":"133.00","qty":"1.00"}],"displayName":"0097","displayTotal":133,"displayBalance":133,"displayPercent":0,"displayAge":4},{"invoice_status_id":"1","created_at":"2014-09-24 00:00:00","invoice_number":"0098","amount":"118.00","balance":"118.00","invoice_items":[{"product_key":"Colorado","cost":"118.00","qty":"1.00"}],"displayName":"0098","displayTotal":118,"displayBalance":118,"displayPercent":0,"displayAge":9},{"invoice_status_id":"5","created_at":"2014-09-15 00:00:00","invoice_number":"0099","amount":"127.00","balance":"0.00","invoice_items":[{"product_key":"Michigan","cost":"127.00","qty":"1.00"}],"displayName":"0099","displayTotal":127,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-08-26 00:00:00","invoice_number":"0100","amount":"80.00","balance":"80.00","invoice_items":[{"product_key":"Maryland","cost":"80.00","qty":"1.00"}],"displayName":"0100","displayTotal":80,"displayBalance":80,"displayPercent":0,"displayAge":38},{"invoice_status_id":"5","created_at":"2014-07-07 00:00:00","invoice_number":"0101","amount":"123.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"123.00","qty":"1.00"}],"displayName":"0101","displayTotal":123,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-05 00:00:00","invoice_number":"0102","amount":"116.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"116.00","qty":"1.00"}],"displayName":"0102","displayTotal":116,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-24 00:00:00","invoice_number":"0103","amount":"36.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"36.00","qty":"1.00"}],"displayName":"0103","displayTotal":36,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-08-03 00:00:00","invoice_number":"0104","amount":"101.00","balance":"101.00","invoice_items":[{"product_key":"Arizona","cost":"101.00","qty":"1.00"}],"displayName":"0104","displayTotal":101,"displayBalance":101,"displayPercent":0,"displayAge":61},{"invoice_status_id":"1","created_at":"2014-07-06 00:00:00","invoice_number":"0105","amount":"132.00","balance":"132.00","invoice_items":[{"product_key":"Connecticut","cost":"132.00","qty":"1.00"}],"displayName":"0105","displayTotal":132,"displayBalance":132,"displayPercent":0,"displayAge":89},{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0106","amount":"13.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"13.00","qty":"1.00"}],"displayName":"0106","displayTotal":13,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-08 00:00:00","invoice_number":"0107","amount":"942.00","balance":"942.00","invoice_items":[{"product_key":"Arizona","cost":"942.00","qty":"1.00"}],"displayName":"0107","displayTotal":942,"displayBalance":942,"displayPercent":0,"displayAge":87},{"invoice_status_id":"5","created_at":"2014-07-20 00:00:00","invoice_number":"0108","amount":"38.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"38.00","qty":"1.00"}],"displayName":"0108","displayTotal":38,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-27 00:00:00","invoice_number":"0109","amount":"145.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"145.00","qty":"1.00"}],"displayName":"0109","displayTotal":145,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-06-27 00:00:00","invoice_number":"0110","amount":"93.00","balance":"0.00","invoice_items":[{"product_key":"Michigan","cost":"93.00","qty":"1.00"}],"displayName":"0110","displayTotal":93,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-21 00:00:00","invoice_number":"0111","amount":"94.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"94.00","qty":"1.00"}],"displayName":"0111","displayTotal":94,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-10 00:00:00","invoice_number":"0112","amount":"41.00","balance":"41.00","invoice_items":[{"product_key":"California","cost":"41.00","qty":"1.00"}],"displayName":"0112","displayTotal":41,"displayBalance":41,"displayPercent":0,"displayAge":85},{"invoice_status_id":"5","created_at":"2014-09-25 00:00:00","invoice_number":"0113","amount":"43.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"43.00","qty":"1.00"}],"displayName":"0113","displayTotal":43,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-03 00:00:00","invoice_number":"0114","amount":"980.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"980.00","qty":"1.00"}],"displayName":"0114","displayTotal":980,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-11 00:00:00","invoice_number":"0115","amount":"903.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"903.00","qty":"1.00"}],"displayName":"0115","displayTotal":903,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-18 00:00:00","invoice_number":"0116","amount":"44.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"44.00","qty":"1.00"}],"displayName":"0116","displayTotal":44,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-30 00:00:00","invoice_number":"0117","amount":"17.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"17.00","qty":"1.00"}],"displayName":"0117","displayTotal":17,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-17 00:00:00","invoice_number":"0118","amount":"133.00","balance":"0.00","invoice_items":[{"product_key":"Michigan","cost":"133.00","qty":"1.00"}],"displayName":"0118","displayTotal":133,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0119","amount":"25.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"25.00","qty":"1.00"}],"displayName":"0119","displayTotal":25,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-12 00:00:00","invoice_number":"0120","amount":"982.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"982.00","qty":"1.00"}],"displayName":"0120","displayTotal":982,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-29 00:00:00","invoice_number":"0121","amount":"57.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"57.00","qty":"1.00"}],"displayName":"0121","displayTotal":57,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-16 00:00:00","invoice_number":"0122","amount":"69.00","balance":"0.00","invoice_items":[{"product_key":"Connecticut","cost":"69.00","qty":"1.00"}],"displayName":"0122","displayTotal":69,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-30 00:00:00","invoice_number":"0123","amount":"14.00","balance":"14.00","invoice_items":[{"product_key":"California","cost":"14.00","qty":"1.00"}],"displayName":"0123","displayTotal":14,"displayBalance":14,"displayPercent":0,"displayAge":3},{"invoice_status_id":"5","created_at":"2014-09-19 00:00:00","invoice_number":"0124","amount":"105.00","balance":"0.00","invoice_items":[{"product_key":"Delaware","cost":"105.00","qty":"1.00"}],"displayName":"0124","displayTotal":105,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-28 00:00:00","invoice_number":"0125","amount":"68.00","balance":"68.00","invoice_items":[{"product_key":"Iowa","cost":"68.00","qty":"1.00"}],"displayName":"0125","displayTotal":68,"displayBalance":68,"displayPercent":0,"displayAge":5},{"invoice_status_id":"1","created_at":"2014-08-17 00:00:00","invoice_number":"0126","amount":"98.00","balance":"98.00","invoice_items":[{"product_key":"Arizona","cost":"98.00","qty":"1.00"}],"displayName":"0126","displayTotal":98,"displayBalance":98,"displayPercent":0,"displayAge":47},{"invoice_status_id":"1","created_at":"2014-09-16 00:00:00","invoice_number":"0127","amount":"68.00","balance":"68.00","invoice_items":[{"product_key":"Maine","cost":"68.00","qty":"1.00"}],"displayName":"0127","displayTotal":68,"displayBalance":68,"displayPercent":0,"displayAge":17},{"invoice_status_id":"1","created_at":"2014-09-30 00:00:00","invoice_number":"0128","amount":"120.00","balance":"120.00","invoice_items":[{"product_key":"New York","cost":"120.00","qty":"1.00"}],"displayName":"0128","displayTotal":120,"displayBalance":120,"displayPercent":0,"displayAge":3},{"invoice_status_id":"5","created_at":"2014-08-08 00:00:00","invoice_number":"0129","amount":"105.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"105.00","qty":"1.00"}],"displayName":"0129","displayTotal":105,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-16 00:00:00","invoice_number":"0130","amount":"117.00","balance":"117.00","invoice_items":[{"product_key":"California","cost":"117.00","qty":"1.00"}],"displayName":"0130","displayTotal":117,"displayBalance":117,"displayPercent":0,"displayAge":17},{"invoice_status_id":"1","created_at":"2014-07-08 00:00:00","invoice_number":"0131","amount":"32.00","balance":"32.00","invoice_items":[{"product_key":"Colorado","cost":"32.00","qty":"1.00"}],"displayName":"0131","displayTotal":32,"displayBalance":32,"displayPercent":0,"displayAge":87},{"invoice_status_id":"1","created_at":"2014-07-05 00:00:00","invoice_number":"0132","amount":"35.00","balance":"35.00","invoice_items":[{"product_key":"Arizona","cost":"35.00","qty":"1.00"}],"displayName":"0132","displayTotal":35,"displayBalance":35,"displayPercent":0,"displayAge":90},{"invoice_status_id":"5","created_at":"2014-07-10 00:00:00","invoice_number":"0133","amount":"14.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"14.00","qty":"1.00"}],"displayName":"0133","displayTotal":14,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-12 00:00:00","invoice_number":"0134","amount":"82.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"82.00","qty":"1.00"}],"displayName":"0134","displayTotal":82,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-20 00:00:00","invoice_number":"0135","amount":"103.00","balance":"103.00","invoice_items":[{"product_key":"Arizona","cost":"103.00","qty":"1.00"}],"displayName":"0135","displayTotal":103,"displayBalance":103,"displayPercent":0,"displayAge":75},{"invoice_status_id":"1","created_at":"2014-06-26 00:00:00","invoice_number":"0136","amount":"49.00","balance":"49.00","invoice_items":[{"product_key":"Massachusetts","cost":"49.00","qty":"1.00"}],"displayName":"0136","displayTotal":49,"displayBalance":49,"displayPercent":0,"displayAge":99},{"invoice_status_id":"5","created_at":"2014-09-07 00:00:00","invoice_number":"0137","amount":"20.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"20.00","qty":"1.00"}],"displayName":"0137","displayTotal":20,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-13 00:00:00","invoice_number":"0138","amount":"56.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"56.00","qty":"1.00"}],"displayName":"0138","displayTotal":56,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-26 00:00:00","invoice_number":"0139","amount":"147.00","balance":"147.00","invoice_items":[{"product_key":"Iowa","cost":"147.00","qty":"1.00"}],"displayName":"0139","displayTotal":147,"displayBalance":147,"displayPercent":0,"displayAge":69},{"invoice_status_id":"1","created_at":"2014-09-06 00:00:00","invoice_number":"0140","amount":"47.00","balance":"47.00","invoice_items":[{"product_key":"California","cost":"47.00","qty":"1.00"}],"displayName":"0140","displayTotal":47,"displayBalance":47,"displayPercent":0,"displayAge":27},{"invoice_status_id":"1","created_at":"2014-08-19 00:00:00","invoice_number":"0141","amount":"147.00","balance":"147.00","invoice_items":[{"product_key":"Colorado","cost":"147.00","qty":"1.00"}],"displayName":"0141","displayTotal":147,"displayBalance":147,"displayPercent":0,"displayAge":45},{"invoice_status_id":"1","created_at":"2014-09-27 00:00:00","invoice_number":"0142","amount":"113.00","balance":"113.00","invoice_items":[{"product_key":"Colorado","cost":"113.00","qty":"1.00"}],"displayName":"0142","displayTotal":113,"displayBalance":113,"displayPercent":0,"displayAge":6},{"invoice_status_id":"1","created_at":"2014-07-01 00:00:00","invoice_number":"0143","amount":"48.00","balance":"48.00","invoice_items":[{"product_key":"Indiana","cost":"48.00","qty":"1.00"}],"displayName":"0143","displayTotal":48,"displayBalance":48,"displayPercent":0,"displayAge":94},{"invoice_status_id":"1","created_at":"2014-08-18 00:00:00","invoice_number":"0144","amount":"137.00","balance":"137.00","invoice_items":[{"product_key":"Arizona","cost":"137.00","qty":"1.00"}],"displayName":"0144","displayTotal":137,"displayBalance":137,"displayPercent":0,"displayAge":46},{"invoice_status_id":"1","created_at":"2014-09-25 00:00:00","invoice_number":"0145","amount":"117.00","balance":"117.00","invoice_items":[{"product_key":"New York","cost":"117.00","qty":"1.00"}],"displayName":"0145","displayTotal":117,"displayBalance":117,"displayPercent":0,"displayAge":8},{"invoice_status_id":"5","created_at":"2014-07-24 00:00:00","invoice_number":"0146","amount":"71.00","balance":"0.00","invoice_items":[{"product_key":"Georgia","cost":"71.00","qty":"1.00"}],"displayName":"0146","displayTotal":71,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-06 00:00:00","invoice_number":"0147","amount":"976.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"976.00","qty":"1.00"}],"displayName":"0147","displayTotal":976,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-16 00:00:00","invoice_number":"0148","amount":"82.00","balance":"0.00","invoice_items":[{"product_key":"Florida","cost":"82.00","qty":"1.00"}],"displayName":"0148","displayTotal":82,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-22 00:00:00","invoice_number":"0149","amount":"134.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"134.00","qty":"1.00"}],"displayName":"0149","displayTotal":134,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-15 00:00:00","invoice_number":"0150","amount":"147.00","balance":"0.00","invoice_items":[{"product_key":"Illinois","cost":"147.00","qty":"1.00"}],"displayName":"0150","displayTotal":147,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-31 00:00:00","invoice_number":"0151","amount":"16.00","balance":"0.00","invoice_items":[{"product_key":"Kansas","cost":"16.00","qty":"1.00"}],"displayName":"0151","displayTotal":16,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-17 00:00:00","invoice_number":"0152","amount":"14.00","balance":"0.00","invoice_items":[{"product_key":"Indiana","cost":"14.00","qty":"1.00"}],"displayName":"0152","displayTotal":14,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-12 00:00:00","invoice_number":"0153","amount":"61.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"61.00","qty":"1.00"}],"displayName":"0153","displayTotal":61,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-17 00:00:00","invoice_number":"0154","amount":"47.00","balance":"0.00","invoice_items":[{"product_key":"Indiana","cost":"47.00","qty":"1.00"}],"displayName":"0154","displayTotal":47,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-10 00:00:00","invoice_number":"0155","amount":"137.00","balance":"137.00","invoice_items":[{"product_key":"California","cost":"137.00","qty":"1.00"}],"displayName":"0155","displayTotal":137,"displayBalance":137,"displayPercent":0,"displayAge":23},{"invoice_status_id":"1","created_at":"2014-07-10 00:00:00","invoice_number":"0156","amount":"76.00","balance":"76.00","invoice_items":[{"product_key":"Massachusetts","cost":"76.00","qty":"1.00"}],"displayName":"0156","displayTotal":76,"displayBalance":76,"displayPercent":0,"displayAge":85},{"invoice_status_id":"5","created_at":"2014-07-26 00:00:00","invoice_number":"0157","amount":"82.00","balance":"0.00","invoice_items":[{"product_key":"Maine","cost":"82.00","qty":"1.00"}],"displayName":"0157","displayTotal":82,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-29 00:00:00","invoice_number":"0158","amount":"76.00","balance":"76.00","invoice_items":[{"product_key":"New York","cost":"76.00","qty":"1.00"}],"displayName":"0158","displayTotal":76,"displayBalance":76,"displayPercent":0,"displayAge":4},{"invoice_status_id":"1","created_at":"2014-08-20 00:00:00","invoice_number":"0159","amount":"111.00","balance":"111.00","invoice_items":[{"product_key":"Arizona","cost":"111.00","qty":"1.00"}],"displayName":"0159","displayTotal":111,"displayBalance":111,"displayPercent":0,"displayAge":44},{"invoice_status_id":"5","created_at":"2014-07-14 00:00:00","invoice_number":"0160","amount":"27.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"27.00","qty":"1.00"}],"displayName":"0160","displayTotal":27,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-17 00:00:00","invoice_number":"0161","amount":"47.00","balance":"47.00","invoice_items":[{"product_key":"Kansas","cost":"47.00","qty":"1.00"}],"displayName":"0161","displayTotal":47,"displayBalance":47,"displayPercent":0,"displayAge":78},{"invoice_status_id":"1","created_at":"2014-08-06 00:00:00","invoice_number":"0162","amount":"31.00","balance":"31.00","invoice_items":[{"product_key":"Indiana","cost":"31.00","qty":"1.00"}],"displayName":"0162","displayTotal":31,"displayBalance":31,"displayPercent":0,"displayAge":58},{"invoice_status_id":"1","created_at":"2014-08-06 00:00:00","invoice_number":"0163","amount":"78.00","balance":"78.00","invoice_items":[{"product_key":"California","cost":"78.00","qty":"1.00"}],"displayName":"0163","displayTotal":78,"displayBalance":78,"displayPercent":0,"displayAge":58},{"invoice_status_id":"5","created_at":"2014-09-24 00:00:00","invoice_number":"0164","amount":"118.00","balance":"0.00","invoice_items":[{"product_key":"Florida","cost":"118.00","qty":"1.00"}],"displayName":"0164","displayTotal":118,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-27 00:00:00","invoice_number":"0165","amount":"21.00","balance":"21.00","invoice_items":[{"product_key":"Colorado","cost":"21.00","qty":"1.00"}],"displayName":"0165","displayTotal":21,"displayBalance":21,"displayPercent":0,"displayAge":68},{"invoice_status_id":"5","created_at":"2014-07-30 00:00:00","invoice_number":"0166","amount":"54.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"54.00","qty":"1.00"}],"displayName":"0166","displayTotal":54,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-03 00:00:00","invoice_number":"0167","amount":"63.00","balance":"63.00","invoice_items":[{"product_key":"Arizona","cost":"63.00","qty":"1.00"}],"displayName":"0167","displayTotal":63,"displayBalance":63,"displayPercent":0,"displayAge":30},{"invoice_status_id":"1","created_at":"2014-06-26 00:00:00","invoice_number":"0168","amount":"941.00","balance":"941.00","invoice_items":[{"product_key":"Louisiana","cost":"941.00","qty":"1.00"}],"displayName":"0168","displayTotal":941,"displayBalance":941,"displayPercent":0,"displayAge":99},{"invoice_status_id":"5","created_at":"2014-08-08 00:00:00","invoice_number":"0169","amount":"69.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"69.00","qty":"1.00"}],"displayName":"0169","displayTotal":69,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-06-24 00:00:00","invoice_number":"0170","amount":"31.00","balance":"0.00","invoice_items":[{"product_key":"Idaho","cost":"31.00","qty":"1.00"}],"displayName":"0170","displayTotal":31,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-30 00:00:00","invoice_number":"0171","amount":"102.00","balance":"0.00","invoice_items":[{"product_key":"Maryland","cost":"102.00","qty":"1.00"}],"displayName":"0171","displayTotal":102,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-24 00:00:00","invoice_number":"0172","amount":"101.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"101.00","qty":"1.00"}],"displayName":"0172","displayTotal":101,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-24 00:00:00","invoice_number":"0173","amount":"971.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"971.00","qty":"1.00"}],"displayName":"0173","displayTotal":971,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-16 00:00:00","invoice_number":"0174","amount":"34.00","balance":"0.00","invoice_items":[{"product_key":"Kentucky","cost":"34.00","qty":"1.00"}],"displayName":"0174","displayTotal":34,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-15 00:00:00","invoice_number":"0175","amount":"71.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"71.00","qty":"1.00"}],"displayName":"0175","displayTotal":71,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-03 00:00:00","invoice_number":"0176","amount":"106.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"106.00","qty":"1.00"}],"displayName":"0176","displayTotal":106,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-21 00:00:00","invoice_number":"0177","amount":"134.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"134.00","qty":"1.00"}],"displayName":"0177","displayTotal":134,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-04 00:00:00","invoice_number":"0178","amount":"24.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"24.00","qty":"1.00"}],"displayName":"0178","displayTotal":24,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-15 00:00:00","invoice_number":"0179","amount":"20.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"20.00","qty":"1.00"}],"displayName":"0179","displayTotal":20,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-30 00:00:00","invoice_number":"0180","amount":"124.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"124.00","qty":"1.00"}],"displayName":"0180","displayTotal":124,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-06-28 00:00:00","invoice_number":"0181","amount":"33.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"33.00","qty":"1.00"}],"displayName":"0181","displayTotal":33,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-23 00:00:00","invoice_number":"0182","amount":"114.00","balance":"0.00","invoice_items":[{"product_key":"New York","cost":"114.00","qty":"1.00"}],"displayName":"0182","displayTotal":114,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-16 00:00:00","invoice_number":"0183","amount":"938.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"938.00","qty":"1.00"}],"displayName":"0183","displayTotal":938,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-15 00:00:00","invoice_number":"0184","amount":"101.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"101.00","qty":"1.00"}],"displayName":"0184","displayTotal":101,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-03 00:00:00","invoice_number":"0185","amount":"87.00","balance":"0.00","invoice_items":[{"product_key":"Indiana","cost":"87.00","qty":"1.00"}],"displayName":"0185","displayTotal":87,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-20 00:00:00","invoice_number":"0186","amount":"58.00","balance":"0.00","invoice_items":[{"product_key":"Iowa","cost":"58.00","qty":"1.00"}],"displayName":"0186","displayTotal":58,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-08-24 00:00:00","invoice_number":"0187","amount":"961.00","balance":"0.00","invoice_items":[{"product_key":"California","cost":"961.00","qty":"1.00"}],"displayName":"0187","displayTotal":961,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-30 00:00:00","invoice_number":"0188","amount":"132.00","balance":"0.00","invoice_items":[{"product_key":"Colorado","cost":"132.00","qty":"1.00"}],"displayName":"0188","displayTotal":132,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-07-13 00:00:00","invoice_number":"0189","amount":"60.00","balance":"0.00","invoice_items":[{"product_key":"Hawaii","cost":"60.00","qty":"1.00"}],"displayName":"0189","displayTotal":60,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"5","created_at":"2014-09-30 00:00:00","invoice_number":"0190","amount":"114.00","balance":"0.00","invoice_items":[{"product_key":"Alabama","cost":"114.00","qty":"1.00"}],"displayName":"0190","displayTotal":114,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-07-13 00:00:00","invoice_number":"0191","amount":"93.00","balance":"93.00","invoice_items":[{"product_key":"Kentucky","cost":"93.00","qty":"1.00"}],"displayName":"0191","displayTotal":93,"displayBalance":93,"displayPercent":0,"displayAge":82},{"invoice_status_id":"5","created_at":"2014-10-01 00:00:00","invoice_number":"0192","amount":"41.00","balance":"0.00","invoice_items":[{"product_key":"Arizona","cost":"41.00","qty":"1.00"}],"displayName":"0192","displayTotal":41,"displayBalance":0,"displayPercent":1,"displayAge":0},{"invoice_status_id":"1","created_at":"2014-09-19 00:00:00","invoice_number":"0193","amount":"91.00","balance":"91.00","invoice_items":[{"product_key":"Iowa","cost":"91.00","qty":"1.00"}],"displayName":"0193","displayTotal":91,"displayBalance":91,"displayPercent":0,"displayAge":14}], + "products":[{"key":"Alabama","values":{"amount":642,"paid":484,"age":84},"displayName":"Alabama","displayTotal":642,"displayBalance":158,"displayPercent":"0.75","displayAge":84},{"key":"Arizona","values":{"amount":7480,"paid":5062,"age":52},"displayName":"Arizona","displayTotal":7480,"displayBalance":2418,"displayPercent":"0.68","displayAge":52},{"key":"California","values":{"amount":6249,"paid":5545,"age":58},"displayName":"California","displayTotal":6249,"displayBalance":704,"displayPercent":"0.89","displayAge":58},{"key":"Colorado","values":{"amount":1260,"paid":666,"age":68},"displayName":"Colorado","displayTotal":1260,"displayBalance":594,"displayPercent":"0.53","displayAge":68},{"key":"Connecticut","values":{"amount":578,"paid":393,"age":74},"displayName":"Connecticut","displayTotal":578,"displayBalance":185,"displayPercent":"0.68","displayAge":74},{"key":"Delaware","values":{"amount":209,"paid":186,"age":72},"displayName":"Delaware","displayTotal":209,"displayBalance":23,"displayPercent":"0.89","displayAge":72},{"key":"Florida","values":{"amount":262,"paid":200,"age":65},"displayName":"Florida","displayTotal":262,"displayBalance":62,"displayPercent":"0.76","displayAge":65},{"key":"Georgia","values":{"amount":71,"paid":71},"displayName":"Georgia","displayTotal":71,"displayBalance":0,"displayPercent":"1.00"},{"key":"Hawaii","values":{"amount":536,"paid":536},"displayName":"Hawaii","displayTotal":536,"displayBalance":0,"displayPercent":"1.00"},{"key":"Idaho","values":{"amount":315,"paid":315},"displayName":"Idaho","displayTotal":315,"displayBalance":0,"displayPercent":"1.00"},{"key":"Illinois","values":{"amount":1281,"paid":1281},"displayName":"Illinois","displayTotal":1281,"displayBalance":0,"displayPercent":"1.00"},{"key":"Indiana","values":{"amount":227,"paid":148,"age":76},"displayName":"Indiana","displayTotal":227,"displayBalance":79,"displayPercent":"0.65","displayAge":76},{"key":"Iowa","values":{"amount":1659,"paid":1261,"age":9.5},"displayName":"Iowa","displayTotal":1659,"displayBalance":398,"displayPercent":"0.76","displayAge":9.5},{"key":"Kansas","values":{"amount":342,"paid":295,"age":78},"displayName":"Kansas","displayTotal":342,"displayBalance":47,"displayPercent":"0.86","displayAge":78},{"key":"Kentucky","values":{"amount":1077,"paid":984,"age":82},"displayName":"Kentucky","displayTotal":1077,"displayBalance":93,"displayPercent":"0.91","displayAge":82},{"key":"Louisiana","values":{"amount":2092,"paid":1151,"age":99},"displayName":"Louisiana","displayTotal":2092,"displayBalance":941,"displayPercent":"0.55","displayAge":99},{"key":"Maine","values":{"amount":211,"paid":143,"age":17},"displayName":"Maine","displayTotal":211,"displayBalance":68,"displayPercent":"0.68","displayAge":17},{"key":"Maryland","values":{"amount":321,"paid":125,"age":25},"displayName":"Maryland","displayTotal":321,"displayBalance":196,"displayPercent":"0.39","displayAge":25},{"key":"Massachusetts","values":{"amount":190,"paid":0,"age":76},"displayName":"Massachusetts","displayTotal":190,"displayBalance":190,"displayPercent":"0.00","displayAge":76},{"key":"Michigan","values":{"amount":522,"paid":387,"age":58},"displayName":"Michigan","displayTotal":522,"displayBalance":135,"displayPercent":"0.74","displayAge":58},{"key":"New York","values":{"amount":4396,"paid":2669,"age":16.5},"displayName":"New York","displayTotal":4396,"displayBalance":1727,"displayPercent":"0.61","displayAge":16.5}] +} \ No newline at end of file