Merge branch 'v5-develop' into v5-stable

This commit is contained in:
David Bomba 2022-07-19 20:24:19 +10:00
commit cffb51762a
152 changed files with 332328 additions and 312559 deletions

View File

@ -1 +1 @@
5.4.6
5.4.11

View File

@ -106,8 +106,8 @@ class CheckData extends Command
}
$this->checkInvoiceBalances();
$this->checkClientBalanceEdgeCases();
$this->checkPaidToDatesNew();
$this->checkContacts();
$this->checkVendorContacts();
$this->checkEntityInvitations();
@ -655,6 +655,39 @@ class CheckData extends Command
$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()
{
$results = \DB::select( \DB::raw("

View File

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

View File

@ -291,7 +291,10 @@ class CompanySettings extends BaseSettings
public $email_from_name = '';
public $auto_archive_invoice_cancelled = false;
public $vendor_portal_enable_uploads=false;
public static $casts = [
'vendor_portal_enable_uploads' => 'bool',
'besr_id' => 'string',
'qr_iban' => 'string',
'email_subject_purchase_order' => 'string',

View File

@ -13,7 +13,7 @@ class PaymentFailed extends Exception
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', [
'message' => $this->getMessage(),
'code' => $this->getCode(),

View File

@ -67,7 +67,7 @@ class InvoiceFilters extends QueryFilters
return $this->builder;
}
public function number(string $number) :Builder
public function number(string $number = '') :Builder
{
return $this->builder->where('number', $number);
}

View File

@ -94,6 +94,9 @@ class QuoteFilters extends QueryFilters
{
$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]);
}

View File

@ -101,16 +101,12 @@ class InvoiceSum
private function calculateCustomValues()
{
// $this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge1, $this->invoice->custom_surcharge_tax1);
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge1);
// $this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge2, $this->invoice->custom_surcharge_tax2);
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge2);
// $this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge3, $this->invoice->custom_surcharge_tax3);
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge3);
// $this->total_taxes += $this->valuerTax($this->invoice->custom_surcharge4, $this->invoice->custom_surcharge_tax4);
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge4);
$this->total += $this->total_custom_values;
@ -155,7 +151,7 @@ class InvoiceSum
*/
private function calculateBalance()
{
//$this->invoice->balance = $this->balance($this->getTotal(), $this->invoice);
$this->setCalculatedAttributes();
return $this;
@ -174,22 +170,6 @@ class InvoiceSum
{
$this->total += $this->total_taxes;
// if (is_numeric($this->invoice->custom_value1)) {
// $this->total += $this->invoice->custom_value1;
// }
// if (is_numeric($this->invoice->custom_value2)) {
// $this->total += $this->invoice->custom_value2;
// }
// if (is_numeric($this->invoice->custom_value3)) {
// $this->total += $this->invoice->custom_value3;
// }
// if (is_numeric($this->invoice->custom_value4)) {
// $this->total += $this->invoice->custom_value4;
// }
return $this;
}

View File

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

View File

@ -601,7 +601,18 @@ class CreditController extends BaseController
}
break;
case 'email':
// EmailCredit::dispatch($credit, $credit->company);
$credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) {
EmailEntity::dispatch($invitation, $credit->company, 'credit');
});
if (! $bulk) {
return response()->json(['message'=>'email sent'], 200);
}
break;
case 'send_email':
$credit->invitations->load('contact.client.country', 'credit.client.country', 'credit.company')->each(function ($invitation) use ($credit) {
EmailEntity::dispatch($invitation, $credit->company, 'credit');

View File

@ -17,12 +17,15 @@ use App\Http\Middleware\UserVerified;
use App\Http\Requests\Email\SendEmailRequest;
use App\Jobs\Entity\EmailEntity;
use App\Jobs\Mail\EntitySentMailer;
use App\Jobs\PurchaseOrder\PurchaseOrderEmail;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\PurchaseOrder;
use App\Models\Quote;
use App\Models\RecurringInvoice;
use App\Transformers\CreditTransformer;
use App\Transformers\InvoiceTransformer;
use App\Transformers\PurchaseOrderTransformer;
use App\Transformers\QuoteTransformer;
use App\Transformers\RecurringInvoiceTransformer;
use App\Utils\Ninja;
@ -125,6 +128,10 @@ class EmailController extends BaseController
'body' => $body
];
if($entity == 'purchaseOrder' || $template == 'purchase_order'){
return $this->sendPurchaseOrder($entity_obj, $data);
}
$entity_obj->invitations->each(function ($invitation) use ($data, $entity_string, $entity_obj, $template) {
if (!$invitation->contact->trashed() && $invitation->contact->email) {
@ -176,4 +183,17 @@ class EmailController extends BaseController
return $this->itemResponse($entity_obj->fresh());
}
private function sendPurchaseOrder($entity_obj, $data)
{
$this->entity_type = PurchaseOrder::class;
$this->entity_transformer = PurchaseOrderTransformer::class;
PurchaseOrderEmail::dispatch($entity_obj, $entity_obj->company, $data);
return $this->itemResponse($entity_obj);
}
}

View File

@ -745,13 +745,7 @@ class InvoiceController extends BaseController
$this->itemResponse($invoice);
}
break;
// case 'reverse':
// $invoice = $invoice->service()->handleReversal()->deletePdf()->save();
// if (! $bulk) {
// $this->itemResponse($invoice);
// }
// break;
case 'email':
//check query parameter for email_type and set the template else use calculateTemplate
@ -769,6 +763,24 @@ class InvoiceController extends BaseController
}
break;
case 'send_email':
//check query parameter for email_type and set the template else use calculateTemplate
if (request()->has('email_type') && property_exists($invoice->company->settings, request()->input('email_type'))) {
$this->reminder_template = $invoice->client->getSetting(request()->input('email_type'));
} else {
$this->reminder_template = $invoice->calculateTemplate('invoice');
}
BulkInvoiceJob::dispatch($invoice, $this->reminder_template);
if (! $bulk) {
return response()->json(['message' => 'email sent'], 200);
}
break;
default:
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
break;

View File

@ -179,6 +179,7 @@ class MigrationController extends BaseController
$company->tasks()->forceDelete();
$company->vendors()->forceDelete();
$company->expenses()->forceDelete();
$company->purchase_orders()->forceDelete();
$settings = $company->settings;
@ -196,6 +197,7 @@ class MigrationController extends BaseController
$settings->ticket_number_counter = 1;
$settings->payment_number_counter = 1;
$settings->project_number_counter = 1;
$settings->purchase_order_number_counter = 1;
$company->settings = $settings;

View File

