Merge pull request #7646 from turbo124/v5-stable

v5.4.10
This commit is contained in:
David Bomba 2022-07-18 07:20:57 +10:00 committed by GitHub
commit 4570b9ab7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 272055 additions and 269393 deletions

View File

@ -1 +1 @@
5.4.9 5.4.10

View File

@ -106,8 +106,8 @@ class CheckData extends Command
} }
$this->checkInvoiceBalances(); $this->checkInvoiceBalances();
$this->checkClientBalanceEdgeCases();
$this->checkPaidToDatesNew(); $this->checkPaidToDatesNew();
$this->checkContacts(); $this->checkContacts();
$this->checkVendorContacts(); $this->checkVendorContacts();
$this->checkEntityInvitations(); $this->checkEntityInvitations();
@ -655,6 +655,39 @@ class CheckData extends Command
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect client balances"); $this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect client balances");
} }
private function checkClientBalanceEdgeCases()
{
Client::query()
->where('is_deleted',false)
->where('balance', '!=', 0)
->cursor()
->each(function ($client){
$count = Invoice::withTrashed()
->where('client_id', $client->id)
->where('is_deleted',false)
->whereIn('status_id', [2,3])
->count();
if($count == 0){
$this->logMessage("# {$client->id} # {$client->name} {$client->balance} is invalid should be 0");
if($this->option('client_balance')){
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->balance} to 0");
$client->balance = 0;
$client->save();
}
}
});
}
private function invoiceBalanceQuery() private function invoiceBalanceQuery()
{ {
$results = \DB::select( \DB::raw(" $results = \DB::select( \DB::raw("

View File

@ -400,6 +400,7 @@ class CreateSingleAccount extends Command
$vendor = Project::factory()->create([ $vendor = Project::factory()->create([
'user_id' => $client->user->id, 'user_id' => $client->user->id,
'company_id' => $client->company->id, 'company_id' => $client->company->id,
'client_id' => $client->id,
]); ]);
} }

View File

@ -13,7 +13,7 @@ class PaymentFailed extends Exception
public function render($request) public function render($request)
{ {
if (auth()->user() || ($request->has('cko-session-id') && $request->query('cko-session-id') )) { if (auth()->guard('contact')->user() || ($request->has('cko-session-id') && $request->query('cko-session-id') )) {
return render('gateways.unsuccessful', [ return render('gateways.unsuccessful', [
'message' => $this->getMessage(), 'message' => $this->getMessage(),
'code' => $this->getCode(), 'code' => $this->getCode(),

View File

@ -94,6 +94,9 @@ class QuoteFilters extends QueryFilters
{ {
$sort_col = explode('|', $sort); $sort_col = explode('|', $sort);
if($sort_col[0] == 'valid_until')
$sort_col[0] = 'due_date';
return $this->builder->orderBy($sort_col[0], $sort_col[1]); return $this->builder->orderBy($sort_col[0], $sort_col[1]);
} }

View File

@ -46,6 +46,8 @@ use Laravel\Socialite\Facades\Socialite;
use PragmaRX\Google2FA\Google2FA; use PragmaRX\Google2FA\Google2FA;
use Turbo124\Beacon\Facades\LightLogs; use Turbo124\Beacon\Facades\LightLogs;
use Microsoft\Graph\Model; use Microsoft\Graph\Model;
use Illuminate\Support\Facades\Http;
class LoginController extends BaseController class LoginController extends BaseController
{ {
@ -334,11 +336,12 @@ class LoginController extends BaseController
} elseif (request()->input('provider') == 'microsoft') { } elseif (request()->input('provider') == 'microsoft') {
return $this->handleMicrosoftOauth(); return $this->handleMicrosoftOauth();
} elseif (request()->input('provider') == 'apple') { } elseif (request()->input('provider') == 'apple') {
// if (request()->has('token')) { if (request()->has('id_token')) {
// return $this->handleSocialiteLogin('apple', request()->get('token')); $token = request()->input('id_token');
// } else { return $this->handleSocialiteLogin('apple', $token);
// $message = 'Token is missing for the apple login'; } else {
// } $message = 'Token is missing for the apple login';
}
} }
return response() return response()
@ -355,6 +358,7 @@ class LoginController extends BaseController
private function handleSocialiteLogin($provider, $token) private function handleSocialiteLogin($provider, $token)
{ {
$user = $this->getSocialiteUser($provider, $token); $user = $this->getSocialiteUser($provider, $token);
nlog($user);
if ($user) { if ($user) {
return $this->loginOrCreateFromSocialite($user, $provider); return $this->loginOrCreateFromSocialite($user, $provider);
} }

View File

@ -656,4 +656,84 @@ class ClientController extends BaseController
//todo add an event here using the client name as reference for purge event //todo add an event here using the client name as reference for purge event
} }
/**
* Update the specified resource in storage.
*
* @param PurgeClientRequest $request
* @param Client $client
* @param string $mergeable client hashed_id
* @return Response
*
*
*
* @OA\Post(
* path="/api/v1/clients/{id}/{mergaeble_client_hashed_id}/merge",
* operationId="mergeClient",
* tags={"clients"},
* summary="Merges two clients",
* description="Handles merging 2 clients",
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"),
* @OA\Parameter(
* name="id",
* in="path",
* description="The Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Parameter(
* name="mergeable_client_hashedid",
* in="path",
* description="The Mergeable Client Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the client object",
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit")
* ),
* @OA\Response(
* response=422,
* description="Validation error",
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
*
* ),
* @OA\Response(
* response="default",
* description="Unexpected Error",
* @OA\JsonContent(ref="#/components/schemas/Error"),
* ),
* )
*/
public function merge(PurgeClientRequest $request, Client $client, string $mergeable_client)
{
$m_client = Client::withTrashed()
->where('id', $this->decodePrimaryKey($mergeable_client))
->where('company_id', auth()->user()->company()->id)
->first();
if(!$m_client)
return response()->json(['message' => "Client not found"]);
$merged_client = $client->service()->merge($m_client)->save();
return $this->itemResponse($merged_client);
}
} }

View File

@ -92,12 +92,27 @@ class PaymentController extends Controller
{ {
$gateway = CompanyGateway::findOrFail($request->input('company_gateway_id')); $gateway = CompanyGateway::findOrFail($request->input('company_gateway_id'));
$payment_hash = PaymentHash::where('hash', $request->payment_hash)->first(); $payment_hash = PaymentHash::where('hash', $request->payment_hash)->firstOrFail();
$invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id); $invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id);
$client = $invoice ? $invoice->client : auth()->user()->client; $client = $invoice ? $invoice->client : auth()->guard('contact')->user()->client;
// 09-07-2022 catch duplicate responses for invoices that already paid here.
if($invoice && $invoice->status_id == Invoice::STATUS_PAID){
$data = [
'invoice' => $invoice,
'key' => false
];
if ($request->query('mode') === 'fullscreen') {
return render('invoices.show-fullscreen', $data);
}
return $this->render('invoices.show', $data);
}
return $gateway return $gateway
// ->driver(auth()->user()->client)
->driver($client) ->driver($client)
->setPaymentMethod($request->input('payment_method_id')) ->setPaymentMethod($request->input('payment_method_id'))
->setPaymentHash($payment_hash) ->setPaymentHash($payment_hash)

View File

@ -204,10 +204,6 @@ class RecurringInvoiceController extends BaseController
{ {
$recurring_invoice = $this->recurring_invoice_repo->save($request->all(), RecurringInvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id)); $recurring_invoice = $this->recurring_invoice_repo->save($request->all(), RecurringInvoiceFactory::create(auth()->user()->company()->id, auth()->user()->id));
// $offset = $recurring_invoice->client->timezone_offset();
// $recurring_invoice->next_send_date = Carbon::parse($recurring_invoice->next_send_date)->startOfDay()->addSeconds($offset);
// $recurring_invoice->saveQuietly();
$recurring_invoice->service() $recurring_invoice->service()
->triggeredActions($request) ->triggeredActions($request)
->save(); ->save();
@ -702,6 +698,15 @@ class RecurringInvoiceController extends BaseController
$this->itemResponse($recurring_invoice); $this->itemResponse($recurring_invoice);
} }
break;
case 'send_now':
$recurring_invoice = $recurring_invoice->service()->sendNow();
if (! $bulk) {
$this->itemResponse($recurring_invoice);
}
break; break;
default: default:
// code... // code...

View File

@ -21,6 +21,7 @@ use App\Models\Company;
use App\Models\CompanyGateway; use App\Models\CompanyGateway;
use App\Models\GatewayType; use App\Models\GatewayType;
use App\PaymentDrivers\Stripe\Connect\Account; use App\PaymentDrivers\Stripe\Connect\Account;
use App\PaymentDrivers\Stripe\Jobs\StripeWebhook;
use Exception; use Exception;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Stripe\Exception\ApiErrorException; use Stripe\Exception\ApiErrorException;
@ -119,6 +120,8 @@ class StripeConnectController extends BaseController
$company_gateway->setConfig($payload); $company_gateway->setConfig($payload);
$company_gateway->save(); $company_gateway->save();
StripeWebhook::dispatch($company->company_key, $company_gateway->id);
//response here //response here
return view('auth.connect.completed'); return view('auth.connect.completed');
} }

View File

@ -44,6 +44,7 @@ use App\Http\Middleware\UrlSetDb;
use App\Http\Middleware\UserVerified; use App\Http\Middleware\UserVerified;
use App\Http\Middleware\VendorLocale; use App\Http\Middleware\VendorLocale;
use App\Http\Middleware\VerifyCsrfToken; use App\Http\Middleware\VerifyCsrfToken;
use App\Http\Middleware\VerifyHash;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
use Illuminate\Auth\Middleware\Authorize; use Illuminate\Auth\Middleware\Authorize;
use Illuminate\Auth\Middleware\EnsureEmailIsVerified; use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
@ -161,6 +162,7 @@ class Kernel extends HttpKernel
'locale' => Locale::class, 'locale' => Locale::class,
'vendor_locale' => VendorLocale::class, 'vendor_locale' => VendorLocale::class,
'contact_register' => ContactRegister::class, 'contact_register' => ContactRegister::class,
'verify_hash' => VerifyHash::class,
'shop_token_auth' => ShopTokenAuth::class, 'shop_token_auth' => ShopTokenAuth::class,
'phantom_secret' => PhantomSecret::class, 'phantom_secret' => PhantomSecret::class,
'contact_key_login' => ContactKeyLogin::class, 'contact_key_login' => ContactKeyLogin::class,

View File

@ -73,6 +73,12 @@ class RequiredClientInfo extends Component
'state', 'state',
'postal_code', 'postal_code',
'country_id', 'country_id',
'shipping_address1',
'shipping_address2',
'shipping_city',
'shipping_state',
'shipping_postal_code',
'shipping_country_id',
]; ];
protected $rules = [ protected $rules = [

View File

@ -0,0 +1,37 @@
<?php
namespace App\Http\Middleware;
use App\Models\Account;
use App\Models\Company;
use App\Models\PaymentHash;
use App\Utils\Ninja;
use Closure;
use Illuminate\Http\Request;
class VerifyHash
{
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if($request->has('payment_hash')){
$ph = PaymentHash::with('fee_invoice')->where('hash', $request->payment_hash)->first();
if($ph)
auth()->guard('contact')->loginUsingId($ph->fee_invoice->invitations->first()->contact->id, true);
return $next($request);
}
abort(404, 'Unable to verify payment hash');
}
}

View File

@ -62,9 +62,6 @@ class UpdateInvoiceRequest extends Request
$rules['discount'] = 'sometimes|numeric'; $rules['discount'] = 'sometimes|numeric';
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
// if($this->input('status_id') != Invoice::STATUS_DRAFT)
// $rules['balance'] = new InvoiceBalanceSanity($this->invoice, $this->all());
return $rules; return $rules;
} }

View File

@ -123,7 +123,7 @@ class Request extends FormRequest
} }
} }
if (isset($input['invitations'])) { if (isset($input['invitations']) && is_array($input['invitations'])) {
foreach ($input['invitations'] as $key => $value) { foreach ($input['invitations'] as $key => $value) {
if (isset($input['invitations'][$key]['id']) && is_numeric($input['invitations'][$key]['id'])) { if (isset($input['invitations'][$key]['id']) && is_numeric($input['invitations'][$key]['id'])) {
unset($input['invitations'][$key]['id']); unset($input['invitations'][$key]['id']);

View File

@ -1,10 +1,10 @@
<?php <?php
/** /**
* Quote Ninja (https://paymentninja.com). * Invoice Ninja (https://paymentninja.com).
* *
* @link https://github.com/paymentninja/paymentninja source repository * @link https://github.com/paymentninja/paymentninja source repository
* *
* @copyright Copyright (c) 2022. Quote Ninja LLC (https://paymentninja.com) * @copyright Copyright (c) 2022. Invoice Ninja LLC (https://paymentninja.com)
* *
* @license https://www.elastic.co/licensing/elastic-license * @license https://www.elastic.co/licensing/elastic-license
*/ */
@ -24,7 +24,7 @@ class SortTaskRequest extends Request
{ {
return true; return true;
// return auth()->user()->can('edit', $this->task);
} }
public function rules() public function rules()

View File

@ -44,7 +44,7 @@ class ValidCreditsPresentRule implements Rule
{ {
//todo need to ensure the clients credits are here not random ones! //todo need to ensure the clients credits are here not random ones!
if (request()->input('credits') && is_array(request()->input('credits'))) { if (request()->input('credits') && is_array(request()->input('credits')) && count(request()->input('credits')) > 0) {
$credit_collection = Credit::whereIn('id', $this->transformKeys(array_column(request()->input('credits'), 'credit_id'))) $credit_collection = Credit::whereIn('id', $this->transformKeys(array_column(request()->input('credits'), 'credit_id')))
->count(); ->count();

View File

@ -20,6 +20,7 @@ use App\Mail\DownloadInvoices;
use App\Models\Company; use App\Models\Company;
use App\Models\CreditInvitation; use App\Models\CreditInvitation;
use App\Models\InvoiceInvitation; use App\Models\InvoiceInvitation;
use App\Models\PurchaseOrderInvitation;
use App\Models\QuoteInvitation; use App\Models\QuoteInvitation;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\Models\RecurringInvoiceInvitation; use App\Models\RecurringInvoiceInvitation;
@ -32,8 +33,8 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Storage;
class CompanyExport implements ShouldQueue class CompanyExport implements ShouldQueue
{ {
@ -424,9 +425,9 @@ class CompanyExport implements ShouldQueue
$this->export_data['vendor_contacts'] = VendorContact::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($vendor){ $this->export_data['vendor_contacts'] = VendorContact::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($vendor){
$vendor = $this->transformBasicEntities($vendor); $vendor = $this->transformBasicEntities($vendor);
$vendor->vendor_id = $this->encodePrimaryKey($vendor->vendor_id); $vendor = $this->transformArrayOfKeys($vendor, ['vendor_id']);
return $vendor->makeVisible(['id']); return $vendor->makeVisible(['id','user_id']);
})->all(); })->all();
@ -439,6 +440,31 @@ class CompanyExport implements ShouldQueue
})->makeHidden(['id'])->all(); })->makeHidden(['id'])->all();
$this->export_data['purchase_orders'] = $this->company->purchase_orders()->orderBy('number', 'DESC')->cursor()->map(function ($purchase_order){
$purchase_order = $this->transformBasicEntities($purchase_order);
$purchase_order = $this->transformArrayOfKeys($purchase_order, ['expense_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id','project_id']);
return $purchase_order->makeVisible(['id',
'private_notes',
'user_id',
'client_id',
'vendor_id',
'company_id',]);
})->all();
$this->export_data['purchase_order_invitations'] = PurchaseOrderInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($purchase_order){
$purchase_order = $this->transformArrayOfKeys($purchase_order, ['company_id', 'user_id', 'vendor_contact_id', 'purchase_order_id']);
return $purchase_order->makeVisible(['id']);
})->all();
//write to tmp and email to owner(); //write to tmp and email to owner();
$this->zipAndSend(); $this->zipAndSend();

View File

@ -45,6 +45,8 @@ use App\Models\PaymentTerm;
use App\Models\Paymentable; use App\Models\Paymentable;
use App\Models\Product; use App\Models\Product;
use App\Models\Project; use App\Models\Project;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderInvitation;
use App\Models\Quote; use App\Models\Quote;
use App\Models\QuoteInvitation; use App\Models\QuoteInvitation;
use App\Models\RecurringExpense; use App\Models\RecurringExpense;
@ -74,7 +76,6 @@ use Illuminate\Support\Str;
use JsonMachine\JsonDecoder\ExtJsonDecoder; use JsonMachine\JsonDecoder\ExtJsonDecoder;
use JsonMachine\JsonMachine; use JsonMachine\JsonMachine;
use ZipArchive; use ZipArchive;
use function GuzzleHttp\json_encode; use function GuzzleHttp\json_encode;
class CompanyImport implements ShouldQueue class CompanyImport implements ShouldQueue
@ -122,6 +123,7 @@ class CompanyImport implements ShouldQueue
'clients', 'clients',
'client_contacts', 'client_contacts',
'vendors', 'vendors',
'vendor_contacts',
'projects', 'projects',
'products', 'products',
'company_gateways', 'company_gateways',
@ -147,6 +149,8 @@ class CompanyImport implements ShouldQueue
'documents', 'documents',
'webhooks', 'webhooks',
'system_logs', 'system_logs',
'purchase_orders',
'purchase_order_invitations'
]; ];
private $company_properties = [ private $company_properties = [
@ -454,7 +458,7 @@ class CompanyImport implements ShouldQueue
$settings->ticket_number_counter = 1; $settings->ticket_number_counter = 1;
$settings->payment_number_counter = 1; $settings->payment_number_counter = 1;
$settings->project_number_counter = 1; $settings->project_number_counter = 1;
$settings->purchase_order_counter = 1;
$this->company->settings = $co->settings; $this->company->settings = $co->settings;
// $this->company->settings = $this->backup_file->company->settings; // $this->company->settings = $this->backup_file->company->settings;
$this->company->save(); $this->company->save();
@ -471,6 +475,7 @@ class CompanyImport implements ShouldQueue
$this->company->vendors()->forceDelete(); $this->company->vendors()->forceDelete();
$this->company->expenses()->forceDelete(); $this->company->expenses()->forceDelete();
$this->company->subscriptions()->forceDelete(); $this->company->subscriptions()->forceDelete();
$this->company->purchase_orders()->forceDelete();
$this->company->save(); $this->company->save();
@ -649,6 +654,19 @@ class CompanyImport implements ShouldQueue
return $this; return $this;
} }
private function import_vendor_contacts()
{
$this->genericImport(VendorContact::class,
['user_id', 'company_id', 'id', 'hashed_id','company','assigned_user_id'],
[['users' => 'user_id'], ['vendors' => 'vendor_id']],
'vendor_contacts',
'email');
return $this;
}
private function import_projects() private function import_projects()
{ {
@ -796,6 +814,42 @@ class CompanyImport implements ShouldQueue
return $this; return $this;
} }
private function import_purchase_orders()
{
$this->genericImport(PurchaseOrder::class,
['user_id', 'company_id', 'id', 'hashed_id', 'recurring_id','status', 'vendor_id', 'subscription_id','client_id'],
[
['users' => 'user_id'],
['users' => 'assigned_user_id'],
['recurring_invoices' => 'recurring_id'],
['projects' => 'project_id'],
['vendors' => 'vendor_id'],
],
'purchase_orders',
'number');
return $this;
}
private function import_purchase_order_invitations()
{
$this->genericImport(PurchaseOrderInvitation::class,
['user_id', 'vendor_contact_id', 'company_id', 'id', 'hashed_id', 'purchase_order_id'],
[
['users' => 'user_id'],
['purchase_orders' => 'purchase_order_id'],
['vendor_contacts' => 'vendor_contact_id'],
],
'purchase_order_invitations',
'key');
return $this;
}
private function import_quotes() private function import_quotes()
{ {
@ -1425,6 +1479,13 @@ class CompanyImport implements ShouldQueue
$new_obj->save(['timestamps' => false]); $new_obj->save(['timestamps' => false]);
$new_obj->number = $this->getNextInvoiceNumber($client = Client::withTrashed()->find($obj_array['client_id']),$new_obj); $new_obj->number = $this->getNextInvoiceNumber($client = Client::withTrashed()->find($obj_array['client_id']),$new_obj);
} }
elseif($class == 'App\Models\PurchaseOrder' && is_null($obj->{$match_key})){
$new_obj = new PurchaseOrder();
$new_obj->company_id = $this->company->id;
$new_obj->fill($obj_array);
$new_obj->save(['timestamps' => false]);
$new_obj->number = $this->getNextPurchaseOrderNumber($new_obj);
}
elseif($class == 'App\Models\Payment' && is_null($obj->{$match_key})){ elseif($class == 'App\Models\Payment' && is_null($obj->{$match_key})){
$new_obj = new Payment(); $new_obj = new Payment();
$new_obj->company_id = $this->company->id; $new_obj->company_id = $this->company->id;
@ -1445,6 +1506,12 @@ class CompanyImport implements ShouldQueue
$new_obj->fill($obj_array); $new_obj->fill($obj_array);
$new_obj->save(['timestamps' => false]); $new_obj->save(['timestamps' => false]);
} }
elseif($class == 'App\Models\VendorContact'){
$new_obj = new VendorContact();
$new_obj->company_id = $this->company->id;
$new_obj->fill($obj_array);
$new_obj->save(['timestamps' => false]);
}
elseif($class == 'App\Models\RecurringExpense' && is_null($obj->{$match_key})){ elseif($class == 'App\Models\RecurringExpense' && is_null($obj->{$match_key})){
$new_obj = new RecurringExpense(); $new_obj = new RecurringExpense();
$new_obj->company_id = $this->company->id; $new_obj->company_id = $this->company->id;
@ -1466,6 +1533,13 @@ class CompanyImport implements ShouldQueue
$new_obj->save(['timestamps' => false]); $new_obj->save(['timestamps' => false]);
$new_obj->number = $this->getNextTaskNumber($new_obj); $new_obj->number = $this->getNextTaskNumber($new_obj);
} }
elseif($class == 'App\Models\Vendor' && is_null($obj->{$match_key})){
$new_obj = new Vendor();
$new_obj->company_id = $this->company->id;
$new_obj->fill($obj_array);
$new_obj->save(['timestamps' => false]);
$new_obj->number = $this->getNextVendorNumber($new_obj);
}
elseif($class == 'App\Models\CompanyLedger'){ elseif($class == 'App\Models\CompanyLedger'){
$new_obj = $class::firstOrNew( $new_obj = $class::firstOrNew(
[$match_key => $obj->{$match_key}, 'company_id' => $this->company->id], [$match_key => $obj->{$match_key}, 'company_id' => $this->company->id],

View File

@ -220,8 +220,8 @@ class ProcessPostmarkWebhook implements ShouldQueue
SystemLogger::dispatch($this->request, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company); SystemLogger::dispatch($this->request, SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client, $this->invitation->company);
if(config('ninja.notification.slack')) // if(config('ninja.notification.slack'))
$this->invitation->company->notification(new EmailBounceNotification($this->invitation->company->account))->ninja(); // $this->invitation->company->notification(new EmailBounceNotification($this->invitation->company->account))->ninja();
} }

View File

@ -190,7 +190,7 @@ class Import implements ShouldQueue
public function middleware() public function middleware()
{ {
return [new WithoutOverlapping($this->company->account->key)]; return [new WithoutOverlapping($this->company->company_key)];
} }
/** /**

View File

@ -39,7 +39,7 @@ class VersionCheck implements ShouldQueue
nlog("latest version = {$version_file}"); nlog("latest version = {$version_file}");
if ($version_file) { if (Ninja::isSelfHost() && $version_file) {
Account::whereNotNull('id')->update(['latest_version' => $version_file]); Account::whereNotNull('id')->update(['latest_version' => $version_file]);
} }

View File

@ -491,4 +491,24 @@ class Account extends BaseModel
->where('id', $this->decodePrimaryKey($value))->firstOrFail(); ->where('id', $this->decodePrimaryKey($value))->firstOrFail();
} }
public function getTrialDays()
{
if($this->payment_id)
return 0;
$plan_expires = Carbon::parse($this->plan_expires);
if(!$this->payment_id && $plan_expires->gt(now())){
$diff = $plan_expires->diffInDays();
if($diff > 14);
return 0;
return $diff;
}
return 0;
}
} }

View File

@ -204,4 +204,9 @@ class BaseModel extends Model
return $formatted_number; return $formatted_number;
} }
public function translate_entity()
{
return ctrans('texts.item');
}
} }

View File

@ -18,7 +18,7 @@ class PaymentType extends StaticModel
*/ */
public $timestamps = false; public $timestamps = false;
const CREDIT = 1; const CREDIT = 32;
const ACH = 4; const ACH = 4;
const VISA = 5; const VISA = 5;
const MASTERCARD = 6; const MASTERCARD = 6;

View File

@ -32,7 +32,6 @@ class PurchaseOrder extends BaseModel
protected $fillable = [ protected $fillable = [
'number', 'number',
'discount', 'discount',
'company_id',
'status_id', 'status_id',
'last_sent_date', 'last_sent_date',
'is_deleted', 'is_deleted',
@ -272,4 +271,8 @@ class PurchaseOrder extends BaseModel
return $purchase_order_calc->build(); return $purchase_order_calc->build();
} }
public function translate_entity()
{
return ctrans('texts.purchase_order');
}
} }

View File

@ -66,7 +66,19 @@ class AuthorizePaymentDriver extends BaseDriver
public function getClientRequiredFields(): array public function getClientRequiredFields(): array
{ {
return [
$fields = [];
if ($this->company_gateway->require_shipping_address) {
$fields[] = ['name' => 'client_shipping_address_line_1', 'label' => ctrans('texts.shipping_address1'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_shipping_city', 'label' => ctrans('texts.shipping_city'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_shipping_state', 'label' => ctrans('texts.shipping_state'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_shipping_postal_code', 'label' => ctrans('texts.shipping_postal_code'), 'type' => 'text', 'validation' => 'required'];
$fields[] = ['name' => 'client_shipping_country_id', 'label' => ctrans('texts.shipping_country'), 'type' => 'text', 'validation' => 'required'];
}
$data = [
['name' => 'client_name', 'label' => ctrans('texts.name'), 'type' => 'text', 'validation' => 'required|min:2'], ['name' => 'client_name', 'label' => ctrans('texts.name'), 'type' => 'text', 'validation' => 'required|min:2'],
['name' => 'contact_email', 'label' => ctrans('texts.email'), 'type' => 'text', 'validation' => 'required|email:rfc'], ['name' => 'contact_email', 'label' => ctrans('texts.email'), 'type' => 'text', 'validation' => 'required|email:rfc'],
['name' => 'client_address_line_1', 'label' => ctrans('texts.address1'), 'type' => 'text', 'validation' => 'required'], ['name' => 'client_address_line_1', 'label' => ctrans('texts.address1'), 'type' => 'text', 'validation' => 'required'],
@ -75,6 +87,9 @@ class AuthorizePaymentDriver extends BaseDriver
['name' => 'client_postal_code', 'label' => ctrans('texts.postal_code'), 'type' => 'text', 'validation' => 'required'], ['name' => 'client_postal_code', 'label' => ctrans('texts.postal_code'), 'type' => 'text', 'validation' => 'required'],
['name' => 'client_country_id', 'label' => ctrans('texts.country'), 'type' => 'select', 'validation' => 'required'], ['name' => 'client_country_id', 'label' => ctrans('texts.country'), 'type' => 'select', 'validation' => 'required'],
]; ];
return array_merge($fields, $data);
} }
public function authorizeView($payment_method) public function authorizeView($payment_method)

View File

@ -304,9 +304,10 @@ class BaseRepository
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) { if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
//10-07-2022
$model->service()->updateStatus()->save(); $model->service()->updateStatus()->save();
$model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']), "Update adjustment for invoice {$model->number}");
$model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save(); $model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
$model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']), "Update adjustment for invoice {$model->number}");
} }

View File

@ -83,7 +83,7 @@ class PaymentRepository extends BaseRepository {
$client->service()->updatePaidToDate($data['amount'])->save(); $client->service()->updatePaidToDate($data['amount'])->save();
} }
// elseif($data['amount'] >0){
else{ else{
//this fixes an edge case with unapplied payments //this fixes an edge case with unapplied payments
$client->service()->updatePaidToDate($data['amount'])->save(); $client->service()->updatePaidToDate($data['amount'])->save();

View File

@ -116,7 +116,7 @@ class AddGatewayFee extends AbstractService
$this->invoice $this->invoice
->ledger() ->ledger()
->updateInvoiceBalance($adjustment, 'Adjustment for removing gateway fee'); ->updateInvoiceBalance($adjustment, 'Adjustment for adding gateway fee');
} }
return $this->invoice; return $this->invoice;
@ -165,7 +165,7 @@ class AddGatewayFee extends AbstractService
$this->invoice $this->invoice
->ledger() ->ledger()
->updateInvoiceBalance($adjustment * -1, 'Adjustment for removing gateway fee'); ->updateInvoiceBalance($adjustment * -1, 'Adjustment for adding gateway fee');
} }

View File

@ -14,6 +14,7 @@ namespace App\Services\Payment;
use App\Events\Invoice\InvoiceWasUpdated; use App\Events\Invoice\InvoiceWasUpdated;
use App\Jobs\Invoice\InvoiceWorkflowSettings; use App\Jobs\Invoice\InvoiceWorkflowSettings;
use App\Jobs\Ninja\TransactionLog; use App\Jobs\Ninja\TransactionLog;
use App\Models\Client;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Payment; use App\Models\Payment;
use App\Models\PaymentHash; use App\Models\PaymentHash;
@ -48,8 +49,6 @@ class UpdateInvoicePayment
collect($paid_invoices)->each(function ($paid_invoice) use ($invoices, $client) { collect($paid_invoices)->each(function ($paid_invoice) use ($invoices, $client) {
$client = $client->fresh();
$invoice = $invoices->first(function ($inv) use ($paid_invoice) { $invoice = $invoices->first(function ($inv) use ($paid_invoice) {
return $paid_invoice->invoice_id == $inv->hashed_id; return $paid_invoice->invoice_id == $inv->hashed_id;
}); });
@ -63,9 +62,15 @@ class UpdateInvoicePayment
$paid_amount = $paid_invoice->amount; $paid_amount = $paid_invoice->amount;
} }
$client->paid_to_date += $paid_amount; \DB::connection(config('database.default'))->transaction(function () use($client, $paid_amount){
$client->balance -= $paid_amount;
$client->save(); $update_client = Client::withTrashed()->where('id', $client->id)->lockForUpdate()->first();
$update_client->paid_to_date += $paid_amount;
$update_client->balance -= $paid_amount;
$update_client->save();
}, 1);
/* Need to determine here is we have an OVER payment - if YES only apply the max invoice amount */ /* Need to determine here is we have an OVER payment - if YES only apply the max invoice amount */
if($paid_amount > $invoice->partial && $paid_amount > $invoice->balance) if($paid_amount > $invoice->partial && $paid_amount > $invoice->balance)

View File

@ -46,7 +46,7 @@ class ApplyNumber extends AbstractService
$this->trySaving(); $this->trySaving();
break; break;
case 'when_sent': case 'when_sent':
if ($this->invoice->status_id == PurchaseOrder::STATUS_SENT) { if ($this->purchase_order->status_id == PurchaseOrder::STATUS_SENT) {
$this->trySaving(); $this->trySaving();
} }
break; break;

View File

@ -13,9 +13,11 @@ namespace App\Services\PurchaseOrder;
use App\Factory\ExpenseFactory; use App\Factory\ExpenseFactory;
use App\Models\PurchaseOrder; use App\Models\PurchaseOrder;
use App\Utils\Traits\GeneratesCounter;
class PurchaseOrderExpense class PurchaseOrderExpense
{ {
use GeneratesCounter;
private PurchaseOrder $purchase_order; private PurchaseOrder $purchase_order;
@ -36,11 +38,25 @@ class PurchaseOrderExpense
$expense->public_notes = $this->purchase_order->public_notes; $expense->public_notes = $this->purchase_order->public_notes;
$expense->uses_inclusive_taxes = $this->purchase_order->uses_inclusive_taxes; $expense->uses_inclusive_taxes = $this->purchase_order->uses_inclusive_taxes;
$expense->calculate_tax_by_amount = true; $expense->calculate_tax_by_amount = true;
$expense->private_notes = ctrans('texts.purchase_order_number_short') . " " . $this->purchase_order->number;
$line_items = $this->purchase_order->line_items;
$expense->public_notes = '';
foreach($line_items as $line_item){
$expense->public_notes .= $line_item->quantity . " x " . $line_item->product_key. " [ " .$line_item->notes . " ]\n";
}
$tax_map = $this->purchase_order->calc()->getTaxMap(); $tax_map = $this->purchase_order->calc()->getTaxMap();
if($this->purchase_order->total_taxes > 0)
{
$expense->tax_amount1 = $this->purchase_order->total_taxes; $expense->tax_amount1 = $this->purchase_order->total_taxes;
$expense->tax_name1 = ctrans("texts.tax"); $expense->tax_name1 = ctrans("texts.tax");
}
$expense->number = empty($expense->number) ? $this->getNextExpenseNumber($expense) : $expense->number;
$expense->save(); $expense->save();

View File

@ -48,19 +48,27 @@ class PurchaseOrderService
public function fillDefaults() public function fillDefaults()
{ {
// $settings = $this->purchase_order->client->getMergedSettings();
// //TODO implement design, footer, terms $settings = $this->purchase_order->company->settings;
// /* If client currency differs from the company default currency, then insert the client exchange rate on the model.*/ if (! $this->purchase_order->design_id)
// if (!isset($this->purchase_order->exchange_rate) && $this->purchase_order->client->currency()->id != (int)$this->purchase_order->company->settings->currency_id) $this->purchase_order->design_id = $this->decodePrimaryKey($settings->invoice_design_id);
// $this->purchase_order->exchange_rate = $this->purchase_order->client->currency()->exchange_rate;
// if (!isset($this->purchase_order->public_notes)) if (!isset($this->invoice->footer) || empty($this->invoice->footer))
// $this->purchase_order->public_notes = $this->purchase_order->client->public_notes; $this->purchase_order->footer = $settings->purchase_order_footer;
if (!isset($this->purchase_order->terms) || empty($this->purchase_order->terms))
$this->purchase_order->terms = $settings->purchase_order_terms;
if (!isset($this->purchase_order->public_notes) || empty($this->purchase_order->public_notes))
$this->purchase_order->public_notes = $this->purchase_order->vendor->public_notes;
if($settings->counter_number_applied == 'when_saved'){
$this->applyNumber()->save();
}
return $this; return $this;
} }
public function triggeredActions($request) public function triggeredActions($request)

View File

@ -11,6 +11,7 @@
namespace App\Services\Recurring; namespace App\Services\Recurring;
use App\Jobs\RecurringInvoice\SendRecurring;
use App\Jobs\Util\UnlinkFile; use App\Jobs\Util\UnlinkFile;
use App\Models\RecurringInvoice; use App\Models\RecurringInvoice;
use App\Services\Recurring\GetInvoicePdf; use App\Services\Recurring\GetInvoicePdf;
@ -106,6 +107,10 @@ class RecurringService
$this->stop(); $this->stop();
} }
if ($request->has('send_now') && $request->input('send_now') == 'true' && $this->recurring_entity->invoices()->count() == 0) {
$this->sendNow();
}
if(isset($this->recurring_entity->client)) if(isset($this->recurring_entity->client))
{ {
$offset = $this->recurring_entity->client->timezone_offset(); $offset = $this->recurring_entity->client->timezone_offset();
@ -115,6 +120,18 @@ class RecurringService
return $this; return $this;
} }
public function sendNow()
{
if($this->recurring_entity instanceof RecurringInvoice && $this->recurring_entity->status_id == RecurringInvoice::STATUS_DRAFT){
$this->start()->save();
SendRecurring::dispatchNow($this->recurring_entity, $this->recurring_entity->company->db);
}
return $this->recurring_entity;
}
public function fillDefaults() public function fillDefaults()
{ {

View File

@ -86,7 +86,8 @@ class AccountTransformer extends EntityTransformer
'hosted_client_count' => (int) $account->hosted_client_count, 'hosted_client_count' => (int) $account->hosted_client_count,
'hosted_company_count' => (int) $account->hosted_company_count, 'hosted_company_count' => (int) $account->hosted_company_count,
'is_hosted' => (bool) Ninja::isHosted(), 'is_hosted' => (bool) Ninja::isHosted(),
'set_react_as_default_ap' => (bool) $account->set_react_as_default_ap 'set_react_as_default_ap' => (bool) $account->set_react_as_default_ap,
'trial_days_left' => Ninja::isHosted() ? (int) $account->getTrialDays() : 0,
]; ];
} }
@ -110,6 +111,5 @@ class AccountTransformer extends EntityTransformer
return $this->includeItem(auth()->user(), $transformer, User::class); return $this->includeItem(auth()->user(), $transformer, User::class);
// return $this->includeItem($account->default_company->owner(), $transformer, User::class);
} }
} }

