commit
bb5072d58f
141 changed files with 453026 additions and 448025 deletions
|
|
@ -1 +1 @@
|
|||
5.3.66
|
||||
5.3.67
|
||||
|
|
@ -74,7 +74,7 @@ class CheckData extends Command
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ninja:check-data {--database=} {--fix=} {--client_id=} {--vendor_id=} {--paid_to_date=} {--client_balance=}';
|
||||
protected $signature = 'ninja:check-data {--database=} {--fix=} {--client_id=} {--vendor_id=} {--paid_to_date=} {--client_balance=} {--ledger_balance=}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
|
@ -102,7 +102,7 @@ class CheckData extends Command
|
|||
config(['database.default' => $database]);
|
||||
}
|
||||
|
||||
// $this->checkInvoiceBalances();
|
||||
$this->checkInvoiceBalances();
|
||||
$this->checkInvoiceBalancesNew();
|
||||
//$this->checkInvoicePayments();
|
||||
|
||||
|
|
@ -482,6 +482,7 @@ class CheckData extends Command
|
|||
payments.id = paymentables.payment_id
|
||||
WHERE paymentable_type = ?
|
||||
AND paymentables.deleted_at is NULL
|
||||
AND payments.amount > 0
|
||||
AND payments.is_deleted = 0
|
||||
AND payments.client_id = ?;
|
||||
"), [App\Models\Credit::class, $client->id] );
|
||||
|
|
@ -499,9 +500,11 @@ class CheckData extends Command
|
|||
{
|
||||
$client = Client::withTrashed()->find($_client->client_id);
|
||||
|
||||
$credits_from_reversal = Credit::withTrashed()->where('client_id', $client->id)->where('is_deleted', 0)->whereNotNull('invoice_id')->sum('amount');
|
||||
|
||||
$credits_used_for_payments = $this->clientCreditPaymentables($client);
|
||||
|
||||
$total_paid_to_date = $_client->payments_applied + $credits_used_for_payments[0]->credit_payment;
|
||||
$total_paid_to_date = $_client->payments_applied + $credits_used_for_payments[0]->credit_payment - $credits_from_reversal;
|
||||
|
||||
if(round($total_paid_to_date,2) != round($_client->client_paid_to_date,2)){
|
||||
|
||||
|
|
@ -736,7 +739,7 @@ ORDER BY clients.id;
|
|||
$this->logMessage($client_object->present()->name.' - '.$client_object->id." - calculated client balances do not match Invoice Balances = {$invoice_balance} - Client Balance = ".rtrim($client['client_balance'], '0'). " Ledger balance = {$ledger->balance}");
|
||||
|
||||
|
||||
if($this->option('client_balance')){
|
||||
if($this->option('ledger_balance')){
|
||||
|
||||
$this->logMessage("# {$client_object->id} " . $client_object->present()->name.' - '.$client_object->number." Fixing {$client_object->balance} to {$invoice_balance}");
|
||||
$client_object->balance = $invoice_balance;
|
||||
|
|
@ -853,18 +856,16 @@ ORDER BY clients.id;
|
|||
|
||||
foreach (Client::where('is_deleted', 0)->where('clients.updated_at', '>', now()->subDays(2))->cursor() as $client) {
|
||||
$invoice_balance = $client->invoices()->where('is_deleted', false)->where('status_id', '>', 1)->sum('balance');
|
||||
$credit_balance = $client->credits()->where('is_deleted', false)->sum('balance');
|
||||
|
||||
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
|
||||
|
||||
if ($ledger && number_format($invoice_balance, 4) != number_format($client->balance, 4)) {
|
||||
if ($ledger && number_format($ledger->balance, 4) != number_format($client->balance, 4)) {
|
||||
$this->wrong_balances++;
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}");
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." - Balance Failure - Client Balance = {$client->balance} Ledger Balance = {$ledger->balance}");
|
||||
|
||||
$this->isValid = false;
|
||||
|
||||
|
||||
if($this->option('client_balance')){
|
||||
if($this->option('ledger_balance')){
|
||||
|
||||
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
|
||||
$client->balance = $invoice_balance;
|
||||
|
|
@ -879,7 +880,7 @@ ORDER BY clients.id;
|
|||
}
|
||||
}
|
||||
|
||||
$this->logMessage("{$this->wrong_balances} clients with incorrect balances");
|
||||
$this->logMessage("{$this->wrong_balances} clients with incorrect ledger balances");
|
||||
}
|
||||
|
||||
private function checkLogoFiles()
|
||||
|
|
@ -1011,6 +1012,27 @@ ORDER BY clients.id;
|
|||
}
|
||||
|
||||
|
||||
/* //used to set a company owner on the company_users table
|
||||
|
||||
$c = Company::whereDoesntHave('company_users', function ($query){
|
||||
$query->where('is_owner', true)->withTrashed();
|
||||
})->cursor()->each(function ($company){
|
||||
|
||||
if(!$company->company_users()->exists()){
|
||||
echo "No company users AT ALL {$company->id}\n";
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
$cu = $company->company_users()->orderBy('id', 'ASC')->orderBy('is_admin', 'ASC')->first();
|
||||
echo "{$company->id} - {$cu->id} \n";
|
||||
$cu->is_owner=true;
|
||||
$cu->save();
|
||||
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
/* query if we want to company company ledger to client balance
|
||||
$results = \DB::select( \DB::raw("
|
||||
SELECT
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\DataMapper\ClientRegistrationFields;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\DataMapper\FeesAndLimits;
|
||||
use App\Events\Invoice\InvoiceWasCreated;
|
||||
|
|
@ -115,6 +116,7 @@ class CreateSingleAccount extends Command
|
|||
$settings->invoice_footer = 'Default invoice footer';
|
||||
|
||||
$company->settings = $settings;
|
||||
$company->client_registration_fields = ClientRegistrationFields::generate();
|
||||
$company->save();
|
||||
|
||||
$account->default_company_id = $company->id;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class Kernel extends ConsoleKernel
|
|||
|
||||
$schedule->job(new RecurringExpensesCron)->dailyAt('00:10')->withoutOverlapping();
|
||||
|
||||
$schedule->job(new AutoBillCron)->dailyAt('00:30')->withoutOverlapping();
|
||||
$schedule->job(new AutoBillCron)->dailyAt('12:20')->withoutOverlapping();
|
||||
|
||||
$schedule->job(new SchedulerCheck)->daily()->withoutOverlapping();
|
||||
|
||||
|
|
|
|||
51
app/DataMapper/Analytics/TrialFinished.php
Normal file
51
app/DataMapper/Analytics/TrialFinished.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Analytics;
|
||||
|
||||
use Turbo124\Beacon\ExampleMetric\GenericCounter;
|
||||
|
||||
class TrialFinished extends GenericCounter
|
||||
{
|
||||
/**
|
||||
* The type of Sample.
|
||||
*
|
||||
* Monotonically incrementing counter
|
||||
*
|
||||
* - counter
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'counter';
|
||||
|
||||
/**
|
||||
* The name of the counter.
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'account.trial_finished';
|
||||
|
||||
/**
|
||||
* The datetime of the counter measurement.
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
/**
|
||||
* The increment amount... should always be
|
||||
* set to 0.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $metric = 0;
|
||||
}
|
||||
51
app/DataMapper/Analytics/TrialStarted.php
Normal file
51
app/DataMapper/Analytics/TrialStarted.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Analytics;
|
||||
|
||||
use Turbo124\Beacon\ExampleMetric\GenericCounter;
|
||||
|
||||
class TrialStarted extends GenericCounter
|
||||
{
|
||||
/**
|
||||
* The type of Sample.
|
||||
*
|
||||
* Monotonically incrementing counter
|
||||
*
|
||||
* - counter
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'counter';
|
||||
|
||||
/**
|
||||
* The name of the counter.
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'account.trial_started';
|
||||
|
||||
/**
|
||||
* The datetime of the counter measurement.
|
||||
*
|
||||
* date("Y-m-d H:i:s")
|
||||
*
|
||||
* @var DateTime
|
||||
*/
|
||||
public $datetime;
|
||||
|
||||
/**
|
||||
* The increment amount... should always be
|
||||
* set to 0.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $metric = 0;
|
||||
}
|
||||
|
|
@ -66,7 +66,7 @@ class CompanySettings extends BaseSettings
|
|||
public $auto_convert_quote = true; //@implemented
|
||||
public $auto_email_invoice = true; //@only used for Recurring Invoices, if set to false, we never send?
|
||||
|
||||
public $entity_send_time = 0;
|
||||
public $entity_send_time = 6;
|
||||
|
||||
public $inclusive_taxes = false; //@implemented
|
||||
public $quote_footer = ''; //@implmented
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class EmailTemplateDefaults
|
|||
|
||||
public static function emailInvoiceTemplate()
|
||||
{
|
||||
$invoice_message = '<p>'.self::transformText('invoice_message').'</p><div class="center">$view_button</div>';
|
||||
$invoice_message = '<p>$client<br><br>'.self::transformText('invoice_message').'</p><div class="center">$view_button</div>';
|
||||
|
||||
return $invoice_message;
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ class EmailTemplateDefaults
|
|||
|
||||
public static function emailQuoteTemplate()
|
||||
{
|
||||
$quote_message = '<p>'.self::transformText('quote_message').'</p><div class="center">$view_button</div>';
|
||||
$quote_message = '<p>$client<br><br>'.self::transformText('quote_message').'</p><div class="center">$view_button</div>';
|
||||
|
||||
return $quote_message;
|
||||
}
|
||||
|
|
@ -147,21 +147,21 @@ class EmailTemplateDefaults
|
|||
|
||||
public static function emailPaymentTemplate()
|
||||
{
|
||||
$payment_message = '<p>'.self::transformText('payment_message').'</p><div class="center">$view_button</div>';
|
||||
$payment_message = '<p>$client<br><br>'.self::transformText('payment_message').'<br><br>$invoices</p><div class="center">$view_button</div>';
|
||||
|
||||
return $payment_message;
|
||||
}
|
||||
|
||||
public static function emailCreditTemplate()
|
||||
{
|
||||
$credit_message = '<p>'.self::transformText('credit_message').'</p><div class="center">$view_button</div>';
|
||||
$credit_message = '<p>$client<br><br>'.self::transformText('credit_message').'</p><div class="center">$view_button</div>';
|
||||
|
||||
return $credit_message;
|
||||
}
|
||||
|
||||
public static function emailPaymentPartialTemplate()
|
||||
{
|
||||
$payment_message = '<p>'.self::transformText('payment_message').'</p><div class="center">$view_button</div>';
|
||||
$payment_message = '<p>$client<br><br>'.self::transformText('payment_message').'<br><br>$invoices</p><div class="center">$view_button</div>';
|
||||
|
||||
return $payment_message;
|
||||
}
|
||||
|
|
|
|||
100
app/DataMapper/Transactions/BaseTransaction.php
Normal file
100
app/DataMapper/Transactions/BaseTransaction.php
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* BaseTransaction.
|
||||
*/
|
||||
class BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::INVOICE_MARK_PAID;
|
||||
|
||||
public array $model = [
|
||||
'client_id',
|
||||
'invoice_id',
|
||||
'payment_id',
|
||||
'credit_id',
|
||||
'client_balance',
|
||||
'client_paid_to_date',
|
||||
'client_credit_balance',
|
||||
'invoice_balance',
|
||||
'invoice_amount',
|
||||
'invoice_partial',
|
||||
'invoice_paid_to_date',
|
||||
'invoice_status',
|
||||
'payment_amount',
|
||||
'payment_applied',
|
||||
'payment_refunded',
|
||||
'payment_status',
|
||||
'paymentables',
|
||||
'event_id',
|
||||
'timestamp',
|
||||
'payment_request',
|
||||
'metadata',
|
||||
'credit_balance',
|
||||
'credit_amount',
|
||||
'credit_status',
|
||||
];
|
||||
|
||||
public function transform(array $data) :array
|
||||
{
|
||||
// $invoice = $data['invoice'];
|
||||
// $payment = $data['payment'];
|
||||
// $client = $data['client'];
|
||||
// $credit = $data['credit'];
|
||||
// $payment_request = $data['payment']['payment_request'];
|
||||
// $metadata = $data['metadata'];
|
||||
|
||||
return array_merge(
|
||||
$data['invoice'],
|
||||
$data['payment'],
|
||||
$data['client'],
|
||||
$data['credit'],
|
||||
$data['metadata'],
|
||||
['event_id' => $this->event_id, 'timestamp' =>time()],
|
||||
);
|
||||
// return [
|
||||
// 'event_id' => $this->event_id,
|
||||
// 'client_id' => $client?->id,
|
||||
// 'invoice_id' => $invoice?->id,
|
||||
// 'payment_id' => $payment?->id,
|
||||
// 'credit_id' => $credit?->creditid,
|
||||
// 'client_balance' => $client?->balance,
|
||||
// 'client_paid_to_date' => $client?->paid_to_date,
|
||||
// 'client_credit_balance' => $client?->credit_balance,
|
||||
// 'invoice_balance' => $invoice?->balance,
|
||||
// 'invoice_amount' => $invoice?->amount,
|
||||
// 'invoice_partial' => $invoice?->partial,
|
||||
// 'invoice_paid_to_date' => $invoice?->paid_to_date,
|
||||
// 'invoice_status' => $invoice?->status_id,
|
||||
// 'payment_amount' => $payment?->amount,
|
||||
// 'payment_applied' => $payment?->applied,
|
||||
// 'payment_refunded' => $payment?->refunded,
|
||||
// 'payment_status' => $payment?->status_id,
|
||||
// 'paymentables' => $payment?->paymentables,
|
||||
// 'payment_request' => $payment_request,
|
||||
// 'metadata' => $metadata,
|
||||
// 'credit_balance' => $credit?->balance,
|
||||
// 'credit_amount' => $credit?->amount,
|
||||
// 'credit_status' => $credit?->status_id,
|
||||
// 'timestamp' => time(),
|
||||
// ];
|
||||
|
||||
}
|
||||
}
|
||||
28
app/DataMapper/Transactions/ClientStatusTransaction.php
Normal file
28
app/DataMapper/Transactions/ClientStatusTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* ClientStatusTransaction.
|
||||
*/
|
||||
class ClientStatusTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::CLIENT_STATUS;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* GatewayPaymentMadeTransaction.
|
||||
*/
|
||||
class GatewayPaymentMadeTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::GATEWAY_PAYMENT_MADE;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/InvoiceCancelledTransaction.php
Normal file
28
app/DataMapper/Transactions/InvoiceCancelledTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* InvoiceCancelledTransaction.
|
||||
*/
|
||||
class InvoiceCancelledTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::INVOICE_CANCELLED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/InvoiceDeletedTransaction.php
Normal file
28
app/DataMapper/Transactions/InvoiceDeletedTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* InvoiceDeletedTransaction.
|
||||
*/
|
||||
class InvoiceDeletedTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::INVOICE_DELETED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/InvoiceFeeAppliedTransaction.php
Normal file
28
app/DataMapper/Transactions/InvoiceFeeAppliedTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* InvoiceFeeAppliedTransaction.
|
||||
*/
|
||||
class InvoiceFeeAppliedTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::INVOICE_FEE_APPLIED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/InvoicePaymentTransaction.php
Normal file
28
app/DataMapper/Transactions/InvoicePaymentTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* InvoicePaymentTransaction.
|
||||
*/
|
||||
class InvoicePaymentTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::INVOICE_PAYMENT_APPLIED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/InvoiceReversalTransaction.php
Normal file
28
app/DataMapper/Transactions/InvoiceReversalTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* InvoiceReversalTransaction.
|
||||
*/
|
||||
class InvoiceReversalTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::INVOICE_REVERSED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/InvoiceUpdatedTransaction.php
Normal file
28
app/DataMapper/Transactions/InvoiceUpdatedTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* InvoiceUpdatedTransaction.
|
||||
*/
|
||||
class InvoiceUpdatedTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::INVOICE_UPDATED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/MarkPaidTransaction.php
Normal file
28
app/DataMapper/Transactions/MarkPaidTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* BaseTransaction.
|
||||
*/
|
||||
class MarkPaidTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::INVOICE_MARK_PAID;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/PaymentAppliedTransaction.php
Normal file
28
app/DataMapper/Transactions/PaymentAppliedTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* PaymentAppliedTransaction.
|
||||
*/
|
||||
class PaymentAppliedTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::PAYMENT_APPLIED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/PaymentDeletedTransaction.php
Normal file
28
app/DataMapper/Transactions/PaymentDeletedTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* PaymentDeletedTransaction.
|
||||
*/
|
||||
class PaymentDeletedTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::PAYMENT_DELETED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/PaymentFailedTransaction.php
Normal file
28
app/DataMapper/Transactions/PaymentFailedTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* PaymentFailedTransaction.
|
||||
*/
|
||||
class PaymentFailedTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::PAYMENT_FAILED;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/PaymentMadeTransaction.php
Normal file
28
app/DataMapper/Transactions/PaymentMadeTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* PaymentMadeTransaction.
|
||||
*/
|
||||
class PaymentMadeTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::PAYMENT_MADE;
|
||||
|
||||
}
|
||||
28
app/DataMapper/Transactions/PaymentRefundedTransaction.php
Normal file
28
app/DataMapper/Transactions/PaymentRefundedTransaction.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
|
||||
/**
|
||||
* PaymentRefundedTransaction.
|
||||
*/
|
||||
class PaymentRefundedTransaction extends BaseTransaction implements TransactionInterface
|
||||
{
|
||||
|
||||
public $event_id = TransactionEvent::PAYMENT_REFUND;
|
||||
|
||||
}
|
||||
17
app/DataMapper/Transactions/TransactionInterface.php
Normal file
17
app/DataMapper/Transactions/TransactionInterface.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\DataMapper\Transactions;
|
||||
|
||||
interface TransactionInterface
|
||||
{
|
||||
public function transform(array $data) :array;
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ class CreditFactory
|
|||
$credit->terms = '';
|
||||
$credit->public_notes = '';
|
||||
$credit->private_notes = '';
|
||||
$credit->date = null;
|
||||
$credit->date = now()->format('Y-m-d');
|
||||
$credit->due_date = null;
|
||||
$credit->partial_due_date = null;
|
||||
$credit->is_deleted = false;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class InvoiceFactory
|
|||
$invoice->terms = '';
|
||||
$invoice->public_notes = '';
|
||||
$invoice->private_notes = '';
|
||||
$invoice->date = null;
|
||||
$invoice->date = now()->format('Y-m-d');
|
||||
$invoice->due_date = null;
|
||||
$invoice->partial_due_date = null;
|
||||
$invoice->is_deleted = false;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class QuoteFactory
|
|||
$quote->terms = '';
|
||||
$quote->public_notes = '';
|
||||
$quote->private_notes = '';
|
||||
$quote->date = null;
|
||||
$quote->date = now()->format('Y-m-d');
|
||||
$quote->due_date = null;
|
||||
$quote->partial_due_date = null;
|
||||
$quote->is_deleted = false;
|
||||
|
|
|
|||
|
|
@ -89,9 +89,6 @@ class InvoiceItemSumInclusive
|
|||
{
|
||||
$this->setLineTotal($this->item->cost * $this->item->quantity);
|
||||
|
||||
//11-02-2022
|
||||
// $this->setLineTotal($this->formatValue($this->item->cost, $this->currency->precision) * $this->formatValue($this->item->quantity, $this->currency->precision));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +168,8 @@ class InvoiceItemSumInclusive
|
|||
|
||||
public function setLineTotal($total)
|
||||
{
|
||||
$this->item->gross_line_total = $total;
|
||||
|
||||
$this->item->line_total = $total;
|
||||
|
||||
return $this;
|
||||
|
|
|
|||
|
|
@ -764,7 +764,8 @@ class BaseController extends Controller
|
|||
|
||||
$this->buildCache();
|
||||
|
||||
return view('index.index', $data);
|
||||
return response()->view('index.index', $data)->header('X-Frame-Options', 'SAMEORIGIN', false);
|
||||
|
||||
}
|
||||
|
||||
return redirect('/setup');
|
||||
|
|
|
|||
|
|
@ -264,17 +264,17 @@ class InvitationController extends Controller
|
|||
abort(404, "Invoice not found");
|
||||
}
|
||||
|
||||
public function unsubscribe(Request $request, string $entity_type, string $invitation_key)
|
||||
public function unsubscribe(Request $request, string $entity, string $invitation_key)
|
||||
{
|
||||
if($entity_type == 'invoice'){
|
||||
if($entity == 'invoice'){
|
||||
$invite = InvoiceInvitation::withTrashed()->where('key', $invitation_key)->first();
|
||||
$invite->contact->send_email = false;
|
||||
$invite->contact->save();
|
||||
}elseif($entity_type == 'quote'){
|
||||
}elseif($entity == 'quote'){
|
||||
$invite = QuoteInvitation::withTrashed()->where('key', $invitation_key)->first();
|
||||
$invite->contact->send_email = false;
|
||||
$invite->contact->save();
|
||||
}elseif($entity_type == 'credit'){
|
||||
}elseif($entity == 'credit'){
|
||||
$invite = CreditInvitation::withTrashed()->where('key', $invitation_key)->first();
|
||||
$invite->contact->send_email = false;
|
||||
$invite->contact->save();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace App\Http\Controllers\ClientPortal;
|
||||
|
||||
use App\DataMapper\Analytics\TrialStarted;
|
||||
use App\Factory\RecurringInvoiceFactory;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ClientPortal\Uploads\StoreUploadRequest;
|
||||
|
|
@ -32,6 +33,7 @@ use Illuminate\Http\Request;
|
|||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Turbo124\Beacon\Facades\LightLogs;
|
||||
|
||||
class NinjaPlanController extends Controller
|
||||
{
|
||||
|
|
@ -134,7 +136,7 @@ class NinjaPlanController extends Controller
|
|||
// $account = auth()->guard('contact')->user()->company->account;
|
||||
if(auth()->guard('contact')->user()->client->custom_value2){
|
||||
MultiDB::findAndSetDbByAccountKey(auth()->guard('contact')->user()->client->custom_value2);
|
||||
$account = Account::where('key', auth()->guard('contact')->user()->client->custom_value2);
|
||||
$account = Account::where('key', auth()->guard('contact')->user()->client->custom_value2)->first();
|
||||
$account->trial_started = now();
|
||||
$account->trial_plan = 'pro';
|
||||
$account->save();
|
||||
|
|
@ -159,11 +161,15 @@ class NinjaPlanController extends Controller
|
|||
$recurring_invoice->next_send_date = now()->addDays(14)->format('Y-m-d');
|
||||
|
||||
$recurring_invoice->save();
|
||||
$recurring_invoice = $recurring_invoice->calc()->getRecurringInvoice();
|
||||
$r = $recurring_invoice->calc()->getRecurringInvoice();
|
||||
|
||||
$recurring_invoice->service()->start();
|
||||
$recurring_invoice->service()->start()->save();
|
||||
|
||||
return redirect('/');
|
||||
LightLogs::create(new TrialStarted())
|
||||
->increment()
|
||||
->queue();
|
||||
|
||||
return $this->render('plan.trial_confirmed', $data);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +186,7 @@ class NinjaPlanController extends Controller
|
|||
|
||||
public function plan()
|
||||
{
|
||||
|
||||
// return $this->trial();
|
||||
//harvest the current plan
|
||||
$data = [];
|
||||
$data['late_invoice'] = false;
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ class PaymentMethodController extends Controller
|
|||
|
||||
return redirect()
|
||||
->route('client.payment_methods.index')
|
||||
->withSuccess('Payment method has been successfully removed.');
|
||||
->withSuccess(ctrans('texts.payment_method_removed'));
|
||||
}
|
||||
|
||||
private function getClientGateway()
|
||||
|
|
|
|||
|
|
@ -29,11 +29,13 @@ use App\Http\Requests\Invoice\UploadInvoiceRequest;
|
|||
use App\Jobs\Entity\EmailEntity;
|
||||
use App\Jobs\Invoice\StoreInvoice;
|
||||
use App\Jobs\Invoice\ZipInvoices;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Jobs\Util\UnlinkFile;
|
||||
use App\Models\Account;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Quote;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Transformers\InvoiceTransformer;
|
||||
use App\Transformers\QuoteTransformer;
|
||||
|
|
@ -224,6 +226,16 @@ class InvoiceController extends BaseController
|
|||
|
||||
event(new InvoiceWasCreated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $invoice->transaction_event(),
|
||||
'payment' => [],
|
||||
'client' => $invoice->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::INVOICE_UPDATED, $transaction, $invoice->company->db);
|
||||
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
|
||||
|
|
@ -405,6 +417,16 @@ class InvoiceController extends BaseController
|
|||
|
||||
event(new InvoiceWasUpdated($invoice, $invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $invoice->transaction_event(),
|
||||
'payment' => [],
|
||||
'client' => $invoice->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::INVOICE_UPDATED, $transaction, $invoice->company->db);
|
||||
|
||||
return $this->itemResponse($invoice);
|
||||
}
|
||||
|
||||
|
|
@ -663,7 +685,7 @@ class InvoiceController extends BaseController
|
|||
return $this->errorResponse(['message' => ctrans('texts.invoice_cannot_be_marked_paid')], 400);
|
||||
}
|
||||
|
||||
$invoice = $invoice->service()->markPaid();
|
||||
$invoice = $invoice->service()->markPaid()->save();
|
||||
|
||||
if (! $bulk) {
|
||||
return $this->itemResponse($invoice);
|
||||
|
|
@ -935,6 +957,9 @@ class InvoiceController extends BaseController
|
|||
if ($request->has('documents'))
|
||||
$this->saveDocuments($request->file('documents'), $invoice);
|
||||
|
||||
if ($request->has('file'))
|
||||
$this->saveDocuments($request->file('documents'), $invoice);
|
||||
|
||||
return $this->itemResponse($invoice->fresh());
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -672,8 +672,7 @@ class QuoteController extends BaseController
|
|||
return $this->itemResponse($quote);
|
||||
break;
|
||||
case 'approve':
|
||||
//make sure it hasn't already been approved!!
|
||||
if ($quote->status_id != Quote::STATUS_SENT) {
|
||||
if (!in_array($quote->status_id, [Quote::STATUS_SENT, Quote::STATUS_DRAFT]) ) {
|
||||
return response()->json(['message' => ctrans('texts.quote_unapprovable')], 400);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ class RequiredClientInfo extends Component
|
|||
*/
|
||||
public $contact;
|
||||
|
||||
public $client;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
|
|
@ -64,6 +66,36 @@ class RequiredClientInfo extends Component
|
|||
// 'contact_phone' => 'phone',
|
||||
];
|
||||
|
||||
public $client_address_array = [
|
||||
'address1',
|
||||
'address2',
|
||||
'city',
|
||||
'state',
|
||||
'postal_code',
|
||||
'country_id',
|
||||
];
|
||||
|
||||
protected $rules = [
|
||||
'client.address1' => '',
|
||||
'client.address2' => '',
|
||||
'client.city' => '',
|
||||
'client.state' => '',
|
||||
'client.postal_code' => '',
|
||||
'client.country_id' => '',
|
||||
'client.shipping_address1' => '',
|
||||
'client.shipping_address2' => '',
|
||||
'client.shipping_city' => '',
|
||||
'client.shipping_state' => '',
|
||||
'client.shipping_postal_code' => '',
|
||||
'client.shipping_country_id' => '',
|
||||
'contact.first_name' => '',
|
||||
'contact.last_name' => '',
|
||||
'contact.email' => '',
|
||||
'client.name' => '',
|
||||
'client.website' => '',
|
||||
'client.phone' => '',
|
||||
];
|
||||
|
||||
public $show_form = false;
|
||||
|
||||
public $company;
|
||||
|
|
@ -71,6 +103,13 @@ class RequiredClientInfo extends Component
|
|||
public function mount()
|
||||
{
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
$this->client = $this->contact->client;
|
||||
|
||||
count($this->fields) > 0
|
||||
? $this->checkFields()
|
||||
: $this->show_form = false;
|
||||
|
||||
}
|
||||
|
||||
public function handleSubmit(array $data): bool
|
||||
|
|
@ -141,8 +180,7 @@ class RequiredClientInfo extends Component
|
|||
$_field = $this->mappings[$field['name']];
|
||||
|
||||
if (Str::startsWith($field['name'], 'client_')) {
|
||||
if (empty($this->contact->client->{$_field}) || is_null($this->contact->client->{$_field})) {
|
||||
// if (empty($this->contact->client->{$_field}) || is_null($this->contact->client->{$_field}) || $this->contact->client->{$_field} == 840) {
|
||||
if (empty($this->contact->client->{$_field}) || is_null($this->contact->client->{$_field}) || in_array($_field, $this->client_address_array)) {
|
||||
$this->show_form = true;
|
||||
} else {
|
||||
$this->fields[$index]['filled'] = true;
|
||||
|
|
@ -151,7 +189,6 @@ class RequiredClientInfo extends Component
|
|||
|
||||
if (Str::startsWith($field['name'], 'contact_')) {
|
||||
if (empty($this->contact->{$_field}) || is_null($this->contact->{$_field})) {
|
||||
// if ((empty($this->contact->{$_field}) || is_null($this->contact->{$_field})) || $this->contact->client->{$_field} == 840) {
|
||||
$this->show_form = true;
|
||||
} else {
|
||||
$this->fields[$index]['filled'] = true;
|
||||
|
|
@ -193,10 +230,6 @@ class RequiredClientInfo extends Component
|
|||
|
||||
public function render()
|
||||
{
|
||||
count($this->fields) > 0
|
||||
? $this->checkFields()
|
||||
: $this->show_form = false;
|
||||
|
||||
return render('components.livewire.required-client-info');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,15 @@ class TrustProxies extends Middleware
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
// protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
|
||||
//07-03-2022 - fixes for symfony 5.2
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
|
||||
/*
|
||||
* Instantiate trusted proxies middleware
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class StoreClientRequest extends Request
|
|||
];
|
||||
|
||||
if (auth()->user()->company()->account->isFreeHostedClient()) {
|
||||
$rules['hosted_clients'] = new CanStoreClientsRule($this->company_id);
|
||||
$rules['id'] = new CanStoreClientsRule(auth()->user()->company()->id);
|
||||
}
|
||||
|
||||
$rules['number'] = ['nullable',Rule::unique('clients')->where('company_id', auth()->user()->company()->id)];
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ class StoreInvoiceRequest extends Request
|
|||
$rules['documents'] = 'file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
|
||||
if ($this->input('file') && is_array($this->input('file'))) {
|
||||
$documents = count($this->input('file'));
|
||||
|
||||
foreach (range(0, $documents) as $index) {
|
||||
$rules['file.'.$index] = 'file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
} elseif ($this->input('file')) {
|
||||
$rules['file'] = 'file|mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
|
||||
$rules['client_id'] = 'bail|required|exists:clients,id,company_id,'.auth()->user()->company()->id.',is_deleted,0';
|
||||
// $rules['client_id'] = ['required', Rule::exists('clients')->where('company_id', auth()->user()->company()->id)];
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ namespace App\Http\Requests\Invoice;
|
|||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Invoice\InvoiceBalanceSanity;
|
||||
use App\Http\ValidationRules\Invoice\LockedInvoiceRule;
|
||||
use App\Http\ValidationRules\Project\ValidProjectForClient;
|
||||
use App\Models\Invoice;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\CleanLineItems;
|
||||
|
|
@ -59,6 +60,7 @@ class UpdateInvoiceRequest extends Request
|
|||
|
||||
$rules['line_items'] = 'array';
|
||||
$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());
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ class UploadInvoiceRequest extends Request
|
|||
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';
|
||||
|
||||
if($this->input('file'))
|
||||
$rules['file'] = 'file|mimes:csv,png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000';
|
||||
|
||||
return $rules;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
namespace App\Http\Requests\RecurringInvoice;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Project\ValidProjectForClient;
|
||||
use App\Http\ValidationRules\Recurring\UniqueRecurringInvoiceNumberRule;
|
||||
use App\Models\Client;
|
||||
use App\Models\RecurringInvoice;
|
||||
|
|
@ -55,6 +56,8 @@ class StoreRecurringInvoiceRequest extends Request
|
|||
|
||||
$rules['frequency_id'] = 'required|integer|digits_between:1,12';
|
||||
|
||||
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
|
||||
|
||||
$rules['number'] = new UniqueRecurringInvoiceNumberRule($this->all());
|
||||
|
||||
return $rules;
|
||||
|
|
@ -80,6 +83,11 @@ class StoreRecurringInvoiceRequest extends Request
|
|||
$input['vendor_id'] = $this->decodePrimaryKey($input['vendor_id']);
|
||||
}
|
||||
|
||||
if (array_key_exists('project_id', $input) && is_string($input['project_id'])) {
|
||||
$input['project_id'] = $this->decodePrimaryKey($input['project_id']);
|
||||
}
|
||||
|
||||
|
||||
if (isset($input['client_contacts'])) {
|
||||
foreach ($input['client_contacts'] as $key => $contact) {
|
||||
if (! array_key_exists('send_email', $contact) || ! array_key_exists('id', $contact)) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
namespace App\Http\Requests\RecurringInvoice;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Http\ValidationRules\Project\ValidProjectForClient;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\CleanLineItems;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
|
@ -51,6 +52,7 @@ class UpdateRecurringInvoiceRequest extends Request
|
|||
if($this->number)
|
||||
$rules['number'] = Rule::unique('recurring_invoices')->where('company_id', auth()->user()->company()->id)->ignore($this->recurring_invoice->id);
|
||||
|
||||
$rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())];
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
|
@ -59,16 +61,6 @@ class UpdateRecurringInvoiceRequest extends Request
|
|||
{
|
||||
$input = $this->all();
|
||||
|
||||
// foreach($this->input('documents') as $document)
|
||||
// {
|
||||
// if($document instanceof UploadedFile){
|
||||
// nlog("i am an uploaded file");
|
||||
// nlog($document);
|
||||
// }
|
||||
// else
|
||||
// nlog($document);
|
||||
// }
|
||||
|
||||
if (array_key_exists('design_id', $input) && is_string($input['design_id'])) {
|
||||
$input['design_id'] = $this->decodePrimaryKey($input['design_id']);
|
||||
}
|
||||
|
|
@ -81,6 +73,11 @@ class UpdateRecurringInvoiceRequest extends Request
|
|||
$input['assigned_user_id'] = $this->decodePrimaryKey($input['assigned_user_id']);
|
||||
}
|
||||
|
||||
if (array_key_exists('project_id', $input) && is_string($input['project_id'])) {
|
||||
$input['project_id'] = $this->decodePrimaryKey($input['project_id']);
|
||||
}
|
||||
|
||||
|
||||
if (isset($input['invitations'])) {
|
||||
foreach ($input['invitations'] as $key => $value) {
|
||||
if (is_numeric($input['invitations'][$key]['id'])) {
|
||||
|
|
|
|||
11
app/Http/Requests/Vendor/StoreVendorRequest.php
vendored
11
app/Http/Requests/Vendor/StoreVendorRequest.php
vendored
|
|
@ -36,14 +36,19 @@ class StoreVendorRequest extends Request
|
|||
|
||||
/* Ensure we have a client name, and that all emails are unique*/
|
||||
//$rules['name'] = 'required|min:1';
|
||||
$rules['id_number'] = 'unique:vendors,id_number,'.$this->id.',id,company_id,'.$this->company_id;
|
||||
// $rules['id_number'] = 'unique:vendors,id_number,'.$this->id.',id,company_id,'.auth()->user()->company()->id;
|
||||
//$rules['settings'] = new ValidVendorGroupSettingsRule();
|
||||
$rules['contacts.*.email'] = 'nullable|distinct';
|
||||
|
||||
$rules['contacts.*.email'] = 'bail|nullable|distinct|sometimes|email';
|
||||
|
||||
if (isset($this->number)) {
|
||||
$rules['number'] = Rule::unique('vendors')->where('company_id', auth()->user()->company()->id);
|
||||
}
|
||||
|
||||
// if (isset($this->id_number)) {
|
||||
// $rules['id_number'] = Rule::unique('vendors')->where('company_id', auth()->user()->company()->id);
|
||||
// }
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +64,7 @@ class StoreVendorRequest extends Request
|
|||
public function messages()
|
||||
{
|
||||
return [
|
||||
'unique' => ctrans('validation.unique', ['attribute' => 'email']),
|
||||
// 'unique' => ctrans('validation.unique', ['attribute' => 'email']),
|
||||
//'required' => trans('validation.required', ['attribute' => 'email']),
|
||||
'contacts.*.email.required' => ctrans('validation.email', ['attribute' => 'email']),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -40,11 +40,11 @@ class UpdateVendorRequest extends Request
|
|||
if($this->number)
|
||||
$rules['number'] = Rule::unique('vendors')->where('company_id', auth()->user()->company()->id)->ignore($this->vendor->id);
|
||||
|
||||
if($this->id_number)
|
||||
$rules['id_number'] = Rule::unique('vendors')->where('company_id', auth()->user()->company()->id)->ignore($this->vendor->id);
|
||||
// if($this->id_number)
|
||||
// $rules['id_number'] = Rule::unique('vendors')->where('company_id', auth()->user()->company()->id)->ignore($this->vendor->id);
|
||||
|
||||
$rules['contacts.*.email'] = 'nullable|distinct';
|
||||
|
||||
// $rules['id_number'] = 'unique:vendors,id_number,'.$this->id.',id,company_id,'.auth()->user()->company()->id;
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ class CanStoreClientsRule implements Rule
|
|||
{
|
||||
public $company_id;
|
||||
|
||||
public $company;
|
||||
|
||||
public function __construct($company_id)
|
||||
{
|
||||
$this->company_id = $company_id;
|
||||
|
|
@ -33,9 +35,9 @@ class CanStoreClientsRule implements Rule
|
|||
*/
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
$company = Company::find($this->company_id);
|
||||
$this->company = Company::find($this->company_id);
|
||||
|
||||
return $company->clients->count() < $company->account->hosted_client_count;
|
||||
return $this->company->clients()->count() < $this->company->account->hosted_client_count;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -43,6 +45,6 @@ class CanStoreClientsRule implements Rule
|
|||
*/
|
||||
public function message()
|
||||
{
|
||||
return ctrans('texts.limit_clients', ['count' => $company->account->hosted_client_count]);
|
||||
return ctrans('texts.limit_clients', ['count' => $this->company->account->hosted_client_count]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class PaymentTransformer extends BaseTransformer
|
|||
}
|
||||
|
||||
$transformed = [
|
||||
'company_id' => $this->maps['company']->id,
|
||||
'company_id' => $this->company->id,
|
||||
'number' => $this->getString($data, 'payment.number'),
|
||||
'user_id' => $this->getString($data, 'payment.user_id'),
|
||||
'amount' => $this->getFloat($data, 'payment.amount'),
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ class CompanyExport implements ShouldQueue
|
|||
$this->export_data['invoices'] = $this->company->invoices()->orderBy('number', 'DESC')->cursor()->map(function ($invoice){
|
||||
|
||||
$invoice = $this->transformBasicEntities($invoice);
|
||||
$invoice = $this->transformArrayOfKeys($invoice, ['recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id']);
|
||||
$invoice = $this->transformArrayOfKeys($invoice, ['recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id','project_id']);
|
||||
|
||||
return $invoice->makeVisible(['id',
|
||||
'private_notes',
|
||||
|
|
|
|||
|
|
@ -91,8 +91,9 @@ class ZipCredits implements ShouldQueue
|
|||
|
||||
foreach ($this->credits as $credit) {
|
||||
|
||||
$download_file = file_get_contents($credit->pdf_file_path($invitation, 'url', true));
|
||||
$zipFile->addFromString(basename($credit->pdf_file_path($invitation)), $download_file);
|
||||
$file = $credit->service()->getCreditPdf($credit->invitations()->first());
|
||||
$zip_file_name = basename($file);
|
||||
$zipFile->addFromString($zip_file_name, Storage::get($file));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,12 @@ class ZipInvoices implements ShouldQueue
|
|||
|
||||
foreach ($this->invoices as $invoice) {
|
||||
|
||||
$download_file = file_get_contents($invoice->pdf_file_path($invitation, 'url', true));
|
||||
$zipFile->addFromString(basename($invoice->pdf_file_path($invitation)), $download_file);
|
||||
$file = $invoice->service()->getInvoicePdf();
|
||||
$zip_file_name = basename($file);
|
||||
$zipFile->addFromString($zip_file_name, Storage::get($file));
|
||||
|
||||
//$download_file = file_get_contents($invoice->pdf_file_path($invitation, 'url', true));
|
||||
//$zipFile->addFromString(basename($invoice->pdf_file_path($invitation)), $download_file);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
116
app/Jobs/Ninja/TransactionLog.php
Normal file
116
app/Jobs/Ninja/TransactionLog.php
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Ninja;
|
||||
|
||||
use App\DataMapper\Transactions\ClientStatusTransaction;
|
||||
use App\DataMapper\Transactions\GatewayPaymentMadeTransaction;
|
||||
use App\DataMapper\Transactions\InvoiceCancelledTransaction;
|
||||
use App\DataMapper\Transactions\InvoiceDeletedTransaction;
|
||||
use App\DataMapper\Transactions\InvoiceFeeAppliedTransaction;
|
||||
use App\DataMapper\Transactions\InvoicePaymentTransaction;
|
||||
use App\DataMapper\Transactions\InvoiceReversalTransaction;
|
||||
use App\DataMapper\Transactions\InvoiceUpdatedTransaction;
|
||||
use App\DataMapper\Transactions\MarkPaidTransaction;
|
||||
use App\DataMapper\Transactions\PaymentAppliedTransaction;
|
||||
use App\DataMapper\Transactions\PaymentDeletedTransaction;
|
||||
use App\DataMapper\Transactions\PaymentFailedTransaction;
|
||||
use App\DataMapper\Transactions\PaymentMadeTransaction;
|
||||
use App\DataMapper\Transactions\PaymentRefundedTransaction;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TransactionLog implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
|
||||
private array $payload;
|
||||
|
||||
private string $db;
|
||||
|
||||
private array $data;
|
||||
|
||||
private $event;
|
||||
|
||||
private $event_transformer;
|
||||
|
||||
private array $transformer_array = [
|
||||
TransactionEvent::INVOICE_MARK_PAID => MarkPaidTransaction::class, //
|
||||
TransactionEvent::INVOICE_UPDATED => InvoiceUpdatedTransaction::class, //
|
||||
TransactionEvent::INVOICE_DELETED => InvoiceDeletedTransaction::class, //
|
||||
TransactionEvent::INVOICE_PAYMENT_APPLIED => InvoicePaymentTransaction::class,
|
||||
TransactionEvent::INVOICE_CANCELLED => InvoiceCancelledTransaction::class,
|
||||
TransactionEvent::INVOICE_REVERSED => InvoiceReversalTransaction::class, //
|
||||
TransactionEvent::INVOICE_FEE_APPLIED => InvoiceFeeAppliedTransaction::class, //
|
||||
TransactionEvent::PAYMENT_MADE => PaymentMadeTransaction::class, //
|
||||
TransactionEvent::GATEWAY_PAYMENT_MADE => GatewayPaymentMadeTransaction::class, //
|
||||
TransactionEvent::PAYMENT_APPLIED => PaymentAppliedTransaction::class,
|
||||
TransactionEvent::PAYMENT_REFUND => PaymentRefundedTransaction::class, //
|
||||
TransactionEvent::PAYMENT_FAILED => PaymentFailedTransaction::class,
|
||||
TransactionEvent::PAYMENT_DELETED => PaymentDeletedTransaction::class, //
|
||||
TransactionEvent::CLIENT_STATUS => ClientStatusTransaction::class, //
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($event, $data, $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->event = $event;
|
||||
$this->data = $data;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// if(!Ninja::isHosted())
|
||||
// return;
|
||||
|
||||
$this->setTransformer();
|
||||
|
||||
$this->payload = $this->event_transformer->transform($this->data);
|
||||
|
||||
$this->persist();
|
||||
}
|
||||
|
||||
|
||||
private function setTransformer()
|
||||
{
|
||||
$class = $this->transformer_array[$this->event];
|
||||
|
||||
$this->event_transformer = new $class();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
private function persist()
|
||||
{
|
||||
MultiDB::setDB($this->db);
|
||||
|
||||
TransactionEvent::create($this->payload);
|
||||
}
|
||||
}
|
||||
|
|
@ -92,8 +92,12 @@ class ZipQuotes implements ShouldQueue
|
|||
|
||||
foreach ($this->quotes as $quote) {
|
||||
|
||||
$download_file = file_get_contents($quote->pdf_file_path($invitation, 'url', true));
|
||||
$zipFile->addFromString(basename($quote->pdf_file_path($invitation)), $download_file);
|
||||
$file = $quote->service()->getQuotePdf();
|
||||
$zip_file_name = basename($file);
|
||||
$zipFile->addFromString($zip_file_name, Storage::get($file));
|
||||
|
||||
// $download_file = file_get_contents($quote->pdf_file_path($invitation, 'url', true));
|
||||
// $zipFile->addFromString(basename($quote->pdf_file_path($invitation)), $download_file);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,7 +237,8 @@ class Import implements ShouldQueue
|
|||
|
||||
//company size check
|
||||
if ($this->company->invoices()->count() > 500 || $this->company->products()->count() > 500 || $this->company->clients()->count() > 500) {
|
||||
$this->company->is_large = true;
|
||||
// $this->company->is_large = true;
|
||||
$this->company->account->companies()->update(['is_large' => true]);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -649,6 +650,7 @@ class Import implements ShouldQueue
|
|||
if(array_key_exists('updated_at', $modified))
|
||||
$client->updated_at = Carbon::parse($modified['updated_at']);
|
||||
|
||||
$client->country_id = array_key_exists('country_id', $modified) ? $modified['country_id'] : $this->company->settings->country_id;
|
||||
$client->save(['timestamps' => false]);
|
||||
$client->fresh();
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ class InvitationViewedListener implements ShouldQueue
|
|||
$entity_name = lcfirst(class_basename($event->entity));
|
||||
$invitation = $event->invitation;
|
||||
|
||||
if($entity_name == 'recurringInvoice')
|
||||
return;
|
||||
|
||||
$nmo = new NinjaMailerObject;
|
||||
$nmo->mailable = new NinjaMailer( (new EntityViewedObject($invitation, $entity_name))->build() );
|
||||
$nmo->company = $invitation->company;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ class Client extends BaseModel implements HasLocalePreference
|
|||
|
||||
public function gateway_tokens()
|
||||
{
|
||||
return $this->hasMany(ClientGatewayToken::class);
|
||||
return $this->hasMany(ClientGatewayToken::class)->orderBy('is_default', 'ASC');
|
||||
}
|
||||
|
||||
public function expenses()
|
||||
|
|
@ -840,4 +840,17 @@ class Client extends BaseModel implements HasLocalePreference
|
|||
|
||||
return $offset;
|
||||
}
|
||||
|
||||
public function transaction_event()
|
||||
{
|
||||
$client = $this->fresh();
|
||||
|
||||
return [
|
||||
'client_id' => $client->id,
|
||||
'client_balance' => $client->balance ?: 0,
|
||||
'client_paid_to_date' => $client->paid_to_date ?: 0,
|
||||
'client_credit_balance' => $client->credit_balance ?: 0
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,7 +476,8 @@ class Company extends BaseModel
|
|||
|
||||
public function owner()
|
||||
{
|
||||
return $this->company_users->where('is_owner', true)->first()->user;
|
||||
return $this->company_users()->withTrashed()->where('is_owner', true)->first()->user;
|
||||
//return $this->company_users->where('is_owner', true)->first()->user;
|
||||
}
|
||||
|
||||
public function resolveRouteBinding($value, $field = null)
|
||||
|
|
|
|||
|
|
@ -302,4 +302,16 @@ class Credit extends BaseModel
|
|||
});
|
||||
}
|
||||
|
||||
public function transaction_event()
|
||||
{
|
||||
|
||||
$credit = $this->fresh();
|
||||
|
||||
return [
|
||||
'credit_id' => $credit->id,
|
||||
'credit_amount' => $credit->amount ?: 0,
|
||||
'credit_balance' => $credit->balance ?: 0,
|
||||
'credit_status' => $credit->status_id ?: 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class Gateway extends StaticModel
|
|||
case 20:
|
||||
return [
|
||||
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true],
|
||||
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']],
|
||||
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded','payment_intent.succeeded']],
|
||||
GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false],
|
||||
GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false],
|
||||
GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], //Stripe
|
||||
|
|
|
|||
|
|
@ -232,6 +232,11 @@ class Invoice extends BaseModel
|
|||
{
|
||||
return $this->hasMany(Expense::class);
|
||||
}
|
||||
|
||||
public function expense()
|
||||
{
|
||||
return $this->hasOne(Expense::class);
|
||||
}
|
||||
/**
|
||||
* Service entry points.
|
||||
*/
|
||||
|
|
@ -535,4 +540,19 @@ class Invoice extends BaseModel
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function transaction_event()
|
||||
{
|
||||
|
||||
$invoice = $this->fresh();
|
||||
|
||||
return [
|
||||
'invoice_id' => $invoice->id,
|
||||
'invoice_amount' => $invoice->amount ?: 0,
|
||||
'invoice_partial' => $invoice->partial ?: 0,
|
||||
'invoice_balance' => $invoice->balance ?: 0,
|
||||
'invoice_paid_to_date' => $invoice->paid_to_date ?: 0,
|
||||
'invoice_status' => $invoice->status_id ?: 1,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use App\Utils\Traits\MakesDates;
|
|||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\Payment\Refundable;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class Payment extends BaseModel
|
||||
{
|
||||
|
|
@ -149,6 +150,15 @@ class Payment extends BaseModel
|
|||
return $this->belongsTo(PaymentType::class);
|
||||
}
|
||||
|
||||
public function translatedType()
|
||||
{
|
||||
if(!$this->type)
|
||||
return '';
|
||||
|
||||
return ctrans('texts.payment_type_'.$this->type->name);
|
||||
|
||||
}
|
||||
|
||||
public function gateway_type()
|
||||
{
|
||||
return $this->belongsTo(GatewayType::class);
|
||||
|
|
@ -314,4 +324,19 @@ class Payment extends BaseModel
|
|||
|
||||
}
|
||||
|
||||
public function transaction_event()
|
||||
{
|
||||
$payment = $this->fresh();
|
||||
|
||||
return [
|
||||
'payment_id' => $payment->id,
|
||||
'payment_amount' => $payment->amount ?: 0,
|
||||
'payment_applied' => $payment->applied ?: 0,
|
||||
'payment_refunded' => $payment->refunded ?: 0,
|
||||
'payment_status' => $payment->status_id ?: 1,
|
||||
'paymentables' => $payment->paymentables->toArray(),
|
||||
'payment_request' => request() ? request()->all() : [],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
46
app/Models/TransactionEvent.php
Normal file
46
app/Models/TransactionEvent.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* Class Bank.
|
||||
*/
|
||||
class TransactionEvent extends StaticModel
|
||||
{
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
public $guarded = ['id'];
|
||||
|
||||
public $casts = [
|
||||
'metadata' => 'array',
|
||||
'payment_request' => 'array',
|
||||
'paymentables' => 'array',
|
||||
];
|
||||
|
||||
public const INVOICE_MARK_PAID = 1;
|
||||
public const INVOICE_UPDATED = 2;
|
||||
public const INVOICE_DELETED = 3;
|
||||
public const INVOICE_PAYMENT_APPLIED = 4;
|
||||
public const INVOICE_CANCELLED = 5;
|
||||
public const INVOICE_FEE_APPLIED = 6;
|
||||
public const INVOICE_REVERSED = 7;
|
||||
|
||||
public const PAYMENT_MADE = 100;
|
||||
public const PAYMENT_APPLIED = 101;
|
||||
public const PAYMENT_REFUND = 102;
|
||||
public const PAYMENT_FAILED = 103;
|
||||
public const GATEWAY_PAYMENT_MADE = 104;
|
||||
public const PAYMENT_DELETED = 105;
|
||||
|
||||
public const CLIENT_STATUS = 200;
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ namespace App\PaymentDrivers\Authorize;
|
|||
use App\PaymentDrivers\AuthorizePaymentDriver;
|
||||
use net\authorize\api\contract\v1\CreateTransactionRequest;
|
||||
use net\authorize\api\contract\v1\CustomerProfilePaymentType;
|
||||
use net\authorize\api\contract\v1\OrderType;
|
||||
use net\authorize\api\contract\v1\PaymentProfileType;
|
||||
use net\authorize\api\contract\v1\TransactionRequestType;
|
||||
use net\authorize\api\controller\CreateTransactionController;
|
||||
|
|
@ -42,9 +43,21 @@ class ChargePaymentProfile
|
|||
$paymentProfile->setPaymentProfileId($payment_profile_id);
|
||||
$profileToCharge->setPaymentProfile($paymentProfile);
|
||||
|
||||
$invoice_numbers = '';
|
||||
|
||||
if($this->authorize->payment_hash->data)
|
||||
$invoice_numbers = collect($this->authorize->payment_hash->data->invoices)->pluck('invoice_number')->implode(',');
|
||||
|
||||
$description = "Invoices: {$invoice_numbers} for {$amount} for client {$this->authorize->client->present()->name()}";
|
||||
|
||||
$order = new OrderType();
|
||||
$order->setInvoiceNumber($invoice_numbers);
|
||||
$order->setDescription($description);
|
||||
|
||||
$transactionRequestType = new TransactionRequestType();
|
||||
$transactionRequestType->setTransactionType('authCaptureTransaction');
|
||||
$transactionRequestType->setAmount($amount);
|
||||
$transactionRequestType->setOrder($order);
|
||||
$transactionRequestType->setProfile($profileToCharge);
|
||||
$transactionRequestType->setCurrencyCode($this->authorize->client->currency()->code);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use App\Jobs\Mail\NinjaMailer;
|
|||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
use App\Jobs\Mail\PaymentFailedMailer;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Mail\Admin\ClientPaymentFailureObject;
|
||||
use App\Models\Client;
|
||||
|
|
@ -32,6 +33,7 @@ use App\Models\Payment;
|
|||
use App\Models\PaymentHash;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Services\Subscription\SubscriptionService;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
|
@ -317,11 +319,23 @@ class BaseDriver extends AbstractPaymentDriver
|
|||
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))->withTrashed()->get();
|
||||
|
||||
$invoices->each(function ($invoice) use ($fee_total) {
|
||||
|
||||
if (collect($invoice->line_items)->contains('type_id', '3')) {
|
||||
$invoice->service()->toggleFeesPaid()->save();
|
||||
$invoice->client->service()->updateBalance($fee_total)->save();
|
||||
$invoice->ledger()->updateInvoiceBalance($fee_total, "Gateway fee adjustment for invoice {$invoice->number}");
|
||||
}
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $invoice->transaction_event(),
|
||||
'payment' => [],
|
||||
'client' => $invoice->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::INVOICE_FEE_APPLIED, $transaction, $invoice->company->db);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,9 +146,21 @@ class CreditCard
|
|||
|
||||
}
|
||||
|
||||
$invoice_numbers = '';
|
||||
|
||||
if($this->eway_driver->payment_hash->data)
|
||||
$invoice_numbers = collect($this->eway_driver->payment_hash->data->invoices)->pluck('invoice_number')->implode(',');
|
||||
|
||||
$amount = array_sum(array_column($this->eway_driver->payment_hash->invoices(), 'amount')) + $this->eway_driver->payment_hash->fee_total;
|
||||
|
||||
$description = "Invoices: {$invoice_numbers} for {$amount} for client {$this->eway_driver->client->present()->name()}";
|
||||
|
||||
$transaction = [
|
||||
'Payment' => [
|
||||
'TotalAmount' => $this->convertAmountForEway(),
|
||||
'CurrencyCode' => $this->eway_driver->client->currency()->code,
|
||||
'InvoiceNumber' => $invoice_numbers,
|
||||
'InvoiceReference' => $description,
|
||||
],
|
||||
'TransactionType' => \Eway\Rapid\Enum\TransactionType::PURCHASE,
|
||||
'SecuredCardData' => $request->input('securefieldcode'),
|
||||
|
|
@ -225,12 +237,22 @@ class CreditCard
|
|||
{
|
||||
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
|
||||
|
||||
|
||||
if($this->eway_driver->payment_hash->data)
|
||||
$invoice_numbers = collect($this->eway_driver->payment_hash->data->invoices)->pluck('invoice_number')->implode(',');
|
||||
|
||||
$description = "Invoices: {$invoice_numbers} for {$amount} for client {$this->eway_driver->client->present()->name()}";
|
||||
|
||||
$transaction = [
|
||||
'Customer' => [
|
||||
'TokenCustomerID' => $token,
|
||||
],
|
||||
'Payment' => [
|
||||
'TotalAmount' => $this->convertAmountForEway($amount),
|
||||
'CurrencyCode' => $this->eway_driver->client->currency()->code,
|
||||
'InvoiceNumber' => $invoice_numbers,
|
||||
'InvoiceDescription' => $description,
|
||||
'InvoiceReference' => $description,
|
||||
],
|
||||
'TransactionType' => \Eway\Rapid\Enum\TransactionType::RECURRING,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -43,6 +43,14 @@ class Token
|
|||
|
||||
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
|
||||
|
||||
|
||||
$invoice_numbers = '';
|
||||
|
||||
if($this->eway_driver->payment_hash->data)
|
||||
$invoice_numbers = collect($this->eway_driver->payment_hash->data->invoices)->pluck('invoice_number')->implode(',');
|
||||
|
||||
$description = "Invoices: {$invoice_numbers} for {$amount} for client {$this->eway_driver->client->present()->name()}";
|
||||
|
||||
$this->eway_driver->payment_hash = $payment_hash;
|
||||
|
||||
$transaction = [
|
||||
|
|
@ -51,6 +59,10 @@ class Token
|
|||
],
|
||||
'Payment' => [
|
||||
'TotalAmount' => $this->eway_driver->convertAmount($amount),
|
||||
'CurrencyCode' => $this->eway_driver->client->currency()->code,
|
||||
'InvoiceNumber' => $invoice_numbers,
|
||||
'InvoiceDescription' => $description,
|
||||
'InvoiceReference' => $description,
|
||||
],
|
||||
'TransactionType' => \Eway\Rapid\Enum\TransactionType::RECURRING,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ class ACSS
|
|||
'interval_description' => 'when any invoice becomes due',
|
||||
'transaction_type' => 'personal' // TODO: check if is company or personal https://stripe.com/docs/payments/acss-debit
|
||||
],
|
||||
'verification_method' => 'instant',
|
||||
]
|
||||
]
|
||||
], $this->stripe->stripe_connect_auth);
|
||||
|
|
@ -183,7 +184,7 @@ class ACSS
|
|||
$this->stripe->payment_hash->save();
|
||||
|
||||
if (property_exists($gateway_response, 'status') && $gateway_response->status == 'processing') {
|
||||
$this->storePaymentMethod($gateway_response);
|
||||
// $this->storePaymentMethod($gateway_response);
|
||||
return $this->processSuccessfulPayment($gateway_response->id);
|
||||
}
|
||||
return $this->processUnsuccessfulPayment();
|
||||
|
|
@ -243,12 +244,13 @@ class ACSS
|
|||
|
||||
private function storePaymentMethod($intent)
|
||||
{
|
||||
|
||||
try {
|
||||
$method = $this->stripe->getStripePaymentMethod($intent->payment_method);
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->brand = (string) \sprintf('%s (%s)', $method->au_becs_debit->bank_code, ctrans('texts.acss'));
|
||||
$payment_meta->last4 = (string) $method->au_becs_debit->last4;
|
||||
$payment_meta->brand = (string) $method->acss_debit->bank_name;
|
||||
$payment_meta->last4 = (string) $method->acss_debit->last4;
|
||||
$payment_meta->state = 'authorized';
|
||||
$payment_meta->type = GatewayType::ACSS;
|
||||
|
||||
|
|
|
|||
|
|
@ -198,14 +198,6 @@ class BrowserPay implements MethodInterface
|
|||
return;
|
||||
}
|
||||
|
||||
// $domain = config('ninja.app_url');
|
||||
|
||||
// if (Ninja::isHosted()) {
|
||||
// $domain = isset($this->stripe->company_gateway->company->portal_domain)
|
||||
// ? $this->stripe->company_gateway->company->portal_domain
|
||||
// : $this->stripe->company_gateway->company->domain();
|
||||
// }
|
||||
|
||||
$domain = $this->getAppleDomain();
|
||||
|
||||
if(!$domain)
|
||||
|
|
@ -244,12 +236,7 @@ class BrowserPay implements MethodInterface
|
|||
$domain = config('ninja.app_url');
|
||||
}
|
||||
|
||||
$parsed_url = parse_url($domain);
|
||||
|
||||
if(array_key_exists('host', $parsed_url))
|
||||
return $parsed_url['host'];
|
||||
|
||||
return false;
|
||||
return str_replace("https://", "", $domain);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,11 +76,9 @@ class ImportCustomers
|
|||
|
||||
$account = $this->stripe->company_gateway->company->account;
|
||||
|
||||
if(!$account->isPaidHostedClient() && Client::where('company_id', $this->stripe->company_gateway->company_id)->count() > config('ninja.quotas.free.clients'))
|
||||
if(Ninja::isHosted() && !$account->isPaidHostedClient() && Client::where('company_id', $this->stripe->company_gateway->company_id)->count() > config('ninja.quotas.free.clients'))
|
||||
return;
|
||||
|
||||
// nlog("search Stripe for {$customer->id}");
|
||||
|
||||
$existing_customer_token = $this->stripe
|
||||
->company_gateway
|
||||
->client_gateway_tokens()
|
||||
|
|
@ -104,9 +102,6 @@ class ImportCustomers
|
|||
return;
|
||||
}
|
||||
|
||||
// nlog("inserting a customer");
|
||||
//nlog($customer);
|
||||
|
||||
$client = ClientFactory::create($this->stripe->company_gateway->company_id, $this->stripe->company_gateway->user_id);
|
||||
|
||||
if($customer->address)
|
||||
|
|
|
|||
|
|
@ -33,33 +33,10 @@ class UpdatePaymentMethods
|
|||
$this->stripe = $stripe;
|
||||
}
|
||||
|
||||
// public function run()
|
||||
// {
|
||||
// $this->stripe->init();
|
||||
|
||||
// $this->stripe
|
||||
// ->company_gateway
|
||||
// ->client_gateway_tokens
|
||||
// ->each(function ($token){
|
||||
|
||||
|
||||
// // $bank_accounts = Customer::allSources(
|
||||
// // $token->gateway_customer_reference,
|
||||
// // ['object' => 'bank_account', 'limit' => 300]
|
||||
// // );
|
||||
|
||||
// // foreach($bank_accounts as $bank_account)
|
||||
// // {
|
||||
// // $this->addOrUpdateBankAccount($bank_account, $token);
|
||||
// // }
|
||||
// // $this->processCustomer($token->gateway_customer_reference);
|
||||
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
public function updateMethods(Customer $customer, Client $client)
|
||||
{
|
||||
$this->stripe->client = $client;
|
||||
|
||||
$card_methods = PaymentMethod::all([
|
||||
'customer' => $customer->id,
|
||||
'type' => 'card',
|
||||
|
|
@ -93,37 +70,52 @@ class UpdatePaymentMethods
|
|||
$this->addOrUpdateCard($method, $customer->id, $client, GatewayType::SOFORT);
|
||||
}
|
||||
|
||||
//$this->importBankAccounts($customer, $client);
|
||||
$this->importBankAccounts($customer, $client);
|
||||
}
|
||||
|
||||
private function importBankAccounts($customer, $client)
|
||||
{
|
||||
|
||||
$sources = $customer->sources;
|
||||
|
||||
foreach($sources->data as $method)
|
||||
{
|
||||
|
||||
$token_exists = ClientGatewayToken::where([
|
||||
'gateway_customer_reference' => $customer->id,
|
||||
'token' => $method->id,
|
||||
'client_id' => $client->id,
|
||||
'company_id' => $client->company_id,
|
||||
])->exists();
|
||||
|
||||
/* Already exists return */
|
||||
if($token_exists)
|
||||
continue;
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->brand = (string) \sprintf('%s (%s)', $method->bank_name, ctrans('texts.ach'));
|
||||
$payment_meta->last4 = (string) $method->last4;
|
||||
$payment_meta->type = GatewayType::BANK_TRANSFER;
|
||||
$payment_meta->state = $method->status;
|
||||
|
||||
$data = [
|
||||
'payment_meta' => $payment_meta,
|
||||
'token' => $method->id,
|
||||
'payment_method_id' => GatewayType::BANK_TRANSFER,
|
||||
];
|
||||
|
||||
$additional_data = ['gateway_customer_reference' => $customer->id];
|
||||
|
||||
if($customer->default_source === $method->id)
|
||||
$additional_data = ['gateway_customer_reference' => $customer->id, 'is_default', 1];
|
||||
|
||||
$this->stripe->storeGatewayToken($data, $additional_data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// private function addOrUpdateBankAccount($bank_account, $customer_reference, Client $client)
|
||||
// {
|
||||
// $token_exists = ClientGatewayToken::where([
|
||||
// 'gateway_customer_reference' => $customer_reference,
|
||||
// 'token' => $bank_account->id,
|
||||
// ])->exists();
|
||||
|
||||
// /* Already exists return */
|
||||
// if($token_exists)
|
||||
// return;
|
||||
|
||||
// $cgt = ClientGatewayTokenFactory::create($client->company_id);
|
||||
// $cgt->client_id = $client->id;
|
||||
// $cgt->token = $bank_account->id;
|
||||
// $cgt->gateway_customer_reference = $customer_reference;
|
||||
// $cgt->company_gateway_id = $this->stripe->company_gateway->id;
|
||||
// $cgt->gateway_type_id = GatewayType::BANK_TRANSFER;
|
||||
// $cgt->meta = new \stdClass;
|
||||
// $cgt->routing_number = $bank_account->routing_number;
|
||||
// $cgt->save();
|
||||
|
||||
// }
|
||||
|
||||
private function addOrUpdateCard(PaymentMethod $method, $customer_reference, Client $client, $type_id)
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -533,12 +533,10 @@ class StripePaymentDriver extends BaseDriver
|
|||
//payment_intent.succeeded - this will confirm or cancel the payment
|
||||
if($request->type === 'payment_intent.succeeded'){
|
||||
PaymentIntentWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id)->delay(10);
|
||||
// PaymentIntentWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id);
|
||||
return response()->json([], 200);
|
||||
}
|
||||
|
||||
if ($request->type === 'charge.succeeded') {
|
||||
// if ($request->type === 'charge.succeeded' || $request->type === 'payment_intent.succeeded') {
|
||||
|
||||
foreach ($request->data as $transaction) {
|
||||
|
||||
|
|
|
|||
|
|
@ -222,6 +222,9 @@ class BaseRepository
|
|||
if (array_key_exists('documents', $data))
|
||||
$this->saveDocuments($data['documents'], $model);
|
||||
|
||||
if (array_key_exists('file', $data))
|
||||
$this->saveDocuments($data['file'], $model);
|
||||
|
||||
/* If invitations are present we need to filter existing invitations with the new ones */
|
||||
if (isset($data['invitations'])) {
|
||||
$invitations = collect($data['invitations']);
|
||||
|
|
|
|||
|
|
@ -14,11 +14,13 @@ namespace App\Repositories;
|
|||
use App\Events\Payment\PaymentWasCreated;
|
||||
use App\Events\Payment\PaymentWasDeleted;
|
||||
use App\Jobs\Credit\ApplyCreditPayment;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\SavesDocuments;
|
||||
|
|
@ -94,11 +96,8 @@ class PaymentRepository extends BaseRepository {
|
|||
if (array_key_exists('credits', $data) && is_array($data['credits']) && count($data['credits']) > 0) {
|
||||
$_credit_totals = array_sum(array_column($data['credits'], 'amount'));
|
||||
|
||||
// if ($data['amount'] == $_credit_totals) {
|
||||
// $data['amount'] = 0;
|
||||
// } else {
|
||||
$client->service()->updatePaidToDate($_credit_totals)->save();
|
||||
// }
|
||||
$client->service()->updatePaidToDate($_credit_totals)->save();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -181,10 +180,19 @@ class PaymentRepository extends BaseRepository {
|
|||
}
|
||||
|
||||
$payment->applied += ($invoice_totals - $credit_totals); //wont work because - check tests
|
||||
// $payment->applied += $invoice_totals; //wont work because - check tests
|
||||
|
||||
$payment->save();
|
||||
|
||||
$transaction = [
|
||||
'invoice' => [],
|
||||
'payment' => $payment->transaction_event(),
|
||||
'client' => $payment->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::PAYMENT_MADE, $transaction, $payment->company->db);
|
||||
|
||||
return $payment->fresh();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,4 +182,50 @@ class TaskRepository extends BaseRepository
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
public function start(Task $task)
|
||||
{
|
||||
if(strlen($task->time_log) < 5)
|
||||
{
|
||||
$log = [];
|
||||
|
||||
$log = array_merge($log, [[time(),0]]);
|
||||
$task->time_log = json_encode($log);
|
||||
$task->save();
|
||||
|
||||
}
|
||||
|
||||
$log = json_decode($task->time_log,true);;
|
||||
|
||||
$last = end($log);
|
||||
|
||||
if($last[1] !== 0){
|
||||
|
||||
$new = [time(), 0];
|
||||
$log = array_merge($log, [$new]);
|
||||
$task->time_log = json_encode($log);
|
||||
$task->save();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function stop(Task $task)
|
||||
{
|
||||
$log = json_decode($task->time_log,true);;
|
||||
|
||||
$last = end($log);
|
||||
|
||||
if($last[1] === 0){
|
||||
|
||||
$last[1] = time();
|
||||
|
||||
array_pop($log);
|
||||
$log = array_merge($log, [$last]);
|
||||
|
||||
$task->time_log = json_encode($log);
|
||||
$task->save();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,21 +28,27 @@ class ClientService
|
|||
|
||||
public function updateBalance(float $amount)
|
||||
{
|
||||
$this->client->balance += $amount;
|
||||
// $this->client->balance += $amount;
|
||||
|
||||
$this->client->increment('balance', $amount);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function updatePaidToDate(float $amount)
|
||||
{
|
||||
$this->client->paid_to_date += $amount;
|
||||
// $this->client->paid_to_date += $amount;
|
||||
|
||||
$this->client->increment('paid_to_date', $amount);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function adjustCreditBalance(float $amount)
|
||||
{
|
||||
$this->client->credit_balance += $amount;
|
||||
// $this->client->credit_balance += $amount;
|
||||
|
||||
$this->client->increment('credit_balance', $amount);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,11 +133,16 @@ class CreditService
|
|||
->attach($this->credit->id, ['amount' => $adjustment]);
|
||||
|
||||
//reduce client paid_to_date by $this->credit->balance amount
|
||||
$this->credit
|
||||
->client
|
||||
->service()
|
||||
->updatePaidToDate($adjustment)
|
||||
->save();
|
||||
// $this->credit
|
||||
// ->client
|
||||
// ->service()
|
||||
// ->updatePaidToDate($adjustment)
|
||||
// ->save();
|
||||
|
||||
$client = $this->credit->client->fresh();
|
||||
$client->service()
|
||||
->updatePaidToDate($adjustment)
|
||||
->save();
|
||||
|
||||
event('eloquent.created: App\Models\Payment', $payment);
|
||||
|
||||
|
|
@ -162,21 +167,24 @@ class CreditService
|
|||
|
||||
public function adjustBalance($adjustment)
|
||||
{
|
||||
$this->credit->balance += $adjustment;
|
||||
// $this->credit->balance += $adjustment;
|
||||
$this->credit->increment('balance', $adjustment);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function updatePaidToDate($adjustment)
|
||||
{
|
||||
$this->credit->paid_to_date += $adjustment;
|
||||
|
||||
// $this->credit->paid_to_date += $adjustment;
|
||||
$this->credit->increment('paid_to_date', $adjustment);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function updateBalance($adjustment)
|
||||
{
|
||||
$this->credit->balance -= $adjustment;
|
||||
// $this->credit->balance -= $adjustment;
|
||||
$this->credit->decrement('balance', $adjustment);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class GetCreditPdf extends AbstractService
|
|||
public function run()
|
||||
{
|
||||
if (! $this->contact) {
|
||||
$this->contact = $this->credit->client->primary_contact()->first();
|
||||
$this->contact = $this->credit->client->primary_contact()->first() ?: $this->credit->client->contacts()->first();
|
||||
}
|
||||
|
||||
$path = $this->credit->client->credit_filepath($this->invitation);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@
|
|||
|
||||
namespace App\Services\Invoice;
|
||||
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Services\AbstractService;
|
||||
|
||||
class ApplyPayment extends AbstractService
|
||||
|
|
@ -128,6 +130,16 @@ class ApplyPayment extends AbstractService
|
|||
|
||||
$this->invoice->service()->applyNumber()->workFlow()->save();
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $this->invoice->transaction_event(),
|
||||
'payment' => $this->payment->transaction_event(),
|
||||
'client' => $this->invoice->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::INVOICE_PAYMENT_APPLIED, $transaction, $this->invoice->company->db);
|
||||
|
||||
return $this->invoice;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,8 +189,8 @@ class AutoBillInvoice extends AbstractService
|
|||
->adjustCreditBalance($amount * -1)
|
||||
->save();
|
||||
|
||||
$this->invoice->ledger()
|
||||
->updateInvoiceBalance($amount * -1, "Invoice {$this->invoice->number} payment using Credit {$current_credit->number}")
|
||||
$this->invoice->ledger() //09-03-2022
|
||||
// ->updateInvoiceBalance($amount * -1, "Invoice {$this->invoice->number} payment using Credit {$current_credit->number}")
|
||||
->updateCreditBalance($amount * -1, "Credit {$current_credit->number} used to pay down Invoice {$this->invoice->number}")
|
||||
->save();
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class GetInvoicePdf extends AbstractService
|
|||
public function run()
|
||||
{
|
||||
if (! $this->contact) {
|
||||
$this->contact = $this->invoice->client->primary_contact()->first();
|
||||
$this->contact = $this->invoice->client->primary_contact()->first() ?: $this->invoice->client->contacts()->first();
|
||||
}
|
||||
|
||||
$invitation = $this->invoice->invitations->where('client_contact_id', $this->contact->id)->first();
|
||||
|
|
|
|||
|
|
@ -12,8 +12,10 @@
|
|||
namespace App\Services\Invoice;
|
||||
|
||||
use App\Events\Invoice\InvoiceWasCancelled;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Models\Client;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Services\AbstractService;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
|
|
@ -52,6 +54,16 @@ class HandleCancellation extends AbstractService
|
|||
|
||||
event(new InvoiceWasCancelled($this->invoice, $this->invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $this->invoice->transaction_event(),
|
||||
'payment' => [],
|
||||
'client' => $this->invoice->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::INVOICE_CANCELLED, $transaction, $this->invoice->company->db);
|
||||
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@ use App\Events\Invoice\InvoiceWasReversed;
|
|||
use App\Factory\CreditFactory;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Helpers\Invoice\InvoiceSum;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Models\Client;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\Paymentable;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Services\AbstractService;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
|
|
@ -136,6 +138,16 @@ class HandleReversal extends AbstractService
|
|||
|
||||
event(new InvoiceWasReversed($this->invoice, $this->invoice->company, Ninja::eventVars()));
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $this->invoice->transaction_event(),
|
||||
'payment' => [],
|
||||
'client' => $this->invoice->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::INVOICE_REVERSED, $transaction, $this->invoice->company->db);
|
||||
|
||||
return $this->invoice;
|
||||
//create a ledger row for this with the resulting Credit ( also include an explanation in the notes section )
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,8 +145,11 @@ class InvoiceService
|
|||
return $this;
|
||||
}
|
||||
|
||||
$this->invoice->balance += $balance_adjustment;
|
||||
// $this->invoice->balance += $balance_adjustment;
|
||||
|
||||
$this->invoice->increment('balance', $balance_adjustment);
|
||||
|
||||
|
||||
if (round($this->invoice->balance,2) == 0 && !$is_draft) {
|
||||
$this->invoice->status_id = Invoice::STATUS_PAID;
|
||||
}
|
||||
|
|
@ -160,7 +163,10 @@ class InvoiceService
|
|||
|
||||
public function updatePaidToDate($adjustment)
|
||||
{
|
||||
$this->invoice->paid_to_date += $adjustment;
|
||||
// $this->invoice->paid_to_date += $adjustment;
|
||||
|
||||
$this->invoice->increment('paid_to_date', $adjustment);
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -381,7 +387,8 @@ class InvoiceService
|
|||
/*Update the partial amount of a invoice*/
|
||||
public function updatePartial($amount)
|
||||
{
|
||||
$this->invoice->partial += $amount;
|
||||
// $this->invoice->partial += $amount;
|
||||
$this->invoice->increment('partial', $amount);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
namespace App\Services\Invoice;
|
||||
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Services\AbstractService;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
|
@ -47,6 +49,16 @@ class MarkInvoiceDeleted extends AbstractService
|
|||
->adjustBalance()
|
||||
->adjustLedger();
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $this->invoice->transaction_event(),
|
||||
'payment' => $this->invoice->payments()->exists() ? $this->invoice->payments()->first()->transaction_event() : [],
|
||||
'client' => $this->invoice->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => ['total_payments' => $this->total_payments, 'balance_adjustment' => $this->balance_adjustment, 'adjustment_amount' => $this->adjustment_amount],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::INVOICE_DELETED, $transaction, $this->invoice->company->db);
|
||||
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
|
|
@ -127,11 +139,6 @@ class MarkInvoiceDeleted extends AbstractService
|
|||
$this->total_payments = $this->invoice->payments->sum('amount') - $this->invoice->payments->sum('refunded');
|
||||
|
||||
$this->balance_adjustment = $this->invoice->balance;
|
||||
|
||||
//$this->total_payments = $this->invoice->payments->sum('amount - refunded');
|
||||
|
||||
// nlog("adjustment amount = {$this->adjustment_amount}");
|
||||
// nlog("total payments = {$this->total_payments}");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ use App\Events\Invoice\InvoiceWasPaid;
|
|||
use App\Events\Payment\PaymentWasCreated;
|
||||
use App\Factory\PaymentFactory;
|
||||
use App\Jobs\Invoice\InvoiceWorkflowSettings;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Jobs\Payment\EmailPayment;
|
||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Services\AbstractService;
|
||||
use App\Services\Client\ClientService;
|
||||
use App\Utils\Ninja;
|
||||
|
|
@ -110,6 +112,16 @@ class MarkPaid extends AbstractService
|
|||
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
event(new InvoiceWasPaid($this->invoice, $payment, $payment->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $this->invoice->transaction_event(),
|
||||
'payment' => $payment->transaction_event(),
|
||||
'client' => $this->invoice->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::INVOICE_MARK_PAID, $transaction, $this->invoice->company->db);
|
||||
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,17 +34,20 @@ class UpdateBalance extends AbstractService
|
|||
if ($this->invoice->is_deleted) {
|
||||
return $this->invoice;
|
||||
}
|
||||
nlog("invoice id = {$this->invoice->id}");
|
||||
nlog("invoice balance = {$this->invoice->balance}");
|
||||
nlog("invoice adjustment = {$this->balance_adjustment}");
|
||||
|
||||
nlog("invoice id = {$this->invoice->id}");
|
||||
nlog("invoice balance = {$this->invoice->balance}");
|
||||
nlog("invoice adjustment = {$this->balance_adjustment}");
|
||||
|
||||
$this->invoice->balance += floatval($this->balance_adjustment);
|
||||
// $this->invoice->balance += floatval($this->balance_adjustment);
|
||||
|
||||
$this->invoice->increment('balance', floatval($this->balance_adjustment));
|
||||
|
||||
if ($this->invoice->balance == 0 && !$this->is_draft) {
|
||||
$this->invoice->status_id = Invoice::STATUS_PAID;
|
||||
}
|
||||
|
||||
nlog("final balance = {$this->invoice->balance}");
|
||||
nlog("final balance = {$this->invoice->balance}");
|
||||
|
||||
return $this->invoice;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@
|
|||
|
||||
namespace App\Services\Payment;
|
||||
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Repositories\ActivityRepository;
|
||||
|
||||
class DeletePayment
|
||||
|
|
@ -82,6 +84,8 @@ class DeletePayment
|
|||
|
||||
$net_deletable = $paymentable_invoice->pivot->amount - $paymentable_invoice->pivot->refunded;
|
||||
|
||||
$client = $this->payment->client->fresh();
|
||||
|
||||
nlog("net deletable amount - refunded = {$net_deletable}");
|
||||
|
||||
if(!$paymentable_invoice->is_deleted)
|
||||
|
|
@ -95,17 +99,16 @@ class DeletePayment
|
|||
->updateInvoiceBalance($net_deletable, "Adjusting invoice {$paymentable_invoice->number} due to deletion of Payment {$this->payment->number}")
|
||||
->save();
|
||||
|
||||
$paymentable_invoice->client
|
||||
->service()
|
||||
->updateBalance($net_deletable)
|
||||
// ->updatePaidToDate($net_deletable * -1)
|
||||
->save();
|
||||
$client = $client->service()
|
||||
->updateBalance($net_deletable)
|
||||
->save();
|
||||
|
||||
if ($paymentable_invoice->balance == $paymentable_invoice->amount) {
|
||||
$paymentable_invoice->service()->setStatus(Invoice::STATUS_SENT)->save();
|
||||
} else {
|
||||
$paymentable_invoice->service()->setStatus(Invoice::STATUS_PARTIAL)->save();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
|
|
@ -118,19 +121,36 @@ class DeletePayment
|
|||
|
||||
}
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $paymentable_invoice->transaction_event(),
|
||||
'payment' => $this->payment->transaction_event(),
|
||||
'client' => $client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::PAYMENT_DELETED, $transaction, $paymentable_invoice->company->db);
|
||||
|
||||
});
|
||||
}
|
||||
// else {
|
||||
|
||||
/* If there are no invoices - then we need to still adjust the total client->paid_to_date amount*/
|
||||
$this->payment
|
||||
->client
|
||||
->service()
|
||||
->updatePaidToDate(($this->payment->amount - $this->payment->refunded)*-1)
|
||||
->save();
|
||||
|
||||
$this->payment
|
||||
->client
|
||||
->service()
|
||||
->updatePaidToDate(($this->payment->amount - $this->payment->refunded)*-1)
|
||||
->save();
|
||||
$transaction = [
|
||||
'invoice' => [],
|
||||
'payment' => [],
|
||||
'client' => $this->payment->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
// }
|
||||
TransactionLog::dispatch(TransactionEvent::CLIENT_STATUS, $transaction, $this->payment->company->db);
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,12 @@ namespace App\Services\Payment;
|
|||
use App\Exceptions\PaymentRefundFailed;
|
||||
use App\Factory\CreditFactory;
|
||||
use App\Factory\InvoiceItemFactory;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Models\Activity;
|
||||
use App\Models\Credit;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Repositories\ActivityRepository;
|
||||
use App\Utils\Ninja;
|
||||
use stdClass;
|
||||
|
|
@ -51,7 +53,7 @@ class RefundPayment
|
|||
|
||||
public function run()
|
||||
{
|
||||
return $this->calculateTotalRefund() //sets amount for the refund (needed if we are refunding multiple invoices in one payment)
|
||||
$this->payment = $this->calculateTotalRefund() //sets amount for the refund (needed if we are refunding multiple invoices in one payment)
|
||||
->setStatus() //sets status of payment
|
||||
//->reversePayment()
|
||||
//->buildCreditNote() //generate the credit note
|
||||
|
|
@ -61,6 +63,18 @@ class RefundPayment
|
|||
->adjustInvoices()
|
||||
->processGatewayRefund() //process the gateway refund if needed
|
||||
->save();
|
||||
|
||||
$transaction = [
|
||||
'invoice' => [],
|
||||
'payment' => $this->payment->transaction_event(),
|
||||
'client' => $this->payment->client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::PAYMENT_REFUND, $transaction, $this->payment->company->db);
|
||||
|
||||
return $this->payment;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -256,27 +270,51 @@ class RefundPayment
|
|||
|
||||
$adjustment_amount += $refunded_invoice['amount'];
|
||||
$client->balance += $refunded_invoice['amount'];
|
||||
//$client->paid_to_date -= $refunded_invoice['amount'];//todo refund balancing
|
||||
$client->save();
|
||||
|
||||
//todo adjust ledger balance here? or after and reference the credit and its total
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $invoice->transaction_event(),
|
||||
'payment' => [],
|
||||
'client' => $client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::PAYMENT_REFUND, $transaction, $invoice->company->db);
|
||||
|
||||
}
|
||||
|
||||
// $ledger_string = "Refund for Invoice {$invoice->number} for amount " . $refunded_invoice['amount']; //todo
|
||||
|
||||
// $this->credit_note->ledger()->updateCreditBalance($adjustment_amount, $ledger_string);
|
||||
|
||||
$client = $this->payment->client->fresh();
|
||||
|
||||
$client = $this->payment->client->fresh();
|
||||
$client->service()->updatePaidToDate(-1 * $refunded_invoice['amount'])->save();
|
||||
|
||||
|
||||
$transaction = [
|
||||
'invoice' => [],
|
||||
'payment' => [],
|
||||
'client' => $client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::PAYMENT_REFUND, $transaction, $client->company->db);
|
||||
|
||||
}
|
||||
else{
|
||||
//if we are refunding and no payments have been tagged, then we need to decrement the client->paid_to_date by the total refund amount.
|
||||
|
||||
$client = $this->payment->client->fresh();
|
||||
|
||||
$client->service()->updatePaidToDate(-1 * $this->total_refund)->save();
|
||||
|
||||
$transaction = [
|
||||
'invoice' => [],
|
||||
'payment' => [],
|
||||
'client' => $client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::PAYMENT_REFUND, $transaction, $client->company->db);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ namespace App\Services\Payment;
|
|||
|
||||
use App\Events\Invoice\InvoiceWasUpdated;
|
||||
use App\Jobs\Invoice\InvoiceWorkflowSettings;
|
||||
use App\Jobs\Ninja\TransactionLog;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\TransactionEvent;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
|
|
@ -88,6 +90,17 @@ class UpdateInvoicePayment
|
|||
|
||||
$this->payment->applied += $paid_amount;
|
||||
|
||||
$transaction = [
|
||||
'invoice' => $invoice->transaction_event(),
|
||||
'payment' => $this->payment->transaction_event(),
|
||||
'client' => $client->transaction_event(),
|
||||
'credit' => [],
|
||||
'metadata' => [],
|
||||
];
|
||||
|
||||
TransactionLog::dispatch(TransactionEvent::GATEWAY_PAYMENT_MADE, $transaction, $invoice->company->db);
|
||||
|
||||
|
||||
});
|
||||
|
||||
/* Remove the event updater from within the loop to prevent race conditions */
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class GetQuotePdf extends AbstractService
|
|||
public function run()
|
||||
{
|
||||
if (! $this->contact) {
|
||||
$this->contact = $this->quote->client->primary_contact()->first();
|
||||
$this->contact = $this->quote->client->primary_contact()->first() ?: $this->quote->client->contacts()->first();
|
||||
}
|
||||
|
||||
$invitation = $this->quote->invitations->where('client_contact_id', $this->contact->id)->first();
|
||||
|
|
|
|||
|
|
@ -174,6 +174,16 @@ class HtmlEngine
|
|||
$data['$approveButton'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_quote').'</a>', 'label' => ctrans('texts.approve')];
|
||||
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_quote')];
|
||||
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: ' ', 'label' => ctrans('texts.quote_date')];
|
||||
|
||||
if($this->entity->project) {
|
||||
$data['$project.name'] = ['value' => $this->entity->project->name, 'label' => ctrans('texts.project_name')];
|
||||
$data['$invoice.project'] = &$data['$project.name'];
|
||||
}
|
||||
|
||||
if($this->entity->vendor) {
|
||||
$data['$invoice.vendor'] = ['value' => $this->entity->vendor->present()->name(), 'label' => ctrans('texts.vendor_name')];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($this->entity_string == 'credit') {
|
||||
|
|
@ -317,6 +327,7 @@ class HtmlEngine
|
|||
$data['$website'] = ['value' => $this->client->present()->website() ?: ' ', 'label' => ctrans('texts.website')];
|
||||
$data['$phone'] = ['value' => $this->client->present()->phone() ?: ' ', 'label' => ctrans('texts.phone')];
|
||||
$data['$country'] = ['value' => isset($this->client->country->name) ? ctrans('texts.country_' . $this->client->country->name) : '', 'label' => ctrans('texts.country')];
|
||||
$data['$country_2'] = ['value' => isset($this->client->country) ? $this->client->country->iso_3166_2 : '', 'label' => ctrans('texts.country')];
|
||||
$data['$email'] = ['value' => isset($this->contact) ? $this->contact->email : 'no contact email on record', 'label' => ctrans('texts.email')];
|
||||
$data['$client_name'] = ['value' => $this->entity->present()->clientName() ?: ' ', 'label' => ctrans('texts.client_name')];
|
||||
$data['$client.name'] = &$data['$client_name'];
|
||||
|
|
@ -392,6 +403,7 @@ class HtmlEngine
|
|||
$data['$company.state'] = ['value' => $this->settings->state ?: ' ', 'label' => ctrans('texts.state')];
|
||||
$data['$company.postal_code'] = ['value' => $this->settings->postal_code ?: ' ', 'label' => ctrans('texts.postal_code')];
|
||||
$data['$company.country'] = ['value' => $this->getCountryName(), 'label' => ctrans('texts.country')];
|
||||
$data['$company.country_2'] = ['value' => $this->getCountryCode(), 'label' => ctrans('texts.country')];
|
||||
$data['$company.phone'] = ['value' => $this->settings->phone ?: ' ', 'label' => ctrans('texts.phone')];
|
||||
$data['$company.email'] = ['value' => $this->settings->email ?: ' ', 'label' => ctrans('texts.email')];
|
||||
$data['$company.vat_number'] = ['value' => $this->settings->vat_number ?: ' ', 'label' => ctrans('texts.vat_number')];
|
||||
|
|
@ -617,6 +629,17 @@ class HtmlEngine
|
|||
return ' ';
|
||||
}
|
||||
|
||||
|
||||
private function getCountryCode() :string
|
||||
{
|
||||
$country = Country::find($this->settings->country_id);
|
||||
|
||||
if ($country) {
|
||||
return ctrans('texts.country_' . $country->iso_3166_2);
|
||||
}
|
||||
|
||||
return ' ';
|
||||
}
|
||||
/**
|
||||
* Due to the way we are compiling the blade template we
|
||||
* have no ability to iterate, so in the case
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ trait SavesDocuments
|
|||
$is_public
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function saveDocument($document, $entity, $is_public = true)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class TranslationHelper
|
|||
return Cache::get('countries')->each(function ($country) {
|
||||
$country->name = ctrans('texts.country_'.$country->name);
|
||||
})->sortBy(function ($country) {
|
||||
return $country->name;
|
||||
return $country->iso_3166_2;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.3.66',
|
||||
'app_tag' => '5.3.66',
|
||||
'app_version' => '5.3.67',
|
||||
'app_tag' => '5.3.67',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use Illuminate\Database\Migrations\Migration;
|
|||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class Onboarding extends Migration
|
||||
//class Onboarding extends Migration
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
|
|
@ -34,4 +35,4 @@ class Onboarding extends Migration
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
58
database/migrations/2022_03_09_053508_transaction_events.php
Normal file
58
database/migrations/2022_03_09_053508_transaction_events.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class TransactionEvents extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('transaction_events', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('client_id')->index();
|
||||
$table->unsignedInteger('invoice_id');
|
||||
$table->unsignedInteger('payment_id');
|
||||
$table->unsignedInteger('credit_id');
|
||||
$table->decimal('client_balance', 16, 4)->default(0);
|
||||
$table->decimal('client_paid_to_date', 16, 4)->default(0);
|
||||
$table->decimal('client_credit_balance', 16, 4)->default(0);
|
||||
$table->decimal('invoice_balance', 16, 4)->default(0);
|
||||
$table->decimal('invoice_amount', 16, 4)->default(0);
|
||||
$table->decimal('invoice_partial', 16, 4)->default(0);
|
||||
$table->decimal('invoice_paid_to_date', 16, 4)->default(0);
|
||||
$table->unsignedInteger('invoice_status')->nullable();
|
||||
$table->decimal('payment_amount', 16, 4)->default(0);
|
||||
$table->decimal('payment_applied', 16, 4)->default(0);
|
||||
$table->decimal('payment_refunded', 16, 4)->default(0);
|
||||
$table->unsignedInteger('payment_status')->nullable();
|
||||
$table->mediumText('paymentables')->nullable();
|
||||
$table->unsignedInteger('event_id');
|
||||
$table->unsignedInteger('timestamp');
|
||||
$table->mediumText('payment_request')->nullable();
|
||||
$table->mediumText('metadata')->nullable();
|
||||
$table->decimal('credit_balance', 16, 4)->default(0);
|
||||
$table->decimal('credit_amount', 16, 4)->default(0);
|
||||
$table->unsignedInteger('credit_status')->nullable();
|
||||
|
||||
$table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade')->onUpdate('cascade');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
2
public/css/app.css
vendored
2
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
56
public/flutter_service_worker.js
vendored
56
public/flutter_service_worker.js
vendored
|
|
@ -3,42 +3,42 @@ const MANIFEST = 'flutter-app-manifest';
|
|||
const TEMP = 'flutter-temp-cache';
|
||||
const CACHE_NAME = 'flutter-app-cache';
|
||||
const RESOURCES = {
|
||||
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
|
||||
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
|
||||
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
|
||||
"canvaskit/canvaskit.js": "c2b4e5f3d7a3d82aed024e7249a78487",
|
||||
"assets/fonts/MaterialIcons-Regular.otf": "7e7a6cccddf6d7b20012a548461d5d81",
|
||||
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
||||
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
|
||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
|
||||
"assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a",
|
||||
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
|
||||
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
|
||||
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
|
||||
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
|
||||
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
|
||||
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
|
||||
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
|
||||
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
|
||||
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
|
||||
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
|
||||
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
|
||||
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
|
||||
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
|
||||
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
|
||||
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
|
||||
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
|
||||
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
|
||||
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
|
||||
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
|
||||
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
|
||||
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
|
||||
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
|
||||
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
|
||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
|
||||
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "015400679694f1f51047e46da0e1dc98",
|
||||
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
|
||||
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
|
||||
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
|
||||
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
|
||||
"assets/NOTICES": "9a4bf0423a5e265f38c4df37f7a0a913",
|
||||
"assets/fonts/MaterialIcons-Regular.otf": "7e7a6cccddf6d7b20012a548461d5d81",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"/": "7c3ca4e7f4b430421585744bdd926f67",
|
||||
"version.json": "443986d36b3df952ad780139ecccd516",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"main.dart.js": "c0d886e3bce647afe312a4cc2853c08f",
|
||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "015400679694f1f51047e46da0e1dc98",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
|
||||
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
|
||||
"canvaskit/canvaskit.js": "c2b4e5f3d7a3d82aed024e7249a78487",
|
||||
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba"
|
||||
"/": "9c1820b56e212ef046fb5b877da280e6",
|
||||
"version.json": "443986d36b3df952ad780139ecccd516",
|
||||
"main.dart.js": "e82126a54ecc81baa8cf3c81f212ca69",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628"
|
||||
};
|
||||
|
||||
// The application shell files that are downloaded before a service worker can
|
||||
|
|
|
|||
2
public/js/clients/payments/stripe-sepa.js
vendored
2
public/js/clients/payments/stripe-sepa.js
vendored
File diff suppressed because one or more lines are too long
221559
public/main.dart.js
vendored
221559
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
224334
public/main.foss.dart.js
vendored
224334
public/main.foss.dart.js
vendored
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
Loading…
Add table
Reference in a new issue