@ -23,21 +23,27 @@ use App\Http\Requests\PurchaseOrder\EditPurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\ShowPurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\StorePurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\UpdatePurchaseOrderRequest;
use App\Http\Requests\PurchaseOrder\UploadPurchaseOrderRequest;
use App\Jobs\Invoice\ZipInvoices;
use App\Jobs\PurchaseOrder\PurchaseOrderEmail;
use App\Jobs\PurchaseOrder\ZipPurchaseOrders;
use App\Models\Account;
use App\Models\Client;
use App\Models\Expense;
use App\Models\PurchaseOrder;
use App\Repositories\PurchaseOrderRepository;
use App\Transformers\ExpenseTransformer;
use App\Transformers\PurchaseOrderTransformer;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;
class PurchaseOrderController extends BaseController
{
use MakesHash;
use SavesDocuments;
protected $entity_type = PurchaseOrder::class;
protected $entity_transformer = PurchaseOrderTransformer::class;
@ -361,6 +367,10 @@ class PurchaseOrderController extends BaseController
$purchase_order = $this->purchase_order_repository->save($request->all(), $purchase_order);
$purchase_order = $purchase_order->service()
->triggeredActions($request)
->save();
event(new PurchaseOrderWasUpdated($purchase_order, $purchase_order->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
return $this->itemResponse($purchase_order);
@ -636,6 +646,31 @@ class PurchaseOrderController extends BaseController
if (! $bulk) {
return response()->json(['message' => 'email sent'], 200);
}
break;
case 'send_email':
//check query parameter for email_type and set the template else use calculateTemplate
PurchaseOrderEmail::dispatch($purchase_order, $purchase_order->company);
if (! $bulk) {
return response()->json(['message' => 'email sent'], 200);
}
break;
case 'add_to_inventory':
$purchase_order->service()->add_to_inventory();
return $this->itemResponse($purchase_order);
case 'expense':
if($purchase_order->expense()->exists())
return response()->json(['message' => ctrans('texts.purchase_order_already_expensed')], 400);
$expense = $purchase_order->service()->expense();
return $this->itemResponse($purchase_order);
case 'cancel':
@ -655,4 +690,69 @@ class PurchaseOrderController extends BaseController
break;
}
}
/**
* Update the specified resource in storage.
*
* @param UploadPurchaseOrderRequest $request
* @param PurchaseOrder $purchase_order
* @return Response
*
*
*
* @OA\Put(
* path="/api/v1/purchase_orders/{id}/upload",
* operationId="uploadPurchaseOrder",
* tags={"purchase_orders"},
* summary="Uploads a document to a purchase_orders",
* description="Handles the uploading of a document to a purchase_order",
* @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 Purchase Order Hashed ID",
* example="D2J234DFA",
* required=true,
* @OA\Schema(
* type="string",
* format="string",
* ),
* ),
* @OA\Response(
* response=200,
* description="Returns the Purchase Order 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\JsonContent(ref="#/components/schemas/Vendor"),
* ),
* @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 upload(UploadPurchaseOrderRequest $request, PurchaseOrder $purchase_order)
{
if(!$this->checkFeature(Account::FEATURE_DOCUMENTS))
return $this->featureFailure();
if ($request->has('documents'))
$this->saveDocuments($request->file('documents'), $purchase_order);
return $this->itemResponse($purchase_order->fresh());
}
}

View File

@ -722,6 +722,13 @@ class QuoteController extends BaseController
return response()->json(['message'=> ctrans('texts.sent_message')], 200);
break;
case 'send_email':
$quote->service()->sendEmail();
return response()->json(['message'=> ctrans('texts.sent_message')], 200);
break;
case 'mark_sent':
$quote->service()->markSent()->save();

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));
// $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()
->triggeredActions($request)
->save();
@ -702,6 +698,15 @@ class RecurringInvoiceController extends BaseController
$this->itemResponse($recurring_invoice);
}
break;
case 'send_now':
$recurring_invoice = $recurring_invoice->service()->sendNow();
if (! $bulk) {
$this->itemResponse($recurring_invoice);
}
break;
default:
// code...

View File

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

View File

@ -0,0 +1,41 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Controllers\VendorPortal;
use App\Http\Controllers\Controller;
use App\Http\Requests\VendorPortal\Uploads\StoreUploadRequest;
use App\Models\PurchaseOrder;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SavesDocuments;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\Response;
class UploadController extends Controller
{
use SavesDocuments;
use MakesHash;
/**
* Main logic behind uploading the files.
*
* @param StoreUploadRequest $request
* @return Response|ResponseFactory
*/
public function upload(StoreUploadRequest $request, PurchaseOrder $purchase_order)
{
$this->saveDocuments($request->getFile(), $purchase_order, true);
return response([], 200);
}
}

View File

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

View File

@ -144,7 +144,7 @@ class BillingPortalPurchase extends Component
*
* @var int
*/
public $quantity = 1;
public $quantity;
/**
* First-hit request data (queries, locales...).
@ -183,6 +183,8 @@ class BillingPortalPurchase extends Component
{
MultiDB::setDb($this->company->db);
$this->quantity = 1;
$this->price = $this->subscription->price;
if (request()->query('coupon')) {
@ -358,7 +360,7 @@ class BillingPortalPurchase extends Component
$this->invoice = $this->subscription
->service()
->createInvoice($data)
->createInvoice($data, $this->quantity)
->service()
->markSent()
->fillDefaults()
@ -433,13 +435,14 @@ class BillingPortalPurchase extends Component
if ($option == 'increment') {
$this->quantity++;
return $this->price = (int)$this->price + $this->subscription->product->price;
$this->price = $this->subscription->promo_price * $this->quantity;
return $this->quantity;
}
$this->quantity--;
$this->price = (int)$this->price - $this->subscription->product->price;
$this->quantity--;
$this->price = $this->subscription->promo_price * $this->quantity;
return 0;
return $this->quantity;
}
public function handleCoupon()

View File

@ -73,6 +73,12 @@ class RequiredClientInfo extends Component
'state',
'postal_code',
'country_id',
'shipping_address1',
'shipping_address2',
'shipping_city',
'shipping_state',
'shipping_postal_code',
'shipping_country_id',
];
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

@ -18,7 +18,7 @@ class ShowRecurringInvoiceRequest extends Request
{
public function authorize() : bool
{
return auth()->guard('contact')->user()->client->id === $this->recurring_invoice->client_id
return auth()->guard('contact')->user()->client->id == $this->recurring_invoice->client_id
&& auth()->guard('contact')->user()->company->enabled_modules & PortalComposer::MODULE_RECURRING_INVOICES;
}

View File

@ -1,4 +1,14 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Requests\ClientPortal\Uploads;

View File

@ -63,10 +63,6 @@ class StoreCompanyRequest extends Request
{
$input = $this->all();
//https not sure i should be forcing this.
// if(array_key_exists('portal_domain', $input) && strlen($input['portal_domain']) > 1)
// $input['portal_domain'] = str_replace("http:", "https:", $input['portal_domain']);
if (array_key_exists('google_analytics_url', $input)) {
$input['google_analytics_key'] = $input['google_analytics_url'];
}

View File

@ -13,6 +13,7 @@ namespace App\Http\Requests\Email;
use App\Http\Requests\Request;
use App\Utils\Traits\MakesHash;
use Illuminate\Support\Str;
class SendEmailRequest extends Request
{
@ -60,7 +61,7 @@ class SendEmailRequest extends Request
$input['entity_id'] = $this->decodePrimaryKey($input['entity_id']);
if(array_key_exists('entity', $input))
$input['entity'] = "App\Models\\".ucfirst($input['entity']);
$input['entity'] = "App\Models\\".ucfirst(Str::camel($input['entity']));
$this->replace($input);
}

View File

@ -14,6 +14,7 @@ namespace App\Http\Requests\Expense;
use App\Http\Requests\Request;
use App\Http\ValidationRules\Expense\UniqueExpenseNumberRule;
use App\Models\Expense;
use App\Models\PurchaseOrder;
use App\Utils\Traits\MakesHash;
use Illuminate\Validation\Rule;

View File

@ -62,9 +62,6 @@ class UpdateInvoiceRequest extends Request
$rules['discount'] = 'sometimes|numeric';
$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;
}

View File

@ -0,0 +1,39 @@
<?php
/**
* Quote Ninja (https://paymentninja.com).
*
* @link https://github.com/paymentninja/paymentninja source repository
*
* @copyright Copyright (c) 2022. Quote Ninja LLC (https://paymentninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Requests\PurchaseOrder;
use App\Http\Requests\Request;
class UploadPurchaseOrderRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize() : bool
{
return auth()->user()->can('edit', $this->purchase_order);
}
public function rules()
{
$rules = [];
if($this->input('documents'))
$rules['documents'] = 'file|mimes:csv,png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
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) {
if (isset($input['invitations'][$key]['id']) && is_numeric($input['invitations'][$key]['id'])) {
unset($input['invitations'][$key]['id']);

View File

@ -1,10 +1,10 @@
<?php
/**
* Quote Ninja (https://paymentninja.com).
* Invoice Ninja (https://paymentninja.com).
*
* @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
*/
@ -24,7 +24,7 @@ class SortTaskRequest extends Request
{
return true;
// return auth()->user()->can('edit', $this->task);
}
public function rules()

View File

@ -0,0 +1,55 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Requests\VendorPortal\Uploads;
use Illuminate\Foundation\Http\FormRequest;
class StoreUploadRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return (bool) auth()->guard('vendor')->user()->vendor->company->getSetting('vendor_portal_enable_uploads');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'file' => ['file', 'mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000'],
];
}
/**
* Since saveDocuments() expects an array of uploaded files,
* we need to convert it to an array before uploading.
*
* @return mixed
*/
public function getFile()
{
if (gettype($this->file) !== 'array') {
return [$this->file];
}
return $this->file;
}
}