View File

@ -13,6 +13,8 @@ namespace App\Transformers;
use App\Models\Document; use App\Models\Document;
use App\Models\Task; use App\Models\Task;
use App\Models\TaskStatus;
use App\Transformers\TaskStatusTransformer;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
@ -32,6 +34,7 @@ class TaskTransformer extends EntityTransformer
*/ */
protected $availableIncludes = [ protected $availableIncludes = [
'client', 'client',
'status'
]; ];
public function includeDocuments(Task $task) public function includeDocuments(Task $task)
@ -41,13 +44,27 @@ class TaskTransformer extends EntityTransformer
return $this->includeCollection($task->documents, $transformer, Document::class); return $this->includeCollection($task->documents, $transformer, Document::class);
} }
public function includeClient(Task $task): Item public function includeClient(Task $task): ?Item
{ {
$transformer = new ClientTransformer($this->serializer); $transformer = new ClientTransformer($this->serializer);
if(!$task->client)
return null;
return $this->includeItem($task->client, $transformer, Client::class); return $this->includeItem($task->client, $transformer, Client::class);
} }
public function includeStatus(Task $task): ?Item
{
$transformer = new TaskStatusTransformer($this->serializer);
if(!$task->status)
return null;
return $this->includeItem($task->status, $transformer, TaskStatus::class);
}
public function transform(Task $task) public function transform(Task $task)
{ {
return [ return [

219
composer.lock generated
View File

@ -434,16 +434,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.230.0", "version": "3.231.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "474f351aff22cc7a61016c1de79d7d2fe6c80d2b" "reference": "4ea642d1c7f8002037ef46e5f17c9fc1273a6021"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/474f351aff22cc7a61016c1de79d7d2fe6c80d2b", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/4ea642d1c7f8002037ef46e5f17c9fc1273a6021",
"reference": "474f351aff22cc7a61016c1de79d7d2fe6c80d2b", "reference": "4ea642d1c7f8002037ef46e5f17c9fc1273a6021",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -461,6 +461,7 @@
"andrewsville/php-token-reflection": "^1.4", "andrewsville/php-token-reflection": "^1.4",
"aws/aws-php-sns-message-validator": "~1.0", "aws/aws-php-sns-message-validator": "~1.0",
"behat/behat": "~3.0", "behat/behat": "~3.0",
"composer/composer": "^1.10.22",
"doctrine/cache": "~1.4", "doctrine/cache": "~1.4",
"ext-dom": "*", "ext-dom": "*",
"ext-openssl": "*", "ext-openssl": "*",
@ -519,9 +520,9 @@
"support": { "support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues", "issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.230.0" "source": "https://github.com/aws/aws-sdk-php/tree/3.231.5"
}, },
"time": "2022-07-05T18:19:42+00:00" "time": "2022-07-13T18:36:03+00:00"
}, },
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@ -2244,16 +2245,16 @@
}, },
{ {
"name": "gocardless/gocardless-pro", "name": "gocardless/gocardless-pro",
"version": "4.17.0", "version": "4.19.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/gocardless/gocardless-pro-php.git", "url": "https://github.com/gocardless/gocardless-pro-php.git",
"reference": "59ccdcbfbbf1a18b55c749ed121137dce6d6f3ae" "reference": "ed88cd22b6a790ee37758afa8bf7c9d43caa796c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/59ccdcbfbbf1a18b55c749ed121137dce6d6f3ae", "url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/ed88cd22b6a790ee37758afa8bf7c9d43caa796c",
"reference": "59ccdcbfbbf1a18b55c749ed121137dce6d6f3ae", "reference": "ed88cd22b6a790ee37758afa8bf7c9d43caa796c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2293,9 +2294,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/gocardless/gocardless-pro-php/issues", "issues": "https://github.com/gocardless/gocardless-pro-php/issues",
"source": "https://github.com/gocardless/gocardless-pro-php/tree/v4.17.0" "source": "https://github.com/gocardless/gocardless-pro-php/tree/v4.19.0"
}, },
"time": "2022-06-29T12:55:58+00:00" "time": "2022-07-13T14:44:43+00:00"
}, },
{ {
"name": "google/apiclient", "name": "google/apiclient",
@ -2369,16 +2370,16 @@
}, },
{ {
"name": "google/apiclient-services", "name": "google/apiclient-services",
"version": "v0.256.0", "version": "v0.257.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/googleapis/google-api-php-client-services.git", "url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "122e51021eb19b53f831904918460671d1e7259d" "reference": "ae109202ee831a1fb70ba824181852e6179c848b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/122e51021eb19b53f831904918460671d1e7259d", "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/ae109202ee831a1fb70ba824181852e6179c848b",
"reference": "122e51021eb19b53f831904918460671d1e7259d", "reference": "ae109202ee831a1fb70ba824181852e6179c848b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2407,9 +2408,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/googleapis/google-api-php-client-services/issues", "issues": "https://github.com/googleapis/google-api-php-client-services/issues",
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.256.0" "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.257.0"
}, },
"time": "2022-07-04T01:10:37+00:00" "time": "2022-07-08T01:28:13+00:00"
}, },
{ {
"name": "google/auth", "name": "google/auth",
@ -3679,16 +3680,16 @@
}, },
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v8.83.18", "version": "v8.83.19",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/framework.git", "url": "https://github.com/laravel/framework.git",
"reference": "db8188e9cc8359a5c6706fa9d9f55aad7f235077" "reference": "4264f2ee12330bdb1be050998f58ba7271236395"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/db8188e9cc8359a5c6706fa9d9f55aad7f235077", "url": "https://api.github.com/repos/laravel/framework/zipball/4264f2ee12330bdb1be050998f58ba7271236395",
"reference": "db8188e9cc8359a5c6706fa9d9f55aad7f235077", "reference": "4264f2ee12330bdb1be050998f58ba7271236395",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3848,7 +3849,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2022-06-28T14:30:38+00:00" "time": "2022-07-13T13:23:09+00:00"
}, },
{ {
"name": "laravel/serializable-closure", "name": "laravel/serializable-closure",
@ -5123,16 +5124,16 @@
}, },
{ {
"name": "microsoft/microsoft-graph", "name": "microsoft/microsoft-graph",
"version": "1.70.0", "version": "1.72.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/microsoftgraph/msgraph-sdk-php.git", "url": "https://github.com/microsoftgraph/msgraph-sdk-php.git",
"reference": "7d85293be037c4a2891a03cb953eb204bf68387e" "reference": "2cf18e6f3e4519a2a749ce4656b6d3bcae1e1ac4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/7d85293be037c4a2891a03cb953eb204bf68387e", "url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/2cf18e6f3e4519a2a749ce4656b6d3bcae1e1ac4",
"reference": "7d85293be037c4a2891a03cb953eb204bf68387e", "reference": "2cf18e6f3e4519a2a749ce4656b6d3bcae1e1ac4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5168,22 +5169,22 @@
"homepage": "https://developer.microsoft.com/en-us/graph", "homepage": "https://developer.microsoft.com/en-us/graph",
"support": { "support": {
"issues": "https://github.com/microsoftgraph/msgraph-sdk-php/issues", "issues": "https://github.com/microsoftgraph/msgraph-sdk-php/issues",
"source": "https://github.com/microsoftgraph/msgraph-sdk-php/tree/1.70.0" "source": "https://github.com/microsoftgraph/msgraph-sdk-php/tree/1.72.0"
}, },
"time": "2022-06-21T13:37:02+00:00" "time": "2022-07-12T16:45:29+00:00"
}, },
{ {
"name": "mollie/mollie-api-php", "name": "mollie/mollie-api-php",
"version": "v2.44.1", "version": "v2.45.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/mollie/mollie-api-php.git", "url": "https://github.com/mollie/mollie-api-php.git",
"reference": "5906cf9ff3133a4f47fea47624f3839ac07d0805" "reference": "43ae5471967a47b34752b6b3a229038a05034527"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/5906cf9ff3133a4f47fea47624f3839ac07d0805", "url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/43ae5471967a47b34752b6b3a229038a05034527",
"reference": "5906cf9ff3133a4f47fea47624f3839ac07d0805", "reference": "43ae5471967a47b34752b6b3a229038a05034527",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -5260,9 +5261,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/mollie/mollie-api-php/issues", "issues": "https://github.com/mollie/mollie-api-php/issues",
"source": "https://github.com/mollie/mollie-api-php/tree/v2.44.1" "source": "https://github.com/mollie/mollie-api-php/tree/v2.45.0"
}, },
"time": "2022-05-24T14:03:01+00:00" "time": "2022-07-11T15:03:39+00:00"
}, },
{ {
"name": "moneyphp/money", "name": "moneyphp/money",
@ -6577,16 +6578,16 @@
}, },
{ {
"name": "php-http/discovery", "name": "php-http/discovery",
"version": "1.14.2", "version": "1.14.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-http/discovery.git", "url": "https://github.com/php-http/discovery.git",
"reference": "c8d48852fbc052454af42f6de27635ddd916b959" "reference": "31d8ee46d0215108df16a8527c7438e96a4d7735"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-http/discovery/zipball/c8d48852fbc052454af42f6de27635ddd916b959", "url": "https://api.github.com/repos/php-http/discovery/zipball/31d8ee46d0215108df16a8527c7438e96a4d7735",
"reference": "c8d48852fbc052454af42f6de27635ddd916b959", "reference": "31d8ee46d0215108df16a8527c7438e96a4d7735",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -6638,9 +6639,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/php-http/discovery/issues", "issues": "https://github.com/php-http/discovery/issues",
"source": "https://github.com/php-http/discovery/tree/1.14.2" "source": "https://github.com/php-http/discovery/tree/1.14.3"
}, },
"time": "2022-05-25T07:26:05+00:00" "time": "2022-07-11T14:04:40+00:00"
}, },
{ {
"name": "php-http/guzzle7-adapter", "name": "php-http/guzzle7-adapter",
@ -7659,16 +7660,16 @@
}, },
{ {
"name": "psy/psysh", "name": "psy/psysh",
"version": "v0.11.6", "version": "v0.11.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/bobthecow/psysh.git", "url": "https://github.com/bobthecow/psysh.git",
"reference": "3f5b5f8aaa979fbd0d1783173f4c82ad529fe621" "reference": "77fc7270031fbc28f9a7bea31385da5c4855cb7a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/3f5b5f8aaa979fbd0d1783173f4c82ad529fe621", "url": "https://api.github.com/repos/bobthecow/psysh/zipball/77fc7270031fbc28f9a7bea31385da5c4855cb7a",
"reference": "3f5b5f8aaa979fbd0d1783173f4c82ad529fe621", "reference": "77fc7270031fbc28f9a7bea31385da5c4855cb7a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -7729,9 +7730,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/bobthecow/psysh/issues", "issues": "https://github.com/bobthecow/psysh/issues",
"source": "https://github.com/bobthecow/psysh/tree/v0.11.6" "source": "https://github.com/bobthecow/psysh/tree/v0.11.7"
}, },
"time": "2022-07-03T16:40:23+00:00" "time": "2022-07-07T13:49:11+00:00"
}, },
{ {
"name": "ralouphie/getallheaders", "name": "ralouphie/getallheaders",
@ -12852,30 +12853,29 @@
}, },
{ {
"name": "barryvdh/laravel-debugbar", "name": "barryvdh/laravel-debugbar",
"version": "v3.6.8", "version": "v3.7.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git", "url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "814b36a08a60f4159cdcbb1c466a6a0027440b6c" "reference": "3372ed65e6d2039d663ed19aa699956f9d346271"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/814b36a08a60f4159cdcbb1c466a6a0027440b6c", "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/3372ed65e6d2039d663ed19aa699956f9d346271",
"reference": "814b36a08a60f4159cdcbb1c466a6a0027440b6c", "reference": "3372ed65e6d2039d663ed19aa699956f9d346271",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"illuminate/routing": "^6|^7|^8|^9", "illuminate/routing": "^7|^8|^9",
"illuminate/session": "^6|^7|^8|^9", "illuminate/session": "^7|^8|^9",
"illuminate/support": "^6|^7|^8|^9", "illuminate/support": "^7|^8|^9",
"maximebf/debugbar": "^1.17.2", "maximebf/debugbar": "^1.17.2",
"php": ">=7.2", "php": ">=7.2.5",
"symfony/debug": "^4.3|^5|^6", "symfony/finder": "^5|^6"
"symfony/finder": "^4.3|^5|^6"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": "^1.3.3", "mockery/mockery": "^1.3.3",
"orchestra/testbench-dusk": "^4|^5|^6|^7", "orchestra/testbench-dusk": "^5|^6|^7",
"phpunit/phpunit": "^8.5|^9.0", "phpunit/phpunit": "^8.5|^9.0",
"squizlabs/php_codesniffer": "^3.5" "squizlabs/php_codesniffer": "^3.5"
}, },
@ -12921,7 +12921,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues", "issues": "https://github.com/barryvdh/laravel-debugbar/issues",
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.8" "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.7.0"
}, },
"funding": [ "funding": [
{ {
@ -12933,20 +12933,20 @@
"type": "github" "type": "github"
} }
], ],
"time": "2022-06-08T15:03:05+00:00" "time": "2022-07-11T09:26:42+00:00"
}, },
{ {
"name": "brianium/paratest", "name": "brianium/paratest",
"version": "v6.5.1", "version": "v6.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/paratestphp/paratest.git", "url": "https://github.com/paratestphp/paratest.git",
"reference": "41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9" "reference": "bce7b965a5fe5028a53c3151042ca12777600acd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9", "url": "https://api.github.com/repos/paratestphp/paratest/zipball/bce7b965a5fe5028a53c3151042ca12777600acd",
"reference": "41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9", "reference": "bce7b965a5fe5028a53c3151042ca12777600acd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -12961,18 +12961,18 @@
"phpunit/php-timer": "^5.0.3", "phpunit/php-timer": "^5.0.3",
"phpunit/phpunit": "^9.5.21", "phpunit/phpunit": "^9.5.21",
"sebastian/environment": "^5.1.4", "sebastian/environment": "^5.1.4",
"symfony/console": "^5.4.9 || ^6.1.1", "symfony/console": "^5.4.9 || ^6.1.2",
"symfony/process": "^5.4.8 || ^6.1.0" "symfony/process": "^5.4.8 || ^6.1.0"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^9.0.0", "doctrine/coding-standard": "^9.0.0",
"ext-pcov": "*", "ext-pcov": "*",
"ext-posix": "*", "ext-posix": "*",
"infection/infection": "^0.26.12", "infection/infection": "^0.26.13",
"malukenho/mcbumpface": "^1.1.5", "malukenho/mcbumpface": "^1.1.5",
"squizlabs/php_codesniffer": "^3.7.1", "squizlabs/php_codesniffer": "^3.7.1",
"symfony/filesystem": "^5.4.9 || ^6.1.0", "symfony/filesystem": "^5.4.9 || ^6.1.0",
"vimeo/psalm": "^4.23.0" "vimeo/psalm": "^4.24.0"
}, },
"bin": [ "bin": [
"bin/paratest", "bin/paratest",
@ -13013,7 +13013,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/paratestphp/paratest/issues", "issues": "https://github.com/paratestphp/paratest/issues",
"source": "https://github.com/paratestphp/paratest/tree/v6.5.1" "source": "https://github.com/paratestphp/paratest/tree/v6.6.0"
}, },
"funding": [ "funding": [
{ {
@ -13025,7 +13025,7 @@
"type": "paypal" "type": "paypal"
} }
], ],
"time": "2022-06-24T16:02:27+00:00" "time": "2022-07-12T07:15:58+00:00"
}, },
{ {
"name": "composer/pcre", "name": "composer/pcre",
@ -13896,16 +13896,16 @@
}, },
{ {
"name": "laravel/dusk", "name": "laravel/dusk",
"version": "v6.24.0", "version": "v6.25.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laravel/dusk.git", "url": "https://github.com/laravel/dusk.git",
"reference": "7fed3695741787d9998c5f04c94adfd62d70e766" "reference": "b4632b7493a187d31afc5c9ddec437c81b16421a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laravel/dusk/zipball/7fed3695741787d9998c5f04c94adfd62d70e766", "url": "https://api.github.com/repos/laravel/dusk/zipball/b4632b7493a187d31afc5c9ddec437c81b16421a",
"reference": "7fed3695741787d9998c5f04c94adfd62d70e766", "reference": "b4632b7493a187d31afc5c9ddec437c81b16421a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -13963,9 +13963,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/laravel/dusk/issues", "issues": "https://github.com/laravel/dusk/issues",
"source": "https://github.com/laravel/dusk/tree/v6.24.0" "source": "https://github.com/laravel/dusk/tree/v6.25.0"
}, },
"time": "2022-05-09T13:43:52+00:00" "time": "2022-07-11T11:38:43+00:00"
}, },
{ {
"name": "maximebf/debugbar", "name": "maximebf/debugbar",
@ -16154,75 +16154,6 @@
}, },
"time": "2021-10-14T14:25:14+00:00" "time": "2021-10-14T14:25:14+00:00"
}, },
{
"name": "symfony/debug",
"version": "v4.4.41",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "6637e62480b60817b9a6984154a533e8e64c6bd5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/6637e62480b60817b9a6984154a533e8e64c6bd5",
"reference": "6637e62480b60817b9a6984154a533e8e64c6bd5",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "^1|^2|^3"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "^3.4|^4.0|^5.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides tools to ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/debug/tree/v4.4.41"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"abandoned": "symfony/error-handler",
"time": "2022-04-12T15:19:55+00:00"
},
{ {
"name": "symfony/polyfill-php70", "name": "symfony/polyfill-php70",
"version": "v1.20.0", "version": "v1.20.0",

View File

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true), 'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.4.9', 'app_version' => '5.4.10',
'app_tag' => '5.4.9', 'app_tag' => '5.4.10',
'minimum_client_version' => '5.0.16', 'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1', 'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''), 'api_secret' => env('API_SECRET', ''),
@ -194,5 +194,8 @@ return [
'ninja_apple_bundle_id' => env('APPLE_BUNDLE_ID', false), 'ninja_apple_bundle_id' => env('APPLE_BUNDLE_ID', false),
'ninja_apple_issuer_id' => env('APPLE_ISSUER_ID', false), 'ninja_apple_issuer_id' => env('APPLE_ISSUER_ID', false),
'react_app_enabled' => env('REACT_APP_ENABLED', false), 'react_app_enabled' => env('REACT_APP_ENABLED', false),
'ninja_apple_client_id' => env('APPLE_CLIENT_ID', false),
'ninja_apple_client_secret' => env('APPLE_CLIENT_SECRET',false),
'ninja_apple_redirect_url' => env('APPLE_REDIRECT_URI',false),
]; ];

