Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
David Bomba 2016-05-05 07:44:54 +10:00
commit dd4ea2ac17
50 changed files with 1950 additions and 270 deletions

138
.htaccess
View File

@ -6,3 +6,141 @@
# https://coderwall.com/p/erbaig/laravel-s-htaccess-to-remove-public-from-url # https://coderwall.com/p/erbaig/laravel-s-htaccess-to-remove-public-from-url
# RewriteRule ^(.*)$ public/$1 [L] # RewriteRule ^(.*)$ public/$1 [L]
</IfModule> </IfModule>
# https://github.com/h5bp/server-configs-apache/blob/master/dist/.htaccess
# ######################################################################
# # INTERNET EXPLORER #
# ######################################################################
# ----------------------------------------------------------------------
# | Iframes cookies |
# ----------------------------------------------------------------------
# Allow cookies to be set from iframes in Internet Explorer.
#
# https://msdn.microsoft.com/en-us/library/ms537343.aspx
# http://www.w3.org/TR/2000/CR-P3P-20001215/
<IfModule mod_headers.c>
Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""
</IfModule>
# ######################################################################
# # MEDIA TYPES AND CHARACTER ENCODINGS #
# ######################################################################
# ----------------------------------------------------------------------
# | Character encodings |
# ----------------------------------------------------------------------
# Serve all resources labeled as `text/html` or `text/plain`
# with the media type `charset` parameter set to `UTF-8`.
#
# https://httpd.apache.org/docs/current/mod/core.html#adddefaultcharset
AddDefaultCharset utf-8
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Serve the following file types with the media type `charset`
# parameter set to `UTF-8`.
#
# https://httpd.apache.org/docs/current/mod/mod_mime.html#addcharset
<IfModule mod_mime.c>
AddCharset utf-8 .atom \
.bbaw \
.css \
.geojson \
.js \
.json \
.jsonld \
.manifest \
.rdf \
.rss \
.topojson \
.vtt \
.webapp \
.webmanifest \
.xloc \
.xml
</IfModule>
# ######################################################################
# # WEB PERFORMANCE #
# ######################################################################
# ----------------------------------------------------------------------
# | Compression |
# ----------------------------------------------------------------------
<IfModule mod_deflate.c>
# Force compression for mangled headers.
# https://developer.yahoo.com/blogs/ydn/pushing-beyond-gzipping-25601.html
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
</IfModule>
</IfModule>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Map certain file types to the specified encoding type in order to
# make Apache serve them with the appropriate `Content-Encoding` HTTP
# response header (this will NOT make Apache compress them!).
# If the following file types wouldn't be served without the appropriate
# `Content-Enable` HTTP response header, client applications (e.g.:
# browsers) wouldn't know that they first need to uncompress the response,
# and thus, wouldn't be able to understand the content.
# http://httpd.apache.org/docs/current/mod/mod_mime.html#addencoding
<IfModule mod_mime.c>
AddEncoding gzip svgz
</IfModule>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Compress all output labeled with one of the following media types.
# IMPORTANT: For Apache versions below 2.3.7 you don't need to enable
# `mod_filter` and can remove the `<IfModule mod_filter.c>` & `</IfModule>`
# lines as `AddOutputFilterByType` is still in the core directives.
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE "application/atom+xml" \
"application/javascript" \
"application/json" \
"application/ld+json" \
"application/manifest+json" \
"application/rdf+xml" \
"application/rss+xml" \
"application/schema+json" \
"application/vnd.geo+json" \
"application/vnd.ms-fontobject" \
"application/x-font-ttf" \
"application/x-web-app-manifest+json" \
"application/xhtml+xml" \
"application/xml" \
"font/opentype" \
"image/svg+xml" \
"image/x-icon" \
"text/cache-manifest" \
"text/css" \
"text/html" \
"text/javascript" \
"text/plain" \
"text/vtt" \
"text/x-component" \
"text/xml"
</IfModule>
</IfModule>

View File

@ -45,7 +45,8 @@ before_script:
- php artisan key:generate --no-interaction - php artisan key:generate --no-interaction
- sed -i 's/APP_ENV=production/APP_ENV=development/g' .env - sed -i 's/APP_ENV=production/APP_ENV=development/g' .env
- sed -i 's/APP_DEBUG=false/APP_DEBUG=true/g' .env - sed -i 's/APP_DEBUG=false/APP_DEBUG=true/g' .env
- sed -i 's/REQUIRE_HTTPS=false/NINJA_DEV=true/g' .env - sed -i '$a NINJA_DEV=true' .env
- sed -i '$a TRAVIS=true' .env
# create the database and user # create the database and user
- mysql -u root -e "create database IF NOT EXISTS ninja;" - mysql -u root -e "create database IF NOT EXISTS ninja;"
- mysql -u root -e "GRANT ALL PRIVILEGES ON ninja.* To 'ninja'@'localhost' IDENTIFIED BY 'ninja'; FLUSH PRIVILEGES;" - mysql -u root -e "GRANT ALL PRIVILEGES ON ninja.* To 'ninja'@'localhost' IDENTIFIED BY 'ninja'; FLUSH PRIVILEGES;"

View File

