diff --git a/.env.example b/.env.example index b354269ebf64..dd26b20a093f 100644 --- a/.env.example +++ b/.env.example @@ -15,5 +15,6 @@ MAIL_PORT=587 MAIL_ENCRYPTION=tls MAIL_HOST MAIL_USERNAME +MAIL_FROM_ADDRESS MAIL_FROM_NAME MAIL_PASSWORD \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 005c733a9d5e..4b01db377ffd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -56,6 +56,8 @@ module.exports = function(grunt) { 'public/vendor/accounting/accounting.min.js', 'public/vendor/spectrum/spectrum.js', 'public/vendor/jspdf/dist/jspdf.min.js', + 'public/vendor/moment/min/moment.min.js', + //'public/vendor/moment-duration-format/lib/moment-duration-format.js', //'public/vendor/handsontable/dist/jquery.handsontable.full.min.js', //'public/vendor/pdfmake/build/pdfmake.min.js', //'public/vendor/pdfmake/build/vfs_fonts.js', @@ -63,8 +65,7 @@ module.exports = function(grunt) { 'public/js/lightbox.min.js', 'public/js/bootstrap-combobox.js', 'public/js/script.js', - 'public/js/pdf.pdfmake.js', - + 'public/js/pdf.pdfmake.js' ], dest: 'public/js/built.js', nonull: true diff --git a/app/Console/Commands/ImportTimesheetData.php b/app/Console/Commands/ImportTimesheetData.php deleted file mode 100644 index 450b02b1f4c8..000000000000 --- a/app/Console/Commands/ImportTimesheetData.php +++ /dev/null @@ -1,335 +0,0 @@ -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/SendRecurringInvoices.php b/app/Console/Commands/SendRecurringInvoices.php index aefc79bda752..8f65214f7fc1 100644 --- a/app/Console/Commands/SendRecurringInvoices.php +++ b/app/Console/Commands/SendRecurringInvoices.php @@ -51,15 +51,15 @@ class SendRecurringInvoices extends Command $invoice = Invoice::createNew($recurInvoice); $invoice->client_id = $recurInvoice->client_id; $invoice->recurring_invoice_id = $recurInvoice->id; - $invoice->invoice_number = 'R'.$recurInvoice->account->getNextInvoiceNumber(); + $invoice->invoice_number = $recurInvoice->account->getNextInvoiceNumber(false, 'R'); $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->public_notes = Utils::processVariables($recurInvoice->public_notes); + $invoice->terms = Utils::processVariables($recurInvoice->terms); + $invoice->invoice_footer = Utils::processVariables($recurInvoice->invoice_footer); $invoice->tax_name = $recurInvoice->tax_name; $invoice->tax_rate = $recurInvoice->tax_rate; $invoice->invoice_design_id = $recurInvoice->invoice_design_id; diff --git a/app/Console/Commands/SendRenewalInvoices.php b/app/Console/Commands/SendRenewalInvoices.php index ceae80e611dc..cf9a968d56ba 100644 --- a/app/Console/Commands/SendRenewalInvoices.php +++ b/app/Console/Commands/SendRenewalInvoices.php @@ -31,7 +31,7 @@ class SendRenewalInvoices extends Command $accounts = Account::whereRaw('datediff(curdate(), pro_plan_paid) = 355')->get(); $this->info(count($accounts).' accounts found'); - dd(0); + foreach ($accounts as $account) { $client = $this->accountRepo->getNinjaClient($account); $invitation = $this->accountRepo->createNinjaInvoice($client); diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 64d68d6f4642..9235cbf87b58 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -14,7 +14,6 @@ class Kernel extends ConsoleKernel { 'App\Console\Commands\SendRecurringInvoices', 'App\Console\Commands\CreateRandomData', 'App\Console\Commands\ResetData', - 'App\Console\Commands\ImportTimesheetData', 'App\Console\Commands\CheckData', 'App\Console\Commands\SendRenewalInvoices', ]; diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index e67102df2b7a..c366547f9b54 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -209,6 +209,7 @@ class AccountController extends BaseController $data['invoice'] = $invoice; $data['invoiceDesigns'] = InvoiceDesign::availableDesigns(); + $data['invoiceLabels'] = json_decode($account->invoice_labels) ?: []; } else if ($subSection == ACCOUNT_EMAIL_TEMPLATES) { $data['invoiceEmail'] = $account->getEmailTemplate(ENTITY_INVOICE); $data['quoteEmail'] = $account->getEmailTemplate(ENTITY_QUOTE); @@ -331,6 +332,16 @@ class AccountController extends BaseController $account->primary_color = Input::get('primary_color'); $account->secondary_color = Input::get('secondary_color'); $account->invoice_design_id = Input::get('invoice_design_id'); + if (Input::has('font_size')) { + $account->font_size = intval(Input::get('font_size')); + } + + $labels = []; + foreach (['item', 'description', 'unit_cost', 'quantity'] as $field) { + $labels[$field] = trim(Input::get("labels_{$field}")); + } + $account->invoice_labels = json_encode($labels); + $account->save(); Session::flash('message', trans('texts.updated_settings')); diff --git a/app/Http/Controllers/AccountGatewayController.php b/app/Http/Controllers/AccountGatewayController.php index 29002f8727b1..c1d570c6534f 100644 --- a/app/Http/Controllers/AccountGatewayController.php +++ b/app/Http/Controllers/AccountGatewayController.php @@ -10,7 +10,7 @@ use View; use Validator; use stdClass; use URL; - +use Utils; use App\Models\Gateway; use App\Models\Account; use App\Models\AccountGateway; @@ -69,6 +69,7 @@ class AccountGatewayController extends BaseController $data['method'] = 'PUT'; $data['title'] = trans('texts.edit_gateway') . ' - ' . $accountGateway->gateway->name; $data['config'] = $configFields; + $data['hiddenFields'] = Gateway::$hiddenFields; $data['paymentTypeId'] = $accountGateway->getPaymentType(); $data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get(); @@ -97,6 +98,7 @@ class AccountGatewayController extends BaseController $data['method'] = 'POST'; $data['title'] = trans('texts.add_gateway'); $data['selectGateways'] = Gateway::where('payment_library_id', '=', 1)->where('id', '!=', GATEWAY_PAYPAL_EXPRESS)->where('id', '!=', GATEWAY_PAYPAL_EXPRESS)->orderBy('name')->get(); + $data['hiddenFields'] = Gateway::$hiddenFields; return View::make('accounts.account_gateway', $data); } @@ -107,7 +109,7 @@ class AccountGatewayController extends BaseController $account = Auth::user()->account; $paymentTypes = []; - foreach ([PAYMENT_TYPE_CREDIT_CARD, PAYMENT_TYPE_PAYPAL, PAYMENT_TYPE_BITCOIN] as $type) { + foreach (Gateway::$paymentTypes as $type) { if ($accountGateway || !$account->getGatewayByType($type)) { $paymentTypes[$type] = trans('texts.'.strtolower($type)); @@ -132,7 +134,9 @@ class AccountGatewayController extends BaseController $gateways = Gateway::where('payment_library_id', '=', 1)->orderBy('name')->get(); foreach ($gateways as $gateway) { - $gateway->fields = $gateway->getFields(); + $fields = $gateway->getFields(); + asort($fields); + $gateway->fields = $fields; if ($accountGateway && $accountGateway->gateway_id == $gateway->id) { $accountGateway->fields = $gateway->fields; } @@ -182,6 +186,8 @@ class AccountGatewayController extends BaseController $gatewayId = GATEWAY_PAYPAL_EXPRESS; } elseif ($paymentType == PAYMENT_TYPE_BITCOIN) { $gatewayId = GATEWAY_BITPAY; + } elseif ($paymentType == PAYMENT_TYPE_DWOLLA) { + $gatewayId = GATEWAY_DWOLLA; } if (!$gatewayId) { @@ -192,9 +198,14 @@ class AccountGatewayController extends BaseController $gateway = Gateway::findOrFail($gatewayId); $fields = $gateway->getFields(); + $optional = array_merge(Gateway::$hiddenFields, Gateway::$optionalFields); + + if (Utils::isNinja() && $gatewayId == GATEWAY_DWOLLA) { + $optional = array_merge($optional, ['key', 'secret']); + } foreach ($fields as $field => $details) { - if (!in_array($field, ['testMode', 'developerMode', 'headerImageUrl', 'solutionType', 'landingPage', 'brandName', 'logoImageUrl', 'borderColor'])) { + if (!in_array($field, $optional)) { if (strtolower($gateway->name) == 'beanstream') { if (in_array($field, ['merchant_id', 'passCode'])) { $rules[$gateway->id.'_'.$field] = 'required'; @@ -271,4 +282,4 @@ class AccountGatewayController extends BaseController } } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php index bf37d1cb9a54..9704b3adaaad 100644 --- a/app/Http/Controllers/ActivityController.php +++ b/app/Http/Controllers/ActivityController.php @@ -17,7 +17,7 @@ class ActivityController extends BaseController ->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('activities.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 ? self::wrapAdjustment($model->adjustment, $model->currency_id) : ''; }) diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php index 7616128b92bd..745c38579e5a 100644 --- a/app/Http/Controllers/AppController.php +++ b/app/Http/Controllers/AppController.php @@ -116,7 +116,6 @@ class AppController extends BaseController $user = $account->users()->first(); //Auth::login($user, true); - $this->accountRepo->registerUser($user); return Redirect::to('/login'); } diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index 7a58ad08bb8c..9072f6960d70 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -20,6 +20,7 @@ use App\Models\PaymentTerm; use App\Models\Industry; use App\Models\Currency; use App\Models\Country; +use App\Models\Task; use App\Ninja\Repositories\ClientRepository; @@ -58,7 +59,7 @@ class ClientController extends BaseController ->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('clients.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) { @@ -75,9 +76,16 @@ class ClientController extends BaseController if (!$model->deleted_at || $model->deleted_at == '0000-00-00') { $str .= '
  • '.trans('texts.edit_client').'
  • -
  • '.trans('texts.new_invoice').'
  • -
  • '.trans('texts.new_payment').'
  • -
  • '.trans('texts.new_credit').'
  • +
  • '.trans('texts.new_task').'
  • +
  • '.trans('texts.new_invoice').'
  • '; + + if (Auth::user()->isPro()) { + $str .= '
  • '.trans('texts.new_quote').'
  • '; + } + + $str .= '
  • +
  • '.trans('texts.enter_payment').'
  • +
  • '.trans('texts.enter_credit').'
  • '.trans('texts.archive_client').'
  • '; } else { @@ -112,15 +120,18 @@ class ClientController extends BaseController Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT); $actionLinks = [ - ['label' => trans('texts.create_invoice'), 'url' => '/invoices/create/'.$client->public_id], - ['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id], - ['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id], + ['label' => trans('texts.new_task'), 'url' => '/tasks/create/'.$client->public_id] ]; if (Utils::isPro()) { - array_unshift($actionLinks, ['label' => trans('texts.create_quote'), 'url' => '/quotes/create/'.$client->public_id]); + array_push($actionLinks, ['label' => trans('texts.new_quote'), 'url' => '/quotes/create/'.$client->public_id]); } + array_push($actionLinks, + ['label' => trans('texts.enter_payment'), 'url' => '/payments/create/'.$client->public_id], + ['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id] + ); + $data = array( 'actionLinks' => $actionLinks, 'showBreadcrumbs' => false, @@ -128,6 +139,8 @@ class ClientController extends BaseController 'credit' => $client->getTotalCredit(), 'title' => trans('texts.view_client'), 'hasRecurringInvoices' => Invoice::scope()->where('is_recurring', '=', true)->whereClientId($client->id)->count() > 0, + 'hasQuotes' => Invoice::scope()->where('is_quote', '=', true)->whereClientId($client->id)->count() > 0, + 'hasTasks' => Task::scope()->whereClientId($client->id)->count() > 0, 'gatewayLink' => $client->getGatewayLink(), ); diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 6eacdad00f52..1e851f98dafe 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -1,5 +1,6 @@ Utils::trans(['checkbox', 'invoice_number', 'client', 'invoice_date', 'invoice_total', 'balance_due', 'due_date', 'status', 'action']), ]; - $recurringInvoices = Invoice::scope()->where('is_recurring', '=', true); + $recurringInvoices = Invoice::scope() + ->where('is_recurring', '=', true); if (Session::get('show_trash:invoice')) { $recurringInvoices->withTrashed(); + } else { + $recurringInvoices->join('clients', 'clients.id', '=', 'invoices.client_id') + ->where('clients.deleted_at', '=', null); } if ($recurringInvoices->count() > 0) { @@ -221,14 +227,14 @@ class InvoiceController extends BaseController 'url' => URL::to("payment/{$invitation->invitation_key}/".PAYMENT_TYPE_TOKEN), 'label' => trans('texts.use_card_on_file') ]; } - foreach([PAYMENT_TYPE_CREDIT_CARD, PAYMENT_TYPE_PAYPAL, PAYMENT_TYPE_BITCOIN] as $type) { + foreach(Gateway::$paymentTypes as $type) { if ($account->getGatewayByType($type)) { $paymentTypes[] = [ 'url' => URL::to("/payment/{$invitation->invitation_key}/{$type}"), 'label' => trans('texts.'.strtolower($type)) ]; } } - + $data = array( 'isConverted' => $invoice->quote_invoice_id ? true : false, 'showBreadcrumbs' => false, @@ -275,6 +281,40 @@ class InvoiceController extends BaseController $invoice->end_date = Utils::fromSqlDate($invoice->end_date); $invoice->is_pro = Auth::user()->isPro(); + $actions = [ + ['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")], + ['url' => URL::to("{$entityType}s/{$entityType}_history/{$invoice->public_id}"), 'label' => trans("texts.view_history")], + DropdownButton::DIVIDER + ]; + + if ($invoice->invoice_status_id < INVOICE_STATUS_SENT && !$invoice->is_recurring) { + $actions[] = ['url' => 'javascript:onMarkClick()', 'label' => trans("texts.mark_sent")]; + } + + if ($entityType == ENTITY_QUOTE) { + if ($invoice->quote_invoice_id) { + $actions[] = ['url' => URL::to("invoices/{$invoice->quote_invoice_id}/edit"), 'label' => trans("texts.view_invoice")]; + } else { + $actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans("texts.convert_to_invoice")]; + } + } elseif ($entityType == ENTITY_INVOICE) { + if ($invoice->quote_id) { + $actions[] = ['url' => URL::to("quotes/{$invoice->quote_id}/edit"), 'label' => trans("texts.view_quote")]; + } + + if (!$invoice->is_recurring && $invoice->balance > 0) { + $actions[] = ['url' => 'javascript:onPaymentClick()', 'label' => trans('texts.enter_payment')]; + } + } + + if (count($actions) > 3) { + $actions[] = DropdownButton::DIVIDER; + } + + $actions[] = ['url' => 'javascript:onArchiveClick()', 'label' => trans("texts.archive_{$entityType}")]; + $actions[] = ['url' => 'javascript:onDeleteClick()', 'label' => trans("texts.delete_{$entityType}")]; + + $data = array( 'entityType' => $entityType, 'showBreadcrumbs' => $clone, @@ -285,7 +325,8 @@ class InvoiceController extends BaseController 'invitationContactIds' => $contactIds, 'url' => $url, 'title' => trans("texts.edit_{$entityType}"), - 'client' => $invoice->client, ); + 'client' => $invoice->client, + 'actions' => $actions); $data = array_merge($data, self::getViewModel()); // Set the invitation link on the client's contacts @@ -327,7 +368,8 @@ class InvoiceController extends BaseController 'method' => 'POST', 'url' => 'invoices', 'title' => trans('texts.new_invoice'), - 'client' => $client, ); + 'client' => $client, + 'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null); $data = array_merge($data, self::getViewModel()); return View::make('invoices.edit', $data); @@ -366,7 +408,9 @@ class InvoiceController extends BaseController 6 => 'Six months', 7 => 'Annually', ), - 'recurringHelp' => $recurringHelp + 'recurringHelp' => $recurringHelp, + 'invoiceLabels' => Auth::user()->account->getInvoiceLabels(), + ]; } diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index b9c67a151778..752f34df357e 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -90,7 +90,7 @@ class PaymentController extends BaseController } $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' : ''); }); + ->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? $model->gateway_name : ''); }); 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); }) @@ -195,11 +195,6 @@ class PaymentController extends BaseController $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; @@ -209,8 +204,14 @@ class PaymentController extends BaseController $gateway->$function($val); } - if (Utils::isNinjaDev()) { - $gateway->setTestMode(true); + if ($accountGateway->gateway->id == GATEWAY_DWOLLA) { + if ($gateway->getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) { + $gateway->setKey($_ENV['DWOLLA_SANDBOX_KEY']); + $gateway->setSecret($_ENV['DWOLLA_SANSBOX_SECRET']); + } elseif (isset($_ENV['DWOLLA_KEY']) && isset($_ENV['DWOLLA_SECRET'])) { + $gateway->setKey($_ENV['DWOLLA_KEY']); + $gateway->setSecret($_ENV['DWOLLA_SECRET']); + } } return $gateway; @@ -325,6 +326,7 @@ class PaymentController extends BaseController 'countries' => Cache::get('countries'), 'currencyId' => $client->currency_id, 'account' => $client->account, + 'hideLogo' => $account->isWhiteLabel(), ]; return View::make('payments.payment', $data); @@ -448,6 +450,7 @@ class PaymentController extends BaseController 'message' => $affiliate->payment_subtitle, 'license' => $licenseKey, 'hideHeader' => true, + 'productId' => $license->product_id ]; $name = "{$license->first_name} {$license->last_name}"; @@ -473,7 +476,7 @@ class PaymentController extends BaseController $productId = Input::get('product_id', PRODUCT_ONE_CLICK_INSTALL); $license = License::where('license_key', '=', $licenseKey) - ->where('is_claimed', '<', 3) + ->where('is_claimed', '<', 5) ->where('product_id', '=', $productId) ->first(); @@ -483,7 +486,7 @@ class PaymentController extends BaseController $license->save(); } - return $productId == PRODUCT_INVOICE_DESIGNS ? $_ENV['INVOICE_DESIGNS'] : 'valid'; + return $productId == PRODUCT_INVOICE_DESIGNS ? file_get_contents(storage_path() . '/invoice_designs.txt') : 'valid'; } else { return 'invalid'; } @@ -509,6 +512,7 @@ class PaymentController extends BaseController $validator = Validator::make(Input::all(), $rules); if ($validator->fails()) { + Utils::logError('Payment Error [invalid]'); return Redirect::to('payment/'.$invitationKey) ->withErrors($validator); } @@ -533,7 +537,7 @@ class PaymentController extends BaseController try { $gateway = self::createGateway($accountGateway); - $details = self::getPaymentDetails($invitation, $useToken || !$onSite ? false : Input::all()); + $details = self::getPaymentDetails($invitation, ($useToken || !$onSite) ? false : Input::all()); if ($accountGateway->gateway_id == GATEWAY_STRIPE) { if ($useToken) { @@ -558,6 +562,10 @@ class PaymentController extends BaseController $token->token = $cardReference; $token->save(); + } else { + Session::flash('error', $tokenResponse->getMessage()); + Utils::logError('Payment Error [no-token-ref]: ' . $tokenResponse->getMessage()); + return Redirect::to('payment/'.$invitationKey)->withInput(); } } } @@ -568,6 +576,7 @@ class PaymentController extends BaseController if (!$ref) { Session::flash('error', $response->getMessage()); + Utils::logError('Payment Error [no-ref]: ' . $response->getMessage()); if ($onSite) { return Redirect::to('payment/'.$invitationKey)->withInput(); @@ -580,6 +589,11 @@ class PaymentController extends BaseController $payment = self::createPayment($invitation, $ref); Session::flash('message', trans('texts.applied_payment')); + if ($account->account_key == NINJA_ACCOUNT_KEY) { + Session::flash('trackEventCategory', '/account'); + Session::flash('trackEventAction', '/buy_pro_plan'); + } + return Redirect::to('view/'.$payment->invitation->invitation_key); } elseif ($response->isRedirect()) { $invitation->transaction_reference = $ref; @@ -590,13 +604,14 @@ class PaymentController extends BaseController $response->redirect(); } else { Session::flash('error', $response->getMessage()); + Utils::logError('Payment Error [fatal]: ' . $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)); + Utils::logError('Payment Error [uncaught]:' . Utils::getErrorString($e)); if ($onSite) { return Redirect::to('payment/'.$invitationKey)->withInput(); diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index 039adc0b5643..ebfc8a6629c0 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -20,6 +20,7 @@ use App\Models\Size; use App\Models\TaxRate; use App\Models\Invitation; use App\Models\Activity; +use App\Models\Invoice; use App\Ninja\Mailers\ContactMailer as Mailer; use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\ClientRepository; diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 96e82416e897..b1746761b10f 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -16,13 +16,14 @@ class ReportController extends BaseController public function d3() { $message = ''; + $fileName = storage_path() . '/dataviz_sample.txt'; if (Auth::user()->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']; + } elseif (file_exists($fileName)) { + $clients = file_get_contents($fileName); $message = trans('texts.sample_data'); } else { $clients = '[]'; diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php new file mode 100644 index 000000000000..19e48224a026 --- /dev/null +++ b/app/Http/Controllers/TaskController.php @@ -0,0 +1,260 @@ +taskRepo = $taskRepo; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list', array( + 'entityType' => ENTITY_TASK, + 'title' => trans('texts.tasks'), + 'sortCol' => '2', + 'columns' => Utils::trans(['checkbox', 'client', 'date', 'duration', 'description', 'status', 'action']), + )); + } + + public function getDatatable($clientPublicId = null) + { + $tasks = $this->taskRepo->find($clientPublicId, Input::get('sSearch')); + + $table = Datatable::query($tasks); + + if (!$clientPublicId) { + $table->addColumn('checkbox', function ($model) { return ''; }) + ->addColumn('client_name', function ($model) { return $model->client_public_id ? link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)) : ''; }); + } + + return $table->addColumn('start_time', function($model) { return Utils::fromSqlDateTime($model->start_time); }) + ->addColumn('duration', function($model) { return gmdate('H:i:s', $model->duration == -1 ? time() - strtotime($model->start_time) : $model->duration); }) + ->addColumn('description', function($model) { return $model->description; }) + ->addColumn('invoice_number', function($model) { return self::getStatusLabel($model); }) + ->addColumn('dropdown', function ($model) { + $str = '

    '; + }) + ->make(); + } + + private function getStatusLabel($model) { + if ($model->invoice_number) { + $class = 'success'; + $label = trans('texts.invoiced'); + } elseif ($model->duration == -1) { + $class = 'primary'; + $label = trans('texts.running'); + } else { + $class = 'default'; + $label = trans('texts.logged'); + } + return "

    $label

    "; + } + + + /** + * Store a newly created resource in storage. + * + * @return Response + */ + public function store() + { + return $this->save(); + } + + /** + * Show the form for creating a new resource. + * + * @return Response + */ + public function create($clientPublicId = 0) + { + $data = [ + 'task' => null, + 'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId, + 'method' => 'POST', + 'url' => 'tasks', + 'title' => trans('texts.new_task'), + ]; + + $data = array_merge($data, self::getViewModel()); + + return View::make('tasks.edit', $data); + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return Response + */ + public function edit($publicId) + { + $task = Task::scope($publicId)->with('client')->firstOrFail(); + + $data = [ + 'task' => $task, + 'clientPublicId' => $task->client ? $task->client->public_id : 0, + 'method' => 'PUT', + 'url' => 'tasks/'.$publicId, + 'title' => trans('texts.edit_task'), + ]; + + $data = array_merge($data, self::getViewModel()); + + return View::make('tasks.edit', $data); + } + + /** + * Update the specified resource in storage. + * + * @param int $id + * @return Response + */ + public function update($publicId) + { + return $this->save($publicId); + } + + private static function getViewModel() + { + return [ + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get() + ]; + } + + private function save($publicId = null) + { + $task = $this->taskRepo->save($publicId, Input::all()); + + Session::flash('message', trans($publicId ? 'texts.updated_task' : 'texts.created_task')); + + if (Input::get('action') == 'stop') { + return Redirect::to("tasks"); + } else { + return Redirect::to("tasks/{$task->public_id}/edit"); + } + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('id') ? Input::get('id') : Input::get('ids'); + + if ($action == 'stop') { + $this->taskRepo->save($ids, ['action' => $action]); + Session::flash('message', trans('texts.stopped_task')); + return Redirect::to('tasks'); + } else if ($action == 'invoice') { + + $tasks = Task::scope($ids)->with('client')->get(); + $clientPublicId = false; + $data = []; + + foreach ($tasks as $task) { + if ($task->client) { + if (!$clientPublicId) { + $clientPublicId = $task->client->public_id; + } else if ($clientPublicId != $task->client->public_id) { + Session::flash('error', trans('texts.task_error_multiple_clients')); + return Redirect::to('tasks'); + } + } + + if ($task->duration == -1) { + Session::flash('error', trans('texts.task_error_running')); + return Redirect::to('tasks'); + } else if ($task->invoice_id) { + Session::flash('error', trans('texts.task_error_invoiced')); + return Redirect::to('tasks'); + } + + $data[] = [ + 'publicId' => $task->public_id, + 'description' => $task->description, + 'startTime' => Utils::fromSqlDateTime($task->start_time), + 'duration' => round($task->duration / (60 * 60), 2) + ]; + } + + return Redirect::to("invoices/create/{$clientPublicId}")->with('tasks', $data); + } else { + $count = $this->taskRepo->bulk($ids, $action); + + $message = Utils::pluralize($action.'d_task', $count); + Session::flash('message', $message); + + if ($action == 'restore' && $count == 1) { + return Redirect::to('tasks/'.$ids[0].'/edit'); + } else { + return Redirect::to('tasks'); + } + } + } +} diff --git a/app/Http/Controllers/TimesheetController.php b/app/Http/Controllers/TimesheetController.php deleted file mode 100644 index 7327f0b624c2..000000000000 --- a/app/Http/Controllers/TimesheetController.php +++ /dev/null @@ -1,93 +0,0 @@ - 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/Middleware/StartupCheck.php b/app/Http/Middleware/StartupCheck.php index 4f9672b9919c..4306171c6c1d 100644 --- a/app/Http/Middleware/StartupCheck.php +++ b/app/Http/Middleware/StartupCheck.php @@ -51,7 +51,7 @@ class StartupCheck 'countries' => 'App\Models\Country', ]; foreach ($cachedTables as $name => $class) { - if (!Cache::has($name)) { + if (Input::has('clear_cache') || !Cache::has($name)) { if ($name == 'paymentTerms') { $orderBy = 'num_days'; } elseif (in_array($name, ['currencies', 'sizes', 'industries', 'languages', 'countries'])) { @@ -59,7 +59,10 @@ class StartupCheck } else { $orderBy = 'id'; } - Cache::forever($name, $class::orderBy($orderBy)->get()); + $tableData = $class::orderBy($orderBy)->get(); + if (count($tableData)) { + Cache::forever($name, $tableData); + } } } @@ -138,10 +141,6 @@ class StartupCheck $design->save(); } - if (!Utils::isNinjaProd()) { - Cache::forget('invoice_designs_cache_'.Auth::user()->maxInvoiceDesignId()); - } - Session::flash('message', trans('texts.bought_designs')); } } elseif ($productId == PRODUCT_WHITE_LABEL) { diff --git a/app/Http/routes.php b/app/Http/routes.php index 28647194460b..efad81d4f736 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -31,6 +31,7 @@ Route::get('/', 'HomeController@showIndex'); Route::get('terms', 'HomeController@showTerms'); Route::get('log_error', 'HomeController@logError'); Route::get('invoice_now', 'HomeController@invoiceNow'); +Route::get('keep_alive', 'HomeController@keepAlive'); Route::post('get_started', 'AccountController@getStarted'); // Client visible pages @@ -85,7 +86,7 @@ Route::group(['middleware' => 'auth'], function() { Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible'); Route::get('hide_message', 'HomeController@hideMessage'); Route::get('force_inline_pdf', 'UserController@forcePDFJS'); - + Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable')); Route::resource('users', 'UserController'); Route::post('users/delete', 'UserController@delete'); @@ -122,6 +123,11 @@ Route::group(['middleware' => 'auth'], function() { Route::get('api/activities/{client_id?}', array('as'=>'api.activities', 'uses'=>'ActivityController@getDatatable')); Route::post('clients/bulk', 'ClientController@bulk'); + Route::resource('tasks', 'TaskController'); + Route::get('api/tasks/{client_id?}', array('as'=>'api.tasks', 'uses'=>'TaskController@getDatatable')); + Route::get('tasks/create/{client_id?}', 'TaskController@create'); + Route::post('tasks/bulk', 'TaskController@bulk'); + Route::get('recurring_invoices', 'InvoiceController@recurringIndex'); Route::get('api/recurring_invoices/{client_id?}', array('as'=>'api.recurring_invoices', 'uses'=>'InvoiceController@getRecurringDatatable')); @@ -215,6 +221,7 @@ define('ENTITY_RECURRING_INVOICE', 'recurring_invoice'); define('ENTITY_PAYMENT', 'payment'); define('ENTITY_CREDIT', 'credit'); define('ENTITY_QUOTE', 'quote'); +define('ENTITY_TASK', 'task'); define('PERSON_CONTACT', 'contact'); define('PERSON_USER', 'user'); @@ -278,6 +285,7 @@ define('MAX_NUM_CLIENTS', 500); define('MAX_NUM_CLIENTS_PRO', 20000); define('MAX_NUM_USERS', 20); define('MAX_SUBDOMAIN_LENGTH', 30); +define('DEFAULT_FONT_SIZE', 9); define('INVOICE_STATUS_DRAFT', 1); define('INVOICE_STATUS_SENT', 2); @@ -331,6 +339,7 @@ define('GATEWAY_BEANSTREAM', 29); define('GATEWAY_PSIGATE', 30); define('GATEWAY_MOOLAH', 31); define('GATEWAY_BITPAY', 42); +define('GATEWAY_DWOLLA', 43); define('EVENT_CREATE_CLIENT', 1); define('EVENT_CREATE_INVOICE', 2); @@ -344,7 +353,7 @@ define('NINJA_GATEWAY_ID', GATEWAY_STRIPE); define('NINJA_GATEWAY_CONFIG', ''); define('NINJA_WEB_URL', 'https://www.invoiceninja.com'); define('NINJA_APP_URL', 'https://app.invoiceninja.com'); -define('NINJA_VERSION', '2.0.1'); +define('NINJA_VERSION', '2.2.0'); define('NINJA_DATE', '2000-01-01'); define('NINJA_FROM_EMAIL', 'maildelivery@invoiceninja.com'); define('RELEASES_URL', 'https://github.com/hillelcoren/invoice-ninja/releases/'); @@ -375,6 +384,7 @@ define('TOKEN_BILLING_ALWAYS', 4); define('PAYMENT_TYPE_PAYPAL', 'PAYMENT_TYPE_PAYPAL'); define('PAYMENT_TYPE_CREDIT_CARD', 'PAYMENT_TYPE_CREDIT_CARD'); define('PAYMENT_TYPE_BITCOIN', 'PAYMENT_TYPE_BITCOIN'); +define('PAYMENT_TYPE_DWOLLA', 'PAYMENT_TYPE_DWOLLA'); define('PAYMENT_TYPE_TOKEN', 'PAYMENT_TYPE_TOKEN'); define('PAYMENT_TYPE_ANY', 'PAYMENT_TYPE_ANY'); @@ -386,11 +396,6 @@ define('GATEWAY_GOOGLE', 33); define('GATEWAY_QUICKBOOKS', 35); */ -/** - * TEST VALUES FOR THE CREDIT CARDS - * NUMBER IS FOR THE BINARY COUNT FOR WHICH IMAGES TO DISPLAY - * card IS FOR CARD IMAGE AND text IS FOR CARD NAME (TO ADD TO alt FOR IMAGE) -**/ $creditCards = [ 1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'], 2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'], @@ -401,75 +406,6 @@ $creditCards = [ define('CREDIT_CARDS', serialize($creditCards)); - -HTML::macro('nav_link', function($url, $text, $url2 = '', $extra = '') { - $class = ( Request::is($url) || Request::is($url.'/*') || Request::is($url2.'/*') ) ? ' class="active"' : ''; - $title = ucwords(trans("texts.$text")) . Utils::getProLabel($text); - return ''.$title.''; -}); - -HTML::macro('tab_link', function($url, $text, $active = false) { - $class = $active ? ' class="active"' : ''; - return ''.$text.''; -}); - -HTML::macro('menu_link', function($type) { - $types = $type.'s'; - $Type = ucfirst($type); - $Types = ucfirst($types); - $class = ( Request::is($types) || Request::is('*'.$type.'*')) && !Request::is('*advanced_settings*') ? ' active' : ''; - - return ''; -}); - -HTML::macro('image_data', function($imagePath) { - return 'data:image/jpeg;base64,' . base64_encode(file_get_contents(public_path().'/'.$imagePath)); -}); - - -HTML::macro('breadcrumbs', function() { - $str = ''; -}); - function uctrans($text) { return ucwords(trans($text)); @@ -489,20 +425,6 @@ function otrans($text) } } -Validator::extend('positive', function($attribute, $value, $parameters) { - return Utils::parseFloat($value) >= 0; -}); - -Validator::extend('has_credit', function($attribute, $value, $parameters) { - $publicClientId = $parameters[0]; - $amount = $parameters[1]; - - $client = \App\Models\Client::scope($publicClientId)->firstOrFail(); - $credit = $client->getTotalCredit(); - - return $credit >= $amount; -}); - /* // Log all SQL queries to laravel.log Event::listen('illuminate.query', function($query, $bindings, $time, $name) @@ -535,4 +457,4 @@ if (Auth::check() && Auth::user()->id === 1) { Auth::loginUsingId(1); } -*/ \ No newline at end of file +*/ diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index 45ca2ac27c87..a68cb5dcf20d 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -333,7 +333,23 @@ class Utils $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); $format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT); - $dateTime = DateTime::createFromFormat('Y-m-d', $date, new DateTimeZone($timezone)); + $dateTime = DateTime::createFromFormat('Y-m-d', $date); + $dateTime->setTimeZone(new DateTimeZone($timezone)); + + return $formatResult ? $dateTime->format($format) : $dateTime; + } + + public static function fromSqlDateTime($date, $formatResult = true) + { + if (!$date || $date == '0000-00-00 00:00:00') { + return ''; + } + + $timezone = Session::get(SESSION_TIMEZONE, DEFAULT_TIMEZONE); + $format = Session::get(SESSION_DATETIME_FORMAT, DEFAULT_DATETIME_FORMAT); + + $dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $date); + $dateTime->setTimeZone(new DateTimeZone($timezone)); return $formatResult ? $dateTime->format($format) : $dateTime; } @@ -404,6 +420,9 @@ class Utils if (count($matches) == 0) { continue; } + usort($matches, function($a, $b) { + return strlen($b) - strlen($a); + }); foreach ($matches as $match) { $offset = 0; $addArray = explode('+', $match); diff --git a/app/Libraries/timesheet_utils.php b/app/Libraries/timesheet_utils.php deleted file mode 100644 index 8a225b81e06a..000000000000 --- a/app/Libraries/timesheet_utils.php +++ /dev/null @@ -1,119 +0,0 @@ - '']; - 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/Listeners/HandleUserLoggedIn.php b/app/Listeners/HandleUserLoggedIn.php index f1f4e36eff1d..bea1ab4df4b5 100644 --- a/app/Listeners/HandleUserLoggedIn.php +++ b/app/Listeners/HandleUserLoggedIn.php @@ -1,22 +1,25 @@ accountRepo = $accountRepo; } /** @@ -26,8 +29,13 @@ class HandleUserLoggedIn { * @return void */ public function handle(UserLoggedIn $event) - { + { $account = Auth::user()->account; + + if (!Utils::isNinja() && empty($account->last_login)) { + $this->accountRepo->registerUser(Auth::user()); + } + $account->last_login = Carbon::now()->toDateTimeString(); $account->save(); diff --git a/app/Models/Account.php b/app/Models/Account.php index 9989227851b7..31877bd31754 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -160,12 +160,19 @@ class Account extends Eloquent return $height; } - public function getNextInvoiceNumber($isQuote = false) + public function getNextInvoiceNumber($isQuote = false, $prefix = '') { $counter = $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter; - $prefix = $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix; + $prefix .= $isQuote ? $this->quote_number_prefix : $this->invoice_number_prefix; + + // confirm the invoice number isn't already taken + do { + $number = $prefix.str_pad($counter, 4, "0", STR_PAD_LEFT); + $check = Invoice::scope()->whereInvoiceNumber($number)->withTrashed()->first(); + $counter++; + } while ($check); - return $prefix.str_pad($counter, 4, "0", STR_PAD_LEFT); + return $number; } public function incrementCounter($invoiceNumber, $isQuote = false, $isRecurring) @@ -212,6 +219,8 @@ class Account extends Eloquent public function getInvoiceLabels() { $data = []; + $custom = (array) json_decode($this->invoice_labels); + $fields = [ 'invoice', 'invoice_date', @@ -241,7 +250,11 @@ class Account extends Eloquent ]; foreach ($fields as $field) { - $data[$field] = trans("texts.$field"); + if (isset($custom[$field]) && $custom[$field]) { + $data[$field] = $custom[$field]; + } else { + $data[$field] = trans("texts.$field"); + } } return $data; diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 4c6ed2c1b572..236bc619b7f9 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -317,8 +317,21 @@ class Activity extends Eloquent $invoice = $payment->invoice; $invoice->balance = $invoice->balance + $payment->amount; + if ($invoice->isPaid() && $invoice->balance > 0) { + $invoice->invoice_status_id = ($invoice->balance == $invoice->amount ? INVOICE_STATUS_DRAFT : INVOICE_STATUS_PARTIAL); + } $invoice->save(); + // deleting a payment from credit creates a new credit + if ($payment->payment_type_id == PAYMENT_TYPE_CREDIT) { + $credit = Credit::createNew(); + $credit->client_id = $client->id; + $credit->credit_date = Carbon::now()->toDateTimeString(); + $credit->balance = $credit->amount = $payment->amount; + $credit->private_notes = $payment->transaction_reference; + $credit->save(); + } + $activity = Activity::getBlank(); $activity->payment_id = $payment->id; $activity->client_id = $invoice->client_id; diff --git a/app/Models/EntityModel.php b/app/Models/EntityModel.php index 018622c7e982..98becf4258c1 100644 --- a/app/Models/EntityModel.php +++ b/app/Models/EntityModel.php @@ -65,7 +65,7 @@ class EntityModel extends Eloquent $accountId = Auth::user()->account_id; } - $query->whereAccountId($accountId); + $query->where($this->getTable() .'.account_id', '=', $accountId); if ($publicId) { if (is_array($publicId)) { diff --git a/app/Models/Gateway.php b/app/Models/Gateway.php index 5af3974f6249..b11a4b28112f 100644 --- a/app/Models/Gateway.php +++ b/app/Models/Gateway.php @@ -7,6 +7,33 @@ class Gateway extends Eloquent { public $timestamps = true; + public static $paymentTypes = [ + PAYMENT_TYPE_CREDIT_CARD, + PAYMENT_TYPE_PAYPAL, + PAYMENT_TYPE_BITCOIN, + PAYMENT_TYPE_DWOLLA + ]; + + public static $hiddenFields = [ + // PayPal + 'headerImageUrl', + 'solutionType', + 'landingPage', + 'brandName', + 'logoImageUrl', + 'borderColor', + // Dwolla + 'returnUrl', + ]; + + public static $optionalFields = [ + // PayPal + 'testMode', + 'developerMode', + // Dwolla + 'sandbox', + ]; + public function getLogoUrl() { return '/images/gateways/logo_'.$this->provider.'.png'; @@ -24,6 +51,8 @@ class Gateway extends Eloquent $link = 'https://www.2checkout.com/referral?r=2c37ac2298'; } elseif ($this->id == GATEWAY_BITPAY) { $link = 'https://bitpay.com/dashboard/signup'; + } elseif ($this->id == GATEWAY_DWOLLA) { + $link = 'https://www.dwolla.com/register'; } $key = 'texts.gateway_help_'.$this->id; @@ -42,6 +71,8 @@ class Gateway extends Eloquent return PAYMENT_TYPE_PAYPAL; } else if ($gatewayId == GATEWAY_BITPAY) { return PAYMENT_TYPE_BITCOIN; + } else if ($gatewayId == GATEWAY_DWOLLA) { + return PAYMENT_TYPE_DWOLLA; } else { return PAYMENT_TYPE_CREDIT_CARD; } diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php index a42c82eb53f3..b7895fda96a9 100644 --- a/app/Models/Invitation.php +++ b/app/Models/Invitation.php @@ -31,9 +31,12 @@ class Invitation extends EntityModel { $this->load('account'); $url = SITE_URL; - + if ($this->account->subdomain) { - $url = str_replace('://www.', "://{$this->account->subdomain}.", $url); + $parsedUrl = parse_url($url); + $host = explode('.', $parsedUrl['host']); + $subdomain = $host[0]; + $url = str_replace("://{$subdomain}.", "://{$this->account->subdomain}.", $url); } return "{$url}/view/{$this->invitation_key}"; diff --git a/app/Models/Project.php b/app/Models/Project.php deleted file mode 100644 index 921090293581..000000000000 --- a/app/Models/Project.php +++ /dev/null @@ -1,49 +0,0 @@ -belongsTo('App\Models\Account'); - } - - public function user() - { - return $this->belongsTo('App\Models\User'); - } - - public function client() - { - return $this->belongsTo('App\Models\Client'); - } - - public function codes() - { - return $this->hasMany('App\Models\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 deleted file mode 100644 index 1eece95d4c65..000000000000 --- a/app/Models/ProjectCode.php +++ /dev/null @@ -1,51 +0,0 @@ -belongsTo('App\Models\Account'); - } - - public function user() - { - return $this->belongsTo('App\Models\User'); - } - - public function project() - { - return $this->belongsTo('App\Models\Project'); - } - - public function events() - { - return $this->hasMany('App\Models\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/Task.php b/app/Models/Task.php new file mode 100644 index 000000000000..a6be8204e7e7 --- /dev/null +++ b/app/Models/Task.php @@ -0,0 +1,36 @@ +belongsTo('App\Models\Account'); + } + + public function client() + { + return $this->belongsTo('App\Models\Client')->withTrashed(); + } +} + +Task::created(function ($task) { + //Activity::createTask($task); +}); + +Task::updating(function ($task) { + //Activity::updateTask($task); +}); + +Task::deleting(function ($task) { + //Activity::archiveTask($task); +}); + +Task::restoring(function ($task) { + //Activity::restoreTask($task); +}); diff --git a/app/Models/Timesheet.php b/app/Models/Timesheet.php deleted file mode 100644 index 085cb3ef3390..000000000000 --- a/app/Models/Timesheet.php +++ /dev/null @@ -1,26 +0,0 @@ -belongsTo('App\Models\Account'); - } - - public function user() - { - return $this->belongsTo('App\Models\User'); - } - - public function timesheet_events() - { - return $this->hasMany('App\Models\TimeSheetEvent'); - } -} diff --git a/app/Models/TimesheetEvent.php b/app/Models/TimesheetEvent.php deleted file mode 100644 index 44a04f842119..000000000000 --- a/app/Models/TimesheetEvent.php +++ /dev/null @@ -1,128 +0,0 @@ -attributes['org_updated_at'] = $value->getTimestamp(); - }*/ - - public function account() - { - return $this->belongsTo('App\Models\Account'); - } - - public function user() - { - return $this->belongsTo('App\Models\User'); - } - - public function source() - { - return $this->belongsTo('App\Models\TimesheetEventSource'); - } - - public function timesheet() - { - return $this->belongsTo('App\Models\Timesheet'); - } - - public function project() - { - return $this->belongsTo('App\Models\Project'); - } - - public function project_code() - { - return $this->belongsTo('App\Models\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 deleted file mode 100644 index 99ee62f69f86..000000000000 --- a/app/Models/TimesheetEventSource.php +++ /dev/null @@ -1,46 +0,0 @@ -belongsTo('App\Models\Account'); - } - - public function user() - { - return $this->belongsTo('App\Models\User'); - } - - public function events() - { - return $this->hasMany('App\Models\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/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php index 2a5276787723..5ff208f36239 100644 --- a/app/Ninja/Repositories/ClientRepository.php +++ b/app/Ninja/Repositories/ClientRepository.php @@ -49,7 +49,6 @@ class ClientRepository { if (!$publicId || $publicId == "-1") { $client = Client::createNew(); - $client->currency_id = 1; $contact = Contact::createNew(); $contact->is_primary = true; $contact->send_invoice = true; diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index fa67b6270e1a..43ac20c5bc26 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -4,6 +4,7 @@ use App\Models\Invoice; use App\Models\InvoiceItem; use App\Models\Invitation; use App\Models\Product; +use App\Models\Task; use Utils; class InvoiceRepository @@ -51,10 +52,10 @@ class InvoiceRepository ->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) + ->where('clients.deleted_at', '=', null) ->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) { @@ -158,7 +159,7 @@ class InvoiceRepository } if ($entityType == ENTITY_INVOICE) { - if ($model->invoice_status_id < INVOICE_STATUS_PAID) { + if ($model->balance > 0) { $str .= '
  • '.trans('texts.enter_payment').'
  • '; } @@ -291,6 +292,12 @@ class InvoiceRepository $invoice->terms = trim($data['terms']) ? trim($data['terms']) : (!$publicId && $account->invoice_terms ? $account->invoice_terms : ''); $invoice->invoice_footer = trim($data['invoice_footer']) ? trim($data['invoice_footer']) : (!$publicId && $account->invoice_footer ? $account->invoice_footer : ''); $invoice->public_notes = trim($data['public_notes']); + + // process date variables + $invoice->terms = Utils::processVariables($invoice->terms); + $invoice->invoice_footer = Utils::processVariables($invoice->invoice_footer); + $invoice->public_notes = Utils::processVariables($invoice->public_notes); + $invoice->po_number = trim($data['po_number']); $invoice->invoice_design_id = $data['invoice_design_id']; @@ -374,7 +381,12 @@ class InvoiceRepository continue; } - if ($item['product_key']) { + if (isset($item['task_public_id']) && $item['task_public_id']) { + $task = Task::scope($item['task_public_id'])->where('invoice_id', '=', null)->firstOrFail(); + $task->invoice_id = $invoice->id; + $task->client_id = $invoice->client_id; + $task->save(); + } else if ($item['product_key']) { $product = Product::findProductByKey(trim($item['product_key'])); if (!$product) { @@ -423,7 +435,7 @@ class InvoiceRepository && $account->share_counter) { $invoiceNumber = $invoice->invoice_number; - if (strpos($invoiceNumber, $account->quote_number_prefix) === 0) { + if ($account->quote_number_prefix && strpos($invoiceNumber, $account->quote_number_prefix) === 0) { $invoiceNumber = substr($invoiceNumber, strlen($account->quote_number_prefix)); } $clone->invoice_number = $account->invoice_number_prefix.$invoiceNumber; @@ -453,7 +465,8 @@ class InvoiceRepository 'custom_value1', 'custom_value2', 'custom_taxes1', - 'custom_taxes2', ] as $field) { + 'custom_taxes2', + 'partial'] as $field) { $clone->$field = $invoice->$field; } diff --git a/app/Ninja/Repositories/PaymentRepository.php b/app/Ninja/Repositories/PaymentRepository.php index 3d7134c3de4c..8c0a87839d68 100644 --- a/app/Ninja/Repositories/PaymentRepository.php +++ b/app/Ninja/Repositories/PaymentRepository.php @@ -15,11 +15,13 @@ class PaymentRepository ->join('invoices', 'invoices.id', '=', 'payments.invoice_id') ->join('contacts', 'contacts.client_id', '=', 'clients.id') ->leftJoin('payment_types', 'payment_types.id', '=', 'payments.payment_type_id') + ->leftJoin('account_gateways', 'account_gateways.id', '=', 'payments.account_gateway_id') + ->leftJoin('gateways', 'gateways.id', '=', 'account_gateways.gateway_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'); + ->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', 'gateways.name as gateway_name'); if (!\Session::get('show_trash:payment')) { $query->where('payments.deleted_at', '=', null) @@ -78,6 +80,11 @@ class PaymentRepository $rules['payment_type_id'] = 'has_credit:'.$input['client'].','.$input['amount']; } + if (isset($input['invoice']) && $input['invoice']) { + $invoice = Invoice::scope($input['invoice'])->firstOrFail(); + $rules['amount'] .= "|less_than:{$invoice->balance}"; + } + $validator = \Validator::make($input, $rules); if ($validator->fails()) { diff --git a/app/Ninja/Repositories/TaskRepository.php b/app/Ninja/Repositories/TaskRepository.php new file mode 100644 index 000000000000..a601ff3a7d2f --- /dev/null +++ b/app/Ninja/Repositories/TaskRepository.php @@ -0,0 +1,102 @@ +leftJoin('clients', 'tasks.client_id', '=', 'clients.id') + ->leftJoin('contacts', 'contacts.client_id', '=', 'clients.id') + ->leftJoin('invoices', 'invoices.id', '=', 'tasks.invoice_id') + ->where('tasks.account_id', '=', Auth::user()->account_id) + ->where(function ($query) { + $query->where('contacts.is_primary', '=', true) + ->orWhere('contacts.is_primary', '=', null); + }) + ->where('contacts.deleted_at', '=', null) + ->where('clients.deleted_at', '=', null) + ->select('tasks.public_id', 'clients.name as client_name', 'clients.public_id as client_public_id', 'contacts.first_name', 'contacts.email', 'contacts.last_name', 'invoices.invoice_status_id', 'tasks.start_time', 'tasks.description', 'tasks.duration', 'tasks.is_deleted', 'tasks.deleted_at', 'invoices.invoice_number', 'invoices.public_id as invoice_public_id'); + + if ($clientPublicId) { + $query->where('clients.public_id', '=', $clientPublicId); + } + + if (!Session::get('show_trash:task')) { + $query->where('tasks.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('tasks.description', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function save($publicId, $data) + { + if ($publicId) { + $task = Task::scope($publicId)->firstOrFail(); + } else { + $task = Task::createNew(); + } + + if (isset($data['client']) && $data['client']) { + $task->client_id = Client::getPrivateId($data['client']); + } + if (isset($data['description'])) { + $task->description = trim($data['description']); + } + + if ($data['action'] == 'start') { + $task->start_time = Carbon::now()->toDateTimeString(); + $task->duration = -1; + } else if ($data['action'] == 'stop' && $task->duration == -1) { + $task->duration = strtotime('now') - strtotime($task->start_time); + } else if ($data['action'] == 'save' && $task->duration != -1) { + $task->start_time = $data['start_time']; + $task->duration = $data['duration']; + } + + $task->duration = max($task->duration, -1); + + $task->save(); + + return $task; + } + + public function bulk($ids, $action) + { + $tasks = Task::withTrashed()->scope($ids)->get(); + + foreach ($tasks as $task) { + if ($action == 'restore') { + $task->restore(); + + $task->is_deleted = false; + $task->save(); + } else { + if ($action == 'delete') { + $task->is_deleted = true; + $task->save(); + } + + $task->delete(); + } + } + + return count($tasks); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index ff9d6f68fb66..a55ecfd5b476 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -1,5 +1,12 @@ '.$title.''; + }); + + HTML::macro('tab_link', function($url, $text, $active = false) { + $class = $active ? ' class="active"' : ''; + return ''.$text.''; + }); + + HTML::macro('menu_link', function($type) { + $types = $type.'s'; + $Type = ucfirst($type); + $Types = ucfirst($types); + $class = ( Request::is($types) || Request::is('*'.$type.'*')) && !Request::is('*advanced_settings*') ? ' active' : ''; + + $str = ''; + + return $str; + }); + + HTML::macro('image_data', function($imagePath) { + return 'data:image/jpeg;base64,' . base64_encode(file_get_contents(public_path().'/'.$imagePath)); + }); + + + HTML::macro('breadcrumbs', function() { + $str = ''; + }); + + Validator::extend('positive', function($attribute, $value, $parameters) { + return Utils::parseFloat($value) >= 0; + }); + + Validator::extend('has_credit', function($attribute, $value, $parameters) { + $publicClientId = $parameters[0]; + $amount = $parameters[1]; + + $client = \App\Models\Client::scope($publicClientId)->firstOrFail(); + $credit = $client->getTotalCredit(); + + return $credit >= $amount; + }); + + + Validator::extend('less_than', function($attribute, $value, $parameters) { + return floatval($value) <= floatval($parameters[0]); + }); + + Validator::replacer('less_than', function($message, $attribute, $rule, $parameters) { + return str_replace(':value', $parameters[0], $message); + }); } /** diff --git a/bower.json b/bower.json index 0f700cb634df..11d0755064c3 100644 --- a/bower.json +++ b/bower.json @@ -19,7 +19,8 @@ "spectrum": "~1.3.4", "d3": "~3.4.11", "handsontable": "*", - "pdfmake": "*" + "pdfmake": "*", + "moment": "*" }, "resolutions": { "jquery": "~1.11" diff --git a/composer.json b/composer.json index 23390e0c1890..96c3b4314fe5 100644 --- a/composer.json +++ b/composer.json @@ -33,8 +33,11 @@ "coatesap/omnipay-realex": "~2.0", "fruitcakestudio/omnipay-sisow": "~2.0", "alfaproject/omnipay-skrill": "dev-master", - "illuminate/html": "5.*", - "omnipay/bitpay": "dev-master" + "omnipay/bitpay": "dev-master", + "guzzlehttp/guzzle": "~5.0", + "laravelcollective/html": "~5.0", + "wildbit/laravel-postmark-provider": "dev-master", + "Dwolla/omnipay-dwolla": "dev-master" }, "require-dev": { "phpunit/phpunit": "~4.0", diff --git a/composer.lock b/composer.lock index 55b4a6af45b4..77c352837051 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "456867b27b6caddd5d681f7bad019be4", + "hash": "d0351e24aaf5ec67780a029d5deaebf4", "packages": [ { "name": "alfaproject/omnipay-neteller", @@ -120,26 +120,26 @@ "source": { "type": "git", "url": "https://github.com/formers/former.git", - "reference": "4a03cdd08f1bdd975bd2521bed74ab38bf590388" + "reference": "a2fbec9d29cf820d54dfa6f0ddb875339d77e930" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/formers/former/zipball/4a03cdd08f1bdd975bd2521bed74ab38bf590388", - "reference": "4a03cdd08f1bdd975bd2521bed74ab38bf590388", + "url": "https://api.github.com/repos/formers/former/zipball/a2fbec9d29cf820d54dfa6f0ddb875339d77e930", + "reference": "a2fbec9d29cf820d54dfa6f0ddb875339d77e930", "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.*", + "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.*", + "illuminate/database": "~5.0", "mockery/mockery": "~0.9.1", "phpunit/phpunit": "~4" }, @@ -171,7 +171,7 @@ "foundation", "laravel" ], - "time": "2015-04-20 13:53:18" + "time": "2015-06-01 18:46:46" }, { "name": "anahkiasen/html-object", @@ -384,20 +384,20 @@ }, { "name": "classpreloader/classpreloader", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/ClassPreloader/ClassPreloader.git", - "reference": "0544616ba33fb2a6b792b3a7822650810c6d65d9" + "reference": "b76f3f4f603ebbe7e64351a7ef973431ddaf7b27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/0544616ba33fb2a6b792b3a7822650810c6d65d9", - "reference": "0544616ba33fb2a6b792b3a7822650810c6d65d9", + "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/b76f3f4f603ebbe7e64351a7ef973431ddaf7b27", + "reference": "b76f3f4f603ebbe7e64351a7ef973431ddaf7b27", "shasum": "" }, "require": { - "nikic/php-parser": "^1.2.2", + "nikic/php-parser": "~1.3", "php": ">=5.3.3", "symfony/console": "~2.1", "symfony/filesystem": "~2.1", @@ -412,7 +412,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -425,13 +425,13 @@ "MIT" ], "authors": [ - { - "name": "Graham Campbell", - "email": "graham@mineuk.com" - }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com" + }, + { + "name": "Graham Campbell", + "email": "graham@cachethq.io" } ], "description": "Helps class loading performance by generating a single PHP file containing all of the autoloaded files for a specific use case", @@ -440,7 +440,7 @@ "class", "preload" ], - "time": "2015-04-15 21:59:30" + "time": "2015-05-26 10:57:51" }, { "name": "coatesap/omnipay-datacash", @@ -1169,6 +1169,63 @@ ], "time": "2014-09-09 13:34:57" }, + { + "name": "dwolla/omnipay-dwolla", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Dwolla/omnipay-dwolla.git", + "reference": "f6cf1650a368fd9388a63c5af47be2873782c006" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Dwolla/omnipay-dwolla/zipball/f6cf1650a368fd9388a63c5af47be2873782c006", + "reference": "f6cf1650a368fd9388a63c5af47be2873782c006", + "shasum": "" + }, + "require": { + "omnipay/common": "~2.0" + }, + "require-dev": { + "omnipay/tests": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Omnipay\\Dwolla\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrian Macneil", + "email": "adrian@adrianmacneil.com" + }, + { + "name": "David Stancu", + "homepage": "https://github.com/mach-kernel" + } + ], + "description": "Dwolla support for the Omnipay payment library", + "homepage": "https://github.com/mach-kernel/omnipay-dwolla", + "keywords": [ + "dwolla", + "gateway", + "merchant", + "omnipay", + "pay", + "payment" + ], + "time": "2015-06-04 22:32:07" + }, { "name": "fruitcakestudio/omnipay-sisow", "version": "v2.0.1", @@ -1320,6 +1377,165 @@ ], "time": "2015-03-18 18:23:50" }, + { + "name": "guzzlehttp/guzzle", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "f3c8c22471cb55475105c14769644a49c3262b93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f3c8c22471cb55475105c14769644a49c3262b93", + "reference": "f3c8c22471cb55475105c14769644a49c3262b93", + "shasum": "" + }, + "require": { + "guzzlehttp/ringphp": "^1.1", + "php": ">=5.4.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0", + "psr/log": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-05-20 03:47:55" + }, + { + "name": "guzzlehttp/ringphp", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/RingPHP.git", + "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b", + "shasum": "" + }, + "require": { + "guzzlehttp/streams": "~3.0", + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "ext-curl": "Guzzle will use specific adapters if cURL is present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Ring\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", + "time": "2015-05-20 03:37:09" + }, + { + "name": "guzzlehttp/streams", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/streams.git", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple abstraction over streams of data", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "stream" + ], + "time": "2014-10-12 19:18:40" + }, { "name": "illuminate/html", "version": "v5.0.0", @@ -1372,12 +1588,12 @@ "source": { "type": "git", "url": "https://github.com/Intervention/image.git", - "reference": "6626d7624ac0895137a38c123943afedd0827efc" + "reference": "1f33a7c6c5847ddaa4c0c347be375d38ee4c2f43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Intervention/image/zipball/6626d7624ac0895137a38c123943afedd0827efc", - "reference": "6626d7624ac0895137a38c123943afedd0827efc", + "url": "https://api.github.com/repos/Intervention/image/zipball/1f33a7c6c5847ddaa4c0c347be375d38ee4c2f43", + "reference": "1f33a7c6c5847ddaa4c0c347be375d38ee4c2f43", "shasum": "" }, "require": { @@ -1420,7 +1636,7 @@ "thumbnail", "watermark" ], - "time": "2015-04-24 14:50:48" + "time": "2015-05-14 08:43:38" }, { "name": "ircmaxell/password-compat", @@ -1650,16 +1866,16 @@ }, { "name": "laravel/framework", - "version": "v5.0.28", + "version": "v5.0.32", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "06a09429322cf53e5bd4587db1060f02a291562e" + "reference": "85f12207cf45cc288e9e6b9b5d184aad5f08e2ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/06a09429322cf53e5bd4587db1060f02a291562e", - "reference": "06a09429322cf53e5bd4587db1060f02a291562e", + "url": "https://api.github.com/repos/laravel/framework/zipball/85f12207cf45cc288e9e6b9b5d184aad5f08e2ca", + "reference": "85f12207cf45cc288e9e6b9b5d184aad5f08e2ca", "shasum": "" }, "require": { @@ -1772,7 +1988,57 @@ "framework", "laravel" ], - "time": "2015-04-21 01:44:32" + "time": "2015-05-29 18:56:49" + }, + { + "name": "laravelcollective/html", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/LaravelCollective/html.git", + "reference": "c55fda58b1a9a1b58bd04f97e0fb9ebc238a0a94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/LaravelCollective/html/zipball/c55fda58b1a9a1b58bd04f97e0fb9ebc238a0a94", + "reference": "c55fda58b1a9a1b58bd04f97e0fb9ebc238a0a94", + "shasum": "" + }, + "require": { + "illuminate/http": "~5.0", + "illuminate/routing": "~5.0", + "illuminate/session": "~5.0", + "illuminate/support": "~5.0", + "php": ">=5.4.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Collective\\Html\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + }, + { + "name": "Adam Engebretson", + "email": "adam@laravelcollective.com" + } + ], + "time": "2015-05-06 14:23:37" }, { "name": "league/flysystem", @@ -2136,21 +2402,21 @@ }, { "name": "nesbot/carbon", - "version": "1.18.0", + "version": "1.19.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36" + "reference": "68868e0b02d2d803d0052a59d4e5003cccf87320" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36", - "reference": "99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/68868e0b02d2d803d0052a59d4e5003cccf87320", + "reference": "68868e0b02d2d803d0052a59d4e5003cccf87320", "shasum": "" }, "require": { "php": ">=5.3.0", - "symfony/translation": "2.6.*" + "symfony/translation": "~2.6" }, "require-dev": { "phpunit/phpunit": "~4.0" @@ -2179,20 +2445,20 @@ "datetime", "time" ], - "time": "2015-03-26 03:05:57" + "time": "2015-05-09 03:23:44" }, { "name": "nikic/php-parser", - "version": "v1.2.2", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "08f97eb4efa029e2fafb6d8c98b71731bf0cf621" + "reference": "dff239267fd1befa1cd40430c9ed12591aa720ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/08f97eb4efa029e2fafb6d8c98b71731bf0cf621", - "reference": "08f97eb4efa029e2fafb6d8c98b71731bf0cf621", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dff239267fd1befa1cd40430c9ed12591aa720ca", + "reference": "dff239267fd1befa1cd40430c9ed12591aa720ca", "shasum": "" }, "require": { @@ -2202,7 +2468,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -2224,7 +2490,7 @@ "parser", "php" ], - "time": "2015-04-03 14:33:59" + "time": "2015-05-02 15:40:40" }, { "name": "omnipay/2checkout", @@ -3152,16 +3418,16 @@ }, { "name": "omnipay/netaxept", - "version": "v2.2.0", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-netaxept.git", - "reference": "a661c212428703175f17e3f8f0a32f24b06fe9f8" + "reference": "a15ab75a338726536880b9ac0c1e6071a81342f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-netaxept/zipball/a661c212428703175f17e3f8f0a32f24b06fe9f8", - "reference": "a661c212428703175f17e3f8f0a32f24b06fe9f8", + "url": "https://api.github.com/repos/thephpleague/omnipay-netaxept/zipball/a15ab75a338726536880b9ac0c1e6071a81342f9", + "reference": "a15ab75a338726536880b9ac0c1e6071a81342f9", "shasum": "" }, "require": { @@ -3205,7 +3471,7 @@ "pay", "payment" ], - "time": "2015-01-12 16:10:59" + "time": "2015-05-08 15:13:17" }, { "name": "omnipay/netbanx", @@ -3843,16 +4109,16 @@ }, { "name": "omnipay/targetpay", - "version": "v2.2.0", + "version": "v2.2.1", "source": { "type": "git", - "url": "https://github.com/omnipay/targetpay.git", - "reference": "7274721c97f6f8ad3d2a8b4dea474ac548c45bac" + "url": "https://github.com/thephpleague/omnipay-targetpay.git", + "reference": "fc74d5d0f7929ce86298faec9e195985d7d4afe0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/omnipay/targetpay/zipball/7274721c97f6f8ad3d2a8b4dea474ac548c45bac", - "reference": "7274721c97f6f8ad3d2a8b4dea474ac548c45bac", + "url": "https://api.github.com/repos/thephpleague/omnipay-targetpay/zipball/fc74d5d0f7929ce86298faec9e195985d7d4afe0", + "reference": "fc74d5d0f7929ce86298faec9e195985d7d4afe0", "shasum": "" }, "require": { @@ -3883,11 +4149,11 @@ }, { "name": "Omnipay Contributors", - "homepage": "https://github.com/omnipay/targetpay/contributors" + "homepage": "https://github.com/thephpleague/omnipay-targetpay/contributors" } ], "description": "TargetPay driver for the Omnipay payment processing library", - "homepage": "https://github.com/omnipay/targetpay", + "homepage": "https://github.com/thephpleague/omnipay-targetpay", "keywords": [ "gateway", "merchant", @@ -3896,7 +4162,7 @@ "payment", "targetpay" ], - "time": "2014-04-14 12:23:56" + "time": "2014-09-17 00:38:39" }, { "name": "omnipay/worldpay", @@ -4172,6 +4438,50 @@ ], "time": "2015-03-26 18:43:54" }, + { + "name": "react/promise", + "version": "v2.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/365fcee430dfa4ace1fbc75737ca60ceea7eeeef", + "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@googlemail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "time": "2014-12-30 13:32:42" + }, { "name": "swiftmailer/swiftmailer", "version": "v5.4.0", @@ -4226,21 +4536,20 @@ }, { "name": "symfony/class-loader", - "version": "v2.6.6", - "target-dir": "Symfony/Component/ClassLoader", + "version": "v2.7.0", "source": { "type": "git", "url": "https://github.com/symfony/ClassLoader.git", - "reference": "861765b3e5f32979de5bd19ad2577cbb830a29d5" + "reference": "fa19598cb708b92d983b34aae313f57c217f9386" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ClassLoader/zipball/861765b3e5f32979de5bd19ad2577cbb830a29d5", - "reference": "861765b3e5f32979de5bd19ad2577cbb830a29d5", + "url": "https://api.github.com/repos/symfony/ClassLoader/zipball/fa19598cb708b92d983b34aae313f57c217f9386", + "reference": "fa19598cb708b92d983b34aae313f57c217f9386", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.9" }, "require-dev": { "symfony/finder": "~2.0,>=2.0.5", @@ -4249,11 +4558,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\ClassLoader\\": "" } }, @@ -4262,32 +4571,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony ClassLoader Component", - "homepage": "http://symfony.com", - "time": "2015-03-27 10:19:51" + "homepage": "https://symfony.com", + "time": "2015-05-15 13:33:16" }, { "name": "symfony/console", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "5b91dc4ed5eb08553f57f6df04c4730a73992667" + "reference": "b5ec0c11a204718f2b656357f5505a8e578f30dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/5b91dc4ed5eb08553f57f6df04c4730a73992667", - "reference": "5b91dc4ed5eb08553f57f6df04c4730a73992667", + "url": "https://api.github.com/repos/symfony/Console/zipball/b5ec0c11a204718f2b656357f5505a8e578f30dd", + "reference": "b5ec0c11a204718f2b656357f5505a8e578f30dd", "shasum": "" }, "require": { @@ -4320,32 +4629,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Console Component", - "homepage": "http://symfony.com", - "time": "2015-03-30 15:54:10" + "homepage": "https://symfony.com", + "time": "2015-05-29 14:42:58" }, { "name": "symfony/debug", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/Debug", "source": { "type": "git", "url": "https://github.com/symfony/Debug.git", - "reference": "d49a46a20a8f0544aedac54466750ad787d3d3e3" + "reference": "4851a041c48e76b91a221db84ab5850daa6a7b33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Debug/zipball/d49a46a20a8f0544aedac54466750ad787d3d3e3", - "reference": "d49a46a20a8f0544aedac54466750ad787d3d3e3", + "url": "https://api.github.com/repos/symfony/Debug/zipball/4851a041c48e76b91a221db84ab5850daa6a7b33", + "reference": "4851a041c48e76b91a221db84ab5850daa6a7b33", "shasum": "" }, "require": { @@ -4381,36 +4690,35 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Debug Component", - "homepage": "http://symfony.com", - "time": "2015-03-22 16:55:57" + "homepage": "https://symfony.com", + "time": "2015-05-20 13:09:45" }, { "name": "symfony/event-dispatcher", - "version": "v2.6.6", - "target-dir": "Symfony/Component/EventDispatcher", + "version": "v2.7.0", "source": { "type": "git", "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284" + "reference": "687039686d0e923429ba6e958d0baa920cd5d458" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/70f7c8478739ad21e3deef0d977b38c77f1fb284", - "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/687039686d0e923429ba6e958d0baa920cd5d458", + "reference": "687039686d0e923429ba6e958d0baa920cd5d458", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.9" }, "require-dev": { "psr/log": "~1.0", @@ -4427,11 +4735,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" } }, @@ -4440,36 +4748,35 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony EventDispatcher Component", - "homepage": "http://symfony.com", - "time": "2015-03-13 17:37:22" + "homepage": "https://symfony.com", + "time": "2015-05-02 15:21:08" }, { "name": "symfony/filesystem", - "version": "v2.6.6", - "target-dir": "Symfony/Component/Filesystem", + "version": "v2.7.0", "source": { "type": "git", "url": "https://github.com/symfony/Filesystem.git", - "reference": "4983964b3693e4f13449cb3800c64a9112c301b4" + "reference": "ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/4983964b3693e4f13449cb3800c64a9112c301b4", - "reference": "4983964b3693e4f13449cb3800c64a9112c301b4", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba", + "reference": "ae4551fd6d4d4f51f2e7390fbc902fbd67f3b7ba", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.9" }, "require-dev": { "symfony/phpunit-bridge": "~2.7" @@ -4477,11 +4784,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\Filesystem\\": "" } }, @@ -4490,32 +4797,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Filesystem Component", - "homepage": "http://symfony.com", - "time": "2015-03-22 16:55:57" + "homepage": "https://symfony.com", + "time": "2015-05-15 13:33:16" }, { "name": "symfony/finder", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "5dbe2e73a580618f5b4880fda93406eed25de251" + "reference": "ffedd3e0ff8155188155e9322fe21b9ee012ac14" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/5dbe2e73a580618f5b4880fda93406eed25de251", - "reference": "5dbe2e73a580618f5b4880fda93406eed25de251", + "url": "https://api.github.com/repos/symfony/Finder/zipball/ffedd3e0ff8155188155e9322fe21b9ee012ac14", + "reference": "ffedd3e0ff8155188155e9322fe21b9ee012ac14", "shasum": "" }, "require": { @@ -4540,32 +4847,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Finder Component", - "homepage": "http://symfony.com", - "time": "2015-03-30 15:54:10" + "homepage": "https://symfony.com", + "time": "2015-05-15 13:32:45" }, { "name": "symfony/http-foundation", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/HttpFoundation", "source": { "type": "git", "url": "https://github.com/symfony/HttpFoundation.git", - "reference": "8a6337233f08f7520de97f4ffd6f00e947d892f9" + "reference": "f9b28dcc6d3e50f5568b42dda7292656a9fe8432" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/8a6337233f08f7520de97f4ffd6f00e947d892f9", - "reference": "8a6337233f08f7520de97f4ffd6f00e947d892f9", + "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/f9b28dcc6d3e50f5568b42dda7292656a9fe8432", + "reference": "f9b28dcc6d3e50f5568b42dda7292656a9fe8432", "shasum": "" }, "require": { @@ -4594,32 +4901,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony HttpFoundation Component", - "homepage": "http://symfony.com", - "time": "2015-04-01 16:50:12" + "homepage": "https://symfony.com", + "time": "2015-05-22 14:53:08" }, { "name": "symfony/http-kernel", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/HttpKernel", "source": { "type": "git", "url": "https://github.com/symfony/HttpKernel.git", - "reference": "3829cacfe21eaf3f73604a62d79183d1f6e792c4" + "reference": "7c883eb1a5d8b52b1fa6d4134b82304c6bb7007f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/3829cacfe21eaf3f73604a62d79183d1f6e792c4", - "reference": "3829cacfe21eaf3f73604a62d79183d1f6e792c4", + "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/7c883eb1a5d8b52b1fa6d4134b82304c6bb7007f", + "reference": "7c883eb1a5d8b52b1fa6d4134b82304c6bb7007f", "shasum": "" }, "require": { @@ -4672,32 +4979,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony HttpKernel Component", - "homepage": "http://symfony.com", - "time": "2015-04-01 16:55:26" + "homepage": "https://symfony.com", + "time": "2015-05-29 22:55:07" }, { "name": "symfony/process", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/Process", "source": { "type": "git", "url": "https://github.com/symfony/Process.git", - "reference": "a8bebaec1a9dc6cde53e0250e32917579b0be552" + "reference": "7856d78ab6cce6e59d02d9e1a873441f6bd21306" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Process/zipball/a8bebaec1a9dc6cde53e0250e32917579b0be552", - "reference": "a8bebaec1a9dc6cde53e0250e32917579b0be552", + "url": "https://api.github.com/repos/symfony/Process/zipball/7856d78ab6cce6e59d02d9e1a873441f6bd21306", + "reference": "7856d78ab6cce6e59d02d9e1a873441f6bd21306", "shasum": "" }, "require": { @@ -4722,32 +5029,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Process Component", - "homepage": "http://symfony.com", - "time": "2015-03-30 15:54:10" + "homepage": "https://symfony.com", + "time": "2015-05-15 13:32:45" }, { "name": "symfony/routing", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/Routing", "source": { "type": "git", "url": "https://github.com/symfony/Routing.git", - "reference": "4e173a645b63ff60a124f3741b4f15feebd908fa" + "reference": "dc9df18a1cfe87de65e270e8f01407ca6d7c39cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Routing/zipball/4e173a645b63ff60a124f3741b4f15feebd908fa", - "reference": "4e173a645b63ff60a124f3741b4f15feebd908fa", + "url": "https://api.github.com/repos/symfony/Routing/zipball/dc9df18a1cfe87de65e270e8f01407ca6d7c39cb", + "reference": "dc9df18a1cfe87de65e270e8f01407ca6d7c39cb", "shasum": "" }, "require": { @@ -4785,38 +5092,38 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Routing Component", - "homepage": "http://symfony.com", + "homepage": "https://symfony.com", "keywords": [ "router", "routing", "uri", "url" ], - "time": "2015-03-30 15:54:10" + "time": "2015-05-15 13:32:45" }, { "name": "symfony/security-core", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/Security/Core", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "d25c17db741f58c0f615e52006a47f6fb23cd9b3" + "reference": "1ad0ee4b2a1ab32924cd0be397f0196b5d47e5d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/d25c17db741f58c0f615e52006a47f6fb23cd9b3", - "reference": "d25c17db741f58c0f615e52006a47f6fb23cd9b3", + "url": "https://api.github.com/repos/symfony/security-core/zipball/1ad0ee4b2a1ab32924cd0be397f0196b5d47e5d0", + "reference": "1ad0ee4b2a1ab32924cd0be397f0196b5d47e5d0", "shasum": "" }, "require": { @@ -4855,32 +5162,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Security Component - Core Library", - "homepage": "http://symfony.com", - "time": "2015-03-30 15:54:10" + "homepage": "https://symfony.com", + "time": "2015-05-15 13:53:19" }, { "name": "symfony/translation", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/Translation", "source": { "type": "git", "url": "https://github.com/symfony/Translation.git", - "reference": "bd939f05cdaca128f4ddbae1b447d6f0203b60af" + "reference": "89cdf3c43bc24c85dd8173dfcf5a979a95e5bd9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/bd939f05cdaca128f4ddbae1b447d6f0203b60af", - "reference": "bd939f05cdaca128f4ddbae1b447d6f0203b60af", + "url": "https://api.github.com/repos/symfony/Translation/zipball/89cdf3c43bc24c85dd8173dfcf5a979a95e5bd9c", + "reference": "89cdf3c43bc24c85dd8173dfcf5a979a95e5bd9c", "shasum": "" }, "require": { @@ -4914,32 +5221,32 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Translation Component", - "homepage": "http://symfony.com", - "time": "2015-03-30 15:54:10" + "homepage": "https://symfony.com", + "time": "2015-05-29 14:42:58" }, { "name": "symfony/var-dumper", - "version": "v2.6.6", + "version": "v2.6.9", "target-dir": "Symfony/Component/VarDumper", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "aafae00236e147568832de3c65ccb94cfc836278" + "reference": "89eec96645fb44af4a454a26c74c72ba6311f5bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/aafae00236e147568832de3c65ccb94cfc836278", - "reference": "aafae00236e147568832de3c65ccb94cfc836278", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/89eec96645fb44af4a454a26c74c72ba6311f5bc", + "reference": "89eec96645fb44af4a454a26c74c72ba6311f5bc", "shasum": "" }, "require": { @@ -4970,22 +5277,22 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony mechanism for exploring and dumping PHP variables", - "homepage": "http://symfony.com", + "homepage": "https://symfony.com", "keywords": [ "debug", "dump" ], - "time": "2015-03-31 08:12:29" + "time": "2015-05-01 14:14:24" }, { "name": "twbs/bootstrap", @@ -5040,16 +5347,16 @@ }, { "name": "vlucas/phpdotenv", - "version": "v1.1.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "732d2adb7d916c9593b9d58c3b0d9ebefead07aa" + "reference": "0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/732d2adb7d916c9593b9d58c3b0d9ebefead07aa", - "reference": "732d2adb7d916c9593b9d58c3b0d9ebefead07aa", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa", + "reference": "0cac554ce06277e33ddf9f0b7ade4b8bbf2af3fa", "shasum": "" }, "require": { @@ -5059,11 +5366,6 @@ "phpunit/phpunit": "~4.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-0": { "Dotenv": "src/" @@ -5087,7 +5389,7 @@ "env", "environment" ], - "time": "2014-12-05 15:19:21" + "time": "2015-05-30 15:59:26" }, { "name": "webpatser/laravel-countries", @@ -5095,12 +5397,12 @@ "source": { "type": "git", "url": "https://github.com/webpatser/laravel-countries.git", - "reference": "0b5bf74d85470430af7296e9f316d6f4ad9a5fa4" + "reference": "3d2ee664037783d0df629a178437981e6f1a1f8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webpatser/laravel-countries/zipball/0b5bf74d85470430af7296e9f316d6f4ad9a5fa4", - "reference": "0b5bf74d85470430af7296e9f316d6f4ad9a5fa4", + "url": "https://api.github.com/repos/webpatser/laravel-countries/zipball/3d2ee664037783d0df629a178437981e6f1a1f8b", + "reference": "3d2ee664037783d0df629a178437981e6f1a1f8b", "shasum": "" }, "require": { @@ -5139,7 +5441,81 @@ "iso_3166_3", "laravel" ], - "time": "2015-03-25 08:28:59" + "time": "2015-06-02 10:57:25" + }, + { + "name": "wildbit/laravel-postmark-provider", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/wildbit/laravel-postmark-provider.git", + "reference": "3cab780369d206e1c7eaae3f576ca7f0c4f5edc6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wildbit/laravel-postmark-provider/zipball/3cab780369d206e1c7eaae3f576ca7f0c4f5edc6", + "reference": "3cab780369d206e1c7eaae3f576ca7f0c4f5edc6", + "shasum": "" + }, + "require": { + "illuminate/mail": "~5.0", + "wildbit/swiftmailer-postmark": "~1.1" + }, + "type": "library", + "autoload": { + "psr-0": { + "Postmark\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "An officially supported mail provider to send mail from Laravel through Postmark, see instructions for integrating it here: https://github.com/wildbit/laravel-postmark-provider/blob/master/README.md", + "time": "2015-03-19 13:32:47" + }, + { + "name": "wildbit/swiftmailer-postmark", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/wildbit/swiftmailer-postmark.git", + "reference": "2aff78a6cb2892e0c02e64edb753ad41d8f6496c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wildbit/swiftmailer-postmark/zipball/2aff78a6cb2892e0c02e64edb753ad41d8f6496c", + "reference": "2aff78a6cb2892e0c02e64edb753ad41d8f6496c", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "~5.2", + "swiftmailer/swiftmailer": "~5.1" + }, + "require-dev": { + "phpunit/phpunit": "~4.5" + }, + "suggest": { + "wildbit/laravel-postmark-provider": "~1.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Postmark\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Postmark", + "email": "support@postmarkapp.com" + } + ], + "description": "A Swiftmailer Transport for Postmark.", + "time": "2015-03-19 13:06:11" } ], "packages-dev": [ @@ -5233,16 +5609,16 @@ }, { "name": "phpspec/phpspec", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/phpspec/phpspec.git", - "reference": "9727d75919a00455433e867565bc022f0b985a39" + "reference": "e9a40577323e67f1de2e214abf32976a0352d8f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/phpspec/zipball/9727d75919a00455433e867565bc022f0b985a39", - "reference": "9727d75919a00455433e867565bc022f0b985a39", + "url": "https://api.github.com/repos/phpspec/phpspec/zipball/e9a40577323e67f1de2e214abf32976a0352d8f8", + "reference": "e9a40577323e67f1de2e214abf32976a0352d8f8", "shasum": "" }, "require": { @@ -5307,20 +5683,20 @@ "testing", "tests" ], - "time": "2015-04-18 16:22:51" + "time": "2015-05-30 15:21:40" }, { "name": "phpspec/prophecy", - "version": "1.4.0", + "version": "v1.4.1", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5" + "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5", - "reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373", + "reference": "3132b1f44c7bf2ec4c7eb2d3cb78fdeca760d373", "shasum": "" }, "require": { @@ -5367,20 +5743,20 @@ "spy", "stub" ], - "time": "2015-03-27 19:31:25" + "time": "2015-04-27 22:15:08" }, { "name": "phpunit/php-code-coverage", - "version": "2.0.16", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c" + "reference": "28a6b34e91d789b2608072ab3c82eaae7cdb973c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/934fd03eb6840508231a7f73eb8940cf32c3b66c", - "reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/28a6b34e91d789b2608072ab3c82eaae7cdb973c", + "reference": "28a6b34e91d789b2608072ab3c82eaae7cdb973c", "shasum": "" }, "require": { @@ -5403,7 +5779,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.1.x-dev" } }, "autoload": { @@ -5429,7 +5805,7 @@ "testing", "xunit" ], - "time": "2015-04-11 04:35:00" + "time": "2015-06-03 07:01:01" }, { "name": "phpunit/php-file-iterator", @@ -5617,16 +5993,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.6.4", + "version": "4.7.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "163232991e652e6efed2f8470326fffa61e848e2" + "reference": "c2241b8d3381be3e4c6125ae347687d59f286784" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/163232991e652e6efed2f8470326fffa61e848e2", - "reference": "163232991e652e6efed2f8470326fffa61e848e2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c2241b8d3381be3e4c6125ae347687d59f286784", + "reference": "c2241b8d3381be3e4c6125ae347687d59f286784", "shasum": "" }, "require": { @@ -5637,7 +6013,7 @@ "ext-spl": "*", "php": ">=5.3.3", "phpspec/prophecy": "~1.3,>=1.3.1", - "phpunit/php-code-coverage": "~2.0,>=2.0.11", + "phpunit/php-code-coverage": "~2.1", "phpunit/php-file-iterator": "~1.4", "phpunit/php-text-template": "~1.2", "phpunit/php-timer": "~1.0", @@ -5659,7 +6035,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.6.x-dev" + "dev-master": "4.7.x-dev" } }, "autoload": { @@ -5685,20 +6061,20 @@ "testing", "xunit" ], - "time": "2015-04-11 05:23:21" + "time": "2015-06-05 04:14:02" }, { "name": "phpunit/phpunit-mock-objects", - "version": "2.3.1", + "version": "2.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "74ffb87f527f24616f72460e54b595f508dccb5c" + "reference": "253c005852591fd547fc18cd5b7b43a1ec82d8f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/74ffb87f527f24616f72460e54b595f508dccb5c", - "reference": "74ffb87f527f24616f72460e54b595f508dccb5c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/253c005852591fd547fc18cd5b7b43a1ec82d8f7", + "reference": "253c005852591fd547fc18cd5b7b43a1ec82d8f7", "shasum": "" }, "require": { @@ -5740,7 +6116,7 @@ "mock", "xunit" ], - "time": "2015-04-02 05:36:41" + "time": "2015-05-29 05:19:18" }, { "name": "sebastian/comparator", @@ -6115,21 +6491,20 @@ }, { "name": "symfony/yaml", - "version": "v2.6.6", - "target-dir": "Symfony/Component/Yaml", + "version": "v2.7.0", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "174f009ed36379a801109955fc5a71a49fe62dd4" + "reference": "4a29a5248aed4fb45f626a7bbbd330291492f5c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/174f009ed36379a801109955fc5a71a49fe62dd4", - "reference": "174f009ed36379a801109955fc5a71a49fe62dd4", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/4a29a5248aed4fb45f626a7bbbd330291492f5c3", + "reference": "4a29a5248aed4fb45f626a7bbbd330291492f5c3", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.9" }, "require-dev": { "symfony/phpunit-bridge": "~2.7" @@ -6137,11 +6512,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\Yaml\\": "" } }, @@ -6150,18 +6525,18 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Yaml Component", - "homepage": "http://symfony.com", - "time": "2015-03-30 15:54:10" + "homepage": "https://symfony.com", + "time": "2015-05-02 15:21:08" } ], "aliases": [], @@ -6174,7 +6549,9 @@ "lokielse/omnipay-alipay": 20, "alfaproject/omnipay-neteller": 20, "alfaproject/omnipay-skrill": 20, - "omnipay/bitpay": 20 + "omnipay/bitpay": 20, + "wildbit/laravel-postmark-provider": 20, + "dwolla/omnipay-dwolla": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/config/app.php b/config/app.php index d4ca7d6d4020..48ffb7ef3abe 100644 --- a/config/app.php +++ b/config/app.php @@ -1,5 +1,7 @@ 'Illuminate\Support\Facades\File', //'Form' => 'Illuminate\Support\Facades\Form', 'Hash' => 'Illuminate\Support\Facades\Hash', - 'HTML' => 'Illuminate\Support\Facades\HTML', + //'HTML' => 'Illuminate\Support\Facades\HTML', 'Input' => 'Illuminate\Support\Facades\Input', 'Lang' => 'Illuminate\Support\Facades\Lang', 'Log' => 'Illuminate\Support\Facades\Log', @@ -244,8 +246,8 @@ return [ // Added Class Aliases 'Utils' => 'App\Libraries\Utils', - 'Form' => 'Illuminate\Html\FormFacade', - 'HTML' => 'Illuminate\Html\HtmlFacade', + 'Form' => 'Collective\Html\FormFacade', + 'HTML' => 'Collective\Html\HtmlFacade', 'SSH' => 'Illuminate\Support\Facades\SSH', 'Alert' => 'Bootstrapper\Facades\Alert', 'Badge' => 'Bootstrapper\Facades\Badge', @@ -255,7 +257,7 @@ return [ 'ButtonToolbar' => 'Bootstrapper\Facades\ButtonToolbar', 'Carousel' => 'Bootstrapper\Facades\Carousel', 'DropdownButton' => 'Bootstrapper\Facades\DropdownButton', - 'Form' => 'Bootstrapper\Facades\Form', + //'Form' => 'Bootstrapper\Facades\Form', //need to clarify this guy 'Helpers' => 'Bootstrapper\Facades\Helpers', 'Icon' => 'Bootstrapper\Facades\Icon', //'Image' => 'Bootstrapper\Facades\Image', diff --git a/config/former.php b/config/former.php index 3c30b7ad2871..e6f0f3c77c53 100644 --- a/config/former.php +++ b/config/former.php @@ -1,66 +1,184 @@ true, + // Whether labels should be automatically computed from name + 'automatic_label' => true, - // The default form type - 'default_form_type' => 'horizontal', + // The default form type + 'default_form_type' => 'horizontal', - // The framework to be used by Former - 'framework' => 'TwitterBootstrap3', + // Validation + //////////////////////////////////////////////////////////////////// - // Validation - //////////////////////////////////////////////////////////////////// + // Whether Former should fetch errors from Session + 'fetch_errors' => true, - // Whether Former should fetch errors from Session - 'fetch_errors' => true, + // Whether Former should try to apply Validator rules as attributes + 'live_validation' => true, - // Whether Former should try to apply Validator rules as attributes - 'live_validation' => true, + // Whether Former should automatically fetch error messages and + // display them next to the matching fields + 'error_messages' => true, - // Whether Former should automatically fetch error messages and - // display them next to the matching fields - 'error_messages' => true, + // Checkables + //////////////////////////////////////////////////////////////////// - // Checkables - //////////////////////////////////////////////////////////////////// + // Whether checkboxes should always be present in the POST data, + // no matter if you checked them or not + 'push_checkboxes' => false, - // Whether checkboxes should always be present in the POST data, - // no matter if you checked them or not - 'push_checkboxes' => false, + // The value a checkbox will have in the POST array if unchecked + 'unchecked_value' => 0, - // The value a checkbox will have in the POST array if unchecked - 'unchecked_value' => 0, + // Required fields + //////////////////////////////////////////////////////////////////// - // Required fields - //////////////////////////////////////////////////////////////////// + // The class to be added to required fields + 'required_class' => 'required', - // The class to be added to required fields - 'required_class' => 'required', + // A facultative text to append to the labels of required fields + 'required_text' => '*', - // A facultative text to append to the labels of required fields - 'required_text' => '*', + // Translations + //////////////////////////////////////////////////////////////////// - // Translations - //////////////////////////////////////////////////////////////////// + // Where Former should look for translations + 'translate_from' => 'texts', - // Where Former should look for translations - 'translate_from' => 'texts', + // Whether text that comes out of the translated + // should be capitalized (ex: email => Email) automatically + 'capitalize_translations' => true, - // Whether text that comes out of the translated - // should be capitalized (ex: email => Email) automatically - 'capitalize_translations' => true, + // An array of attributes to automatically translate + 'translatable' => array( + 'help', + 'inlineHelp', + 'blockHelp', + 'placeholder', + 'data_placeholder', + 'label', + ), - // An array of attributes to automatically translate - 'translatable' => array( - 'help', - 'inlineHelp', - 'blockHelp', - 'placeholder', - 'data_placeholder', - 'label', - ), -); + // Framework + //////////////////////////////////////////////////////////////////// + + // The framework to be used by Former + 'framework' => 'TwitterBootstrap3', + + 'TwitterBootstrap3' => array( + + // Map Former-supported viewports to Bootstrap 3 equivalents + 'viewports' => array( + 'large' => 'lg', + 'medium' => 'md', + 'small' => 'sm', + 'mini' => 'xs', + ), + // Width of labels for horizontal forms expressed as viewport => grid columns + 'labelWidths' => array( + 'large' => 4, + 'small' => 4, + ), + // HTML markup and classes used by Bootstrap 3 for icons + 'icon' => array( + 'tag' => 'span', + 'set' => 'glyphicon', + 'prefix' => 'glyphicon', + ), + + ), + + 'Nude' => array( // No-framework markup + 'icon' => array( + 'tag' => 'i', + 'set' => null, + 'prefix' => 'icon', + ), + ), + + 'TwitterBootstrap' => array( // Twitter Bootstrap version 2 + 'icon' => array( + 'tag' => 'i', + 'set' => null, + 'prefix' => 'icon', + ), + ), + + 'ZurbFoundation5' => array( + // Map Former-supported viewports to Foundation 5 equivalents + 'viewports' => array( + 'large' => 'large', + 'medium' => null, + 'small' => 'small', + 'mini' => null, + ), + // Width of labels for horizontal forms expressed as viewport => grid columns + 'labelWidths' => array( + 'small' => 3, + ), + // Classes to be applied to wrapped labels in horizontal forms + 'wrappedLabelClasses' => array('right', 'inline'), + // HTML markup and classes used by Foundation 5 for icons + 'icon' => array( + 'tag' => 'i', + 'set' => null, + 'prefix' => 'fi', + ), + // CSS for inline validation errors + 'error_classes' => array('class' => 'error'), + ), + + 'ZurbFoundation4' => array( + // Foundation 4 also has an experimental "medium" breakpoint + // explained at http://foundation.zurb.com/docs/components/grid.html + 'viewports' => array( + 'large' => 'large', + 'medium' => null, + 'small' => 'small', + 'mini' => null, + ), + // Width of labels for horizontal forms expressed as viewport => grid columns + 'labelWidths' => array( + 'small' => 3, + ), + // Classes to be applied to wrapped labels in horizontal forms + 'wrappedLabelClasses' => array('right', 'inline'), + // HTML markup and classes used by Foundation 4 for icons + 'icon' => array( + 'tag' => 'i', + 'set' => 'general', + 'prefix' => 'foundicon', + ), + // CSS for inline validation errors + 'error_classes' => array('class' => 'alert-box radius warning'), + ), + + 'ZurbFoundation' => array( // Foundation 3 + 'viewports' => array( + 'large' => '', + 'medium' => null, + 'small' => 'mobile-', + 'mini' => null, + ), + // Width of labels for horizontal forms expressed as viewport => grid columns + 'labelWidths' => array( + 'large' => 2, + 'small' => 4, + ), + // Classes to be applied to wrapped labels in horizontal forms + 'wrappedLabelClasses' => array('right', 'inline'), + // HTML markup and classes used by Foundation 3 for icons + 'icon' => array( + 'tag' => 'i', + 'set' => null, + 'prefix' => 'fi', + ), + // CSS for inline validation errors + // should work for Zurb 2 and 3 + 'error_classes' => array('class' => 'alert-box alert error'), + ), + + +); \ No newline at end of file diff --git a/config/former/Nude.php b/config/former/Nude.php deleted file mode 100644 index 18f5239b82d0..000000000000 --- a/config/former/Nude.php +++ /dev/null @@ -1,14 +0,0 @@ - array( - - 'tag' => 'i', - 'set' => null, - 'prefix' => 'icon', - - ), - -); \ No newline at end of file diff --git a/config/former/TwitterBootstrap.php b/config/former/TwitterBootstrap.php deleted file mode 100644 index dfac6d7bc77e..000000000000 --- a/config/former/TwitterBootstrap.php +++ /dev/null @@ -1,14 +0,0 @@ - array( - - 'tag' => 'i', - 'set' => null, - 'prefix' => 'icon', - - ), - -); \ No newline at end of file diff --git a/config/former/TwitterBootstrap3.php b/config/former/TwitterBootstrap3.php deleted file mode 100644 index fad6b7882c89..000000000000 --- a/config/former/TwitterBootstrap3.php +++ /dev/null @@ -1,26 +0,0 @@ - array( - 'large' => 'lg', - 'medium' => 'md', - 'small' => 'sm', - 'mini' => 'xs', - ), - - // Width of labels for horizontal forms expressed as viewport => grid columns - 'labelWidths' => array( - 'large' => 4, - 'small' => 4, - ), - - // HTML markup and classes used by Bootstrap 3 for icons - 'icon' => array( - 'tag' => 'span', - 'set' => 'glyphicon', - 'prefix' => 'glyphicon', - ), - -); \ No newline at end of file diff --git a/config/former/ZurbFoundation.php b/config/former/ZurbFoundation.php deleted file mode 100644 index 9223978736d5..000000000000 --- a/config/former/ZurbFoundation.php +++ /dev/null @@ -1,35 +0,0 @@ - array( - - 'large' => '', - 'medium' => null, - 'small' => 'mobile-', - 'mini' => null, - - ), - - // Width of labels for horizontal forms expressed as viewport => grid columns - 'labelWidths' => array( - - 'large' => 2, - 'small' => 4, - - ), - - // Classes to be applied to wrapped labels in horizontal forms - 'wrappedLabelClasses' => array('right','inline'), - - // HTML markup and classes used by Foundation 3 for icons - 'icon' => array( - - 'tag' => 'i', - 'set' => null, - 'prefix' => 'fi', - - ), - -); \ No newline at end of file diff --git a/config/former/ZurbFoundation4.php b/config/former/ZurbFoundation4.php deleted file mode 100644 index 4f55a44f9c40..000000000000 --- a/config/former/ZurbFoundation4.php +++ /dev/null @@ -1,36 +0,0 @@ - array( - - 'large' => 'large', - 'medium' => null, - 'small' => 'small', - 'mini' => null, - - ), - - // Width of labels for horizontal forms expressed as viewport => grid columns - 'labelWidths' => array( - - 'small' => 3, - - ), - - // Classes to be applied to wrapped labels in horizontal forms - 'wrappedLabelClasses' => array('right','inline'), - - // HTML markup and classes used by Foundation 4 for icons - 'icon' => array( - - 'tag' => 'i', - 'set' => 'general', - 'prefix' => 'foundicon', - - ), - -); \ No newline at end of file diff --git a/config/mail.php b/config/mail.php index 0d5473eb370a..728a0356929c 100644 --- a/config/mail.php +++ b/config/mail.php @@ -54,7 +54,7 @@ return [ | */ - 'from' => ['address' => env('MAIL_USERNAME'), 'name' => env('MAIL_FROM_NAME')], + 'from' => ['address' => env('MAIL_FROM_ADDRESS', env('MAIL_USERNAME')), 'name' => env('MAIL_FROM_NAME')], /* |-------------------------------------------------------------------------- diff --git a/config/packages/anahkiasen/former/Nude.php b/config/packages/anahkiasen/former/Nude.php deleted file mode 100644 index 18f5239b82d0..000000000000 --- a/config/packages/anahkiasen/former/Nude.php +++ /dev/null @@ -1,14 +0,0 @@ - array( - - 'tag' => 'i', - 'set' => null, - 'prefix' => 'icon', - - ), - -); \ No newline at end of file diff --git a/config/packages/anahkiasen/former/TwitterBootstrap.php b/config/packages/anahkiasen/former/TwitterBootstrap.php deleted file mode 100644 index dfac6d7bc77e..000000000000 --- a/config/packages/anahkiasen/former/TwitterBootstrap.php +++ /dev/null @@ -1,14 +0,0 @@ - array( - - 'tag' => 'i', - 'set' => null, - 'prefix' => 'icon', - - ), - -); \ No newline at end of file diff --git a/config/packages/anahkiasen/former/TwitterBootstrap3.php b/config/packages/anahkiasen/former/TwitterBootstrap3.php deleted file mode 100644 index fad6b7882c89..000000000000 --- a/config/packages/anahkiasen/former/TwitterBootstrap3.php +++ /dev/null @@ -1,26 +0,0 @@ - array( - 'large' => 'lg', - 'medium' => 'md', - 'small' => 'sm', - 'mini' => 'xs', - ), - - // Width of labels for horizontal forms expressed as viewport => grid columns - 'labelWidths' => array( - 'large' => 4, - 'small' => 4, - ), - - // HTML markup and classes used by Bootstrap 3 for icons - 'icon' => array( - 'tag' => 'span', - 'set' => 'glyphicon', - 'prefix' => 'glyphicon', - ), - -); \ No newline at end of file diff --git a/config/packages/anahkiasen/former/ZurbFoundation.php b/config/packages/anahkiasen/former/ZurbFoundation.php deleted file mode 100644 index 9223978736d5..000000000000 --- a/config/packages/anahkiasen/former/ZurbFoundation.php +++ /dev/null @@ -1,35 +0,0 @@ - array( - - 'large' => '', - 'medium' => null, - 'small' => 'mobile-', - 'mini' => null, - - ), - - // Width of labels for horizontal forms expressed as viewport => grid columns - 'labelWidths' => array( - - 'large' => 2, - 'small' => 4, - - ), - - // Classes to be applied to wrapped labels in horizontal forms - 'wrappedLabelClasses' => array('right','inline'), - - // HTML markup and classes used by Foundation 3 for icons - 'icon' => array( - - 'tag' => 'i', - 'set' => null, - 'prefix' => 'fi', - - ), - -); \ No newline at end of file diff --git a/config/packages/anahkiasen/former/ZurbFoundation4.php b/config/packages/anahkiasen/former/ZurbFoundation4.php deleted file mode 100644 index 4f55a44f9c40..000000000000 --- a/config/packages/anahkiasen/former/ZurbFoundation4.php +++ /dev/null @@ -1,36 +0,0 @@ - array( - - 'large' => 'large', - 'medium' => null, - 'small' => 'small', - 'mini' => null, - - ), - - // Width of labels for horizontal forms expressed as viewport => grid columns - 'labelWidths' => array( - - 'small' => 3, - - ), - - // Classes to be applied to wrapped labels in horizontal forms - 'wrappedLabelClasses' => array('right','inline'), - - // HTML markup and classes used by Foundation 4 for icons - 'icon' => array( - - 'tag' => 'i', - 'set' => 'general', - 'prefix' => 'foundicon', - - ), - -); \ No newline at end of file diff --git a/config/packages/anahkiasen/former/config.php b/config/packages/anahkiasen/former/config.php deleted file mode 100644 index 327019638f9d..000000000000 --- a/config/packages/anahkiasen/former/config.php +++ /dev/null @@ -1,59 +0,0 @@ - true, - - // The default form type - 'default_form_type' => 'horizontal', - - // The framework to be used by Former - 'framework' => 'TwitterBootstrap3', - - // Validation - //////////////////////////////////////////////////////////////////// - - // Whether Former should fetch errors from Session - 'fetch_errors' => true, - - // Whether Former should try to apply Validator rules as attributes - 'live_validation' => true, - - // Whether Former should automatically fetch error messages and - // display them next to the matching fields - 'error_messages' => true, - - // Checkables - //////////////////////////////////////////////////////////////////// - - // Whether checkboxes should always be present in the POST data, - // no matter if you checked them or not - 'push_checkboxes' => false, - - // The value a checkbox will have in the POST array if unchecked - 'unchecked_value' => 0, - - // Required fields - //////////////////////////////////////////////////////////////////// - - // The class to be added to required fields - 'required_class' => 'required', - - // A facultative text to append to the labels of required fields - 'required_text' => '', //'*', - - // Translations - //////////////////////////////////////////////////////////////////// - - // Where Former should look for translations - 'translate_from' => 'texts', - - // An array of attributes to automatically translate - 'translatable' => array( - 'help', 'inlineHelp', 'blockHelp', - 'placeholder', 'data_placeholder', - 'label' - ), -); diff --git a/config/services.php b/config/services.php index dddc9866010f..c76b0832db58 100644 --- a/config/services.php +++ b/config/services.php @@ -14,6 +14,8 @@ return [ | */ + 'postmark' => env('POSTMARK_API_TOKEN', ''), + 'mailgun' => [ 'domain' => '', 'secret' => '', diff --git a/config/session.php b/config/session.php index 2ffb7d5cc968..a00d15e74be3 100644 --- a/config/session.php +++ b/config/session.php @@ -29,7 +29,7 @@ return [ | */ - 'lifetime' => 360, + 'lifetime' => env('SESSION_LIFETIME', 120), 'expire_on_close' => false, 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 index cb2594770923..6a370bd67127 100644 --- a/database/migrations/2013_11_05_180133_confide_setup_users_table.php +++ b/database/migrations/2013_11_05_180133_confide_setup_users_table.php @@ -183,7 +183,7 @@ class ConfideSetupUsersTable extends Migration { $t->string('username')->unique(); $t->string('email')->nullable(); $t->string('password'); - $t->string('confirmation_code'); + $t->string('confirmation_code')->nullable(); $t->boolean('registered')->default(false); $t->boolean('confirmed')->default(false); $t->integer('theme_id')->nullable(); @@ -355,8 +355,8 @@ class ConfideSetupUsersTable extends Migration { $t->softDeletes(); $t->string('transaction_reference')->nullable(); - $t->timestamp('sent_date'); - $t->timestamp('viewed_date'); + $t->timestamp('sent_date')->nullable(); + $t->timestamp('viewed_date')->nullable(); $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');; $t->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); diff --git a/database/migrations/2014_10_06_103529_add_timesheets.php b/database/migrations/2014_10_06_103529_add_timesheets.php index 879cd450402d..61f8b842f358 100644 --- a/database/migrations/2014_10_06_103529_add_timesheets.php +++ b/database/migrations/2014_10_06_103529_add_timesheets.php @@ -142,11 +142,11 @@ class AddTimesheets extends Migration { */ public function down() { - Schema::drop('timesheet_events'); - Schema::drop('timesheet_event_sources'); - Schema::drop('timesheets'); - Schema::drop('project_codes'); - Schema::drop('projects'); + Schema::dropIfExists('timesheet_events'); + Schema::dropIfExists('timesheet_event_sources'); + Schema::dropIfExists('timesheets'); + Schema::dropIfExists('project_codes'); + Schema::dropIfExists('projects'); } } diff --git a/database/migrations/2015_05_21_184104_add_font_size.php b/database/migrations/2015_05_21_184104_add_font_size.php new file mode 100644 index 000000000000..b4a7c210d8eb --- /dev/null +++ b/database/migrations/2015_05_21_184104_add_font_size.php @@ -0,0 +1,34 @@ +smallInteger('font_size')->default(DEFAULT_FONT_SIZE); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('font_size'); + }); + } + +} diff --git a/database/migrations/2015_05_27_121828_add_tasks.php b/database/migrations/2015_05_27_121828_add_tasks.php new file mode 100644 index 000000000000..b02b5fe702c7 --- /dev/null +++ b/database/migrations/2015_05_27_121828_add_tasks.php @@ -0,0 +1,55 @@ +increments('id'); + $table->unsignedInteger('user_id'); + $table->unsignedInteger('account_id')->index(); + $table->unsignedInteger('client_id')->nullable(); + $table->unsignedInteger('invoice_id')->nullable(); + $table->timestamps(); + $table->softDeletes(); + + $table->timestamp('start_time'); + $table->integer('duration')->nullable(); + $table->string('description')->nullable(); + $table->boolean('is_deleted')->default(false); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + $table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + + $table->unsignedInteger('public_id')->index(); + $table->unique( array('account_id','public_id') ); + }); + + Schema::dropIfExists('timesheets'); + Schema::dropIfExists('timesheet_events'); + Schema::dropIfExists('timesheet_event_sources'); + Schema::dropIfExists('project_codes'); + Schema::dropIfExists('projects'); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('tasks'); + } + +} diff --git a/database/migrations/2015_05_27_170808_add_custom_invoice_labels.php b/database/migrations/2015_05_27_170808_add_custom_invoice_labels.php new file mode 100644 index 000000000000..24415d381b02 --- /dev/null +++ b/database/migrations/2015_05_27_170808_add_custom_invoice_labels.php @@ -0,0 +1,35 @@ +text('invoice_labels')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function($table) + { + $table->dropColumn('invoice_labels'); + }); + + } + +} diff --git a/database/seeds/ConstantsSeeder.php b/database/seeds/ConstantsSeeder.php index 6fbb0cb59ad1..a4de2124da08 100644 --- a/database/seeds/ConstantsSeeder.php +++ b/database/seeds/ConstantsSeeder.php @@ -111,42 +111,6 @@ class ConstantsSeeder extends Seeder 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' => '.')); - Currency::create(array('name' => 'Guatemalan Quetzal', 'code' => 'GTQ', 'symbol' => 'Q', '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')); - DateFormat::create(array('format' => 'Y-M-d', 'picker_format' => 'yyyy-M-dd', 'label' => '2013-03-10')); - PaymentLibrary::create(['name' => 'Omnipay']); PaymentLibrary::create(['name' => 'PHP-Payments [Deprecated]']); diff --git a/database/seeds/PaymentLibrariesSeeder.php b/database/seeds/PaymentLibrariesSeeder.php index a02a6c92135c..f6b0f80526ff 100644 --- a/database/seeds/PaymentLibrariesSeeder.php +++ b/database/seeds/PaymentLibrariesSeeder.php @@ -2,49 +2,133 @@ use App\Models\Gateway; use App\Models\PaymentTerm; +use App\Models\Currency; +use App\Models\DateFormat; +use App\Models\DatetimeFormat; class PaymentLibrariesSeeder extends Seeder { + public function run() + { + Eloquent::unguard(); - public function run() - { - Eloquent::unguard(); + $this->createGateways(); + $this->createPaymentTerms(); + $this->createDateFormats(); + $this->createDatetimeFormats(); + } - $gateways = [ - ['name' => '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], + private function createGateways() { + + $gateways = [ + ['name' => '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], ['name' => 'BitPay', 'provider' => 'BitPay', 'payment_library_id' => 1], - ]; - - foreach ($gateways as $gateway) - { - if (!DB::table('gateways')->where('name', '=', $gateway['name'])->get()) - { - Gateway::create($gateway); - } - } - - $paymentTerms = [ - ['num_days' => -1, 'name' => 'Net 0'] + ['name' => 'Dwolla', 'provider' => 'Dwolla', 'payment_library_id' => 1], ]; - foreach ($paymentTerms as $paymentTerm) - { - if (!DB::table('payment_terms')->where('name', '=', $paymentTerm['name'])->get()) - { + foreach ($gateways as $gateway) { + if (!DB::table('gateways')->where('name', '=', $gateway['name'])->get()) { + Gateway::create($gateway); + } + } + + } + + private function createPaymentTerms() { + + $paymentTerms = [ + ['num_days' => -1, 'name' => 'Net 0'], + ]; + + foreach ($paymentTerms as $paymentTerm) { + if (!DB::table('payment_terms')->where('name', '=', $paymentTerm['name'])->get()) { PaymentTerm::create($paymentTerm); } } - } -} \ No newline at end of file + + $currencies = [ + ['name' => 'US Dollar', 'code' => 'USD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Pound Sterling', 'code' => 'GBP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Euro', 'code' => 'EUR', 'symbol' => '€', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Rand', 'code' => 'ZAR', 'symbol' => 'R', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Danish Krone', 'code' => 'DKK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Israeli Shekel', 'code' => 'ILS', 'symbol' => 'NIS ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Swedish Krona', 'code' => 'SEK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Kenyan Shilling', 'code' => 'KES', 'symbol' => 'KSh ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Canadian Dollar', 'code' => 'CAD', 'symbol' => 'C$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Philippine Peso', 'code' => 'PHP', 'symbol' => 'P ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Indian Rupee', 'code' => 'INR', 'symbol' => 'Rs. ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Australian Dollar', 'code' => 'AUD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Singapore Dollar', 'code' => 'SGD', 'symbol' => 'SGD ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Norske Kroner', 'code' => 'NOK', 'symbol' => 'kr ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'New Zealand Dollar', 'code' => 'NZD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Vietnamese Dong', 'code' => 'VND', 'symbol' => 'VND ', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Swiss Franc', 'code' => 'CHF', 'symbol' => 'CHF ', 'precision' => '2', 'thousand_separator' => '\'', 'decimal_separator' => '.'], + ['name' => 'Guatemalan Quetzal', 'code' => 'GTQ', 'symbol' => 'Q', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Malaysian Ringgit', 'code' => 'MYR', 'symbol' => 'RM', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Brazilian Real', 'code' => 'BRL', 'symbol' => 'R$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Thai baht', 'code' => 'THB', 'symbol' => 'THB ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ]; + + foreach ($currencies as $currency) { + if (!DB::table('currencies')->whereName($currency['name'])->get()) { + Currency::create($currency); + } + } + } + + private function createDateFormats() { + + $formats = [ + ['format' => 'd/M/Y', 'picker_format' => 'dd/M/yyyy', 'label' => '10/Mar/2013'], + ['format' => 'd-M-Y', 'picker_format' => 'dd-M-yyyy', 'label' => '10-Mar-2013'], + ['format' => 'd/F/Y', 'picker_format' => 'dd/MM/yyyy', 'label' => '10/March/2013'], + ['format' => 'd-F-Y', 'picker_format' => 'dd-MM-yyyy', 'label' => '10-March-2013'], + ['format' => 'M j, Y', 'picker_format' => 'M d, yyyy', 'label' => 'Mar 10, 2013'], + ['format' => 'F j, Y', 'picker_format' => 'MM d, yyyy', 'label' => 'March 10, 2013'], + ['format' => 'D M j, Y', 'picker_format' => 'D MM d, yyyy', 'label' => 'Mon March 10, 2013'], + ['format' => 'Y-M-d', 'picker_format' => 'yyyy-M-dd', 'label' => '2013-03-10'], + ['format' => 'd/m/Y', 'picker_format' => 'dd/mm/yyyy', 'label' => '20/03/2013'], + ]; + + foreach ($formats as $format) { + if (!DB::table('date_formats')->whereLabel($format['label'])->get()) { + DateFormat::create($format); + } + } + } + + private function createDatetimeFormats() { + + $formats = [ + ['format' => 'd/M/Y g:i a', 'label' => '10/Mar/2013'], + ['format' => 'd-M-Yk g:i a', 'label' => '10-Mar-2013'], + ['format' => 'd/F/Y g:i a', 'label' => '10/March/2013'], + ['format' => 'd-F-Y g:i a', 'label' => '10-March-2013'], + ['format' => 'M j, Y g:i a', 'label' => 'Mar 10, 2013 6:15 pm'], + ['format' => 'F j, Y g:i a', 'label' => 'March 10, 2013 6:15 pm'], + ['format' => 'D M jS, Y g:ia', 'label' => 'Mon March 10th, 2013 6:15 pm'], + ['format' => 'Y-M-d g:i a', 'label' => '2013-03-10 6:15 pm'], + ['format' => 'd/m/Y g:i a', 'label' => '20/03/2013 6:15 pm'], + ]; + + foreach ($formats as $format) { + if (!DB::table('datetime_formats')->whereLabel($format['label'])->get()) { + DatetimeFormat::create($format); + } + } + } + +} diff --git a/public/css/built.css b/public/css/built.css index b9a4dcbd3c32..37e6594a075c 100644 --- a/public/css/built.css +++ b/public/css/built.css @@ -2449,6 +2449,9 @@ table.dataTable thead > tr > th, table.invoice-table thead > tr > th { background-color: #e37329 !important; color:#fff; } +table.dataTable tr:hover { + background-color: #F2F5FE !important; +} th:first-child { border-radius: 3px 0 0 0; border-left: none; @@ -2467,9 +2470,9 @@ border-bottom: 1px solid #dfe0e1; table.dataTable.no-footer { border-bottom: none; } -.table-striped>tbody>tr:nth-child(odd)>td, +.table-striped>tbody>tr:nth-child(odd)>tr, .table-striped>tbody>tr:nth-child(odd)>th { -background-color: #FDFDFD; +/*background-color: #FDFDFD;*/ } table.table thead .sorting_asc { background: url('../images/sort_asc.png') no-repeat 90% 50%; @@ -2617,7 +2620,11 @@ margin-left: 0px; .btn-primary i{ border-color: #0b4d78; } -.form-actions .btn { margin-left: 10px; } + +.form-actions .btn, +.form-actions div.btn-group { + margin-left: 10px; +} .form-actions .btn.btn-success:first-child { margin-left: 10px !important; @@ -2863,7 +2870,7 @@ background-clip: padding-box; .dashboard .panel-body {padding: 0;} .dashboard .table-striped>tbody>tr>td, .table-striped>tbody>tr>th { background-color: #fbfbfb;} -.dashboard .table-striped>tbody>tr:nth-child(odd)>td, .table-striped>tbody>tr:nth-child(odd)>th { +.dashboard .table-striped>tbody>tr:nth-child(odd)>tr, .table-striped>tbody>tr:nth-child(odd)>th { background-color: #fff; } .dashboard th { @@ -3204,6 +3211,12 @@ div.checkbox > label { border-radius: 3px; } +.container input:focus, +.container textarea:focus, +.container select:focus { + background: #fdfdfd !important; +} + .container input[placeholder], .container textarea[placeholder], .container select[placeholder] { @@ -3226,11 +3239,9 @@ div.checkbox > label { background-color: #0b4d78 !important; } -/* -.panel-default { - border-color: #e37329 !important; +div.alert { + z-index: 1; } -*/ .alert-hide { position: absolute; diff --git a/public/css/style.css b/public/css/style.css index 91e9f45afa5a..c8ec73d51825 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -65,6 +65,11 @@ table.dataTable thead > tr > th, table.invoice-table thead > tr > th { background-color: #e37329 !important; color:#fff; } +/* +table.dataTable tr:hover { + background-color: #F2F5FE !important; +} +*/ th:first-child { border-radius: 3px 0 0 0; border-left: none; @@ -83,7 +88,7 @@ border-bottom: 1px solid #dfe0e1; table.dataTable.no-footer { border-bottom: none; } -.table-striped>tbody>tr:nth-child(odd)>td, +.table-striped>tbody>tr:nth-child(odd)>tr, .table-striped>tbody>tr:nth-child(odd)>th { background-color: #FDFDFD; } @@ -233,7 +238,11 @@ margin-left: 0px; .btn-primary i{ border-color: #0b4d78; } -.form-actions .btn { margin-left: 10px; } + +.form-actions .btn, +.form-actions div.btn-group { + margin-left: 10px; +} .form-actions .btn.btn-success:first-child { margin-left: 10px !important; @@ -479,7 +488,7 @@ background-clip: padding-box; .dashboard .panel-body {padding: 0;} .dashboard .table-striped>tbody>tr>td, .table-striped>tbody>tr>th { background-color: #fbfbfb;} -.dashboard .table-striped>tbody>tr:nth-child(odd)>td, .table-striped>tbody>tr:nth-child(odd)>th { +.dashboard .table-striped>tbody>tr:nth-child(odd)>tr, .table-striped>tbody>tr:nth-child(odd)>th { background-color: #fff; } .dashboard th { @@ -820,6 +829,12 @@ div.checkbox > label { border-radius: 3px; } +.container input:focus, +.container textarea:focus, +.container select:focus { + background: #fdfdfd !important; +} + .container input[placeholder], .container textarea[placeholder], .container select[placeholder] { @@ -842,11 +857,9 @@ div.checkbox > label { background-color: #0b4d78 !important; } -/* -.panel-default { - border-color: #e37329 !important; +div.alert { + z-index: 1; } -*/ .alert-hide { position: absolute; diff --git a/public/favicon.png b/public/favicon.png old mode 100755 new mode 100644 index 8032c422badb..41739df6c3c7 Binary files a/public/favicon.png and b/public/favicon.png differ diff --git a/public/js/built.js b/public/js/built.js index 13f3cd92e6e8..06e46a9d8c1f 100644 --- a/public/js/built.js +++ b/public/js/built.js @@ -31097,6 +31097,13 @@ MIT license. for(n=[],r=[],s=0,f=t.rows[0].cells.length,c=t.clientWidth;f>s;)l=t.rows[0].cells[s],r[s]={name:l.textContent.toLowerCase().replace(/\s+/g,""),prompt:l.textContent.replace(/\r?\n/g,""),width:l.clientWidth/c*e.pdf.internal.pageSize.width},s++;for(s=1;sa;){if(s=i[a],"object"==typeof s){if(e.executeWatchFunctions(s),1===s.nodeType&&"HEADER"===s.nodeName){var w=s,g=e.pdf.margins_doc.top;e.pdf.internal.events.subscribe("addPage",function(){e.y=g,n(w,e,r),e.pdf.margins_doc.top=e.y+10,e.y+=10},!1)}if(8===s.nodeType&&"#comment"===s.nodeName)~s.textContent.indexOf("ADD_PAGE")&&(e.pdf.addPage(),e.y=e.pdf.margins_doc.top);else if(1!==s.nodeType||b[s.nodeName])if(3===s.nodeType){var y=s.nodeValue;if(s.nodeValue&&"LI"===s.parentNode.nodeName)if("OL"===s.parentNode.parentNode.nodeName)y=q++ +". "+y;else{var x=16*o["font-size"],k=2;x>20&&(k=3),h=function(t,e){this.pdf.circle(t,e,k,"FD")}}e.addText(y,o)}else"string"==typeof s&&e.addText(s,o);else{var _;if("IMG"===s.nodeName){var A=s.getAttribute("src");_=m[e.pdf.sHashCode(A)||A]}if(_){e.pdf.internal.pageSize.height-e.pdf.margins_doc.bottome.pdf.margins_doc.top&&(e.pdf.addPage(),e.y=e.pdf.margins_doc.top,e.executeWatchFunctions(s));var C=u(s),S=e.x,E=12/e.pdf.internal.scaleFactor,z=(C["margin-left"]+C["padding-left"])*E,T=(C["margin-right"]+C["padding-right"])*E,I=(C["margin-top"]+C["padding-top"])*E,B=(C["margin-bottom"]+C["padding-bottom"])*E;S+=void 0!==C["float"]&&"right"===C["float"]?e.settings.width-s.width-T:z,e.pdf.addImage(_,S,e.y+I,s.width,s.height),_=void 0,"right"===C["float"]||"left"===C["float"]?(e.watchFunctions.push(function(t,n,r,s){return e.y>=n?(e.x+=t,e.settings.width+=r,!0):s&&1===s.nodeType&&!b[s.nodeName]&&e.x+s.width>e.pdf.margins_doc.left+e.pdf.margins_doc.width?(e.x+=t,e.y=n,e.settings.width+=r,!0):!1}.bind(this,"left"===C["float"]?-s.width-z-T:0,e.y+s.height+I+B,s.width)),e.watchFunctions.push(function(t,n,r){return e.y0){s=s[0];var i=e.pdf.internal.write,o=e.y;e.pdf.internal.write=function(){},n(s,e,r);var a=Math.ceil(e.y-o)+5;e.y=o,e.pdf.internal.write=i,e.pdf.margins_doc.bottom+=a;for(var u=function(t){var i=void 0!==t?t.pageNumber:1,o=e.y;e.y=e.pdf.internal.pageSize.height-e.pdf.margins_doc.bottom,e.pdf.margins_doc.bottom-=a;for(var u=s.getElementsByTagName("span"),c=0;c-1&&(u[c].innerHTML=i),(" "+u[c].className+" ").replace(/[\n\t]/g," ").indexOf(" totalPages ")>-1&&(u[c].innerHTML="###jsPDFVarTotalPages###");n(s,e,r),e.pdf.margins_doc.bottom+=a,e.y=o},c=s.getElementsByTagName("span"),l=0;l-1&&e.pdf.internal.events.subscribe("htmlRenderingFinished",e.pdf.putTotalPages.bind(e.pdf,"###jsPDFVarTotalPages###"),!0);e.pdf.internal.events.subscribe("addPage",u,!1),u(),b.FOOTER=1}},y=function(t,e,r,s,i,o){if(!e)return!1;"string"==typeof e||e.parentNode||(e=""+e.innerHTML),"string"==typeof e&&(e=function(t){var e,n,r,s;return r="jsPDFhtmlText"+Date.now().toString()+(1e3*Math.random()).toFixed(0),s="position: absolute !important;clip: rect(1px 1px 1px 1px); /* IE6, IE7 */clip: rect(1px, 1px, 1px, 1px);padding:0 !important;border:0 !important;height: 1px !important;width: 1px !important; top:auto;left:-100px;overflow: hidden;",n=document.createElement("div"),n.style.cssText=s,n.innerHTML='