merge v5-dev

This commit is contained in:
David Bomba 2022-07-17 20:38:00 +10:00
commit 9b6bfbf96c
18 changed files with 186033 additions and 186186 deletions

View File

@ -91,38 +91,38 @@ class CheckData extends Command
protected $wrong_paid_status = 0;
public function handle()
{
$time_start = microtime(true);
$time_start = microtime(true);
$database_connection = $this->option('database') ? $this->option('database') : 'Connected to Default DB';
$fix_status = $this->option('fix') ? 'Fixing Issues' : 'Just checking issues ';
$fix_status = $this->option('fix') ? "Fixing Issues" : "Just checking issues ";
$this->logMessage(date('Y-m-d h:i:s').' Running CheckData... on '.$database_connection." Fix Status = {$fix_status}");
$this->logMessage(date('Y-m-d h:i:s').' Running CheckData... on ' . $database_connection . " Fix Status = {$fix_status}");
if ($database = $this->option('database')) {
config(['database.default' => $database]);
}
$this->checkInvoiceBalances();
$this->checkInvoiceBalances();
$this->checkClientBalanceEdgeCases();
$this->checkPaidToDatesNew();
$this->checkContacts();
$this->checkVendorContacts();
$this->checkEntityInvitations();
$this->checkCompanyData();
$this->checkBalanceVsPaidStatus();
if (Ninja::isHosted()) {
if(Ninja::isHosted())
$this->checkAccountStatuses();
}
if (! $this->option('client_id')) {
$this->checkOAuth();
}
$this->logMessage('Done: '.strtoupper($this->isValid ? Account::RESULT_SUCCESS : Account::RESULT_FAILURE));
$this->logMessage('Total execution time in seconds: '.(microtime(true) - $time_start));
$this->logMessage('Total execution time in seconds: ' . (microtime(true) - $time_start));
$errorEmail = config('ninja.error_email');
@ -235,7 +235,7 @@ class CheckData extends Command
if ($this->option('fix') == 'true') {
foreach ($clients as $client) {
$this->logMessage("Fixing missing contacts #{$client->id}");
$new_contact = ClientContactFactory::create($client->company_id, $client->user_id);
$new_contact->client_id = $client->id;
$new_contact->contact_key = Str::random(40);
@ -243,6 +243,7 @@ class CheckData extends Command
$new_contact->save();
}
}
}
private function checkVendorContacts()
@ -290,11 +291,12 @@ class CheckData extends Command
}
if ($this->option('fix') == 'true') {
$vendors = Vendor::withTrashed()->doesntHave('contacts')->get();
foreach ($vendors as $vendor) {
$this->logMessage("Fixing missing vendor contacts #{$vendor->id}");
$new_contact = VendorContactFactory::create($vendor->company_id, $vendor->user_id);
$new_contact->vendor_id = $vendor->id;
$new_contact->contact_key = Str::random(40);
@ -302,8 +304,10 @@ class CheckData extends Command
$new_contact->save();
}
}
}
private function checkFailedJobs()
{
if (config('ninja.testvars.travis')) {
@ -352,32 +356,36 @@ class CheckData extends Command
private function checkEntityInvitations()
{
RecurringInvoiceInvitation::where('deleted_at', '0000-00-00 00:00:00.000000')->withTrashed()->update(['deleted_at' => null]);
InvoiceInvitation::where('deleted_at', '0000-00-00 00:00:00.000000')->withTrashed()->update(['deleted_at' => null]);
QuoteInvitation::where('deleted_at', '0000-00-00 00:00:00.000000')->withTrashed()->update(['deleted_at' => null]);
CreditInvitation::where('deleted_at', '0000-00-00 00:00:00.000000')->withTrashed()->update(['deleted_at' => null]);
RecurringInvoiceInvitation::where('deleted_at',"0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]);
InvoiceInvitation::where('deleted_at',"0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]);
QuoteInvitation::where('deleted_at',"0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]);
CreditInvitation::where('deleted_at',"0000-00-00 00:00:00.000000")->withTrashed()->update(['deleted_at' => null]);
$entities = ['invoice', 'quote', 'credit', 'recurring_invoice'];
foreach ($entities as $entity) {
foreach($entities as $entity)
{
$table = "{$entity}s";
$invitation_table = "{$entity}_invitations";
$entities = DB::table($table)
->leftJoin($invitation_table, function ($join) use ($invitation_table, $table, $entity) {
$entities = DB::table($table)
->leftJoin($invitation_table, function ($join) use($invitation_table, $table, $entity){
$join->on("{$invitation_table}.{$entity}_id", '=', "{$table}.id");
// ->whereNull("{$invitation_table}.deleted_at");
// ->whereNull("{$invitation_table}.deleted_at");
})
->groupBy("{$table}.id", "{$table}.user_id", "{$table}.company_id", "{$table}.client_id")
->havingRaw("count({$invitation_table}.id) = 0")
->get(["{$table}.id", "{$table}.user_id", "{$table}.company_id", "{$table}.client_id"]);
$this->logMessage($entities->count()." {$table} without any invitations");
if ($this->option('fix') == 'true') {
$this->fixInvitations($entities, $entity);
}
$this->logMessage($entities->count()." {$table} without any invitations");
if ($this->option('fix') == 'true')
$this->fixInvitations($entities, $entity);
}
}
private function fixInvitations($entities, $entity)
@ -386,7 +394,8 @@ class CheckData extends Command
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
foreach ($entities as $entity) {
foreach($entities as $entity)
{
$invitation = new $entity_obj();
$invitation->company_id = $entity->company_id;
$invitation->user_id = $entity->user_id;
@ -394,17 +403,20 @@ class CheckData extends Command
$invitation->client_contact_id = ClientContact::whereClientId($entity->client_id)->first()->id;
$invitation->key = Str::random(config('ninja.key_length'));
try {
try{
$invitation->save();
} catch (\Exception $e) {
}
catch(\Exception $e){
$invitation = null;
}
}
}
private function clientPaidToDateQuery()
{
$results = \DB::select(\DB::raw('
$results = \DB::select( \DB::raw("
SELECT
clients.id as client_id,
clients.paid_to_date as client_paid_to_date,
@ -419,14 +431,14 @@ class CheckData extends Command
GROUP BY clients.id
HAVING payments_applied != client_paid_to_date
ORDER BY clients.id;
'));
") );
return $results;
}
private function clientCreditPaymentables($client)
{
$results = \DB::select(\DB::raw('
$results = \DB::select( \DB::raw("
SELECT
SUM(paymentables.amount - paymentables.refunded) as credit_payment
FROM payments
@ -438,8 +450,8 @@ class CheckData extends Command
AND paymentables.amount > 0
AND payments.is_deleted = 0
AND payments.client_id = ?;
'), [App\Models\Credit::class, $client->id]);
"), [App\Models\Credit::class, $client->id] );
return $results;
}
@ -448,8 +460,9 @@ class CheckData extends Command
$clients_to_check = $this->clientPaidToDateQuery();
$this->wrong_paid_to_dates = 0;
foreach ($clients_to_check as $_client) {
foreach($clients_to_check as $_client)
{
$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');
@ -458,22 +471,26 @@ class CheckData extends Command
$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)) {
if(round($total_paid_to_date,2) != round($_client->client_paid_to_date,2)){
$this->wrong_paid_to_dates++;
$this->logMessage($client->present()->name.' id = # '.$client->id." - Client Paid To Date = {$client->paid_to_date} != Invoice Payments = {$total_paid_to_date} - {$_client->payments_applied} + {$credits_used_for_payments[0]->credit_payment}");
$this->isValid = false;
if ($this->option('paid_to_date')) {
$this->logMessage("# {$client->id} ".$client->present()->name.' - '.$client->number." Fixing {$client->paid_to_date} to {$total_paid_to_date}");
if($this->option('paid_to_date')){
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->paid_to_date} to {$total_paid_to_date}");
$client->paid_to_date = $total_paid_to_date;
$client->save();
}
}
}
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect paid to dates");
}
private function checkPaidToDates()
@ -482,12 +499,12 @@ class CheckData extends Command
$credit_total_applied = 0;
$clients = DB::table('clients')
->leftJoin('payments', function ($join) {
->leftJoin('payments', function($join) {
$join->on('payments.client_id', '=', 'clients.id')
->where('payments.is_deleted', 0)
->whereIn('payments.status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED]);
})
->where('clients.is_deleted', 0)
->where('clients.is_deleted',0)
->where('clients.updated_at', '>', now()->subDays(2))
->groupBy('clients.id')
->havingRaw('clients.paid_to_date != sum(coalesce(payments.amount - payments.refunded, 0))')
@ -495,16 +512,19 @@ class CheckData extends Command
/* Due to accounting differences we need to perform a second loop here to ensure there actually is an issue */
$clients->each(function ($client_record) use ($credit_total_applied) {
$client = Client::withTrashed()->find($client_record->id);
$total_invoice_payments = 0;
foreach ($client->invoices()->where('is_deleted', false)->where('status_id', '>', 1)->get() as $invoice) {
$total_invoice_payments += $invoice->payments()
->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])
->selectRaw('sum(paymentables.amount - paymentables.refunded) as p')
->pluck('p')
->first();
}
//commented IN 27/06/2021 - sums ALL client payments AND the unapplied amounts to match the client paid to date
@ -517,6 +537,7 @@ class CheckData extends Command
// 10/02/21
foreach ($client->payments as $payment) {
$credit_total_applied += $payment->paymentables()
->where('paymentable_type', App\Models\Credit::class)
->selectRaw('sum(paymentables.amount - paymentables.refunded) as p')
@ -526,7 +547,7 @@ class CheckData extends Command
if ($credit_total_applied < 0) {
$total_invoice_payments += $credit_total_applied;
}
}
if (round($total_invoice_payments, 2) != round($client->paid_to_date, 2)) {
$this->wrong_paid_to_dates++;
@ -535,8 +556,8 @@ class CheckData extends Command
$this->isValid = false;
if ($this->option('paid_to_date')) {
$this->logMessage("# {$client->id} ".$client->present()->name.' - '.$client->number." Fixing {$client->paid_to_date} to {$total_invoice_payments}");
if($this->option('paid_to_date')){
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->paid_to_date} to {$total_invoice_payments}");
$client->paid_to_date = $total_invoice_payments;
$client->save();
}
@ -551,7 +572,9 @@ class CheckData extends Command
$this->wrong_balances = 0;
Client::cursor()->where('is_deleted', 0)->where('clients.updated_at', '>', now()->subDays(2))->each(function ($client) {
$client->invoices->where('is_deleted', false)->whereIn('status_id', '!=', Invoice::STATUS_DRAFT)->each(function ($invoice) use ($client) {
$total_paid = $invoice->payments()
->where('is_deleted', false)->whereIn('status_id', [Payment::STATUS_COMPLETED, Payment:: STATUS_PENDING, Payment::STATUS_PARTIALLY_REFUNDED, Payment::STATUS_REFUNDED])
->selectRaw('sum(paymentables.amount - paymentables.refunded) as p')
@ -562,7 +585,7 @@ class CheckData extends Command
$calculated_paid_amount = $invoice->amount - $invoice->balance - $total_credit;
if ((string) $total_paid != (string) ($invoice->amount - $invoice->balance - $total_credit)) {
if ((string)$total_paid != (string)($invoice->amount - $invoice->balance - $total_credit)) {
$this->wrong_balances++;
$this->logMessage($client->present()->name.' - '.$client->id." - Total Paid = {$total_paid} != Calculated Total = {$calculated_paid_amount}");
@ -570,6 +593,7 @@ class CheckData extends Command
$this->isValid = false;
}
});
});
$this->logMessage("{$this->wrong_balances} clients with incorrect invoice balances");
@ -577,7 +601,7 @@ class CheckData extends Command
private function clientBalanceQuery()
{
$results = \DB::select(\DB::raw('
$results = \DB::select( \DB::raw("
SELECT
SUM(invoices.balance) as invoice_balance,
clients.id as client_id,
@ -591,8 +615,8 @@ class CheckData extends Command
GROUP BY clients.id
HAVING invoice_balance != clients.balance
ORDER BY clients.id;
'));
") );
return $results;
}
@ -603,32 +627,70 @@ class CheckData extends Command
$clients = $this->clientBalanceQuery();
foreach ($clients as $client) {
$client = (array) $client;
foreach($clients as $client)
{
$client = (array)$client;
if ((string) $client['invoice_balance'] != (string) $client['client_balance']) {
$this->wrong_paid_to_dates++;
$client_object = Client::withTrashed()->find($client['client_id']);
$this->logMessage($client_object->present()->name.' - '.$client_object->id.' - calculated client balances do not match Invoice Balances = '.$client['invoice_balance'].' - Client Balance = '.rtrim($client['client_balance'], '0'));
if ($this->option('client_balance')) {
$this->logMessage("# {$client_object->id} ".$client_object->present()->name.' - '.$client_object->number." Fixing {$client_object->balance} to ".$client['invoice_balance']);
$this->logMessage($client_object->present()->name.' - '.$client_object->id." - calculated client balances do not match Invoice Balances = ". $client['invoice_balance'] ." - Client Balance = ".rtrim($client['client_balance'], '0'));
if($this->option('client_balance')){
$this->logMessage("# {$client_object->id} " . $client_object->present()->name.' - '.$client_object->number." Fixing {$client_object->balance} to " . $client['invoice_balance']);
$client_object->balance = $client['invoice_balance'];
$client_object->save();
}
$this->isValid = false;
$this->isValid = false;
}
}
$this->logMessage("{$this->wrong_paid_to_dates} clients with incorrect client balances");
}
private function checkClientBalanceEdgeCases()
{
Client::query()
->where('is_deleted',false)
->where('balance', '!=', 0)
->cursor()
->each(function ($client){
$count = Invoice::withTrashed()
->where('client_id', $client->id)
->where('is_deleted',false)
->whereIn('status_id', [2,3])
->count();
if($count == 0){
$this->logMessage("# {$client->id} # {$client->name} {$client->balance} is invalid should be 0");
if($this->option('client_balance')){
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->balance} to 0");
$client->balance = 0;
$client->save();
}
}
});
}
private function invoiceBalanceQuery()
{
$results = \DB::select(\DB::raw('
$results = \DB::select( \DB::raw("
SELECT
clients.id,
clients.balance,
@ -642,8 +704,8 @@ class CheckData extends Command
GROUP BY clients.id
HAVING(invoices_balance != clients.balance)
ORDER BY clients.id;
'));
") );
return $results;
}
@ -654,10 +716,11 @@ class CheckData extends Command
$_clients = $this->invoiceBalanceQuery();
foreach ($_clients as $_client) {
foreach($_clients as $_client)
{
$client = Client::withTrashed()->find($_client->id);
$invoice_balance = $client->invoices()->where('is_deleted', false)->whereIn('status_id', [2, 3])->sum('balance');
$invoice_balance = $client->invoices()->where('is_deleted', false)->whereIn('status_id', [2,3])->sum('balance');
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
@ -665,26 +728,31 @@ class CheckData extends Command
$this->wrong_balances++;
$ledger_balance = $ledger ? $ledger->balance : 0;
$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 - Invoice Balances = {$invoice_balance} Client Balance = {$client->balance} Ledger Balance = {$ledger_balance}");
$this->isValid = false;
if ($this->option('client_balance')) {
$this->logMessage("# {$client->id} ".$client->present()->name.' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
if($this->option('client_balance')){
$this->logMessage("# {$client->id} " . $client->present()->name.' - '.$client->number." Fixing {$client->balance} to {$invoice_balance}");
$client->balance = $invoice_balance;
$client->save();
}
if ($ledger && (number_format($invoice_balance, 4) != number_format($ledger->balance, 4))) {
if($ledger && (number_format($invoice_balance, 4) != number_format($ledger->balance, 4)))
{
$ledger->adjustment = $invoice_balance;
$ledger->balance = $invoice_balance;
$ledger->notes = 'Ledger Adjustment';
$ledger->save();
}
}
}
$this->logMessage("{$this->wrong_balances} clients with incorrect balances");
}
private function checkLedgerBalances()
@ -693,17 +761,19 @@ class CheckData extends Command
$this->wrong_paid_to_dates = 0;
foreach (Client::where('is_deleted', 0)->where('clients.updated_at', '>', now()->subDays(2))->cursor() as $client) {
$invoice_balance = $client->invoices()->where('is_deleted', false)->whereIn('status_id', [2, 3])->sum('balance');
$invoice_balance = $client->invoices()->where('is_deleted', false)->whereIn('status_id', [2,3])->sum('balance');
$ledger = CompanyLedger::where('client_id', $client->id)->orderBy('id', 'DESC')->first();
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 - 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('ledger_balance')) {
$this->logMessage("# {$client->id} ".$client->present()->name.' - '.$client->number." Fixing {$client->balance} to {$invoice_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;
$client->save();
@ -712,6 +782,7 @@ class CheckData extends Command
$ledger->notes = 'Ledger Adjustment';
$ledger->save();
}
}
}
@ -803,20 +874,22 @@ class CheckData extends Command
public function checkAccountStatuses()
{
Account::where('plan_expires', '<=', now()->subDays(2))->cursor()->each(function ($account) {
$client = Client::on('db-ninja-01')->where('company_id', config('ninja.ninja_default_company_id'))->where('custom_value2', $account->key)->first();
Account::where('plan_expires', '<=', now()->subDays(2))->cursor()->each(function ($account){
if ($client) {
$client = Client::on('db-ninja-01')->where('company_id', config('ninja.ninja_default_company_id'))->where('custom_value2', $account->key)->first();
if($client){
$payment = Payment::on('db-ninja-01')
->where('company_id', config('ninja.ninja_default_company_id'))
->where('client_id', $client->id)
->where('date', '>=', now()->subDays(2))
->exists();
if ($payment) {
if($payment)
$this->logMessage("I found a payment for {$account->key}");
}
}
});
}
@ -824,21 +897,24 @@ class CheckData extends Command
{
$this->wrong_paid_status = 0;
foreach (Invoice::with(['payments'])->whereHas('payments')->where('status_id', 4)->where('balance', '>', 0)->where('is_deleted', 0)->cursor() as $invoice) {
foreach(Invoice::with(['payments'])->whereHas('payments')->where('status_id', 4)->where('balance', '>', 0)->where('is_deleted',0)->cursor() as $invoice)
{
$this->wrong_paid_status++;
$this->logMessage("# {$invoice->id} " . ' - '.$invoice->number." - Marked as paid, but balance = {$invoice->balance}");
$this->logMessage("# {$invoice->id} ".' - '.$invoice->number." - Marked as paid, but balance = {$invoice->balance}");
if($this->option('balance_status')){
if ($this->option('balance_status')) {
$val = $invoice->balance;
$invoice->balance = 0;
$invoice->paid_to_date = $val;
$invoice->paid_to_date=$val;
$invoice->save();
$p = $invoice->payments->first();
if ($p && (int) $p->amount == 0) {
if($p && (int)$p->amount == 0)
{
$p->amount = $val;
$p->applied = $val;
$p->save();
@ -848,10 +924,14 @@ class CheckData extends Command
$pivot->save();
}
$this->logMessage("Fixing {$invoice->id} settings payment to {$val}");
}
}
$this->logMessage($this->wrong_paid_status.' wrong invoices with bad balance state');
$this->logMessage($this->wrong_paid_status." wrong invoices with bad balance state");
}
}
}

View File

@ -57,9 +57,9 @@ use stdClass;
class CreateSingleAccount extends Command
{
use MakesHash, GeneratesCounter;
protected $description = 'Create Single Sample Account';
protected $signature = 'ninja:create-single-account {gateway=all} {--database=db-ninja-01}';
protected $invoice_repo;
@ -75,13 +75,12 @@ class CreateSingleAccount extends Command
*/
public function handle()
{
if (config('ninja.is_docker')) {
return;
}
if (! $this->confirm('Are you sure you want to inject dummy data?')) {
if(config('ninja.is_docker'))
return;
if (!$this->confirm('Are you sure you want to inject dummy data?'))
return;
}
$this->invoice_repo = new InvoiceRepository();
@ -106,10 +105,10 @@ class CreateSingleAccount extends Command
$company = Company::factory()->create([
'account_id' => $account->id,
'slack_webhook_url' => config('ninja.notification.slack'),
'default_password_timeout' => 30 * 60000,
'default_password_timeout' => 30*60000,
'portal_mode' => 'domain',
'portal_domain' => 'http://ninja.test:8000',
'track_inventory' => true,
'track_inventory' => true
]);
$settings = $company->settings;
@ -154,31 +153,33 @@ class CreateSingleAccount extends Command
]);
Product::factory()->count(1)->create([
'user_id' => $user->id,
'company_id' => $company->id,
]);
'user_id' => $user->id,
'company_id' => $company->id,
]);
TaxRate::factory()->create([
'user_id' => $user->id,
'company_id' => $company->id,
'name' => 'GST',
'rate' => 10,
'rate' => 10
]);
TaxRate::factory()->create([
'user_id' => $user->id,
'company_id' => $company->id,
'name' => 'VAT',
'rate' => 17.5,
'rate' => 17.5
]);
TaxRate::factory()->create([
'user_id' => $user->id,
'company_id' => $company->id,
'name' => 'CA Sales Tax',
'rate' => 5,
'rate' => 5
]);
$this->info('Creating '.$this->count.' clients');
for ($x = 0; $x < $this->count; $x++) {
@ -188,7 +189,7 @@ class CreateSingleAccount extends Command
$this->createClient($company, $user);
}
CreateCompanyTaskStatuses::dispatchSync($company, $user);
CreateCompanyTaskStatuses::dispatchNow($company, $user);
for ($x = 0; $x < $this->count; $x++) {
$client = $company->clients->random();
@ -226,18 +227,18 @@ class CreateSingleAccount extends Command
$client = $company->clients->random();
$this->info('creating task for client #'.$client->id);
$this->info('creating task for client #' . $client->id);
$this->createTask($client);
$client = $company->clients->random();
$this->info('creating project for client #'.$client->id);
$this->info('creating project for client #' . $client->id);
$this->createProject($client);
$this->info('creating credit for client #'.$client->id);
$this->info('creating credit for client #' . $client->id);
$this->createCredit($client);
$this->info('creating recurring invoice for client # '.$client->id);
$this->info('creating recurring invoice for client # ' . $client->id);
$this->createRecurringInvoice($client);
}
@ -249,7 +250,7 @@ class CreateSingleAccount extends Command
private function createSubsData($company, $user)
{
$gs = GroupSettingFactory::create($company->id, $user->id);
$gs->name = 'plans';
$gs->name = "plans";
$gs->save();
$p1 = Product::factory()->create([
@ -289,7 +290,7 @@ class CreateSingleAccount extends Command
];
$sub = SubscriptionFactory::create($company->id, $user->id);
$sub->name = 'Pro Plan';
$sub->name = "Pro Plan";
$sub->group_id = $gs->id;
$sub->recurring_product_ids = "{$p1->hashed_id}";
$sub->webhook_configuration = $webhook_config;
@ -298,7 +299,7 @@ class CreateSingleAccount extends Command
$sub->save();
$sub = SubscriptionFactory::create($company->id, $user->id);
$sub->name = 'Enterprise Plan';
$sub->name = "Enterprise Plan";
$sub->group_id = $gs->id;
$sub->recurring_product_ids = "{$p2->hashed_id}";
$sub->webhook_configuration = $webhook_config;
@ -307,7 +308,7 @@ class CreateSingleAccount extends Command
$sub->save();
$sub = SubscriptionFactory::create($company->id, $user->id);
$sub->name = 'Free Plan';
$sub->name = "Free Plan";
$sub->group_id = $gs->id;
$sub->recurring_product_ids = "{$p3->hashed_id}";
$sub->webhook_configuration = $webhook_config;
@ -323,28 +324,28 @@ class CreateSingleAccount extends Command
// });
$client = Client::factory()->create([
'user_id' => $user->id,
'company_id' => $company->id,
]);
'user_id' => $user->id,
'company_id' => $company->id,
]);
ClientContact::factory()->create([
'user_id' => $user->id,
'client_id' => $client->id,
'company_id' => $company->id,
'is_primary' => 1,
'email' => 'user@example.com',
]);
'user_id' => $user->id,
'client_id' => $client->id,
'company_id' => $company->id,
'is_primary' => 1,
'email' => 'user@example.com'
]);
ClientContact::factory()->count(rand(1, 2))->create([
'user_id' => $user->id,
'client_id' => $client->id,
'company_id' => $company->id,
]);
'user_id' => $user->id,
'client_id' => $client->id,
'company_id' => $company->id,
]);
$client->number = $this->getNextClientNumber($client);
$settings = $client->settings;
$settings->currency_id = '1';
$settings->currency_id = "1";
// $settings->use_credits_payment = "always";
$client->settings = $settings;
@ -358,48 +359,49 @@ class CreateSingleAccount extends Command
private function createExpense($client)
{
Expense::factory()->count(rand(1, 2))->create([
'user_id' => $client->user->id,
'client_id' => $client->id,
'company_id' => $client->company->id,
]);
'user_id' => $client->user->id,
'client_id' => $client->id,
'company_id' => $client->company->id,
]);
}
private function createVendor($client)
{
$vendor = Vendor::factory()->create([
'user_id' => $client->user->id,
'company_id' => $client->company->id,
]);
'user_id' => $client->user->id,
'company_id' => $client->company->id,
]);
VendorContact::factory()->create([
'user_id' => $client->user->id,
'vendor_id' => $vendor->id,
'company_id' => $client->company->id,
'is_primary' => 1,
]);
'user_id' => $client->user->id,
'vendor_id' => $vendor->id,
'company_id' => $client->company->id,
'is_primary' => 1,
]);
VendorContact::factory()->count(rand(1, 2))->create([
'user_id' => $client->user->id,
'vendor_id' => $vendor->id,
'company_id' => $client->company->id,
'is_primary' => 0,
]);
'user_id' => $client->user->id,
'vendor_id' => $vendor->id,
'company_id' => $client->company->id,
'is_primary' => 0,
]);
}
private function createTask($client)
{
$vendor = Task::factory()->create([
'user_id' => $client->user->id,
'company_id' => $client->company->id,
]);
'user_id' => $client->user->id,
'company_id' => $client->company->id,
]);
}
private function createProject($client)
{
$vendor = Project::factory()->create([
'user_id' => $client->user->id,
'company_id' => $client->company->id,
]);
'user_id' => $client->user->id,
'company_id' => $client->company->id,
'client_id' => $client->id,
]);
}
private function createInvoice($client)
@ -429,7 +431,7 @@ class CreateSingleAccount extends Command
$invoice->tax_rate3 = 5;
}
$invoice->custom_value1 = $faker->date();
$invoice->custom_value1 = $faker->date;
$invoice->custom_value2 = rand(0, 1) ? 'yes' : 'no';
$invoice->save();
@ -516,6 +518,7 @@ class CreateSingleAccount extends Command
$quote->service()->createInvitations();
}
private function buildCreditItem()
{
$line_items = [];
@ -536,9 +539,11 @@ class CreateSingleAccount extends Command
$line_items[] = $item;
return $line_items;
}
private function buildLineItems($count = 1)
{
$line_items = [];
@ -610,6 +615,7 @@ class CreateSingleAccount extends Command
private function createGateways($company, $user)
{
if (config('ninja.testvars.stripe') && ($this->gateway == 'all' || $this->gateway == 'stripe')) {
$cg = new CompanyGateway;
$cg->company_id = $company->id;
$cg->user_id = $user->id;
@ -628,6 +634,8 @@ class CreateSingleAccount extends Command
$cg->fees_and_limits = $fees_and_limits;
$cg->save();
}
if (config('ninja.testvars.paypal') && ($this->gateway == 'all' || $this->gateway == 'paypal')) {
@ -735,6 +743,7 @@ class CreateSingleAccount extends Command
$cg->save();
}
if (config('ninja.testvars.paytrace.decrypted') && ($this->gateway == 'all' || $this->gateway == 'paytrace')) {
$cg = new CompanyGateway;
$cg->company_id = $company->id;
@ -748,6 +757,7 @@ class CreateSingleAccount extends Command
$cg->save();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
@ -827,7 +837,7 @@ class CreateSingleAccount extends Command
$invoice->tax_rate3 = 5;
}
$invoice->custom_value1 = $faker->date();
$invoice->custom_value1 = $faker->date;
$invoice->custom_value2 = rand(0, 1) ? 'yes' : 'no';
$invoice->status_id = RecurringInvoice::STATUS_ACTIVE;

View File

@ -97,8 +97,20 @@ class PaymentController extends Controller
$client = $invoice ? $invoice->client : auth()->guard('contact')->user()->client;
// 09-07-2022 catch duplicate responses for invoices that already paid here.
if($invoice && $invoice->status_id == Invoice::STATUS_PAID)
abort(400, 'Invoice paid. Duplicate submission');
if($invoice && $invoice->status_id == Invoice::STATUS_PAID){
$data = [
'invoice' => $invoice,
'key' => false
];
if ($request->query('mode') === 'fullscreen') {
return render('invoices.show-fullscreen', $data);
}
return $this->render('invoices.show', $data);
}
return $gateway
->driver($client)

View File

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

View File

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

View File

@ -20,6 +20,7 @@ use App\Mail\DownloadInvoices;
use App\Models\Company;
use App\Models\CreditInvitation;
use App\Models\InvoiceInvitation;
use App\Models\PurchaseOrderInvitation;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoice;
use App\Models\RecurringInvoiceInvitation;
@ -68,6 +69,7 @@ class CompanyExport implements ShouldQueue
*/
public function handle()
{
MultiDB::setDb($this->company->db);
$this->company = Company::where('company_key', $this->company->company_key)->first();
@ -76,7 +78,8 @@ class CompanyExport implements ShouldQueue
$this->export_data['app_version'] = config('ninja.app_version');
$this->export_data['activities'] = $this->company->all_activities->map(function ($activity) {
$this->export_data['activities'] = $this->company->all_activities->map(function ($activity){
$activity = $this->transformArrayOfKeys($activity, [
'user_id',
'company_id',
@ -94,10 +97,11 @@ class CompanyExport implements ShouldQueue
'token_id',
'quote_id',
'subscription_id',
'recurring_invoice_id',
'recurring_invoice_id'
]);
return $activity;
})->makeHidden(['id'])->all();
// $this->export_data['backups'] = $this->company->all_activities()->with('backup')->cursor()->map(function ($activity){
@ -113,276 +117,387 @@ class CompanyExport implements ShouldQueue
// })->all();
$this->export_data['users'] = $this->company->users()->withTrashed()->cursor()->map(function ($user) {
$this->export_data['users'] = $this->company->users()->withTrashed()->cursor()->map(function ($user){
$user->account_id = $this->encodePrimaryKey($user->account_id);
// $user->id = $this->encodePrimaryKey($user->id);
return $user->makeVisible(['id']);
})->all();
$this->export_data['client_contacts'] = $this->company->client_contacts->map(function ($client_contact) {
$this->export_data['client_contacts'] = $this->company->client_contacts->map(function ($client_contact){
$client_contact = $this->transformArrayOfKeys($client_contact, ['company_id', 'user_id', 'client_id']);
return $client_contact->makeVisible([
'password',
'remember_token',
'user_id',
'company_id',
'client_id',
'google_2fa_secret',
'id',
'oauth_provider_id',
'oauth_user_id',
'token',
'hashed_id',
]);
return $client_contact->makeVisible([
'password',
'remember_token',
'user_id',
'company_id',
'client_id',
'google_2fa_secret',
'id',
'oauth_provider_id',
'oauth_user_id',
'token',
'hashed_id',
]);
})->all();
$this->export_data['client_gateway_tokens'] = $this->company->client_gateway_tokens->map(function ($client_gateway_token) {
$this->export_data['client_gateway_tokens'] = $this->company->client_gateway_tokens->map(function ($client_gateway_token){
$client_gateway_token = $this->transformArrayOfKeys($client_gateway_token, ['company_id', 'client_id', 'company_gateway_id']);
return $client_gateway_token->makeVisible(['id']);
})->all();
$this->export_data['clients'] = $this->company->clients()->orderBy('number', 'DESC')->cursor()->map(function ($client) {
$this->export_data['clients'] = $this->company->clients()->orderBy('number', 'DESC')->cursor()->map(function ($client){
$client = $this->transformArrayOfKeys($client, ['company_id', 'user_id', 'assigned_user_id', 'group_settings_id']);
return $client->makeVisible(['id', 'private_notes', 'user_id', 'company_id', 'last_login', 'hashed_id']);
return $client->makeVisible(['id','private_notes','user_id','company_id','last_login','hashed_id']);
})->all();
$this->export_data['company'] = $this->company->toArray();
$this->export_data['company_gateways'] = $this->company->company_gateways()->withTrashed()->cursor()->map(function ($company_gateway) {
$this->export_data['company_gateways'] = $this->company->company_gateways()->withTrashed()->cursor()->map(function ($company_gateway){
$company_gateway = $this->transformArrayOfKeys($company_gateway, ['company_id', 'user_id']);
$company_gateway->config = decrypt($company_gateway->config);
return $company_gateway->makeVisible(['id']);
})->all();
$this->export_data['company_tokens'] = $this->company->tokens->map(function ($token) {
$this->export_data['company_tokens'] = $this->company->tokens->map(function ($token){
$token = $this->transformArrayOfKeys($token, ['company_id', 'account_id', 'user_id']);
return $token;
})->all();
$this->export_data['company_ledger'] = $this->company->ledger->map(function ($ledger) {
$ledger = $this->transformArrayOfKeys($ledger, ['activity_id', 'client_id', 'company_id', 'account_id', 'user_id', 'company_ledgerable_id']);
$this->export_data['company_ledger'] = $this->company->ledger->map(function ($ledger){
$ledger = $this->transformArrayOfKeys($ledger, ['activity_id', 'client_id', 'company_id', 'account_id', 'user_id','company_ledgerable_id']);
return $ledger;
})->all();
$this->export_data['company_users'] = $this->company->company_users()->without(['user', 'account'])->cursor()->map(function ($company_user) {
$this->export_data['company_users'] = $this->company->company_users()->without(['user','account'])->cursor()->map(function ($company_user){
$company_user = $this->transformArrayOfKeys($company_user, ['company_id', 'account_id', 'user_id']);
return $company_user;
})->all();
$this->export_data['credits'] = $this->company->credits()->orderBy('number', 'DESC')->cursor()->map(function ($credit) {
$this->export_data['credits'] = $this->company->credits()->orderBy('number', 'DESC')->cursor()->map(function ($credit){
$credit = $this->transformBasicEntities($credit);
$credit = $this->transformArrayOfKeys($credit, ['recurring_id', 'client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id', 'invoice_id']);
$credit = $this->transformArrayOfKeys($credit, ['recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id','invoice_id']);
return $credit->makeVisible(['id']);
})->all();
$this->export_data['credit_invitations'] = CreditInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($credit) {
$this->export_data['credit_invitations'] = CreditInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($credit){
$credit = $this->transformArrayOfKeys($credit, ['company_id', 'user_id', 'client_contact_id', 'credit_id']);
return $credit->makeVisible(['id']);
})->all();
$this->export_data['designs'] = $this->company->user_designs->makeHidden(['id'])->all();
$this->export_data['documents'] = $this->company->all_documents->map(function ($document) {
$document = $this->transformArrayOfKeys($document, ['user_id', 'assigned_user_id', 'company_id', 'project_id', 'vendor_id', 'documentable_id']);
$this->export_data['documents'] = $this->company->all_documents->map(function ($document){
$document = $this->transformArrayOfKeys($document, ['user_id', 'assigned_user_id', 'company_id', 'project_id', 'vendor_id','documentable_id']);
$document->hashed_id = $this->encodePrimaryKey($document->id);
return $document->makeVisible(['id']);
})->all();
$this->export_data['expense_categories'] = $this->company->expense_categories->map(function ($expense_category) {
$this->export_data['expense_categories'] = $this->company->expense_categories->map(function ($expense_category){
$expense_category = $this->transformArrayOfKeys($expense_category, ['user_id', 'company_id']);
return $expense_category->makeVisible(['id']);
})->all();
$this->export_data['expenses'] = $this->company->expenses()->orderBy('number', 'DESC')->cursor()->map(function ($expense) {
$this->export_data['expenses'] = $this->company->expenses()->orderBy('number', 'DESC')->cursor()->map(function ($expense){
$expense = $this->transformBasicEntities($expense);
$expense = $this->transformArrayOfKeys($expense, ['vendor_id', 'invoice_id', 'client_id', 'category_id', 'recurring_expense_id', 'project_id']);
$expense = $this->transformArrayOfKeys($expense, ['vendor_id', 'invoice_id', 'client_id', 'category_id', 'recurring_expense_id','project_id']);
return $expense->makeVisible(['id']);
})->all();
$this->export_data['group_settings'] = $this->company->group_settings->map(function ($gs) {
$this->export_data['group_settings'] = $this->company->group_settings->map(function ($gs){
$gs = $this->transformArrayOfKeys($gs, ['user_id', 'company_id']);
return $gs->makeVisible(['id']);
})->all();
$this->export_data['invoices'] = $this->company->invoices()->orderBy('number', 'DESC')->cursor()->map(function ($invoice) {
$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', 'project_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',
'user_id',
'client_id',
'company_id', ]);
'private_notes',
'user_id',
'client_id',
'company_id',]);
})->all();
$this->export_data['invoice_invitations'] = InvoiceInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($invoice) {
$this->export_data['invoice_invitations'] = InvoiceInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($invoice){
$invoice = $this->transformArrayOfKeys($invoice, ['company_id', 'user_id', 'client_contact_id', 'invoice_id']);
return $invoice->makeVisible(['id']);
})->all();
$this->export_data['payment_terms'] = $this->company->user_payment_terms->map(function ($term) {
$this->export_data['payment_terms'] = $this->company->user_payment_terms->map(function ($term){
$term = $this->transformArrayOfKeys($term, ['user_id', 'company_id']);
return $term;
})->makeHidden(['id'])->all();
$this->export_data['payments'] = $this->company->payments()->orderBy('number', 'DESC')->cursor()->map(function ($payment) {
$this->export_data['payments'] = $this->company->payments()->orderBy('number', 'DESC')->cursor()->map(function ($payment){
$payment = $this->transformBasicEntities($payment);
$payment = $this->transformArrayOfKeys($payment, ['client_id', 'project_id', 'vendor_id', 'client_contact_id', 'invitation_id', 'company_gateway_id']);
$payment = $this->transformArrayOfKeys($payment, ['client_id','project_id', 'vendor_id', 'client_contact_id', 'invitation_id', 'company_gateway_id']);
$payment->paymentables = $this->transformPaymentable($payment);
return $payment->makeVisible(['id']);
})->all();
$this->export_data['products'] = $this->company->products->map(function ($product) {
$this->export_data['products'] = $this->company->products->map(function ($product){
$product = $this->transformBasicEntities($product);
$product = $this->transformArrayOfKeys($product, ['vendor_id', 'project_id']);
$product = $this->transformArrayOfKeys($product, ['vendor_id','project_id']);
return $product->makeVisible(['id']);
})->all();
$this->export_data['projects'] = $this->company->projects()->orderBy('number', 'DESC')->cursor()->map(function ($project) {
$this->export_data['projects'] = $this->company->projects()->orderBy('number', 'DESC')->cursor()->map(function ($project){
$project = $this->transformBasicEntities($project);
$project = $this->transformArrayOfKeys($project, ['client_id']);
return $project->makeVisible(['id']);
})->all();
$this->export_data['quotes'] = $this->company->quotes()->orderBy('number', 'DESC')->cursor()->map(function ($quote) {
$this->export_data['quotes'] = $this->company->quotes()->orderBy('number', 'DESC')->cursor()->map(function ($quote){
$quote = $this->transformBasicEntities($quote);
$quote = $this->transformArrayOfKeys($quote, ['invoice_id', 'recurring_id', 'client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id']);
$quote = $this->transformArrayOfKeys($quote, ['invoice_id','recurring_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id']);
return $quote->makeVisible(['id']);
})->all();
$this->export_data['quote_invitations'] = QuoteInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($quote) {
$this->export_data['quote_invitations'] = QuoteInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($quote){
$quote = $this->transformArrayOfKeys($quote, ['company_id', 'user_id', 'client_contact_id', 'quote_id']);
return $quote->makeVisible(['id']);
})->all();
$this->export_data['recurring_expenses'] = $this->company->recurring_expenses()->orderBy('number', 'DESC')->cursor()->map(function ($expense) {
$this->export_data['recurring_expenses'] = $this->company->recurring_expenses()->orderBy('number', 'DESC')->cursor()->map(function ($expense){
$expense = $this->transformBasicEntities($expense);
$expense = $this->transformArrayOfKeys($expense, ['vendor_id', 'invoice_id', 'client_id', 'category_id', 'project_id']);
return $expense->makeVisible(['id']);
})->all();
$this->export_data['recurring_invoices'] = $this->company->recurring_invoices()->orderBy('number', 'DESC')->cursor()->map(function ($ri) {
$this->export_data['recurring_invoices'] = $this->company->recurring_invoices()->orderBy('number', 'DESC')->cursor()->map(function ($ri){
$ri = $this->transformBasicEntities($ri);
$ri = $this->transformArrayOfKeys($ri, ['client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id']);
return $ri->makeVisible(['id']);
})->all();
$this->export_data['recurring_invoice_invitations'] = RecurringInvoiceInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($ri) {
$this->export_data['recurring_invoice_invitations'] = RecurringInvoiceInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($ri){
$ri = $this->transformArrayOfKeys($ri, ['company_id', 'user_id', 'client_contact_id', 'recurring_invoice_id']);
return $ri;
})->all();
$this->export_data['subscriptions'] = $this->company->subscriptions->map(function ($subscription) {
$this->export_data['subscriptions'] = $this->company->subscriptions->map(function ($subscription){
$subscription = $this->transformBasicEntities($subscription);
$subscription->group_id = $this->encodePrimaryKey($subscription->group_id);
return $subscription->makeVisible(['id',
'user_id',
'assigned_user_id',
'company_id',
'product_ids',
'recurring_product_ids',
'group_id', ]);
return $subscription->makeVisible([ 'id',
'user_id',
'assigned_user_id',
'company_id',
'product_ids',
'recurring_product_ids',
'group_id']);
})->all();
$this->export_data['system_logs'] = $this->company->system_logs->map(function ($log) {
$this->export_data['system_logs'] = $this->company->system_logs->map(function ($log){
$log->client_id = $this->encodePrimaryKey($log->client_id);
$log->company_id = $this->encodePrimaryKey($log->company_id);
return $log;
})->makeHidden(['id'])->all();
$this->export_data['tasks'] = $this->company->tasks()->orderBy('number', 'DESC')->cursor()->map(function ($task) {
$this->export_data['tasks'] = $this->company->tasks()->orderBy('number', 'DESC')->cursor()->map(function ($task){
$task = $this->transformBasicEntities($task);
$task = $this->transformArrayOfKeys($task, ['client_id', 'invoice_id', 'project_id', 'status_id']);
return $task->makeVisible(['id']);
})->all();
$this->export_data['task_statuses'] = $this->company->task_statuses->map(function ($status) {
$this->export_data['task_statuses'] = $this->company->task_statuses->map(function ($status){
$status->id = $this->encodePrimaryKey($status->id);
$status->user_id = $this->encodePrimaryKey($status->user_id);
$status->company_id = $this->encodePrimaryKey($status->company_id);
return $status;
})->all();
$this->export_data['tax_rates'] = $this->company->tax_rates->map(function ($rate) {
$this->export_data['tax_rates'] = $this->company->tax_rates->map(function ($rate){
$rate->company_id = $this->encodePrimaryKey($rate->company_id);
$rate->user_id = $this->encodePrimaryKey($rate->user_id);
return $rate;
})->makeHidden(['id'])->all();
$this->export_data['vendors'] = $this->company->vendors()->orderBy('number', 'DESC')->cursor()->map(function ($vendor) {
$this->export_data['vendors'] = $this->company->vendors()->orderBy('number', 'DESC')->cursor()->map(function ($vendor){
return $this->transformBasicEntities($vendor)->makeVisible(['id']);
})->all();
$this->export_data['vendor_contacts'] = VendorContact::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($vendor) {
$this->export_data['vendor_contacts'] = VendorContact::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($vendor){
$vendor = $this->transformBasicEntities($vendor);
$vendor->vendor_id = $this->encodePrimaryKey($vendor->vendor_id);
$vendor = $this->transformArrayOfKeys($vendor, ['vendor_id']);
return $vendor->makeVisible(['id','user_id']);
return $vendor->makeVisible(['id']);
})->all();
$this->export_data['webhooks'] = $this->company->webhooks->map(function ($hook) {
$this->export_data['webhooks'] = $this->company->webhooks->map(function ($hook){
$hook->user_id = $this->encodePrimaryKey($hook->user_id);
$hook->company_id = $this->encodePrimaryKey($hook->company_id);
return $hook;
})->makeHidden(['id'])->all();
$this->export_data['purchase_orders'] = $this->company->purchase_orders()->orderBy('number', 'DESC')->cursor()->map(function ($purchase_order){
$purchase_order = $this->transformBasicEntities($purchase_order);
$purchase_order = $this->transformArrayOfKeys($purchase_order, ['expense_id','client_id', 'vendor_id', 'project_id', 'design_id', 'subscription_id','project_id']);
return $purchase_order->makeVisible(['id',
'private_notes',
'user_id',
'client_id',
'vendor_id',
'company_id',]);
})->all();
$this->export_data['purchase_order_invitations'] = PurchaseOrderInvitation::where('company_id', $this->company->id)->withTrashed()->cursor()->map(function ($purchase_order){
$purchase_order = $this->transformArrayOfKeys($purchase_order, ['company_id', 'user_id', 'vendor_contact_id', 'purchase_order_id']);
return $purchase_order->makeVisible(['id']);
})->all();
//write to tmp and email to owner();
$this->zipAndSend();
$this->zipAndSend();
return true;
return true;
}
private function transformBasicEntities($model)
{
return $this->transformArrayOfKeys($model, ['user_id', 'assigned_user_id', 'company_id']);
}
private function transformArrayOfKeys($model, $keys)
{
foreach ($keys as $key) {
foreach($keys as $key){
$model->{$key} = $this->encodePrimaryKey($model->{$key});
}
return $model;
}
private function transformPaymentable($payment)
{
$new_arr = [];
foreach ($payment->paymentables as $paymentable) {
foreach($payment->paymentables as $paymentable)
{
$paymentable->payment_id = $this->encodePrimaryKey($paymentable->payment_id);
$paymentable->paymentable_id = $this->encodePrimaryKey($paymentable->paymentable_id);
@ -390,29 +505,30 @@ class CompanyExport implements ShouldQueue
}
return $new_arr;
}
private function zipAndSend()
{
$file_name = date('Y-m-d').'_'.str_replace([' ', '/'], ['_', ''], $this->company->present()->name().'_'.$this->company->company_key.'.zip');
$file_name = date('Y-m-d').'_'.str_replace([" ", "/"],["_",""], $this->company->present()->name() . '_' . $this->company->company_key .'.zip');
$path = 'backups';
if (! Storage::disk(config('filesystems.default'))->exists($path)) {
if(!Storage::disk(config('filesystems.default'))->exists($path))
Storage::disk(config('filesystems.default'))->makeDirectory($path, 0775);
}
$zip_path = public_path('storage/backups/'.$file_name);
$zip = new \ZipArchive();
if ($zip->open($zip_path, \ZipArchive::CREATE) !== true) {
if ($zip->open($zip_path, \ZipArchive::CREATE)!==TRUE) {
nlog("cannot open {$zip_path}");
}
$zip->addFromString('backup.json', json_encode($this->export_data));
$zip->addFromString("backup.json", json_encode($this->export_data));
$zip->close();
if (Ninja::isHosted()) {
if(Ninja::isHosted()) {
Storage::disk(config('filesystems.default'))->put('backups/'.$file_name, file_get_contents($zip_path));
}
@ -422,19 +538,20 @@ class CompanyExport implements ShouldQueue
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings));
$company_reference = Company::find($this->company->id);
$company_reference = Company::find($this->company->id);;
$nmo = new NinjaMailerObject;
$nmo->mailable = new DownloadBackup($storage_file_path, $company_reference);
$nmo->to_user = $this->user;
$nmo->company = $company_reference;
$nmo->settings = $this->company->settings;
NinjaMailerJob::dispatch($nmo, true);
if (Ninja::isHosted()) {
if(Ninja::isHosted()){
sleep(3);
unlink($zip_path);
}
}
}

View File

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

View File

@ -498,8 +498,15 @@ class Account extends BaseModel
$plan_expires = Carbon::parse($this->plan_expires);
if(!$this->payment_id && $plan_expires->gt(now()))
return $plan_expires->diffInDays();
if(!$this->payment_id && $plan_expires->gt(now())){
$diff = $plan_expires->diffInDays();
if($diff > 14);
return 0;
return $diff;
}
return 0;
}

View File

@ -23,10 +23,13 @@ use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
/**
* Class BaseModel
*
* @method scope() static
*
* @package App\Models
*/
class BaseModel extends Model
{
@ -187,17 +190,23 @@ class BaseModel extends Model
public function numberFormatter()
{
$number = strlen($this->number) >= 1 ? $this->number : class_basename($this).'_'.Str::random(5);
$number = strlen($this->number) >= 1 ? $this->number : class_basename($this) . "_" . Str::random(5);
$formatted_number = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $number);
$formatted_number = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $number);
// Remove any runs of periods (thanks falstro!)
$formatted_number = mb_ereg_replace("([\.]{2,})", '', $formatted_number);
// $formatted_number = str_replace(" ", "_", $formatted_number);
//11-01-2021 fixes for multiple spaces
$formatted_number = preg_replace('/\s+/', '_', $formatted_number);
return $formatted_number;
}
public function translate_entity()
{
return ctrans('texts.item');
}
}

View File

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

View File

@ -309,7 +309,6 @@ class BaseRepository
$model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
$model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']), "Update adjustment for invoice {$model->number}");
}
if (! $model->design_id)

View File

@ -5978,6 +5978,10 @@ google_sign_in_platform_interface
google_sign_in_web
image_picker_for_web
image_picker_platform_interface
in_app_purchase
in_app_purchase_android
in_app_purchase_platform_interface
in_app_purchase_storekit
local_auth
package_info
path_provider

View File

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

188167
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

172403
public/main.foss.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long