@ -0,0 +1,172 @@
<?php namespace App\Console\Commands;
use stdClass;
use Auth;
use DB;
use Utils;
use Artisan;
use Illuminate\Console\Command;
use Faker\Factory;
use App\Models\User;
use App\Ninja\Repositories\ClientRepository;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\VendorRepository;
use App\Ninja\Repositories\ExpenseRepository;
class CreateTestData extends Command
{
//protected $name = 'ninja:create-test-data';
protected $description = 'Create Test Data';
protected $signature = 'ninja:create-test-data {count=1}';
protected $token;
public function __construct(
ClientRepository $clientRepo,
InvoiceRepository $invoiceRepo,
PaymentRepository $paymentRepo,
VendorRepository $vendorRepo,
ExpenseRepository $expenseRepo)
{
parent::__construct();
$this->faker = Factory::create();
$this->clientRepo = $clientRepo;
$this->invoiceRepo = $invoiceRepo;
$this->paymentRepo = $paymentRepo;
$this->vendorRepo = $vendorRepo;
$this->expenseRepo = $expenseRepo;
}
public function fire()
{
if (Utils::isNinjaProd()) {
return false;
}
$this->info(date('Y-m-d').' Running CreateTestData...');
Auth::loginUsingId(1);
$this->count = $this->argument('count');
$this->createClients();
$this->createVendors();
$this->info('Done');
}
private function createClients()
{
for ($i=0; $i<$this->count; $i++) {
$data = [
'name' => $this->faker->name,
'address1' => $this->faker->streetAddress,
'address2' => $this->faker->secondaryAddress,
'city' => $this->faker->city,
'state' => $this->faker->state,
'postal_code' => $this->faker->postcode,
'contacts' => [[
'first_name' => $this->faker->firstName,
'last_name' => $this->faker->lastName,
'email' => $this->faker->safeEmail,
'phone' => $this->faker->phoneNumber,
]]
];
$client = $this->clientRepo->save($data);
$this->info('Client: ' . $client->name);
$this->createInvoices($client);
}
}
private function createInvoices($client)
{
for ($i=0; $i<$this->count; $i++) {
$data = [
'client_id' => $client->id,
'invoice_items' => [[
'product_key' => $this->faker->word,
'qty' => $this->faker->randomDigit + 1,
'cost' => $this->faker->randomFloat(2, 1, 10),
'notes' => $this->faker->text($this->faker->numberBetween(50, 300))
]]
];
$invoice = $this->invoiceRepo->save($data);
$this->info('Invoice: ' . $invoice->invoice_number);
$this->createPayment($client, $invoice);
}
}
private function createPayment($client, $invoice)
{
$data = [
'invoice_id' => $invoice->id,
'client_id' => $client->id,
'amount' => $this->faker->randomFloat(2, 0, $invoice->amount)
];
$payment = $this->paymentRepo->save($data);
$this->info('Payment: ' . $payment->amount);
}
private function createVendors()
{
for ($i=0; $i<$this->count; $i++) {
$data = [
'name' => $this->faker->name,
'address1' => $this->faker->streetAddress,
'address2' => $this->faker->secondaryAddress,
'city' => $this->faker->city,
'state' => $this->faker->state,
'postal_code' => $this->faker->postcode,
'vendor_contacts' => [[
'first_name' => $this->faker->firstName,
'last_name' => $this->faker->lastName,
'email' => $this->faker->safeEmail,
'phone' => $this->faker->phoneNumber,
]]
];
$vendor = $this->vendorRepo->save($data);
$this->info('Vendor: ' . $vendor->name);
$this->createExpense($vendor);
}
}
private function createExpense($vendor)
{
for ($i=0; $i<$this->count; $i++) {
$data = [
'vendor_id' => $vendor->id,
'amount' => $this->faker->randomFloat(2, 1, 10),
'expense_date' => null,
'public_notes' => null,
];
$expense = $this->expenseRepo->save($data);
$this->info('Expense: ' . $expense->amount);
}
}
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

@ -17,6 +17,7 @@ class Kernel extends ConsoleKernel
'App\Console\Commands\ResetData', 'App\Console\Commands\ResetData',
'App\Console\Commands\CheckData', 'App\Console\Commands\CheckData',
'App\Console\Commands\PruneData', 'App\Console\Commands\PruneData',
'App\Console\Commands\CreateTestData',
'App\Console\Commands\SendRenewalInvoices', 'App\Console\Commands\SendRenewalInvoices',
'App\Console\Commands\ChargeRenewalInvoices', 'App\Console\Commands\ChargeRenewalInvoices',
'App\Console\Commands\SendReminders', 'App\Console\Commands\SendReminders',

View File

@ -39,7 +39,7 @@ class Handler extends ExceptionHandler {
return false; return false;
} }
if (Utils::isNinja()) { if (Utils::isNinja() && ! Utils::isTravis()) {
Utils::logError(Utils::getErrorString($e)); Utils::logError(Utils::getErrorString($e));
return false; return false;
} else { } else {

View File

@ -90,9 +90,22 @@ class BaseAPIController extends Controller
$transformerClass = EntityModel::getTransformerName($this->entityType); $transformerClass = EntityModel::getTransformerName($this->entityType);
$transformer = new $transformerClass(Auth::user()->account, Input::get('serializer')); $transformer = new $transformerClass(Auth::user()->account, Input::get('serializer'));
$include = $transformer->getDefaultIncludes(); $includes = $transformer->getDefaultIncludes();
$include = $this->getRequestIncludes($include); $includes = $this->getRequestIncludes($includes);
$query->with($include);
$query->with($includes);
if ($updatedAt = Input::get('updated_at')) {
$updatedAt = date('Y-m-d H:i:s', $updatedAt);
$query->where(function($query) use ($includes, $updatedAt) {
$query->where('updated_at', '>=', $updatedAt);
foreach ($includes as $include) {
$query->orWhereHas($include, function($query) use ($updatedAt) {
$query->where('updated_at', '>=', $updatedAt);
});
}
});
}
if ($clientPublicId = Input::get('client_id')) { if ($clientPublicId = Input::get('client_id')) {
$filter = function($query) use ($clientPublicId) { $filter = function($query) use ($clientPublicId) {
@ -156,7 +169,7 @@ class BaseAPIController extends Controller
if (Utils::isNinjaDev()) { if (Utils::isNinjaDev()) {
$count = count(\DB::getQueryLog()); $count = count(\DB::getQueryLog());
Log::info(Request::method() . ' - ' . Request::url() . ": $count queries"); Log::info(Request::method() . ' - ' . Request::url() . ": $count queries");
//Log::info(print_r(\DB::getQueryLog(), true)); Log::info(json_encode(\DB::getQueryLog()));
} }
$index = Request::get('index') ?: 'data'; $index = Request::get('index') ?: 'data';
@ -193,23 +206,19 @@ class BaseAPIController extends Controller
protected function getRequestIncludes($data) protected function getRequestIncludes($data)
{ {
$data[] = 'user';
$included = Request::get('include'); $included = Request::get('include');
$included = explode(',', $included); $included = explode(',', $included);
foreach ($included as $include) { foreach ($included as $include) {
if ($include == 'invoices') { if ($include == 'invoices') {
$data[] = 'invoices.invoice_items'; $data[] = 'invoices.invoice_items';
$data[] = 'invoices.user'; } elseif ($include == 'client') {
$data[] = 'client.contacts';
} elseif ($include == 'clients') { } elseif ($include == 'clients') {
$data[] = 'clients.contacts'; $data[] = 'clients.contacts';
$data[] = 'clients.user';
} elseif ($include == 'vendors') { } elseif ($include == 'vendors') {
$data[] = 'vendors.vendorcontacts'; $data[] = 'vendors.vendor_contacts';
$data[] = 'vendors.user'; } elseif ($include) {
}
elseif ($include) {
$data[] = $include; $data[] = $include;
} }
} }

View File

@ -143,20 +143,13 @@ class ClientApiController extends BaseAPIController
* ) * )
*/ */
public function destroy($publicId) public function destroy(UpdateClientRequest $request)
{ {
$client = Client::scope($publicId)->withTrashed()->first(); $client = $request->entity();
$this->clientRepo->delete($client); $this->clientRepo->delete($client);
$client = Client::scope($publicId) return $this->itemResponse($client);
->with('country', 'contacts', 'industry', 'size', 'currency')
->withTrashed()
->first();
$transformer = new ClientTransformer(Auth::user()->account, Input::get('serializer'));
$data = $this->createItem($client, $transformer, ENTITY_CLIENT);
return $this->response($data);
} }
} }

View File

@ -30,6 +30,7 @@ class ExpenseApiController extends BaseAPIController
{ {
$expenses = Expense::scope() $expenses = Expense::scope()
->withTrashed() ->withTrashed()
->with('client', 'invoice', 'vendor')
->orderBy('created_at','desc'); ->orderBy('created_at','desc');
return $this->listResponse($expenses); return $this->listResponse($expenses);

View File

@ -74,7 +74,7 @@ class ExpenseController extends BaseController
public function create(ExpenseRequest $request) public function create(ExpenseRequest $request)
{ {
if ($request->vendor_id != 0) { if ($request->vendor_id != 0) {
$vendor = Vendor::scope($request->vendor_id)->with('vendorcontacts')->firstOrFail(); $vendor = Vendor::scope($request->vendor_id)->with('vendor_contacts')->firstOrFail();
} else { } else {
$vendor = null; $vendor = null;
} }
@ -85,7 +85,7 @@ class ExpenseController extends BaseController
'method' => 'POST', 'method' => 'POST',
'url' => 'expenses', 'url' => 'expenses',
'title' => trans('texts.new_expense'), 'title' => trans('texts.new_expense'),
'vendors' => Vendor::scope()->with('vendorcontacts')->orderBy('name')->get(), 'vendors' => Vendor::scope()->with('vendor_contacts')->orderBy('name')->get(),
'vendor' => $vendor, 'vendor' => $vendor,
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
'clientPublicId' => $request->client_id, 'clientPublicId' => $request->client_id,
@ -124,7 +124,7 @@ class ExpenseController extends BaseController
'url' => 'expenses/'.$expense->public_id, 'url' => 'expenses/'.$expense->public_id,
'title' => 'Edit Expense', 'title' => 'Edit Expense',
'actions' => $actions, 'actions' => $actions,
'vendors' => Vendor::scope()->with('vendorcontacts')->orderBy('name')->get(), 'vendors' => Vendor::scope()->with('vendor_contacts')->orderBy('name')->get(),
'vendorPublicId' => $expense->vendor ? $expense->vendor->public_id : null, 'vendorPublicId' => $expense->vendor ? $expense->vendor->public_id : null,
'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
'clientPublicId' => $expense->client ? $expense->client->public_id : null, 'clientPublicId' => $expense->client ? $expense->client->public_id : null,

View File

@ -164,12 +164,12 @@ class ExportController extends BaseController
if ($request->input(ENTITY_VENDOR)) { if ($request->input(ENTITY_VENDOR)) {
$data['clients'] = Vendor::scope() $data['clients'] = Vendor::scope()
->with('user', 'vendorcontacts', 'country') ->with('user', 'vendor_contacts', 'country')
->withArchived() ->withArchived()
->get(); ->get();
$data['vendor_contacts'] = VendorContact::scope() $data['vendor_contacts'] = VendorContact::scope()
->with('user', 'vendor.contacts') ->with('user', 'vendor.vendor_contacts')
->withTrashed() ->withTrashed()
->get(); ->get();

View File

@ -61,7 +61,7 @@ class InvoiceApiController extends BaseAPIController
{ {
$invoices = Invoice::scope() $invoices = Invoice::scope()
->withTrashed() ->withTrashed()
->with('invoice_items') ->with('invoice_items', 'client')
->orderBy('created_at', 'desc'); ->orderBy('created_at', 'desc');
return $this->listResponse($invoices); return $this->listResponse($invoices);
@ -359,18 +359,13 @@ class InvoiceApiController extends BaseAPIController
* ) * )
*/ */
public function destroy($publicId) public function destroy(UpdateInvoiceAPIRequest $request)
{ {
$data['public_id'] = $publicId; $invoice = $request->entity();
$invoice = Invoice::scope($publicId)->firstOrFail();
$this->invoiceRepo->delete($invoice); $this->invoiceRepo->delete($invoice);
$transformer = new InvoiceTransformer(\Auth::user()->account, Input::get('serializer')); return $this->itemResponse($invoice);
$data = $this->createItem($invoice, $transformer, 'invoice');
return $this->response($data);
} }
} }

View File

@ -49,7 +49,7 @@ class PaymentApiController extends BaseAPIController
{ {
$payments = Payment::scope() $payments = Payment::scope()
->withTrashed() ->withTrashed()
->with(['client.contacts', 'invitation', 'user', 'invoice']) ->with(['invoice'])
->orderBy('created_at', 'desc'); ->orderBy('created_at', 'desc');
return $this->listResponse($payments); return $this->listResponse($payments);
@ -145,17 +145,13 @@ class PaymentApiController extends BaseAPIController
* ) * )
*/ */
public function destroy($publicId) public function destroy(UpdatePaymentRequest $request)
{ {
$payment = $request->entity();
$payment = Payment::scope($publicId)->withTrashed()->first(); $this->clientRepo->delete($payment);
$invoiceId = $payment->invoice->public_id;
$this->paymentRepo->delete($payment); return $this->itemResponse($payment);
$transformer = new PaymentTransformer(\Auth::user()->account, Input::get('serializer'));
$data = $this->createItem($payment, $transformer, 'invoice');
return $this->response($data);
} }
} }

View File

@ -551,7 +551,8 @@ class PaymentController extends BaseController
$payment = $this->paymentService->createPayment($invitation, $accountGateway, $token, $payerId); $payment = $this->paymentService->createPayment($invitation, $accountGateway, $token, $payerId);
Session::flash('message', trans('texts.applied_payment')); Session::flash('message', trans('texts.applied_payment'));
} else { } else {
Session::flash('error', Input::get('message')); $message = Input::get('message') . ': ' . Input::get('invalid_fields');
Session::flash('error', $message);
} }
return Redirect::to($invitation->getLink()); return Redirect::to($invitation->getLink());
} elseif (method_exists($gateway, 'completePurchase') } elseif (method_exists($gateway, 'completePurchase')

View File

@ -81,7 +81,7 @@ class VendorApiController extends BaseAPIController
$vendor = $this->vendorRepo->save($request->input()); $vendor = $this->vendorRepo->save($request->input());
$vendor = Vendor::scope($vendor->public_id) $vendor = Vendor::scope($vendor->public_id)
->with('country', 'vendorcontacts', 'industry', 'size', 'currency') ->with('country', 'vendor_contacts', 'industry', 'size', 'currency')
->first(); ->first();
return $this->itemResponse($vendor); return $this->itemResponse($vendor);

View File

@ -1,30 +0,0 @@
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
use Illuminate\Validation\Factory;
class CreatePaymentTermRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'num_days' => 'required',
'name' => 'required',
];
}
}

View File

@ -1,30 +0,0 @@
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
use Illuminate\Validation\Factory;
class UpdateExpenseRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'amount' => 'required|positive',
];
}
}