View File

@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIndexToPaymentHash extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('payment_hashes', function (Blueprint $table) {
$table->string('hash', 255)->index()->change();
});
Schema::table('activities', function (Blueprint $table) {
$table->index(['quote_id', 'company_id']);
$table->index(['recurring_invoice_id', 'company_id']);
$table->index(['purchase_order_id', 'company_id']);
$table->index(['vendor_contact_id', 'company_id']);
});
Schema::table('products', function (Blueprint $table) {
$table->index(['company_id', 'user_id', 'assigned_user_id', 'updated_at'],'pro_co_us_up_index');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
}

View File

@ -5978,6 +5978,10 @@ google_sign_in_platform_interface
google_sign_in_web google_sign_in_web
image_picker_for_web image_picker_for_web
image_picker_platform_interface image_picker_platform_interface
in_app_purchase
in_app_purchase_android
in_app_purchase_platform_interface
in_app_purchase_storekit
local_auth local_auth
package_info package_info
path_provider path_provider
@ -16760,6 +16764,36 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
sign_in_with_apple
Copyright 2019 sign_in_with_apple authors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.ˀ
--------------------------------------------------------------------------------
sign_in_with_apple_platform_interface
Copyright 2021 sign_in_with_apple_platform_interface authors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.ˀ
--------------------------------------------------------------------------------
sign_in_with_apple_web
Copyright 2021 sign_in_with_apple_web authors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.ˀ
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
skcms skcms
vulkan vulkan

View File

@ -3,43 +3,43 @@ const MANIFEST = 'flutter-app-manifest';
const TEMP = 'flutter-temp-cache'; const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache'; const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = { const RESOURCES = {
"favicon.png": "dca91c54388f52eded692718d5a98b8b", "favicon.ico": "51636d3a390451561744c42188ccd628",
"canvaskit/canvaskit.js": "c2b4e5f3d7a3d82aed024e7249a78487", "manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900", "assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd", "assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba", "assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
"/": "64646ca7ed0ecaa992228dad831af5cc", "assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
"assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a",
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",
"assets/NOTICES": "c6e3ca05e75eaf4b48a1de0f34708ab4",
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
"assets/fonts/MaterialIcons-Regular.otf": "95db9098c58fd6db106f1116bae85a0b",
"version.json": "4dfad0f7098e523184a2f58aff0e3940",
"flutter.js": "eb2682e33f25cd8f1fc59011497c35f8", "flutter.js": "eb2682e33f25cd8f1fc59011497c35f8",
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35", "icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed", "icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40", "canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
"version.json": "69380d22a7eec2ffb5bf7efff4808f6d", "canvaskit/canvaskit.js": "c2b4e5f3d7a3d82aed024e7249a78487",
"favicon.ico": "51636d3a390451561744c42188ccd628", "canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f", "canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
"assets/fonts/MaterialIcons-Regular.otf": "95db9098c58fd6db106f1116bae85a0b", "/": "f0472d186e41814a028b5ca7814378c4",
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5", "favicon.png": "dca91c54388f52eded692718d5a98b8b",
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541", "main.dart.js": "fe987ef50f1a627038a89c1f4f1dabb0"
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
"assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a",
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",
"assets/NOTICES": "f02d972147eb81eae2a8202a2914cb88",
"main.dart.js": "de27ceaac92f1f3f73522e1cfd7c42c1"
}; };
// The application shell files that are downloaded before a service worker can // The application shell files that are downloaded before a service worker can