View File

@ -44,7 +44,7 @@ class ValidCreditsPresentRule implements Rule
{
//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')))
->count();

View File

@ -20,6 +20,7 @@ use App\Mail\DownloadInvoices;
use App\Models\Company;
use App\Models\CreditInvitation;
use App\Models\InvoiceInvitation;
use App\Models\PurchaseOrderInvitation;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoice;
use App\Models\RecurringInvoiceInvitation;
@ -32,8 +33,8 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Storage;
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){
$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();
@ -439,6 +440,31 @@ class CompanyExport implements ShouldQueue
})->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();
$this->zipAndSend();

View File

@ -45,6 +45,8 @@ use App\Models\PaymentTerm;
use App\Models\Paymentable;
use App\Models\Product;
use App\Models\Project;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderInvitation;
use App\Models\Quote;
use App\Models\QuoteInvitation;
use App\Models\RecurringExpense;
@ -74,7 +76,6 @@ use Illuminate\Support\Str;
use JsonMachine\JsonDecoder\ExtJsonDecoder;
use JsonMachine\JsonMachine;
use ZipArchive;
use function GuzzleHttp\json_encode;
class CompanyImport implements ShouldQueue
@ -122,6 +123,7 @@ class CompanyImport implements ShouldQueue
'clients',
'client_contacts',
'vendors',
'vendor_contacts',
'projects',
'products',
'company_gateways',
@ -147,6 +149,8 @@ class CompanyImport implements ShouldQueue
'documents',
'webhooks',
'system_logs',
'purchase_orders',
'purchase_order_invitations'
];
private $company_properties = [
@ -454,7 +458,7 @@ class CompanyImport implements ShouldQueue
$settings->ticket_number_counter = 1;
$settings->payment_number_counter = 1;
$settings->project_number_counter = 1;
$settings->purchase_order_number_counter = 1;
$this->company->settings = $co->settings;
// $this->company->settings = $this->backup_file->company->settings;
$this->company->save();
@ -471,6 +475,7 @@ class CompanyImport implements ShouldQueue
$this->company->vendors()->forceDelete();
$this->company->expenses()->forceDelete();
$this->company->subscriptions()->forceDelete();
$this->company->purchase_orders()->forceDelete();
$this->company->save();
@ -649,6 +654,19 @@ class CompanyImport implements ShouldQueue
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()
{
@ -796,6 +814,42 @@ class CompanyImport implements ShouldQueue
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()
{
@ -1425,6 +1479,13 @@ class CompanyImport implements ShouldQueue
$new_obj->save(['timestamps' => false]);
$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})){
$new_obj = new Payment();
$new_obj->company_id = $this->company->id;
@ -1445,6 +1506,12 @@ class CompanyImport implements ShouldQueue
$new_obj->fill($obj_array);
$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})){
$new_obj = new RecurringExpense();
$new_obj->company_id = $this->company->id;
@ -1466,6 +1533,13 @@ class CompanyImport implements ShouldQueue
$new_obj->save(['timestamps' => false]);
$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'){
$new_obj = $class::firstOrNew(
[$match_key => $obj->{$match_key}, 'company_id' => $this->company->id],

View File

@ -334,8 +334,8 @@ class NinjaMailerJob implements ShouldQueue
return true;
/* On the hosted platform we actively scan all outbound emails to ensure outbound email quality remains high */
// if(Ninja::isHosted())
// return (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
if(class_exists(\Modules\Admin\Jobs\Account\EmailQuality::class))
return (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
return false;
}
@ -399,7 +399,7 @@ class NinjaMailerJob implements ShouldQueue
return false;
}
return $user->oauth_user_refresh_token;
return $user->oauth_user_token;
}

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);
if(config('ninja.notification.slack'))
$this->invitation->company->notification(new EmailBounceNotification($this->invitation->company->account))->ninja();
// if(config('ninja.notification.slack'))
// $this->invitation->company->notification(new EmailBounceNotification($this->invitation->company->account))->ninja();
}

View File

@ -85,7 +85,6 @@ class SendRecurring implements ShouldQueue
$invoice = $invoice->service()
->markSent()
->applyNumber()
//->createInvitations() //need to only link invitations to those in the recurring invoice
->fillDefaults()
->adjustInventory()
->save();

View File