View File

@ -9,8 +9,8 @@ class VendorRequest extends EntityRequest {
$vendor = parent::entity(); $vendor = parent::entity();
// eager load the contacts // eager load the contacts
if ($vendor && ! count($vendor->vendorcontacts)) { if ($vendor && ! count($vendor->vendor_contacts)) {
$vendor->load('vendorcontacts'); $vendor->load('vendor_contacts');
} }
return $vendor; return $vendor;

View File

@ -2,6 +2,8 @@
// https://github.com/denvertimothy/OFX // https://github.com/denvertimothy/OFX
use Utils;
use Log;
use SimpleXMLElement; use SimpleXMLElement;
class OFX class OFX
@ -21,13 +23,19 @@ class OFX
$c = curl_init(); $c = curl_init();
curl_setopt($c, CURLOPT_URL, $this->bank->url); curl_setopt($c, CURLOPT_URL, $this->bank->url);
curl_setopt($c, CURLOPT_POST, 1); curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/x-ofx')); // User-Agent: http://www.ofxhome.com/ofxforum/viewtopic.php?pid=108091#p108091
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/x-ofx', 'User-Agent: httpclient'));
curl_setopt($c, CURLOPT_POSTFIELDS, $this->request); curl_setopt($c, CURLOPT_POSTFIELDS, $this->request);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$this->response = curl_exec($c); $this->response = curl_exec($c);
//print_r($this->response);
//\Log::info(print_r($this->response, true)); if (Utils::isNinjaDev()) {
Log::info(print_r($this->response, true));
}
curl_close($c); curl_close($c);
$tmp = explode('<OFX>', $this->response); $tmp = explode('<OFX>', $this->response);
$this->responseHeader = $tmp[0]; $this->responseHeader = $tmp[0];
$this->responseBody = '<OFX>'.$tmp[1]; $this->responseBody = '<OFX>'.$tmp[1];
@ -35,14 +43,15 @@ class OFX
public function xml() public function xml()
{ {
$xml = $this->responseBody; $xml = $this->responseBody;
self::closeTags($xml); $xml = self::closeTags($xml);
$x = new SimpleXMLElement($xml); $x = new SimpleXMLElement($xml);
return $x; return $x;
} }
public static function closeTags(&$x) public static function closeTags($x)
{ {
$x = preg_replace('/(<([^<\/]+)>)(?!.*?<\/\2>)([^<]+)/', '\1\3</\2>', $x); $x = preg_replace('/\s+/', '', $x);
return preg_replace('/(<([^<\/]+)>)(?!.*?<\/\2>)([^<]+)/', '\1\3</\2>', $x);
} }
} }
@ -224,3 +233,4 @@ class Account
} }
} }
} }

View File

@ -51,6 +51,11 @@ class Utils
return php_sapi_name() == 'cli'; return php_sapi_name() == 'cli';
} }
public static function isTravis()
{
return env('TRAVIS') == 'true';
}
public static function isNinja() public static function isNinja()
{ {
return self::isNinjaProd() || self::isNinjaDev(); return self::isNinjaProd() || self::isNinjaDev();

View File

@ -19,6 +19,11 @@ class InvoiceItem extends EntityModel
return $this->belongsTo('App\Models\Invoice'); return $this->belongsTo('App\Models\Invoice');
} }
public function user()
{
return $this->belongsTo('App\Models\User')->withTrashed();
}
public function product() public function product()
{ {
return $this->belongsTo('App\Models\Product'); return $this->belongsTo('App\Models\Product');

View File

@ -26,6 +26,11 @@ class Product extends EntityModel
return Product::scope()->where('product_key', '=', $key)->first(); return Product::scope()->where('product_key', '=', $key)->first();
} }
public function user()
{
return $this->belongsTo('App\Models\User')->withTrashed();
}
public function default_tax_rate() public function default_tax_rate()
{ {
return $this->belongsTo('App\Models\TaxRate'); return $this->belongsTo('App\Models\TaxRate');

View File

@ -17,4 +17,9 @@ class TaxRate extends EntityModel
{ {
return ENTITY_TAX_RATE; return ENTITY_TAX_RATE;
} }
public function user()
{
return $this->belongsTo('App\Models\User')->withTrashed();
}
} }

View File

@ -95,7 +95,7 @@ class Vendor extends EntityModel
return $this->hasMany('App\Models\Payment'); return $this->hasMany('App\Models\Payment');
} }
public function vendorContacts() public function vendor_contacts()
{ {
return $this->hasMany('App\Models\VendorContact'); return $this->hasMany('App\Models\VendorContact');
} }
@ -143,7 +143,7 @@ class Vendor extends EntityModel
$contact->fill($data); $contact->fill($data);
$contact->is_primary = $isPrimary; $contact->is_primary = $isPrimary;
return $this->vendorContacts()->save($contact); return $this->vendor_contacts()->save($contact);
} }
public function getRoute() public function getRoute()

View File

