mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-12 22:22:32 +01:00
commit
24f238d4a6
@ -1,8 +1,9 @@
|
||||
APP_ENV=development
|
||||
APP_DEBUG=true
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_URL=http://ninja.dev
|
||||
APP_CIPHER=rijndael-128
|
||||
APP_KEY
|
||||
APP_TIMEZONE
|
||||
|
||||
DB_TYPE=mysql
|
||||
DB_HOST=localhost
|
||||
@ -15,5 +16,6 @@ MAIL_PORT=587
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_HOST
|
||||
MAIL_USERNAME
|
||||
MAIL_FROM_ADDRESS
|
||||
MAIL_FROM_NAME
|
||||
MAIL_PASSWORD
|
||||
MAIL_PASSWORD
|
||||
|
@ -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
|
||||
@ -107,6 +108,7 @@ module.exports = function(grunt) {
|
||||
css_public: {
|
||||
src: [
|
||||
'public/vendor/bootstrap/dist/css/bootstrap.min.css',
|
||||
'public/vendor/font-awesome/css/font-awesome.min.css',
|
||||
/*
|
||||
'public/css/bootstrap.splash.css',
|
||||
'public/css/splash.css',
|
||||
|
@ -49,24 +49,6 @@ class CheckData extends Command {
|
||||
$today = new DateTime();
|
||||
|
||||
if (!$this->option('client_id')) {
|
||||
// update client deletion activities with the client's current balance
|
||||
$activities = DB::table('activities')
|
||||
->join('clients', 'clients.id', '=', 'activities.client_id')
|
||||
->where('activities.activity_type_id', '=', ACTIVITY_TYPE_DELETE_CLIENT)
|
||||
->where('activities.balance', '=', 0)
|
||||
->where('clients.balance', '!=', 0)
|
||||
->get(['activities.id', 'clients.balance']);
|
||||
|
||||
$this->info(count($activities) . ' delete client activities with zero balance');
|
||||
|
||||
if ($this->option('fix') == 'true') {
|
||||
foreach ($activities as $activity) {
|
||||
DB::table('activities')
|
||||
->where('id', $activity->id)
|
||||
->update(['balance' => $activity->balance]);
|
||||
}
|
||||
}
|
||||
|
||||
// update client paid_to_date value
|
||||
$clients = DB::table('clients')
|
||||
->join('payments', 'payments.client_id', '=', 'clients.id')
|
||||
@ -77,7 +59,7 @@ class CheckData extends Command {
|
||||
->havingRaw('clients.paid_to_date != sum(payments.amount) and clients.paid_to_date != 999999999.9999')
|
||||
->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(payments.amount) as amount')]);
|
||||
$this->info(count($clients) . ' clients with incorrect paid to date');
|
||||
|
||||
|
||||
if ($this->option('fix') == 'true') {
|
||||
foreach ($clients as $client) {
|
||||
DB::table('clients')
|
||||
|
@ -1,335 +0,0 @@
|
||||
<?php namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use PHPBenchTime\Timer;
|
||||
|
||||
class ImportTimesheetData extends Command {
|
||||
|
||||
protected $name = 'ninja:import-timesheet-data';
|
||||
protected $description = 'Import timesheet data';
|
||||
|
||||
public function fire() {
|
||||
$this->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(
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
];
|
||||
|
@ -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'));
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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) : ''; })
|
||||
|
@ -79,9 +79,8 @@ class AppController extends BaseController
|
||||
return Redirect::to('/setup')->withInput();
|
||||
}
|
||||
|
||||
// == ENV Settings (Production) == //
|
||||
$config = "APP_ENV=development\n".
|
||||
"APP_DEBUG=true\n".
|
||||
$config = "APP_ENV=production\n".
|
||||
"APP_DEBUG=false\n".
|
||||
"APP_URL={$app['url']}\n".
|
||||
"APP_KEY={$app['key']}\n\n".
|
||||
"DB_TYPE={$dbType}\n".
|
||||
@ -116,7 +115,6 @@ class AppController extends BaseController
|
||||
$user = $account->users()->first();
|
||||
|
||||
//Auth::login($user, true);
|
||||
$this->accountRepo->registerUser($user);
|
||||
|
||||
return Redirect::to('/login');
|
||||
}
|
||||
|
@ -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 .= '<li><a href="'.URL::to('clients/'.$model->public_id.'/edit').'">'.trans('texts.edit_client').'</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="'.URL::to('invoices/create/'.$model->public_id).'">'.trans('texts.new_invoice').'</a></li>
|
||||
<li><a href="'.URL::to('payments/create/'.$model->public_id).'">'.trans('texts.new_payment').'</a></li>
|
||||
<li><a href="'.URL::to('credits/create/'.$model->public_id).'">'.trans('texts.new_credit').'</a></li>
|
||||
<li><a href="'.URL::to('tasks/create/'.$model->public_id).'">'.trans('texts.new_task').'</a></li>
|
||||
<li><a href="'.URL::to('invoices/create/'.$model->public_id).'">'.trans('texts.new_invoice').'</a></li>';
|
||||
|
||||
if (Auth::user()->isPro()) {
|
||||
$str .= '<li><a href="'.URL::to('quotes/create/'.$model->public_id).'">'.trans('texts.new_quote').'</a></li>';
|
||||
}
|
||||
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="'.URL::to('payments/create/'.$model->public_id).'">'.trans('texts.enter_payment').'</a></li>
|
||||
<li><a href="'.URL::to('credits/create/'.$model->public_id).'">'.trans('texts.enter_credit').'</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="javascript:archiveEntity('.$model->public_id.')">'.trans('texts.archive_client').'</a></li>';
|
||||
} else {
|
||||
@ -112,15 +120,18 @@ class ClientController extends BaseController
|
||||
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
|
||||
|
||||
$actionLinks = [
|
||||
['label' => trans('texts.create_invoice'), 'url' => URL::to('invoices/create/'.$client->public_id)],
|
||||
['label' => trans('texts.enter_payment'), 'url' => URL::to('payments/create/'.$client->public_id)],
|
||||
['label' => trans('texts.enter_credit'), 'url' => URL::to('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' => URL::to('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(),
|
||||
);
|
||||
|
||||
|
@ -54,21 +54,25 @@ class DashboardController extends BaseController
|
||||
->where('activity_type_id', '>', 0)
|
||||
->orderBy('created_at', 'desc')->take(14)->get();
|
||||
|
||||
$pastDue = Invoice::scope()
|
||||
->where('due_date', '<', date('Y-m-d'))
|
||||
->where('balance', '>', 0)
|
||||
->where('is_recurring', '=', false)
|
||||
->where('is_quote', '=', false)
|
||||
->where('is_deleted', '=', false)
|
||||
->orderBy('due_date', 'asc')->take(6)->get();
|
||||
$pastDue = Invoice::scope()->whereHas('client', function($query) {
|
||||
$query->where('deleted_at', '=', null);
|
||||
})
|
||||
->where('due_date', '<', date('Y-m-d'))
|
||||
->where('balance', '>', 0)
|
||||
->where('is_recurring', '=', false)
|
||||
->where('is_quote', '=', false)
|
||||
->where('is_deleted', '=', false)
|
||||
->orderBy('due_date', 'asc')->take(6)->get();
|
||||
|
||||
$upcoming = Invoice::scope()
|
||||
->where('due_date', '>=', date('Y-m-d'))
|
||||
->where('balance', '>', 0)
|
||||
->where('is_recurring', '=', false)
|
||||
->where('is_quote', '=', false)
|
||||
->where('is_deleted', '=', false)
|
||||
->orderBy('due_date', 'asc')->take(6)->get();
|
||||
$upcoming = Invoice::scope()->whereHas('client', function($query) {
|
||||
$query->where('deleted_at', '=', null);
|
||||
})
|
||||
->where('due_date', '>=', date('Y-m-d'))
|
||||
->where('balance', '>', 0)
|
||||
->where('is_recurring', '=', false)
|
||||
->where('is_quote', '=', false)
|
||||
->where('is_deleted', '=', false)
|
||||
->orderBy('due_date', 'asc')->take(6)->get();
|
||||
|
||||
$data = [
|
||||
'paidToDate' => $paidToDate,
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use Response;
|
||||
use Request;
|
||||
use Redirect;
|
||||
use Auth;
|
||||
use View;
|
||||
@ -8,6 +10,7 @@ use Session;
|
||||
use App\Models\Account;
|
||||
use App\Libraries\Utils;
|
||||
use App\Ninja\Mailers\Mailer;
|
||||
use Symfony\Component\Security\Core\Util\StringUtils;
|
||||
|
||||
class HomeController extends BaseController
|
||||
{
|
||||
@ -76,4 +79,9 @@ class HomeController extends BaseController
|
||||
{
|
||||
return Utils::logError(Input::get('error'), 'JavaScript');
|
||||
}
|
||||
|
||||
public function keepAlive()
|
||||
{
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
@ -60,10 +60,11 @@ class InvoiceApiController extends Controller
|
||||
}
|
||||
|
||||
if (isset($data['email'])) {
|
||||
$contact = Contact::scope()->with('client')->whereEmail($data['email'])->first();
|
||||
if ($contact) {
|
||||
$client = $contact->client;
|
||||
} else {
|
||||
$client = Client::scope()->whereHas('contacts', function($query) use ($data) {
|
||||
$query->where('email', '=', $data['email']);
|
||||
})->first();
|
||||
|
||||
if (!$client) {
|
||||
$clientData = ['contact' => ['email' => $data['email']]];
|
||||
foreach (['name', 'private_notes'] as $field) {
|
||||
if (isset($data[$field])) {
|
||||
|
@ -13,6 +13,7 @@ use URL;
|
||||
use Datatable;
|
||||
use finfo;
|
||||
use Request;
|
||||
use DropdownButton;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Invitation;
|
||||
use App\Models\Client;
|
||||
@ -27,6 +28,7 @@ use App\Models\PaymentTerm;
|
||||
use App\Models\InvoiceDesign;
|
||||
use App\Models\AccountGateway;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Gateway;
|
||||
use App\Ninja\Mailers\ContactMailer as Mailer;
|
||||
use App\Ninja\Repositories\InvoiceRepository;
|
||||
use App\Ninja\Repositories\ClientRepository;
|
||||
@ -58,10 +60,14 @@ class InvoiceController extends BaseController
|
||||
'columns' => 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(),
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ class PaymentController extends BaseController
|
||||
}
|
||||
|
||||
$table->addColumn('transaction_reference', function ($model) { return $model->transaction_reference ? $model->transaction_reference : '<i>Manual entry</i>'; })
|
||||
->addColumn('payment_type', function ($model) { return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? '<i>Online payment</i>' : ''); });
|
||||
->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;
|
||||
@ -284,7 +285,7 @@ class PaymentController extends BaseController
|
||||
}
|
||||
|
||||
public function show_payment($invitationKey, $paymentType = false)
|
||||
{
|
||||
{
|
||||
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
||||
$invoice = $invitation->invoice;
|
||||
$client = $invoice->client;
|
||||
@ -292,8 +293,9 @@ class PaymentController extends BaseController
|
||||
$useToken = false;
|
||||
|
||||
if (!$paymentType) {
|
||||
$paymentType = $account->account_gateways[0]->getPaymentType();
|
||||
} else if ($paymentType == PAYMENT_TYPE_TOKEN) {
|
||||
$paymentType = Session::get('payment_type', $account->account_gateways[0]->getPaymentType());
|
||||
}
|
||||
if ($paymentType == PAYMENT_TYPE_TOKEN) {
|
||||
$useToken = true;
|
||||
$paymentType = PAYMENT_TYPE_CREDIT_CARD;
|
||||
}
|
||||
@ -323,8 +325,9 @@ class PaymentController extends BaseController
|
||||
'gateway' => $gateway,
|
||||
'acceptedCreditCardTypes' => $acceptedCreditCardTypes,
|
||||
'countries' => Cache::get('countries'),
|
||||
'currencyId' => $client->currency_id,
|
||||
'currencyId' => $client->getCurrencyId(),
|
||||
'account' => $client->account,
|
||||
'hideLogo' => $account->isWhiteLabel(),
|
||||
];
|
||||
|
||||
return View::make('payments.payment', $data);
|
||||
@ -448,6 +451,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 +477,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 +487,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,8 +513,10 @@ 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);
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,7 +539,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 +564,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 +578,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 +591,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 +606,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.<p>', $response->getMessage());
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$errorMessage = trans('texts.payment_error');
|
||||
Session::flash('error', $errorMessage."<p>".$e->getMessage());
|
||||
Utils::logError(Utils::getErrorString($e));
|
||||
Utils::logError('Payment Error [uncaught]:' . Utils::getErrorString($e));
|
||||
|
||||
if ($onSite) {
|
||||
return Redirect::to('payment/'.$invitationKey)->withInput();
|
||||
|
@ -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;
|
||||
|
@ -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 = '[]';
|
||||
|
261
app/Http/Controllers/TaskController.php
Normal file
261
app/Http/Controllers/TaskController.php
Normal file
@ -0,0 +1,261 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use View;
|
||||
use URL;
|
||||
use Utils;
|
||||
use Input;
|
||||
use Datatable;
|
||||
use Validator;
|
||||
use Redirect;
|
||||
use Session;
|
||||
use App\Models\Client;
|
||||
use App\Models\Task;
|
||||
|
||||
/*
|
||||
use Auth;
|
||||
use Cache;
|
||||
|
||||
use App\Models\Activity;
|
||||
use App\Models\Contact;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Size;
|
||||
use App\Models\PaymentTerm;
|
||||
use App\Models\Industry;
|
||||
use App\Models\Currency;
|
||||
use App\Models\Country;
|
||||
*/
|
||||
|
||||
use App\Ninja\Repositories\TaskRepository;
|
||||
|
||||
class TaskController extends BaseController
|
||||
{
|
||||
protected $taskRepo;
|
||||
|
||||
public function __construct(TaskRepository $taskRepo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->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 '<input type="checkbox" name="ids[]" value="'.$model->public_id.'" '.Utils::getEntityRowClass($model).'>'; })
|
||||
->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 = '<div class="btn-group tr-action" style="visibility:hidden;">
|
||||
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
'.trans('texts.select').' <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">';
|
||||
|
||||
if (!$model->deleted_at || $model->deleted_at == '0000-00-00') {
|
||||
$str .= '<li><a href="'.URL::to('tasks/'.$model->public_id.'/edit').'">'.trans('texts.edit_task').'</a></li>';
|
||||
}
|
||||
|
||||
if ($model->invoice_number) {
|
||||
$str .= '<li>' . link_to("/invoices/{$model->invoice_public_id}/edit", trans('texts.view_invoice')) . '</li>';
|
||||
} elseif ($model->duration == -1) {
|
||||
$str .= '<li><a href="javascript:stopTask('.$model->public_id.')">'.trans('texts.stop_task').'</a></li>';
|
||||
} elseif (!$model->deleted_at || $model->deleted_at == '0000-00-00') {
|
||||
$str .= '<li><a href="javascript:invoiceTask('.$model->public_id.')">'.trans('texts.invoice_task').'</a></li>';
|
||||
}
|
||||
|
||||
if (!$model->deleted_at || $model->deleted_at == '0000-00-00') {
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="javascript:archiveEntity('.$model->public_id.')">'.trans('texts.archive_task').'</a></li>';
|
||||
} else {
|
||||
$str .= '<li><a href="javascript:restoreEntity('.$model->public_id.')">'.trans('texts.restore_task').'</a></li>';
|
||||
}
|
||||
|
||||
if (!$model->is_deleted) {
|
||||
$str .= '<li><a href="javascript:deleteEntity('.$model->public_id.')">'.trans('texts.delete_task').'</a></li></ul>';
|
||||
}
|
||||
|
||||
return $str . '</div>';
|
||||
})
|
||||
->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 "<h4><div class=\"label label-{$class}\">$label</div></h4>";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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'),
|
||||
'duration' => time() - strtotime($task->start_time),
|
||||
];
|
||||
|
||||
$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');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
class TimesheetController extends BaseController {
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$data = [
|
||||
'showBreadcrumbs' => 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)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -12,7 +12,7 @@ use Session;
|
||||
use URL;
|
||||
use Utils;
|
||||
use Validator;
|
||||
|
||||
use Illuminate\Auth\Passwords\TokenRepositoryInterface;
|
||||
use App\Models\User;
|
||||
use App\Http\Requests;
|
||||
use App\Ninja\Repositories\AccountRepository;
|
||||
@ -263,7 +263,7 @@ class UserController extends BaseController
|
||||
*
|
||||
* @param string $code
|
||||
*/
|
||||
public function confirm($code)
|
||||
public function confirm($code, TokenRepositoryInterface $tokenRepo)
|
||||
{
|
||||
$user = User::where('confirmation_code', '=', $code)->get()->first();
|
||||
|
||||
@ -275,9 +275,10 @@ class UserController extends BaseController
|
||||
$user->save();
|
||||
|
||||
if ($user->public_id) {
|
||||
Auth::login($user);
|
||||
//Auth::login($user);
|
||||
$token = $tokenRepo->create($user);
|
||||
|
||||
return Redirect::to('user/reset');
|
||||
return Redirect::to("/password/reset/{$token}");
|
||||
} else {
|
||||
if (Session::has(REQUESTED_PRO_PLAN)) {
|
||||
Session::forget(REQUESTED_PRO_PLAN);
|
||||
|
@ -35,7 +35,7 @@ class ApiCheck {
|
||||
}
|
||||
|
||||
if (!Utils::isNinja()) {
|
||||
return null;
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if (!Utils::isPro()) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php namespace app\Http\Middleware;
|
||||
|
||||
use Request;
|
||||
use Closure;
|
||||
use Utils;
|
||||
use App;
|
||||
@ -50,7 +51,10 @@ class StartupCheck
|
||||
'countries' => 'App\Models\Country',
|
||||
];
|
||||
foreach ($cachedTables as $name => $class) {
|
||||
if (!Cache::has($name)) {
|
||||
if (Input::has('clear_cache')) {
|
||||
Session::flash('message', 'Cache cleared');
|
||||
}
|
||||
if (Input::has('clear_cache') || !Cache::has($name)) {
|
||||
if ($name == 'paymentTerms') {
|
||||
$orderBy = 'num_days';
|
||||
} elseif (in_array($name, ['currencies', 'sizes', 'industries', 'languages', 'countries'])) {
|
||||
@ -58,7 +62,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,10 +144,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) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Routes
|
||||
@ -32,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
|
||||
@ -74,16 +74,6 @@ get('/password/reset/{token}', array('as' => 'forgot', 'uses' => 'Auth\PasswordC
|
||||
post('/password/reset', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postReset'));
|
||||
get('/user/confirm/{code}', 'UserController@confirm');
|
||||
|
||||
/*
|
||||
// Confide routes
|
||||
Route::get('login', 'UserController@login');
|
||||
Route::post('login', 'UserController@do_login');
|
||||
Route::get('forgot_password', 'UserController@forgot_password');
|
||||
Route::post('forgot_password', 'UserController@do_forgot_password');
|
||||
Route::get('user/reset/{token?}', 'UserController@reset_password');
|
||||
Route::post('user/reset', 'UserController@do_reset_password');
|
||||
Route::get('logout', 'UserController@logout');
|
||||
*/
|
||||
|
||||
if (Utils::isNinja()) {
|
||||
Route::post('/signup/register', 'AccountController@doRegister');
|
||||
@ -96,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');
|
||||
@ -133,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'));
|
||||
|
||||
@ -226,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');
|
||||
@ -289,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);
|
||||
@ -342,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);
|
||||
@ -355,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/');
|
||||
@ -386,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');
|
||||
|
||||
@ -397,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'],
|
||||
@ -412,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 '<li'.$class.'><a href="'.URL::to($url).'" '.$extra.'>'.$title.'</a></li>';
|
||||
});
|
||||
|
||||
HTML::macro('tab_link', function($url, $text, $active = false) {
|
||||
$class = $active ? ' class="active"' : '';
|
||||
return '<li'.$class.'><a href="'.URL::to($url).'" data-toggle="tab">'.$text.'</a></li>';
|
||||
});
|
||||
|
||||
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 '<li class="dropdown '.$class.'">
|
||||
<a href="'.URL::to($types).'" class="dropdown-toggle">'.trans("texts.$types").'</a>
|
||||
<ul class="dropdown-menu" id="menu1">
|
||||
<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>
|
||||
</ul>
|
||||
</li>';
|
||||
});
|
||||
|
||||
HTML::macro('image_data', function($imagePath) {
|
||||
return 'data:image/jpeg;base64,' . base64_encode(file_get_contents(public_path().'/'.$imagePath));
|
||||
});
|
||||
|
||||
|
||||
HTML::macro('breadcrumbs', function() {
|
||||
$str = '<ol class="breadcrumb">';
|
||||
|
||||
// Get the breadcrumbs by exploding the current path.
|
||||
$basePath = Utils::basePath();
|
||||
$parts = explode('?', $_SERVER['REQUEST_URI']);
|
||||
$path = $parts[0];
|
||||
|
||||
if ($basePath != '/') {
|
||||
$path = str_replace($basePath, '', $path);
|
||||
}
|
||||
$crumbs = explode('/', $path);
|
||||
|
||||
foreach ($crumbs as $key => $val) {
|
||||
if (is_numeric($val)) {
|
||||
unset($crumbs[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$crumbs = array_values($crumbs);
|
||||
for ($i=0; $i<count($crumbs); $i++) {
|
||||
$crumb = trim($crumbs[$i]);
|
||||
if (!$crumb) {
|
||||
continue;
|
||||
}
|
||||
if ($crumb == 'company') {
|
||||
return '';
|
||||
}
|
||||
$name = trans("texts.$crumb");
|
||||
if ($i==count($crumbs)-1) {
|
||||
$str .= "<li class='active'>$name</li>";
|
||||
} else {
|
||||
$str .= '<li>'.link_to($crumb, $name).'</li>';
|
||||
}
|
||||
}
|
||||
return $str . '</ol>';
|
||||
});
|
||||
|
||||
function uctrans($text)
|
||||
{
|
||||
return ucwords(trans($text));
|
||||
@ -500,21 +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)
|
||||
@ -547,4 +457,4 @@ if (Auth::check() && Auth::user()->id === 1)
|
||||
{
|
||||
Auth::loginUsingId(1);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
@ -233,7 +233,7 @@ class Utils
|
||||
public static function formatMoney($value, $currencyId = false)
|
||||
{
|
||||
if (!$currencyId) {
|
||||
$currencyId = Session::get(SESSION_CURRENCY);
|
||||
$currencyId = Session::get(SESSION_CURRENCY, DEFAULT_CURRENCY);
|
||||
}
|
||||
|
||||
foreach (Cache::get('currencies') as $currency) {
|
||||
@ -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);
|
||||
|
@ -1,119 +0,0 @@
|
||||
<?php
|
||||
|
||||
class TimesheetUtils
|
||||
{
|
||||
public static function parseEventSummary($summary) {
|
||||
if (preg_match('/^\s*([^\s:\/]+)(?:\/([^:]+))?\s*:\s*([^)].*$|$)$/s', $summary, $matches)) {
|
||||
return [strtoupper($matches[1]), strtolower($matches[2]), $matches[3]];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function parseICALEvent($eventstr) {
|
||||
if (preg_match_all('/(?:^|\r?\n)([^;:]+)[;:]([^\r\n]+)/s', $eventstr, $matches)) {
|
||||
// Build ICAL event array
|
||||
$data = ['summary' => ''];
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,22 +1,25 @@
|
||||
<?php namespace App\Listeners;
|
||||
|
||||
use Utils;
|
||||
use Auth;
|
||||
use Carbon;
|
||||
use App\Events\UserLoggedIn;
|
||||
|
||||
use App\Ninja\Repositories\AccountRepository;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Contracts\Queue\ShouldBeQueued;
|
||||
|
||||
class HandleUserLoggedIn {
|
||||
|
||||
protected $accountRepo;
|
||||
|
||||
/**
|
||||
* Create the event handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(AccountRepository $accountRepo)
|
||||
{
|
||||
//
|
||||
$this->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();
|
||||
|
||||
|
@ -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(false, $this->id)->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',
|
||||
@ -238,10 +247,21 @@ class Account extends Eloquent
|
||||
'quote_number',
|
||||
'total',
|
||||
'invoice_issued_to',
|
||||
'date',
|
||||
'rate',
|
||||
'hours',
|
||||
];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$data[$field] = trans("texts.$field");
|
||||
if (isset($custom[$field]) && $custom[$field]) {
|
||||
$data[$field] = $custom[$field];
|
||||
} else {
|
||||
$data[$field] = uctrans("texts.$field");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (['item', 'quantity', 'unit_cost'] as $field) {
|
||||
$data["{$field}_orig"] = $data[$field];
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
@ -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;
|
||||
@ -393,7 +406,7 @@ class Activity extends Eloquent
|
||||
public static function createCredit($credit)
|
||||
{
|
||||
$activity = Activity::getBlank();
|
||||
$activity->message = Utils::encodeActivity(Auth::user(), 'entered '.Utils::formatMoney($credit->amount, $credit->client->currency_id).' credit');
|
||||
$activity->message = Utils::encodeActivity(Auth::user(), 'entered '.Utils::formatMoney($credit->amount, $credit->client->getCurrencyId()).' credit');
|
||||
$activity->credit_id = $credit->id;
|
||||
$activity->client_id = $credit->client_id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_CREDIT;
|
||||
@ -408,7 +421,7 @@ class Activity extends Eloquent
|
||||
$activity->credit_id = $credit->id;
|
||||
$activity->client_id = $credit->client_id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_DELETE_CREDIT;
|
||||
$activity->message = Utils::encodeActivity(Auth::user(), 'deleted '.Utils::formatMoney($credit->balance, $credit->client->currency_id).' credit');
|
||||
$activity->message = Utils::encodeActivity(Auth::user(), 'deleted '.Utils::formatMoney($credit->balance, $credit->client->getCurrencyId()).' credit');
|
||||
$activity->balance = $credit->client->balance;
|
||||
$activity->save();
|
||||
} else {
|
||||
@ -447,7 +460,7 @@ class Activity extends Eloquent
|
||||
$activity->client_id = $credit->client_id;
|
||||
$activity->credit_id = $credit->id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CREDIT;
|
||||
$activity->message = Utils::encodeActivity(Auth::user(), 'archived '.Utils::formatMoney($credit->balance, $credit->client->currency_id).' credit');
|
||||
$activity->message = Utils::encodeActivity(Auth::user(), 'archived '.Utils::formatMoney($credit->balance, $credit->client->getCurrencyId()).' credit');
|
||||
$activity->balance = $credit->client->balance;
|
||||
$activity->save();
|
||||
}
|
||||
@ -458,7 +471,7 @@ class Activity extends Eloquent
|
||||
$activity->client_id = $credit->client_id;
|
||||
$activity->credit_id = $credit->id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_RESTORE_CREDIT;
|
||||
$activity->message = Utils::encodeActivity(Auth::user(), 'restored '.Utils::formatMoney($credit->balance, $credit->client->currency_id).' credit');
|
||||
$activity->message = Utils::encodeActivity(Auth::user(), 'restored '.Utils::formatMoney($credit->balance, $credit->client->getCurrencyId()).' credit');
|
||||
$activity->balance = $credit->client->balance;
|
||||
$activity->save();
|
||||
}
|
||||
|
@ -148,6 +148,15 @@ class Client extends EntityModel
|
||||
$token = $this->getGatewayToken();
|
||||
return $token ? "https://dashboard.stripe.com/customers/{$token}" : false;
|
||||
}
|
||||
|
||||
public function getCurrencyId()
|
||||
{
|
||||
if (!$this->account) {
|
||||
$this->load('account');
|
||||
}
|
||||
|
||||
return $this->currency_id ?: ($this->account->currency_id ?: DEFAULT_CURRENCY);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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}";
|
||||
|
@ -10,6 +10,7 @@ class Invoice extends EntityModel
|
||||
|
||||
protected $casts = [
|
||||
'is_recurring' => 'boolean',
|
||||
'has_tasks' => 'boolean',
|
||||
];
|
||||
|
||||
public function account()
|
||||
@ -121,6 +122,7 @@ class Invoice extends EntityModel
|
||||
'custom_taxes1',
|
||||
'custom_taxes2',
|
||||
'partial',
|
||||
'has_tasks',
|
||||
]);
|
||||
|
||||
$this->client->setVisible([
|
||||
|
@ -34,7 +34,7 @@ class Payment extends EntityModel
|
||||
|
||||
public function getAmount()
|
||||
{
|
||||
return Utils::formatMoney($this->amount, $this->client->currency_id);
|
||||
return Utils::formatMoney($this->amount, $this->client->getCurrencyId());
|
||||
}
|
||||
|
||||
public function getName()
|
||||
|
@ -1,49 +0,0 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
use Auth;
|
||||
use Utils;
|
||||
use Eloquent;
|
||||
|
||||
class Project extends Eloquent
|
||||
{
|
||||
public $timestamps = true;
|
||||
protected $softDelete = true;
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->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;
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
use Auth;
|
||||
use Utils;
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class ProjectCode extends Eloquent
|
||||
{
|
||||
public $timestamps = true;
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->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;
|
||||
}
|
||||
}
|
36
app/Models/Task.php
Normal file
36
app/Models/Task.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
use DB;
|
||||
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Task extends EntityModel
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->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);
|
||||
});
|
@ -1,26 +0,0 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Timesheet extends Eloquent
|
||||
{
|
||||
public $timestamps = true;
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Account');
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\Models\User');
|
||||
}
|
||||
|
||||
public function timesheet_events()
|
||||
{
|
||||
return $this->hasMany('App\Models\TimeSheetEvent');
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
use Auth;
|
||||
use Utils;
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class TimesheetEvent extends Eloquent
|
||||
{
|
||||
public $timestamps = true;
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
/* protected $dates = array('org_updated_at');
|
||||
|
||||
public function getDates() {
|
||||
return array('created_at', 'updated_at', 'deleted_at');
|
||||
} */
|
||||
|
||||
/* public function setOrgUpdatedAtAttribute($value)
|
||||
{
|
||||
var_dump($value);
|
||||
$this->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;
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
use Auth;
|
||||
use Utils;
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class TimesheetEventSource extends Eloquent
|
||||
{
|
||||
public $timestamps = true;
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
public function account()
|
||||
{
|
||||
return $this->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;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
use Utils;
|
||||
use Event;
|
||||
use URL;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
@ -19,13 +20,13 @@ class ContactMailer extends Mailer
|
||||
$subject = trans("texts.{$entityType}_subject", ['invoice' => $invoice->invoice_number, 'account' => $invoice->account->getDisplayName()]);
|
||||
$accountName = $invoice->account->getDisplayName();
|
||||
$emailTemplate = $invoice->account->getEmailTemplate($entityType);
|
||||
$invoiceAmount = Utils::formatMoney($invoice->getRequestedAmount(), $invoice->client->currency_id);
|
||||
$invoiceAmount = Utils::formatMoney($invoice->getRequestedAmount(), $invoice->client->getCurrencyId());
|
||||
|
||||
foreach ($invoice->invitations as $invitation) {
|
||||
if (!$invitation->user || !$invitation->user->email) {
|
||||
if (!$invitation->user || !$invitation->user->email || $invitation->user->trashed()) {
|
||||
return false;
|
||||
}
|
||||
if (!$invitation->contact || !$invitation->contact->email) {
|
||||
if (!$invitation->contact || !$invitation->contact->email || $invitation->contact->trashed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -41,6 +42,18 @@ class ContactMailer extends Mailer
|
||||
'$amount' => $invoiceAmount
|
||||
];
|
||||
|
||||
// Add variables for available payment types
|
||||
foreach([PAYMENT_TYPE_CREDIT_CARD, PAYMENT_TYPE_PAYPAL, PAYMENT_TYPE_BITCOIN] as $type) {
|
||||
if ($invoice->account->getGatewayByType($type)) {
|
||||
|
||||
// Changes "PAYMENT_TYPE_CREDIT_CARD" to "$credit_card_link"
|
||||
$gateway_slug = '$'.strtolower(str_replace('PAYMENT_TYPE_', '', $type)).'_link';
|
||||
|
||||
$variables[$gateway_slug] = URL::to("/payment/{$invitation->invitation_key}/{$type}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$data['body'] = str_replace(array_keys($variables), array_values($variables), $emailTemplate);
|
||||
$data['link'] = $invitation->getLink();
|
||||
$data['entityType'] = $entityType;
|
||||
@ -72,7 +85,7 @@ class ContactMailer extends Mailer
|
||||
'$footer' => $payment->account->getEmailFooter(),
|
||||
'$client' => $payment->client->getDisplayName(),
|
||||
'$account' => $accountName,
|
||||
'$amount' => Utils::formatMoney($payment->amount, $payment->client->currency_id)
|
||||
'$amount' => Utils::formatMoney($payment->amount, $payment->client->getCurrencyId())
|
||||
];
|
||||
|
||||
$data = ['body' => str_replace(array_keys($variables), array_values($variables), $emailTemplate)];
|
||||
|
@ -39,7 +39,7 @@ class UserMailer extends Mailer
|
||||
return;
|
||||
}
|
||||
|
||||
$entityType = $invoice->getEntityType();
|
||||
$entityType = $notificationType == 'approved' ? ENTITY_QUOTE : ENTITY_INVOICE;
|
||||
$view = "{$entityType}_{$notificationType}";
|
||||
|
||||
$data = [
|
||||
@ -47,13 +47,13 @@ class UserMailer extends Mailer
|
||||
'clientName' => $invoice->client->getDisplayName(),
|
||||
'accountName' => $invoice->account->getDisplayName(),
|
||||
'userName' => $user->getDisplayName(),
|
||||
'invoiceAmount' => Utils::formatMoney($invoice->amount, $invoice->client->currency_id),
|
||||
'invoiceAmount' => Utils::formatMoney($invoice->amount, $invoice->client->getCurrencyId()),
|
||||
'invoiceNumber' => $invoice->invoice_number,
|
||||
'invoiceLink' => SITE_URL."/{$entityType}s/{$invoice->public_id}",
|
||||
];
|
||||
|
||||
if ($payment) {
|
||||
$data['paymentAmount'] = Utils::formatMoney($payment->amount, $invoice->client->currency_id);
|
||||
$data['paymentAmount'] = Utils::formatMoney($payment->amount, $invoice->client->getCurrencyId());
|
||||
}
|
||||
|
||||
$subject = trans("texts.notification_{$entityType}_{$notificationType}_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->getDisplayName()]);
|
||||
|
@ -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;
|
||||
|
@ -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 .= '<li><a href="'.\URL::to('payments/create/'.$model->client_public_id.'/'.$model->public_id).'">'.trans('texts.enter_payment').'</a></li>';
|
||||
}
|
||||
|
||||
@ -271,7 +272,8 @@ class InvoiceRepository
|
||||
$invoice->invoice_number = trim($data['invoice_number']);
|
||||
$invoice->partial = round(Utils::parseFloat($data['partial']), 2);
|
||||
$invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']);
|
||||
|
||||
$invoice->has_tasks = isset($data['has_tasks']) ? $data['has_tasks'] : false;
|
||||
|
||||
if (!$publicId) {
|
||||
$invoice->is_recurring = $data['is_recurring'] && !Utils::isDemo() ? true : false;
|
||||
}
|
||||
@ -291,6 +293,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 +382,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 +436,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 +466,8 @@ class InvoiceRepository
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
'custom_taxes1',
|
||||
'custom_taxes2', ] as $field) {
|
||||
'custom_taxes2',
|
||||
'partial'] as $field) {
|
||||
$clone->$field = $invoice->$field;
|
||||
}
|
||||
|
||||
|
@ -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()) {
|
||||
@ -95,8 +102,12 @@ class PaymentRepository
|
||||
$payment = Payment::createNew();
|
||||
}
|
||||
|
||||
$paymentTypeId = $input['payment_type_id'] ? $input['payment_type_id'] : null;
|
||||
$payment->payment_type_id = $paymentTypeId;
|
||||
$paymentTypeId = false;
|
||||
if (isset($input['payment_type_id'])) {
|
||||
$paymentTypeId = $input['payment_type_id'] ? $input['payment_type_id'] : null;
|
||||
$payment->payment_type_id = $paymentTypeId;
|
||||
}
|
||||
|
||||
$payment->payment_date = Utils::toSqlDate($input['payment_date']);
|
||||
$payment->transaction_reference = trim($input['transaction_reference']);
|
||||
|
||||
|
102
app/Ninja/Repositories/TaskRepository.php
Normal file
102
app/Ninja/Repositories/TaskRepository.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php namespace App\Ninja\Repositories;
|
||||
|
||||
use Auth;
|
||||
use Carbon;
|
||||
use Session;
|
||||
use App\Models\Client;
|
||||
use App\Models\Contact;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Task;
|
||||
|
||||
class TaskRepository
|
||||
{
|
||||
public function find($clientPublicId = null, $filter = null)
|
||||
{
|
||||
$query = \DB::table('tasks')
|
||||
->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);
|
||||
}
|
||||
}
|
@ -1,5 +1,12 @@
|
||||
<?php namespace App\Providers;
|
||||
|
||||
use Session;
|
||||
use Auth;
|
||||
use Utils;
|
||||
use HTML;
|
||||
use URL;
|
||||
use Request;
|
||||
use Validator;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider {
|
||||
@ -11,7 +18,105 @@ class AppServiceProvider extends ServiceProvider {
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
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 '<li'.$class.'><a href="'.URL::to($url).'" '.$extra.'>'.$title.'</a></li>';
|
||||
});
|
||||
|
||||
HTML::macro('tab_link', function($url, $text, $active = false) {
|
||||
$class = $active ? ' class="active"' : '';
|
||||
return '<li'.$class.'><a href="'.URL::to($url).'" data-toggle="tab">'.$text.'</a></li>';
|
||||
});
|
||||
|
||||
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 = '<li class="dropdown '.$class.'">
|
||||
<a href="'.URL::to($types).'" class="dropdown-toggle">'.trans("texts.$types").'</a>
|
||||
<ul class="dropdown-menu" id="menu1">
|
||||
<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>';
|
||||
|
||||
if ($type == ENTITY_INVOICE && Auth::user()->isPro()) {
|
||||
$str .= '<li class="divider"></li>
|
||||
<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>
|
||||
<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
|
||||
}
|
||||
|
||||
$str .= '</ul>
|
||||
</li>';
|
||||
|
||||
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 = '<ol class="breadcrumb">';
|
||||
|
||||
// Get the breadcrumbs by exploding the current path.
|
||||
$basePath = Utils::basePath();
|
||||
$parts = explode('?', $_SERVER['REQUEST_URI']);
|
||||
$path = $parts[0];
|
||||
|
||||
if ($basePath != '/') {
|
||||
$path = str_replace($basePath, '', $path);
|
||||
}
|
||||
$crumbs = explode('/', $path);
|
||||
|
||||
foreach ($crumbs as $key => $val) {
|
||||
if (is_numeric($val)) {
|
||||
unset($crumbs[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$crumbs = array_values($crumbs);
|
||||
for ($i=0; $i<count($crumbs); $i++) {
|
||||
$crumb = trim($crumbs[$i]);
|
||||
if (!$crumb) {
|
||||
continue;
|
||||
}
|
||||
if ($crumb == 'company') {
|
||||
return '';
|
||||
}
|
||||
$name = trans("texts.$crumb");
|
||||
if ($i==count($crumbs)-1) {
|
||||
$str .= "<li class='active'>$name</li>";
|
||||
} else {
|
||||
$str .= '<li>'.link_to($crumb, $name).'</li>';
|
||||
}
|
||||
}
|
||||
return $str . '</ol>';
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,8 @@
|
||||
"spectrum": "~1.3.4",
|
||||
"d3": "~3.4.11",
|
||||
"handsontable": "*",
|
||||
"pdfmake": "*"
|
||||
"pdfmake": "*",
|
||||
"moment": "*"
|
||||
},
|
||||
"resolutions": {
|
||||
"jquery": "~1.11"
|
||||
|
@ -18,7 +18,7 @@
|
||||
"patricktalmadge/bootstrapper": "5.5.x",
|
||||
"anahkiasen/former": "4.0.*@dev",
|
||||
"barryvdh/laravel-debugbar": "~2.0.2",
|
||||
"chumper/datatable": "dev-develop",
|
||||
"chumper/datatable": "dev-develop#7fa47cb",
|
||||
"omnipay/omnipay": "2.3.x",
|
||||
"intervention/image": "dev-master",
|
||||
"webpatser/laravel-countries": "dev-master",
|
||||
@ -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",
|
||||
|
893
composer.lock
generated
893
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Libraries\Utils;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
@ -39,7 +41,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'timezone' => 'UTC',
|
||||
'timezone' => env('APP_TIMEZONE', 'UTC'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@ -125,8 +127,8 @@ return [
|
||||
'Illuminate\Filesystem\FilesystemServiceProvider',
|
||||
'Illuminate\Foundation\Providers\FoundationServiceProvider',
|
||||
'Illuminate\Hashing\HashServiceProvider',
|
||||
'Illuminate\Mail\MailServiceProvider',
|
||||
'Illuminate\Pagination\PaginationServiceProvider',
|
||||
(isset($_ENV['POSTMARK_API_TOKEN']) ? 'Postmark\Adapters\LaravelMailProvider' : 'Illuminate\Mail\MailServiceProvider'),
|
||||
'Illuminate\Pagination\PaginationServiceProvider',
|
||||
'Illuminate\Pipeline\PipelineServiceProvider',
|
||||
'Illuminate\Queue\QueueServiceProvider',
|
||||
'Illuminate\Redis\RedisServiceProvider',
|
||||
@ -187,7 +189,7 @@ return [
|
||||
'File' => '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',
|
||||
|
@ -1,66 +1,184 @@
|
||||
<?php return array(
|
||||
|
||||
// Markup
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Markup
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Whether labels should be automatically computed from name
|
||||
'automatic_label' => 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' => '<sup>*</sup>',
|
||||
// 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'),
|
||||
),
|
||||
|
||||
|
||||
);
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
// HTML markup and classes used by the "Nude" framework for icons
|
||||
'icon' => array(
|
||||
|
||||
'tag' => 'i',
|
||||
'set' => null,
|
||||
'prefix' => 'icon',
|
||||
|
||||
),
|
||||
|
||||
);
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
// HTML markup and classes used by Bootstrap for icons
|
||||
'icon' => array(
|
||||
|
||||
'tag' => 'i',
|
||||
'set' => null,
|
||||
'prefix' => 'icon',
|
||||
|
||||
),
|
||||
|
||||
);
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
return 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',
|
||||
),
|
||||
|
||||
);
|
@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
// Map Former-supported viewports to Foundation 3 equivalents
|
||||
'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',
|
||||
|
||||
),
|
||||
|
||||
);
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
// Map Former-supported viewports to Foundation 4 equivalents
|
||||
// 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',
|
||||
|
||||
),
|
||||
|
||||
);
|
@ -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')],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
// HTML markup and classes used by the "Nude" framework for icons
|
||||
'icon' => array(
|
||||
|
||||
'tag' => 'i',
|
||||
'set' => null,
|
||||
'prefix' => 'icon',
|
||||
|
||||
),
|
||||
|
||||
);
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
// HTML markup and classes used by Bootstrap for icons
|
||||
'icon' => array(
|
||||
|
||||
'tag' => 'i',
|
||||
'set' => null,
|
||||
'prefix' => 'icon',
|
||||
|
||||
),
|
||||
|
||||
);
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
return 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',
|
||||
),
|
||||
|
||||
);
|
@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
// Map Former-supported viewports to Foundation 3 equivalents
|
||||
'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',
|
||||
|
||||
),
|
||||
|
||||
);
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
return array(
|
||||
|
||||
// Map Former-supported viewports to Foundation 4 equivalents
|
||||
// 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',
|
||||
|
||||
),
|
||||
|
||||
);
|
@ -1,59 +0,0 @@
|
||||
<?php return array(
|
||||
|
||||
// Markup
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Whether labels should be automatically computed from name
|
||||
'automatic_label' => 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' => '', //'<sup>*</sup>',
|
||||
|
||||
// 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'
|
||||
),
|
||||
);
|
@ -14,6 +14,8 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'postmark' => env('POSTMARK_API_TOKEN', ''),
|
||||
|
||||
'mailgun' => [
|
||||
'domain' => '',
|
||||
'secret' => '',
|
||||
|
@ -29,7 +29,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'lifetime' => 360,
|
||||
'lifetime' => env('SESSION_LIFETIME', 120),
|
||||
|
||||
'expire_on_close' => false,
|
||||
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
34
database/migrations/2015_05_21_184104_add_font_size.php
Normal file
34
database/migrations/2015_05_21_184104_add_font_size.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddFontSize extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function($table)
|
||||
{
|
||||
$table->smallInteger('font_size')->default(DEFAULT_FONT_SIZE);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function($table)
|
||||
{
|
||||
$table->dropColumn('font_size');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
55
database/migrations/2015_05_27_121828_add_tasks.php
Normal file
55
database/migrations/2015_05_27_121828_add_tasks.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddTasks extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('tasks', function($table) {
|
||||
$table->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');
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddCustomInvoiceLabels extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function($table)
|
||||
{
|
||||
$table->text('invoice_labels')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function($table)
|
||||
{
|
||||
$table->dropColumn('invoice_labels');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddHasTasksToInvoices extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('invoices', function($table)
|
||||
{
|
||||
$table->boolean('has_tasks')->default(false);
|
||||
});
|
||||
|
||||
$invoices = DB::table('invoices')
|
||||
->join('tasks', 'tasks.invoice_id', '=', 'invoices.id')
|
||||
->selectRaw('DISTINCT invoices.id')
|
||||
->get();
|
||||
|
||||
foreach ($invoices as $invoice) {
|
||||
DB::table('invoices')
|
||||
->where('id', $invoice->id)
|
||||
->update(['has_tasks' => true]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('invoices', function($table)
|
||||
{
|
||||
$table->dropColumn('has_tasks');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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]']);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
27
public/css/built.css
vendored
27
public/css/built.css
vendored
@ -2449,6 +2449,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;
|
||||
@ -2467,7 +2472,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;
|
||||
}
|
||||
@ -2617,7 +2622,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 +2872,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 +3213,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 +3241,9 @@ div.checkbox > label {
|
||||
background-color: #0b4d78 !important;
|
||||
}
|
||||
|
||||
/*
|
||||
.panel-default {
|
||||
border-color: #e37329 !important;
|
||||
div.alert {
|
||||
z-index: 1;
|
||||
}
|
||||
*/
|
||||
|
||||
.alert-hide {
|
||||
position: absolute;
|
||||
|
4
public/css/built.public.css
vendored
4
public/css/built.public.css
vendored
File diff suppressed because one or more lines are too long
27
public/css/style.css
vendored
27
public/css/style.css
vendored
@ -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;
|
||||
|
BIN
public/favicon.png
Executable file → Normal file
BIN
public/favicon.png
Executable file → Normal file
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 23 KiB |
File diff suppressed because one or more lines are too long
@ -1,47 +1,115 @@
|
||||
var NINJA = NINJA || {};
|
||||
|
||||
function GetPdfMake(invoice, javascript, callback) {
|
||||
var account = invoice.account;
|
||||
eval(javascript);
|
||||
var baseDD = {
|
||||
pageMargins: [40, 40, 40, 40],
|
||||
styles: {
|
||||
bold: {
|
||||
bold: true
|
||||
},
|
||||
cost: {
|
||||
alignment: 'right'
|
||||
},
|
||||
quantity: {
|
||||
alignment: 'right'
|
||||
},
|
||||
tax: {
|
||||
alignment: 'right'
|
||||
},
|
||||
lineTotal: {
|
||||
alignment: 'right'
|
||||
},
|
||||
right: {
|
||||
alignment: 'right'
|
||||
},
|
||||
subtotals: {
|
||||
alignment: 'right'
|
||||
},
|
||||
termsLabel: {
|
||||
bold: true,
|
||||
margin: [0, 10, 0, 4]
|
||||
}
|
||||
},
|
||||
footer: function(){
|
||||
f = [{ text:invoice.invoice_footer?processVariables(invoice.invoice_footer):"", margin: [40, 0]}]
|
||||
if (!invoice.is_pro && logoImages.imageLogo1) {
|
||||
f.push({
|
||||
image: logoImages.imageLogo1,
|
||||
width: 150,
|
||||
margin: [40,0]
|
||||
});
|
||||
}
|
||||
return f;
|
||||
},
|
||||
|
||||
/*
|
||||
var fonts = {
|
||||
Roboto: {
|
||||
normal: 'Roboto-Regular.ttf',
|
||||
bold: 'Roboto-Medium.ttf',
|
||||
italics: 'Roboto-Italic.ttf',
|
||||
bolditalics: 'Roboto-Italic.ttf'
|
||||
},
|
||||
};
|
||||
*/
|
||||
};
|
||||
|
||||
doc = pdfMake.createPdf(dd);
|
||||
doc.save = function(fileName) {
|
||||
this.download(fileName);
|
||||
};
|
||||
return doc;
|
||||
eval(javascript);
|
||||
dd = $.extend(true, baseDD, dd);
|
||||
|
||||
/*
|
||||
pdfMake.fonts = {
|
||||
wqy: {
|
||||
normal: 'wqy.ttf',
|
||||
bold: 'wqy.ttf',
|
||||
italics: 'wqy.ttf',
|
||||
bolditalics: 'wqy.ttf'
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
pdfMake.fonts = {
|
||||
NotoSansCJKsc: {
|
||||
normal: 'NotoSansCJKsc-Regular.ttf',
|
||||
bold: 'NotoSansCJKsc-Medium.ttf',
|
||||
italics: 'NotoSansCJKsc-Italic.ttf',
|
||||
bolditalics: 'NotoSansCJKsc-Italic.ttf'
|
||||
},
|
||||
Roboto: {
|
||||
normal: 'Roboto-Regular.ttf',
|
||||
bold: 'Roboto-Medium.ttf',
|
||||
italics: 'Roboto-Italic.ttf',
|
||||
bolditalics: 'Roboto-Italic.ttf'
|
||||
},
|
||||
};
|
||||
*/
|
||||
|
||||
doc = pdfMake.createPdf(dd);
|
||||
doc.save = function(fileName) {
|
||||
this.download(fileName);
|
||||
};
|
||||
return doc;
|
||||
}
|
||||
function notesAndTerms(invoice)
|
||||
|
||||
NINJA.notesAndTerms = function(invoice)
|
||||
{
|
||||
var text = [];
|
||||
if (invoice.public_notes) {
|
||||
text.push({text:invoice.public_notes, style:'notes'});
|
||||
text.push({text:processVariables(invoice.public_notes), style:'notes'});
|
||||
}
|
||||
|
||||
if (invoice.terms) {
|
||||
text.push({text:invoiceLabels.terms, style:'termsLabel'});
|
||||
text.push({text:invoice.terms, style:'terms'});
|
||||
text.push({text:processVariables(invoice.terms), style:'terms'});
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
function invoiceLines(invoice) {
|
||||
var grid =
|
||||
[[{text: invoiceLabels.item, style: 'tableHeader'},
|
||||
{text: invoiceLabels.description, style: 'tableHeader'},
|
||||
{text: invoiceLabels.unit_cost, style: 'tableHeader'},
|
||||
{text: invoiceLabels.quantity, style: 'tableHeader'},
|
||||
{text: invoice.has_taxes?invoiceLabels.tax:'', style: 'tableHeader'},
|
||||
{text: invoiceLabels.line_total, style: 'tableHeader'}]];
|
||||
NINJA.invoiceLines = function(invoice) {
|
||||
var grid = [
|
||||
[
|
||||
{text: invoiceLabels.item, style: 'tableHeader'},
|
||||
{text: invoiceLabels.description, style: 'tableHeader'},
|
||||
{text: invoiceLabels.unit_cost, style: 'tableHeader'},
|
||||
{text: invoiceLabels.quantity, style: 'tableHeader'},
|
||||
{text: invoice.has_taxes?invoiceLabels.tax:'', style: 'tableHeader'},
|
||||
{text: invoiceLabels.line_total, style: 'tableHeader'}
|
||||
]
|
||||
];
|
||||
|
||||
var total = 0;
|
||||
var shownItem = false;
|
||||
var currencyId = invoice && invoice.client ? invoice.client.currency_id : 1;
|
||||
@ -61,50 +129,52 @@ function invoiceLines(invoice) {
|
||||
tax = parseFloat(item.tax_rate);
|
||||
}
|
||||
|
||||
// show at most one blank line
|
||||
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
|
||||
continue;
|
||||
}
|
||||
shownItem = true;
|
||||
// show at most one blank line
|
||||
if (shownItem && (!cost || cost == '0.00') && !notes && !productKey) {
|
||||
continue;
|
||||
}
|
||||
shownItem = true;
|
||||
|
||||
// process date variables
|
||||
if (invoice.is_recurring) {
|
||||
notes = processVariables(notes);
|
||||
productKey = processVariables(productKey);
|
||||
// process date variables
|
||||
if (invoice.is_recurring) {
|
||||
notes = processVariables(notes);
|
||||
productKey = processVariables(productKey);
|
||||
}
|
||||
|
||||
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
||||
if (tax) {
|
||||
lineTotal += lineTotal * tax / 100;
|
||||
}
|
||||
if (lineTotal) {
|
||||
total += lineTotal;
|
||||
}
|
||||
lineTotal = formatMoney(lineTotal, currencyId);
|
||||
|
||||
rowStyle = i%2===0?'odd':'even';
|
||||
|
||||
row[0] = {style:["productKey", rowStyle], text:productKey};
|
||||
row[1] = {style:["notes", rowStyle], text:notes};
|
||||
row[2] = {style:["cost", rowStyle], text:cost};
|
||||
row[3] = {style:["quantity", rowStyle], text:qty};
|
||||
row[4] = {style:["tax", rowStyle], text:""+tax};
|
||||
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
|
||||
|
||||
grid.push(row);
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
var lineTotal = roundToTwo(NINJA.parseFloat(item.cost)) * roundToTwo(NINJA.parseFloat(item.qty));
|
||||
if (tax) {
|
||||
lineTotal += lineTotal * tax / 100;
|
||||
}
|
||||
if (lineTotal) {
|
||||
total += lineTotal;
|
||||
}
|
||||
lineTotal = formatMoney(lineTotal, currencyId);
|
||||
|
||||
rowStyle = i%2===0?'odd':'even';
|
||||
|
||||
row[0] = {style:["productKey", rowStyle], text:productKey};
|
||||
row[1] = {style:["notes", rowStyle], text:notes};
|
||||
row[2] = {style:["cost", rowStyle], text:cost};
|
||||
row[3] = {style:["quantity", rowStyle], text:qty};
|
||||
row[4] = {style:["tax", rowStyle], text:""+tax};
|
||||
row[5] = {style:["lineTotal", rowStyle], text:lineTotal};
|
||||
|
||||
grid.push(row);
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
|
||||
function subtotals(invoice)
|
||||
NINJA.subtotals = function(invoice)
|
||||
{
|
||||
if (!invoice) {
|
||||
return;
|
||||
}
|
||||
|
||||
var data = [
|
||||
[invoiceLabels.subtotal, formatMoney(invoice.subtotal_amount, invoice.client.currency_id)],
|
||||
[invoiceLabels.subtotal, formatMoney(invoice.subtotal_amount, invoice.client.currency_id)],
|
||||
];
|
||||
|
||||
if(invoice.discount_amount != 0) {
|
||||
data.push([invoiceLabels.discount, formatMoney(invoice.discount_amount, invoice.client.currency_id)]);
|
||||
}
|
||||
@ -137,7 +207,7 @@ function subtotals(invoice)
|
||||
return data;
|
||||
}
|
||||
|
||||
function accountDetails(account) {
|
||||
NINJA.accountDetails = function(account) {
|
||||
var data = [];
|
||||
if(account.name) data.push({text:account.name, style:'accountName'});
|
||||
if(account.id_number) data.push({text:account.id_number, style:'accountDetails'});
|
||||
@ -147,7 +217,7 @@ function accountDetails(account) {
|
||||
return data;
|
||||
}
|
||||
|
||||
function accountAddress(account) {
|
||||
NINJA.accountAddress = function(account) {
|
||||
var address = '';
|
||||
if (account.city || account.state || account.postal_code) {
|
||||
address = ((account.city ? account.city + ', ' : '') + account.state + ' ' + account.postal_code).trim();
|
||||
@ -157,10 +227,12 @@ function accountAddress(account) {
|
||||
if(account.address2) data.push({text:account.address2, style:'accountDetails'});
|
||||
if(address) data.push({text:address, style:'accountDetails'});
|
||||
if(account.country) data.push({text:account.country.name, style: 'accountDetails'});
|
||||
if(account.custom_label1 && account.custom_value1) data.push({text:account.custom_label1 +' '+ account.custom_value1, style: 'accountDetails'});
|
||||
if(account.custom_label2 && account.custom_value2) data.push({text:account.custom_label2 +' '+ account.custom_value2, style: 'accountDetails'});
|
||||
return data;
|
||||
}
|
||||
|
||||
function invoiceDetails(invoice) {
|
||||
NINJA.invoiceDetails = function(invoice) {
|
||||
var data = [
|
||||
[
|
||||
invoice.is_quote ? invoiceLabels.quote_number : invoiceLabels.invoice_number,
|
||||
@ -179,11 +251,12 @@ function invoiceDetails(invoice) {
|
||||
return data;
|
||||
}
|
||||
|
||||
function clientDetails(invoice) {
|
||||
NINJA.clientDetails = function(invoice) {
|
||||
var client = invoice.client;
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fields = [
|
||||
getClientDisplayName(client),
|
||||
client.id_number,
|
||||
@ -202,16 +275,23 @@ function clientDetails(invoice) {
|
||||
if (!field) {
|
||||
continue;
|
||||
}
|
||||
data.push(field);
|
||||
}
|
||||
data.push([field]);
|
||||
}
|
||||
if (!data.length) {
|
||||
data.push(['']);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
function primaryColor( defaultColor) {
|
||||
return NINJA.primaryColor?NINJA.primaryColor:defaultColor;
|
||||
NINJA.getPrimaryColor = function(defaultColor) {
|
||||
return NINJA.primaryColor ? NINJA.primaryColor : defaultColor;
|
||||
}
|
||||
|
||||
function secondaryColor( defaultColor) {
|
||||
return NINJA.primaryColor?NINJA.secondaryColor:defaultColor;
|
||||
NINJA.getSecondaryColor = function(defaultColor) {
|
||||
return NINJA.primaryColor ? NINJA.secondaryColor : defaultColor;
|
||||
}
|
||||
|
||||
NINJA.getEntityLabel = function(invoice) {
|
||||
return invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice;
|
||||
}
|
66368
public/js/pdfmake.js
Normal file
66368
public/js/pdfmake.js
Normal file
File diff suppressed because one or more lines are too long
12
public/js/pdfmake.min.js
vendored
Normal file
12
public/js/pdfmake.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/pdfmake.min.js.map
Normal file
1
public/js/pdfmake.min.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -102,7 +102,7 @@ function GetPdf(invoice, javascript){
|
||||
SetPdfColor(invoice.invoice_design_id == 2 || invoice.invoice_design_id == 3 ? 'White' : 'Black',doc);
|
||||
var top = doc.internal.pageSize.height - layout.marginLeft;
|
||||
if (!invoice.is_pro) top -= 25;
|
||||
var footer = doc.splitTextToSize(invoice.invoice_footer, 500);
|
||||
var footer = doc.splitTextToSize(processVariables(invoice.invoice_footer), 500);
|
||||
var numLines = footer.length - 1;
|
||||
doc.text(layout.marginLeft, top - (numLines * 8), footer);
|
||||
}
|
||||
@ -884,13 +884,13 @@ function displayNotesAndTerms(doc, layout, invoice, y)
|
||||
var origY = y;
|
||||
|
||||
if (invoice.public_notes) {
|
||||
var notes = doc.splitTextToSize(invoice.public_notes, 260);
|
||||
var notes = doc.splitTextToSize(processVariables(invoice.public_notes), 260);
|
||||
doc.text(layout.marginLeft, y, notes);
|
||||
y += 16 + (notes.length * doc.internal.getFontSize());
|
||||
}
|
||||
|
||||
if (invoice.terms) {
|
||||
var terms = doc.splitTextToSize(invoice.terms, 260);
|
||||
var terms = doc.splitTextToSize(processVariables(invoice.terms), 260);
|
||||
doc.setFontType("bold");
|
||||
doc.text(layout.marginLeft, y, invoiceLabels.terms);
|
||||
y += 16;
|
||||
@ -1539,4 +1539,31 @@ function roundToTwo(num, toString) {
|
||||
|
||||
function truncate(str, length) {
|
||||
return (str && str.length > length) ? (str.substr(0, length-1) + '...') : str;
|
||||
}
|
||||
|
||||
// http://codeaid.net/javascript/convert-seconds-to-hours-minutes-and-seconds-%28javascript%29
|
||||
function secondsToTime(secs)
|
||||
{
|
||||
secs = Math.round(secs);
|
||||
var hours = Math.floor(secs / (60 * 60));
|
||||
|
||||
var divisor_for_minutes = secs % (60 * 60);
|
||||
var minutes = Math.floor(divisor_for_minutes / 60);
|
||||
|
||||
var divisor_for_seconds = divisor_for_minutes % 60;
|
||||
var seconds = Math.ceil(divisor_for_seconds);
|
||||
|
||||
var obj = {
|
||||
"h": hours,
|
||||
"m": minutes,
|
||||
"s": seconds
|
||||
};
|
||||
return obj;
|
||||
}
|
||||
|
||||
function twoDigits(value) {
|
||||
if (value < 10) {
|
||||
return '0' + value;
|
||||
}
|
||||
return value;
|
||||
}
|
@ -1,192 +1,162 @@
|
||||
//pdfmake
|
||||
|
||||
/*
|
||||
var dd = {
|
||||
content: 'wqy中文wqy',
|
||||
defaultStyle: {
|
||||
font: 'wqy'
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
var dd = {
|
||||
content: [
|
||||
content: [
|
||||
{
|
||||
columns: [
|
||||
columns: [
|
||||
[
|
||||
invoice.image?
|
||||
{
|
||||
image: invoice.image,
|
||||
fit: [150, 80]
|
||||
}:""
|
||||
invoice.image?
|
||||
{
|
||||
image: invoice.image,
|
||||
fit: [150, 80]
|
||||
}:""
|
||||
],
|
||||
{
|
||||
stack: accountDetails(account)
|
||||
stack: NINJA.accountDetails(account)
|
||||
},
|
||||
{
|
||||
stack: accountAddress(account)
|
||||
stack: NINJA.accountAddress(account)
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
text:(invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase(),
|
||||
margin: [8, 70, 8, 16],
|
||||
style: 'primaryColor',
|
||||
fontSize: 11
|
||||
text:(NINJA.getEntityLabel(invoice)).toUpperCase(),
|
||||
margin: [8, 70, 8, 16],
|
||||
style: 'primaryColor',
|
||||
fontSize: NINJA.fontSize + 2
|
||||
},
|
||||
{
|
||||
style: 'tableExample',
|
||||
table: {
|
||||
headerRows: 1,
|
||||
widths: ['auto', 'auto', '*'],
|
||||
body: [[
|
||||
{
|
||||
table: {
|
||||
body: invoiceDetails(invoice),
|
||||
},
|
||||
layout: 'noBorders',
|
||||
},
|
||||
clientDetails(invoice),
|
||||
''
|
||||
]]
|
||||
},
|
||||
layout: {
|
||||
hLineWidth: function (i, node) {
|
||||
return (i === 0 || i === node.table.body.length) ? .5 : 0;
|
||||
table: {
|
||||
headerRows: 1,
|
||||
widths: ['auto', 'auto', '*'],
|
||||
body: [
|
||||
[
|
||||
{
|
||||
table: {
|
||||
body: NINJA.invoiceDetails(invoice),
|
||||
},
|
||||
layout: 'noBorders',
|
||||
},
|
||||
{
|
||||
table: {
|
||||
body: NINJA.clientDetails(invoice),
|
||||
},
|
||||
layout: 'noBorders',
|
||||
},
|
||||
''
|
||||
]
|
||||
]
|
||||
},
|
||||
vLineWidth: function (i, node) {
|
||||
return 0;//(i === 0 || i === node.table.widths.length) ? 2 : 1;
|
||||
},
|
||||
hLineColor: function (i, node) {
|
||||
return '#D8D8D8';//(i === 0 || i === node.table.body.length) ? 'black' : 'gray';
|
||||
},
|
||||
/*vLineColor: function (i, node) {
|
||||
return (i === 0 || i === node.table.widths.length) ? 'black' : 'gray';
|
||||
},*/
|
||||
paddingLeft: function(i, node) { return 8; },
|
||||
paddingRight: function(i, node) { return 8; },
|
||||
paddingTop: function(i, node) { return 4; },
|
||||
paddingBottom: function(i, node) { return 4; }
|
||||
}
|
||||
},
|
||||
'\n',
|
||||
{
|
||||
table: {
|
||||
headerRows: 1,
|
||||
widths: ['15%', '*', 'auto', 'auto', 'auto', 'auto'],
|
||||
body:invoiceLines(invoice),
|
||||
},
|
||||
layout: {
|
||||
hLineWidth: function (i, node) {
|
||||
return i === 0 ? 0 : .5;
|
||||
},
|
||||
vLineWidth: function (i, node) {
|
||||
return 0;
|
||||
},
|
||||
hLineColor: function (i, node) {
|
||||
return '#D8D8D8';
|
||||
},
|
||||
paddingLeft: function(i, node) { return 8; },
|
||||
paddingRight: function(i, node) { return 8; },
|
||||
paddingTop: function(i, node) { return 8; },
|
||||
paddingBottom: function(i, node) { return 8; }
|
||||
},
|
||||
},
|
||||
'\n',
|
||||
{
|
||||
columns: [
|
||||
notesAndTerms(invoice),
|
||||
{
|
||||
style: 'subtotals',
|
||||
table: {
|
||||
widths: ['*', '*'],
|
||||
body: subtotals(invoice),
|
||||
},
|
||||
layout: {
|
||||
layout: {
|
||||
hLineWidth: function (i, node) {
|
||||
return 0;
|
||||
return (i === 0 || i === node.table.body.length) ? .5 : 0;
|
||||
},
|
||||
vLineWidth: function (i, node) {
|
||||
return 0;
|
||||
return 0;
|
||||
},
|
||||
hLineColor: function (i, node) {
|
||||
return '#D8D8D8';
|
||||
},
|
||||
paddingLeft: function(i, node) { return 8; },
|
||||
paddingRight: function(i, node) { return 8; },
|
||||
paddingTop: function(i, node) { return 4; },
|
||||
paddingBottom: function(i, node) { return 4; }
|
||||
},
|
||||
paddingBottom: function(i, node) { return 4; }
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
'\n',
|
||||
{
|
||||
table: {
|
||||
headerRows: 1,
|
||||
widths: ['15%', '*', 'auto', 'auto', 'auto', 'auto'],
|
||||
body: NINJA.invoiceLines(invoice),
|
||||
},
|
||||
layout: {
|
||||
hLineWidth: function (i, node) {
|
||||
return i === 0 ? 0 : .5;
|
||||
},
|
||||
vLineWidth: function (i, node) {
|
||||
return 0;
|
||||
},
|
||||
hLineColor: function (i, node) {
|
||||
return '#D8D8D8';
|
||||
},
|
||||
paddingLeft: function(i, node) { return 8; },
|
||||
paddingRight: function(i, node) { return 8; },
|
||||
paddingTop: function(i, node) { return 8; },
|
||||
paddingBottom: function(i, node) { return 8; }
|
||||
},
|
||||
},
|
||||
'\n',
|
||||
{
|
||||
columns: [
|
||||
NINJA.notesAndTerms(invoice),
|
||||
{
|
||||
style: 'subtotals',
|
||||
table: {
|
||||
widths: ['*', '*'],
|
||||
body: NINJA.subtotals(invoice),
|
||||
},
|
||||
layout: {
|
||||
hLineWidth: function (i, node) {
|
||||
return 0;
|
||||
},
|
||||
vLineWidth: function (i, node) {
|
||||
return 0;
|
||||
},
|
||||
paddingLeft: function(i, node) { return 8; },
|
||||
paddingRight: function(i, node) { return 8; },
|
||||
paddingTop: function(i, node) { return 4; },
|
||||
paddingBottom: function(i, node) { return 4; }
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
footer: function(){
|
||||
f = [{ text:invoice.invoice_footer?invoice.invoice_footer:"", margin: [40, 0]}]
|
||||
if (!invoice.is_pro && logoImages.imageLogo1) {
|
||||
f.push({
|
||||
image: logoImages.imageLogo1,
|
||||
width: 150,
|
||||
margin: [40,0]
|
||||
});
|
||||
}
|
||||
return f;
|
||||
},
|
||||
|
||||
defaultStyle: {
|
||||
//font: 'Roboto',
|
||||
fontSize: 9,
|
||||
margin: [8, 4, 8, 4]
|
||||
},
|
||||
styles: {
|
||||
primaryColor:{
|
||||
color: primaryColor('#299CC2')
|
||||
defaultStyle: {
|
||||
//font: 'arialuni',
|
||||
fontSize: NINJA.fontSize,
|
||||
margin: [8, 4, 8, 4]
|
||||
},
|
||||
accountName: {
|
||||
margin: [4, 2, 4, 2],
|
||||
color:primaryColor('#299CC2')
|
||||
styles: {
|
||||
primaryColor:{
|
||||
color: NINJA.getPrimaryColor('#299CC2')
|
||||
},
|
||||
accountName: {
|
||||
margin: [4, 2, 4, 2],
|
||||
color: NINJA.getPrimaryColor('#299CC2')
|
||||
},
|
||||
accountDetails: {
|
||||
margin: [4, 2, 4, 2],
|
||||
color: '#AAA9A9'
|
||||
},
|
||||
even: {
|
||||
},
|
||||
odd: {
|
||||
fillColor:'#F4F4F4'
|
||||
},
|
||||
productKey: {
|
||||
color: NINJA.getPrimaryColor('#299CC2')
|
||||
},
|
||||
tableHeader: {
|
||||
bold: true
|
||||
},
|
||||
balanceDueLabel: {
|
||||
fontSize: NINJA.fontSize + 2
|
||||
},
|
||||
balanceDueValue: {
|
||||
fontSize: NINJA.fontSize + 2,
|
||||
color: NINJA.getPrimaryColor('#299CC2')
|
||||
},
|
||||
},
|
||||
accountDetails: {
|
||||
margin: [4, 2, 4, 2],
|
||||
color: '#AAA9A9'
|
||||
},
|
||||
bold: {
|
||||
bold: true
|
||||
},
|
||||
even: {
|
||||
},
|
||||
odd: {
|
||||
fillColor:'#F4F4F4'
|
||||
},
|
||||
productKey: {
|
||||
color:primaryColor('#299CC2')
|
||||
},
|
||||
cost: {
|
||||
alignment: 'right'
|
||||
},
|
||||
quantity: {
|
||||
alignment: 'right'
|
||||
},
|
||||
tax: {
|
||||
alignment: 'right'
|
||||
},
|
||||
lineTotal: {
|
||||
alignment: 'right'
|
||||
},
|
||||
right: {
|
||||
alignment: 'right'
|
||||
},
|
||||
subtotals: {
|
||||
alignment: 'right'
|
||||
},
|
||||
tableHeader: {
|
||||
bold: true
|
||||
},
|
||||
balanceDueLabel: {
|
||||
fontSize: 11
|
||||
},
|
||||
balanceDueValue: {
|
||||
fontSize: 11,
|
||||
color:primaryColor('#299CC2')
|
||||
},
|
||||
notes: {
|
||||
},
|
||||
terms: {
|
||||
|
||||
},
|
||||
termsLabel: {
|
||||
bold: true,
|
||||
fontSize: 10,
|
||||
margin: [0, 10, 0, 4]
|
||||
}
|
||||
},
|
||||
pageMargins: [40, 40, 40, 40]
|
||||
pageMargins: [40, 40, 40, 40],
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
# Invoice Ninja
|
||||
### [https://www.invoiceninja.com](https://www.invoiceninja.com)
|
||||
##### Please [click here](https://bitnami.com/stack/invoice-ninja) to vote for us to be added to Bitnami's one-click install library
|
||||
|
||||
If you'd like to use our code to sell your own invoicing app we have an affiliate program. Get in touch for more details.
|
||||
|
||||
@ -8,7 +7,7 @@ If you'd like to use our code to sell your own invoicing app we have an affiliat
|
||||
|
||||
To setup the site you can either use the [zip file](https://www.invoiceninja.com/knowledgebase/self-host/) (easier to run) or checkout the code from GitHub (easier to make changes).
|
||||
|
||||
For updates follow [@invoiceninja](https://twitter.com/invoiceninja) or join the [Facebook Group](https://www.facebook.com/invoiceninja). For discussion of the code please use the [Google Group](https://groups.google.com/d/forum/invoiceninja).
|
||||
For updates follow [@invoiceninja](https://twitter.com/invoiceninja) or join the [Facebook Group](https://www.facebook.com/invoiceninja). For discussion of the app please use our [new forum](http://www.invoiceninja.com/forums).
|
||||
|
||||
If you'd like to translate the site please use [caouecs/Laravel4-long](https://github.com/caouecs/Laravel4-lang) for the starter files.
|
||||
|
||||
@ -20,8 +19,9 @@ Developed by [@hillelcoren](https://twitter.com/hillelcoren) | Designed by [kant
|
||||
* Live PDF generation
|
||||
* Integrates with 30+ payment providers
|
||||
* Recurring invoices
|
||||
* Tax rates and payment terms
|
||||
* Tasks with time-tracking
|
||||
* Multi-user support
|
||||
* Tax rates and payment terms
|
||||
* Partial payments
|
||||
* Custom email templates
|
||||
* [Zapier](https://zapier.com/) integration
|
||||
|
@ -626,5 +626,56 @@ return array(
|
||||
'zapier' => 'Zapier <sup>Beta</sup>',
|
||||
'recurring' => 'Recurring',
|
||||
'last_invoice_sent' => 'Last invoice sent :date',
|
||||
|
||||
|
||||
'processed_updates' => 'Successfully completed update',
|
||||
'tasks' => 'Tasks',
|
||||
'new_task' => 'New Task',
|
||||
'start_time' => 'Start Time',
|
||||
'created_task' => 'Successfully created task',
|
||||
'updated_task' => 'Successfully updated task',
|
||||
'edit_task' => 'Edit Task',
|
||||
'archive_task' => 'Archive Task',
|
||||
'restore_task' => 'Restore Task',
|
||||
'delete_task' => 'Delete Task',
|
||||
'stop_task' => 'Stop Task',
|
||||
'time' => 'Time',
|
||||
'start' => 'Start',
|
||||
'stop' => 'Stop',
|
||||
'now' => 'Now',
|
||||
'timer' => 'Timer',
|
||||
'manual' => 'Manual',
|
||||
'date_and_time' => 'Date & Time',
|
||||
'second' => 'second',
|
||||
'seconds' => 'seconds',
|
||||
'minute' => 'minute',
|
||||
'minutes' => 'minutes',
|
||||
'hour' => 'hour',
|
||||
'hours' => 'hours',
|
||||
'task_details' => 'Task Details',
|
||||
'duration' => 'Duration',
|
||||
'end_time' => 'End Time',
|
||||
'end' => 'End',
|
||||
'invoiced' => 'Invoiced',
|
||||
'logged' => 'Logged',
|
||||
'running' => 'Running',
|
||||
'task_error_multiple_clients' => 'The tasks can\'t belong to different clients',
|
||||
'task_error_running' => 'Please stop running tasks first',
|
||||
'task_error_invoiced' => 'Tasks have already been invoiced',
|
||||
'restored_task' => 'Successfully restored task',
|
||||
'archived_task' => 'Successfully archived task',
|
||||
'archived_tasks' => 'Successfully archived :count tasks',
|
||||
'deleted_task' => 'Successfully deleted task',
|
||||
'deleted_tasks' => 'Successfully deleted :count tasks',
|
||||
'create_task' => 'Create Task',
|
||||
'stopped_task' => 'Successfully stopped task',
|
||||
'invoice_task' => 'Invoice Task',
|
||||
'invoice_labels' => 'Invoice Labels',
|
||||
'prefix' => 'Prefix',
|
||||
'counter' => 'Counter',
|
||||
|
||||
'payment_type_dwolla' => 'Dwolla',
|
||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||
'partial_value' => 'Must be greater than zero and less than the total',
|
||||
'more_actions' => 'More Actions',
|
||||
|
||||
);
|
||||
|
@ -76,7 +76,8 @@ return array(
|
||||
"positive" => "The :attribute must be greater than zero.",
|
||||
"has_credit" => "The client does not have enough credit.",
|
||||
"notmasked" => "The values are masked",
|
||||
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Language Lines
|
||||
|
@ -618,5 +618,55 @@ return array(
|
||||
'recurring' => 'Wiederkehrend',
|
||||
'last_invoice_sent' => 'Letzte Rechnung verschickt am :date',
|
||||
|
||||
'processed_updates' => 'Successfully completed update',
|
||||
'tasks' => 'Tasks',
|
||||
'new_task' => 'New Task',
|
||||
'start_time' => 'Start Time',
|
||||
'created_task' => 'Successfully created task',
|
||||
'updated_task' => 'Successfully updated task',
|
||||
'edit_task' => 'Edit Task',
|
||||
'archive_task' => 'Archive Task',
|
||||
'restore_task' => 'Restore Task',
|
||||
'delete_task' => 'Delete Task',
|
||||
'stop_task' => 'Stop Task',
|
||||
'time' => 'Time',
|
||||
'start' => 'Start',
|
||||
'stop' => 'Stop',
|
||||
'now' => 'Now',
|
||||
'timer' => 'Timer',
|
||||
'manual' => 'Manual',
|
||||
'date_and_time' => 'Date & Time',
|
||||
'second' => 'second',
|
||||
'seconds' => 'seconds',
|
||||
'minute' => 'minute',
|
||||
'minutes' => 'minutes',
|
||||
'hour' => 'hour',
|
||||
'hours' => 'hours',
|
||||
'task_details' => 'Task Details',
|
||||
'duration' => 'Duration',
|
||||
'end_time' => 'End Time',
|
||||
'end' => 'End',
|
||||
'invoiced' => 'Invoiced',
|
||||
'logged' => 'Logged',
|
||||
'running' => 'Running',
|
||||
'task_error_multiple_clients' => 'The tasks can\'t belong to different clients',
|
||||
'task_error_running' => 'Please stop running tasks first',
|
||||
'task_error_invoiced' => 'Tasks have already been invoiced',
|
||||
'restored_task' => 'Successfully restored task',
|
||||
'archived_task' => 'Successfully archived task',
|
||||
'archived_tasks' => 'Successfully archived :count tasks',
|
||||
'deleted_task' => 'Successfully deleted task',
|
||||
'deleted_tasks' => 'Successfully deleted :count tasks',
|
||||
'create_task' => 'Create Task',
|
||||
'stopped_task' => 'Successfully stopped task',
|
||||
'invoice_task' => 'Invoice Task',
|
||||
'invoice_labels' => 'Invoice Labels',
|
||||
'prefix' => 'Prefix',
|
||||
'counter' => 'Counter',
|
||||
|
||||
'payment_type_dwolla' => 'Dwolla',
|
||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||
'partial_value' => 'Must be greater than zero and less than the total',
|
||||
'more_actions' => 'More Actions',
|
||||
|
||||
);
|
@ -74,7 +74,8 @@ return array(
|
||||
"positive" => ":attribute muss größer als null sein.",
|
||||
"has_credit" => "Der Kunde hat nicht genug Guthaben.",
|
||||
"notmasked" => "The values are masked",
|
||||
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Language Lines
|
||||
|
@ -135,8 +135,8 @@ return array(
|
||||
'filter' => 'Filter',
|
||||
'new_client' => 'New Client',
|
||||
'new_invoice' => 'New Invoice',
|
||||
'new_payment' => 'New Payment',
|
||||
'new_credit' => 'New Credit',
|
||||
'new_payment' => 'Enter Payment',
|
||||
'new_credit' => 'Enter Credit',
|
||||
'contact' => 'Contact',
|
||||
'date_created' => 'Date Created',
|
||||
'last_login' => 'Last Login',
|
||||
@ -443,7 +443,7 @@ return array(
|
||||
'share_invoice_counter' => 'Share invoice counter',
|
||||
'invoice_issued_to' => 'Invoice issued to',
|
||||
'invalid_counter' => 'To prevent a possible conflict please set either an invoice or quote number prefix',
|
||||
'mark_sent' => 'Mark sent',
|
||||
'mark_sent' => 'Mark Sent',
|
||||
|
||||
'gateway_help_1' => ':link to sign up for Authorize.net.',
|
||||
'gateway_help_2' => ':link to sign up for Authorize.net.',
|
||||
@ -626,5 +626,54 @@ return array(
|
||||
'last_invoice_sent' => 'Last invoice sent :date',
|
||||
|
||||
'processed_updates' => 'Successfully completed update',
|
||||
'tasks' => 'Tasks',
|
||||
'new_task' => 'New Task',
|
||||
'start_time' => 'Start Time',
|
||||
'created_task' => 'Successfully created task',
|
||||
'updated_task' => 'Successfully updated task',
|
||||
'edit_task' => 'Edit Task',
|
||||
'archive_task' => 'Archive Task',
|
||||
'restore_task' => 'Restore Task',
|
||||
'delete_task' => 'Delete Task',
|
||||
'stop_task' => 'Stop Task',
|
||||
'time' => 'Time',
|
||||
'start' => 'Start',
|
||||
'stop' => 'Stop',
|
||||
'now' => 'Now',
|
||||
'timer' => 'Timer',
|
||||
'manual' => 'Manual',
|
||||
'date_and_time' => 'Date & Time',
|
||||
'second' => 'second',
|
||||
'seconds' => 'seconds',
|
||||
'minute' => 'minute',
|
||||
'minutes' => 'minutes',
|
||||
'hour' => 'hour',
|
||||
'hours' => 'hours',
|
||||
'task_details' => 'Task Details',
|
||||
'duration' => 'Duration',
|
||||
'end_time' => 'End Time',
|
||||
'end' => 'End',
|
||||
'invoiced' => 'Invoiced',
|
||||
'logged' => 'Logged',
|
||||
'running' => 'Running',
|
||||
'task_error_multiple_clients' => 'The tasks can\'t belong to different clients',
|
||||
'task_error_running' => 'Please stop running tasks first',
|
||||
'task_error_invoiced' => 'Tasks have already been invoiced',
|
||||
'restored_task' => 'Successfully restored task',
|
||||
'archived_task' => 'Successfully archived task',
|
||||
'archived_tasks' => 'Successfully archived :count tasks',
|
||||
'deleted_task' => 'Successfully deleted task',
|
||||
'deleted_tasks' => 'Successfully deleted :count tasks',
|
||||
'create_task' => 'Create Task',
|
||||
'stopped_task' => 'Successfully stopped task',
|
||||
'invoice_task' => 'Invoice Task',
|
||||
'invoice_labels' => 'Invoice Labels',
|
||||
'prefix' => 'Prefix',
|
||||
'counter' => 'Counter',
|
||||
|
||||
'payment_type_dwolla' => 'Dwolla',
|
||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||
'partial_value' => 'Must be greater than zero and less than the total',
|
||||
'more_actions' => 'More Actions',
|
||||
|
||||
);
|
||||
|
@ -72,6 +72,7 @@ return array(
|
||||
"positive" => "The :attribute must be greater than zero.",
|
||||
"has_credit" => "The client does not have enough credit.",
|
||||
"notmasked" => "The values are masked",
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -597,6 +597,55 @@ return array(
|
||||
'recurring' => 'Recurring',
|
||||
'last_invoice_sent' => 'Last invoice sent :date',
|
||||
|
||||
'processed_updates' => 'Successfully completed update',
|
||||
'tasks' => 'Tasks',
|
||||
'new_task' => 'New Task',
|
||||
'start_time' => 'Start Time',
|
||||
'created_task' => 'Successfully created task',
|
||||
'updated_task' => 'Successfully updated task',
|
||||
'edit_task' => 'Edit Task',
|
||||
'archive_task' => 'Archive Task',
|
||||
'restore_task' => 'Restore Task',
|
||||
'delete_task' => 'Delete Task',
|
||||
'stop_task' => 'Stop Task',
|
||||
'time' => 'Time',
|
||||
'start' => 'Start',
|
||||
'stop' => 'Stop',
|
||||
'now' => 'Now',
|
||||
'timer' => 'Timer',
|
||||
'manual' => 'Manual',
|
||||
'date_and_time' => 'Date & Time',
|
||||
'second' => 'second',
|
||||
'seconds' => 'seconds',
|
||||
'minute' => 'minute',
|
||||
'minutes' => 'minutes',
|
||||
'hour' => 'hour',
|
||||
'hours' => 'hours',
|
||||
'task_details' => 'Task Details',
|
||||
'duration' => 'Duration',
|
||||
'end_time' => 'End Time',
|
||||
'end' => 'End',
|
||||
'invoiced' => 'Invoiced',
|
||||
'logged' => 'Logged',
|
||||
'running' => 'Running',
|
||||
'task_error_multiple_clients' => 'The tasks can\'t belong to different clients',
|
||||
'task_error_running' => 'Please stop running tasks first',
|
||||
'task_error_invoiced' => 'Tasks have already been invoiced',
|
||||
'restored_task' => 'Successfully restored task',
|
||||
'archived_task' => 'Successfully archived task',
|
||||
'archived_tasks' => 'Successfully archived :count tasks',
|
||||
'deleted_task' => 'Successfully deleted task',
|
||||
'deleted_tasks' => 'Successfully deleted :count tasks',
|
||||
'create_task' => 'Create Task',
|
||||
'stopped_task' => 'Successfully stopped task',
|
||||
'invoice_task' => 'Invoice Task',
|
||||
'invoice_labels' => 'Invoice Labels',
|
||||
'prefix' => 'Prefix',
|
||||
'counter' => 'Counter',
|
||||
|
||||
'payment_type_dwolla' => 'Dwolla',
|
||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||
'partial_value' => 'Must be greater than zero and less than the total',
|
||||
'more_actions' => 'More Actions',
|
||||
|
||||
);
|
@ -73,7 +73,7 @@ return array(
|
||||
"positive" => ":attribute debe ser mayor que cero.",
|
||||
"has_credit" => "el cliente no tiene crédito suficiente.",
|
||||
"notmasked" => "The values are masked",
|
||||
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -626,5 +626,55 @@ return array(
|
||||
'recurring' => 'Recurring',
|
||||
'last_invoice_sent' => 'Last invoice sent :date',
|
||||
|
||||
'processed_updates' => 'Successfully completed update',
|
||||
'tasks' => 'Tasks',
|
||||
'new_task' => 'New Task',
|
||||
'start_time' => 'Start Time',
|
||||
'created_task' => 'Successfully created task',
|
||||
'updated_task' => 'Successfully updated task',
|
||||
'edit_task' => 'Edit Task',
|
||||
'archive_task' => 'Archive Task',
|
||||
'restore_task' => 'Restore Task',
|
||||
'delete_task' => 'Delete Task',
|
||||
'stop_task' => 'Stop Task',
|
||||
'time' => 'Time',
|
||||
'start' => 'Start',
|
||||
'stop' => 'Stop',
|
||||
'now' => 'Now',
|
||||
'timer' => 'Timer',
|
||||
'manual' => 'Manual',
|
||||
'date_and_time' => 'Date & Time',
|
||||
'second' => 'second',
|
||||
'seconds' => 'seconds',
|
||||
'minute' => 'minute',
|
||||
'minutes' => 'minutes',
|
||||
'hour' => 'hour',
|
||||
'hours' => 'hours',
|
||||
'task_details' => 'Task Details',
|
||||
'duration' => 'Duration',
|
||||
'end_time' => 'End Time',
|
||||
'end' => 'End',
|
||||
'invoiced' => 'Invoiced',
|
||||
'logged' => 'Logged',
|
||||
'running' => 'Running',
|
||||
'task_error_multiple_clients' => 'The tasks can\'t belong to different clients',
|
||||
'task_error_running' => 'Please stop running tasks first',
|
||||
'task_error_invoiced' => 'Tasks have already been invoiced',
|
||||
'restored_task' => 'Successfully restored task',
|
||||
'archived_task' => 'Successfully archived task',
|
||||
'archived_tasks' => 'Successfully archived :count tasks',
|
||||
'deleted_task' => 'Successfully deleted task',
|
||||
'deleted_tasks' => 'Successfully deleted :count tasks',
|
||||
'create_task' => 'Create Task',
|
||||
'stopped_task' => 'Successfully stopped task',
|
||||
'invoice_task' => 'Invoice Task',
|
||||
'invoice_labels' => 'Invoice Labels',
|
||||
'prefix' => 'Prefix',
|
||||
'counter' => 'Counter',
|
||||
|
||||
'payment_type_dwolla' => 'Dwolla',
|
||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||
'partial_value' => 'Must be greater than zero and less than the total',
|
||||
'more_actions' => 'More Actions',
|
||||
|
||||
);
|
@ -73,7 +73,7 @@ return array(
|
||||
"positive" => ":attribute debe ser mayor que cero.",
|
||||
"has_credit" => "el cliente no tiene crédito suficiente.",
|
||||
"notmasked" => "The values are masked",
|
||||
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -618,5 +618,55 @@ return array(
|
||||
'recurring' => 'Recurring',
|
||||
'last_invoice_sent' => 'Last invoice sent :date',
|
||||
|
||||
'processed_updates' => 'Successfully completed update',
|
||||
'tasks' => 'Tasks',
|
||||
'new_task' => 'New Task',
|
||||
'start_time' => 'Start Time',
|
||||
'created_task' => 'Successfully created task',
|
||||
'updated_task' => 'Successfully updated task',
|
||||
'edit_task' => 'Edit Task',
|
||||
'archive_task' => 'Archive Task',
|
||||
'restore_task' => 'Restore Task',
|
||||
'delete_task' => 'Delete Task',
|
||||
'stop_task' => 'Stop Task',
|
||||
'time' => 'Time',
|
||||
'start' => 'Start',
|
||||
'stop' => 'Stop',
|
||||
'now' => 'Now',
|
||||
'timer' => 'Timer',
|
||||
'manual' => 'Manual',
|
||||
'date_and_time' => 'Date & Time',
|
||||
'second' => 'second',
|
||||
'seconds' => 'seconds',
|
||||
'minute' => 'minute',
|
||||
'minutes' => 'minutes',
|
||||
'hour' => 'hour',
|
||||
'hours' => 'hours',
|
||||
'task_details' => 'Task Details',
|
||||
'duration' => 'Duration',
|
||||
'end_time' => 'End Time',
|
||||
'end' => 'End',
|
||||
'invoiced' => 'Invoiced',
|
||||
'logged' => 'Logged',
|
||||
'running' => 'Running',
|
||||
'task_error_multiple_clients' => 'The tasks can\'t belong to different clients',
|
||||
'task_error_running' => 'Please stop running tasks first',
|
||||
'task_error_invoiced' => 'Tasks have already been invoiced',
|
||||
'restored_task' => 'Successfully restored task',
|
||||
'archived_task' => 'Successfully archived task',
|
||||
'archived_tasks' => 'Successfully archived :count tasks',
|
||||
'deleted_task' => 'Successfully deleted task',
|
||||
'deleted_tasks' => 'Successfully deleted :count tasks',
|
||||
'create_task' => 'Create Task',
|
||||
'stopped_task' => 'Successfully stopped task',
|
||||
'invoice_task' => 'Invoice Task',
|
||||
'invoice_labels' => 'Invoice Labels',
|
||||
'prefix' => 'Prefix',
|
||||
'counter' => 'Counter',
|
||||
|
||||
'payment_type_dwolla' => 'Dwolla',
|
||||
'gateway_help_43' => ':link to sign up for Dwolla.',
|
||||
'partial_value' => 'Must be greater than zero and less than the total',
|
||||
'more_actions' => 'More Actions',
|
||||
|
||||
);
|
@ -74,7 +74,8 @@ return array(
|
||||
"positive" => "The :attribute must be greater than zero.",
|
||||
"has_credit" => "The client does not have enough credit.",
|
||||
"notmasked" => "The values are masked",
|
||||
|
||||
"less_than" => 'The :attribute must be less than :value',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Language Lines
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user