@ -190,7 +190,7 @@ class Import implements ShouldQueue
public function middleware()
{
return [new WithoutOverlapping($this->company->account->key)];
return [new WithoutOverlapping($this->company->company_key)];
}
/**
@ -275,7 +275,12 @@ class Import implements ShouldQueue
info('Completed🚀🚀🚀🚀🚀 at '.now());
unlink($this->file_path);
try{
unlink($this->file_path);
}
catch(\Exception $e){
nlog("problem unsetting file");
}
}
private function fixData()
@ -923,6 +928,9 @@ class Import implements ShouldQueue
$modified['company_id'] = $this->company->id;
$modified['line_items'] = $this->cleanItems($modified['line_items']);
if(array_key_exists('next_send_date', $resource))
$modified['next_send_date_client'] = $resource['next_send_date'];
if(array_key_exists('created_at', $modified))
$modified['created_at'] = Carbon::parse($modified['created_at']);

View File

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

View File

@ -21,7 +21,7 @@ class InvoiceArchivedActivity implements ShouldQueue
{
protected $activity_repo;
public $delay = 5;
public $delay = 15;
/**
* Create the event listener.

View File

@ -21,7 +21,7 @@ class InvoicePaidActivity implements ShouldQueue
{
protected $activity_repo;
public $delay = 5;
public $delay = 10;
/**
* Create the event listener.

View File

@ -33,7 +33,7 @@ class Account extends BaseModel
use PresentableTrait;
use MakesHash;
private $free_plan_email_quota = 100;
private $free_plan_email_quota = 50;
private $paid_plan_email_quota = 500;
/**
@ -491,4 +491,24 @@ class Account extends BaseModel
->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;
}
public function translate_entity()
{
return ctrans('texts.item');
}
}

View File

@ -210,7 +210,6 @@ class ClientContact extends Authenticatable implements HasLocalePreference
NinjaMailerJob::dispatch($nmo);
//$this->notify(new ClientContactResetPassword($token));
}
public function preferredLocale()

View File

@ -56,6 +56,7 @@ class Expense extends BaseModel
'tax_amount3',
'uses_inclusive_taxes',
'calculate_tax_by_amount',
'purchase_order_id',
];
protected $casts = [
@ -102,6 +103,11 @@ class Expense extends BaseModel
return $this->belongsTo(Client::class);
}
public function purchase_order()
{
return $this->hasOne(PurchaseOrder::class);
}
public function translate_entity()
{
return ctrans('texts.expense');

View File

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

View File

@ -32,7 +32,6 @@ class PurchaseOrder extends BaseModel
protected $fillable = [
'number',
'discount',
'company_id',
'status_id',
'last_sent_date',
'is_deleted',
@ -72,10 +71,6 @@ class PurchaseOrder extends BaseModel
'custom_surcharge2',
'custom_surcharge3',
'custom_surcharge4',
// 'custom_surcharge_tax1',
// 'custom_surcharge_tax2',
// 'custom_surcharge_tax3',
// 'custom_surcharge_tax4',
'design_id',
'invoice_id',
'assigned_user_id',
@ -83,7 +78,6 @@ class PurchaseOrder extends BaseModel
'balance',
'partial',
'paid_to_date',
// 'subscription_id',
'vendor_id',
'last_viewed'
];
@ -101,7 +95,8 @@ class PurchaseOrder extends BaseModel
const STATUS_DRAFT = 1;
const STATUS_SENT = 2;
const STATUS_ACCEPTED = 3;
const STATUS_CANCELLED = 4;
const STATUS_RECEIVED = 4;
const STATUS_CANCELLED = 5;
public static function stringStatus(int $status)
{
@ -171,6 +166,11 @@ class PurchaseOrder extends BaseModel
return $this->belongsTo(Company::class);
}
public function expense()
{
return $this->belongsTo(Expense::class);
}
public function user()
{
return $this->belongsTo(User::class)->withTrashed();
@ -271,4 +271,8 @@ class PurchaseOrder extends BaseModel
return $purchase_order_calc->build();
}
public function translate_entity()
{
return ctrans('texts.purchase_order');
}
}

View File

@ -71,22 +71,22 @@ class Task extends BaseModel
public function client()
{
return $this->belongsTo(Client::class);
return $this->belongsTo(Client::class)->withTrashed();
}
public function status()
{
return $this->belongsTo(TaskStatus::class);
return $this->belongsTo(TaskStatus::class)->withTrashed();
}
public function invoice()
{
return $this->belongsTo(Invoice::class);
return $this->belongsTo(Invoice::class)->withTrashed();
}
public function project()
{
return $this->belongsTo(Project::class);
return $this->belongsTo(Project::class)->withTrashed();
}

View File

@ -0,0 +1,93 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Notifications\Ninja;
use App\Models\Company;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class EmailQualityNotification extends Notification
{
/**
* Create a new notification instance.
*
* @return void
*/
protected Company $company;
protected string $spam_string;
public function __construct(Company $company, string $spam_string)
{
$this->company = $company;
$this->spam_string = $spam_string;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['slack'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return MailMessage
*/
public function toMail($notifiable)
{
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
public function toSlack($notifiable)
{
$content = "Email Quality notification for Company {$this->company->company_key} \n";
$owner = $this->company->owner();
$content .= "Owner {$owner->present()->name() } | {$owner->email} \n";
$content .= "Spam trigger: {$this->spam_string}";
return (new SlackMessage)
->success()
->from(ctrans('texts.notification_bot'))
->image('https://app.invoiceninja.com/favicon.png')
->content($content);
}
}

View File

@ -78,10 +78,10 @@ class NewAccountNotification extends Notification
public function toSlack($notifiable)
{
$content = "New Trial Started\n";
$content = "{$this->client->name}\n";
$content = "Account key: {$this->account->key}\n";
$content = "Users: {$this->account->users()->pluck('email')}\n";
$content = "Contacts: {$this->client->contacts()->pluck('email')}\n";
$content .= "{$this->client->name}\n";
$content .= "Account key: {$this->account->key}\n";
$content .= "Users: {$this->account->users()->pluck('email')}\n";
$content .= "Contacts: {$this->client->contacts()->pluck('email')}\n";
return (new SlackMessage)

View File

@ -66,7 +66,19 @@ class AuthorizePaymentDriver extends BaseDriver
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' => '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'],
@ -75,6 +87,9 @@ class AuthorizePaymentDriver extends BaseDriver
['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'],
];
return array_merge($fields, $data);
}
public function authorizeView($payment_method)

View File

@ -59,7 +59,7 @@ class Alipay
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
if (in_array($request->redirect_status, ['succeeded', 'pending'])) {
return $this->processSuccesfulRedirect($request->source);
}

View File

@ -81,7 +81,7 @@ class Bancontact
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
if (in_array($request->redirect_status, ['succeeded','pending'])) {
return $this->processSuccessfulPayment($request->payment_intent);
}

View File

@ -80,7 +80,7 @@ class EPS
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
if (in_array($request->redirect_status, ['succeeded','pending'])) {
return $this->processSuccessfulPayment($request->payment_intent);
}

View File

@ -81,7 +81,7 @@ class FPX
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
if (in_array($request->redirect_status, ['succeeded','pending'])) {
return $this->processSuccessfulPayment($request->payment_intent);
}

View File

@ -80,7 +80,7 @@ class GIROPAY
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
if (in_array($request->redirect_status, ['succeeded','pending'])) {
return $this->processSuccessfulPayment($request->payment_intent);
}

View File

@ -80,7 +80,7 @@ class PRZELEWY24
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
if (in_array($request->redirect_status, ['succeeded','pending'])) {
return $this->processSuccessfulPayment($request->payment_intent);
}

View File

@ -77,10 +77,11 @@ class SOFORT
public function paymentResponse($request)
{
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
if (in_array($request->redirect_status, ['succeeded','pending'])) {
return $this->processSuccessfulPayment($request->payment_intent);
}

View File

@ -80,7 +80,7 @@ class iDeal
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
if (in_array($request->redirect_status, ['succeeded','pending'])) {
return $this->processSuccessfulPayment($request->payment_intent);
}

View File

@ -304,9 +304,10 @@ class BaseRepository
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
//10-07-2022
$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->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();
}
// elseif($data['amount'] >0){
else{
//this fixes an edge case with unapplied payments
$client->service()->updatePaidToDate($data['amount'])->save();

View File

@ -28,6 +28,8 @@ class SubscriptionRepository extends BaseRepository
{
use CleanLineItems;
public int $quantity = 1;
public function save($data, Subscription $subscription): ?Subscription
{
$subscription->fill($data);
@ -124,7 +126,7 @@ class SubscriptionRepository extends BaseRepository
private function makeLineItem($product, $multiplier)
{
$item = new InvoiceItem;
$item->quantity = $product->quantity;
$item->quantity = $this->quantity;
$item->product_key = $product->product_key;
$item->notes = $product->notes;
$item->cost = $product->price*$multiplier;

View File

@ -32,7 +32,7 @@ class VendorContactRepository extends BaseRepository
}
/* Get array of IDs which have been removed from the contacts array and soft delete each contact */
$vendor->contacts->pluck('id')->diff($contacts->pluck('id'))->each(function ($contact) {
$vendor->contacts->pluck('hashed_id')->diff($contacts->pluck('id'))->each(function ($contact) {
VendorContact::destroy($contact);
});

View File

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

View File

@ -43,12 +43,10 @@ class ApplyNumber extends AbstractService
switch ($this->client->getSetting('counter_number_applied')) {
case 'when_saved':
$this->trySaving();
// $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id);
break;
case 'when_sent':
if ($this->invoice->status_id == Invoice::STATUS_SENT) {
$this->trySaving();
// $this->invoice->number = $this->getNextInvoiceNumber($this->client, $this->invoice, $this->invoice->recurring_id);
}
break;

View File

@ -310,6 +310,9 @@ class InvoiceService
elseif ($this->invoice->balance > 0 && $this->invoice->balance < $this->invoice->amount) {
$this->invoice->status_id = Invoice::STATUS_PARTIAL;
}
elseif ($this->invoice->balance < 0) {
$this->invoice->status_id = Invoice::STATUS_SENT;
}
return $this;
}

View File

@ -14,6 +14,7 @@ namespace App\Services\Payment;
use App\Events\Invoice\InvoiceWasUpdated;
use App\Jobs\Invoice\InvoiceWorkflowSettings;
use App\Jobs\Ninja\TransactionLog;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentHash;
@ -48,8 +49,6 @@ class UpdateInvoicePayment
collect($paid_invoices)->each(function ($paid_invoice) use ($invoices, $client) {
$client = $client->fresh();
$invoice = $invoices->first(function ($inv) use ($paid_invoice) {
return $paid_invoice->invoice_id == $inv->hashed_id;
});
@ -63,9 +62,15 @@ class UpdateInvoicePayment
$paid_amount = $paid_invoice->amount;
}
$client->paid_to_date += $paid_amount;
$client->balance -= $paid_amount;
$client->save();
\DB::connection(config('database.default'))->transaction(function () use($client, $paid_amount){
$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 */
if($paid_amount > $invoice->partial && $paid_amount > $invoice->balance)

View File

@ -332,7 +332,10 @@ class Design extends BaseDesign
$_variable = explode('.', $variable)[1];
$_customs = ['custom1', 'custom2', 'custom3', 'custom4'];
if (in_array($_variable, $_customs)) {
/* 2/7/2022 don't show custom values if they are empty */
$var = str_replace("custom", "custom_value", $_variable);
if (in_array($_variable, $_customs) && !empty($this->entity->{$var})) {
$elements[] = ['element' => 'tr', 'elements' => [
['element' => 'th', 'content' => $variable . '_label', 'properties' => ['data-ref' => 'entity_details-' . substr($variable, 1) . '_label']],
['element' => 'th', 'content' => $variable, 'properties' => ['data-ref' => 'entity_details-' . substr($variable, 1)]],
@ -778,6 +781,14 @@ class Design extends BaseDesign
}
}
if ($this->entity instanceof Credit) {
// We don't want to show Balanace due on the quotes.
if (in_array('$paid_to_date', $variables)) {
$variables = \array_diff($variables, ['$paid_to_date']);
}
}
foreach (['discount'] as $property) {
$variable = sprintf('%s%s', '$', $property);

View File

@ -41,7 +41,20 @@ class ApplyNumber extends AbstractService
return $this->purchase_order;
}
$this->trySaving();
switch ($this->vendor->company->getSetting('counter_number_applied')) {
case 'when_saved':
$this->trySaving();
break;
case 'when_sent':
if ($this->purchase_order->status_id == PurchaseOrder::STATUS_SENT) {
$this->trySaving();
}
break;
default:
break;
}
return $this->purchase_order;
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Services\PurchaseOrder;
use App\Factory\ExpenseFactory;
use App\Models\PurchaseOrder;
use App\Utils\Traits\GeneratesCounter;
class PurchaseOrderExpense
{
use GeneratesCounter;
private PurchaseOrder $purchase_order;
public function __construct(PurchaseOrder $purchase_order)
{
$this->purchase_order = $purchase_order;
}
public function run()
{
$expense = ExpenseFactory::create($this->purchase_order->company_id, $this->purchase_order->user_id);
$expense->amount = $this->purchase_order->uses_inclusive_taxes ? $this->purchase_order->amount : ($this->purchase_order->amount - $this->purchase_order->total_taxes);
$expense->date = now();
$expense->vendor_id = $this->purchase_order->vendor_id;
$expense->public_notes = $this->purchase_order->public_notes;
$expense->uses_inclusive_taxes = $this->purchase_order->uses_inclusive_taxes;
$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();
if($this->purchase_order->total_taxes > 0)
{
$expense->tax_amount1 = $this->purchase_order->total_taxes;
$expense->tax_name1 = ctrans("texts.tax");
}
$expense->number = empty($expense->number) ? $this->getNextExpenseNumber($expense) : $expense->number;
$expense->save();
$this->purchase_order->expense_id = $expense->id;
$this->purchase_order->save();
return $expense;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Services\PurchaseOrder;
use App\Factory\ExpenseFactory;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Mail\Admin\InventoryNotificationObject;
use App\Models\Product;
use App\Models\PurchaseOrder;
class PurchaseOrderInventory
{
private PurchaseOrder $purchase_order;
public function __construct(PurchaseOrder $purchase_order)
{
$this->purchase_order = $purchase_order;
}
public function run()
{
$line_items = $this->purchase_order->line_items;
foreach($line_items as $item)
{
$p = Product::where('product_key', $item->product_key)->where('company_id', $this->purchase_order->company_id)->first();
if(!$p)
continue;
$p->in_stock_quantity += $item->quantity;
$p->saveQuietly();
}
$this->purchase_order->status_id = PurchaseOrder::STATUS_RECEIVED;
$this->purchase_order->save();
return $this->purchase_order;
}
}

View File

@ -16,6 +16,7 @@ use App\Models\PurchaseOrder;
use App\Services\PurchaseOrder\ApplyNumber;
use App\Services\PurchaseOrder\CreateInvitations;
use App\Services\PurchaseOrder\GetPurchaseOrderPdf;
use App\Services\PurchaseOrder\PurchaseOrderExpense;
use App\Services\PurchaseOrder\TriggeredActions;
use App\Utils\Traits\MakesHash;
@ -40,26 +41,34 @@ class PurchaseOrderService
public function applyNumber()
{
$this->invoice = (new ApplyNumber($this->purchase_order->vendor, $this->purchase_order))->run();
$this->purchase_order = (new ApplyNumber($this->purchase_order->vendor, $this->purchase_order))->run();
return $this;
}
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 (!isset($this->purchase_order->exchange_rate) && $this->purchase_order->client->currency()->id != (int)$this->purchase_order->company->settings->currency_id)
// $this->purchase_order->exchange_rate = $this->purchase_order->client->currency()->exchange_rate;
if (! $this->purchase_order->design_id)
$this->purchase_order->design_id = $this->decodePrimaryKey($settings->invoice_design_id);
// if (!isset($this->purchase_order->public_notes))
// $this->purchase_order->public_notes = $this->purchase_order->client->public_notes;
if (!isset($this->invoice->footer) || empty($this->invoice->footer))
$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;
}
public function triggeredActions($request)
@ -115,6 +124,28 @@ class PurchaseOrderService
return $this;
}
public function add_to_inventory()
{
if($this->purchase_order->status_id >= PurchaseOrder::STATUS_RECEIVED)
return $this->purchase_order;
$this->purchase_order = (new PurchaseOrderInventory($this->purchase_order))->run();
return $this;
}
public function expense()
{
$this->markSent();
if($this->purchase_order->expense()->exists())
return $this;
$expense = (new PurchaseOrderExpense($this->purchase_order))->run();
return $expense;
}
/**
* Saves the purchase order.
* @return \App\Models\PurchaseOrder object

View File

@ -11,6 +11,7 @@
namespace App\Services\Recurring;
use App\Jobs\RecurringInvoice\SendRecurring;
use App\Jobs\Util\UnlinkFile;
use App\Models\RecurringInvoice;
use App\Services\Recurring\GetInvoicePdf;
@ -106,6 +107,10 @@ class RecurringService
$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))
{
$offset = $this->recurring_entity->client->timezone_offset();
@ -115,6 +120,18 @@ class RecurringService
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()
{

View File

@ -706,11 +706,12 @@ class SubscriptionService
* @param array $data
* @return Invoice
*/
public function createInvoice($data): ?\App\Models\Invoice
public function createInvoice($data, $quantity = 1): ?\App\Models\Invoice
{
$invoice_repo = new InvoiceRepository();
$subscription_repo = new SubscriptionRepository();
$subscription_repo->quantity = $quantity;
$invoice = InvoiceFactory::create($this->subscription->company_id, $this->subscription->user_id);
$invoice->line_items = $subscription_repo->generateLineItems($this->subscription);

View File

@ -86,7 +86,8 @@ class AccountTransformer extends EntityTransformer
'hosted_client_count' => (int) $account->hosted_client_count,
'hosted_company_count' => (int) $account->hosted_company_count,
'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($account->default_company->owner(), $transformer, User::class);
}
}

View File

@ -78,7 +78,6 @@ class ExpenseTransformer extends EntityTransformer
'transaction_reference' => (string) $expense->transaction_reference ?: '',
'transaction_id' => (string) $expense->transaction_id ?: '',
'date' => $expense->date ?: '',
//'expense_date' => $expense->date ?: '',
'number' => (string)$expense->number ?: '',
'payment_date' => $expense->payment_date ?: '',
'custom_value1' => $expense->custom_value1 ?: '',

View File

@ -14,6 +14,7 @@ namespace App\Transformers;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderInvitation;
use App\Transformers\DocumentTransformer;
use App\Utils\Traits\MakesHash;
class PurchaseOrderTransformer extends EntityTransformer
@ -22,6 +23,11 @@ class PurchaseOrderTransformer extends EntityTransformer
protected $defaultIncludes = [
'invitations',
'documents'
];
protected $availableIncludes = [
'expense'
];
public function includeInvitations(PurchaseOrder $purchase_order)
@ -31,6 +37,21 @@ class PurchaseOrderTransformer extends EntityTransformer
return $this->includeCollection($purchase_order->invitations, $transformer, PurchaseOrderInvitation::class);
}
public function includeDocuments(PurchaseOrder $purchase_order)
{
$transformer = new DocumentTransformer($this->serializer);
return $this->includeCollection($purchase_order->documents, $transformer, Document::class);
}
public function includeExpense(PurchaseOrder $purchase_order)
{
$transformer = new ExpenseTransformer($this->serializer);
return $this->includeItem($purchase_order->expense, $transformer, Document::class);
}
public function transform(PurchaseOrder $purchase_order)
{
return [
@ -93,6 +114,7 @@ class PurchaseOrderTransformer extends EntityTransformer
'exchange_rate' => (float)$purchase_order->exchange_rate,
'paid_to_date' => (float)$purchase_order->paid_to_date,
'subscription_id' => $this->encodePrimaryKey($purchase_order->subscription_id),
'expense_id' => $this->encodePrimaryKey($purchase_order->expense_id),
];
}

View File

@ -13,7 +13,10 @@ namespace App\Transformers;
use App\Models\Document;
use App\Models\Task;
use App\Models\TaskStatus;
use App\Transformers\TaskStatusTransformer;
use App\Utils\Traits\MakesHash;
use League\Fractal\Resource\Item;
/**
* class TaskTransformer.
@ -30,6 +33,8 @@ class TaskTransformer extends EntityTransformer
* @var array
*/
protected $availableIncludes = [
'client',
'status'
];
public function includeDocuments(Task $task)
@ -39,6 +44,27 @@ class TaskTransformer extends EntityTransformer
return $this->includeCollection($task->documents, $transformer, Document::class);
}
public function includeClient(Task $task): ?Item
{
$transformer = new ClientTransformer($this->serializer);
if(!$task->client)
return null;
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)
{
return [

View File

@ -85,9 +85,6 @@ class TemplateEngine
public function build()
{
if ($this->template == 'email_template_null')
$this->template = 'email_template_purchase_order';
return $this->setEntity()
->setSettingsObject()
->setTemplates()
@ -185,7 +182,8 @@ class TemplateEngine
'allow_unsafe_links' => false,
]);
$this->body = $converter->convert($this->body);
$this->body = $converter->convert($this->body)->getContent();
}
private function entityValues($contact)

View File

@ -89,8 +89,9 @@ trait ClientGroupSettingsSaver
if(property_exists($settings, 'translations'))
unset($settings->translations);
//18-07-2022 removed || empty($settings->{$key}) from this check to allow "0" values to persist
foreach ($settings as $key => $value) {
if (! isset($settings->{$key}) || empty($settings->{$key}) || (! is_object($settings->{$key}) && strlen($settings->{$key}) == 0)) {
if (! isset($settings->{$key}) || (! is_object($settings->{$key}) && strlen($settings->{$key}) == 0)) {
unset($settings->{$key});
}
}

284
composer.lock generated
View File

@ -434,16 +434,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.229.0",
"version": "3.231.5",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "5e01f0809682060dc5018bf5f267f40c32f4944d"
"reference": "4ea642d1c7f8002037ef46e5f17c9fc1273a6021"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5e01f0809682060dc5018bf5f267f40c32f4944d",
"reference": "5e01f0809682060dc5018bf5f267f40c32f4944d",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/4ea642d1c7f8002037ef46e5f17c9fc1273a6021",
"reference": "4ea642d1c7f8002037ef46e5f17c9fc1273a6021",
"shasum": ""
},
"require": {
@ -461,6 +461,7 @@
"andrewsville/php-token-reflection": "^1.4",
"aws/aws-php-sns-message-validator": "~1.0",
"behat/behat": "~3.0",
"composer/composer": "^1.10.22",
"doctrine/cache": "~1.4",
"ext-dom": "*",
"ext-openssl": "*",
@ -519,9 +520,9 @@
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.229.0"
"source": "https://github.com/aws/aws-sdk-php/tree/3.231.5"
},
"time": "2022-06-29T18:15:30+00:00"
"time": "2022-07-13T18:36:03+00:00"
},
{
"name": "bacon/bacon-qr-code",
@ -741,16 +742,16 @@
},
{
"name": "checkout/checkout-sdk-php",
"version": "2.5.1",
"version": "2.5.2",
"source": {
"type": "git",
"url": "https://github.com/checkout/checkout-sdk-php.git",
"reference": "097b862487f7583fd0fab47a08e3dc0800f5c3e4"
"reference": "ab1e493ac9aa9c0350f58f069f6157b2a02a7e27"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/097b862487f7583fd0fab47a08e3dc0800f5c3e4",
"reference": "097b862487f7583fd0fab47a08e3dc0800f5c3e4",
"url": "https://api.github.com/repos/checkout/checkout-sdk-php/zipball/ab1e493ac9aa9c0350f58f069f6157b2a02a7e27",
"reference": "ab1e493ac9aa9c0350f58f069f6157b2a02a7e27",
"shasum": ""
},
"require": {
@ -803,9 +804,9 @@
],
"support": {
"issues": "https://github.com/checkout/checkout-sdk-php/issues",
"source": "https://github.com/checkout/checkout-sdk-php/tree/2.5.1"
"source": "https://github.com/checkout/checkout-sdk-php/tree/2.5.2"
},
"time": "2022-06-13T00:23:23+00:00"
"time": "2022-06-30T14:46:15+00:00"
},
{
"name": "cleverit/ubl_invoice",
@ -2244,16 +2245,16 @@
},
{
"name": "gocardless/gocardless-pro",
"version": "4.17.0",
"version": "4.19.0",
"source": {
"type": "git",
"url": "https://github.com/gocardless/gocardless-pro-php.git",
"reference": "59ccdcbfbbf1a18b55c749ed121137dce6d6f3ae"
"reference": "ed88cd22b6a790ee37758afa8bf7c9d43caa796c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/59ccdcbfbbf1a18b55c749ed121137dce6d6f3ae",
"reference": "59ccdcbfbbf1a18b55c749ed121137dce6d6f3ae",
"url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/ed88cd22b6a790ee37758afa8bf7c9d43caa796c",
"reference": "ed88cd22b6a790ee37758afa8bf7c9d43caa796c",
"shasum": ""
},
"require": {
@ -2293,9 +2294,9 @@
],
"support": {
"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",
@ -2369,16 +2370,16 @@
},
{
"name": "google/apiclient-services",
"version": "v0.255.0",
"version": "v0.257.0",
"source": {
"type": "git",
"url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "2b895ceb08eb106f65e975221e5d2e971cf7470e"
"reference": "ae109202ee831a1fb70ba824181852e6179c848b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/2b895ceb08eb106f65e975221e5d2e971cf7470e",
"reference": "2b895ceb08eb106f65e975221e5d2e971cf7470e",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/ae109202ee831a1fb70ba824181852e6179c848b",
"reference": "ae109202ee831a1fb70ba824181852e6179c848b",
"shasum": ""
},
"require": {
@ -2407,9 +2408,9 @@
],
"support": {
"issues": "https://github.com/googleapis/google-api-php-client-services/issues",
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.255.0"
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.257.0"
},
"time": "2022-06-27T01:30:11+00:00"
"time": "2022-07-08T01:28:13+00:00"
},
{
"name": "google/auth",
@ -3679,16 +3680,16 @@
},
{
"name": "laravel/framework",
"version": "v8.83.18",
"version": "v8.83.19",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "db8188e9cc8359a5c6706fa9d9f55aad7f235077"
"reference": "4264f2ee12330bdb1be050998f58ba7271236395"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/db8188e9cc8359a5c6706fa9d9f55aad7f235077",
"reference": "db8188e9cc8359a5c6706fa9d9f55aad7f235077",
"url": "https://api.github.com/repos/laravel/framework/zipball/4264f2ee12330bdb1be050998f58ba7271236395",
"reference": "4264f2ee12330bdb1be050998f58ba7271236395",
"shasum": ""
},
"require": {
@ -3848,7 +3849,7 @@
"issues": "https://github.com/laravel/framework/issues",
"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",
@ -4671,16 +4672,16 @@
},
{
"name": "league/flysystem-aws-s3-v3",
"version": "1.0.29",
"version": "1.0.30",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git",
"reference": "4e25cc0582a36a786c31115e419c6e40498f6972"
"reference": "af286f291ebab6877bac0c359c6c2cb017eb061d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/4e25cc0582a36a786c31115e419c6e40498f6972",
"reference": "4e25cc0582a36a786c31115e419c6e40498f6972",
"url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/af286f291ebab6877bac0c359c6c2cb017eb061d",
"reference": "af286f291ebab6877bac0c359c6c2cb017eb061d",
"shasum": ""
},
"require": {
@ -4716,9 +4717,23 @@
"description": "Flysystem adapter for the AWS S3 SDK v3.x",
"support": {
"issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues",
"source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/1.0.29"
"source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/1.0.30"
},
"time": "2020-10-08T18:58:37+00:00"
"funding": [
{
"url": "https://offset.earth/frankdejonge",
"type": "custom"
},
{
"url": "https://github.com/frankdejonge",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/league/flysystem",
"type": "tidelift"
}
],
"time": "2022-07-02T13:51:38+00:00"
},
{
"name": "league/flysystem-cached-adapter",
@ -5109,16 +5124,16 @@
},
{
"name": "microsoft/microsoft-graph",
"version": "1.70.0",
"version": "1.72.0",
"source": {
"type": "git",
"url": "https://github.com/microsoftgraph/msgraph-sdk-php.git",
"reference": "7d85293be037c4a2891a03cb953eb204bf68387e"
"reference": "2cf18e6f3e4519a2a749ce4656b6d3bcae1e1ac4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/7d85293be037c4a2891a03cb953eb204bf68387e",
"reference": "7d85293be037c4a2891a03cb953eb204bf68387e",
"url": "https://api.github.com/repos/microsoftgraph/msgraph-sdk-php/zipball/2cf18e6f3e4519a2a749ce4656b6d3bcae1e1ac4",
"reference": "2cf18e6f3e4519a2a749ce4656b6d3bcae1e1ac4",
"shasum": ""
},
"require": {
@ -5154,22 +5169,22 @@
"homepage": "https://developer.microsoft.com/en-us/graph",
"support": {
"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",
"version": "v2.44.1",
"version": "v2.45.0",
"source": {
"type": "git",
"url": "https://github.com/mollie/mollie-api-php.git",
"reference": "5906cf9ff3133a4f47fea47624f3839ac07d0805"
"reference": "43ae5471967a47b34752b6b3a229038a05034527"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/5906cf9ff3133a4f47fea47624f3839ac07d0805",
"reference": "5906cf9ff3133a4f47fea47624f3839ac07d0805",
"url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/43ae5471967a47b34752b6b3a229038a05034527",
"reference": "43ae5471967a47b34752b6b3a229038a05034527",
"shasum": ""
},
"require": {
@ -5246,9 +5261,9 @@
],
"support": {
"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",
@ -6563,16 +6578,16 @@
},
{
"name": "php-http/discovery",
"version": "1.14.2",
"version": "1.14.3",
"source": {
"type": "git",
"url": "https://github.com/php-http/discovery.git",
"reference": "c8d48852fbc052454af42f6de27635ddd916b959"
"reference": "31d8ee46d0215108df16a8527c7438e96a4d7735"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-http/discovery/zipball/c8d48852fbc052454af42f6de27635ddd916b959",
"reference": "c8d48852fbc052454af42f6de27635ddd916b959",
"url": "https://api.github.com/repos/php-http/discovery/zipball/31d8ee46d0215108df16a8527c7438e96a4d7735",
"reference": "31d8ee46d0215108df16a8527c7438e96a4d7735",
"shasum": ""
},
"require": {
@ -6624,9 +6639,9 @@
],
"support": {
"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",
@ -7645,16 +7660,16 @@
},
{
"name": "psy/psysh",
"version": "v0.11.5",
"version": "v0.11.7",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
"reference": "c23686f9c48ca202710dbb967df8385a952a2daf"
"reference": "77fc7270031fbc28f9a7bea31385da5c4855cb7a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/c23686f9c48ca202710dbb967df8385a952a2daf",
"reference": "c23686f9c48ca202710dbb967df8385a952a2daf",
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/77fc7270031fbc28f9a7bea31385da5c4855cb7a",
"reference": "77fc7270031fbc28f9a7bea31385da5c4855cb7a",
"shasum": ""
},
"require": {
@ -7715,9 +7730,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
"source": "https://github.com/bobthecow/psysh/tree/v0.11.5"
"source": "https://github.com/bobthecow/psysh/tree/v0.11.7"
},
"time": "2022-05-27T18:03:49+00:00"
"time": "2022-07-07T13:49:11+00:00"
},
{
"name": "ralouphie/getallheaders",
@ -12838,30 +12853,29 @@
},
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.6.7",
"version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "b96f9820aaf1ff9afe945207883149e1c7afb298"
"reference": "3372ed65e6d2039d663ed19aa699956f9d346271"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/b96f9820aaf1ff9afe945207883149e1c7afb298",
"reference": "b96f9820aaf1ff9afe945207883149e1c7afb298",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/3372ed65e6d2039d663ed19aa699956f9d346271",
"reference": "3372ed65e6d2039d663ed19aa699956f9d346271",
"shasum": ""
},
"require": {
"illuminate/routing": "^6|^7|^8|^9",
"illuminate/session": "^6|^7|^8|^9",
"illuminate/support": "^6|^7|^8|^9",
"illuminate/routing": "^7|^8|^9",
"illuminate/session": "^7|^8|^9",
"illuminate/support": "^7|^8|^9",
"maximebf/debugbar": "^1.17.2",
"php": ">=7.2",
"symfony/debug": "^4.3|^5|^6",
"symfony/finder": "^4.3|^5|^6"
"php": ">=7.2.5",
"symfony/finder": "^5|^6"
},
"require-dev": {
"mockery/mockery": "^1.3.3",
"orchestra/testbench-dusk": "^4|^5|^6|^7",
"orchestra/testbench-dusk": "^5|^6|^7",
"phpunit/phpunit": "^8.5|^9.0",
"squizlabs/php_codesniffer": "^3.5"
},
@ -12907,7 +12921,7 @@
],
"support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.7"
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.7.0"
},
"funding": [
{
@ -12919,20 +12933,20 @@
"type": "github"
}
],
"time": "2022-02-09T07:52:32+00:00"
"time": "2022-07-11T09:26:42+00:00"
},
{
"name": "brianium/paratest",
"version": "v6.5.1",
"version": "v6.6.0",
"source": {
"type": "git",
"url": "https://github.com/paratestphp/paratest.git",
"reference": "41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9"
"reference": "bce7b965a5fe5028a53c3151042ca12777600acd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9",
"reference": "41fc4cc01422dae2d6bf6a0ce39756f57ac7d8a9",
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/bce7b965a5fe5028a53c3151042ca12777600acd",
"reference": "bce7b965a5fe5028a53c3151042ca12777600acd",
"shasum": ""
},
"require": {
@ -12947,18 +12961,18 @@
"phpunit/php-timer": "^5.0.3",
"phpunit/phpunit": "^9.5.21",
"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"
},
"require-dev": {
"doctrine/coding-standard": "^9.0.0",
"ext-pcov": "*",
"ext-posix": "*",
"infection/infection": "^0.26.12",
"infection/infection": "^0.26.13",
"malukenho/mcbumpface": "^1.1.5",
"squizlabs/php_codesniffer": "^3.7.1",
"symfony/filesystem": "^5.4.9 || ^6.1.0",
"vimeo/psalm": "^4.23.0"
"vimeo/psalm": "^4.24.0"
},
"bin": [
"bin/paratest",
@ -12999,7 +13013,7 @@
],
"support": {
"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": [
{
@ -13011,7 +13025,7 @@
"type": "paypal"
}
],
"time": "2022-06-24T16:02:27+00:00"
"time": "2022-07-12T07:15:58+00:00"
},
{
"name": "composer/pcre",
@ -13312,16 +13326,16 @@
},
{
"name": "doctrine/annotations",
"version": "1.13.2",
"version": "1.13.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "5b668aef16090008790395c02c893b1ba13f7e08"
"reference": "648b0343343565c4a056bfc8392201385e8d89f0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08",
"reference": "5b668aef16090008790395c02c893b1ba13f7e08",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0",
"reference": "648b0343343565c4a056bfc8392201385e8d89f0",
"shasum": ""
},
"require": {
@ -13333,9 +13347,10 @@
"require-dev": {
"doctrine/cache": "^1.11 || ^2.0",
"doctrine/coding-standard": "^6.0 || ^8.1",
"phpstan/phpstan": "^0.12.20",
"phpstan/phpstan": "^1.4.10 || ^1.8.0",
"phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5",
"symfony/cache": "^4.4 || ^5.2"
"symfony/cache": "^4.4 || ^5.2",
"vimeo/psalm": "^4.10"
},
"type": "library",
"autoload": {
@ -13378,9 +13393,9 @@
],
"support": {
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/1.13.2"
"source": "https://github.com/doctrine/annotations/tree/1.13.3"
},
"time": "2021-08-05T19:00:23+00:00"
"time": "2022-07-02T10:48:51+00:00"
},
{
"name": "doctrine/instantiator",
@ -13519,16 +13534,16 @@
},
{
"name": "facade/ignition",
"version": "2.17.5",
"version": "2.17.6",
"source": {
"type": "git",
"url": "https://github.com/facade/ignition.git",
"reference": "1d71996f83c9a5a7807331b8986ac890352b7a0c"
"reference": "6acd82e986a2ecee89e2e68adfc30a1936d1ab7c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/facade/ignition/zipball/1d71996f83c9a5a7807331b8986ac890352b7a0c",
"reference": "1d71996f83c9a5a7807331b8986ac890352b7a0c",
"url": "https://api.github.com/repos/facade/ignition/zipball/6acd82e986a2ecee89e2e68adfc30a1936d1ab7c",
"reference": "6acd82e986a2ecee89e2e68adfc30a1936d1ab7c",
"shasum": ""
},
"require": {
@ -13593,7 +13608,7 @@
"issues": "https://github.com/facade/ignition/issues",
"source": "https://github.com/facade/ignition"
},
"time": "2022-02-23T18:31:24+00:00"
"time": "2022-06-30T18:26:59+00:00"
},
{
"name": "facade/ignition-contracts",
@ -13881,16 +13896,16 @@
},
{
"name": "laravel/dusk",
"version": "v6.24.0",
"version": "v6.25.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/dusk.git",
"reference": "7fed3695741787d9998c5f04c94adfd62d70e766"
"reference": "b4632b7493a187d31afc5c9ddec437c81b16421a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/dusk/zipball/7fed3695741787d9998c5f04c94adfd62d70e766",
"reference": "7fed3695741787d9998c5f04c94adfd62d70e766",
"url": "https://api.github.com/repos/laravel/dusk/zipball/b4632b7493a187d31afc5c9ddec437c81b16421a",
"reference": "b4632b7493a187d31afc5c9ddec437c81b16421a",
"shasum": ""
},
"require": {
@ -13948,9 +13963,9 @@
],
"support": {
"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",
@ -16139,75 +16154,6 @@
},
"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",
"version": "v1.20.0",

View File

@ -14,8 +14,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.4.6',
'app_tag' => '5.4.6',
'app_version' => '5.4.11',
'app_tag' => '5.4.11',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),
@ -194,5 +194,8 @@ return [
'ninja_apple_bundle_id' => env('APPLE_BUNDLE_ID', false),
'ninja_apple_issuer_id' => env('APPLE_ISSUER_ID', 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

@ -1,5 +1,13 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

View File

@ -1,5 +1,13 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

View File

@ -1,5 +1,13 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

View File

@ -1,5 +1,13 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

View File

@ -1,5 +1,13 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

View File

@ -0,0 +1,55 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
use App\Models\Language;
use App\Models\PurchaseOrder;
use App\Utils\Traits\AppSetup;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPurchaseOrderToExpense extends Migration
{
use AppSetup;
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('purchase_orders', function (Blueprint $table) {
$table->unsignedInteger('expense_id')->nullable()->index();
});
PurchaseOrder::withTrashed()->where('status_id', 4)->update(['status_id' => 5]);
$language = Language::find(36);
if(!$language){
Language::unguard();
Language::create(['id' => 36, 'name' => 'Bulgarian', 'locale' => 'bg']);
$this->buildCache(true);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
}

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
image_picker_for_web
image_picker_platform_interface
in_app_purchase
in_app_purchase_android
in_app_purchase_platform_interface
in_app_purchase_storekit
local_auth
package_info
path_provider
@ -13070,6 +13074,32 @@ The above copyright notice and this permission notice shall be included in all c
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.
--------------------------------------------------------------------------------
in_app_review
in_app_review_platform_interface
MIT License
Copyright (c) 2020 Britannio Jarrett
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.
--------------------------------------------------------------------------------
intl
@ -16734,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
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
vulkan

39
public/flutter.js vendored
View File

@ -16,14 +16,23 @@ _flutter.loader = null;
(function() {
"use strict";
class FlutterLoader {
// TODO: Move the below methods to "#private" once supported by all the browsers
// we support. In the meantime, we use the "revealing module" pattern.
/**
* Creates a FlutterLoader, and initializes its instance methods.
*/
constructor() {
// TODO: Move the below methods to "#private" once supported by all the browsers
// we support. In the meantime, we use the "revealing module" pattern.
// Watchdog to prevent injecting the main entrypoint multiple times.
_scriptLoaded = null;
// Watchdog to prevent injecting the main entrypoint multiple times.
this._scriptLoaded = null;
// Resolver for the pending promise returned by loadEntrypoint.
_didCreateEngineInitializerResolve = null;
// Resolver for the pending promise returned by loadEntrypoint.
this._didCreateEngineInitializerResolve = null;
// Called by Flutter web.
// Bound to `this` now, so "this" is preserved across JS <-> Flutter jumps.
this.didCreateEngineInitializer = this._didCreateEngineInitializer.bind(this);
}
/**
* Initializes the main.dart.js with/without serviceWorker.
@ -40,19 +49,19 @@ _flutter.loader = null;
}
/**
* Resolves the promise created by loadEntrypoint. Called by Flutter.
* Needs to be weirdly bound like it is, so "this" is preserved across
* the JS <-> Flutter jumps.
* Resolves the promise created by loadEntrypoint.
* Called by Flutter through the public `didCreateEngineInitializer` method,
* which is bound to the correct instance of the FlutterLoader on the page.
* @param {*} engineInitializer
*/
didCreateEngineInitializer = (function(engineInitializer) {
_didCreateEngineInitializer(engineInitializer) {
if (typeof this._didCreateEngineInitializerResolve != "function") {
console.warn("Do not call didCreateEngineInitializer by hand. Start with loadEntrypoint instead.");
}
this._didCreateEngineInitializerResolve(engineInitializer);
// Remove this method after it's done, so Flutter Web can hot restart.
// Remove the public method after it's done, so Flutter Web can hot restart.
delete this.didCreateEngineInitializer;
}).bind(this);
}
_loadEntrypoint(entrypointUrl) {
if (!this._scriptLoaded) {
@ -60,7 +69,11 @@ _flutter.loader = null;
let scriptTag = document.createElement("script");
scriptTag.src = entrypointUrl;
scriptTag.type = "application/javascript";
this._didCreateEngineInitializerResolve = resolve; // Cache the resolve, so it can be called from Flutter.
// Cache the resolve, so it can be called from Flutter.
// Note: Flutter hot restart doesn't re-create this promise, so this
// can only be called once. Instead, we need to model this as a stream
// of `engineCreated` events coming from Flutter that are handled by JS.
this._didCreateEngineInitializerResolve = resolve;
scriptTag.addEventListener("error", reject);
document.body.append(scriptTag);
});

View File

@ -3,43 +3,43 @@ const MANIFEST = 'flutter-app-manifest';
const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = {
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"canvaskit/canvaskit.js": "c2b4e5f3d7a3d82aed024e7249a78487",
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
"/": "46443d15dbe8e491c73190330d91d4e2",
"flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67",
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
"version.json": "d72bd323e3b8e22ce5acdc247f4e6f62",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
"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",
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
"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": "9b6b63256d3a6491659b71127ee9f3b6",
"main.dart.js": "0f10062693740735811a5a29bc063592"
"version.json": "4dfad0f7098e523184a2f58aff0e3940",
"flutter.js": "eb2682e33f25cd8f1fc59011497c35f8",
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
"canvaskit/canvaskit.js": "c2b4e5f3d7a3d82aed024e7249a78487",
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
"/": "f0472d186e41814a028b5ca7814378c4",
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"main.dart.js": "fe987ef50f1a627038a89c1f4f1dabb0"
};
// The application shell files that are downloaded before a service worker can

297525
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

299341
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

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