@ -16,7 +16,7 @@ class VendorRepository extends BaseRepository
public function all() public function all()
{ {
return Vendor::scope() return Vendor::scope()
->with('user', 'vendorcontacts', 'country') ->with('user', 'vendor_contacts', 'country')
->withTrashed() ->withTrashed()
->where('is_deleted', '=', false) ->where('is_deleted', '=', false)
->get(); ->get();
@ -71,7 +71,7 @@ class VendorRepository extends BaseRepository
} elseif (!$publicId || $publicId == '-1') { } elseif (!$publicId || $publicId == '-1') {
$vendor = Vendor::createNew(); $vendor = Vendor::createNew();
} else { } else {
$vendor = Vendor::scope($publicId)->with('vendorcontacts')->firstOrFail(); $vendor = Vendor::scope($publicId)->with('vendor_contacts')->firstOrFail();
\Log::warning('Entity not set in vendor repo save'); \Log::warning('Entity not set in vendor repo save');
} }
@ -79,7 +79,7 @@ class VendorRepository extends BaseRepository
$vendor->save(); $vendor->save();
$first = true; $first = true;
$vendorcontacts = isset($data['vendorcontact']) ? [$data['vendorcontact']] : $data['vendorcontacts']; $vendorcontacts = isset($data['vendor_contact']) ? [$data['vendor_contact']] : $data['vendor_contacts'];
foreach ($vendorcontacts as $vendorcontact) { foreach ($vendorcontacts as $vendorcontact) {
$vendorcontact = $vendor->addVendorContact($vendorcontact, $first); $vendorcontact = $vendor->addVendorContact($vendorcontact, $first);

View File

@ -14,12 +14,12 @@ class AccountTransformer extends EntityTransformer
'users', 'users',
'products', 'products',
'taxRates', 'taxRates',
'payments'
]; ];
protected $availableIncludes = [ protected $availableIncludes = [
'clients', 'clients',
'invoices', 'invoices',
'payments',
]; ];
public function includeUsers(Account $account) public function includeUsers(Account $account)

View File

@ -47,7 +47,7 @@ class ClientTransformer extends EntityTransformer
protected $availableIncludes = [ protected $availableIncludes = [
'invoices', 'invoices',
'credits', 'credits',
'expenses', //'expenses',
]; ];
public function includeContacts(Client $client) public function includeContacts(Client $client)
@ -77,13 +77,11 @@ class ClientTransformer extends EntityTransformer
public function transform(Client $client) public function transform(Client $client)
{ {
return [ return array_merge($this->getDefaults($client), [
'id' => (int) $client->public_id, 'id' => (int) $client->public_id,
'name' => $client->name, 'name' => $client->name,
'balance' => (float) $client->balance, 'balance' => (float) $client->balance,
'paid_to_date' => (float) $client->paid_to_date, 'paid_to_date' => (float) $client->paid_to_date,
'user_id' => (int) $client->user->public_id + 1,
'account_key' => $this->account->account_key,
'updated_at' => $this->getTimestamp($client->updated_at), 'updated_at' => $this->getTimestamp($client->updated_at),
'archived_at' => $this->getTimestamp($client->deleted_at), 'archived_at' => $this->getTimestamp($client->deleted_at),
'address1' => $client->address1, 'address1' => $client->address1,
@ -106,6 +104,6 @@ class ClientTransformer extends EntityTransformer
'currency_id' => (int) $client->currency_id, 'currency_id' => (int) $client->currency_id,
'custom_value1' => $client->custom_value1, 'custom_value1' => $client->custom_value1,
'custom_value2' => $client->custom_value2, 'custom_value2' => $client->custom_value2,
]; ]);
} }
} }

View File

@ -8,7 +8,7 @@ class ContactTransformer extends EntityTransformer
{ {
public function transform(Contact $contact) public function transform(Contact $contact)
{ {
return [ return array_merge($this->getDefaults($contact), [
'id' => (int) $contact->public_id, 'id' => (int) $contact->public_id,
'first_name' => $contact->first_name, 'first_name' => $contact->first_name,
'last_name' => $contact->last_name, 'last_name' => $contact->last_name,
@ -18,8 +18,7 @@ class ContactTransformer extends EntityTransformer
'is_primary' => (bool) $contact->is_primary, 'is_primary' => (bool) $contact->is_primary,
'phone' => $contact->phone, 'phone' => $contact->phone,
'last_login' => $contact->last_login, 'last_login' => $contact->last_login,
'account_key' => $this->account->account_key,
'send_invoice' => (bool) $contact->send_invoice, 'send_invoice' => (bool) $contact->send_invoice,
]; ]);
} }
} }

View File

@ -8,17 +8,16 @@ class CreditTransformer extends EntityTransformer
{ {
public function transform(Credit $credit) public function transform(Credit $credit)
{ {
return [ return array_merge($this->getDefaults($credit), [
'id' => (int) $credit->public_id, 'id' => (int) $credit->public_id,
'amount' => (float) $credit->amount, 'amount' => (float) $credit->amount,
'balance' => (float) $credit->balance, 'balance' => (float) $credit->balance,
'updated_at' => $this->getTimestamp($credit->updated_at), 'updated_at' => $this->getTimestamp($credit->updated_at),
'archived_at' => $this->getTimestamp($credit->deleted_at), 'archived_at' => $this->getTimestamp($credit->deleted_at),
'is_deleted' => (bool) $credit->is_deleted, 'is_deleted' => (bool) $credit->is_deleted,
'account_key' => $this->account->account_key,
'credit_date' => $credit->credit_date, 'credit_date' => $credit->credit_date,
'credit_number' => $credit->credit_number, 'credit_number' => $credit->credit_number,
'private_notes' => $credit->private_notes, 'private_notes' => $credit->private_notes,
]; ]);
} }
} }

View File

@ -8,14 +8,12 @@ class DocumentTransformer extends EntityTransformer
{ {
public function transform(Document $document) public function transform(Document $document)
{ {
return array_merge($this->getDefaults($document), [
return [
'id' => (int) $document->public_id, 'id' => (int) $document->public_id,
'name' => $document->name, 'name' => $document->name,
'account_key' => $this->account->account_key,
'type' => $document->type, 'type' => $document->type,
'invoice_id' => isset($document->invoice->public_id) ? (int) $document->invoice->public_id : null, 'invoice_id' => isset($document->invoice->public_id) ? (int) $document->invoice->public_id : null,
'expense_id' => isset($document->expense->public_id) ? (int) $document->expense->public_id : null, 'expense_id' => isset($document->expense->public_id) ? (int) $document->expense->public_id : null,
]; ]);
} }
} }

View File

@ -1,5 +1,6 @@
<?php namespace App\Ninja\Transformers; <?php namespace App\Ninja\Transformers;
use Auth;
use App\Models\Account; use App\Models\Account;
use App\Models\Client; use App\Models\Client;
use League\Fractal\TransformerAbstract; use League\Fractal\TransformerAbstract;
@ -42,4 +43,18 @@ class EntityTransformer extends TransformerAbstract
{ {
return $this->defaultIncludes; return $this->defaultIncludes;
} }
protected function getDefaults($entity)
{
$data = [
'account_key' => $this->account->account_key,
'is_owner' => (bool) Auth::user()->owns($entity),
];
if ($entity->relationLoaded('user')) {
$data['user_id'] = (int) $entity->user->public_id + 1;
}
return $data;
}
} }

View File

@ -15,7 +15,7 @@ class ExpenseTransformer extends EntityTransformer
public function transform(Expense $expense) public function transform(Expense $expense)
{ {
return [ return array_merge($this->getDefaults($expense), [
'id' => (int) $expense->public_id, 'id' => (int) $expense->public_id,
'private_notes' => $expense->private_notes, 'private_notes' => $expense->private_notes,
'public_notes' => $expense->public_notes, 'public_notes' => $expense->public_notes,
@ -25,7 +25,6 @@ class ExpenseTransformer extends EntityTransformer
'transaction_id' => $expense->transaction_id, 'transaction_id' => $expense->transaction_id,
'bank_id' => $expense->bank_id, 'bank_id' => $expense->bank_id,
'expense_currency_id' => (int) $expense->expense_currency_id, 'expense_currency_id' => (int) $expense->expense_currency_id,
'account_key' => $this->account->account_key,
'amount' => (float) $expense->amount, 'amount' => (float) $expense->amount,
'expense_date' => $expense->expense_date, 'expense_date' => $expense->expense_date,
'exchange_rate' => (float) $expense->exchange_rate, 'exchange_rate' => (float) $expense->exchange_rate,
@ -34,6 +33,6 @@ class ExpenseTransformer extends EntityTransformer
'client_id' => $this->client ? $this->client->public_id : (isset($expense->client->public_id) ? (int) $expense->client->public_id : null), 'client_id' => $this->client ? $this->client->public_id : (isset($expense->client->public_id) ? (int) $expense->client->public_id : null),
'invoice_id' => isset($expense->invoice->public_id) ? (int) $expense->invoice->public_id : null, 'invoice_id' => isset($expense->invoice->public_id) ? (int) $expense->invoice->public_id : null,
'vendor_id' => isset($expense->vendor->public_id) ? (int) $expense->vendor->public_id : null, 'vendor_id' => isset($expense->vendor->public_id) ? (int) $expense->vendor->public_id : null,
]; ]);
} }
} }

View File

