1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Merge Laravel 5.2 upgrade

This commit is contained in:
Joshua Dwire 2016-03-03 21:57:15 -05:00
commit 903904d423
154 changed files with 4388 additions and 2245 deletions

View File

@ -20,11 +20,25 @@ MAIL_FROM_ADDRESS
MAIL_FROM_NAME
MAIL_PASSWORD
#POSTMARK_API_TOKEN=
PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'
LOG=single
REQUIRE_HTTPS=false
API_SECRET=password
GOOGLE_CLIENT_ID
GOOGLE_CLIENT_SECRET
GOOGLE_OAUTH_REDIRECT=http://ninja.dev/auth/google
#TRUSTED_PROXIES=
#SESSION_DRIVER=
#SESSION_DOMAIN=
#SESSION_ENCRYPT=
#SESSION_SECURE=
#CACHE_DRIVER=
#CACHE_HOST=
#CACHE_PORT1=
#CACHE_PORT2=
#GOOGLE_CLIENT_ID=
#GOOGLE_CLIENT_SECRET=
#GOOGLE_OAUTH_REDIRECT=http://ninja.dev/auth/google

View File

@ -3,7 +3,7 @@ language: php
sudo: true
php:
- 5.5
- 5.5.9
# - 5.6
# - 7.0
# - hhvm
@ -64,16 +64,17 @@ before_script:
script:
- php ./vendor/codeception/codeception/codecept run --debug acceptance AllPagesCept.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance APICest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance CheckBalanceCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance CreditCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceDesignCest.php
#- php ./vendor/codeception/codeception/codecept run acceptance OnlinePaymentCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance PaymentCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php
#- php ./vendor/codeception/codeception/codecept run --debug acceptance TaxRatesCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance APICest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance CheckBalanceCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance ClientCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance ExpenseCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance CreditCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance InvoiceDesignCest.php
- php ./vendor/codeception/codeception/codecept run acceptance OnlinePaymentCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance PaymentCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance TaskCest.php
- php ./vendor/codeception/codeception/codecept run --debug acceptance TaxRatesCest.php
#- sed -i 's/NINJA_DEV=true/NINJA_PROD=true/g' .env
#- php ./vendor/codeception/codeception/codecept run acceptance GoProCest.php

View File

@ -95,19 +95,19 @@ module.exports = function(grunt) {
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.no.min.js',
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.es.min.js',
'public/vendor/bootstrap-datepicker/dist/locales/bootstrap-datepicker.sv.min.js',
'public/vendor/typeahead.js/dist/typeahead.min.js',
'public/vendor/typeahead.js/dist/typeahead.jquery.min.js',
'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-timezone/builds/moment-timezone-with-data.min.js',
'public/vendor/stacktrace-js/dist/stacktrace-with-polyfills.min.js',
'public/vendor/fuse.js/src/fuse.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',
//'public/js/vfs_fonts.js',
'public/js/lightbox.min.js',
'public/js/bootstrap-combobox.js',
'public/js/script.js',
'public/js/pdf.pdfmake.js',
@ -140,7 +140,6 @@ module.exports = function(grunt) {
'public/vendor/spectrum/spectrum.css',
'public/css/bootstrap-combobox.css',
'public/css/typeahead.js-bootstrap.css',
'public/css/lightbox.css',
//'public/vendor/handsontable/dist/jquery.handsontable.full.css',
'public/css/style.css',
],

View File

@ -0,0 +1,63 @@
<?php namespace App\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\AccountRepository;
use App\Services\PaymentService;
use App\Models\Invoice;
class ChargeRenewalInvoices extends Command
{
protected $name = 'ninja:charge-renewals';
protected $description = 'Charge renewal invoices';
protected $mailer;
protected $accountRepo;
protected $paymentService;
public function __construct(Mailer $mailer, AccountRepository $repo, PaymentService $paymentService)
{
parent::__construct();
$this->mailer = $mailer;
$this->accountRepo = $repo;
$this->paymentService = $paymentService;
}
public function fire()
{
$this->info(date('Y-m-d').' ChargeRenewalInvoices...');
$account = $this->accountRepo->getNinjaAccount();
$invoices = Invoice::whereAccountId($account->id)
->whereDueDate(date('Y-m-d'))
->with('client')
->orderBy('id')
->get();
$this->info(count($invoices).' invoices found');
foreach ($invoices as $invoice) {
$this->info("Charging invoice {$invoice->invoice_number}");
$this->paymentService->autoBillInvoice($invoice);
}
$this->info('Done');
}
protected function getArguments()
{
return array(
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
}
protected function getOptions()
{
return array(
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
}
}

View File

@ -47,7 +47,7 @@ class SendRenewalInvoices extends Command
}
$client = $this->accountRepo->getNinjaClient($account);
$invitation = $this->accountRepo->createNinjaInvoice($client);
$invitation = $this->accountRepo->createNinjaInvoice($client, $account);
// set the due date to 10 days from now
$invoice = $invitation->invoice;

View File

@ -16,6 +16,7 @@ class Kernel extends ConsoleKernel
'App\Console\Commands\ResetData',
'App\Console\Commands\CheckData',
'App\Console\Commands\SendRenewalInvoices',
'App\Console\Commands\ChargeRenewalInvoices',
'App\Console\Commands\SendReminders',
'App\Console\Commands\TestOFX',
'App\Console\Commands\GenerateResources',

View File

@ -47,13 +47,16 @@ class Handler extends ExceptionHandler {
if ($e instanceof ModelNotFoundException) {
return Redirect::to('/');
} elseif ($e instanceof \Illuminate\Session\TokenMismatchException) {
// https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
return redirect()
->back()
->withInput($request->except('password', '_token'))
->with([
'warning' => trans('texts.token_expired')
]);
// prevent loop since the page auto-submits
if ($request->path() != 'get_started') {
// https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
return redirect()
->back()
->withInput($request->except('password', '_token'))
->with([
'warning' => trans('texts.token_expired')
]);
}
}
// In production, except for maintenance mode, we'll show a custom error screen

View File

@ -52,7 +52,7 @@ class AccountApiController extends BaseAPIController
// Create a new token only if one does not already exist
$user = Auth::user();
$this->accountRepo->createTokens($user, $request->token_name);
$users = $this->accountRepo->findUsers($user, 'account.account_tokens');
$transformer = new UserAccountTransformer($user->account, $request->serializer, $request->token_name);
$data = $this->createCollection($users, $transformer, 'user_account');
@ -117,4 +117,82 @@ class AccountApiController extends BaseAPIController
return $this->response($account);
}
public function addDeviceToken(Request $request)
{
$account = Auth::user()->account;
//scan if this user has a token already registered (tokens can change, so we need to use the users email as key)
$devices = json_decode($account->devices,TRUE);
for($x=0; $x<count($devices); $x++)
{
if ($devices[$x]['email'] == Auth::user()->username) {
$devices[$x]['token'] = $request->token; //update
$account->devices = json_encode($devices);
$account->save();
$devices[$x]['account_key'] = $account->account_key;
return $this->response($devices[$x]);
}
}
//User does not have a device, create new record
$newDevice = [
'token' => $request->token,
'email' => $request->email,
'device' => $request->device,
'account_key' => $account->account_key,
'notify_sent' => TRUE,
'notify_viewed' => TRUE,
'notify_approved' => TRUE,
'notify_paid' => TRUE,
];
$devices[] = $newDevice;
$account->devices = json_encode($devices);
$account->save();
return $this->response($newDevice);
}
public function updatePushNotifications(Request $request)
{
$account = Auth::user()->account;
$devices = json_decode($account->devices, TRUE);
if(count($devices) < 1)
return $this->errorResponse(['message'=>'No registered devices.'], 400);
for($x=0; $x<count($devices); $x++)
{
if($devices[$x]['email'] == Auth::user()->username)
{
$newDevice = [
'token' => $devices[$x]['token'],
'email' => $devices[$x]['email'],
'device' => $devices[$x]['device'],
'account_key' => $account->account_key,
'notify_sent' => $request->notify_sent,
'notify_viewed' => $request->notify_viewed,
'notify_approved' => $request->notify_approved,
'notify_paid' => $request->notify_paid,
];
//unset($devices[$x]);
$devices[$x] = $newDevice;
$account->devices = json_encode($devices);
$account->save();
return $this->response($newDevice);
}
}
}
}

View File

@ -15,6 +15,7 @@ use Response;
use Request;
use App\Models\Affiliate;
use App\Models\License;
use App\Models\Invoice;
use App\Models\User;
use App\Models\Account;
use App\Models\Gateway;
@ -40,7 +41,7 @@ class AccountController extends BaseController
public function __construct(AccountRepository $accountRepo, UserMailer $userMailer, ContactMailer $contactMailer, ReferralRepository $referralRepository)
{
parent::__construct();
//parent::__construct();
$this->accountRepo = $accountRepo;
$this->userMailer = $userMailer;
@ -393,6 +394,21 @@ class AccountController extends BaseController
if ($section == ACCOUNT_CUSTOMIZE_DESIGN) {
$data['customDesign'] = ($account->custom_design && !$design) ? $account->custom_design : $design;
// sample invoice to help determine variables
$invoice = Invoice::scope()
->with('client', 'account')
->where('is_quote', '=', false)
->where('is_recurring', '=', false)
->first();
if ($invoice) {
$invoice->hidePrivateFields();
unset($invoice->account);
unset($invoice->invoice_items);
unset($invoice->client->contacts);
$data['sampleInvoice'] = $invoice;
}
}
return View::make("accounts.{$section}", $data);
@ -419,6 +435,7 @@ class AccountController extends BaseController
'send_portal_password' => $account->send_portal_password,
'title' => trans("texts.client_portal"),
'section' => ACCOUNT_CLIENT_PORTAL,
'account' => $account,
];
return View::make("accounts.client_portal", $data);
@ -531,9 +548,11 @@ class AccountController extends BaseController
$account = Auth::user()->account;
$account->client_view_css = $sanitized_css;
$account->enable_portal_password = Input::get('enable_portal_password');
$account->fill_portal_password = Input::get('fill_portal_password');
$account->send_portal_password = Input::get('send_portal_password');
$account->enable_portal_password = !!Input::get('enable_portal_password');
$account->fill_portal_password = !!Input::get('fill_portal_password');
$account->send_portal_password = !!Input::get('send_portal_password');
$account->save();
Session::flash('message', trans('texts.updated_settings'));
@ -674,6 +693,8 @@ class AccountController extends BaseController
$account->custom_invoice_taxes2 = Input::get('custom_invoice_taxes2') ? true : false;
$account->custom_invoice_text_label1 = trim(Input::get('custom_invoice_text_label1'));
$account->custom_invoice_text_label2 = trim(Input::get('custom_invoice_text_label2'));
$account->custom_invoice_item_label1 = trim(Input::get('custom_invoice_item_label1'));
$account->custom_invoice_item_label2 = trim(Input::get('custom_invoice_item_label2'));
$account->invoice_number_counter = Input::get('invoice_number_counter');
$account->quote_number_prefix = Input::get('quote_number_prefix');
@ -682,6 +703,7 @@ class AccountController extends BaseController
$account->invoice_footer = Input::get('invoice_footer');
$account->quote_terms = Input::get('quote_terms');
$account->auto_convert_quote = Input::get('auto_convert_quote');
$account->recurring_invoice_number_prefix = Input::get('recurring_invoice_number_prefix');
if (Input::has('recurring_hour')) {
$account->recurring_hour = Input::get('recurring_hour');

View File

@ -24,7 +24,7 @@ class AccountGatewayController extends BaseController
public function __construct(AccountGatewayService $accountGatewayService)
{
parent::__construct();
//parent::__construct();
$this->accountGatewayService = $accountGatewayService;
}

View File

@ -15,7 +15,7 @@ class ActivityController extends BaseController
public function __construct(ActivityService $activityService)
{
parent::__construct();
//parent::__construct();
$this->activityService = $activityService;
}

View File

@ -30,7 +30,7 @@ class AppController extends BaseController
public function __construct(AccountRepository $accountRepo, Mailer $mailer, EmailService $emailService)
{
parent::__construct();
//parent::__construct();
$this->accountRepo = $accountRepo;
$this->mailer = $mailer;
@ -78,7 +78,7 @@ class AppController extends BaseController
} elseif (!$valid) {
return Redirect::to('/setup')->withInput();
}
if (Utils::isDatabaseSetup() && Account::count() > 0) {
return Redirect::to('/');
}
@ -114,7 +114,7 @@ class AppController extends BaseController
}
Cache::flush();
Artisan::call('optimize', array('--force' => true));
$firstName = trim(Input::get('first_name'));
$lastName = trim(Input::get('last_name'));
$email = trim(strtolower(Input::get('email')));
@ -152,7 +152,7 @@ class AppController extends BaseController
$_ENV['DB_DATABASE'] = $db['type']['database'];
$_ENV['DB_USERNAME'] = $db['type']['username'];
$_ENV['DB_PASSWORD'] = $db['type']['password'];
if ($mail) {
$_ENV['MAIL_DRIVER'] = $mail['driver'];
$_ENV['MAIL_PORT'] = $mail['port'];
@ -184,7 +184,7 @@ class AppController extends BaseController
foreach ($database['connections'][$dbType] as $key => $val) {
Config::set("database.connections.{$dbType}.{$key}", $val);
}
try {
DB::reconnect();
$valid = DB::connection()->getDatabaseName() ? true : false;
@ -206,7 +206,7 @@ class AppController extends BaseController
Config::set('mail.from.address', $email);
Config::set('mail.from.name', $fromName);
$data = [
'text' => 'Test email',
];
@ -243,6 +243,7 @@ class AppController extends BaseController
if (!Utils::isNinjaProd()) {
try {
set_time_limit(60 * 5);
Artisan::call('optimize', array('--force' => true));
Cache::flush();
Session::flush();
Artisan::call('migrate', array('--force' => true));
@ -250,11 +251,14 @@ class AppController extends BaseController
'PaymentLibraries',
'Fonts',
'Banks',
'InvoiceStatus'
'InvoiceStatus',
'Currencies',
'DateFormats',
'InvoiceDesigns',
'PaymentTerms',
] as $seeder) {
Artisan::call('db:seed', array('--force' => true, '--class' => "{$seeder}Seeder"));
}
Artisan::call('optimize', array('--force' => true));
Event::fire(new UserSettingsChanged());
Session::flash('message', trans('texts.processed_updates'));
} catch (Exception $e) {
@ -276,7 +280,7 @@ class AppController extends BaseController
{
$messageId = Input::get('MessageID');
return $this->emailService->markOpened($messageId) ? RESULT_SUCCESS : RESULT_FAILURE;
return RESULT_SUCCESS;
}
@ -288,7 +292,7 @@ class AppController extends BaseController
}
if (Utils::getResllerType() == RESELLER_REVENUE_SHARE) {
$payments = DB::table('accounts')
$data = DB::table('accounts')
->leftJoin('payments', 'payments.account_id', '=', 'accounts.id')
->leftJoin('clients', 'clients.id', '=', 'payments.client_id')
->where('accounts.account_key', '=', NINJA_ACCOUNT_KEY)
@ -300,15 +304,9 @@ class AppController extends BaseController
'payments.amount'
]);
} else {
$payments = DB::table('accounts')
->leftJoin('payments', 'payments.account_id', '=', 'accounts.id')
->leftJoin('clients', 'clients.id', '=', 'payments.client_id')
->where('accounts.account_key', '=', NINJA_ACCOUNT_KEY)
->where('payments.is_deleted', '=', false)
->groupBy('clients.id')
->count();
$data = DB::table('users')->count();
}
return json_encode($payments);
return json_encode($data);
}
}

View File