264008
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

260046
public/main.foss.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"app_name":"invoiceninja_flutter","version":"5.0.87","build_number":"87","package_name":"invoiceninja_flutter"} {"app_name":"invoiceninja_flutter","version":"5.0.88","build_number":"88","package_name":"invoiceninja_flutter"}

View File

@ -2247,7 +2247,7 @@ $LANG = array(
'navigation_variables' => 'Navigation Variables', 'navigation_variables' => 'Navigation Variables',
'custom_variables' => 'Custom Variables', 'custom_variables' => 'Custom Variables',
'invalid_file' => 'Invalid file type', 'invalid_file' => 'Invalid file type',
'add_documents_to_invoice' => 'Add documents to invoice', 'add_documents_to_invoice' => 'Add Documents to Invoice',
'mark_expense_paid' => 'Mark paid', 'mark_expense_paid' => 'Mark paid',
'white_label_license_error' => 'Failed to validate the license, check storage/logs/laravel-error.log for more details.', 'white_label_license_error' => 'Failed to validate the license, check storage/logs/laravel-error.log for more details.',
'plan_price' => 'Plan Price', 'plan_price' => 'Plan Price',

View File

@ -8,6 +8,7 @@
<meta name="google-signin-client_id" content="{{ config('services.google.client_id') }}"> <meta name="google-signin-client_id" content="{{ config('services.google.client_id') }}">
<link rel="manifest" href="manifest.json?v={{ config('ninja.app_version') }}"> <link rel="manifest" href="manifest.json?v={{ config('ninja.app_version') }}">
<script src="{{ asset('js/pdf.min.js') }}"></script> <script src="{{ asset('js/pdf.min.js') }}"></script>
<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
<script type="text/javascript"> <script type="text/javascript">
pdfjsLib.GlobalWorkerOptions.workerSrc = "{{ asset('js/pdf.worker.min.js') }}"; pdfjsLib.GlobalWorkerOptions.workerSrc = "{{ asset('js/pdf.worker.min.js') }}";
</script> </script>

View File

@ -39,6 +39,11 @@
{{ ctrans('texts.invoice_number') }} {{ ctrans('texts.invoice_number') }}
</span> </span>
</th> </th>
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
<span role="button" wire:click="sortBy('number')" class="cursor-pointer">
{{ ctrans('texts.po_number') }}
</span>
</th>
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary"> <th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
<span role="button" wire:click="sortBy('date')" class="cursor-pointer"> <span role="button" wire:click="sortBy('date')" class="cursor-pointer">
{{ ctrans('texts.invoice_date') }} {{ ctrans('texts.invoice_date') }}
@ -78,6 +83,9 @@
<td class="px-6 py-4 text-sm leading-5 text-gray-500 whitespace-nowrap"> <td class="px-6 py-4 text-sm leading-5 text-gray-500 whitespace-nowrap">
{{ $invoice->number }} {{ $invoice->number }}
</td> </td>
<td class="px-6 py-4 text-sm leading-5 text-gray-500 whitespace-nowrap">
{{ $invoice->po_number }}
</td>
<td class="px-6 py-4 text-sm leading-5 text-gray-500 whitespace-nowrap"> <td class="px-6 py-4 text-sm leading-5 text-gray-500 whitespace-nowrap">
{{ $invoice->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()) }} {{ $invoice->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()) }}
</td> </td>