@ -8,11 +8,9 @@ class InvoiceItemTransformer extends EntityTransformer
{ {
public function transform(InvoiceItem $item) public function transform(InvoiceItem $item)
{ {
return [ return array_merge($this->getDefaults($item), [
'id' => (int) $item->public_id, 'id' => (int) $item->public_id,
'product_key' => $item->product_key, 'product_key' => $item->product_key,
'account_key' => $this->account->account_key,
'user_id' => (int) $item->user_id,
'updated_at' => $this->getTimestamp($item->updated_at), 'updated_at' => $this->getTimestamp($item->updated_at),
'archived_at' => $this->getTimestamp($item->deleted_at), 'archived_at' => $this->getTimestamp($item->deleted_at),
'product_key' => $item->product_key, 'product_key' => $item->product_key,
@ -23,6 +21,6 @@ class InvoiceItemTransformer extends EntityTransformer
'tax_rate1' => (float) $item->tax_rate1, 'tax_rate1' => (float) $item->tax_rate1,
'tax_name2' => $item->tax_name2 ? $item->tax_name1 : '', 'tax_name2' => $item->tax_name2 ? $item->tax_name1 : '',
'tax_rate2' => (float) $item->tax_rate2, 'tax_rate2' => (float) $item->tax_rate2,
]; ]);
} }
} }

View File

@ -28,7 +28,7 @@ class InvoiceTransformer extends EntityTransformer
'invitations', 'invitations',
'payments', 'payments',
'client', 'client',
'expenses', //'expenses',
]; ];
public function __construct($account = null, $serializer = null, $client = null) public function __construct($account = null, $serializer = null, $client = null)
@ -71,7 +71,7 @@ class InvoiceTransformer extends EntityTransformer
public function transform(Invoice $invoice) public function transform(Invoice $invoice)
{ {
return [ return array_merge($this->getDefaults($invoice), [
'id' => (int) $invoice->public_id, 'id' => (int) $invoice->public_id,
'amount' => (float) $invoice->amount, 'amount' => (float) $invoice->amount,
'balance' => (float) $invoice->balance, 'balance' => (float) $invoice->balance,
@ -105,8 +105,6 @@ class InvoiceTransformer extends EntityTransformer
'partial' => (float) $invoice->partial, 'partial' => (float) $invoice->partial,
'has_tasks' => (bool) $invoice->has_tasks, 'has_tasks' => (bool) $invoice->has_tasks,
'auto_bill' => (bool) $invoice->auto_bill, 'auto_bill' => (bool) $invoice->auto_bill,
'account_key' => $this->account->account_key,
'user_id' => (int) $invoice->user->public_id + 1,
'custom_value1' => (float) $invoice->custom_value1, 'custom_value1' => (float) $invoice->custom_value1,
'custom_value2' => (float) $invoice->custom_value2, 'custom_value2' => (float) $invoice->custom_value2,
'custom_taxes1' => (bool) $invoice->custom_taxes1, 'custom_taxes1' => (bool) $invoice->custom_taxes1,
@ -115,6 +113,6 @@ class InvoiceTransformer extends EntityTransformer
'quote_invoice_id' => (int) $invoice->quote_invoice_id, 'quote_invoice_id' => (int) $invoice->quote_invoice_id,
'custom_text_value1' => $invoice->custom_text_value1, 'custom_text_value1' => $invoice->custom_text_value1,
'custom_text_value2' => $invoice->custom_text_value2, 'custom_text_value2' => $invoice->custom_text_value2,
]; ]);
} }
} }

View File

@ -47,11 +47,9 @@ class PaymentTransformer extends EntityTransformer
public function transform(Payment $payment) public function transform(Payment $payment)
{ {
return [ return array_merge($this->getDefaults($payment), [
'id' => (int) $payment->public_id, 'id' => (int) $payment->public_id,
'amount' => (float) $payment->amount, 'amount' => (float) $payment->amount,
'account_key' => $this->account->account_key,
'user_id' => (int) $payment->user->public_id + 1,
'transaction_reference' => $payment->transaction_reference, 'transaction_reference' => $payment->transaction_reference,
'payment_date' => $payment->payment_date, 'payment_date' => $payment->payment_date,
'updated_at' => $this->getTimestamp($payment->updated_at), 'updated_at' => $this->getTimestamp($payment->updated_at),
@ -59,6 +57,6 @@ class PaymentTransformer extends EntityTransformer
'is_deleted' => (bool) $payment->is_deleted, 'is_deleted' => (bool) $payment->is_deleted,
'payment_type_id' => (int) $payment->payment_type_id, 'payment_type_id' => (int) $payment->payment_type_id,
'invoice_id' => (int) ($this->invoice ? $this->invoice->public_id : $payment->invoice->public_id), 'invoice_id' => (int) ($this->invoice ? $this->invoice->public_id : $payment->invoice->public_id),
]; ]);
} }
} }

View File

@ -7,16 +7,15 @@ class ProductTransformer extends EntityTransformer
{ {
public function transform(Product $product) public function transform(Product $product)
{ {
return [ return array_merge($this->getDefaults($product), [
'id' => (int) $product->public_id, 'id' => (int) $product->public_id,
'product_key' => $product->product_key, 'product_key' => $product->product_key,
'notes' => $product->notes, 'notes' => $product->notes,
'cost' => $product->cost, 'cost' => $product->cost,
'qty' => $product->qty, 'qty' => $product->qty,
'account_key' =>$this->account->account_key,
'default_tax_rate_id' =>$product->default_tax_rate_id, 'default_tax_rate_id' =>$product->default_tax_rate_id,
'updated_at' =>$this->getTimestamp($product->updated_at), 'updated_at' =>$this->getTimestamp($product->updated_at),
'archived_at' => $this->getTimestamp($product->deleted_at), 'archived_at' => $this->getTimestamp($product->deleted_at),
]; ]);
} }
} }

View File

@ -39,12 +39,10 @@ class TaskTransformer extends EntityTransformer
public function transform(Task $task) public function transform(Task $task)
{ {
return [ return array_merge($this->getDefaults($task), [
'id' => (int) $task->public_id, 'id' => (int) $task->public_id,
'account_key' => $this->account->account_key,
'user_id' => (int) $task->user->public_id + 1,
'description' => $task->description, 'description' => $task->description,
'duration' => $task->getDuration() 'duration' => $task->getDuration()
]; ]);
} }
} }

View File

@ -21,13 +21,12 @@ class TaxRateTransformer extends EntityTransformer
public function transform(TaxRate $taxRate) public function transform(TaxRate $taxRate)
{ {
return [ return array_merge($this->getDefaults($taxRate), [
'id' => (int) $taxRate->public_id, 'id' => (int) $taxRate->public_id,
'name' => $taxRate->name, 'name' => $taxRate->name,
'rate' => (float) $taxRate->rate, 'rate' => (float) $taxRate->rate,
'updated_at' => $this->getTimestamp($taxRate->updated_at), 'updated_at' => $this->getTimestamp($taxRate->updated_at),
'archived_at' => $this->getTimestamp($taxRate->deleted_at), 'archived_at' => $this->getTimestamp($taxRate->deleted_at),
'account_key' => $this->account->account_key, ]);
];
} }
} }

View File

@ -8,7 +8,7 @@ class VendorContactTransformer extends EntityTransformer
{ {
public function transform(VendorContact $contact) public function transform(VendorContact $contact)
{ {
return [ return array_merge($this->getDefaults($contact), [
'id' => (int) $contact->public_id, 'id' => (int) $contact->public_id,
'first_name' => $contact->first_name, 'first_name' => $contact->first_name,
'last_name' => $contact->last_name, 'last_name' => $contact->last_name,
@ -17,7 +17,6 @@ class VendorContactTransformer extends EntityTransformer
'archived_at' => $this->getTimestamp($contact->deleted_at), 'archived_at' => $this->getTimestamp($contact->deleted_at),
'is_primary' => (bool) $contact->is_primary, 'is_primary' => (bool) $contact->is_primary,
'phone' => $contact->phone, 'phone' => $contact->phone,
'account_key' => $this->account->account_key, ]);
];
} }
} }

View File

@ -35,16 +35,19 @@ class VendorTransformer extends EntityTransformer
* @SWG\Property(property="id_number", type="string", example="123456") * @SWG\Property(property="id_number", type="string", example="123456")
*/ */
protected $defaultIncludes = [
'vendor_contacts',
];
protected $availableIncludes = [ protected $availableIncludes = [
'vendorContacts',
'invoices', 'invoices',
'expenses', //'expenses',
]; ];
public function includeVendorContacts(Vendor $vendor) public function includeVendorContacts(Vendor $vendor)
{ {
$transformer = new VendorContactTransformer($this->account, $this->serializer); $transformer = new VendorContactTransformer($this->account, $this->serializer);
return $this->includeCollection($vendor->vendorContacts, $transformer, ENTITY_CONTACT); return $this->includeCollection($vendor->vendor_contacts, $transformer, ENTITY_CONTACT);
} }
public function includeInvoices(Vendor $vendor) public function includeInvoices(Vendor $vendor)
@ -61,13 +64,11 @@ class VendorTransformer extends EntityTransformer
public function transform(Vendor $vendor) public function transform(Vendor $vendor)
{ {
return [ return array_merge($this->getDefaults($vendor), [
'id' => (int) $vendor->public_id, 'id' => (int) $vendor->public_id,
'name' => $vendor->name, 'name' => $vendor->name,
'balance' => (float) $vendor->balance, 'balance' => (float) $vendor->balance,
'paid_to_date' => (float) $vendor->paid_to_date, 'paid_to_date' => (float) $vendor->paid_to_date,
'user_id' => (int) $vendor->user->public_id + 1,
'account_key' => $this->account->account_key,
'updated_at' => $this->getTimestamp($vendor->updated_at), 'updated_at' => $this->getTimestamp($vendor->updated_at),
'archived_at' => $this->getTimestamp($vendor->deleted_at), 'archived_at' => $this->getTimestamp($vendor->deleted_at),
'address1' => $vendor->address1, 'address1' => $vendor->address1,
@ -84,6 +85,6 @@ class VendorTransformer extends EntityTransformer
'vat_number' => $vendor->vat_number, 'vat_number' => $vendor->vat_number,
'id_number' => $vendor->id_number, 'id_number' => $vendor->id_number,
'currency_id' => (int) $vendor->currency_id 'currency_id' => (int) $vendor->currency_id
]; ]);
} }
} }

View File

@ -0,0 +1,48 @@
<?php
use App\Models\Client;
use App\Models\Contact;
use App\Models\Country;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| Here you may define all of your model factories. Model factories give
| you a convenient way to create models for testing and seeding your
| database. Just tell the factory how a default model should look.
|
*/
$factory->define(Contact::class, function (Faker\Generator $faker) {
return [
'client_id' => function() {
return factory(Client::class)->create()->id;
},
'user_id' => 1,
'account_id' => 1,
'public_id' => Contact::count() + 1,
'is_primary' => true,
'send_invoice' => true,
'first_name' => $faker->firstName,
'last_name' => $faker->lastName,
'email' => $faker->safeEmail,
'phone' => $faker->phoneNumber,
];
});
$factory->define(Client::class, function (Faker\Generator $faker) {
return [
'user_id' => 1,
'account_id' => 1,
'public_id' => Client::count() + 1,
'name' => $faker->name,
'address1' => $faker->streetAddress,
'address2' => $faker->secondaryAddress,
'city' => $faker->city,
'state' => $faker->state,
'postal_code' => $faker->postcode,
'country_id' => Country::all()->random()->id,
];
});

View File

@ -382,11 +382,11 @@ return array(
'converted_to_invoice' => 'Il preventivo è stato convertito a fattura con successo', 'converted_to_invoice' => 'Il preventivo è stato convertito a fattura con successo',
'quote_subject' => 'Nuovo preventivo da :account', 'quote_subject' => 'Nuovo preventivo da :account',
'quote_message' => 'Per visualizzare il vostro preventivo per :amount, cliccare il collegamento sotto.', 'quote_message' => 'Per visualizzare il vostro preventivo di :amount, cliccate il collegamento sotto.',
'quote_link_message' => 'Per visualizzare il preventivo del vostro cliante cliccate il collegamento sotto:', 'quote_link_message' => 'Per visualizzare il preventivo del vostro cliente cliccate il collegamento sotto:',
'notification_quote_sent_subject' => 'Il preventivo :invoice è stato inviato a :client', 'notification_quote_sent_subject' => 'Il preventivo :invoice è stato inviato a :client',
'notification_quote_viewed_subject' => 'Il preventivo :invoice è stato visualizzato da :client', 'notification_quote_viewed_subject' => 'Il preventivo :invoice è stato visualizzato da :client',
'notification_quote_sent' => 'Al seguente cliente :client è stata inviata la fattura :invoice per :amount.', 'notification_quote_sent' => 'Al seguente cliente :client è stata inviato il preventivo :invoice per un importo di :amount.',
'notification_quote_viewed' => 'Il seguente cliente :client ha visualizzato il preventivo :invoice di :amount.', 'notification_quote_viewed' => 'Il seguente cliente :client ha visualizzato il preventivo :invoice di :amount.',
'session_expired' => 'La vostra sessione è scaduta.', 'session_expired' => 'La vostra sessione è scaduta.',
@ -728,12 +728,12 @@ return array(
'header' => 'Header', 'header' => 'Header',
'footer' => 'Footer', 'footer' => 'Footer',
'custom' => 'Custom', 'custom' => 'Custom',
'invoice_to' => 'Invoice to', 'invoice_to' => 'Fattura a',
'invoice_no' => 'Invoice No.', 'invoice_no' => 'Fattura N.',
'recent_payments' => 'Recent Payments', 'recent_payments' => 'Pagamenti recenti',
'outstanding' => 'Outstanding', 'outstanding' => 'Inevaso',
'manage_companies' => 'Manage Companies', 'manage_companies' => 'Gestisci aziende',
'total_revenue' => 'Total Revenue', 'total_revenue' => 'Ricavo totale',
'current_user' => 'Current User', 'current_user' => 'Current User',
'new_recurring_invoice' => 'Nuova Fattura Ricorrente', 'new_recurring_invoice' => 'Nuova Fattura Ricorrente',
@ -784,7 +784,7 @@ return array(
'last_sent_on' => 'Last sent on :date', 'last_sent_on' => 'Last sent on :date',
'page_expire' => 'This page will expire soon, :click_here to keep working', 'page_expire' => 'This page will expire soon, :click_here to keep working',
'upcoming_quotes' => 'Upcoming Quotes', 'upcoming_quotes' => 'Preventivi in scadenza',
'expired_quotes' => 'Preventivi Scaduti', 'expired_quotes' => 'Preventivi Scaduti',
'sign_up_using' => 'Sign up using', 'sign_up_using' => 'Sign up using',
@ -842,19 +842,19 @@ return array(
'quote_counter' => 'Quote Counter', 'quote_counter' => 'Quote Counter',
'type' => 'Type', 'type' => 'Type',
'activity_1' => ':user created client :client', 'activity_1' => ':user ha creato il cliente :client',
'activity_2' => ':user archived client :client', 'activity_2' => ':user ha archiviato il cliente :client',
'activity_3' => ':user deleted client :client', 'activity_3' => ':user deleted client :client',
'activity_4' => ':user ha creato la fattura :invoice', 'activity_4' => ':user ha creato la fattura :invoice',
'activity_5' => ':user ha aggiornato la fattura :invoice', 'activity_5' => ':user ha aggiornato la fattura :invoice',
'activity_6' => ':user emailed invoice :invoice to :contact', 'activity_6' => ':user ha inviato per email la fattura :invoice a :contact',
'activity_7' => ':contact viewed invoice :invoice', 'activity_7' => ':contact ha visto la fattura :invoice',
'activity_8' => ':user archived invoice :invoice', 'activity_8' => ':user ha archiviato la fattura :invoice',
'activity_9' => ':user deleted invoice :invoice', 'activity_9' => ':user ha cancellato la fattura :invoice',
'activity_10' => ':contact entered payment :payment for :invoice', 'activity_10' => ':contact ha inserito il pagamento :payment per :invoice',
'activity_11' => ':user updated payment :payment', 'activity_11' => ':user ha aggiornato il pagamento :payment',
'activity_12' => ':user archived payment :payment', 'activity_12' => ':user ha archiviato il pagamento :payment',
'activity_13' => ':user deleted payment :payment', 'activity_13' => ':user ha cancellato il pagamento :payment',
'activity_14' => ':user entered :credit credit', 'activity_14' => ':user entered :credit credit',
'activity_15' => ':user updated :credit credit', 'activity_15' => ':user updated :credit credit',
'activity_16' => ':user archived :credit credit', 'activity_16' => ':user archived :credit credit',
@ -862,7 +862,7 @@ return array(
'activity_18' => ':user created quote :quote', 'activity_18' => ':user created quote :quote',
'activity_19' => ':user updated quote :quote', 'activity_19' => ':user updated quote :quote',
'activity_20' => ':user emailed quote :quote to :contact', 'activity_20' => ':user emailed quote :quote to :contact',
'activity_21' => ':contact viewed quote :quote', 'activity_21' => ':contact ha visto il preventivo :quote',
'activity_22' => ':user archived quote :quote', 'activity_22' => ':user archived quote :quote',
'activity_23' => ':user deleted quote :quote', 'activity_23' => ':user deleted quote :quote',
'activity_24' => ':user restored quote :quote', 'activity_24' => ':user restored quote :quote',
@ -870,7 +870,7 @@ return array(
'activity_26' => ':user restored client :client', 'activity_26' => ':user restored client :client',
'activity_27' => ':user restored payment :payment', 'activity_27' => ':user restored payment :payment',
'activity_28' => ':user restored :credit credit', 'activity_28' => ':user restored :credit credit',
'activity_29' => ':contact approved quote :quote', 'activity_29' => ':contact ha approvato la fattura :quote',
'payment' => 'Payment', 'payment' => 'Payment',
'system' => 'System', 'system' => 'System',
@ -1004,33 +1004,33 @@ return array(
'archived_expenses' => 'Successfully archived expenses', 'archived_expenses' => 'Successfully archived expenses',
// Expenses // Expenses
'expense_amount' => 'Expense Amount', 'expense_amount' => 'Importo Spesa',
'expense_balance' => 'Expense Balance', 'expense_balance' => 'Bilancio Spesa',
'expense_date' => 'Expense Date', 'expense_date' => 'Data Spesa',
'expense_should_be_invoiced' => 'Should this expense be invoiced?', 'expense_should_be_invoiced' => 'Questa spesa deve essere fatturata?',
'public_notes' => 'Public Notes', 'public_notes' => 'Note Pubbliche (Descrizione in fattura)',
'invoice_amount' => 'Invoice Amount', 'invoice_amount' => 'Importo Fattura',
'exchange_rate' => 'Exchange Rate', 'exchange_rate' => 'Tasso di Cambio',
'yes' => 'Yes', 'yes' => 'Si',
'no' => 'No', 'no' => 'No',
'should_be_invoiced' => 'Should be invoiced', 'should_be_invoiced' => 'Deve essere fatturata',
'view_expense' => 'View expense # :expense', 'view_expense' => 'Vedi spesa # :expense',
'edit_expense' => 'Edit Expense', 'edit_expense' => 'Modifica Spesa',
'archive_expense' => 'Archive Expense', 'archive_expense' => 'Archivia Spesa',
'delete_expense' => 'Delete Expense', 'delete_expense' => 'Cancella Spesa',
'view_expense_num' => 'Expense # :expense', 'view_expense_num' => 'Spesa # :expense',
'updated_expense' => 'Successfully updated expense', 'updated_expense' => 'Spesa aggiornata con successo',
'created_expense' => 'Successfully created expense', 'created_expense' => 'Spesa creata con successo',
'enter_expense' => 'Enter Expense', 'enter_expense' => 'Inserisci Spesa',
'view' => 'View', 'view' => 'Vedi',
'restore_expense' => 'Restore Expense', 'restore_expense' => 'Ripristina Spesa',
'invoice_expense' => 'Invoice Expense', 'invoice_expense' => 'Fattura Spesa',
'expense_error_multiple_clients' =>'The expenses can\'t belong to different clients', 'expense_error_multiple_clients' =>'Le spese non possono appartenere a clienti differenti',
'expense_error_invoiced' => 'Expense has already been invoiced', 'expense_error_invoiced' => 'La spesa è stata già fatturata',
'convert_currency' => 'Convert currency', 'convert_currency' => 'Converti valuta',
// Payment terms // Payment terms
'num_days' => 'Number of days', 'num_days' => 'Numero di giorni',
'create_payment_term' => 'Create Payment Term', 'create_payment_term' => 'Create Payment Term',
'edit_payment_terms' => 'Edit Payment Term', 'edit_payment_terms' => 'Edit Payment Term',
'edit_payment_term' => 'Edit Payment Term', 'edit_payment_term' => 'Edit Payment Term',
@ -1053,17 +1053,17 @@ return array(
</ul>', </ul>',
'due' => 'Due', 'due' => 'Due',
'next_due_on' => 'Due Next: :date', 'next_due_on' => 'Due Next: :date',
'use_client_terms' => 'Use client terms', 'use_client_terms' => 'Usa i termini del cliente',
'day_of_month' => ':ordinal day of month', 'day_of_month' => ':ordinal giorno del mese',
'last_day_of_month' => 'Last day of month', 'last_day_of_month' => 'L\'ultimo giorno del mese',
'day_of_week_after' => ':ordinal :day after', 'day_of_week_after' => ':ordinal :day dopo',
'sunday' => 'Sunday', 'sunday' => 'Domenica',
'monday' => 'Monday', 'monday' => 'Lunedì',
'tuesday' => 'Tuesday', 'tuesday' => 'Martedì',
'wednesday' => 'Wednesday', 'wednesday' => 'Mercoledì',
'thursday' => 'Thursday', 'thursday' => 'Giovedì',
'friday' => 'Friday', 'friday' => 'Venerdì',
'saturday' => 'Saturday', 'saturday' => 'Sabato',
// Fonts // Fonts
'header_font_id' => 'Header Font', 'header_font_id' => 'Header Font',
@ -1182,17 +1182,17 @@ return array(
'edit_all_help' => 'Allow user to modify records they didn\'t create', 'edit_all_help' => 'Allow user to modify records they didn\'t create',
'view_payment' => 'View Payment', 'view_payment' => 'View Payment',
'january' => 'January', 'january' => 'Gennaio',
'february' => 'February', 'february' => 'Febbraio',
'march' => 'March', 'march' => 'Marzo',
'april' => 'April', 'april' => 'Aprile',
'may' => 'May', 'may' => 'Maggio',
'june' => 'June', 'june' => 'Giugno',
'july' => 'July', 'july' => 'Luglio',
'august' => 'August', 'august' => 'Agosto',
'september' => 'September', 'september' => 'Settembre',
'october' => 'October', 'october' => 'Ottobre',
'november' => 'November', 'november' => 'Novembre',
'december' => 'December', 'december' => 'Dicembre',
); );

View File

@ -0,0 +1,20 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Poprzedni',
'next' => 'Następny &raquo;',
);

View File

@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reminder Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
"password" => "Hasło musi mieć conajmniej sześć znaków i być takie samo jak potwierdzające.",
"user" => "Użytkownik o podanym adresie e-mail nie istnieje.",
"token" => "Wprowadzony token jest nieprawidłowy.",
"sent" => "Link do resetowania hasła został wysłany.",
"reset" => "Twoje hasło zostało zresetowane!",
];

View File

@ -0,0 +1,24 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Password Reminder Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
"password" => "Hasło musi mieć conajmniej sześć znaków i być takie samo jak potwierdzające.",
"user" => "Użytkownik o podanym adresie e-mail nie istnieje.",
"token" => "Wprowadzony token jest nieprawidłowy.",
"sent" => "Przypomnienie hasła zostało wysłane!",
);

1184
resources/lang/pl/texts.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,106 @@
<?php
return array(
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| such as the size rules. Feel free to tweak each of these messages.
|
*/
"accepted" => ":attribute musi być zaakceptowany.",
"active_url" => ":attribute nie jest poprawnym URL-em.",
"after" => ":attribute musi być datą za :date.",
"alpha" => ":attribute może zawierać tylko litery.",
"alpha_dash" => ":attribute może zawierać tylko litery, liczby i myślniki.",
"alpha_num" => ":attribute może zawierać tylko litery i liczby.",
"array" => ":attribute musi być tablicą.",
"before" => ":attribute musi być datą przed :date.",
"between" => array(
"numeric" => ":attribute musi być pomiędzy :min - :max.",
"file" => ":attribute musi mieć rozmiar pomiędzy :min - :max kilobajtów.",
"string" => ":attribute musi mieć pomiędzy :min - :max znaków.",
"array" => ":attribute musi zawierać :min - :max pozycji.",
),
"confirmed" => ":attribute potwierdzenie nie jest zgodne.",
"date" => ":attribute nie jest prawidłową datą.",
"date_format" => ":attribute nie jest zgodne z formatem :format.",
"different" => ":attribute i :other muszą być różne.",
"digits" => ":attribute musi mieć :digits cyfr.",
"digits_between" => ":attribute musi być w przedziale od :min do :max cyfr.",
"email" => ":attribute format jest nieprawidłowy.",
"exists" => "Zaznaczony :attribute jest niepoprawny.",
"image" => ":attribute musi być zdjęciem.",
"in" => "Zaznaczony :attribute jest niepoprawny.",
"integer" => ":attribute musi być liczbą całkowitą.",
"ip" => ":attribute musi być poprawnym adresem IP.",
"max" => array(
"numeric" => ":attribute nie może być większy niż :max.",
"file" => ":attribute nie może być większy niż :max kilobajtów.",
"string" => ":attribute nie może być dłuższy niż :max znaków.",
"array" => ":attribute nie może zawierać więcej niż :max pozycji.",
),
"mimes" => ":attribute musi być plikiem o typie: :values.",
"min" => array(
"numeric" => ":attribute musi być przynajmniej :min.",
"file" => ":attribute musi mieć przynajmniej :min kilobajtów.",
"string" => ":attribute musi mieć przynajmniej :min znaków.",
"array" => ":attribute musi zawierać przynajmniej :min pozycji.",
),
"not_in" => "Zaznaczony :attribute jest niepoprawny.",
"numeric" => ":attribute musi być cyfrą.",
"regex" => ":attribute format jest niepoprawny.",
"required" => ":attribute pole jest wymagane.",
"required_if" => ":attribute pole jest wymagane jeśli :other ma :value.",
"required_with" => ":attribute pole jest wymagane kiedy :values jest obecne.",
"required_without" => ":attribute pole jest wymagane kiedy :values nie występuje.",
"same" => ":attribute i :other muszą być takie same.",
"size" => array(
"numeric" => ":attribute musi mieć :size.",
"file" => ":attribute musi mieć :size kilobajtów.",
"string" => ":attribute musi mieć :size znaków.",
"array" => ":attribute musi zawierać :size pozycji.",
),
"unique" => ":attribute już istnieje.",
"url" => ":attribute format jest nieprawidłowy.",
"positive" => ":attribute musi być większe niż zero.",
"has_credit" => "Klient ma niewystarczająco kredytu.",
"notmasked" => "Wartości są maskowane",
"less_than" => ":attribute musi być mniejsze od :value",
"has_counter" => "Wartość musi zawierać {\$counter}",
"valid_contacts" => "Kontakt musi posiadać e-mail lub nazwę",
"valid_invoice_items" => "Faktura przekracza maksymalną kwotę",
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => array(),
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
'attributes' => array(),
);

View File

@ -7,8 +7,8 @@
@section('content') @section('content')
@if ($errors->first('vendorcontacts')) @if ($errors->first('vendor_contacts'))
<div class="alert alert-danger">{{ trans($errors->first('vendorcontacts')) }}</div> <div class="alert alert-danger">{{ trans($errors->first('vendor_contacts')) }}</div>
@endif @endif
<div class="row"> <div class="row">
@ -73,26 +73,26 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div data-bind='template: { foreach: vendorcontacts, <div data-bind='template: { foreach: vendor_contacts,
beforeRemove: hideContact, beforeRemove: hideContact,
afterAdd: showContact }'> afterAdd: showContact }'>
{!! Former::hidden('public_id')->data_bind("value: public_id, valueUpdate: 'afterkeydown', {!! Former::hidden('public_id')->data_bind("value: public_id, valueUpdate: 'afterkeydown',
attr: {name: 'vendorcontacts[' + \$index() + '][public_id]'}") !!} attr: {name: 'vendor_contacts[' + \$index() + '][public_id]'}") !!}
{!! Former::text('first_name')->data_bind("value: first_name, valueUpdate: 'afterkeydown', {!! Former::text('first_name')->data_bind("value: first_name, valueUpdate: 'afterkeydown',
attr: {name: 'vendorcontacts[' + \$index() + '][first_name]'}") !!} attr: {name: 'vendor_contacts[' + \$index() + '][first_name]'}") !!}
{!! Former::text('last_name')->data_bind("value: last_name, valueUpdate: 'afterkeydown', {!! Former::text('last_name')->data_bind("value: last_name, valueUpdate: 'afterkeydown',
attr: {name: 'vendorcontacts[' + \$index() + '][last_name]'}") !!} attr: {name: 'vendor_contacts[' + \$index() + '][last_name]'}") !!}
{!! Former::text('email')->data_bind("value: email, valueUpdate: 'afterkeydown', {!! Former::text('email')->data_bind("value: email, valueUpdate: 'afterkeydown',
attr: {name: 'vendorcontacts[' + \$index() + '][email]', id:'email'+\$index()}") !!} attr: {name: 'vendor_contacts[' + \$index() + '][email]', id:'email'+\$index()}") !!}
{!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown', {!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown',
attr: {name: 'vendorcontacts[' + \$index() + '][phone]'}") !!} attr: {name: 'vendor_contacts[' + \$index() + '][phone]'}") !!}
<div class="form-group"> <div class="form-group">
<div class="col-lg-8 col-lg-offset-4 bold"> <div class="col-lg-8 col-lg-offset-4 bold">
<span class="redlink bold" data-bind="visible: $parent.vendorcontacts().length > 1"> <span class="redlink bold" data-bind="visible: $parent.vendor_contacts().length > 1">
{!! link_to('#', trans('texts.remove_contact').' -', array('data-bind'=>'click: $parent.removeContact')) !!} {!! link_to('#', trans('texts.remove_contact').' -', array('data-bind'=>'click: $parent.removeContact')) !!}
</span> </span>
<span data-bind="visible: $index() === ($parent.vendorcontacts().length - 1)" class="pull-right greenlink bold"> <span data-bind="visible: $index() === ($parent.vendor_contacts().length - 1)" class="pull-right greenlink bold">
{!! link_to('#', trans('texts.add_contact').' +', array('onclick'=>'return addContact()')) !!} {!! link_to('#', trans('texts.add_contact').' +', array('onclick'=>'return addContact()')) !!}
</span> </span>
</div> </div>
@ -186,10 +186,10 @@
function VendorModel(data) { function VendorModel(data) {
var self = this; var self = this;
self.vendorcontacts = ko.observableArray(); self.vendor_contacts = ko.observableArray();
self.mapping = { self.mapping = {
'vendorcontacts': { 'vendor_contacts': {
create: function(options) { create: function(options) {
return new VendorContactModel(options.data); return new VendorContactModel(options.data);
} }
@ -199,12 +199,12 @@
if (data) { if (data) {
ko.mapping.fromJS(data, self.mapping, this); ko.mapping.fromJS(data, self.mapping, this);
} else { } else {
self.vendorcontacts.push(new VendorContactModel()); self.vendor_contacts.push(new VendorContactModel());
} }
self.placeholderName = ko.computed(function() { self.placeholderName = ko.computed(function() {
if (self.vendorcontacts().length == 0) return ''; if (self.vendor_contacts().length == 0) return '';
var contact = self.vendorcontacts()[0]; var contact = self.vendor_contacts()[0];
if (contact.first_name() || contact.last_name()) { if (contact.first_name() || contact.last_name()) {
return contact.first_name() + ' ' + contact.last_name(); return contact.first_name() + ' ' + contact.last_name();
} else { } else {
@ -226,12 +226,12 @@
ko.applyBindings(model); ko.applyBindings(model);
function addContact() { function addContact() {
model.vendorcontacts.push(new VendorContactModel()); model.vendor_contacts.push(new VendorContactModel());
return false; return false;
} }
model.removeContact = function() { model.removeContact = function() {
model.vendorcontacts.remove(this); model.vendor_contacts.remove(this);
} }

View File

@ -109,7 +109,7 @@
<div class="col-md-3"> <div class="col-md-3">
<h3>{{ trans('texts.contacts') }}</h3> <h3>{{ trans('texts.contacts') }}</h3>
@foreach ($vendor->vendorcontacts as $contact) @foreach ($vendor->vendor_contacts as $contact)
@if ($contact->first_name || $contact->last_name) @if ($contact->first_name || $contact->last_name)
<b>{{ $contact->first_name.' '.$contact->last_name }}</b><br/> <b>{{ $contact->first_name.' '.$contact->last_name }}</b><br/>
@endif @endif

View File

@ -78,7 +78,7 @@ class APICest
$data = new stdClass; $data = new stdClass;
$data->name = $this->faker->word; $data->name = $this->faker->word;
$data->vendorcontacts = []; $data->vendor_contacts = [];
$this->createEntity('vendor', $data); $this->createEntity('vendor', $data);
$this->listEntities('vendor'); $this->listEntities('vendor');

View File

@ -44,13 +44,14 @@ class ExpenseCest
$I->selectDropdown($I, $vendorName, '.vendor-select .dropdown-toggle'); $I->selectDropdown($I, $vendorName, '.vendor-select .dropdown-toggle');
$I->selectDropdown($I, $clientEmail, '.client-select .dropdown-toggle'); $I->selectDropdown($I, $clientEmail, '.client-select .dropdown-toggle');
$I->click('Save'); $I->click('Save');
$I->wait(2);
$I->seeInDatabase('expenses', ['vendor_id' => $vendorId]); $I->seeInDatabase('expenses', ['vendor_id' => $vendorId]);
// invoice expense // invoice expense
$I->executeJS('submitAction(\'invoice\')'); $I->executeJS('submitAction(\'invoice\')');
$I->wait(3); $I->wait(2);
$I->click('Save'); $I->click('Save');
$I->wait(3); $I->wait(2);
$I->see($clientEmail); $I->see($clientEmail);
$I->see($amount); $I->see($amount);
} }