@ -10,8 +10,6 @@ use App\Events\UserLoggedIn;
use App\Http\Controllers\Controller;
use App\Ninja\Repositories\AccountRepository;
use App\Services\AuthService;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\Registrar;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller {
@ -29,7 +27,6 @@ class AuthController extends Controller {
use AuthenticatesAndRegistersUsers;
protected $loginPath = '/login';
protected $redirectTo = '/dashboard';
protected $authService;
protected $accountRepo;
@ -41,16 +38,38 @@ class AuthController extends Controller {
* @param \Illuminate\Contracts\Auth\Registrar $registrar
* @return void
*/
public function __construct(Guard $auth, Registrar $registrar, AccountRepository $repo, AuthService $authService)
public function __construct(AccountRepository $repo, AuthService $authService)
{
$this->auth = $auth;
$this->registrar = $registrar;
$this->accountRepo = $repo;
$this->authService = $authService;
//$this->middleware('guest', ['except' => 'getLogout']);
}
public function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
public function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
public function authLogin($provider, Request $request)
{
return $this->authService->execute($provider, $request->has('code'));

View File

@ -1,8 +1,6 @@
<?php namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Foundation\Auth\ResetsPasswords;
class PasswordController extends Controller {
@ -29,11 +27,8 @@ class PasswordController extends Controller {
* @param \Illuminate\Contracts\Auth\PasswordBroker $passwords
* @return void
*/
public function __construct(Guard $auth, PasswordBroker $passwords)
public function __construct()
{
$this->auth = $auth;
$this->passwords = $passwords;
$this->middleware('guest');
}

View File

@ -27,7 +27,7 @@ class BankAccountController extends BaseController
public function __construct(BankAccountService $bankAccountService, BankAccountRepository $bankAccountRepo)
{
parent::__construct();
//parent::__construct();
$this->bankAccountService = $bankAccountService;
$this->bankAccountRepo = $bankAccountRepo;
@ -91,7 +91,7 @@ class BankAccountController extends BaseController
$publicId = Input::get('public_id');
$username = trim(Input::get('bank_username'));
$password = trim(Input::get('bank_password'));
if ($publicId) {
$bankAccount = BankAccount::scope($publicId)->firstOrFail();
if ($username != $bankAccount->username) {

View File

@ -1,10 +1,10 @@
<?php namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesCommands;
use Illuminate\Foundation\Bus\DispatchesJobs;
class BaseController extends Controller
{
use DispatchesCommands;
use DispatchesJobs;
/**
* Setup the layout used by the controller.
@ -18,8 +18,10 @@ class BaseController extends Controller
}
}
/*
public function __construct()
{
$this->beforeFilter('csrf', array('on' => array('post', 'delete', 'put')));
}
*/
}

View File

@ -174,7 +174,7 @@ class ClientApiController extends BaseAPIController
if(!$client)
return $this->errorResponse(['message'=>'Client not found.'],400);
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
$data = $this->createItem($client, $transformer, ENTITY_CLIENT);
@ -203,7 +203,7 @@ class ClientApiController extends BaseAPIController
* )
* )
*/
public function destroy($publicId)
{

View File

@ -35,7 +35,7 @@ class ClientController extends BaseController
public function __construct(ClientRepository $clientRepo, ClientService $clientService)
{
parent::__construct();
//parent::__construct();
$this->clientRepo = $clientRepo;
$this->clientService = $clientService;
@ -78,9 +78,9 @@ class ClientController extends BaseController
public function store(CreateClientRequest $request)
{
$client = $this->clientService->save($request->input());
Session::flash('message', trans('texts.created_client'));
return redirect()->to($client->getRoute());
}
@ -109,7 +109,7 @@ class ClientController extends BaseController
['label' => trans('texts.enter_credit'), 'url' => '/credits/create/'.$client->public_id],
['label' => trans('texts.enter_expense'), 'url' => '/expenses/create/0/'.$client->public_id]
);
$data = array(
'actionLinks' => $actionLinks,
'showBreadcrumbs' => false,
@ -132,7 +132,7 @@ class ClientController extends BaseController
*/
public function create()
{
if (Client::scope()->count() > Auth::user()->getMaxNumClients()) {
if (Client::scope()->withTrashed()->count() > Auth::user()->getMaxNumClients()) {
return View::make('error', ['hideHeader' => true, 'error' => "Sorry, you've exceeded the limit of ".Auth::user()->getMaxNumClients()." clients"]);
}
@ -200,9 +200,9 @@ class ClientController extends BaseController
public function update(UpdateClientRequest $request)
{
$client = $this->clientService->save($request->input());
Session::flash('message', trans('texts.updated_client'));
return redirect()->to($client->getRoute());
}

View File

@ -1,11 +1,11 @@
<?php namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesCommands;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
abstract class Controller extends BaseController {
use DispatchesCommands, ValidatesRequests;
use DispatchesJobs, ValidatesRequests;
}

View File

@ -20,7 +20,7 @@ class CreditController extends BaseController
public function __construct(CreditRepository $creditRepo, CreditService $creditService)
{
parent::__construct();
//parent::__construct();
$this->creditRepo = $creditRepo;
$this->creditService = $creditService;
@ -88,9 +88,9 @@ class CreditController extends BaseController
public function store(CreateCreditRequest $request)
{
$credit = $this->creditRepo->save($request->input());
Session::flash('message', trans('texts.created_credit'));
return redirect()->to($credit->client->getRoute());
}

View File

@ -28,7 +28,7 @@ class ExpenseController extends BaseController
public function __construct(ExpenseRepository $expenseRepo, ExpenseService $expenseService)
{
parent::__construct();
//parent::__construct();
$this->expenseRepo = $expenseRepo;
$this->expenseService = $expenseService;

View File

@ -109,8 +109,7 @@ class ExportController extends BaseController
if ($request->input(ENTITY_CLIENT)) {
$data['clients'] = Client::scope()
->with('user', 'contacts', 'country')
->withTrashed()
->where('is_deleted', '=', false)
->withArchived()
->get();
$data['contacts'] = Contact::scope()
@ -126,33 +125,36 @@ class ExportController extends BaseController
if ($request->input(ENTITY_TASK)) {
$data['tasks'] = Task::scope()
->with('user', 'client.contacts')
->withTrashed()
->where('is_deleted', '=', false)
->withArchived()
->get();
}
if ($request->input(ENTITY_INVOICE)) {
$data['invoices'] = Invoice::scope()
->with('user', 'client.contacts', 'invoice_status')
->withTrashed()
->where('is_deleted', '=', false)
->withArchived()
->where('is_quote', '=', false)
->where('is_recurring', '=', false)
->get();
$data['quotes'] = Invoice::scope()
->with('user', 'client.contacts', 'invoice_status')
->withTrashed()
->where('is_deleted', '=', false)
->withArchived()
->where('is_quote', '=', true)
->where('is_recurring', '=', false)
->get();
$data['recurringInvoices'] = Invoice::scope()
->with('user', 'client.contacts', 'invoice_status', 'frequency')
->withArchived()
->where('is_quote', '=', false)
->where('is_recurring', '=', true)
->get();
}
if ($request->input(ENTITY_PAYMENT)) {
$data['payments'] = Payment::scope()
->withTrashed()
->where('is_deleted', '=', false)
->withArchived()
->with('user', 'client.contacts', 'payment_type', 'invoice', 'account_gateway.gateway')
->get();
}
@ -161,14 +163,14 @@ class ExportController extends BaseController
if ($request->input(ENTITY_VENDOR)) {
$data['clients'] = Vendor::scope()
->with('user', 'vendorcontacts', 'country')
->withTrashed()
->where('is_deleted', '=', false)
->withArchived()
->get();
$data['vendor_contacts'] = VendorContact::scope()
->with('user', 'vendor.contacts')
->withTrashed()
->get();
/*
$data['expenses'] = Credit::scope()
->with('user', 'client.contacts')

View File

@ -17,7 +17,7 @@ class HomeController extends BaseController
public function __construct(Mailer $mailer)
{
parent::__construct();
//parent::__construct();
$this->mailer = $mailer;
}

View File

@ -13,7 +13,7 @@ class ImportController extends BaseController
{
public function __construct(ImportService $importService)
{
parent::__construct();
//parent::__construct();
$this->importService = $importService;
}

View File

@ -149,7 +149,7 @@ class InvoiceApiController extends BaseAPIController
$client = Client::scope()->whereHas('contacts', function($query) use ($email) {
$query->where('email', '=', $email);
})->first();
if (!$client) {
$validator = Validator::make(['email'=>$email], ['email' => 'email']);
if ($validator->fails()) {
@ -220,7 +220,7 @@ class InvoiceApiController extends BaseAPIController
{
$account = Auth::user()->account;
$account->loadLocalizationSettings($client);
// set defaults for optional fields
$fields = [
'discount' => 0,

View File

@ -37,7 +37,7 @@ class InvoiceController extends BaseController
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService, RecurringInvoiceService $recurringInvoiceService)
{
parent::__construct();
//parent::__construct();
$this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo;

View File

@ -32,7 +32,7 @@ class PaymentController extends BaseController
{
public function __construct(PaymentRepository $paymentRepo, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo, ContactMailer $contactMailer, PaymentService $paymentService)
{
parent::__construct();
//parent::__construct();
$this->paymentRepo = $paymentRepo;
$this->invoiceRepo = $invoiceRepo;

View File

@ -22,8 +22,8 @@ class PaymentTermController extends BaseController
public function __construct(PaymentTermService $paymentTermService)
{
parent::__construct();
//parent::__construct();
$this->paymentTermService = $paymentTermService;
}
@ -99,5 +99,5 @@ class PaymentTermController extends BaseController
return Redirect::to('settings/' . ACCOUNT_PAYMENT_TERMS);
}
}

View File

@ -21,7 +21,7 @@ class ProductController extends BaseController
public function __construct(ProductService $productService)
{
parent::__construct();
//parent::__construct();
$this->productService = $productService;
}

View File

@ -34,10 +34,7 @@ class PublicClientController extends BaseController
public function view($invitationKey)
{
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
return response()->view('error', [
'error' => trans('texts.invoice_not_found'),
'hideHeader' => true,
]);
return $this->returnError();
}
$invoice = $invitation->invoice;
@ -118,6 +115,7 @@ class PublicClientController extends BaseController
'showBreadcrumbs' => false,
'hideLogo' => $account->isWhiteLabel(),
'hideHeader' => $account->isNinjaAccount(),
'hideDashboard' => !$account->enable_client_portal,
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
'invoice' => $invoice->hidePrivateFields(),
@ -188,11 +186,16 @@ class PublicClientController extends BaseController
if (!$invitation = $this->getInvitation()) {
return $this->returnError();
}
$account = $invitation->account;
$invoice = $invitation->invoice;
$client = $invoice->client;
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
if (!$account->enable_client_portal) {
return $this->returnError();
}
$data = [
'color' => $color,
'account' => $account,
@ -244,6 +247,7 @@ class PublicClientController extends BaseController
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'hideDashboard' => !$account->enable_client_portal,
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
'title' => trans('texts.invoices'),
@ -275,6 +279,7 @@ class PublicClientController extends BaseController
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'hideDashboard' => !$account->enable_client_portal,
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
'entityType' => ENTITY_PAYMENT,
@ -312,6 +317,7 @@ class PublicClientController extends BaseController
$data = [
'color' => $color,
'hideLogo' => $account->isWhiteLabel(),
'hideDashboard' => !$account->enable_client_portal,
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
'title' => trans('texts.quotes'),
@ -332,13 +338,11 @@ class PublicClientController extends BaseController
return $this->invoiceRepo->getClientDatatable($invitation->contact_id, ENTITY_QUOTE, Input::get('sSearch'));
}
private function returnError()
private function returnError($error = false)
{
return response()->view('error', [
'error' => trans('texts.invoice_not_found'),
'error' => $error ?: trans('texts.invoice_not_found'),
'hideHeader' => true,
'clientViewCSS' => $account->clientViewCSS(),
'clientFontUrl' => $account->getFontsUrl(),
]);
}

View File

@ -52,7 +52,7 @@ class QuoteApiController extends BaseAPIController
}
$invoices = $invoices->orderBy('created_at', 'desc')->paginate();
$transformer = new QuoteTransformer(\Auth::user()->account, Input::get('serializer'));
$paginator = $paginator->paginate();

View File

@ -36,7 +36,7 @@ class QuoteController extends BaseController
public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService)
{
parent::__construct();
//parent::__construct();
$this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo;
@ -99,7 +99,7 @@ class QuoteController extends BaseController
'title' => trans('texts.new_quote'),
];
$data = array_merge($data, self::getViewModel());
return View::make('invoices.edit', $data);
}
@ -136,7 +136,7 @@ class QuoteController extends BaseController
Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/'.$clone->public_id);
}
$count = $this->invoiceService->bulk($ids, $action);
if ($count > 0) {

View File

@ -9,7 +9,7 @@ class RecurringInvoiceController extends BaseController
public function __construct(InvoiceRepository $invoiceRepo)
{
parent::__construct();
//parent::__construct();
$this->invoiceRepo = $invoiceRepo;
}
@ -29,7 +29,7 @@ class RecurringInvoiceController extends BaseController
'action'
])
];
return response()->view('list', $data);
}

View File

@ -10,6 +10,9 @@ use DatePeriod;
use Session;
use View;
use App\Models\Account;
use App\Models\Client;
use App\Models\Payment;
use App\Models\Expense;
class ReportController extends BaseController
{
@ -47,6 +50,7 @@ class ReportController extends BaseController
$groupBy = Input::get('group_by');
$chartType = Input::get('chart_type');
$reportType = Input::get('report_type');
$dateField = Input::get('date_field');
$startDate = Utils::toSqlDate(Input::get('start_date'), false);
$endDate = Utils::toSqlDate(Input::get('end_date'), false);
$enableReport = Input::get('enable_report') ? true : false;
@ -55,6 +59,7 @@ class ReportController extends BaseController
$groupBy = 'MONTH';
$chartType = 'Bar';
$reportType = ENTITY_INVOICE;
$dateField = FILTER_INVOICE_DATE;
$startDate = Utils::today(false)->modify('-3 month');
$endDate = Utils::today(false);
$enableReport = true;
@ -76,6 +81,8 @@ class ReportController extends BaseController
ENTITY_CLIENT => trans('texts.client'),
ENTITY_INVOICE => trans('texts.invoice'),
ENTITY_PAYMENT => trans('texts.payment'),
ENTITY_EXPENSE => trans('texts.expenses'),
ENTITY_TAX_RATE => trans('texts.taxes'),
];
$params = [
@ -94,10 +101,11 @@ class ReportController extends BaseController
if (Auth::user()->account->isPro()) {
if ($enableReport) {
$params = array_merge($params, self::generateReport($reportType, $groupBy, $startDate, $endDate));
$isExport = $action == 'export';
$params = array_merge($params, self::generateReport($reportType, $startDate, $endDate, $dateField, $isExport));
if ($action == 'export') {
self::export($params['exportData'], $params['reportTotals']);
if ($isExport) {
self::export($params['displayData'], $params['columns'], $params['reportTotals']);
}
}
if ($enableChart) {
@ -106,11 +114,7 @@ class ReportController extends BaseController
} else {
$params['columns'] = [];
$params['displayData'] = [];
$params['reportTotals'] = [
'amount' => [],
'balance' => [],
'paid' => [],
];
$params['reportTotals'] = [];
$params['labels'] = [];
$params['datasets'] = [];
$params['scaleStepWidth'] = 100;
@ -212,165 +216,314 @@ class ReportController extends BaseController
];
}
private function generateReport($reportType, $groupBy, $startDate, $endDate)
private function generateReport($reportType, $startDate, $endDate, $dateField, $isExport)
{
if ($reportType == ENTITY_CLIENT) {
$columns = ['client', 'amount', 'paid', 'balance'];
return $this->generateClientReport($startDate, $endDate, $isExport);
} elseif ($reportType == ENTITY_INVOICE) {
$columns = ['client', 'invoice_number', 'invoice_date', 'amount', 'paid', 'balance'];
} else {
$columns = ['client', 'invoice_number', 'invoice_date', 'amount', 'payment_date', 'paid', 'method'];
return $this->generateInvoiceReport($startDate, $endDate, $isExport);
} elseif ($reportType == ENTITY_PAYMENT) {
return $this->generatePaymentReport($startDate, $endDate, $isExport);
} elseif ($reportType == ENTITY_TAX_RATE) {
return $this->generateTaxRateReport($startDate, $endDate, $dateField, $isExport);
} elseif ($reportType == ENTITY_EXPENSE) {
return $this->generateExpenseReport($startDate, $endDate, $isExport);
}
}
$query = DB::table('invoices')
->join('accounts', 'accounts.id', '=', 'invoices.account_id')
->join('clients', 'clients.id', '=', 'invoices.client_id')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('invoices.account_id', '=', Auth::user()->account_id)
->where('invoices.is_deleted', '=', false)
->where('clients.is_deleted', '=', false)
->where('contacts.deleted_at', '=', null)
->where('invoices.invoice_date', '>=', $startDate->format('Y-m-d'))
->where('invoices.invoice_date', '<=', $endDate->format('Y-m-d'))
->where('invoices.is_quote', '=', false)
->where('invoices.is_recurring', '=', false)
->where('contacts.is_primary', '=', true);
private function generateTaxRateReport($startDate, $endDate, $dateField, $isExport)
{
$columns = ['tax_name', 'tax_rate', 'amount', 'paid'];
$select = [
DB::raw('COALESCE(clients.currency_id, accounts.currency_id) currency_id'),
'accounts.country_id',
'contacts.first_name',
'contacts.last_name',
'contacts.email',
'clients.name as client_name',
'clients.public_id as client_public_id',
'invoices.public_id as invoice_public_id'
];
if ($reportType == ENTITY_CLIENT) {
$query->groupBy('clients.id');
array_push($select, DB::raw('sum(invoices.amount) amount'), DB::raw('sum(invoices.balance) balance'), DB::raw('sum(invoices.amount - invoices.balance) paid'));
} else {
$query->orderBy('invoices.id');
array_push($select, 'invoices.invoice_number', 'invoices.amount', 'invoices.balance', 'invoices.invoice_date');
if ($reportType == ENTITY_INVOICE) {
array_push($select, DB::raw('(invoices.amount - invoices.balance) paid'));
} else {
$query->join('payments', 'payments.invoice_id', '=', 'invoices.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');
array_push($select, 'payments.payment_date', 'payments.amount as paid', 'payment_types.name as payment_type', 'gateways.name as gateway');
}
}
$query->select($select);
$data = $query->get();
$lastInvoiceId = null;
$sameAsLast = false;
$account = Auth::user()->account;
$displayData = [];
$reportTotals = [];
$exportData = [];
$reportTotals = [
'amount' => [],
'balance' => [],
'paid' => [],
];
$clients = Client::scope()
->withArchived()
->with('contacts')
->with(['invoices' => function($query) use ($startDate, $endDate, $dateField) {
$query->withArchived();
if ($dateField == FILTER_PAYMENT_DATE) {
$query->where('invoice_date', '>=', $startDate)
->where('invoice_date', '<=', $endDate)
->whereHas('payments', function($query) use ($startDate, $endDate) {
$query->where('payment_date', '>=', $startDate)
->where('payment_date', '<=', $endDate)
->withArchived();
})
->with(['payments' => function($query) use ($startDate, $endDate) {
$query->where('payment_date', '>=', $startDate)
->where('payment_date', '<=', $endDate)
->withArchived()
->with('payment_type', 'account_gateway.gateway');
}, 'invoice_items']);
}
}]);
foreach ($data as $record) {
$sameAsLast = ($lastInvoiceId == $record->invoice_public_id);
$lastInvoiceId = $record->invoice_public_id;
foreach ($clients->get() as $client) {
$currencyId = $client->currency_id ?: Auth::user()->account->getCurrencyId();
$amount = 0;
$paid = 0;
$taxTotals = [];
$displayRow = [];
if ($sameAsLast) {
array_push($displayRow, '', '', '', '');
} else {
array_push($displayRow, link_to('/clients/'.$record->client_public_id, Utils::getClientDisplayName($record)));
if ($reportType != ENTITY_CLIENT) {
array_push($displayRow,
link_to('/invoices/'.$record->invoice_public_id, $record->invoice_number),
Utils::fromSqlDate($record->invoice_date, true)
);
foreach ($client->invoices as $invoice) {
foreach ($invoice->getTaxes(true) as $key => $tax) {
if ( ! isset($taxTotals[$currencyId])) {
$taxTotals[$currencyId] = [];
}
if (isset($taxTotals[$currencyId][$key])) {
$taxTotals[$currencyId][$key]['amount'] += $tax['amount'];
$taxTotals[$currencyId][$key]['paid'] += $tax['paid'];
} else {
$taxTotals[$currencyId][$key] = $tax;
}
}
array_push($displayRow, Utils::formatMoney($record->amount, $record->currency_id, $record->country_id));
}
if ($reportType != ENTITY_PAYMENT) {
array_push($displayRow, Utils::formatMoney($record->paid, $record->currency_id, $record->country_id));
}
if ($reportType == ENTITY_PAYMENT) {
array_push($displayRow,
Utils::fromSqlDate($record->payment_date, true),
Utils::formatMoney($record->paid, $record->currency_id, $record->country_id),
$record->gateway ?: $record->payment_type
);
} else {
array_push($displayRow, Utils::formatMoney($record->balance, $record->currency_id, $record->country_id));
$amount += $invoice->amount;
$paid += $invoice->getAmountPaid();
}
// export data
$exportRow = [];
if ($sameAsLast) {
$exportRow[trans('texts.client')] = ' ';
$exportRow[trans('texts.invoice_number')] = ' ';
$exportRow[trans('texts.invoice_date')] = ' ';
$exportRow[trans('texts.amount')] = ' ';
} else {
$exportRow[trans('texts.client')] = Utils::getClientDisplayName($record);
if ($reportType != ENTITY_CLIENT) {
$exportRow[trans('texts.invoice_number')] = $record->invoice_number;
$exportRow[trans('texts.invoice_date')] = Utils::fromSqlDate($record->invoice_date, true);
foreach ($taxTotals as $currencyId => $taxes) {
foreach ($taxes as $tax) {
$displayData[] = [
$tax['name'],
$tax['rate'] . '%',
$account->formatMoney($tax['amount'], $client),
$account->formatMoney($tax['paid'], $client)
];
}
$exportRow[trans('texts.amount')] = Utils::formatMoney($record->amount, $record->currency_id, $record->country_id);
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'amount', $tax['amount']);
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'paid', $tax['paid']);
}
if ($reportType != ENTITY_PAYMENT) {
$exportRow[trans('texts.paid')] = Utils::formatMoney($record->paid, $record->currency_id, $record->country_id);
}
if ($reportType == ENTITY_PAYMENT) {
$exportRow[trans('texts.payment_date')] = Utils::fromSqlDate($record->payment_date, true);
$exportRow[trans('texts.payment_amount')] = Utils::formatMoney($record->paid, $record->currency_id, $record->country_id);
$exportRow[trans('texts.method')] = $record->gateway ?: $record->payment_type;
} else {
$exportRow[trans('texts.balance')] = Utils::formatMoney($record->balance, $record->currency_id, $record->country_id);
}
$displayData[] = $displayRow;
$exportData[] = $exportRow;
$accountCurrencyId = Auth::user()->account->currency_id;
$currencyId = $record->currency_id ? $record->currency_id : ($accountCurrencyId ? $accountCurrencyId : DEFAULT_CURRENCY);
if (!isset($reportTotals['amount'][$currencyId])) {
$reportTotals['amount'][$currencyId] = 0;
$reportTotals['balance'][$currencyId] = 0;
$reportTotals['paid'][$currencyId] = 0;
}
if (!$sameAsLast) {
$reportTotals['amount'][$currencyId] += $record->amount;
$reportTotals['balance'][$currencyId] += $record->balance;
}
$reportTotals['paid'][$currencyId] += $record->paid;
}
return [
'columns' => $columns,
'displayData' => $displayData,
'reportTotals' => $reportTotals,
'exportData' => $exportData
];
}
private function generatePaymentReport($startDate, $endDate, $isExport)
{
$columns = ['client', 'invoice_number', 'invoice_date', 'amount', 'payment_date', 'paid', 'method'];
$account = Auth::user()->account;
$displayData = [];
$reportTotals = [];
$payments = Payment::scope()
->withTrashed()
->where('is_deleted', '=', false)
->whereHas('client', function($query) {
$query->where('is_deleted', '=', false);
})
->whereHas('invoice', function($query) {
$query->where('is_deleted', '=', false);
})
->with('client.contacts', 'invoice', 'payment_type', 'account_gateway.gateway')
->where('payment_date', '>=', $startDate)
->where('payment_date', '<=', $endDate);
foreach ($payments->get() as $payment) {
$invoice = $payment->invoice;
$client = $payment->client;
$displayData[] = [
$isExport ? $client->getDisplayName() : $client->present()->link,
$isExport ? $invoice->invoice_number : $invoice->present()->link,
$invoice->present()->invoice_date,
$account->formatMoney($invoice->amount, $client),
$payment->present()->payment_date,
$account->formatMoney($payment->amount, $client),
$payment->present()->method,
];
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'amount', $invoice->amount);
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'paid', $payment->amount);
}
return [
'columns' => $columns,
'displayData' => $displayData,
'reportTotals' => $reportTotals,
];
}
private function export($data, $totals)
private function generateInvoiceReport($startDate, $endDate, $isExport)
{
$columns = ['client', 'invoice_number', 'invoice_date', 'amount', 'paid', 'balance'];
$account = Auth::user()->account;
$displayData = [];
$reportTotals = [];
$clients = Client::scope()
->withTrashed()
->with('contacts')
->where('is_deleted', '=', false)
->with(['invoices' => function($query) use ($startDate, $endDate) {
$query->where('invoice_date', '>=', $startDate)
->where('invoice_date', '<=', $endDate)
->where('is_deleted', '=', false)
->where('is_quote', '=', false)
->where('is_recurring', '=', false)
->with(['payments' => function($query) {
$query->withTrashed()
->with('payment_type', 'account_gateway.gateway')
->where('is_deleted', '=', false);
}, 'invoice_items'])
->withTrashed();
}]);
foreach ($clients->get() as $client) {
$currencyId = $client->currency_id ?: Auth::user()->account->getCurrencyId();
foreach ($client->invoices as $invoice) {
$displayData[] = [
$isExport ? $client->getDisplayName() : $client->present()->link,
$isExport ? $invoice->invoice_number : $invoice->present()->link,
$invoice->present()->invoice_date,
$account->formatMoney($invoice->amount, $client),
$account->formatMoney($invoice->getAmountPaid(), $client),
$account->formatMoney($invoice->balance, $client),
];
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'amount', $invoice->amount);
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'paid', $invoice->getAmountPaid());
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'balance', $invoice->balance);
}
}
return [
'columns' => $columns,
'displayData' => $displayData,
'reportTotals' => $reportTotals,
];
}
private function generateClientReport($startDate, $endDate, $isExport)
{
$columns = ['client', 'amount', 'paid', 'balance'];
$account = Auth::user()->account;
$displayData = [];
$reportTotals = [];
$clients = Client::scope()
->withArchived()
->with('contacts')
->with(['invoices' => function($query) use ($startDate, $endDate) {
$query->where('invoice_date', '>=', $startDate)
->where('invoice_date', '<=', $endDate)
->where('is_quote', '=', false)
->where('is_recurring', '=', false)
->withArchived();
}]);
foreach ($clients->get() as $client) {
$amount = 0;
$paid = 0;
foreach ($client->invoices as $invoice) {
$amount += $invoice->amount;
$paid += $invoice->getAmountPaid();
}
$displayData[] = [
$isExport ? $client->getDisplayName() : $client->present()->link,
$account->formatMoney($amount, $client),
$account->formatMoney($paid, $client),
$account->formatMoney($amount - $paid, $client)
];
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'amount', $amount);
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'paid', $paid);
$reportTotals = $this->addToTotals($reportTotals, $client->currency_id, 'balance', $amount - $paid);
}
return [
'columns' => $columns,
'displayData' => $displayData,
'reportTotals' => $reportTotals,
];
}
private function generateExpenseReport($startDate, $endDate, $isExport)
{
$columns = ['vendor', 'client', 'date', 'expense_amount', 'invoiced_amount'];
$account = Auth::user()->account;
$displayData = [];
$reportTotals = [];
$expenses = Expense::scope()
->withTrashed()
->with('client.contacts', 'vendor')
->where('expense_date', '>=', $startDate)
->where('expense_date', '<=', $endDate);
foreach ($expenses->get() as $expense) {
$amount = $expense->amount;
$invoiced = $expense->present()->invoiced_amount;
$displayData[] = [
$expense->vendor ? ($isExport ? $expense->vendor->name : $expense->vendor->present()->link) : '',
$expense->client ? ($isExport ? $expense->client->getDisplayName() : $expense->client->present()->link) : '',
$expense->present()->expense_date,
Utils::formatMoney($amount, $expense->currency_id),
Utils::formatMoney($invoiced, $expense->invoice_currency_id),
];
$reportTotals = $this->addToTotals($reportTotals, $expense->expense_currency_id, 'amount', $amount);
$reportTotals = $this->addToTotals($reportTotals, $expense->invoice_currency_id, 'amount', 0);
$reportTotals = $this->addToTotals($reportTotals, $expense->invoice_currency_id, 'invoiced', $invoiced);
$reportTotals = $this->addToTotals($reportTotals, $expense->expense_currency_id, 'invoiced', 0);
}
return [
'columns' => $columns,
'displayData' => $displayData,
'reportTotals' => $reportTotals,
];
}
private function addToTotals($data, $currencyId, $field, $value) {
$currencyId = $currencyId ?: Auth::user()->account->getCurrencyId();
if (!isset($data[$currencyId][$field])) {
$data[$currencyId][$field] = 0;
}
$data[$currencyId][$field] += $value;
return $data;
}
private function export($data, $columns, $totals)
{
$output = fopen('php://output', 'w') or Utils::fatalError();
header('Content-Type:application/csv');
header('Content-Disposition:attachment;filename=ninja-report.csv');
Utils::exportData($output, $data);
Utils::exportData($output, $data, Utils::trans($columns));
fwrite($output, trans('texts.totals'));
foreach ($totals as $currencyId => $fields) {
foreach ($fields as $key => $value) {
fwrite($output, ',' . trans("texts.{$key}"));
}
fwrite($output, "\n");
break;
}
foreach (['amount', 'paid', 'balance'] as $type) {
$csv = trans("texts.{$type}").',';
foreach ($totals[$type] as $currencyId => $amount) {
$csv .= Utils::formatMoney($amount, $currencyId).',';
foreach ($totals as $currencyId => $fields) {
$csv = Utils::getFromCache($currencyId, 'currencies')->name . ',';
foreach ($fields as $key => $value) {
$csv .= '"' . Utils::formatMoney($value, $currencyId).'",';
}
fwrite($output, $csv."\n");
}

View File

@ -49,7 +49,7 @@ class TaskApiController extends BaseAPIController
$tasks->whereHas('client', $filter);
$paginator->whereHas('client', $filter);
}
$tasks = $tasks->orderBy('created_at', 'desc')->paginate();
$paginator = $paginator->paginate();
$transformer = new TaskTransformer(\Auth::user()->account, Input::get('serializer'));
@ -84,11 +84,11 @@ class TaskApiController extends BaseAPIController
{
$data = Input::all();
$taskId = isset($data['id']) ? $data['id'] : false;
if (isset($data['client_id']) && $data['client_id']) {
$data['client'] = $data['client_id'];
}
$task = $this->taskRepo->save($taskId, $data);
$task = Task::scope($task->public_id)->with('client')->first();

View File

@ -25,7 +25,7 @@ class TaskController extends BaseController
public function __construct(TaskRepository $taskRepo, InvoiceRepository $invoiceRepo, TaskService $taskService)
{
parent::__construct();
//parent::__construct();
$this->taskRepo = $taskRepo;
$this->invoiceRepo = $invoiceRepo;

View File

@ -25,7 +25,7 @@ class TaxRateController extends BaseController
public function __construct(TaxRateService $taxRateService, TaxRateRepository $taxRateRepo)
{
parent::__construct();
//parent::__construct();
$this->taxRateService = $taxRateService;
$this->taxRateRepo = $taxRateRepo;
@ -76,9 +76,9 @@ class TaxRateController extends BaseController
public function update(UpdateTaxRateRequest $request, $publicId)
{
$taxRate = TaxRate::scope($publicId)->firstOrFail();
$this->taxRateRepo->save($request->input(), $taxRate);
Session::flash('message', trans('texts.updated_tax_rate'));
return Redirect::to('settings/' . ACCOUNT_TAX_RATES);
}

View File

@ -20,7 +20,7 @@ class TokenController extends BaseController
public function __construct(TokenService $tokenService)
{
parent::__construct();
//parent::__construct();
$this->tokenService = $tokenService;
}

View File

@ -42,7 +42,7 @@ class UserApiController extends BaseAPIController
return $this->save($request);
}
*/
public function update(UpdateUserRequest $request, $userPublicId)
{
/*

View File

@ -30,7 +30,7 @@ class UserController extends BaseController
public function __construct(AccountRepository $accountRepo, ContactMailer $contactMailer, UserMailer $userMailer, UserService $userService)
{
parent::__construct();
//parent::__construct();
$this->accountRepo = $accountRepo;
$this->contactMailer = $contactMailer;
@ -130,7 +130,7 @@ class UserController extends BaseController
{
$action = Input::get('bulk_action');
$id = Input::get('bulk_public_id');
$user = User::where('account_id', '=', Auth::user()->account_id)
->where('public_id', '=', $id)
->withTrashed()
@ -219,7 +219,7 @@ class UserController extends BaseController
Session::flash('message', $message);
}
return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT);
}
@ -243,7 +243,7 @@ class UserController extends BaseController
public function confirm($code, TokenRepositoryInterface $tokenRepo)
{
$user = User::where('confirmation_code', '=', $code)->get()->first();
if ($user) {
$notice_msg = trans('texts.security.confirmation');
@ -294,7 +294,7 @@ class UserController extends BaseController
return Redirect::to('/')->with('clearGuestKey', true);
}
*/
public function changePassword()
{
// check the current password is correct
@ -326,7 +326,7 @@ class UserController extends BaseController
$oldUserId = Auth::user()->id;
$referer = Request::header('referer');
$account = $this->accountRepo->findUserAccounts($newUserId, $oldUserId);
if ($account) {
if ($account->hasUserId($newUserId) && $account->hasUserId($oldUserId)) {
Auth::loginUsingId($newUserId);
@ -337,7 +337,7 @@ class UserController extends BaseController
Session::put('_token', str_random(40));
}
}
return Redirect::to($referer);
}

View File

@ -83,7 +83,7 @@ class VendorApiController extends BaseAPIController
public function store(CreateVendorRequest $request)
{
$vendor = $this->vendorRepo->save($request->input());
$vendor = Vendor::scope($vendor->public_id)
->with('country', 'vendorcontacts', 'industry', 'size', 'currency')
->first();

View File

@ -33,7 +33,7 @@ class VendorController extends BaseController
public function __construct(VendorRepository $vendorRepo, VendorService $vendorService)
{
parent::__construct();
//parent::__construct();
$this->vendorRepo = $vendorRepo;
$this->vendorService = $vendorService;

View File

@ -48,6 +48,9 @@ class StartupCheck
$file = storage_path() . '/version.txt';
$version = @file_get_contents($file);
if ($version != NINJA_VERSION) {
if (version_compare(phpversion(), '5.5.9', '<')) {
dd('Please update PHP to >= 5.5.9');
}
$handle = fopen($file, 'w');
fwrite($handle, NINJA_VERSION);
fclose($handle);

View File

@ -67,16 +67,16 @@ Route::post('/hook/email_bounced', 'AppController@emailBounced');
Route::post('/hook/email_opened', 'AppController@emailOpened');
// Laravel auth routes
get('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@getRegister'));
post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@postRegister'));
get('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@getLoginWrapper'));
post('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@postLoginWrapper'));
get('/logout', array('as' => 'logout', 'uses' => 'Auth\AuthController@getLogoutWrapper'));
get('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail'));
post('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail'));
get('/password/reset/{token}', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset'));
post('/password/reset', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postReset'));
get('/user/confirm/{code}', 'UserController@confirm');
Route::get('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@getRegister'));
Route::post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@postRegister'));
Route::get('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@getLoginWrapper'));
Route::post('/login', array('as' => 'login', 'uses' => 'Auth\AuthController@postLoginWrapper'));
Route::get('/logout', array('as' => 'logout', 'uses' => 'Auth\AuthController@getLogoutWrapper'));
Route::get('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getEmail'));
Route::post('/forgot', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postEmail'));
Route::get('/password/reset/{token}', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@getReset'));
Route::post('/password/reset', array('as' => 'forgot', 'uses' => 'Auth\PasswordController@postReset'));
Route::get('/user/confirm/{code}', 'UserController@confirm');
if (Utils::isNinja()) {
@ -195,8 +195,8 @@ Route::group(['middleware' => 'auth'], function() {
Route::get('api/credits/{client_id?}', array('as'=>'api.credits', 'uses'=>'CreditController@getDatatable'));
Route::post('credits/bulk', 'CreditController@bulk');
get('/resend_confirmation', 'AccountController@resendConfirmation');
post('/update_setup', 'AppController@updateSetup');
Route::get('/resend_confirmation', 'AccountController@resendConfirmation');
Route::post('/update_setup', 'AppController@updateSetup');
// vendor
@ -236,6 +236,8 @@ Route::group(['middleware' => 'api', 'prefix' => 'api/v1'], function()
Route::resource('tax_rates', 'TaxRateApiController');
Route::resource('users', 'UserApiController');
Route::resource('expenses','ExpenseApiController');
Route::post('add_token', 'AccountApiController@addDeviceToken');
Route::post('update_notifications', 'AccountApiController@updatePushNotifications');
// Vendor
Route::resource('vendors', 'VendorApiController');
@ -529,6 +531,8 @@ if (!defined('CONTACT_EMAIL')) {
define('EMAIL_MARKUP_URL', 'https://developers.google.com/gmail/markup');
define('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all');
define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=');
define('COUNT_FREE_DESIGNS', 4);
define('COUNT_FREE_DESIGNS_SELF_HOST', 5); // include the custom design
define('PRODUCT_ONE_CLICK_INSTALL', 1);
@ -551,6 +555,9 @@ if (!defined('CONTACT_EMAIL')) {
define('TEST_PASSWORD', 'password');
define('API_SECRET', 'API_SECRET');
define('IOS_PRODUCTION_PUSH','ninjaIOS');
define('IOS_DEV_PUSH','devNinjaIOS');
define('TOKEN_BILLING_DISABLED', 1);
define('TOKEN_BILLING_OPT_IN', 2);
define('TOKEN_BILLING_OPT_OUT', 3);
@ -574,6 +581,9 @@ if (!defined('CONTACT_EMAIL')) {
define('REMINDER_FIELD_DUE_DATE', 1);
define('REMINDER_FIELD_INVOICE_DATE', 2);
define('FILTER_INVOICE_DATE', 'invoice_date');
define('FILTER_PAYMENT_DATE', 'payment_date');
define('SOCIAL_GOOGLE', 'Google');
define('SOCIAL_FACEBOOK', 'Facebook');
define('SOCIAL_GITHUB', 'GitHub');
@ -670,8 +680,9 @@ if (Utils::isNinjaDev()) {
*/
/*
if (Utils::isNinjaDev() && Auth::check() && Auth::user()->id === 1)
if (Utils::isNinjaDev())
{
Auth::loginUsingId(1);
//ini_set('memory_limit','1024M');
//Auth::loginUsingId(1);
}
*/

View File

@ -72,7 +72,7 @@ class Utils
public static function requireHTTPS()
{
if (Request::root() === 'http://ninja.dev:8000') {
if (Request::root() === 'http://ninja.dev' || Request::root() === 'http://ninja.dev:8000') {
return false;
}
@ -127,6 +127,13 @@ class Utils
{
return App::getLocale() == 'en';
}
public static function getLocaleRegion()
{
$parts = explode('_', App::getLocale());
return count($parts) ? $parts[0] : 'en';
}
public static function getUserType()
{
@ -767,9 +774,11 @@ class Utils
return $str;
}
public static function exportData($output, $data)
public static function exportData($output, $data, $headers = false)
{
if (count($data) > 0) {
if ($headers) {
fputcsv($output, $headers);
} elseif (count($data) > 0) {
fputcsv($output, array_keys($data[0]));
}

View File

@ -9,16 +9,20 @@ use App\Events\InvoiceInvitationWasViewed;
use App\Events\QuoteInvitationWasViewed;
use App\Events\QuoteInvitationWasApproved;
use App\Events\PaymentWasCreated;
use App\Ninja\Notifications;
use App\Services\PushService;
class NotificationListener
{
protected $userMailer;
protected $contactMailer;
protected $pushService;
public function __construct(UserMailer $userMailer, ContactMailer $contactMailer)
public function __construct(UserMailer $userMailer, ContactMailer $contactMailer, PushService $pushService)
{
$this->userMailer = $userMailer;
$this->contactMailer = $contactMailer;
$this->pushService = $pushService;
}
private function sendEmails($invoice, $type, $payment = null)
@ -35,26 +39,31 @@ class NotificationListener
public function emailedInvoice(InvoiceWasEmailed $event)
{
$this->sendEmails($event->invoice, 'sent');
$this->pushService->sendNotification($event->invoice, 'sent');
}
public function emailedQuote(QuoteWasEmailed $event)
{
$this->sendEmails($event->quote, 'sent');
$this->pushService->sendNotification($event->quote, 'sent');
}
public function viewedInvoice(InvoiceInvitationWasViewed $event)
{
$this->sendEmails($event->invoice, 'viewed');
$this->pushService->sendNotification($event->invoice, 'viewed');
}
public function viewedQuote(QuoteInvitationWasViewed $event)
{
$this->sendEmails($event->quote, 'viewed');
$this->pushService->sendNotification($event->quote, 'viewed');
}
public function approvedQuote(QuoteInvitationWasApproved $event)
{
$this->sendEmails($event->quote, 'approved');
$this->pushService->sendNotification($event->quote, 'approved');
}
public function createdPayment(PaymentWasCreated $event)
@ -66,6 +75,8 @@ class NotificationListener
$this->contactMailer->sendPaymentConfirmation($event->payment);
$this->sendEmails($event->payment->invoice, 'paid', $event->payment);
$this->pushService->sendNotification($event->payment->invoice, 'paid');
}
}

View File

@ -24,29 +24,49 @@ class SubscriptionListener
{
public function createdClient(ClientWasCreated $event)
{
if ( ! Auth::check()) {
return;
}
$transformer = new ClientTransformer(Auth::user()->account);
$this->checkSubscriptions(ACTIVITY_TYPE_CREATE_CLIENT, $event->client, $transformer);
}
public function createdQuote(QuoteWasCreated $event)
{
if ( ! Auth::check()) {
return;
}
$transformer = new InvoiceTransformer(Auth::user()->account);
$this->checkSubscriptions(ACTIVITY_TYPE_CREATE_QUOTE, $event->quote, $transformer, ENTITY_CLIENT);
}
public function createdPayment(PaymentWasCreated $event)
{
if ( ! Auth::check()) {
return;
}
$transformer = new PaymentTransformer(Auth::user()->account);
$this->checkSubscriptions(ACTIVITY_TYPE_CREATE_PAYMENT, $event->payment, $transformer, [ENTITY_CLIENT, ENTITY_INVOICE]);
}
public function createdCredit(CreditWasCreated $event)
{
if ( ! Auth::check()) {
return;
}
//$this->checkSubscriptions(ACTIVITY_TYPE_CREATE_CREDIT, $event->credit);
}
public function createdInvoice(InvoiceWasCreated $event)
{
if ( ! Auth::check()) {
return;
}
$transformer = new InvoiceTransformer(Auth::user()->account);
$this->checkSubscriptions(ACTIVITY_TYPE_CREATE_INVOICE, $event->invoice, $transformer, ENTITY_CLIENT);
}
@ -55,7 +75,7 @@ class SubscriptionListener
{
//$this->checkSubscriptions(ACTIVITY_TYPE_CREATE_VENDOR, $event->vendor);
}
public function createdExpense(ExpenseWasCreated $event)
{
//$this->checkSubscriptions(ACTIVITY_TYPE_CREATE_EXPENSE, $event->expense);
@ -69,10 +89,15 @@ class SubscriptionListener
$manager = new Manager();
$manager->setSerializer(new ArraySerializer());
$manager->parseIncludes($include);
$resource = new Item($entity, $transformer, $entity->getEntityType());
$data = $manager->createData($resource)->toArray();
// For legacy Zapier support
if (isset($data['client_id'])) {
$data['client_name'] = $entity->client->getDisplayName();
}
Utils::notifyZapier($subscription, $data);
}
}

View File

@ -439,7 +439,7 @@ class Account extends Eloquent
return $height;
}
public function createInvoice($entityType, $clientId = null)
public function createInvoice($entityType = ENTITY_INVOICE, $clientId = null)
{
$invoice = Invoice::createNew();

View File

@ -280,6 +280,11 @@ class Client extends EntityModel
return $token ? "https://dashboard.stripe.com/customers/{$token}" : false;
}
public function getAmount()
{
return $this->balance + $this->paid_to_date;
}
public function getCurrencyId()
{
if ($this->currency_id) {

View File

@ -42,7 +42,7 @@ class EntityModel extends Eloquent
{
$className = get_called_class();
return $className::scope($publicId)->withTrashed()->pluck('id');
return $className::scope($publicId)->withTrashed()->value('id');
}
public function getActivityKey()
@ -81,6 +81,11 @@ class EntityModel extends Eloquent
return $query;
}
public function scopeWithArchived($query)
{
return $query->withTrashed()->where('is_deleted', '=', false);
}
public function getName()
{
return $this->public_id;

View File

@ -129,13 +129,21 @@ class Invoice extends EntityModel implements BalanceAffecting
return false;
}
public function getAmountPaid()
public function getAmountPaid($calculate = false)
{
if ($this->is_quote || $this->is_recurring) {
return 0;
}
return ($this->amount - $this->balance);
if ($calculate) {
$amount = 0;
foreach ($this->payments as $payment) {
$amount += $payment->amount;
}
return $amount;
} else {
return ($this->amount - $this->balance);
}
}
public function trashed()
@ -192,6 +200,11 @@ class Invoice extends EntityModel implements BalanceAffecting
return $this->hasMany('App\Models\Invoice', 'recurring_invoice_id');
}
public function frequency()
{
return $this->belongsTo('App\Models\Frequency');
}
public function invitations()
{
return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id');
@ -442,12 +455,16 @@ class Invoice extends EntityModel implements BalanceAffecting
'show_item_taxes',
'custom_invoice_text_label1',
'custom_invoice_text_label2',
'custom_invoice_item_label1',
'custom_invoice_item_label2',
]);
foreach ($this->invoice_items as $invoiceItem) {
$invoiceItem->setVisible([
'product_key',
'notes',
'custom_value1',
'custom_value2',
'cost',
'qty',
'tax_name',
@ -752,6 +769,98 @@ class Invoice extends EntityModel implements BalanceAffecting
return Utils::decodePDF($pdfString);
}
public function getItemTaxable($invoiceItem, $invoiceTotal)
{
$total = $invoiceItem->qty * $invoiceItem->cost;
if ($this->discount > 0) {
if ($this->is_amount_discount) {
$total -= $invoiceTotal ? ($total / $invoiceTotal * $this->discount) : 0;
} else {
$total *= (100 - $this->discount) / 100;
$total = round($total, 2);
}
}
return $total;
}
public function getTaxable()
{
$total = 0;
foreach ($this->invoice_items as $invoiceItem) {
$total += $invoiceItem->qty * $invoiceItem->cost;
}
if ($this->discount > 0) {
if ($this->is_amount_discount) {
$total -= $this->discount;
} else {
$total *= (100 - $this->discount) / 100;
$total = round($total, 2);
}
}
if ($this->custom_value1 && $this->custom_taxes1) {
$total += $this->custom_value1;
}
if ($this->custom_value2 && $this->custom_taxes2) {
$total += $this->custom_value2;
}
return $total;
}
public function getTaxes($calculatePaid = false)
{
$taxes = [];
$taxable = $this->getTaxable();
if ($this->tax_rate && $this->tax_name) {
$taxAmount = $taxable * ($this->tax_rate / 100);
$taxAmount = round($taxAmount, 2);
if ($taxAmount) {
$taxes[$this->tax_name.$this->tax_rate] = [
'name' => $this->tax_name,
'rate' => $this->tax_rate,
'amount' => $taxAmount,
'paid' => round($this->getAmountPaid($calculatePaid) / $this->amount * $taxAmount, 2)
];
}
}
foreach ($this->invoice_items as $invoiceItem) {
if ( ! $invoiceItem->tax_rate || ! $invoiceItem->tax_name) {
continue;
}
$taxAmount = $this->getItemTaxable($invoiceItem, $taxable);
$taxAmount = $taxable * ($invoiceItem->tax_rate / 100);
$taxAmount = round($taxAmount, 2);
if ($taxAmount) {
$key = $invoiceItem->tax_name.$invoiceItem->tax_rate;
if ( ! isset($taxes[$key])) {
$taxes[$key] = [
'amount' => 0,
'paid' => 0
];
}
$taxes[$key]['amount'] += $taxAmount;
$taxes[$key]['paid'] += $this->amount && $taxAmount ? round($this->getAmountPaid($calculatePaid) / $this->amount * $taxAmount, 2) : 0;
$taxes[$key]['name'] = $invoiceItem->tax_name;
$taxes[$key]['rate'] = $invoiceItem->tax_rate;
}
}
return $taxes;
}
}
Invoice::creating(function ($invoice) {

View File

@ -1,6 +1,6 @@
<?php namespace App\Ninja\Mailers;
use HTML;
use Form;
use Utils;
use Event;
use URL;
@ -246,9 +246,9 @@ class ContactMailer extends Mailer
'$quote' => $invoice->invoice_number,
'$link' => $invitation->getLink(),
'$viewLink' => $invitation->getLink(),
'$viewButton' => HTML::emailViewButton($invitation->getLink(), $invoice->getEntityType()),
'$viewButton' => Form::emailViewButton($invitation->getLink(), $invoice->getEntityType()),
'$paymentLink' => $invitation->getLink('payment'),
'$paymentButton' => HTML::emailPaymentButton($invitation->getLink('payment')),
'$paymentButton' => Form::emailPaymentButton($invitation->getLink('payment')),
'$customClient1' => $account->custom_client_label1,
'$customClient2' => $account->custom_client_label2,
'$customInvoice1' => $account->custom_invoice_text_label1,
@ -260,7 +260,7 @@ class ContactMailer extends Mailer
$camelType = Gateway::getPaymentTypeName($type);
$type = Utils::toSnakeCase($camelType);
$variables["\${$camelType}Link"] = $invitation->getLink() . "/{$type}";
$variables["\${$camelType}Button"] = HTML::emailPaymentButton($invitation->getLink('payment') . "/{$type}");
$variables["\${$camelType}Button"] = Form::emailPaymentButton($invitation->getLink('payment') . "/{$type}");
}
$str = str_replace(array_keys($variables), array_values($variables), $template);

View File

@ -0,0 +1,96 @@
<?php
namespace App\Ninja\Notifications;
use Davibennun\LaravelPushNotification\Facades\PushNotification;
use Illuminate\Http\Request;
/**
* Class PushFactory
* @package App\Ninja\Notifications
*/
class PushFactory
{
/**
* PushFactory constructor.
*
* @param $this->certificate - Development or production.
*
* Static variables defined in routes.php
*
* IOS_PRODUCTION_PUSH
* IOS_DEV_PUSH
*/
public function __construct()
{
$this->certificate = IOS_DEV_PUSH;
}
/**
* customMessage function
*
* Send a message with a nested custom payload to perform additional trickery within application
*
* @access public
*
* @param $token
* @param $message
* @param $messageArray
*
* @return void
*/
public function customMessage($token, $message, $messageArray)
{
$customMessage = PushNotification::Message($message, $messageArray);
$this->message($token, $customMessage);
}
/**
* message function
*
* Send a plain text only message to a single device.
*
* @access public
*
* @param $token - device token
* @param $message - user specific message
*
* @return void
*
*/
public function message($token, $message)
{
PushNotification::app($this->certificate)
->to($token)
->send($message);
}
/**
* getFeedback function
*
* Returns an array of expired/invalid tokens to be removed from iOS PUSH notifications.
*
* We need to run this once ~ 24hrs
*
* @access public
*
* @param string $token - A valid token (can be any valid token)
* @param string $message - Nil value for message
*
* @return array
*/
public function getFeedback($token, $message = '')
{
$feedback = PushNotification::app($this->certificate)
->to($token)
->send($message);
return $feedback->getFeedback();
}
}

View File

@ -1,5 +1,6 @@
<?php namespace App\Ninja\Presenters;
use URL;
use Utils;
use Laracasts\Presenter\Presenter;
@ -26,6 +27,15 @@ class ClientPresenter extends Presenter {
}
return "<span class=\"label label-{$class}\">{$text}</span>";
}
public function url()
{
return URL::to('/clients/' . $this->entity->public_id);
}
public function link()
{
return link_to('/clients/' . $this->entity->public_id, $this->entity->getDisplayName());
}
}

View File

@ -20,4 +20,14 @@ class ExpensePresenter extends Presenter {
{
return round($this->entity->amount * $this->entity->exchange_rate, 2);
}
public function invoiced_amount()
{
return $this->entity->invoice_id ? $this->converted_amount() : 0;
}
public function link()
{
return link_to('/expenses/' . $this->entity->public_id, $this->entity->name);
}
}

View File

@ -1,5 +1,6 @@
<?php namespace App\Ninja\Presenters;
use URL;
use Utils;
use Laracasts\Presenter\Presenter;
@ -40,9 +41,15 @@ class InvoicePresenter extends Presenter {
public function status()
{
$status = $this->entity->invoice_status ? $this->entity->invoice_status->name : 'draft';
$status = strtolower($status);
return trans("texts.status_{$status}");
if ($this->entity->is_deleted) {
return trans('texts.deleted');
} elseif ($this->entity->trashed()) {
return trans('texts.archived');
} else {
$status = $this->entity->invoice_status ? $this->entity->invoice_status->name : 'draft';
$status = strtolower($status);
return trans("texts.status_{$status}");
}
}
public function invoice_date()
@ -55,4 +62,24 @@ class InvoicePresenter extends Presenter {
return Utils::fromSqlDate($this->entity->due_date);
}
public function frequency()
{
return $this->entity->frequency ? $this->entity->frequency->name : '';
}
public function url()
{
return URL::to('/invoices/' . $this->entity->public_id);
}
public function link()
{
return link_to('/invoices/' . $this->entity->public_id, $this->entity->invoice_number);
}
public function email()
{
$client = $this->entity->client;
return count($client->contacts) ? $client->contacts[0]->email : '';
}
}

View File

@ -9,4 +9,9 @@ class VendorPresenter extends Presenter {
{
return $this->entity->country ? $this->entity->country->name : '';
}
public function link()
{
return link_to('/vendors/' . $this->entity->public_id, $this->entity->name);
}
}

View File

@ -5,6 +5,7 @@ use Request;
use Session;
use Utils;
use DB;
use URL;
use stdClass;
use Validator;
use Schema;
@ -71,47 +72,104 @@ class AccountRepository
public function getSearchData()
{
$clients = \DB::table('clients')
->where('clients.deleted_at', '=', null)
->where('clients.account_id', '=', \Auth::user()->account_id)
->whereRaw("clients.name <> ''")
->select(\DB::raw("'clients' as type, '" . trans('texts.clients') . "' as trans_type, clients.public_id, clients.name, '' as token"));
$data = $this->getAccountSearchData();
$contacts = \DB::table('clients')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('clients.deleted_at', '=', null)
->where('clients.account_id', '=', \Auth::user()->account_id)
->whereRaw("CONCAT(contacts.first_name, contacts.last_name, contacts.email) <> ''")
->select(\DB::raw("'clients' as type, '" . trans('texts.contacts') . "' as trans_type, clients.public_id, CONCAT(contacts.first_name, ' ', contacts.last_name, ' ', contacts.email) as name, '' as token"));
$data['navigation'] = $this->getNavigationSearchData();
$invoices = \DB::table('clients')
->join('invoices', 'invoices.client_id', '=', 'clients.id')
->where('clients.account_id', '=', \Auth::user()->account_id)
->where('clients.deleted_at', '=', null)
->where('invoices.deleted_at', '=', null)
->select(\DB::raw("'invoices' as type, '" . trans('texts.invoices') . "' as trans_type, invoices.public_id, CONCAT(invoices.invoice_number, ': ', clients.name) as name, invoices.invoice_number as token"));
return $data;
}
$data = [];
private function getAccountSearchData()
{
$data = [
'clients' => [],
'contacts' => [],
'invoices' => [],
'quotes' => [],
];
foreach ($clients->union($contacts)->union($invoices)->get() as $row) {
$type = $row->trans_type;
$clients = Client::scope()
->with('contacts', 'invoices')
->get();
if (!isset($data[$type])) {
$data[$type] = [];
foreach ($clients as $client) {
if ($client->name) {
$data['clients'][] = [
'value' => $client->name,
'url' => $client->present()->url,
];
}
$tokens = explode(' ', $row->name);
$tokens[] = $type;
if ($type == 'Invoices') {
$tokens[] = intVal($row->token).'';
foreach ($client->contacts as $contact) {
if ($contact->getFullName()) {
$data['contacts'][] = [
'value' => $contact->getDisplayName(),
'url' => $client->present()->url,
];
}
if ($contact->email) {
$data[trans('texts.contacts')][] = [
'value' => $contact->email,
'url' => $client->present()->url,
];
}
}
$data[$type][] = [
'value' => $row->name,
'public_id' => $row->public_id,
'tokens' => $tokens,
'entity_type' => $row->type,
foreach ($client->invoices as $invoice) {
$entityType = $invoice->getEntityType();
$data["{$entityType}s"][] = [
'value' => $invoice->getDisplayName() . ': ' . $client->getDisplayName(),
'url' => $invoice->present()->url,
];
}
}
return $data;
}
private function getNavigationSearchData()
{
$entityTypes = [
ENTITY_INVOICE,
ENTITY_CLIENT,
ENTITY_QUOTE,
ENTITY_TASK,
ENTITY_EXPENSE,
ENTITY_RECURRING_INVOICE,
ENTITY_PAYMENT,
ENTITY_CREDIT
];
foreach ($entityTypes as $entityType) {
$features[] = [
"new_{$entityType}",
"/{$entityType}s/create",
];
$features[] = [
"list_{$entityType}s",
"/{$entityType}s",
];
}
$features[] = ['dashboard', '/dashboard'];
$features[] = ['customize_design', '/settings/customize_design'];
$features[] = ['new_tax_rate', '/tax_rates/create'];
$features[] = ['new_product', '/products/create'];
$features[] = ['new_user', '/users/create'];
$settings = array_merge(Account::$basicSettings, Account::$advancedSettings);
foreach ($settings as $setting) {
$features[] = [
$setting,
"/settings/{$setting}",
];
}
foreach ($features as $feature) {
$data[] = [
'value' => trans('texts.' . $feature[0]),
'url' => URL::to($feature[1])
];
}
@ -124,25 +182,25 @@ class AccountRepository
return false;
}
$client = $this->getNinjaClient(Auth::user()->account);
$invitation = $this->createNinjaInvoice($client);
$account = Auth::user()->account;
$client = $this->getNinjaClient($account);
$invitation = $this->createNinjaInvoice($client, $account);
return $invitation;
}
public function createNinjaInvoice($client)
public function createNinjaInvoice($client, $clientAccount)
{
$account = $this->getNinjaAccount();
$lastInvoice = Invoice::withTrashed()->whereAccountId($account->id)->orderBy('public_id', 'DESC')->first();
$publicId = $lastInvoice ? ($lastInvoice->public_id + 1) : 1;
$invoice = new Invoice();
$invoice->account_id = $account->id;
$invoice->user_id = $account->users()->first()->id;
$invoice->public_id = $publicId;
$invoice->client_id = $client->id;
$invoice->invoice_number = $account->getNextInvoiceNumber($invoice);
$invoice->invoice_date = Auth::user()->account->getRenewalDate();
$invoice->invoice_date = $clientAccount->getRenewalDate();
$invoice->amount = PRO_PLAN_PRICE;
$invoice->balance = PRO_PLAN_PRICE;
$invoice->save();

View File

@ -1,6 +1,7 @@
<?php namespace App\Ninja\Repositories;
use DB;
use Cache;
use App\Ninja\Repositories\BaseRepository;
use App\Models\Client;
use App\Models\Contact;
@ -74,6 +75,17 @@ class ClientRepository extends BaseRepository
$client = Client::scope($publicId)->with('contacts')->firstOrFail();
}
// convert currency code to id
if (isset($data['currency_code'])) {
$currencyCode = strtolower($data['currency_code']);
$currency = Cache::get('currencies')->filter(function($item) use ($currencyCode) {
return strtolower($item->code) == $currencyCode;
})->first();
if ($currency) {
$data['currency_id'] = $currency->id;
}
}
$client->fill($data);
$client->save();

View File

@ -398,7 +398,7 @@ class InvoiceRepository extends BaseRepository
foreach ($data['invoice_items'] as $item) {
$item = (array) $item;
if (!$item['cost'] && !$item['product_key'] && !$item['notes']) {
if (empty($item['cost']) && empty($item['product_key']) && empty($item['notes']) && empty($item['custom_value1']) && empty($item['custom_value2'])) {
continue;
}
@ -439,6 +439,13 @@ class InvoiceRepository extends BaseRepository
$invoiceItem->qty = Utils::parseFloat($item['qty']);
$invoiceItem->tax_rate = 0;
if (isset($item['custom_value1'])) {
$invoiceItem->custom_value1 = $item['custom_value1'];
}
if (isset($item['custom_value2'])) {
$invoiceItem->custom_value2 = $item['custom_value2'];
}
if (isset($item['tax_rate']) && isset($item['tax_name']) && $item['tax_name']) {
$invoiceItem['tax_rate'] = Utils::parseFloat($item['tax_rate']);
$invoiceItem['tax_name'] = trim($item['tax_name']);
@ -603,7 +610,7 @@ class InvoiceRepository extends BaseRepository
$invoice = Invoice::createNew($recurInvoice);
$invoice->client_id = $recurInvoice->client_id;
$invoice->recurring_invoice_id = $recurInvoice->id;
$invoice->invoice_number = 'R'.$recurInvoice->account->getNextInvoiceNumber($recurInvoice);
$invoice->invoice_number = $recurInvoice->account->recurring_invoice_number_prefix . $recurInvoice->account->getNextInvoiceNumber($recurInvoice);
$invoice->amount = $recurInvoice->amount;
$invoice->balance = $recurInvoice->amount;
$invoice->invoice_date = date_create()->format('Y-m-d');

View File

@ -116,7 +116,7 @@ class PaymentRepository extends BaseRepository
public function save($input)
{
$publicId = isset($input['public_id']) ? $input['public_id'] : false;
if ($publicId) {
$payment = Payment::scope($publicId)->firstOrFail();
} else {
@ -136,7 +136,7 @@ class PaymentRepository extends BaseRepository
} else {
$payment->payment_date = date('Y-m-d');
}
if (isset($input['transaction_reference'])) {
$payment->transaction_reference = trim($input['transaction_reference']);
}

View File

@ -21,7 +21,11 @@ class UserTransformer extends EntityTransformer
'registered' => (bool) $user->registered,
'confirmed' => (bool) $user->confirmed,
'oauth_user_id' => $user->oauth_user_id,
'oauth_provider_id' => $user->oauth_provider_id
'oauth_provider_id' => $user->oauth_provider_id,
'notify_sent' => (bool) $user->notify_sent,
'notify_viewed' => (bool) $user->notify_viewed,
'notify_paid' => (bool) $user->notify_paid,
'notify_approved' => (bool) $user->notify_approved,
];
}
}

View File

@ -4,6 +4,7 @@ use Session;
use Auth;
use Utils;
use HTML;
use Form;
use URL;
use Request;
use Validator;
@ -18,18 +19,22 @@ class AppServiceProvider extends ServiceProvider {
*/
public function boot()
{
HTML::macro('nav_link', function($url, $text, $url2 = '', $extra = '') {
Form::macro('image_data', function($imagePath) {
return 'data:image/jpeg;base64,' . base64_encode(file_get_contents($imagePath));
});
Form::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) {
Form::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) {
Form::macro('menu_link', function($type) {
$types = $type.'s';
$Type = ucfirst($type);
$Types = ucfirst($types);
@ -65,15 +70,11 @@ class AppServiceProvider extends ServiceProvider {
return $str;
});
HTML::macro('image_data', function($imagePath) {
return 'data:image/jpeg;base64,' . base64_encode(file_get_contents($imagePath));
});
HTML::macro('flatButton', function($label, $color) {
Form::macro('flatButton', function($label, $color) {
return '<input type="button" value="' . trans("texts.{$label}") . '" style="background-color:' . $color . ';border:0 none;border-radius:5px;padding:12px 40px;margin:0 6px;cursor:hand;display:inline-block;font-size:14px;color:#fff;text-transform:none;font-weight:bold;"/>';
});
HTML::macro('emailViewButton', function($link = '#', $entityType = ENTITY_INVOICE) {
Form::macro('emailViewButton', function($link = '#', $entityType = ENTITY_INVOICE) {
return view('partials.email_button')
->with([
'link' => $link,
@ -83,7 +84,7 @@ class AppServiceProvider extends ServiceProvider {
->render();
});
HTML::macro('emailPaymentButton', function($link = '#') {
Form::macro('emailPaymentButton', function($link = '#') {
return view('partials.email_button')
->with([
'link' => $link,
@ -93,7 +94,7 @@ class AppServiceProvider extends ServiceProvider {
->render();
});
HTML::macro('breadcrumbs', function($status = false) {
Form::macro('breadcrumbs', function($status = false) {
$str = '<ol class="breadcrumb">';
// Get the breadcrumbs by exploding the current path.
@ -135,7 +136,7 @@ class AppServiceProvider extends ServiceProvider {
return $str . '</ol>';
});
Validator::extend('positive', function($attribute, $value, $parameters) {
return Utils::parseFloat($value) >= 0;
});
@ -223,11 +224,6 @@ class AppServiceProvider extends ServiceProvider {
'Illuminate\Contracts\Auth\Registrar',
'App\Services\Registrar'
);
$this->app->bind(
'App\Ninja\Import\DataImporterServiceInterface',
'App\Ninja\Import\FreshBooks\FreshBooksDataImporterService'
);
}
}

View File

@ -38,11 +38,11 @@ class ActivityService extends BaseService
'activity_type_id',
function ($model) {
$data = [
'client' => link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model)),
'user' => $model->is_system ? '<i>' . trans('texts.system') . '</i>' : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
'invoice' => $model->invoice ? link_to('/invoices/' . $model->invoice_public_id, $model->is_recurring ? trans('texts.recurring_invoice') : $model->invoice) : null,
'quote' => $model->invoice ? link_to('/quotes/' . $model->invoice_public_id, $model->invoice) : null,
'contact' => $model->contact_id ? link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model)) : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
'client' => link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml(),
'user' => $model->is_system ? '<i>' . trans('texts.system') . '</i>' : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
'invoice' => $model->invoice ? link_to('/invoices/' . $model->invoice_public_id, $model->is_recurring ? trans('texts.recurring_invoice') : $model->invoice)->toHtml() : null,
'quote' => $model->invoice ? link_to('/quotes/' . $model->invoice_public_id, $model->invoice)->toHtml() : null,
'contact' => $model->contact_id ? link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model))->toHtml() : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
'payment' => $model->payment ?: '',
'credit' => Utils::formatMoney($model->credit, $model->currency_id, $model->country_id)
];

View File

@ -4,7 +4,6 @@ use stdClass;
use Utils;
use URL;
use Hash;
use App\Models\Gateway;
use App\Models\BankSubaccount;
use App\Models\Vendor;
use App\Models\Expense;
@ -37,7 +36,7 @@ class BankAccountService extends BaseService
public function loadBankAccounts($bankId, $username, $password, $includeTransactions = true)
{
if ( ! $bankId || ! $username || ! $password) {
if (! $bankId || ! $username || ! $password) {
return false;
}
@ -47,12 +46,13 @@ class BankAccountService extends BaseService
->withTrashed()
->get(['transaction_id'])
->toArray();
$expenses = array_flip(array_map(function($val) {
$expenses = array_flip(array_map(function ($val) {
return $val['transaction_id'];
}, $expenses));
$vendorMap = $this->createVendorMap();
$bankAccounts = BankSubaccount::scope()
->whereHas('bank_account', function($query) use ($bankId) {
->whereHas('bank_account', function ($query) use ($bankId) {
$query->where('bank_id', '=', $bankId);
})
->get();
@ -64,13 +64,13 @@ class BankAccountService extends BaseService
$finance = new Finance();
$finance->banks[$bankId] = $bank->getOFXBank($finance);
$finance->banks[$bankId]->logins[] = new Login($finance->banks[$bankId], $username, $password);
foreach ($finance->banks as $bank) {
foreach ($bank->logins as $login) {
$login->setup();
foreach ($login->accounts as $account) {
$account->setup($includeTransactions);
if ($account = $this->parseBankAccount($account, $bankAccounts, $expenses, $includeTransactions)) {
if ($account = $this->parseBankAccount($account, $bankAccounts, $expenses, $includeTransactions, $vendorMap)) {
$data[] = $account;
}
}
@ -83,9 +83,9 @@ class BankAccountService extends BaseService
}
}
private function parseBankAccount($account, $bankAccounts, $expenses, $includeTransactions)
private function parseBankAccount($account, $bankAccounts, $expenses, $includeTransactions, $vendorMap)
{
$obj = new stdClass;
$obj = new stdClass();
$obj->account_name = '';
// look up bank account name
@ -106,7 +106,7 @@ class BankAccountService extends BaseService
$obj->balance = Utils::formatMoney($account->ledgerBalance, CURRENCY_DOLLAR);
if ($includeTransactions) {
$ofxParser = new \OfxParser\Parser;
$ofxParser = new \OfxParser\Parser();
$ofx = $ofxParser->loadFromString($account->response);
$obj->start_date = $ofx->BankAccount->Statement->startDate;
@ -121,7 +121,13 @@ class BankAccountService extends BaseService
if ($transaction->amount >= 0) {
continue;
}
$transaction->vendor = $this->prepareValue(substr($transaction->name, 0, 20));
// if vendor has already been imported use current name
$vendorName = trim(substr($transaction->name, 0, 20));
$key = strtolower($vendorName);
$vendor = isset($vendorMap[$key]) ? $vendorMap[$key] : null;
$transaction->vendor = $vendor ? $vendor->name : $this->prepareValue($vendorName);
$transaction->info = $this->prepareValue(substr($transaction->name, 20));
$transaction->memo = $this->prepareValue($transaction->memo);
$transaction->date = \Auth::user()->account->formatDate($transaction->date);
@ -133,15 +139,13 @@ class BankAccountService extends BaseService
return $obj;
}
private function prepareValue($value) {
private function prepareValue($value)
{
return ucwords(strtolower(trim($value)));
}
public function importExpenses($bankId, $input) {
$countVendors = 0;
$countExpenses = 0;
// create a vendor map
private function createVendorMap()
{
$vendorMap = [];
$vendors = Vendor::scope()
->withTrashed()
@ -151,6 +155,15 @@ class BankAccountService extends BaseService
$vendorMap[strtolower($vendor->transaction_name)] = $vendor;
}
return $vendorMap;
}
public function importExpenses($bankId, $input)
{
$vendorMap = $this->createVendorMap();
$countVendors = 0;
$countExpenses = 0;
foreach ($input as $transaction) {
$vendorName = $transaction['vendor'];
$key = strtolower($vendorName);
@ -165,7 +178,7 @@ class BankAccountService extends BaseService
$field => $info,
'name' => $vendorName,
'transaction_name' => $transaction['vendor_orig'],
'vendorcontact' => []
'vendorcontact' => [],
]);
$vendorMap[$key] = $vendor;
$vendorMap[$transaction['vendor_orig']] = $vendor;
@ -191,7 +204,8 @@ class BankAccountService extends BaseService
]);
}
private function determineInfoField($value) {
private function determineInfoField($value)
{
if (preg_match("/^[0-9\-\(\)\.]+$/", $value)) {
return 'work_phone';
} elseif (strpos($value, '.') !== false) {
@ -214,8 +228,8 @@ class BankAccountService extends BaseService
[
'bank_name',
function ($model) {
return link_to("bank_accounts/{$model->public_id}/edit", $model->bank_name);
}
return link_to("bank_accounts/{$model->public_id}/edit", $model->bank_name)->toHtml();
},
],
[
'bank_library_id',
@ -233,9 +247,8 @@ class BankAccountService extends BaseService
uctrans('texts.edit_bank_account'),
function ($model) {
return URL::to("bank_accounts/{$model->public_id}/edit");
}
},
]
];
}
}
}

View File

@ -1,11 +1,11 @@
<?php namespace App\Services;
use Illuminate\Foundation\Bus\DispatchesCommands;
use Illuminate\Foundation\Bus\DispatchesJobs;
use App\Services\DatatableService;
class BaseService
{
use DispatchesCommands;
use DispatchesJobs;
protected function getRepo()
{

View File

@ -46,19 +46,19 @@ class ClientService extends BaseService
[
'name',
function ($model) {
return link_to("clients/{$model->public_id}", $model->name ?: '');
return link_to("clients/{$model->public_id}", $model->name ?: '')->toHtml();
}
],
[
'first_name',
function ($model) {
return link_to("clients/{$model->public_id}", $model->first_name.' '.$model->last_name);
return link_to("clients/{$model->public_id}", $model->first_name.' '.$model->last_name)->toHtml();
}
],
[
'email',
function ($model) {
return link_to("clients/{$model->public_id}", $model->email ?: '');
return link_to("clients/{$model->public_id}", $model->email ?: '')->toHtml();
}
],
[

View File

@ -40,7 +40,7 @@ class CreditService extends BaseService
[
'client_name',
function ($model) {
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model)) : '';
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
},
! $hideClient
],

View File

@ -1,5 +1,6 @@
<?php namespace App\Services;
use HtmlString;
use Utils;
use Datatable;

View File

@ -30,11 +30,11 @@ class ExpenseService extends BaseService
if (isset($data['client_id']) && $data['client_id']) {
$data['client_id'] = Client::getPrivateId($data['client_id']);
}
if (isset($data['vendor_id']) && $data['vendor_id']) {
$data['vendor_id'] = Vendor::getPrivateId($data['vendor_id']);
}
return $this->expenseRepo->save($data);
}
@ -63,7 +63,7 @@ class ExpenseService extends BaseService
function ($model)
{
if ($model->vendor_public_id) {
return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name);
return link_to("vendors/{$model->vendor_public_id}", $model->vendor_name)->toHtml();
} else {
return '';
}
@ -74,7 +74,7 @@ class ExpenseService extends BaseService
function ($model)
{
if ($model->client_public_id) {
return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model));
return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
} else {
return '';
}
@ -83,7 +83,7 @@ class ExpenseService extends BaseService
[
'expense_date',
function ($model) {
return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date));
return link_to("expenses/{$model->public_id}/edit", Utils::fromSqlDate($model->expense_date))->toHtml();
}
],
[
@ -92,7 +92,7 @@ class ExpenseService extends BaseService
// show both the amount and the converted amount
if ($model->exchange_rate != 1) {
$converted = round($model->amount * $model->exchange_rate, 2);
return Utils::formatMoney($model->amount, $model->expense_currency_id) . ' | ' .
return Utils::formatMoney($model->amount, $model->expense_currency_id) . ' | ' .
Utils::formatMoney($converted, $model->invoice_currency_id);
} else {
return Utils::formatMoney($model->amount, $model->expense_currency_id);
@ -178,7 +178,7 @@ class ExpenseService extends BaseService
{
return [];
}
private function getStatusLabel($invoiceId, $shouldBeInvoiced)
{
if ($invoiceId) {

View File

@ -1,4 +1,4 @@
<?php namespace app\Services;
<?php namespace App\Services;
use stdClass;
use Excel;

View File

@ -35,7 +35,7 @@ class InvoiceService extends BaseService
}
$invoice = $this->invoiceRepo->save($data);
$client = $invoice->client;
$client->load('contacts');
$sendInvoiceIds = [];
@ -45,7 +45,7 @@ class InvoiceService extends BaseService
$sendInvoiceIds[] = $contact->id;
}
}
foreach ($client->contacts as $contact) {
$invitation = Invitation::scope()->whereContactId($contact->id)->whereInvoiceId($invoice->id)->first();
@ -69,7 +69,7 @@ class InvoiceService extends BaseService
if (!$invitation) {
return $invoice;
}
foreach ($invoice->invitations as $invoiceInvitation) {
if ($invitation->contact_id == $invoiceInvitation->contact_id) {
return $invoiceInvitation->invitation_key;
@ -83,7 +83,7 @@ class InvoiceService extends BaseService
if (!$quote->is_quote || $quote->quote_invoice_id) {
return null;
}
if ($account->auto_convert_quote || ! $account->isPro()) {
$invoice = $this->convertQuote($quote, $invitation);
@ -94,7 +94,7 @@ class InvoiceService extends BaseService
$quote->markApproved();
event(new QuoteInvitationWasApproved($quote, null, $invitation));
foreach ($quote->invitations as $invoiceInvitation) {
if ($invitation->contact_id == $invoiceInvitation->contact_id) {
return $invoiceInvitation->invitation_key;
@ -117,13 +117,13 @@ class InvoiceService extends BaseService
[
'invoice_number',
function ($model) use ($entityType) {
return link_to("{$entityType}s/{$model->public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)]);
return link_to("{$entityType}s/{$model->public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml();
}
],
[
'client_name',
function ($model) {
return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model));
return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
},
! $hideClient
],
@ -160,7 +160,7 @@ class InvoiceService extends BaseService
[
'invoice_status_name',
function ($model) {
return $model->quote_invoice_id ? link_to("invoices/{$model->quote_invoice_id}/edit", trans('texts.converted')) : self::getStatusLabel($model);
return $model->quote_invoice_id ? link_to("invoices/{$model->quote_invoice_id}/edit", trans('texts.converted'))->toHtml() : self::getStatusLabel($model);
}
]
];
@ -266,5 +266,5 @@ class InvoiceService extends BaseService
}
return "<h4><div class=\"label label-{$class}\">$label</div></h4>";
}
}

View File

@ -202,7 +202,7 @@ class PaymentService extends BaseService
if ($response->isRedirect()) {
$token = $response->getTransactionReference();
}
Session::set($invitation->id . 'payment_type', PAYMENT_TYPE_CREDIT_CARD);
return $token;
@ -273,7 +273,7 @@ class PaymentService extends BaseService
// submit purchase/get response
$response = $gateway->purchase($details)->send();
if ($response->isSuccessful()) {
$ref = $response->getTransactionReference();
return $this->createPayment($invitation, $accountGateway, $ref);
@ -295,13 +295,13 @@ class PaymentService extends BaseService
[
'invoice_number',
function ($model) {
return link_to("invoices/{$model->invoice_public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)]);
return link_to("invoices/{$model->invoice_public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml();
}
],
[
'client_name',
function ($model) {
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model)) : '';
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
},
! $hideClient
],

View File

@ -34,7 +34,7 @@ class PaymentTermService extends BaseService
[
'name',
function ($model) {
return link_to("payment_terms/{$model->public_id}/edit", $model->name);
return link_to("payment_terms/{$model->public_id}/edit", $model->name)->toHtml();
}
],
[

View File

@ -44,7 +44,7 @@ class ProductService extends BaseService
[
'product_key',
function ($model) {
return link_to('products/'.$model->public_id.'/edit', $model->product_key);
return link_to('products/'.$model->public_id.'/edit', $model->product_key)->toHtml();
}
],
[

View File

@ -0,0 +1,171 @@
<?php
namespace App\Services;
use Illuminate\Http\Request;
use App\Ninja\Notifications\PushFactory;
/**
* Class PushService
* @package App\Ninja\Notifications
*/
/**
* $account->devices Definition
*
* @param string token (push notification device token)
* @param string email (user email address - required for use as key)
* @param string device (ios, gcm etc etc)
* @param bool notify_sent
* @param bool notify_paid
* @param bool notify_approved
* @param bool notify_viewed
*/
class PushService
{
protected $pushFactory;
/**
* @param PushFactory $pushFactory
*/
public function __construct(PushFactory $pushFactory)
{
$this->pushFactory = $pushFactory;
}
/**
* @param $invoice - Invoice object
* @param $type - Type of notification, ie. Quote APPROVED, Invoice PAID, Invoice/Quote SENT, Invoice/Quote VIEWED
*/
public function sendNotification($invoice, $type)
{
//check user has registered for push notifications
if(!$this->checkDeviceExists($invoice->account))
return;
//Harvest an array of devices that are registered for this notification type
$devices = json_decode($invoice->account->devices, TRUE);
foreach($devices as $device)
{
if(($device["notify_{$type}"] == TRUE) && ($device['device'] == 'ios'))
$this->pushMessage($invoice, $device['token'], $type);
}
}
/**
* pushMessage function
*
* method to dispatch iOS notifications
*
* @param $invoice
* @param $token
* @param $type
*/
private function pushMessage($invoice, $token, $type)
{
$this->pushFactory->message($token, $this->messageType($invoice, $type));
}
/**
* checkDeviceExists function
*
* Returns a boolean if this account has devices registered for PUSH notifications
*
* @param $account
* @return bool
*/
private function checkDeviceExists($account)
{
$devices = json_decode($account->devices, TRUE);
if(count($devices) >= 1)
return TRUE;
else
return FALSE;
}
/**
* messageType function
*
* method which formats an appropriate message depending on message type
*
* @param $invoice
* @param $type
* @return string
*/
private function messageType($invoice, $type)
{
switch($type)
{
case 'sent':
return $this->entitySentMessage($invoice);
break;
case 'paid':
return $this->invoicePaidMessage($invoice);
break;
case 'approved':
return $this->quoteApprovedMessage($invoice);
break;
case 'viewed':
return $this->entityViewedMessage($invoice);
break;
}
}
/**
* @param $invoice
* @return string
*/
private function entitySentMessage($invoice)
{
if($invoice->is_quote)
return trans("texts.notification_quote_sent_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]);
else
return trans("texts.notification_invoice_sent_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]);
}
/**
* @param $invoice
* @return string
*/
private function invoicePaidMessage($invoice)
{
return trans("texts.notification_invoice_paid_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]);
}
/**
* @param $invoice
* @return string
*/
private function quoteApprovedMessage($invoice)
{
return trans("texts.notification_quote_approved_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]);
}
/**
* @param $invoice
* @return string
*/
private function entityViewedMessage($invoice)
{
if($invoice->is_quote)
return trans("texts.notification_quote_viewed_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]);
else
return trans("texts.notification_invoice_viewed_subject", ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]);
}
}

View File

@ -28,13 +28,13 @@ class RecurringInvoiceService extends BaseService
[
'frequency',
function ($model) {
return link_to("invoices/{$model->public_id}", $model->frequency);
return link_to("invoices/{$model->public_id}", $model->frequency)->toHtml();
}
],
[
'client_name',
function ($model) {
return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model));
return link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml();
},
! $hideClient
],

View File

@ -1,39 +0,0 @@
<?php namespace App\Services;
use App\Model\User;
use Validator;
use Illuminate\Contracts\Auth\Registrar as RegistrarContract;
class Registrar implements RegistrarContract {
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
public function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
public function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
}

View File

@ -42,14 +42,14 @@ class TaskService extends BaseService
[
'client_name',
function ($model) {
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model)) : '';
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
},
! $hideClient
],
[
'created_at',
function ($model) {
return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model));
return link_to("tasks/{$model->public_id}/edit", Task::calcStartTime($model))->toHtml();
}
],
[

View File

@ -41,7 +41,7 @@ class TaxRateService extends BaseService
[
'name',
function ($model) {
return link_to("tax_rates/{$model->public_id}/edit", $model->name);
return link_to("tax_rates/{$model->public_id}/edit", $model->name)->toHtml();
}
],
[

View File

@ -40,7 +40,7 @@ class TokenService extends BaseService
[
'name',
function ($model) {
return link_to("tokens/{$model->public_id}/edit", $model->name);
return link_to("tokens/{$model->public_id}/edit", $model->name)->toHtml();
}
],
[

View File

@ -40,7 +40,7 @@ class UserService extends BaseService
[
'first_name',
function ($model) {
return $model->public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name) : ($model->first_name.' '.$model->last_name);
return $model->public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name)->toHtml() : ($model->first_name.' '.$model->last_name);
}
],
[

View File

@ -46,7 +46,7 @@ class VendorService extends BaseService
[
'name',
function ($model) {
return link_to("vendors/{$model->public_id}", $model->name ?: '');
return link_to("vendors/{$model->public_id}", $model->name ?: '')->toHtml();
}
],
[
@ -64,7 +64,7 @@ class VendorService extends BaseService
[
'email',
function ($model) {
return link_to("vendors/{$model->public_id}", $model->email ?: '');
return link_to("vendors/{$model->public_id}", $model->email ?: '')->toHtml();
}
],
[

0
bootstrap/app.php Normal file → Executable file
View File

2
bootstrap/autoload.php Normal file → Executable file
View File

@ -30,7 +30,7 @@ require __DIR__.'/../vendor/autoload.php';
|
*/
$compiledPath = __DIR__.'/../vendor/compiled.php';
$compiledPath = __DIR__.'/cache/compiled.php';
if (file_exists($compiledPath))
{

2
bootstrap/cache/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

0
bootstrap/environment.php Normal file → Executable file
View File

View File

@ -14,7 +14,7 @@
"underscore": "1.7.0",
"jspdf": "1.0.272",
"bootstrap-datepicker": "1.4.0",
"typeahead.js": "0.9.3",
"typeahead.js": "0.11.1",
"accounting": "0.3.2",
"spectrum": "1.3.4",
"d3": "3.4.11",
@ -25,7 +25,8 @@
"moment-timezone": "~0.4.0",
"quill": "~0.20.0",
"datetimepicker": "~2.4.5",
"stacktrace-js": "~1.0.1"
"stacktrace-js": "~1.0.1",
"fuse.js": "~2.0.2"
},
"resolutions": {
"jquery": "~1.11"

View File

@ -10,15 +10,19 @@
}
],
"require": {
"turbo124/laravel-push-notification": "dev-laravel5",
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
"omnipay/gocardless": "dev-master",
"omnipay/stripe": "2.3.0",
"laravel/framework": "5.0.*",
"laravel/framework": "5.2.*",
"laravelcollective/html": "5.2.*",
"laravelcollective/bus": "5.2.*",
"symfony/css-selector": "~3.0",
"patricktalmadge/bootstrapper": "5.5.x",
"anahkiasen/former": "4.0.*@dev",
"barryvdh/laravel-debugbar": "~2.0.2",
"chumper/datatable": "dev-develop#7fa47cb",
"barryvdh/laravel-debugbar": "~2.0",
"chumper/datatable": "dev-develop#04ef2bf",
"omnipay/omnipay": "~2.3.0",
"intervention/image": "dev-master",
"webpatser/laravel-countries": "dev-master",
@ -27,7 +31,6 @@
"jsanc623/phpbenchtime": "2.x",
"lokielse/omnipay-alipay": "dev-master",
"coatesap/omnipay-datacash": "~2.0",
"alfaproject/omnipay-neteller": "1.0.*@dev",
"mfauveau/omnipay-pacnet": "~2.0",
"coatesap/omnipay-paymentsense": "2.0.0",
"coatesap/omnipay-realex": "~2.0",
@ -35,7 +38,6 @@
"alfaproject/omnipay-skrill": "dev-master",
"omnipay/bitpay": "dev-master",
"guzzlehttp/guzzle": "~6.0",
"laravelcollective/html": "~5.0",
"wildbit/laravel-postmark-provider": "2.0",
"Dwolla/omnipay-dwolla": "dev-master",
"laravel/socialite": "~2.0",
@ -71,7 +73,8 @@
"phpspec/phpspec": "~2.1",
"codeception/codeception": "*",
"codeception/c3": "~2.0",
"fzaninotto/faker": "^1.5"
"fzaninotto/faker": "^1.5",
"symfony/dom-crawler": "~3.0"
},
"autoload": {
"classmap": [

1855
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,8 @@ return [
'debug' => env('APP_DEBUG', ''),
'env' => env('APP_ENV', 'production'),
/*
|--------------------------------------------------------------------------
| Application URL
@ -115,12 +117,11 @@ return [
/*
* Laravel Framework Service Providers...
*/
'Illuminate\Foundation\Providers\ArtisanServiceProvider',
'Illuminate\Auth\AuthServiceProvider',
'Illuminate\Bus\BusServiceProvider',
'Collective\Html\HtmlServiceProvider',
'Collective\Bus\BusServiceProvider',
'Illuminate\Cache\CacheServiceProvider',
'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider',
'Illuminate\Routing\ControllerServiceProvider',
'Illuminate\Cookie\CookieServiceProvider',
'Illuminate\Database\DatabaseServiceProvider',
'Illuminate\Encryption\EncryptionServiceProvider',
@ -137,7 +138,8 @@ return [
'Illuminate\Translation\TranslationServiceProvider',
'Illuminate\Validation\ValidationServiceProvider',
'Illuminate\View\ViewServiceProvider',
'Illuminate\Broadcasting\BroadcastServiceProvider',
/*
* Additional Providers
*/
@ -148,7 +150,6 @@ return [
'Intervention\Image\ImageServiceProvider',
'Webpatser\Countries\CountriesServiceProvider',
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
'Illuminate\Html\HtmlServiceProvider',
'Laravel\Socialite\SocialiteServiceProvider',
'Jlapp\Swaggervel\SwaggervelServiceProvider',
'Maatwebsite\Excel\ExcelServiceProvider',
@ -157,12 +158,13 @@ return [
* Application Service Providers...
*/
'App\Providers\AppServiceProvider',
'App\Providers\BusServiceProvider',
//'App\Providers\BusServiceProvider',
'App\Providers\ConfigServiceProvider',
'App\Providers\EventServiceProvider',
'App\Providers\RouteServiceProvider',
'Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider',
'Davibennun\LaravelPushNotification\LaravelPushNotificationServiceProvider',
],
/*
@ -248,6 +250,7 @@ return [
'Rocketeer' => 'Rocketeer\Facades\Rocketeer',
'Socialite' => 'Laravel\Socialite\Facades\Socialite',
'Excel' => 'Maatwebsite\Excel\Facades\Excel',
'PushNotification' => 'Davibennun\LaravelPushNotification\Facades\PushNotification',
],

View File

@ -1,12 +1,106 @@
<?php
return [
'driver' => 'eloquent',
'model' => 'App\Models\User',
'table' => 'users',
'password' => [
'email' => 'emails.password',
'table' => 'password_resets',
'expire' => 60,
]
];
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| Here you may set the options for resetting passwords including the view
| that is your password reset e-mail. You may also set the name of the
| table that maintains all of the reset tokens for your application.
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'email' => 'emails.password', //auth.emails.password
'table' => 'password_resets',
'expire' => 60,
],
],
];

View File

@ -0,0 +1,23 @@
<?php
return [
'devNinjaIOS' => [
'environment' =>'development',
'certificate'=>app_path().'/certs/ninjaIOS.pem',
'passPhrase' =>'',
'service' =>'apns'
],
'ninjaIOS' => [
'environment' =>'production',
'certificate'=>app_path().'/certs/productionNinjaIOS.pem',
'passPhrase' =>'',
'service' =>'apns'
],
'ninjaAndroid' => [
'environment' =>'production',
'apiKey' =>'yourAPIKey',
'service' =>'gcm'
]
];

View File

@ -0,0 +1,51 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddCustomInvoiceFields extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('accounts', function($table) {
$table->string('custom_invoice_item_label1')->nullable();
$table->string('custom_invoice_item_label2')->nullable();
$table->string('recurring_invoice_number_prefix')->default('R');
$table->boolean('enable_client_portal')->default(true);
$table->text('invoice_fields')->nullable();
$table->text('devices')->nullable();
});
Schema::table('invoice_items', function($table) {
$table->string('custom_value1')->nullable();
$table->string('custom_value2')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('accounts', function($table) {
$table->dropColumn('custom_invoice_item_label1');
$table->dropColumn('custom_invoice_item_label2');
$table->dropColumn('recurring_invoice_number_prefix');
$table->dropColumn('enable_client_portal');
$table->dropColumn('invoice_fields');
$table->dropColumn('devices');
});
Schema::table('invoice_items', function($table) {
$table->dropColumn('custom_value1');
$table->dropColumn('custom_value2');
});
}
}

View File

@ -1,5 +1,6 @@
<?php
use Illuminate\Database\Eloquent\Model as Eloquent;
use App\Models\Country;
class CountriesSeeder extends Seeder {
@ -13,25 +14,156 @@ class CountriesSeeder extends Seeder {
//Empty the countries table
DB::table('countries')->delete();
//Get all of the countries
$countries = Countries::getList();
foreach ($countries as $countryId => $country){
DB::table('countries')->insert(array(
'id' => $countryId,
'capital' => ((isset($country['capital'])) ? $country['capital'] : null),
'citizenship' => ((isset($country['citizenship'])) ? $country['citizenship'] : null),
'country_code' => $country['country-code'],
'currency' => ((isset($country['currency'])) ? $country['currency'] : null),
'currency_code' => ((isset($country['currency_code'])) ? $country['currency_code'] : null),
'currency_sub_unit' => ((isset($country['currency_sub_unit'])) ? $country['currency_sub_unit'] : null),
'full_name' => ((isset($country['full_name'])) ? $country['full_name'] : null),
'iso_3166_2' => $country['iso_3166_2'],
'iso_3166_3' => $country['iso_3166_3'],
'name' => $country['name'],
'region_code' => $country['region-code'],
'sub_region_code' => $country['sub-region-code'],
'eea' => (bool)$country['eea']
));
if (DB::table('countries')->count() == 0) {
//Get all of the countries
$countries = Countries::getList();
foreach ($countries as $countryId => $country){
DB::table('countries')->insert(array(
'id' => $countryId,
'capital' => ((isset($country['capital'])) ? $country['capital'] : null),
'citizenship' => ((isset($country['citizenship'])) ? $country['citizenship'] : null),
'country_code' => $country['country-code'],
'currency' => ((isset($country['currency'])) ? $country['currency'] : null),
'currency_code' => ((isset($country['currency_code'])) ? $country['currency_code'] : null),
'currency_sub_unit' => ((isset($country['currency_sub_unit'])) ? $country['currency_sub_unit'] : null),
'full_name' => ((isset($country['full_name'])) ? $country['full_name'] : null),
'iso_3166_2' => $country['iso_3166_2'],
'iso_3166_3' => $country['iso_3166_3'],
'name' => $country['name'],
'region_code' => $country['region-code'],
'sub_region_code' => $country['sub-region-code'],
'eea' => (bool)$country['eea']
));
}
}
// Source: http://www.bitboost.com/ref/international-address-formats.html
// Source: https://en.wikipedia.org/wiki/Linguistic_issues_concerning_the_euro
$countries = [
'AR' => [
'swap_postal_code' => true,
],
'AT' => [ // Austria
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'BE' => [
'swap_postal_code' => true,
],
'BG' => [ // Belgium
'swap_currency_symbol' => true,
],
'CH' => [
'swap_postal_code' => true,
],
'CZ' => [ // Czech Republic
'swap_currency_symbol' => true,
],
'DE' => [ // Germany
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'DK' => [
'swap_postal_code' => true,
],
'EE' => [ // Estonia
'swap_currency_symbol' => true,
],
'ES' => [ // Spain
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'FI' => [ // Finland
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'FR' => [ // France
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'GR' => [ // Greece
'swap_currency_symbol' => true,
],
'HR' => [ // Croatia
'swap_currency_symbol' => true,
],
'HU' => [ // Hungary
'swap_currency_symbol' => true,
],
'GL' => [
'swap_postal_code' => true,
],
'IE' => [ // Ireland
'thousand_separator' => ',',
'decimal_separator' => '.',
],
'IL' => [
'swap_postal_code' => true,
],
'IS' => [ // Iceland
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'IT' => [ // Italy
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'LT' => [ // Lithuania
'swap_currency_symbol' => true,
],
'LU' => [
'swap_postal_code' => true,
],
'MY' => [
'swap_postal_code' => true,
],
'MX' => [
'swap_postal_code' => true,
],
'NL' => [
'swap_postal_code' => true,
],
'PL' => [ // Poland
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'PT' => [ // Portugal
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'RO' => [ // Romania
'swap_currency_symbol' => true,
],
'SE' => [ // Sweden
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'SI' => [ // Slovenia
'swap_currency_symbol' => true,
],
'SK' => [ // Slovakia
'swap_currency_symbol' => true,
],
'UY' => [
'swap_postal_code' => true,
],
];
foreach ($countries as $code => $data) {
$country = Country::where('iso_3166_2', '=', $code)->first();
if (isset($data['swap_postal_code'])) {
$country->swap_postal_code = true;
}
if (isset($data['swap_currency_symbol'])) {
$country->swap_currency_symbol = true;
}
if (isset($data['thousand_separator'])) {
$country->thousand_separator = $data['thousand_separator'];
}
if (isset($data['decimal_separator'])) {
$country->decimal_separator = $data['decimal_separator'];
}
$country->save();
}
}
}

View File

@ -0,0 +1,71 @@
<?php
use App\Models\Currency;
class CurrenciesSeeder extends Seeder
{
public function run()
{
Eloquent::unguard();
$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' => 'South African 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' => '', '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' => '', 'precision' => '0', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Swiss Franc', 'code' => 'CHF', 'symbol' => '', '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' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Nigerian Naira', 'code' => 'NGN', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Argentine Peso', 'code' => 'ARS', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Bangladeshi Taka', 'code' => 'BDT', 'symbol' => 'Tk', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'United Arab Emirates Dirham', 'code' => 'AED', 'symbol' => 'DH ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Hong Kong Dollar', 'code' => 'HKD', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Indonesian Rupiah', 'code' => 'IDR', 'symbol' => 'Rp', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Mexican Peso', 'code' => 'MXN', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Egyptian Pound', 'code' => 'EGP', 'symbol' => 'E£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Colombian Peso', 'code' => 'COP', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'West African Franc', 'code' => 'XOF', 'symbol' => 'CFA ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Chinese Renminbi', 'code' => 'CNY', 'symbol' => 'RMB ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Rwandan Franc', 'code' => 'RWF', 'symbol' => 'RF ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Tanzanian Shilling', 'code' => 'TZS', 'symbol' => 'TSh ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Netherlands Antillean Guilder', 'code' => 'ANG', 'symbol' => '', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Trinidad and Tobago Dollar', 'code' => 'TTD', 'symbol' => 'TT$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'East Caribbean Dollar', 'code' => 'XCD', 'symbol' => 'EC$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Ghanaian Cedi', 'code' => 'GHS', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Bulgarian Lev', 'code' => 'BGN', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => '.'],
['name' => 'Aruban Florin', 'code' => 'AWG', 'symbol' => 'Afl. ', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => '.'],
['name' => 'Turkish Lira', 'code' => 'TRY', 'symbol' => 'TL ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Romanian New Leu', 'code' => 'RON', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Croatian Kuna', 'code' => 'HKR', 'symbol' => 'kn', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Saudi Riyal', 'code' => 'SAR', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
];
foreach ($currencies as $currency) {
$record = Currency::whereCode($currency['code'])->first();
if ($record) {
$record->name = $currency['name'];
$record->symbol = $currency['symbol'];
$record->thousand_separator = $currency['thousand_separator'];
$record->decimal_separator = $currency['decimal_separator'];
$record->save();
} else {
Currency::create($currency);
}
}
}
}

View File

@ -19,5 +19,9 @@ class DatabaseSeeder extends Seeder
$this->call('FontsSeeder');
$this->call('BanksSeeder');
$this->call('InvoiceStatusSeeder');
$this->call('CurrenciesSeeder');
$this->call('DateFormatsSeeder');
$this->call('InvoiceDesignsSeeder');
$this->call('PaymentTermsSeeder');
}
}

View File

@ -0,0 +1,102 @@
<?php
use App\Models\DateFormat;
use App\Models\DatetimeFormat;
class DateFormatsSeeder extends Seeder
{
public function run()
{
Eloquent::unguard();
// Date formats
$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-mm-dd', 'label' => '2013-03-10'],
['format' => 'd-m-Y', 'picker_format' => 'dd-mm-yyyy', 'label' => '20-03-2013'],
['format' => 'm/d/Y', 'picker_format' => 'mm/dd/yyyy', 'label' => '03/20/2013']
];
foreach ($formats as $format) {
$record = DateFormat::whereLabel($format['label'])->first();
if ($record) {
$record->format = $format['format'];
$record->picker_format = $format['picker_format'];
$record->save();
} else {
DateFormat::create($format);
}
}
// Date/time formats
$formats = [
[
'format' => 'd/M/Y g:i a',
'format_moment' => 'DD/MMM/YYYY h:mm:ss a',
'label' => '10/Mar/2013'
],
[
'format' => 'd-M-Y g:i a',
'format_moment' => 'DD-MMM-YYYY h:mm:ss a',
'label' => '10-Mar-2013'
],
[
'format' => 'd/F/Y g:i a',
'format_moment' => 'DD/MMMM/YYYY h:mm:ss a',
'label' => '10/March/2013'
],
[
'format' => 'd-F-Y g:i a',
'format_moment' => 'DD-MMMM-YYYY h:mm:ss a',
'label' => '10-March-2013'
],
[
'format' => 'M j, Y g:i a',
'format_moment' => 'MMM D, YYYY h:mm:ss a',
'label' => 'Mar 10, 2013 6:15 pm'
],
[
'format' => 'F j, Y g:i a',
'format_moment' => 'MMMM D, YYYY h:mm:ss a',
'label' => 'March 10, 2013 6:15 pm'
],
[
'format' => 'D M jS, Y g:i a',
'format_moment' => 'ddd MMM Do, YYYY h:mm:ss a',
'label' => 'Mon March 10th, 2013 6:15 pm'
],
[
'format' => 'Y-m-d g:i a',
'format_moment' => 'YYYY-MMM-DD h:mm:ss a',
'label' => '2013-03-10 6:15 pm'
],
[
'format' => 'd-m-Y g:i a',
'format_moment' => 'DD-MM-YYYY h:mm:ss a',
'label' => '20-03-2013 6:15 pm'
],
[
'format' => 'm/d/Y g:i a',
'format_moment' => 'MM/DD/YYYY h:mm:ss a',
'label' => '03/20/2013 6:15 pm'
]
];
foreach ($formats as $format) {
$record = DatetimeFormat::whereLabel($format['label'])->first();
if ($record) {
$record->format = $format['format'];
$record->format_moment = $format['format_moment'];
$record->save();
} else {
DatetimeFormat::create($format);
}
}
}
}

View File

@ -0,0 +1,43 @@
<?php
use App\Models\InvoiceDesign;
class InvoiceDesignsSeeder extends Seeder
{
public function run()
{
Eloquent::unguard();
$designs = [
'Clean',
'Bold',
'Modern',
'Plain',
'Business',
'Creative',
'Elegant',
'Hipster',
'Playful',
'Photo',
];
for ($i=0; $i<count($designs); $i++) {
$design = $designs[$i];
$fileName = storage_path() . '/templates/' . strtolower($design) . '.js';
if (file_exists($fileName)) {
$pdfmake = file_get_contents($fileName);
if ($pdfmake) {
$record = InvoiceDesign::whereName($design)->first();
if (!$record) {
$record = new InvoiceDesign;
$record->id = $i + 1;
$record->name = $design;
}
$record->pdfmake = $pdfmake;
$record->save();
}
}
}
}
}

View File

@ -14,16 +14,6 @@ class PaymentLibrariesSeeder extends Seeder
{
Eloquent::unguard();
$this->createGateways();
$this->createPaymentTerms();
$this->createDateFormats();
$this->createDatetimeFormats();
$this->createInvoiceDesigns();
$this->updateLocalization();
}
private function createGateways() {
$gateways = [
['name' => 'BeanStream', 'provider' => 'BeanStream', 'payment_library_id' => 2],
['name' => 'Psigate', 'provider' => 'Psigate', 'payment_library_id' => 2],
@ -32,7 +22,7 @@ class PaymentLibrariesSeeder extends Seeder
['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' => 'Neteller', 'provider' => 'Neteller', 'payment_library_id' => 2],
['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],
@ -71,334 +61,4 @@ class PaymentLibrariesSeeder extends Seeder
}
}
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' => 'South African 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' => '', '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' => '', 'precision' => '0', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Swiss Franc', 'code' => 'CHF', 'symbol' => '', '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' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Nigerian Naira', 'code' => 'NGN', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Argentine Peso', 'code' => 'ARS', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Bangladeshi Taka', 'code' => 'BDT', 'symbol' => 'Tk', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'United Arab Emirates Dirham', 'code' => 'AED', 'symbol' => 'DH ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Hong Kong Dollar', 'code' => 'HKD', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Indonesian Rupiah', 'code' => 'IDR', 'symbol' => 'Rp', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Mexican Peso', 'code' => 'MXN', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Egyptian Pound', 'code' => 'EGP', 'symbol' => 'E£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Colombian Peso', 'code' => 'COP', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'West African Franc', 'code' => 'XOF', 'symbol' => 'CFA ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Chinese Renminbi', 'code' => 'CNY', 'symbol' => 'RMB ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Rwandan Franc', 'code' => 'RWF', 'symbol' => 'RF ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Tanzanian Shilling', 'code' => 'TZS', 'symbol' => 'TSh ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Netherlands Antillean Guilder', 'code' => 'ANG', 'symbol' => '', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Trinidad and Tobago Dollar', 'code' => 'TTD', 'symbol' => 'TT$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'East Caribbean Dollar', 'code' => 'XCD', 'symbol' => 'EC$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Ghanaian Cedi', 'code' => 'GHS', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Bulgarian Lev', 'code' => 'BGN', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => '.'],
['name' => 'Aruban Florin', 'code' => 'AWG', 'symbol' => 'Afl. ', 'precision' => '2', 'thousand_separator' => ' ', 'decimal_separator' => '.'],
['name' => 'Turkish Lira', 'code' => 'TRY', 'symbol' => 'TL ', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Romanian New Leu', 'code' => 'RON', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
];
foreach ($currencies as $currency) {
$record = Currency::whereCode($currency['code'])->first();
if ($record) {
$record->name = $currency['name'];
$record->symbol = $currency['symbol'];
$record->thousand_separator = $currency['thousand_separator'];
$record->decimal_separator = $currency['decimal_separator'];
$record->save();
} else {
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-mm-dd', 'label' => '2013-03-10'],
['format' => 'd-m-Y', 'picker_format' => 'dd-mm-yyyy', 'label' => '20-03-2013'],
['format' => 'm/d/Y', 'picker_format' => 'mm/dd/yyyy', 'label' => '03/20/2013']
];
foreach ($formats as $format) {
$record = DateFormat::whereLabel($format['label'])->first();
if ($record) {
$record->format = $format['format'];
$record->picker_format = $format['picker_format'];
$record->save();
} else {
DateFormat::create($format);
}
}
}
private function createDatetimeFormats() {
$formats = [
[
'format' => 'd/M/Y g:i a',
'format_moment' => 'DD/MMM/YYYY h:mm:ss a',
'label' => '10/Mar/2013'
],
[
'format' => 'd-M-Y g:i a',
'format_moment' => 'DD-MMM-YYYY h:mm:ss a',
'label' => '10-Mar-2013'
],
[
'format' => 'd/F/Y g:i a',
'format_moment' => 'DD/MMMM/YYYY h:mm:ss a',
'label' => '10/March/2013'
],
[
'format' => 'd-F-Y g:i a',
'format_moment' => 'DD-MMMM-YYYY h:mm:ss a',
'label' => '10-March-2013'
],
[
'format' => 'M j, Y g:i a',
'format_moment' => 'MMM D, YYYY h:mm:ss a',
'label' => 'Mar 10, 2013 6:15 pm'
],
[
'format' => 'F j, Y g:i a',
'format_moment' => 'MMMM D, YYYY h:mm:ss a',
'label' => 'March 10, 2013 6:15 pm'
],
[
'format' => 'D M jS, Y g:i a',
'format_moment' => 'ddd MMM Do, YYYY h:mm:ss a',
'label' => 'Mon March 10th, 2013 6:15 pm'
],
[
'format' => 'Y-m-d g:i a',
'format_moment' => 'YYYY-MMM-DD h:mm:ss a',
'label' => '2013-03-10 6:15 pm'
],
[
'format' => 'd-m-Y g:i a',
'format_moment' => 'DD-MM-YYYY h:mm:ss a',
'label' => '20-03-2013 6:15 pm'
],
[
'format' => 'm/d/Y g:i a',
'format_moment' => 'MM/DD/YYYY h:mm:ss a',
'label' => '03/20/2013 6:15 pm'
]
];
foreach ($formats as $format) {
$record = DatetimeFormat::whereLabel($format['label'])->first();
if ($record) {
$record->format = $format['format'];
$record->format_moment = $format['format_moment'];
$record->save();
} else {
DatetimeFormat::create($format);
}
}
}
private function createInvoiceDesigns() {
$designs = [
'Clean',
'Bold',
'Modern',
'Plain',
'Business',
'Creative',
'Elegant',
'Hipster',
'Playful',
'Photo',
];
for ($i=0; $i<count($designs); $i++) {
$design = $designs[$i];
$fileName = storage_path() . '/templates/' . strtolower($design) . '.js';
if (file_exists($fileName)) {
$pdfmake = file_get_contents($fileName);
if ($pdfmake) {
$record = InvoiceDesign::whereName($design)->first();
if (!$record) {
$record = new InvoiceDesign;
$record->id = $i + 1;
$record->name = $design;
}
$record->pdfmake = $pdfmake;
$record->save();
}
}
}
}
private function updateLocalization() {
// Source: http://www.bitboost.com/ref/international-address-formats.html
// Source: https://en.wikipedia.org/wiki/Linguistic_issues_concerning_the_euro
$countries = [
'AR' => [
'swap_postal_code' => true,
],
'AT' => [ // Austria
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'BE' => [
'swap_postal_code' => true,
],
'BG' => [ // Belgium
'swap_currency_symbol' => true,
],
'CH' => [
'swap_postal_code' => true,
],
'CZ' => [ // Czech Republic
'swap_currency_symbol' => true,
],
'DE' => [ // Germany
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'DK' => [
'swap_postal_code' => true,
],
'EE' => [ // Estonia
'swap_currency_symbol' => true,
],
'ES' => [ // Spain
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'FI' => [ // Finland
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'FR' => [ // France
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'GR' => [ // Greece
'swap_currency_symbol' => true,
],
'HR' => [ // Croatia
'swap_currency_symbol' => true,
],
'HU' => [ // Hungary
'swap_currency_symbol' => true,
],
'GL' => [
'swap_postal_code' => true,
],
'IE' => [ // Ireland
'thousand_separator' => ',',
'decimal_separator' => '.',
],
'IL' => [
'swap_postal_code' => true,
],
'IS' => [ // Iceland
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'IT' => [ // Italy
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'LT' => [ // Lithuania
'swap_currency_symbol' => true,
],
'LU' => [
'swap_postal_code' => true,
],
'MY' => [
'swap_postal_code' => true,
],
'MX' => [
'swap_postal_code' => true,
],
'NL' => [
'swap_postal_code' => true,
],
'PL' => [ // Poland
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'PT' => [ // Portugal
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'RO' => [ // Romania
'swap_currency_symbol' => true,
],
'SE' => [ // Sweden
'swap_postal_code' => true,
'swap_currency_symbol' => true,
],
'SI' => [ // Slovenia
'swap_currency_symbol' => true,
],
'SK' => [ // Slovakia
'swap_currency_symbol' => true,
],
'UY' => [
'swap_postal_code' => true,
],
];
foreach ($countries as $code => $data) {
$country = Country::where('iso_3166_2', '=', $code)->first();
if (isset($data['swap_postal_code'])) {
$country->swap_postal_code = true;
}
if (isset($data['swap_currency_symbol'])) {
$country->swap_currency_symbol = true;
}
if (isset($data['thousand_separator'])) {
$country->thousand_separator = $data['thousand_separator'];
}
if (isset($data['decimal_separator'])) {
$country->decimal_separator = $data['decimal_separator'];
}
$country->save();
}
}
}

Some files were not shown because too many files have changed in this diff Show More