View File

@ -42,6 +42,7 @@ Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale
Route::put('clients/{client}/adjust_ledger', 'ClientController@adjustLedger')->name('clients.adjust_ledger'); Route::put('clients/{client}/adjust_ledger', 'ClientController@adjustLedger')->name('clients.adjust_ledger');
Route::put('clients/{client}/upload', 'ClientController@upload')->name('clients.upload'); Route::put('clients/{client}/upload', 'ClientController@upload')->name('clients.upload');
Route::post('clients/{client}/purge', 'ClientController@purge')->name('clients.purge')->middleware('password_protected'); Route::post('clients/{client}/purge', 'ClientController@purge')->name('clients.purge')->middleware('password_protected');
Route::post('clients/{client}/{mergeable_client}/merge', 'ClientController@merge')->name('clients.merge')->middleware('password_protected');
Route::post('clients/bulk', 'ClientController@bulk')->name('clients.bulk'); Route::post('clients/bulk', 'ClientController@bulk')->name('clients.bulk');
Route::post('filters/{entity}', 'FilterController@index')->name('filters'); Route::post('filters/{entity}', 'FilterController@index')->name('filters');
@ -157,7 +158,7 @@ Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale
Route::post('recurring_quotes/bulk', 'RecurringQuoteController@bulk')->name('recurring_quotes.bulk'); Route::post('recurring_quotes/bulk', 'RecurringQuoteController@bulk')->name('recurring_quotes.bulk');
Route::put('recurring_quotes/{recurring_quote}/upload', 'RecurringQuoteController@upload'); Route::put('recurring_quotes/{recurring_quote}/upload', 'RecurringQuoteController@upload');
Route::post('refresh', 'Auth\LoginController@refresh')->middleware('throttle:150,3'); Route::post('refresh', 'Auth\LoginController@refresh')->middleware('throttle:300,3');
Route::post('reports/clients', 'Reports\ClientReportController'); Route::post('reports/clients', 'Reports\ClientReportController');
Route::post('reports/contacts', 'Reports\ClientContactReportController'); Route::post('reports/contacts', 'Reports\ClientContactReportController');

View File

@ -53,8 +53,9 @@ Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_clie
Route::get('payments', 'ClientPortal\PaymentController@index')->name('payments.index')->middleware('portal_enabled'); Route::get('payments', 'ClientPortal\PaymentController@index')->name('payments.index')->middleware('portal_enabled');
Route::get('payments/{payment}', 'ClientPortal\PaymentController@show')->name('payments.show'); Route::get('payments/{payment}', 'ClientPortal\PaymentController@show')->name('payments.show');
Route::post('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response');
Route::get('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response.get'); // Route::post('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response');
// Route::get('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response.get');
Route::get('profile/{client_contact}/edit', 'ClientPortal\ProfileController@edit')->name('profile.edit'); Route::get('profile/{client_contact}/edit', 'ClientPortal\ProfileController@edit')->name('profile.edit');
Route::put('profile/{client_contact}/edit', 'ClientPortal\ProfileController@update')->name('profile.update'); Route::put('profile/{client_contact}/edit', 'ClientPortal\ProfileController@update')->name('profile.update');
@ -99,6 +100,9 @@ Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_clie
}); });
Route::post('payments/process/response', 'ClientPortal\PaymentController@response')->name('client.payments.response')->middleware(['locale', 'domain_db', 'verify_hash']);
Route::get('payments/process/response', 'ClientPortal\PaymentController@response')->name('client.payments.response.get')->middleware(['locale', 'domain_db', 'verify_hash']);
Route::get('client/subscriptions/{subscription}/purchase', 'ClientPortal\SubscriptionPurchaseController@index')->name('client.subscription.purchase')->middleware('domain_db'); Route::get('client/subscriptions/{subscription}/purchase', 'ClientPortal\SubscriptionPurchaseController@index')->name('client.subscription.purchase')->middleware('domain_db');
Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () { Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {